Files
zwischenablage-server/README.md
T
2026-10-16 15:55:14 +02:00

178 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NetClip – Netzwerk-Zwischenablage
Eine gemeinsame Zwischenablage für alle eigenen Geräte (Windows, Linux, macOS, Android) – im Stil von
CopyQ, aber über das Netzwerk. Text, **Bilder** und **Dateien/Ordner** werden übertragen: Wird auf dem
einen Rechner ein Ordner kopiert (Strg+C im Explorer/Finder/Dolphin), fügt Strg+V auf dem anderen Rechner
den Ordner in den gerade geöffneten Zielordner ein. Mit Verlauf, um Einträge später erneut einzufügen.
```
PC (Windows) Laptop (Linux) Mac Handy (Android)
│ │ │ │
└──────── WebSocket + HTTPS (Ende-zu-Ende verschlüsselt) ───┘
│
NetClip-Server (Docker)
verbindet nur Clients mit gleichem Token
```
## Funktionsweise
- Alle Geräte mit **demselben Token** bilden einen gemeinsamen „Raum“.
- Der Token verlässt das Gerät nie. Aus ihm werden per PBKDF2 eine Raum-ID (sieht der Server) und ein
AES-256-Schlüssel abgeleitet (sieht der Server nicht). Inhalte, Dateinamen, Vorschauen und Gerätenamen
sind **Ende-zu-Ende verschlüsselt** – der Server speichert und verteilt nur undurchsichtige Blobs.
- Der Server hält einen Verlauf pro Raum (Anzahl, Alter, Speicherplatz begrenzt, siehe `.env`).
- Optional schützt ein `SERVER_KEY` den Server davor, von Fremden benutzt zu werden.
## Server (Docker)
```bash
cp .env.example .env # Werte anpassen (CERT_CN, CERT_SAN, SERVER_KEY, ...)
docker compose up -d --build
```
Die `.env` ist kommentiert. Die wichtigsten Schalter:
| Variable | Bedeutung |
|---|---|
| `COMPOSE_PROFILES=nginx` | nginx als HTTPS-Proxy mit selbstsigniertem Zertifikat mitstarten. **Leer lassen**, wenn schon ein Reverse-Proxy vorhanden ist (siehe [docs/eigener-reverse-proxy.md](docs/eigener-reverse-proxy.md)). |
| `CERT_CN`, `CERT_SAN` | Hostname bzw. weitere Namen/IPs im Zertifikat |
| `CERT_DAYS`, `CERT_RENEW_DAYS` | Gültigkeit; so viele Tage vor Ablauf wird beim Containerstart automatisch erneuert |
| `CERT_KEY_BITS`, `CERT_COUNTRY` … `CERT_OU` | weitere Zertifikatsfelder |
| `SERVER_KEY` | optionaler Zugangsschlüssel für den Server |
| `MAX_CLIP_MB` | maximale Größe eines Clips |
| `HISTORY_MAX`, `HISTORY_DAYS`, `ROOM_QUOTA_MB` | Verlaufsgrenzen pro Token |
| `BIND_ADDR`, `PORT` | direkter HTTP-Port des Servers (mit nginx am besten `BIND_ADDR=127.0.0.1`) |
Ändert man `CERT_*`-Werte, wird das Zertifikat beim nächsten Start neu erzeugt. Eigene Zertifikate:
`fullchain.pem` + `privkey.pem` nach `./certs` legen und `./certs/.selfsigned` löschen.
Selbstsignierte Zertifikate in den Clients: entweder „TLS-Zertifikat prüfen“ abschalten (nur im eigenen
Netz) oder im Desktop-Client unter „Zertifikat“ die `certs/fullchain.pem` des Servers hinterlegen.
> Mit dem alten `docker-compose` (v1) funktioniert es genauso: `docker-compose up -d --build`.
## Desktop-Client (Windows, Linux, macOS)
Python + Qt (PySide6), eine Codebasis für alle drei Systeme. Läuft im System-Tray.
- **Tray-Menü:** die letzten 10 Einträge zum schnellen Einfügen, Verlauf, Pausieren, Einstellungen
- **Verlaufsfenster:** Suche, Doppelklick/Enter = in die Zwischenablage, „Speichern unter …“, Löschen
- **Einstellungen:** Server, Token (**Erzeugen**), Server-Schlüssel, Zertifikat, Gerätename, was
synchronisiert wird, Größenlimits, Autostart
- **Verbindung teilen:** *QR-Code für Android* · *Exportieren* (.netclip-Datei) · *Importieren*
- Passwort-Manager-Einträge (KeePassXC, Bitwarden, 1Password …), die als „geheim“ markiert sind, werden
nicht synchronisiert.
Empfangene Dateien/Ordner werden in den Cache entpackt
(`%LOCALAPPDATA%\NetClip\cache`, `~/Library/Caches/NetClip`, `~/.cache/netclip`) und als Datei-Referenz
in die Zwischenablage gelegt – Strg+V im Dateimanager kopiert sie dann an den gewünschten Ort.
Der Cache wird nach `keep_received_days` (Standard 7 Tage) aufgeräumt.
### Starten aus dem Quellcode
```bash
cd client-desktop
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
python -m netclip
```
### Pakete bauen
PyInstaller baut immer für das System, auf dem es läuft – also einmal je Betriebssystem:
```bash
cd client-desktop
python build.py
```
| System | Ergebnis |
|---|---|
| Windows | `dist/NetClip/NetClip.exe`, danach `packaging/windows-installer.iss` mit Inno Setup kompilieren → `dist/NetClip-Setup-1.0.0.exe` |
| macOS | `dist/NetClip.app` und `dist/NetClip-macos.zip` (Menüleisten-App ohne Dock-Symbol) |
| Linux | `dist/NetClip-linux-x86_64.tar.gz` mit `install-linux.sh` |
### Ausrollen
Kommandozeile (alle Systeme):
```bash
NetClip --configure-only --server https://clip.example.de --token XYZ [--server-key K] [--insecure] [--autostart]
NetClip --import verbindung.netclip
NetClip --show # Verlauf der laufenden Instanz öffnen – z.B. auf ein Tastenkürzel legen
```
Vorgaben für alle Benutzer: eine `config.default.json` neben die Programmdatei legen, z.B.
`{"server": "https://clip.example.de", "token": "...", "verify_tls": false}`. Sie wird beim ersten
Start jedes Benutzers übernommen (Gerätename und Geräte-ID bleiben pro Gerät eindeutig).
- **Windows (GPO/Intune/PDQ):**
`NetClip-Setup-1.0.0.exe /VERYSILENT /SUPPRESSMSGBOXES /SERVER=https://clip.example.de /TOKEN=xyz [/SERVERKEY=k] [/INSECURE=1]`
– schreibt `config.default.json` und richtet den Autostart für alle Benutzer ein.
- **Linux:** `sudo ./install-linux.sh --server https://clip.example.de --token xyz [--insecure]`
- **macOS:** `NetClip.app` nach `/Applications` kopieren, `config.default.json` nach
`NetClip.app/Contents/MacOS/` legen.
Hinweis: Wer den Token kennt, sieht die Zwischenablage. Ein gemeinsamer Token für mehrere Personen
bedeutet eine gemeinsame Zwischenablage – pro Person/Team einen eigenen Token verwenden.
### Plattform-Hinweise
- **Linux/X11:** funktioniert direkt (Dolphin, Nautilus, Nemo, Thunar, Caja).
- **Linux/Wayland:** Wayland gibt Programmen im Hintergrund keinen Zugriff auf die Zwischenablage.
NetClip nutzt dann automatisch `wl-clipboard` (`apt install wl-clipboard`). Das funktioniert unter
KDE Plasma und wlroots-Desktops (Sway, Hyprland), **nicht unter GNOME** – dort eine X11-Sitzung nutzen.
Mit `NETCLIP_BACKEND=qt` lässt sich das Qt-Backend erzwingen.
- **macOS:** beim ersten Start ggf. in den Systemeinstellungen „Öffnen“ bestätigen (unsigniert).
- **Windows:** keine Besonderheiten; Dateien werden als „Kopieren“ (nicht „Ausschneiden“) eingefügt.
## Android-Client
Kotlin, ab Android 8. Läuft als Vordergrunddienst mit dauerhafter Benachrichtigung.
- **Einrichten:** Einstellungen → *QR-Code vom PC scannen* (Desktop: Einstellungen → QR-Code für
Android) oder *.netclip-Datei importieren*. Ein `netclip://`-Link aus einer beliebigen QR-App
öffnet ebenfalls direkt die Einstellungen.
- **Empfangen:** Text und Bilder landen automatisch in der Zwischenablage. Dateien/Ordner kommen per
Benachrichtigung mit *Speichern* (→ `Download/NetClip/`, Ordnerstruktur bleibt erhalten) und *Teilen*.
- **Senden:** Android erlaubt Apps im Hintergrund nicht, die Zwischenablage zu lesen. Deshalb:
- Button *Zwischenablage senden* in der App oder in der Benachrichtigung
- Schnelleinstellungs-Kachel „Zwischenablage senden“ (Kacheln bearbeiten → hinzufügen)
- *Teilen → An NetClip senden* aus jeder App (Text, Bilder, mehrere Dateien)
- Text markieren → *An NetClip senden* im Auswahlmenü
- **Verlauf:** antippen = in die Zwischenablage; lange drücken = Speichern, Teilen, Löschen.
### Bauen
```bash
cd client-android
./gradlew assembleRelease # app/build/outputs/apk/release/app-release.apk
```
Das Release-APK ist zum Testen mit dem Debug-Schlüssel signiert; für die Verteilung in `app/build.gradle`
einen eigenen Keystore eintragen.
## Tests
```bash
# Kompatibilität der Verschlüsselung Python <-> Kotlin
python tools/interop.py gen /tmp/interop
(cd client-android && ./gradlew testDebugUnitTest -Pinterop=/tmp/interop)
python tools/interop.py check /tmp/interop
```
## Protokoll (für eigene Clients)
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | `/healthz` | Status |
| GET | `/api/v1/info` | Server-Limits |
| GET | `/api/v1/rooms/{room}/clips` | Verlauf (`id`, `ts`, `device`, `size`, `meta`) |
| POST | `/api/v1/rooms/{room}/clips` | Body: 4 Byte Länge (BE) + Meta (Base64) + verschlüsselter Blob; Header `X-Device` |
| GET | `/api/v1/rooms/{room}/clips/{id}/blob` | verschlüsselten Inhalt laden |
| DELETE | `/api/v1/rooms/{room}/clips[/{id}]` | Verlauf leeren bzw. Eintrag löschen |
| WS | `/api/v1/rooms/{room}/ws?device=…` | Ereignisse `hello`, `clip`, `deleted`, `cleared`, `devices` |
Mit `SERVER_KEY` ist bei allen `/api/`-Aufrufen `Authorization: Bearer <key>` nötig.
Verschlüsselungsformat: siehe Kopf von [client-desktop/netclip/crypto.py](client-desktop/netclip/crypto.py).