first commit
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
# 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).
|
||||
Reference in New Issue
Block a user