Files
ThreadNet-Web/docs/axion1337-fork.md
T
Thore Cimbal 965c456dee Doku: Merge-Risiko praeziser fassen - Art des Eingriffs, nicht Umfang
Meine Aussage "ClamAV kostet mehr als das gesamte Branding zusammen" war so nicht haltbar: gemessen sind es ~130 zu ~104 Zeilen, der groesste Einzelpatch ist sogar Branding (HelpUserSettingsTab.tsx, 71 Zeilen).

Der Unterschied liegt woanders: Branding-Patches stehen am Rand und sind nach einem Umbau wiederfindbar, ClamAV-Patches stehen mitten in Entschluesselungs- und Fehlerpfaden. Dazu der eigentliche Haken - verschiebt Upstream die viewmodels/-Dateien, entsteht kein Konflikt, die Zeilen sind schlicht weg und Git meldet nichts. Deshalb ist dort ein Funktionstest maszgeblich, nicht die Merge-Ausgabe.

Refs axion1337.chat/ThreadNet-Web#7
2026-08-06 12:00:00 +00:00

8.5 KiB

ThreadNet-Web: Fork-Anpassungen für axion1337.chat

Dieses Dokument beschreibt alles, was dieser Fork gegenüber Upstream Element Web ändert. Der Rest der docs/-Ordner-Dateien und das Root-README.md sind unverändertes Upstream-Material und beschreiben absichtlich nicht diese Anpassungen - diese Datei ist der zentrale Anlaufpunkt dafür.

1. Discord-Style Room-List (Call-Teilnehmer in der Raumliste)

Zeigt aktive Call-Teilnehmer direkt in der Raumliste an (ähnlich Discords Voice-Channel-UI), statt nur einen generischen "Call läuft"-Indikator. Betroffene Komponenten: apps/web/src/room-list/RoomListItemView/RoomListItemView.tsx und RoomListItemView.module.css (vertikale Ausrichtung der Teilnehmer-Avatare).

