Compare commits
No commits in common. "main" and "AYM1607-patch-1" have entirely different histories.
main
...
AYM1607-pa
16 changed files with 33 additions and 293 deletions
|
|
@ -1,99 +0,0 @@
|
|||
# flyctl launch added from .gitignore
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/vim,linux,macos,go
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,linux,macos,go
|
||||
|
||||
### Go ###
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
**/*.exe
|
||||
**/*.exe~
|
||||
**/*.dll
|
||||
**/*.so
|
||||
**/*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
**/*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
**/*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
**/go.work
|
||||
|
||||
### Linux ###
|
||||
**/*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
**/.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
**/.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
**/.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
**/.nfs*
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
**/.DS_Store
|
||||
**/.AppleDouble
|
||||
**/.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
**/Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
**/._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
**/.DocumentRevisions-V100
|
||||
**/.fseventsd
|
||||
**/.Spotlight-V100
|
||||
**/.TemporaryItems
|
||||
**/.Trashes
|
||||
**/.VolumeIcon.icns
|
||||
**/.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
**/.AppleDB
|
||||
**/.AppleDesktop
|
||||
**/Network Trash Folder
|
||||
**/Temporary Items
|
||||
**/.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
**/*.icloud
|
||||
|
||||
### Vim ###
|
||||
# Swap
|
||||
**/[._]*.s[a-v][a-z]
|
||||
!**/*.svg # comment out if you don't need vector files
|
||||
**/[._]*.sw[a-p]
|
||||
**/[._]s[a-rt-v][a-z]
|
||||
**/[._]ss[a-gi-z]
|
||||
**/[._]sw[a-p]
|
||||
|
||||
# Session
|
||||
**/Session.vim
|
||||
**/Sessionx.vim
|
||||
|
||||
# Temporary
|
||||
**/.netrwhist
|
||||
# Auto-generated tag files
|
||||
**/tags
|
||||
# Persistent undo
|
||||
**/[._]*.un~
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/vim,linux,macos,go
|
||||
|
||||
**/.direnv
|
||||
fly.toml
|
||||
1
.envrc
1
.envrc
|
|
@ -1 +0,0 @@
|
|||
use flake
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -93,5 +93,3 @@ tags
|
|||
[._]*.un~
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/vim,linux,macos,go
|
||||
|
||||
.direnv
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/AYM1607/ccclip/pkg/crypto"
|
||||
)
|
||||
|
||||
func main() {
|
||||
privK := crypto.NewPrivateKey()
|
||||
privStr := base64.StdEncoding.EncodeToString(privK.Bytes())
|
||||
pubStr := base64.StdEncoding.EncodeToString(privK.PublicKey().Bytes())
|
||||
|
||||
fmt.Printf("Priv: %s\nPub: %s\n", privStr, pubStr)
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
var apiclient *client.Client
|
||||
|
||||
func init() {
|
||||
apiclient = client.New("https://clipboard.jmug.me")
|
||||
apiclient = client.New("https://api.ccclip.io")
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
func init() {
|
||||
rootCmd.AddCommand(registerDeviceCommand)
|
||||
registerDeviceCommand.Flags().StringVarP(&email, "email", "e", "", "email is your login identifier, ignored if your config file has has an email")
|
||||
}
|
||||
|
||||
var registerDeviceCommand = &cobra.Command{
|
||||
|
|
@ -24,11 +23,8 @@ var registerDeviceCommand = &cobra.Command{
|
|||
return err
|
||||
}
|
||||
|
||||
if cc.Email != "" {
|
||||
email = cc.Email
|
||||
}
|
||||
if email == "" {
|
||||
return errors.New("provide an email through your config file or with --email")
|
||||
if cc.Email == "" {
|
||||
return errors.New("you don't have an account configured for thist device")
|
||||
}
|
||||
|
||||
if cc.DeviceId != "" {
|
||||
|
|
@ -39,7 +35,7 @@ var registerDeviceCommand = &cobra.Command{
|
|||
pbk := pvk.PublicKey()
|
||||
|
||||
password := input.ReadPassword()
|
||||
res, err := apiclient.RegisterDevice(email, password, pbk.Bytes())
|
||||
res, err := apiclient.RegisterDevice(cc.Email, password, pbk.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -47,9 +43,6 @@ var registerDeviceCommand = &cobra.Command{
|
|||
// Write the key files first, if those fail to write then we should not
|
||||
// save the device Id.
|
||||
cc.DeviceId = res.DeviceID
|
||||
if cc.Email == "" {
|
||||
cc.Email = email
|
||||
}
|
||||
err = configfile.SavePrivateKey(pvk)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
FROM golang:1.24-alpine AS builder
|
||||
FROM golang:1.21-alpine AS builder
|
||||
# Ensure we have a c compiler.
|
||||
RUN apk add --no-cache build-base ca-certificates fuse3 sqlite
|
||||
|
||||
# Install LiteFS for distribute SQLite
|
||||
COPY --from=flyio/litefs:0.5 /usr/local/bin/litefs /usr/local/bin/litefs
|
||||
|
||||
COPY cmd/server/litefs.yml /etc/litefs.yml
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
|
|
@ -9,6 +14,6 @@ RUN go mod download
|
|||
COPY . .
|
||||
RUN go build -ldflags='-s -w' -tags 'linux' -trimpath -o /dist/app ./cmd/server
|
||||
|
||||
EXPOSE 8080
|
||||
EXPOSE 3000
|
||||
|
||||
ENTRYPOINT ["/dist/app"]
|
||||
ENTRYPOINT ["litefs", "mount"]
|
||||
|
|
|
|||
81
flake.lock
generated
81
flake.lock
generated
|
|
@ -1,81 +0,0 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gonixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1746518791,
|
||||
"narHash": "sha256-MiJ11L7w18S2G5ftcoYtcrrS0JFqBaj9d5rwJFpC5Wk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1cb1c02a6b1b7cf67e3d7731cbbf327a53da9679",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1cb1c02a6b1b7cf67e3d7731cbbf327a53da9679",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1734629298,
|
||||
"narHash": "sha256-KOzg4I+sRJW6rFaBzVAXKKCi2/uhDgC8YWmImKG6cs8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "fac643b357f5f203cc1fe07f3f070b7534d61334",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"gonixpkgs": "gonixpkgs",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
32
flake.nix
32
flake.nix
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
description = "A basic flake with a shell";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/release-24.11";
|
||||
gonixpkgs.url = "github:NixOS/nixpkgs/1cb1c02a6b1b7cf67e3d7731cbbf327a53da9679";
|
||||
systems.url = "github:nix-systems/default";
|
||||
flake-utils = {
|
||||
url = "github:numtide/flake-utils";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ nixpkgs, gonixpkgs, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
gopkgs = gonixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
packages = with gopkgs; [
|
||||
pkgs.flyctl
|
||||
go
|
||||
gotools
|
||||
gopls
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
30
fly.toml
30
fly.toml
|
|
@ -1,30 +1,30 @@
|
|||
# fly.toml app configuration file generated for ccclip on 2025-05-10T00:45:48-07:00
|
||||
# fly.toml app configuration file generated for dark-paper-8180 on 2023-11-10T08:23:22Z
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'ccclip'
|
||||
primary_region = 'sea'
|
||||
app = "dark-paper-8180"
|
||||
primary_region = "sea"
|
||||
|
||||
[build]
|
||||
dockerfile = './cmd/server/Dockerfile'
|
||||
dockerfile = "./cmd/server/Dockerfile"
|
||||
|
||||
[env]
|
||||
CCCLIP_DATABASE_LOCATION = '/database/ccclip.db'
|
||||
CCCLIP_PORT = "3000"
|
||||
CCCLIP_DATABASE_LOCATION = "/litefs/ccclip.db"
|
||||
|
||||
[[mounts]]
|
||||
source = 'database'
|
||||
destination = '/database'
|
||||
[mounts]
|
||||
source = "litefs"
|
||||
destination = "/var/lib/litefs"
|
||||
|
||||
[http_service]
|
||||
internal_port = 8080
|
||||
force_https = true
|
||||
auto_stop_machines = 'stop'
|
||||
auto_stop_machines = true
|
||||
auto_start_machines = true
|
||||
processes = ['app']
|
||||
min_machines_running = 1
|
||||
processes = ["app"]
|
||||
|
||||
[[vm]]
|
||||
size = 'shared-cpu-1x'
|
||||
memory = '512mb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
[vm]
|
||||
size = "shared-cpu-1x"
|
||||
memory = "1gb"
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -1,8 +1,6 @@
|
|||
module github.com/AYM1607/ccclip
|
||||
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.3
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ type ConfigFile struct {
|
|||
var Path string
|
||||
|
||||
func EnsureAndGet() (ConfigFile, error) {
|
||||
err := os.MkdirAll(Path, os.FileMode(int(0770)))
|
||||
err := os.MkdirAll(Path, os.FileMode(int(0660)))
|
||||
if err != nil {
|
||||
return ConfigFile{}, fmt.Errorf("could not create config directory: %w", err)
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ func EnsureAndGet() (ConfigFile, error) {
|
|||
}
|
||||
|
||||
func Write(c ConfigFile) error {
|
||||
err := os.MkdirAll(Path, os.FileMode(int(0770)))
|
||||
err := os.MkdirAll(Path, os.FileMode(int(0660)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -55,12 +55,12 @@ func Write(c ConfigFile) error {
|
|||
|
||||
func LoadPrivateKey() (*ecdh.PrivateKey, error) {
|
||||
fp := path.Join(Path, PrivateKeyFileName)
|
||||
return crypto.LoadPrivateKeyFromFile(fp), nil
|
||||
return crypto.LoadPrivateKeyFromFile(fp)
|
||||
}
|
||||
|
||||
func LoadPublicKey() (*ecdh.PublicKey, error) {
|
||||
fp := path.Join(Path, PublicKeyFileName)
|
||||
return crypto.LoadPublicKeyFromFile(fp), nil
|
||||
return crypto.LoadPublicKeyFromFile(fp)
|
||||
}
|
||||
|
||||
func SavePrivateKey(k *ecdh.PrivateKey) error {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"crypto/ecdh"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
|
@ -111,8 +110,6 @@ func (c *Client) SetClipboard(plaintext []byte, deviceId string, pvk *ecdh.Priva
|
|||
}
|
||||
|
||||
hres, err := http.Post(c.url+"/setClipboard", "application/json", bytes.NewReader(authReqJson))
|
||||
hresBytes, _ := io.ReadAll(hres.Body)
|
||||
fmt.Println(string(hresBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -197,8 +194,6 @@ func (c *Client) getDevices(deviceId string, pvk *ecdh.PrivateKey) ([]*api.Devic
|
|||
|
||||
hresBody, err := io.ReadAll(hres.Body)
|
||||
defer hres.Body.Close()
|
||||
hresBytes, _ := io.ReadAll(hres.Body)
|
||||
fmt.Println(string(hresBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/AYM1607/ccclip/pkg/crypto"
|
||||
)
|
||||
|
||||
const serverPublicKeyB64 = "Dg6HYJ8aoQOOzGqOCw4J7tnT+QHkokjfdeWM8ktwnks="
|
||||
const serverPublicKeyB64 = "JTyaIVDHe1Nwqmd4NFlkvqj+MZOVp5s3JZP+T3QuoT8="
|
||||
|
||||
var serverPublicKey *ecdh.PublicKey
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package server
|
||||
|
||||
import "log"
|
||||
|
||||
var logger *log.Logger
|
||||
|
||||
func init() {
|
||||
logger = log.Default()
|
||||
}
|
||||
|
|
@ -166,11 +166,9 @@ type GetUserDevicesResponse struct {
|
|||
}
|
||||
|
||||
func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Println("handling get user devices")
|
||||
var authReq AuthenticatedPayload
|
||||
err := json.NewDecoder(r.Body).Decode(&authReq)
|
||||
if err != nil {
|
||||
logger.Printf("decoding request: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -179,21 +177,18 @@ func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request
|
|||
// TODO: verify the request fingerprint. Right now we're just trusting that
|
||||
// if it decrypts successfully then we can trust it.
|
||||
if err != nil {
|
||||
logger.Printf("decrypting payload: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := c.store.GetDeviceUser(authReq.DeviceID)
|
||||
if err != nil {
|
||||
logger.Printf("getting user for device: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
devices, err := c.store.GetUserDevices(user.ID)
|
||||
if err != nil {
|
||||
logger.Printf("getting devices for user: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -202,7 +197,6 @@ func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request
|
|||
w.WriteHeader(http.StatusOK)
|
||||
err = json.NewEncoder(w).Encode(res)
|
||||
if err != nil {
|
||||
logger.Printf("encoding response: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -214,11 +208,9 @@ type SetClipboardRequest struct {
|
|||
}
|
||||
|
||||
func (c *controller) handleSetClipboard(w http.ResponseWriter, r *http.Request) {
|
||||
log.Default().Println("handling set clipboard")
|
||||
var authReq AuthenticatedPayload
|
||||
err := json.NewDecoder(r.Body).Decode(&authReq)
|
||||
if err != nil {
|
||||
log.Default().Printf("decoding request: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -227,21 +219,18 @@ func (c *controller) handleSetClipboard(w http.ResponseWriter, r *http.Request)
|
|||
// TODO: verify the request fingerprint. Right now we're just trusting that
|
||||
// if it decrypts successfully then we can trust it.
|
||||
if err != nil {
|
||||
log.Default().Printf("decrypting authenticated payload: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := c.store.GetDeviceUser(authReq.DeviceID)
|
||||
if err != nil {
|
||||
log.Default().Printf("getting user device: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = c.store.PutClipboard(user.ID, req.Clipboard)
|
||||
if err != nil {
|
||||
log.Default().Printf("putting keyboard: %s\n", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue