Files
pyramid/PROGRESS.md
T
Bernd Steckmeister 254be1b8da docs: M1-Bestandsaufnahme – 3 Punkte bereits vorhanden, SQLCipher-Lücke offen
Key-Backup-Flows und Geräteverwaltung waren schon implementiert (nur nicht
abgehakt). Neue Sicherheitslücke dokumentiert: sqlcipher_flutter_libs ist
eine ungenutzte Abhängigkeit, die Krypto-DB liegt unverschlüsselt vor.
Bewusst nicht blind gefixt (Migrationsrisiko für Bestandsinstallationen),
Frage an Bernd zur Priorität ergänzt.
2026-07-03 10:00:05 +02:00

13 KiB
Raw Blame History

Pyramid Arbeitsprotokoll

Neueste Einträge OBEN. Jede Claude-Session schreibt hier nach jedem abgeschlossenen Schritt (und beim Abbruch mitten im Schritt den Zwischenstand). Format:

## JJJJ-MM-TT  Kurztitel
**Erledigt:** was fertig ist (mit Commit-Hash)
**Offen/Nächster Schritt:** der konkrete nächste Handgriff
**Stolperfallen:** was schiefging und wie es gelöst wurde (damit es nie zweimal passiert)
**Fragen an Bernd:** (optional) gesammelte Richtungsfragen, die nicht blockieren

2026-07-03 M1: Restliche Punkte geprüft 3 schon vorhanden, 1 echte Lücke gefunden

Erledigt:

  • Logout-Warnung bei fehlendem Key-Backup (Commit b5762ea): neue Funktion isKeyBackupMissing(client) in bootstrap_dialog.dart (prüft Cross-Signing + keyManager.isCached()). Beide Logout-Dialoge in settings_modal.dart zeigen jetzt eine rote Klartext-Warnung statt des neutralen Textes, wenn kein Backup eingerichtet ist.
  • Drei ROADMAP-Punkte waren bereits umgesetzt (nur nicht abgehakt) durch Code-Lektüre verifiziert, nicht neu gebaut:
    • Key-Backup einrichten/wiederherstellen: bootstrap_dialog.dart deckt beides über den Bootstrap-Zustandsautomaten des matrix-SDK ab (askNewSsss für Neueinrichtung, askUnlockSsss fragt auf einem neuen Gerät nach dem Recovery-Key). Wird automatisch getriggert, wenn Cross-Signing fehlt (app_shell.dart:_triggerBootstrap).
    • Geräte-/Sessionverwaltung: _SessionsSection in settings_modal.dart Liste, Umbenennen, SAS/QR-Geräteverifizierung, Einzel- und Massen-Abmeldung (mit Passwort-Reauth bei UIA-Anforderung).
  • Echte Sicherheitslücke gefunden: sqlcipher_flutter_libs ist eine Abhängigkeit in pubspec.yaml, wird aber nirgends im Code benutzt. matrix_client.dart (Haupt-App) und background_push.dart (Push-Hintergrund) öffnen pyramid.sqlite beide über den normalen, unverschlüsselten sqflite/sqflite_common_ffi-Factory. Die Krypto-DB (Access-Token, gepickelter Olm-Account, Megolm-Sessions, komplette Nachrichtenhistorie) liegt also im Klartext auf der Platte nur durch Androids App-Sandbox geschützt, nicht durch eine eigene Verschlüsselung.

Offen/Nächster Schritt: SQLCipher-Anbindung NICHT blind auf dem Pi umgesetzt siehe Stolperfalle unten. Braucht einen eigenen, vorsichtig geplanten PC-Termin: Backup der Test-DB, Migrationscode (bestehende Klartext-DB einmalig nach SQLCipher überführen), Test auf einem Gerät mit echten Daten, erst dann Rollout.