2. Client-seitiges ClamAV-Content-Scanning (Issue #19-Erweiterung)

Der Server-seitige Content-Scanner (Synapse-Modul, siehe gitops-Repo docs/deployment-guides/06-moderation-content-scanning.md) sieht bei Ende-zu-Ende-verschlüsselten Räumen nur Ciphertext - eine strukturelle Grenze, kein Bug. Da dieser Client bereits geforkt wird, scannt er stattdessen selbst, auf beiden Seiten:

  • Senden (apps/web/src/ContentMessages.ts, uploadFile()): liest die Datei als ArrayBuffer, scannt sie über scanContent() bevor verschlüsselt/hochgeladen wird - der Upload wird bei Treffer gar nicht erst gestartet.
  • Empfangen (apps/web/src/utils/DecryptFile.ts, decryptFile()): scannt die entschlüsselten Bytes direkt nach dem Entschlüsseln, bevor das Blob an die UI zurückgegeben wird - schützt auch vor Dateien von unveränderten/fremden Matrix-Clients, die diesen Patch nicht haben.
  • Gemeinsame Scan-Logik: apps/web/src/utils/ContentScanner.ts - ruft den (im gitops-Repo deployten) clamav-http-scanner-Dienst per fetch("/_scan", ...) auf, mit dem eigenen Matrix-Access-Token als Bearer-Auth. Fail-open bei Netzwerk-/Scanner-Fehlern (blockiert Uploads/Downloads nicht bei einem Ausfall des Scanners).
  • Neuer Fehlertyp ContentScanRejectedError, verdrahtet durch die bestehenden Fehler-Rendering-Pfade in MImageBody.tsx, MAudioBody.tsx, VideoBodyViewModel.ts, FileBodyViewModel.ts.
  • Live getestet inkl. Hostile-Sender-Simulation (Datei per rohem API-Call ohne diesen Patch gesendet, Empfangs-Hook hat trotzdem geblockt).

⚠️ Bekannte Lücke: Electron/Desktop (Issue #2)

Dieser Fix ist bestätigt nur für den Web-Client-Build wirksam. Der Electron-Desktop-Client bekommt ihn aktuell nicht automatisch - die CI-Workflow-Kette (build_ew-Job) checkt weiterhin element-hq/element-web (Upstream) statt diesen Fork aus, und es ist kein GitHub- Actions-Runner für dieses Repo registriert. Der aktuell veröffentlichte Desktop-Build (desktop-v1.12.17-clientscan Release) wurde manuell gebaut, nicht automatisiert. Details und Fix-Plan: Issue #2.

3. Build-Fixes (historisch, Issue #12)

Zwei Bugs blockierten einen vollständigen docker build von Grund auf (mussten für den Client-Scanning-Rebuild oben behoben werden): (1) mehrere Shell-Skripte waren mit Modus 644 statt 755 committet (nicht ausführbar); (2) der matrix-js-sdk#develop-Git-Ref-Pin in pnpm-lock.yaml war veraltet (fehlte src/oidc/authorize.ts, das apps/web importiert). Beide behoben.

4. Merge-Reibung: was ein Upstream-Update wirklich kostet

Arbeitspaket 3 aus ThreadNet-Web#7. Gemessen am 2026-08-06, nicht geschätzt.

Die unangenehme Grundlage zuerst

Dieses Repo enthält keine Upstream-Historie. Element Web 1.12.17 wurde am 2026-05-10 als kompletter Baum importiert — und zwar in 3da3635, zusammen mit dem ersten eigenen Feature im selben Commit. Davor liegt nur ein Initial commit mit zwei Dateien.

Daraus folgt das Wesentliche: es gibt keinen gemeinsamen Vorfahren mit element-hq/element-web. Ein git merge upstream/develop ist nicht möglich; mit --allow-unrelated-histories erzwungen, kollidiert praktisch jede Datei. Wer „mal eben Upstream nachziehen" sagt, meint in diesem Repo also: neuen Upstream-Stand beschaffen und unsere Änderungen darauf neu auftragen.

Das ist der Grund, warum die Zahl unten überhaupt zählt — sie ist der Aufwand jedes Updates.

Unser Delta: 102 Dateien, davon 12 kritische

git diff --name-only 3da3635..main:

Menge Bereich Konfliktrisiko
46 CI/Build (.github/, .gitlab-ci.yml, dockerbuild/) gering — eigene Strecke, Upstreams Workflows brauchen wir nicht
22 Config, Lockfiles, Upstream-Varianten mittel — pnpm-lock.yaml konfliktet immer, wird aber regeneriert
13 Web-Assets (apps/web/res/) gering — meist eigene Dateien
4 + 3 eigene Icons und apps/desktop/axion1337/ keins — kein Upstream-Pendant
12 Upstream-Quellcode hier entsteht die Arbeit

Die 12 Dateien, und warum sie angefasst wurden

Branding (5) — flach, gut isolierbar:

  • apps/web/src/SdkConfig.ts — Defaults für brand, welcome_background_url, desktopBuilds
  • apps/web/src/vector/index.html<title>, Favicon-Link, PWA-Namen
  • apps/web/src/async-components/structures/ErrorView.tsx — Logo der Fehlerseite
  • apps/web/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx — Attribution + Danksagung
  • apps/web/src/i18n/strings/en_EN.json — einzelne Strings

ClamAV-Client-Scanning (7) — tief in der Medien-Pipeline:

  • apps/web/src/ContentMessages.ts, utils/ContentScanner.ts, utils/DecryptFile.ts
  • apps/web/src/components/views/messages/MImageBody.tsx, MAudioBody.tsx
  • apps/web/src/viewmodels/message-body/FileBodyViewModel.ts, VideoBodyViewModel.ts

Nicht der Umfang entscheidet, sondern die Art des Eingriffs

Gemessen in geänderten Zeilen nehmen sich beide Gruppen wenig: ClamAV ~130 Zeilen, Branding ~104. Der größte Einzelpatch ist sogar Branding (HelpUserSettingsTab.tsx, 71 Zeilen). Wer nur zählt, hält beide für gleich teuer.

Sie sind es nicht, und der Grund ist die Art des Eingriffs:

  • Branding-Patches stehen am Rand. Ein zusätzlicher Default in SdkConfig.ts, ein <link> im <head>, ein <li> in einer Settings-Liste. Wird die Datei umgebaut, sieht man sofort, wo das eigene Stück wieder hin muss.
  • ClamAV-Patches stehen mittendrin — in Entschlüsselungs- und Fehlerpfaden der Medien-Pipeline, verschränkt mit Upstream-Logik. Ein geänderter Kontrollfluss bedeutet nicht „Konflikt lösen", sondern „neu verstehen".

⚠️ Und der eigentliche Haken: viewmodels/. Element baut die Medien-Anzeige gerade auf MVVM um (docs/MVVM.md; v1 ist dort bereits als deprecated markiert — der Umbau läuft also schon in zweiter Runde). FileBodyViewModel.ts und VideoBodyViewModel.ts gab es in älteren Ständen gar nicht. Unsere Änderung darin ist mit je 6 Zeilen winzig — aber wenn Upstream diese Dateien verschiebt, umbenennt oder auflöst, entsteht kein Konflikt: die Zeilen sind einfach weg, und Git meldet nichts. Das ist gefährlicher als ein Konflikt, weil es stillschweigend passiert.

Praktische Folge: Nach einem Upstream-Update ist an ClamAV nicht die Merge-Ausgabe maßgeblich, sondern ein Funktionstest — eine verschlüsselte Datei senden und eine abgelehnte empfangen. Steht so auch in Abschnitt 2.

Was daraus für künftige Änderungen folgt

  1. Erst prüfen, ob es die Konfiguration schon kann. Auth-Logo, logo_link_url und brand liefen ohne Rebuild über die ConfigMap; das Call-Widget wurde vollständig über VITE_PRODUCT_NAME umbenannt, ohne eine einzige Quelldatei. Jede so vermiedene Datei ist eine, die beim Update nicht kollidiert.
  2. Eigene Datei schlagen geänderte Datei. apps/desktop/axion1337/ und eigene Assets kosten beim Merge nichts.
  3. Wenn Upstream-Code sein muss: einen Kommentar mit ThreadNet-Fork: und der Begründung dazu. Beim Neuauftragen auf einen neuen Stand ist die Frage nie „was steht hier", sondern „warum stand das da" — und die beantwortet sonst niemand mehr.

Repo-Topologie (seit 2026-07-31)

Kanonisch ist git.lab/axion1337.chat/ThreadNet-Web (Homelab-GitLab, nur im Lab auflösbar) — dort laufen Entwicklung und CI (.gitlab-ci.yml). Die Kopie auf rohana.axion1337.de/sorb/ThreadNet-Web ist ein Push-Mirror (automatisch, GitLab → Gitea) und dient als Lesekopie plus Standort für Issues, Container-Registry und Releases. Niemals direkt nach rohana pushen — der Mirror überschreibt divergente Stände.