CI / Lint (push) Failing after 9m53s
CI / Test (push) Failing after 5m56s
CI / Build (darwin/amd64) (push) Skipped
CI / Build (linux/amd64) (push) Skipped
CI / Build (windows/amd64) (push) Skipped
CI / Build (darwin/arm64) (push) Skipped
CI / Build (linux/arm64) (push) Skipped
CI / Build (windows/arm64) (push) Skipped
CI / Release (push) Skipped
455 lines
14 KiB
Markdown
455 lines
14 KiB
Markdown
# clip-sync
|
|
|
|
[](https://go.dev)
|
|
[](LICENSE)
|
|
[](.)
|
|
|
|
**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'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>Label</key>
|
|
<string>com.clip-sync</string>
|
|
<key>ProgramArguments</key>
|
|
<array>
|
|
<string>/Users/$(whoami)/.local/bin/clip-sync</string>
|
|
</array>
|
|
<key>RunAtLoad</key>
|
|
<true/>
|
|
<key>KeepAlive</key>
|
|
<true/>
|
|
<key>StandardOutPath</key>
|
|
<string>/Users/$(whoami)/Library/Logs/clip-sync.log</string>
|
|
<key>StandardErrorPath</key>
|
|
<string>/Users/$(whoami)/Library/Logs/clip-sync.err</string>
|
|
</dict>
|
|
</plist>
|
|
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 <path> # 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 <path> # 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
|