Fragen an Bernd:

  • Priorität der SQLCipher-Lücke: Soll das vor M2 (Refactoring) angegangen werden, oder reicht die App-Sandbox als Schutz erstmal aus (Angreifer bräuchte Root oder physischen Zugriff + ADB, um die Datei überhaupt zu lesen)? Die Migration bestehender Installationen (Uta!) ist der aufwändige/riskante Teil, nicht die Verschlüsselung selbst.

Stolperfallen:

  • Eine DB-Verschlüsselungs-Migration ist genau die Art Änderung, die laut CLAUDE.md nicht "mal eben" auf dem Pi ohne Testgerät gemacht werden darf: scheitert die Migration (falscher Schlüssel, falsche PRAGMA-Reihenfolge, Timing zwischen Haupt-App und Push-Hintergrund-Client), sind Utas Nachrichten und Krypto-Schlüssel unwiederbringlich weg. Deshalb hier nur dokumentiert, nicht implementiert.

2026-07-03 M1: Push-Regression vermutlich dieselbe Ursache wie Random-Logout

Erledigt: Vor dem Blick in den Push-Code die Vermutung geprüft, ob die Push-Entschlüsselungs-Regression und der Uta-Random-Logout-Bug (siehe Eintrag weiter unten) zusammenhängen Ergebnis: sehr wahrscheinlich ja, exakt dieselbe Ursache.

  • client.getEventByPushNotification(...) (aufgerufen in _bgDecryptAndShow, background_push.dart:84) ruft als ALLERERSTES ensureNotSoftLoggedOut() auf (matrix-Paket client.dart:1878). Diese Funktion prüft, ob der Access-Token in < 1 Minute abläuft, und löst dann _handleSoftLogout() aus — dieselbe Funktion, die ohne Refresh-Token (unser Zustand vor Commit 9dc83f7) sofort einen echten client.logout() auslöst (siehe Eintrag unten).
  • Der Hintergrund-Client aus _buildClient() liest dieselbe pyramid.sqlite wie der Haupt-Client. Ein logout()/clear() aus dem Hintergrund-Isolat würde also die komplette Session (inkl. Krypto-Schlüssel) für die GESAMTE App zerstören nicht nur für den einen Push. Das erklärt, warum das Problem als dauerhafte Regression erscheint ("seit dem letzten Update nie wieder"): Nach dem ersten Auto-Logout-Ereignis (ausgelöst beim Sync ODER beim Entschlüsseln eines Pushs) sind die Schlüssel weg, jede folgende Entschlüsselung schlägt fehl → BgEngine zeigt nur noch den „Neue Nachricht"-Platzhalter (Fallback nach 6 s), nie mehr den echten Text.
  • Der bereits committete Fix (refreshToken: true beim Login, 9dc83f7) behebt damit vermutlich BEIDE Symptome gleichzeitig: der Refresh-Token liegt in der gemeinsamen DB, also kann auch der Hintergrund-Client ihn lesen und einen drohenden Soft-Logout durch stillen Refresh abwenden, statt die Session zu zerstören.

Offen/Nächster Schritt: Gehört zum selben Praxistest wie der Random-Logout-Punkt oben zusätzlich beobachten, ob nach einer Weile (mehrere Stunden/Tage) echte Push-Inhalte statt Platzhalter ankommen. Schlägt das fehl, liegt eine zweite, unabhängige Ursache vor (dann docs/NOTIFICATIONS.md

  • Memory „Pyramid Push" erneut konsultieren, insbesondere die 3 dort gelisteten Fallstricke der Hintergrund-Entschlüsselung).

Stolperfallen: Diese Verbindung wurde rein durch Lesen des matrix-SDK- Quellcodes hergeleitet (~/.pub-cache/hosted/pub.dev/matrix-6.2.0/lib/src/client.dart), nicht durch Beobachtung auf einem echten Gerät bewusst als Vermutung markiert, bis der PC-Praxistest sie bestätigt.


2026-07-03 M1: Uta-Random-Logout Ursache gefunden + Fix (UNGETESTET/Pi)

Erledigt:

  • Alle Logout-Auslöser im Code kartiert:
    • 3 bewusste Nutzer-Logout-Buttons in settings_modal.dart (alle hinter Bestätigungsdialog) kein Kandidat für "random"
    • Der eigentliche Verdächtige: matrix-Paket (v6.2.0) Client._innerSync() behandelt M_UNKNOWN_TOKEN vom /sync-Endpunkt so: bei soft_logout: true_handleSoftLogout() → versucht refreshAccessToken()das SDK hatte nie einen Refresh-Token angefordert (client.login(...) in login_notifier.dart rief ohne refreshToken: true auf) → refreshAccessToken() wirft sofort "No refresh token available" → Catch-Block ruft await logout() auf: ein echter, destruktiver Logout, ausgelöst rein durch einen normalen Soft-Logout (z. B. abgelaufenes Access-Token), ganz ohne Nutzerinteraktion. Quelle: ~/.pub-cache/hosted/pub.dev/matrix-6.2.0/lib/src/client.dart:2374-2384 und :2496-2509.
  • Logging (Commit 63e4919): neue lib/core/auth_log.dart schreibt jeden Login-Status-Wechsel (client.onLoginStateChanged) sowie SDK-Warnungen/-Fehler (Logs().onLog) in auth_log.txt im App-Support-Verzeichnis übersteht App-Neustart. Zusätzlich loggen alle 3 Nutzer-Logout-Buttons sich selbst, damit sich künftig unterscheiden lässt: Nutzer-Logout vs. SDK-Auto-Logout. Reine Zusatzfunktion, keine Verhaltensänderung.
  • Fix (Commit 9dc83f7): client.login(...) fordert jetzt refreshToken: true an. Damit kann das SDK einen Soft-Logout künftig durch stillen Token-Refresh überstehen, statt die Sitzung zu zerstören. Unterstützt der Server keine Refresh-Tokens, bleibt das Verhalten exakt wie vorher (response.refreshToken ist dann null) der Fix kann also nichts verschlimmern.

Offen/Nächster Schritt:

  1. Praxistest auf dem PC (zwingend vor Haken in ROADMAP!): Login → Nachrichten senden/lesen → Logout → erneuter Login → alte verschlüsselte Nachrichten noch lesbar? Dabei prüfen, ob auth_log.txt (App-Support-Verzeichnis) die Login-Status-Wechsel sauber mitschreibt.
  2. Danach: den nächsten Punkt in M1 angehen (Push-Entschlüsselungs-Regression).
  3. Wichtig für Bernd/Uta: Der Fix wirkt nur für NEUE Logins. Utas bereits bestehende Sitzung bekommt erst nach einem einmaligen manuellen Neu-Login einen Refresh-Token und ist bis dahin weiterhin anfällig. Sobald der PC-Test grün ist, sollte Uta sich einmal aus- und wieder einloggen.

Stolperfallen:

  • Konnte auf dem Pi nicht mit echtem Login/Logout getestet werden (kein GUI, kein Matrix-Testaccount zur Hand) Fix beruht auf genauem Lesen des matrix-SDK-Quellcodes, nicht auf Beobachtung im Betrieb. Deshalb zwingend vor dem nächsten Haken in ROADMAP am PC nachprüfen.
  • chat_provider.dart:42 nutzt weiterhin das deprecated Timeline.onUpdate (Re-Entschlüsseln nach Schlüssel-Empfang) hängt mit demselben Sync-Bereich zusammen, aber bewusst nicht angefasst, um nicht zwei riskante Änderungen im selben Bereich gleichzeitig ungetestet zu committen.

2026-07-03 M0 abgeschlossen: Ordnung, flutter analyze sauber, README

Erledigt:

  • Liegen gebliebene Deprecation-Fixes aus einer abgebrochenen Session committet (withOpacitywithValues, activeColoractiveThumbColor, cacheExtentScrollCacheExtent, PublicRoomsChunkPublishedRoomsChunk) Commit 057ac1e
  • Restliche flutter analyze-Hinweise behoben Commit 401bd6a:
    • document_viewer.dart: Matrix4.translate/scaletranslateByDouble/ scaleByDouble (PDF-Zoom, gleiches Verhalten)
    • rooms_panel.dart: onReorderonReorderItem (Index-Korrektur jetzt intern, manuelles newIdx-- entfernt); implementation_imports-Hinweis kommentiert (SpaceChild wird vom matrix-Paket nicht öffentlich exportiert, kein Fix möglich)
    • voip_manager.dart: getSources()-Override kommentiert (Pflicht-Override der abstrakten MediaDevices-Klasse, die die Methode selbst deprecated hat)
    • settings_modal.dart: zwei BuildContext-nach-await-Stellen mit context.mounted abgesichert (Geräte umbenennen, Passwortabfrage bei Massenlogout)
    • Bewusst NICHT gefixt: chat_provider.dart:42 (Timeline.onUpdate deprecated, Ersatz wäre client.onSync + Raum-Filter). Hängt am E2EE-Redecrypt-Pfad (Re-Entschlüsseln nach Schlüssel-Empfang) laut CLAUDE.md heiliger Bereich, Umbau nur mit dediziertem Login→Nachrichten→Logout→Login-Test, nicht nebenbei.
  • lib/features/calls/ (Leiche) geprüft: existiert nicht mehr, nur lib/features/call/ mit den echten Dateien Punkt war bereits erledigt, nur nicht abgehakt.
  • README.md durch echte Projektbeschreibung ersetzt (Funktionsumfang, Build, Struktur) Commit 74d38fd
  • ROADMAP.md: M0 komplett abgehakt.

Offen/Nächster Schritt: M1, erster Punkt Uta-Random-Logout-Bug untersuchen (Logging an allen Logout-Pfaden einbauen, dann Ursache finden). Direkt danach die Push-Entschlüsselungs-Regression (docs/NOTIFICATIONS.md + Memory „Pyramid Push" vorher lesen).

Stolperfallen:

  • Kein test/-Ordner vorhanden → flutter test läuft ins Leere, keine automatisierte Absicherung. flutter analyze lief sauber (0 Fehler/Warnungen), aber die Lint-Fixes in document_viewer.dart (PDF-Zoom) und rooms_panel.dart (Drag-Reorder der Raumliste) sind UNGETESTET in echter UI nächster Windows-Lauf sollte kurz PDF-Zoom und Raum-Umsortieren per Drag prüfen.
  • Der ignore:-Kommentar für einen deprecated-Aufruf muss auf der Zeile unmittelbar über der betroffenen Codezeile stehen, nicht nur "in der Nähe" sonst wirkt er nicht (bei voip_manager.dart erst falsch über @override gesetzt, dann korrigiert).

2026-07-03 Arbeitsstruktur angelegt + Vollbackup (Setup, noch kein Code)

Erledigt:

  • Vollbackup inkl. Git-Historie: MatrixPi\backups\pyramid-kopie_backup_2026-07-03.tar.gz (510 MB)
  • CLAUDE.md (Arbeitsregeln), ROADMAP.md (M0M7 nach Bernds Prioritäten), dieses Protokoll
  • Klargestellt: C:\Users\nordm\pyramid - Kopie ist das EINZIGE aktuelle Repo; C:\Users\nordm\pyramid und MatrixPi\pyramid sind veraltete April-Stände (Commit c9af913)

Offen/Nächster Schritt: M0, Punkt 2 die ~140 uncommitteten Dateien mit git status sichten und in thematische Commits aufteilen (diese drei neuen Dateien mit committen), dann git push origin master.

Stolperfallen:

  • Letzter Commit ist vom 2026-04-28 (d706ace), gearbeitet wurde aber bis mindestens 2026-06-12 → zwischen Commits und Realität liegen 6 Wochen. Genau deshalb: ab jetzt kleine Commits nach jedem Schritt.
  • Git-Remote (Gitea auf dem Pi) enthält Zugangsdaten in der URL funktioniert, aber nur erreichbar, wenn der Pi läuft (unterwegs: WireGuard nötig).