# 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-.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--windows-setup.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. ## Release erstellen Die Version steht zentral in der Datei `VERSION`. Neue Änderungen kommen laufend in `CHANGELOG.md` unter `## [Unreleased]`. Ein Release: ```bash python3 scripts/release.py # 1.0.0 -> 1.0.1 (patch), committen + taggen python3 scripts/release.py minor --build # 1.0.1 -> 1.1.0 und alle Pakete bauen python3 scripts/release.py --build-only # aktuellen Stand nur bauen git push --follow-tags ``` Das Skript schreibt die neue Version in Server, Desktop-Client, Windows-Installer und Android-App (`versionName`, `versionCode` +1) und macht aus `[Unreleased]` den neuen Versionsabschnitt. Mit `--build` wird ausschließlich in Docker gebaut (`docker-build/`), Ergebnis in `releases/v/`: | Datei | Inhalt | |---|---| | `NetClip--windows-setup.exe` | Windows-Installer (Inno Setup, unter Wine gebaut) | | `NetClip--windows-portable.zip` | Windows ohne Installation | | `NetClip--linux-x86_64.tar.gz` | Linux (Debian 12 / glibc ≥ 2.36 und neuer) | | `NetClip-.apk` | Android | | `netclip-server-.tar.gz` | Server-Image für `docker load -i …` (offline verteilbar) | | `RELEASE-NOTES.md`, `SHA256SUMS` | Änderungen und Prüfsummen | macOS kann nicht in Docker gebaut werden – dafür auf einem Mac in `client-desktop/` `python build.py`. Mit `--targets windows,android` lassen sich einzelne Pakete bauen. **Android-Signatur:** Beim ersten Android-Build wird `secrets/netclip-release.jks` erzeugt (nicht im Git). Diesen Ordner sichern – ohne den Schlüssel lassen sich installierte Apps nicht mehr aktualisieren. ## 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 ` nötig. Verschlüsselungsformat: siehe Kopf von [client-desktop/netclip/crypto.py](client-desktop/netclip/crypto.py).