Update to go 1.24 and add some logging.

Signed-off-by: Mariano Uvalle <u.g.a.mariano@gmail.com>
This commit is contained in:
Mariano Uvalle 2025-05-10 13:59:51 -07:00
parent 7ddf1162c7
commit c041a5feee
13 changed files with 187 additions and 30 deletions

99
.dockerignore Normal file
View file

@ -0,0 +1,99 @@
# 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

16
cmd/admin/main.go Normal file
View file

@ -0,0 +1,16 @@
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)
}

View file

@ -7,7 +7,7 @@ import (
var apiclient *client.Client var apiclient *client.Client
func init() { func init() {
apiclient = client.New("https://api.ccclip.io") apiclient = client.New("https://clipboard.jmug.me")
} }
func main() { func main() {

View file

@ -1,12 +1,7 @@
FROM golang:1.21-alpine AS builder FROM golang:1.24-alpine AS builder
# Ensure we have a c compiler. # Ensure we have a c compiler.
RUN apk add --no-cache build-base ca-certificates fuse3 sqlite 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 WORKDIR /src
COPY go.mod . COPY go.mod .
COPY go.sum . COPY go.sum .
@ -14,6 +9,6 @@ RUN go mod download
COPY . . COPY . .
RUN go build -ldflags='-s -w' -tags 'linux' -trimpath -o /dist/app ./cmd/server RUN go build -ldflags='-s -w' -tags 'linux' -trimpath -o /dist/app ./cmd/server
EXPOSE 3000 EXPOSE 8080
ENTRYPOINT ["litefs", "mount"] ENTRYPOINT ["/dist/app"]

17
flake.lock generated
View file

@ -20,6 +20,22 @@
"type": "github" "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": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1734629298, "lastModified": 1734629298,
@ -39,6 +55,7 @@
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"gonixpkgs": "gonixpkgs",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"systems": "systems" "systems": "systems"
} }

View file

@ -2,6 +2,7 @@
description = "A basic flake with a shell"; description = "A basic flake with a shell";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; nixpkgs.url = "github:NixOS/nixpkgs/release-24.11";
gonixpkgs.url = "github:NixOS/nixpkgs/1cb1c02a6b1b7cf67e3d7731cbbf327a53da9679";
systems.url = "github:nix-systems/default"; systems.url = "github:nix-systems/default";
flake-utils = { flake-utils = {
url = "github:numtide/flake-utils"; url = "github:numtide/flake-utils";
@ -10,15 +11,17 @@
}; };
outputs = outputs =
{ nixpkgs, flake-utils, ... }: { nixpkgs, gonixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem ( flake-utils.lib.eachDefaultSystem (
system: system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
gopkgs = gonixpkgs.legacyPackages.${system};
in in
{ {
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
packages = with pkgs; [ packages = with gopkgs; [
pkgs.flyctl
go go
gotools gotools
gopls gopls

View file

@ -1,30 +1,30 @@
# fly.toml app configuration file generated for dark-paper-8180 on 2023-11-10T08:23:22Z # fly.toml app configuration file generated for ccclip on 2025-05-10T00:45:48-07:00
# #
# See https://fly.io/docs/reference/configuration/ for information about how to use this file. # See https://fly.io/docs/reference/configuration/ for information about how to use this file.
# #
app = "dark-paper-8180" app = 'ccclip'
primary_region = "sea" primary_region = 'sea'
[build] [build]
dockerfile = "./cmd/server/Dockerfile" dockerfile = './cmd/server/Dockerfile'
[env] [env]
CCCLIP_PORT = "3000" CCCLIP_DATABASE_LOCATION = '/database/ccclip.db'
CCCLIP_DATABASE_LOCATION = "/litefs/ccclip.db"
[mounts] [[mounts]]
source = "litefs" source = 'database'
destination = "/var/lib/litefs" destination = '/database'
[http_service] [http_service]
internal_port = 8080 internal_port = 8080
force_https = true force_https = true
auto_stop_machines = true auto_stop_machines = 'stop'
auto_start_machines = true auto_start_machines = true
min_machines_running = 1 processes = ['app']
processes = ["app"]
[vm] [[vm]]
size = "shared-cpu-1x" size = 'shared-cpu-1x'
memory = "1gb" memory = '512mb'
cpu_kind = 'shared'
cpus = 1

4
go.mod
View file

@ -1,6 +1,8 @@
module github.com/AYM1607/ccclip module github.com/AYM1607/ccclip
go 1.21 go 1.24
toolchain go1.24.3
require ( require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0

View file

@ -55,12 +55,12 @@ func Write(c ConfigFile) error {
func LoadPrivateKey() (*ecdh.PrivateKey, error) { func LoadPrivateKey() (*ecdh.PrivateKey, error) {
fp := path.Join(Path, PrivateKeyFileName) fp := path.Join(Path, PrivateKeyFileName)
return crypto.LoadPrivateKeyFromFile(fp) return crypto.LoadPrivateKeyFromFile(fp), nil
} }
func LoadPublicKey() (*ecdh.PublicKey, error) { func LoadPublicKey() (*ecdh.PublicKey, error) {
fp := path.Join(Path, PublicKeyFileName) fp := path.Join(Path, PublicKeyFileName)
return crypto.LoadPublicKeyFromFile(fp) return crypto.LoadPublicKeyFromFile(fp), nil
} }
func SavePrivateKey(k *ecdh.PrivateKey) error { func SavePrivateKey(k *ecdh.PrivateKey) error {

View file

@ -5,6 +5,7 @@ import (
"crypto/ecdh" "crypto/ecdh"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"net/http" "net/http"
"time" "time"
@ -110,6 +111,8 @@ func (c *Client) SetClipboard(plaintext []byte, deviceId string, pvk *ecdh.Priva
} }
hres, err := http.Post(c.url+"/setClipboard", "application/json", bytes.NewReader(authReqJson)) hres, err := http.Post(c.url+"/setClipboard", "application/json", bytes.NewReader(authReqJson))
hresBytes, _ := io.ReadAll(hres.Body)
fmt.Println(string(hresBytes))
if err != nil { if err != nil {
return err return err
} }
@ -194,6 +197,8 @@ func (c *Client) getDevices(deviceId string, pvk *ecdh.PrivateKey) ([]*api.Devic
hresBody, err := io.ReadAll(hres.Body) hresBody, err := io.ReadAll(hres.Body)
defer hres.Body.Close() defer hres.Body.Close()
hresBytes, _ := io.ReadAll(hres.Body)
fmt.Println(string(hresBytes))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -8,7 +8,7 @@ import (
"github.com/AYM1607/ccclip/pkg/crypto" "github.com/AYM1607/ccclip/pkg/crypto"
) )
const serverPublicKeyB64 = "JTyaIVDHe1Nwqmd4NFlkvqj+MZOVp5s3JZP+T3QuoT8=" const serverPublicKeyB64 = "Dg6HYJ8aoQOOzGqOCw4J7tnT+QHkokjfdeWM8ktwnks="
var serverPublicKey *ecdh.PublicKey var serverPublicKey *ecdh.PublicKey

View file

@ -0,0 +1,9 @@
package server
import "log"
var logger *log.Logger
func init() {
logger = log.Default()
}

View file

@ -166,9 +166,11 @@ type GetUserDevicesResponse struct {
} }
func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request) { func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request) {
logger.Println("handling get user devices")
var authReq AuthenticatedPayload var authReq AuthenticatedPayload
err := json.NewDecoder(r.Body).Decode(&authReq) err := json.NewDecoder(r.Body).Decode(&authReq)
if err != nil { if err != nil {
logger.Printf("decoding request: %s\n", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
@ -177,18 +179,21 @@ func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request
// TODO: verify the request fingerprint. Right now we're just trusting that // TODO: verify the request fingerprint. Right now we're just trusting that
// if it decrypts successfully then we can trust it. // if it decrypts successfully then we can trust it.
if err != nil { if err != nil {
logger.Printf("decrypting payload: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
user, err := c.store.GetDeviceUser(authReq.DeviceID) user, err := c.store.GetDeviceUser(authReq.DeviceID)
if err != nil { if err != nil {
logger.Printf("getting user for device: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
devices, err := c.store.GetUserDevices(user.ID) devices, err := c.store.GetUserDevices(user.ID)
if err != nil { if err != nil {
logger.Printf("getting devices for user: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@ -197,6 +202,7 @@ func (c *controller) handleGetUserDevices(w http.ResponseWriter, r *http.Request
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(res) err = json.NewEncoder(w).Encode(res)
if err != nil { if err != nil {
logger.Printf("encoding response: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@ -208,9 +214,11 @@ type SetClipboardRequest struct {
} }
func (c *controller) handleSetClipboard(w http.ResponseWriter, r *http.Request) { func (c *controller) handleSetClipboard(w http.ResponseWriter, r *http.Request) {
log.Default().Println("handling set clipboard")
var authReq AuthenticatedPayload var authReq AuthenticatedPayload
err := json.NewDecoder(r.Body).Decode(&authReq) err := json.NewDecoder(r.Body).Decode(&authReq)
if err != nil { if err != nil {
log.Default().Printf("decoding request: %s\n", err)
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
@ -219,18 +227,21 @@ func (c *controller) handleSetClipboard(w http.ResponseWriter, r *http.Request)
// TODO: verify the request fingerprint. Right now we're just trusting that // TODO: verify the request fingerprint. Right now we're just trusting that
// if it decrypts successfully then we can trust it. // if it decrypts successfully then we can trust it.
if err != nil { if err != nil {
log.Default().Printf("decrypting authenticated payload: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
user, err := c.store.GetDeviceUser(authReq.DeviceID) user, err := c.store.GetDeviceUser(authReq.DeviceID)
if err != nil { if err != nil {
log.Default().Printf("getting user device: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
err = c.store.PutClipboard(user.ID, req.Clipboard) err = c.store.PutClipboard(user.ID, req.Clipboard)
if err != nil { if err != nil {
log.Default().Printf("putting keyboard: %s\n", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }