# clip-sync [![Go Version](https://img.shields.io/badge/Go-1.21+-00ADD8?logo=go)](https://go.dev) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![Tests](https://img.shields.io/badge/tests-100%25-brightgreen)](.) **Daemon de synchronisation bidirectionnelle du presse-papiers sur réseau local.** Copier sur une machine → coller sur une autre, automatiquement et instantanément. ``` ┌──────────────┐ POST /clip ┌──────────────┐ │ Machine A │◄──────────────────────────►│ Machine B │ │ (bureau) │ {text, ts, origin} │ (portable) │ │ :9137 │ │ :9137 │ └──────────────┘ └──────────────┘ ``` ## Installation rapide **Linux / macOS :** ```bash curl -fsSL https://git.dracodev.net/Projets/clip-sync/raw/branch/main/install.sh | bash ``` **Windows (PowerShell) :** ```powershell irm https://git.dracodev.net/Projets/clip-sync/raw/branch/main/install.ps1 | iex ``` Le script détecte l'OS et l'architecture, télécharge le binaire, l'installe et crée la configuration par défaut. Ensuite : éditez `~/.config/clip-sync/peers.toml` et lancez `clip-sync`. Voir [Configuration](#configuration) et [installation détaillée](#installation). ## Fonctionnalités - **Bidirectionnel** — copie A → B et B → A, chaque nœud est client et serveur - **Anti-boucle** — double filtre (hash SHA-256 + timestamp/origine) empêche le ping-pong - **Sécurité** — clé partagée (Bearer token), validation d'origine, TLS optionnel - **Découverte mDNS** — détection automatique des pairs (optionnelle) - **Historique** — derniers clips conservés (`clip-sync history`) - **Transfert de fichiers** — `clip-sync send-file` (réception optionnelle) - **Interface web** — monitoring local sur `http://localhost:9137/` - **Multi-plateforme** — Linux (X11/Wayland), Windows, macOS - **Binaire unique** — zéro runtime externe, compilation Go native - **Configuration simple** — fichier TOML + variables d'environnement - **LAN uniquement** — aucune donnée ne quitte votre réseau local ## Installation ### Méthode 1 : Script automatique en une ligne (recommandé) ```bash curl -fsSL https://git.dracodev.net/Projets/clip-sync/raw/branch/main/install.sh | bash ``` **Windows (PowerShell) :** ```powershell irm https://git.dracodev.net/Projets/clip-sync/raw/branch/main/install.ps1 | iex ``` Le script détecte OS + architecture, télécharge le binaire, l'installe dans le répertoire utilisateur et crée une config par défaut. Pour épingler une version : `CLIP_SYNC_VERSION=v0.2.0` (Linux/macOS) ou `$env:CLIP_SYNC_VERSION='v0.2.0'` (Windows). --- ### Méthode 2 : Instructions détaillées par OS #### 🐧 Linux (X11 ou Wayland) **1. Installer les dépendances** | Distribution | X11 | Wayland | |---|---|---| | **Debian / Ubuntu** | `sudo apt install xclip` | `sudo apt install wl-clipboard` | | **Arch / Manjaro** | `sudo pacman -S xclip` | `sudo pacman -S wl-clipboard` | | **Fedora / RHEL** | `sudo dnf install xclip` | `sudo dnf install wl-clipboard` | | **Alpine** | `sudo apk add xclip` | `sudo apk add wl-clipboard` | clip-sync détecte automatiquement X11 vs Wayland via `$XDG_SESSION_TYPE`. **2. Télécharger le binaire** ```bash # amd64 curl -sSL -o ~/.local/bin/clip-sync \ https://git.dracodev.net/Projets/clip-sync/releases/download/v0.2.0/clip-sync-linux-amd64 chmod +x ~/.local/bin/clip-sync # arm64 (Raspberry Pi, etc.) curl -sSL -o ~/.local/bin/clip-sync \ https://git.dracodev.net/Projets/clip-sync/releases/download/v0.2.0/clip-sync-linux-arm64 chmod +x ~/.local/bin/clip-sync ``` **3. Vérifier le PATH** ```bash # Ajouter ~/.local/bin au PATH si ce n'est pas déjà fait echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc source ~/.bashrc ``` **4. Vérifier l'installation** ```bash clip-sync --version # → clip-sync v0.2.0 ``` **5. Installer comme service (systemd --user)** ```bash mkdir -p ~/.config/systemd/user/ curl -sSL -o ~/.config/systemd/user/clip-sync.service \ https://git.dracodev.net/Projets/clip-sync/raw/branch/main/clip-sync.service systemctl --user daemon-reload systemctl --user enable --now clip-sync systemctl --user status clip-sync ``` --- #### 🍎 macOS **1. Aucune dépendance externe** — `pbpaste`/`pbcopy` sont intégrés à macOS. **2. Télécharger le binaire** ```bash # Apple Silicon (M1/M2/M3) curl -sSL -o ~/.local/bin/clip-sync \ https://git.dracodev.net/Projets/clip-sync/releases/download/v0.2.0/clip-sync-darwin-arm64 chmod +x ~/.local/bin/clip-sync # Intel Mac curl -sSL -o ~/.local/bin/clip-sync \ https://git.dracodev.net/Projets/clip-sync/releases/download/v0.2.0/clip-sync-darwin-amd64 chmod +x ~/.local/bin/clip-sync ``` **3. Vérifier le PATH** ```bash echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc source ~/.zshrc ``` **4. Vérifier l'installation** ```bash clip-sync --version # → clip-sync v0.2.0 ``` **5. Installer comme service (launchd)** ```bash cat > ~/Library/LaunchAgents/com.clip-sync.plist << 'EOF' Label com.clip-sync ProgramArguments /Users/$(whoami)/.local/bin/clip-sync RunAtLoad KeepAlive StandardOutPath /Users/$(whoami)/Library/Logs/clip-sync.log StandardErrorPath /Users/$(whoami)/Library/Logs/clip-sync.err EOF launchctl load ~/Library/LaunchAgents/com.clip-sync.plist launchctl list | grep clip-sync ``` --- #### 🪟 Windows **1. Aucune dépendance externe** — clip-sync utilise l'API Win32 native (user32.dll, kernel32.dll) sans CGo ni runtime externe. **2. Télécharger le binaire** ```powershell # amd64 (standard) Invoke-WebRequest -Uri ` "https://git.dracodev.net/Projets/clip-sync/releases/download/v0.2.0/clip-sync-windows-amd64.exe" ` -OutFile "$env:USERPROFILE\bin\clip-sync.exe" # arm64 (Surface Pro X, etc.) Invoke-WebRequest -Uri ` "https://git.dracodev.net/Projets/clip-sync/releases/download/v0.2.0/clip-sync-windows-arm64.exe" ` -OutFile "$env:USERPROFILE\bin\clip-sync.exe" ``` **3. Ajouter au PATH** ```powershell # PowerShell (admin) — permanent [Environment]::SetEnvironmentVariable( "Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";$env:USERPROFILE\bin", "User" ) ``` **4. Vérifier l'installation** (redémarrer le terminal après l'étape 3) ```powershell clip-sync --version # → clip-sync v0.2.0 ``` **5. Installer comme service Windows (NSSM)** Télécharger [NSSM](https://nssm.cc/download) et l'extraire, puis : ```powershell nssm install clip-sync %USERPROFILE%\bin\clip-sync.exe nssm set clip-sync AppStdout %USERPROFILE%\AppData\Local\clip-sync\stdout.log nssm set clip-sync AppStderr %USERPROFILE%\AppData\Local\clip-sync\stderr.log nssm set clip-sync AppStdoutCreationDisposition 4 nssm set clip-sync AppStderrCreationDisposition 4 nssm start clip-sync ``` **6. Pare-feu Windows** — la première exécution peut déclencher une alerte. Autoriser l'accès réseau privé. --- ### Compilation depuis les sources Prérequis : [Go 1.21+](https://go.dev/dl/) ```bash git clone https://git.dracodev.net/Projets/clip-sync.git cd clip-sync make build # binaire dans ./bin/ make install # copie vers ~/.local/bin/ ``` ## Démarrage rapide ### 1. Créer la configuration ```bash mkdir -p ~/.config/clip-sync ``` **Machine A** (bureau, 192.168.1.10) : ```toml # ~/.config/clip-sync/peers.toml [daemon] port = 9137 poll_interval_ms = 500 [[peers]] name = "portable" addr = "192.168.1.20:9137" ``` **Machine B** (portable, 192.168.1.20) : ```toml # ~/.config/clip-sync/peers.toml [daemon] port = 9137 poll_interval_ms = 500 [[peers]] name = "bureau" addr = "192.168.1.10:9137" ``` ### 2. Lancer le daemon ```bash clip-sync ``` ### 3. Tester Copiez du texte sur la machine A (Ctrl+C), collez sur la machine B (Ctrl+V). Ça marche ! ## Configuration ### Fichier TOML | Clé | Défaut | Description | |-----|--------|-------------| | `daemon.port` | `9137` | Port d'écoute HTTP(S) | | `daemon.poll_interval_ms` | `500` | Intervalle de scrutation du presse-papiers (ms) | | `daemon.max_body_bytes` | `10485760` | Taille max d'une requête (10 MiB) | | `daemon.history_size` | `50` | Nombre d'entrées conservées dans l'historique | | `daemon.discovery` | `false` | Découverte automatique des pairs via mDNS | | `daemon.notify` | `false` | Notifications desktop à chaque clip reçu | | `daemon.sync_images` | `false` | Sync d'images (PNG) entre pairs | | `daemon.receive_files` | `false` | Accepter les transferts de fichiers | | `daemon.receive_dir` | `~/Downloads/clip-sync` | Dossier de réception des fichiers | | `security.shared_key` | — | Clé partagée (`clip-sync --generate-key`) | | `security.allowed_origins` | — | Liste des hôtes autorisés | | `security.tls` | `false` | Chiffrement TLS entre pairs | | `security.cert_file` / `key_file` | `~/.config/clip-sync/{cert,key}.pem` | Certificat auto-signé | | `peers[].name` | — | Nom descriptif du pair | | `peers[].addr` | — | Adresse `host:port` du pair | | `peers[].tls` | `false` | TLS pour ce pair (override global) | ### Variables d'environnement (override) | Variable | Équivalent TOML | |----------|-----------------| | `CLIP_SYNC_PORT` | `daemon.port` | | `CLIP_SYNC_POLL_MS` | `daemon.poll_interval_ms` | | `CLIP_SYNC_KEY` | `security.shared_key` | | `CLIP_SYNC_MAX_BODY_BYTES` | `daemon.max_body_bytes` | ## Commandes ```bash clip-sync # lancer le daemon clip-sync --config # config personnalisée clip-sync --version # afficher la version clip-sync history # afficher l'historique local clip-sync --one-shot [text] # envoyer le presse-papiers (ou text) une fois clip-sync send-file # envoyer un fichier aux pairs clip-sync --generate-key # générer une clé partagée clip-sync --generate-cert # générer un certificat TLS auto-signé ``` ## Sécurité Sur un réseau partagé, activez au minimum une clé partagée : ```bash clip-sync --generate-key # → copier la clé sur toutes les machines ``` ```toml [security] shared_key = "LA_CLÉ_GÉNÉRÉE" ``` Pour chiffrer le trafic, générez un certificat sur une machine, copiez les fichiers `cert.pem`/`key.pem` vers toutes les autres, puis : ```toml [security] tls = true insecure_skip_verify = true # confiance au certificat auto-signé partagé ``` ## Déboguer ```bash # Tester la connectivité entre pairs curl -X POST http://192.168.1.20:9137/clip \ -H 'Content-Type: application/json' \ -d '{"text":"test","ts":0,"origin":"debug"}' ``` L'interface de monitoring est disponible sur `http://localhost:9137/` après le démarrage du daemon. ## Documentation Site de documentation statique : [`docs/index.html`](docs/index.html). Commandes de développement utiles : ```bash make bench # benchmarks make sign # signer les binaires de release avec GPG make test-race # tests avec détecteur de race ``` ## Validation manuelle — notifications Windows Le code des notifications Windows (bulle via `Shell_NotifyIconW`) compile, mais n'a pas été validé sur un vrai poste. Voici exactement quoi tester : 1. **Installer et lancer** : sur Windows, `irm …/install.ps1 | iex`, ou `go build` puis exécuter `clip-sync`. 2. **Activer les notifications** dans `~/.config/clip-sync/peers.toml` : ```toml [daemon] notify = true ``` 3. **Envoyer un clip** depuis une autre machine du LAN, ou en local : ```powershell curl -X POST http://127.0.0.1:9137/clip -H "Content-Type: application/json" ` -d '{"text":"test notification","ts":1700000000000000000,"origin":"autre-machine"}' ``` 4. **Vérifier** qu'une bulle intitulée `clip-sync` apparaît dans la zone de notification (coin bas-droit), avec le message « Clip reçu de autre-machine ». 5. **Tester une image** : activer `sync_images = true`, envoyer une image (copier/coller d'une autre machine), vérifier la bulle « Image reçue de … ». 6. **Vérifier l'icône** : une icône clip-sync doit rester dans la barre des tâches pendant que le daemon tourne (comportement attendu de `Shell_NotifyIcon`). 7. **Robustesse** : envoyer plusieurs clips rapprochés — pas de crash, bulles successives. 8. **Noter la différence Windows 10 vs 11** : bulle classique vs conversion en toast (selon les réglages système), et signaler tout écart observé. ## Signer les releases (GPG) La CI signe automatiquement les binaires si une clé est configurée. Étapes : 1. **Générer une clé** (si absente) : ```bash gpg --full-generate-key # choisir RSA/RSA 4096, saisir nom + email, et une passphrase ``` 2. **Récupérer l'ID de la clé** (la partie après `rsa4096/`) : ```bash gpg --list-secret-keys --keyid-format LONG # sec rsa4096/AAAAAAAAAAAAAAAA 2026-08-14 [SC] ``` 3. **Exporter la clé privée** (bloc armoré) : ```bash gpg --armor --export-secret-keys AAAAAAAAAAAAAAAA ``` 4. **Ajouter les secrets Gitea** : dépôt → *Settings* → *Actions* → *Secrets* : - `GPG_PRIVATE_KEY` = le contenu exporté (le bloc `BEGIN PGP PRIVATE KEY BLOCK`) - `GPG_PASSPHRASE` = la passphrase (seulement si la clé en a une) 5. **Publier une release** : ```bash git tag v0.2.0 git push origin v0.2.0 ``` La CI importe la clé, signe chaque binaire et attache les fichiers `.asc`. 6. **Vérifier** une signature : ```bash gpg --verify clip-sync-linux-amd64.asc ``` (nécessite la clé publique : `gpg --recv-keys AAAAAAAAAAAAAAAA`, ou publiez-la sur un serveur de clés / dans le README). ## Licence MIT © 2026