chore(coturn): automated TURN shared-secret rotation #46

Closed
sorb wants to merge 76 commits from turn-secret-rotation-20260801-020001 into main
Showing only changes of commit 3e147554eb - Show all commits
@@ -126,7 +126,66 @@ schließt genau diesen Callback explizit aus), daher selbst geschrieben.
Grenze: Synapse hat bei E2EE nie den Entschlüsselungsschlüssel, sieht nur Ciphertext. Nur Grenze: Synapse hat bei E2EE nie den Entschlüsselungsschlüssel, sieht nur Ciphertext. Nur
ein kooperierender Client könnte das lösen (siehe oben, existiert nicht offen verfügbar). ein kooperierender Client könnte das lösen (siehe oben, existiert nicht offen verfügbar).
**Bekannte Deckungslücke**: schützt nur unverschlüsselte Räume/DMs (viele öffentliche/ **Bekannte Deckungslücke (Stand vor der Client-Erweiterung unten)**: schützt nur
föderierte Räume) - keine Warnung/Kennzeichnung für Nutzer in verschlüsselten Räumen, dass unverschlüsselte Räume/DMs - keine Warnung/Kennzeichnung für Nutzer in verschlüsselten
dort kein Scanning stattfindet. Folgeidee (Issue #43, LOW): Grafana-Dashboard über die Räumen, dass dort kein Scanning stattfindet. Folgeidee (Issue #43, LOW): Grafana-Dashboard
bestehenden Loki-Logs, um Erkennungen/Scanner-Ausfälle sichtbar zu machen. über die bestehenden Loki-Logs, um Erkennungen/Scanner-Ausfälle sichtbar zu machen.
## 3. Client-seitiges Scanning für verschlüsselte Räume (Issue #19-Erweiterung, 2026-07-29)
Da Synapse bei E2EE-Räumen strukturell nie den Schlüssel hat, kann nur der **Client**
Klartext scannen - einmal beim Senden (vor der Verschlüsselung), einmal beim Empfangen
(nach der Entschlüsselung). Umgesetzt in `ThreadNet-Web` (Fork von Element Web).
### Architektur
Ein neuer, eigener HTTP-Dienst (`apps/production/clamav-http-scanner.py`, eigenes Image via
`clamav-http-scanner-Dockerfile`) macht denselben ClamAV-Pod für Browser-JS erreichbar
(clamd spricht nur rohes TCP, das kann ein Browser nicht). Erreichbar unter
`https://axion1337.chat/_scan`. Auth über Synapses eigenen
`/_matrix/client/v3/account/whoami`-Endpunkt (kein eigenes Auth-System nötig) - verhindert,
dass der Dienst zu einem offenen "teste dein Malware gegen unseren Virenscanner"-Orakel für
das ganze Internet wird. Fail-open bei Scanner-Fehlern, wie beim Synapse-Modul.
**Zwei Patch-Stellen im `ThreadNet-Web`-Fork** (im Repo
`rohana.axion1337.de/sorb/ThreadNet-Web.git`, nicht in diesem gitops-Repo):
- **Empfang**: `apps/web/src/utils/DecryptFile.ts`, Funktion `decryptFile()` - der einzige
Punkt im ganzen Client, an dem entschlüsselte Klartext-Bytes für *jeden* Anhangstyp
entstehen (Bild/Audio/Video/Datei laufen alle über `MediaEventHelper` hier durch). Scan
direkt nach dem Entschlüsseln, vor der Rückgabe als `Blob`.
- **Versand**: `apps/web/src/ContentMessages.ts`, Funktion `uploadFile()` - die eine
gemeinsame Funktion für alle Anhangs-Uploads (Hauptdatei, generierte Thumbnails,
Sprachnachrichten), unabhängig davon ob der Zielraum verschlüsselt ist. Scan direkt nach
dem Einlesen der Datei, vor Verschlüsselung/Upload.
- Gemeinsame Hilfsdatei: `apps/web/src/utils/ContentScanner.ts` (neue `scanContent()`-
Funktion + `ContentScanRejectedError`), von beiden Stellen genutzt. Fehlertexte über die
bereits bestehenden Error-Rendering-Pfade in `MImageBody.tsx`/`MAudioBody.tsx`/
`VideoBodyViewModel.ts`/`FileBodyViewModel.ts` (gleiches Muster wie die schon vorhandenen
`DecryptError`/`DownloadError`).
**Live getestet** (2026-07-29): EICAR in verschlüsseltem Gruppenraum ("testgruppe") und in
1:1-DMs zwischen zwei echten Accounts - in beiden Fällen zuverlässig **vor dem Upload**
blockiert. Vorher (nur Synapse-Modul) lief das durch.
### ⚠️ Wichtig für zukünftige Desktop-/Electron-Forks
**Dieser Fix gilt nur für den Web-Client (Browser), nicht automatisch für Element Desktop.**
Element Desktop (`apps/desktop` im selben Monorepo) ist ein Electron-Wrapper, der die
Web-App nicht selbst baut, sondern per `scripts/fetch-package.ts` ein fertiges,
**offiziell von `element-hq/element-web` signiertes Release-Tarball** herunterlädt und in
ein `webapp.asar` packt (`pnpm run fetch``pnpm run asar-webapp`). Ohne weitere Änderung
würde ein Desktop-Build also die **unveränderte Upstream-Version** bündeln - unsere Patches
wären nicht drin, obwohl sie im selben Monorepo liegen.
**Für einen zukünftigen Desktop-Fork mit dieser Funktion**: `fetch-package.ts` akzeptiert
bereits eine beliebige URL statt einer Versionsnummer als Override
(`targetVersion.includes("://")`-Zweig, keine Code-Änderung nötig) - man müsste nur unseren
eigenen `apps/web`-Build als `.tar.gz` irgendwo selbst hosten (z.B. als Gitea-Release-Asset)
und `pnpm run fetch https://.../unser-build.tar.gz` statt der Standard-Versionsnummer
aufrufen.
**Element X (Mobile, iOS/Android)** ist davon komplett unberührt - eigene Codebasis auf
Basis von `matrix-rust-sdk`, kein gemeinsamer Code mit `ThreadNet-Web`. Ein Schutz dort
wäre ein separates, eigenständiges Projekt.