5.6 KiB
title, description, published, date, tags, editor, dateCreated
| title | description | published | date | tags | editor | dateCreated |
|---|---|---|---|---|---|---|
| Moderation & Content-Scanning | Draupnir-Moderationsbot + ClamAV | true | 2026-08-13T18:04:36.999Z | markdown | 2026-08-13T18:04:36.999Z |
Status: ✅ Draupnir deployed (2026-07-29, Closes Issue #18) | ✅ Content Scanner deployed + live getestet (2026-07-29, Closes Issue #19)
Konfiguration: apps/production/draupnir*.yaml, apps/production/clamav*.yaml, apps/production/clamav_spam_checker.py
1. Draupnir (Moderationsbot)
Community-Nachfolger von Mjolnir. Läuft als eigener Bot-Account (@draupnir:axion1337.chat),
verwaltet Ban-Listen ("Policy Rooms") und setzt sie in geschützten Räumen durch.
Bot-Account & Zugriff (Bootstrap)
Authentifizierung läuft über MAS (kein klassisches registration_shared_secret):
kubectl exec -it -n matrix deploy/matrix-stack-matrix-authentication-service -- \
mas-cli manage register-user draupnir --yes
kubectl exec -it -n matrix deploy/matrix-stack-matrix-authentication-service -- \
mas-cli manage issue-compatibility-token draupnir
Token wird manuell per sops apps/production/draupnir-secret.yaml eingetragen.
Stolpersteine (live gefunden)
gnuxie/draupnir:v2.9.0crasht mitinitialManager("Can't join remote room..."). Die automatische Management-Room-Erstellung funktioniert erst ab v3.1.0 - deployt.- v3.x braucht ein explizites CLI-Argument statt
NODE_CONFIG_DIR-Autodiscovery:args: ["bot", "--draupnir-config", "/data/config/default.yaml"]. - NetworkPolicy:
matrix-stack-synapseroutet über haproxy, dessen Ingress-Policy standardmäßig nur Traefik erlaubt - eigenepodSelector-Ausnahme für Draupnir nötig.
Verschlüsselter Management-Room
Standardmäßig unverschlüsselt. Mit experimentalRustCrypto: true (Hersteller-Warnung: "not
considered production safe", in unserem Test aber fehlerfrei) + manuellem Aktivieren der
Raumverschlüsselung in Element (wirkt nicht rückwirkend auf bereits erstellte Räume).
Befehle (Kurzreferenz)
| Befehl | Zweck |
|---|---|
status |
Bot-Status |
rooms add <room> |
Raum unter Schutz stellen (Voraussetzung für Bans!) |
list create <shortcode> <alias> |
Neue Policy-Liste (automatisch beobachtet + geschützt) |
ban <user> <liste> <grund> |
2. Argument = Policy-Liste, NICHT der Ziel-Raum |
kick <user> <room> <grund> |
Direkter Kick ohne Listen-Umweg |
rules |
Regeln einer Policy-Liste anzeigen |
Live getestet (2026-07-29): Testraum geschützt, Policy-Liste angelegt, Testnutzer über
ban+Liste erfolgreich entfernt. Kernmechanismus bestätigt funktionsfähig.
2. Content Scanner (Issue #19)
Verworfen: matrix-content-scanner-python ist ein Proxy, den der Client explizit
statt der normalen Media-Endpunkte aufrufen muss - weder aktuelles Element Web noch Element X
unterstützen das (geprüft: kein Hook im offenen element-x-android-Repo). Element hat echtes
serverseitiges Scanning nur in der kommerziellen Element Pro + ESS Pro-Kombination.
Umgesetzt: eigenes, kleines Synapse-Modul (clamav_spam_checker.py) nutzt Synapses
echten check_media_file_for_spam-Hook - serverseitig, transparent für jeden Client, kein
fertiges Modul dafür existiert (synapse-http-antispam schließt genau diesen Callback aus).
ClamAV als eigener Pod, Modul per ConfigMap + PYTHONPATH gemounted (kein Custom-Image).
Spricht ClamAVs INSTREAM-Protokoll über Twisted-Primitives, nicht asyncio - Synapse
läuft auf Twisteds Reactor, ein erster asyncio-Versuch schlug live mit
RuntimeError: no running event loop fehl (Fail-Open verschleierte das zunächst - EICAR kam
durch). Fail-open bei Scanner-Fehlern bleibt so: ClamAV-Ausfall blockiert nicht alle Uploads.
Live getestet (2026-07-29): normale Datei unverschlüsselt → durchgelassen; EICAR unverschlüsselt → zuverlässig blockiert.
3. Client-seitiges Scanning für verschlüsselte Räume (Erweiterung, 2026-07-29)
Synapse hat bei E2EE nie den Schlüssel - nur der Client kann Klartext scannen. Neuer
HTTP-Dienst clamav-http-scanner.py macht ClamAV für Browser-JS erreichbar
(https://axion1337.chat/_scan, Auth via Synapses eigenem /whoami, Fail-open). Zwei
Patch-Stellen im ThreadNet-Web-Fork:
- Empfang:
apps/web/src/utils/DecryptFile.ts(decryptFile()) - einziger Punkt für alle Anhangstypen. - Versand:
apps/web/src/ContentMessages.ts(uploadFile()) - eine Funktion für alle Uploads (Datei, Thumbnails, Sprachnachrichten).
Live getestet: EICAR in verschlüsseltem Gruppenraum + 1:1-DMs vor Upload blockiert. Zusätzlich Empfangsseite unabhängig vom Absender bestätigt: EICAR über einen echten, ungepatchten Client (app.element.io) in denselben Raum geschickt - beim Download im gepatchten Client greift der Scanner trotzdem.
Wichtig, korrigiert: gilt bestätigt für den Web-Client. Für Electron/Desktop
unklar bzw. nicht automatisch - apps/desktop hat zwar einen webapp-artifact-Mechanismus,
der den eigenen Fork-Build übernehmen würde, aber keinen laufenden CI-Runner, und der
Build-Job checkt noch das Upstream-Repo aus. Die existierende Desktop-Build (mit der
Discord-Style-Raumliste) kam aus einem manuellen, nicht wiederholten Build. Neues Issue:
#44. Element X (Mobile)
komplett unberührt, eigene Codebasis.
Folgeidee (LOW): Issue #43
- Grafana-Dashboard über die bestehenden Loki-Logs für Erkennungen/Scanner-Ausfälle.
Details: Element-Customization und docs/deployment-guides/06-moderation-content-scanning.md.