From 16561bbdeb352e5458c4a1de3a0e63f728dc4752 Mon Sep 17 00:00:00 2001 From: Bernd Steckmeister Date: Fri, 3 Jul 2026 17:50:58 +0200 Subject: [PATCH] docs: SQLCipher-Migrationsplan + konsolidierter PC-Testplan (M1-Vorbereitung) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die zwei obersten offenen ROADMAP-Punkte sind PC-only in der Umsetzung, aber jetzt maximal vorbereitet: docs/SQLCIPHER_MIGRATION.md (gegen beide DB-Öffnungsstellen und matrix-6.2.0 verifiziert, inkl. Push-Isolate-Falle und Migration-Race) und docs/PC_TESTPLAN.md (alle UNGETESTET(Pi)-Punkte aus 7 verstreuten PROGRESS-Einträgen an einer Stelle). Co-Authored-By: Claude Fable 5 --- CHANGES.md | 9 +++ PROGRESS.md | 35 ++++++++++ ROADMAP.md | 8 ++- docs/PC_TESTPLAN.md | 103 +++++++++++++++++++++++++++++ docs/SQLCIPHER_MIGRATION.md | 125 ++++++++++++++++++++++++++++++++++++ 5 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 docs/PC_TESTPLAN.md create mode 100644 docs/SQLCIPHER_MIGRATION.md diff --git a/CHANGES.md b/CHANGES.md index b6e4be4..5b60c5f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1187,3 +1187,12 @@ 2026-07-03 14:41 [Edit] /home/steggi/pyramid/lib/core/background_push.dart 2026-07-03 14:41 [Edit] /home/steggi/pyramid/lib/core/background_push.dart 2026-07-03 14:41 [Edit] /home/steggi/pyramid/lib/features/auth/login_notifier.dart +2026-07-03 17:45 [Edit] /home/steggi/pyramid/docs/PROGRESS.md +2026-07-03 17:46 [Edit] /home/steggi/pyramid/PROGRESS.md +2026-07-03 17:46 [Edit] /home/steggi/pyramid/ROADMAP.md +2026-07-03 17:49 [Write] /home/steggi/pyramid/docs/SQLCIPHER_MIGRATION.md +2026-07-03 17:49 [Edit] /home/steggi/pyramid/docs/SQLCIPHER_MIGRATION.md +2026-07-03 17:50 [Write] /home/steggi/pyramid/docs/PC_TESTPLAN.md +2026-07-03 17:50 [Edit] /home/steggi/pyramid/PROGRESS.md +2026-07-03 17:50 [Edit] /home/steggi/pyramid/ROADMAP.md +2026-07-03 17:50 [Edit] /home/steggi/pyramid/ROADMAP.md diff --git a/PROGRESS.md b/PROGRESS.md index 4f7eb77..f04b351 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -13,6 +13,41 @@ Schritt (und beim Abbruch mitten im Schritt den Zwischenstand). Format: --- +## 2026-07-03 – M1-Vorbereitung: SQLCipher-Migrationsplan + konsolidierter PC-Testplan + +**Erledigt:** Nach Abschluss des Fable-5-Reviews (Abschnitt darunter) die zwei +obersten offenen ROADMAP-Punkte (SQLCipher, Härtetest) so weit gebracht, wie es +auf dem Pi ohne GUI/Testgerät sicher geht – beide bleiben offen, aber der +nächste PC-Termin kann jetzt direkt loslegen statt zu planen: + +- `docs/SQLCIPHER_MIGRATION.md`: vollständiger Umsetzungsplan, gegen den echten + Code geschrieben (beide DB-Öffnungsstellen, Factory-Wahl pro Plattform). + Kernpunkte: gemeinsame DB-Fassade `app_database.dart` (zahlt aufs + M2-Storage-Modul ein), Android via `databaseFactoryFfi` + + `openCipherOnAndroid`, im Push-Isolate zwingend `databaseFactoryFfiNoIsolate` + (dieselbe Isolate-Falle, an der schon `NativeImplementationsIsolate` + scheiterte), Schlüssel im Android Keystore (`flutter_secure_storage`, schon + Abhängigkeit), Migration per `sqlcipher_export` in NEUE Datei mit + Backup/Verifikation/atomarem Tausch – kein Fehlerpfad darf die Klartext-DB + beschädigen. Marker-Datei gegen das Migration/Push-Race. Phase 1 nur + Android (sqlcipher_flutter_libs liefert keine Windows-Binaries). + Tabellenname für die Verifikation gegen matrix-6.2.0 geprüft + (`box_inbound_group_session`). +- `docs/PC_TESTPLAN.md`: ALLE aufgelaufenen UNGETESTET(Pi)-Punkte aus den + bisherigen PROGRESS-Einträgen an einer Stelle konsolidiert (Härtetest/ + Krypto-Kreislauf zuerst, dann die 6 Split-Bereiche, Reorder-Off-by-One-Check, + PDF-Zoom, Push-Beobachtung, „Uta einmal neu einloggen"). Bisher waren die + über 7 Einträge verstreut – Gefahr, dass der PC-Lauf etwas übersieht. + +**Offen/Nächster Schritt:** Unverändert: PC-Termin (jetzt mit fertigem +Testplan + Migrationsplan) oder Bernds Antworten (Call-Pilot, SQLCipher- +Priorität). Auf dem Pi ist damit alles abgearbeitet, was ohne GUI/Entscheidung +sicher geht – inklusive des kompletten Qualitäts-Reviews. + +**Stolperfallen:** Keine neuen – reine Dokumentation, kein Code angefasst. + +--- + ## Fable-5-Review (Qualitäts-Review aller Autopilot-Commits 25ed765..HEAD) Bernds Auftrag (ROADMAP M0): alle bisherigen Sonnet-5-Commits kritisch und in diff --git a/ROADMAP.md b/ROADMAP.md index e4d8c85..3ea9b25 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -49,7 +49,9 @@ Punkte abhaken (`[x]`), wenn erledigt UND in `PROGRESS.md` protokolliert. auf der Platte. Bewusst NICHT blind auf dem Pi gefixt: eine Umstellung auf SQLCipher braucht eine Migration für bereits bestehende Klartext-DBs (Utas Gerät!) – ohne Testgerät hier zu riskant für „Kein Datenverlust". - Siehe PROGRESS.md 2026-07-03 + Frage an Bernd. + Siehe PROGRESS.md 2026-07-03 + Frage an Bernd. **Umsetzungsplan liegt + fertig in `docs/SQLCIPHER_MIGRATION.md`** (2026-07-03, gegen Code und + SDK verifiziert) – PC-Termin kann direkt damit starten. - [x] Key-Backup einrichten-Flow: bereits vorhanden (`bootstrap_dialog.dart`, wird automatisch getriggert wenn Cross-Signing fehlt, `app_shell.dart`) - [x] Key-Backup wiederherstellen-Flow: bereits vorhanden (`bootstrap_dialog.dart`, @@ -59,7 +61,9 @@ Punkte abhaken (`[x]`), wenn erledigt UND in `PROGRESS.md` protokolliert. (`_SessionsSection` in `settings_modal.dart` – Liste, Umbenennen, Verifizieren per SAS/QR, Abmelden, Massen-Abmeldung mit Passwort-Reauth) - [ ] Härtetest dokumentieren: Login → Nachrichten → Logout → Login neu → alles noch lesbar - (gehört zum ausstehenden PC-Praxistest der beiden Bugfixes oben) + (gehört zum ausstehenden PC-Praxistest der beiden Bugfixes oben; + kompletter Ablauf inkl. aller aufgelaufenen UNGETESTET-Punkte steht + jetzt in `docs/PC_TESTPLAN.md` – dort abarbeiten und abhaken) ## M2 – Das große Refactoring (erst nach M0/M1!) diff --git a/docs/PC_TESTPLAN.md b/docs/PC_TESTPLAN.md new file mode 100644 index 0000000..ae66d53 --- /dev/null +++ b/docs/PC_TESTPLAN.md @@ -0,0 +1,103 @@ +# PC-Testplan – alle aufgelaufenen UNGETESTET(Pi)-Punkte + +Stand: 2026-07-03. Alle Pi-Sessions seit dem 2026-07-03 konnten nur +`flutter analyze` + automatisierte Textvergleiche fahren (kein GUI auf dem Pi). +Dieser Plan konsolidiert JEDEN ausstehenden Praxistest aus PROGRESS.md an einer +Stelle. Beim nächsten Windows-Lauf von oben nach unten abarbeiten, Ergebnis je +Punkt hier eintragen (✅/❌ + Datum), Befunde als eigene PROGRESS-Einträge. + +Schnellster Weg: `flutter run -d windows`. + +## 1. Härtetest Login/Krypto (M1 – PFLICHT, zuerst!) + +Deckt die Fixes 63e4919, 9dc83f7, 891f348 ab (Uta-Random-Logout + Guard). + +- [ ] Login mit Test-Account → Nachrichten in verschlüsseltem Raum senden/lesen +- [ ] `auth_log.txt` (App-Support-Verzeichnis) prüfen: LoginState-Wechsel + werden mitgeschrieben, keine unerwarteten Warnungen +- [ ] Logout (Warnung bei fehlendem Key-Backup erscheint? b5762ea) +- [ ] Erneuter Login → **alte verschlüsselte Nachrichten noch lesbar?** +- [ ] Mehrere Stunden laufen lassen: kein Random-Logout, kein + Login-Screen-Flackern (isLoggedInProvider-Änderung), `auth_log.txt` + zeigt ggf. „Soft-Logout durch Token-Refresh abgewendet" +- [ ] Ergebnis als „Härtetest"-Eintrag in PROGRESS.md dokumentieren + (= ROADMAP-M1-Punkt „Härtetest dokumentieren" abhaken) +- [ ] Android: nach Neu-Login beobachten, ob Push-Inhalte wieder echt + entschlüsselt ankommen (statt „Neue Nachricht"-Platzhalter). Falls nicht: + zweite Ursache, siehe `docs/NOTIFICATIONS.md` + Memory „Pyramid Push" +- [ ] Danach Uta: einmal aus- und wieder einloggen (erst dann hat ihre + Session einen Refresh-Token!) + +## 2. Settings-Split (5d77238, 12 Teildateien) + +Alle Reiter öffnen und benutzen: Profil, Benachrichtigungen, Erscheinungsbild, +Voice, Tastaturkürzel, Privatsphäre, Sessions, Verschlüsselung, Account, Über. + +- [ ] Verschlüsselung (HEILIG): Recovery-Key anzeigen, Megolm-Export UND + -Import (Passphrase), SAS/QR-Verifizierung starten +- [ ] Sessions: Gerät umbenennen, Einzel-Logout, Massen-Logout-Dialog + (Passwort-Reauth) nur bis zur Abfrage +- [ ] Account: Passwort-ändern-Dialog öffnen, Account-löschen-Dialog öffnen + (NICHT bestätigen) +- [ ] Logout-Warnungs-Text bei fehlendem Backup sichtbar (settings_about/shared) + +## 3. Chat-Timeline-Split (5bf45a9) + tote-Code-Bereinigung (6400fb6) + +Einen Chat mit allen Nachrichtentypen durchgehen: + +- [ ] Text mit Link-Vorschau, Bild, Video, Audio, Datei-Anhang +- [ ] Download-/Entschlüsselungs-Fehlerpfade in `message_media.dart` gezielt + ansehen (am wenigsten geprüfter Teil) +- [ ] Reaktionen setzen/entfernen, Hover-Aktionsleiste, Antworten/Zitat +- [ ] Datums-Trenner, „Neue Nachrichten"-Divider +- [ ] Gescheiterte Nachricht: bleibt mit Retry/Löschen stehen, Retry geht +- [ ] Zeitanzeige bei aufeinanderfolgenden Nachrichten + Hover-Uhrzeit bei + Fortsetzungsnachrichten (`_formatMessageTime`-Zusammenführung) + +## 4. Raumlisten-Split (a863fa3) + Reorder-Fix (401bd6a) + +- [ ] Space wechseln, Raum beitreten/verlassen +- [ ] **Drag&Drop-Umsortieren: landet der Raum EXAKT an der Zielposition?** + (onReorder→onReorderItem, Index-Korrektur jetzt im Framework – Off-by-One + wäre hier sichtbar; nach oben UND nach unten ziehen testen) +- [ ] Voice-Channel-Teilnehmerliste in der Raumliste +- [ ] Einladung annehmen/ablehnen, Ungelesen-Badge, DM-Avatare + +## 5. Space-Admin-Split (0c7d359) + +An einem TEST-Space, nicht an Utas echtem: + +- [ ] Übersicht: Sichtbarkeit umschalten, Banner ändern (Danger-Zone nur ansehen) +- [ ] Mitglieder: einladen, Rolle ändern (Selbst-Aussperr-Schutz + `updatePowerLevelsSafely` greift?), kicken +- [ ] Berechtigungen ändern, Kanäle: erstellen + bestehenden Raum hinzufügen + +## 6. Chat-View-Split (31e4001) + +- [ ] Chat-Header (normal + DM mit ausklappendem Header/Presence) +- [ ] Tippanzeige, Offline-/Reconnect-Banner (Netz kurz trennen) +- [ ] Datei per Drag&Drop in den Chat ziehen (Overlay + Senden) + +## 7. Dokument-Viewer-Split (daf4cf3) + Matrix4-Fix (401bd6a) + +- [ ] PDF inline im Chat, Vollbild-Viewer: **Zoom per Buttons/Strg+Mausrad** + (translateByDouble/scaleByDouble-Umbau – zoomt es zentriert wie vorher?), + Seiten-Navigation, Thumbnail-Leiste, Speichern-Button +- [ ] Text/Markdown/SVG-Vorschau, Office-Text-Extraktion +- [ ] ZIP/TAR-Archiv-Browser, PSD-Thumbnail +- [ ] Bild im Chat öffnen (Fallback-Pfade) + +## 8. Kleinkram aus den Lint-Commits + +- [ ] Mini-Call-Widget: Buttons zeigen jetzt Hover-Farbe (9dc1175, gewollt) – + sieht das ok aus? +- [ ] Anhang-Dialog + Raum-erstellen-Dialog: Switches (activeThumbColor) sehen + aus wie vorher +- [ ] Voice-Channel beitreten/verlassen (Kernflow laut CLAUDE.md, von den + Splits nicht berührt, aber Pflicht nach jedem Refactoring) + +## Danach + +- [ ] Alle ✅ hier eintragen, PROGRESS.md-Eintrag „PC-Praxistest" schreiben, + erst DANN neue riskante Punkte anfangen (Call-Fassade, SQLCipher – + siehe `docs/SQLCIPHER_MIGRATION.md`) diff --git a/docs/SQLCIPHER_MIGRATION.md b/docs/SQLCIPHER_MIGRATION.md new file mode 100644 index 0000000..13b413c --- /dev/null +++ b/docs/SQLCIPHER_MIGRATION.md @@ -0,0 +1,125 @@ +# SQLCipher-Migration der `pyramid.sqlite` – Umsetzungsplan (PC-Termin) + +Stand: 2026-07-03, geschrieben auf dem Pi (Plan gegen den echten Code verifiziert, +Umsetzung braucht PC + Android-Testgerät). Gehört zum offenen M1-Punkt +„Sichere Speicherung von Access-Token & Krypto-DB". + +## Für Bernd in einfach + +Die Datenbank der App (Nachrichten, Zugangs-Token, Verschlüsselungs-Schlüssel) +liegt heute **unverschlüsselt** auf dem Gerät – geschützt nur durch die +Android-App-Sandbox. Ein Angreifer bräuchte Root oder physischen Zugriff mit +Entwickler-Tools, um sie zu lesen. Dieser Plan verschlüsselt die Datei selbst. +Der riskante Teil ist nicht die Verschlüsselung, sondern die **einmalige +Umwandlung bestehender Installationen** (Utas Handy!) – deshalb: erst am PC +mit Testdaten, dann eigenes Gerät, dann erst Release. + +**Offene Entscheidung (Frage in PROGRESS.md):** Priorität vor/nach M2? + +## Ist-Zustand (verifiziert im Code) + +| Stelle | Datei | Factory heute | +|---|---|---| +| Haupt-App Android/iOS | `lib/core/matrix_client.dart:24` | `sqflite_native.databaseFactory` (System-SQLite, **kann kein SQLCipher**) | +| Haupt-App Desktop | `lib/core/matrix_client.dart:27` | `databaseFactoryFfi` (gebündeltes sqlite3) | +| Push-Isolate (nur Android) | `lib/core/background_push.dart` `_buildClient()` | `sqflite_native.databaseFactory` | + +- `sqlcipher_flutter_libs ^0.6.8` ist bereits in `pubspec.yaml`, wird nirgends benutzt. +- `flutter_secure_storage ^10` ist bereits da (→ Schlüsselablage im Android Keystore). +- Beide Prozesse öffnen **dieselbe Datei** (`pyramid.sqlite`, WAL-Modus, + `busy_timeout 5000`). + +## Zielarchitektur + +1. **Ein gemeinsamer DB-Öffner** `lib/core/app_database.dart` (neues Storage-Modul + im Sinne von M2): kapselt Factory-Wahl, PRAGMAs, Schlüsselbeschaffung und + Migration. `matrix_client.dart` und `background_push.dart` rufen NUR noch + diese Fassade – damit verschwindet auch die heutige Code-Duplikation der + PRAGMA-Blöcke. +2. **Android:** nicht mehr `sqflite_native`, sondern `databaseFactoryFfi` mit + SQLCipher-Lib: + ```dart + import 'package:sqlite3/open.dart'; + import 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart'; + open.overrideFor(OperatingSystem.android, openCipherOnAndroid); + ``` + **Achtung Push-Isolate:** `databaseFactoryFfi` spawnt ein eigenes Isolate – + im Firebase-Background-Isolate ist das genau die Fallenklasse, an der schon + `NativeImplementationsIsolate` scheiterte (Kommentar in + `background_push.dart`). Dort deshalb `databaseFactoryFfiNoIsolate` benutzen. +3. **Schlüssel:** 32 Byte kryptografisch zufällig (`Random.secure()`), hex-kodiert + in `flutter_secure_storage` unter `db_cipher_key`. Beide Prozesse lesen + denselben Eintrag. Schlüssel wird bei ERSTER Nutzung erzeugt; existiert schon + eine verschlüsselte DB, aber kein Schlüssel im Storage → harter Fehler mit + Klartext-Meldung, NIEMALS still neue DB anlegen (Datenverlust-Regel!). +4. **Öffnen:** `PRAGMA key = "x''"` als allererstes Statement + (`OpenDatabaseOptions(onConfigure: ...)`), danach wie bisher WAL + busy_timeout. +5. **Windows/Linux-Desktop:** `sqlcipher_flutter_libs` liefert dort KEINE + Binaries. Phase 1 = nur Android verschlüsseln (dort liegt das echte Risiko, + dort sind die echten Nutzer); Desktop bleibt vorerst Klartext, klar im Code + kommentiert. Desktop-SQLCipher später als eigener Punkt (eigene DLL bündeln). + +## Migration bestehender Klartext-DBs (der heikle Teil) + +Reihenfolge beim App-Start, VOR `MatrixSdkDatabase.init`, VOR jedem Push-Zugriff: + +1. Erkennung: Datei beginnt mit `SQLite format 3\0` → Klartext → Migration nötig. + (Verschlüsselte SQLCipher-Dateien haben keinen lesbaren Header.) +2. WAL eindampfen: Klartext-DB kurz normal öffnen, + `PRAGMA wal_checkpoint(TRUNCATE)`, schließen – sonst verlieren wir Daten, + die noch in `pyramid.sqlite-wal` liegen. +3. **Backup:** `pyramid.sqlite` → `pyramid.sqlite.premigration` kopieren + (Bytes, nicht rename). Bleibt bis zum verifizierten Erfolg liegen. +4. Export in NEUE Datei (Original bleibt unangetastet): + ```sql + ATTACH DATABASE 'pyramid.enc.sqlite' AS enc KEY "x''"; + SELECT sqlcipher_export('enc'); + DETACH DATABASE enc; + ``` + (läuft über die SQLCipher-FFI-Verbindung auf der Klartext-DB) +5. Verifikation: `pyramid.enc.sqlite` mit Schlüssel öffnen, + `PRAGMA integrity_check` == ok UND Zeilenzahl einer Kerntabelle + (z. B. `box_inbound_group_session`, Name gegen matrix-6.2.0 + `matrix_sdk_database.dart:139` verifiziert) identisch mit Original. Schlägt IRGENDWAS + fehl → `pyramid.enc.sqlite` löschen, App startet normal mit Klartext-DB + weiter, Fehler in `auth_log.txt`. **Kein Zustand darf die Klartext-DB + beschädigt zurücklassen.** +6. Tausch: Original + `-wal`/`-shm` löschen, `pyramid.enc.sqlite` → + `pyramid.sqlite` (rename, gleiche Partition = atomar). +7. `.premigration`-Backup erst nach N erfolgreichen Tagen / manuell löschen + (Entscheidung Bernd: sonst liegt weiter eine Klartext-Kopie herum – + Kompromiss: nach 7 Tagen beim Start automatisch löschen). + +### Race mit dem Push-Isolate + +Kommt ein FCM-Push, während die Haupt-App migriert, würde das Isolate die DB +mittendrin öffnen. Lösung: Marker-Datei `pyramid.sqlite.migrating` vor Schritt 2 +anlegen, nach Schritt 6 löschen; `_buildClient()` im Push-Pfad bricht bei +vorhandenem Marker sofort ab (Notification zeigt dann einmalig den +„Neue Nachricht"-Platzhalter – akzeptabel). Zusätzlich erkennt das Isolate +selbst Klartext vs. verschlüsselt am Datei-Header und wählt PRAGMA key +entsprechend – es migriert aber NIE selbst. + +## Testplan (PC-Termin, in dieser Reihenfolge) + +1. Windows-Build mit Test-Account: Migration Klartext→SQLCipher durchlaufen + lassen (Desktop kriegt fürs TESTEN die FFI-SQLCipher-Variante per lokalem + Override, auch wenn Phase 1 sie im Release nicht aktiviert). +2. Kernflow danach: Login erhalten? Alte verschlüsselte Nachrichten lesbar? + Logout → Neu-Login → immer noch lesbar? (`docs/PC_TESTPLAN.md` Abschnitt 1) +3. Fehlerpfade erzwingen: Migration mit vollem Datenträger / Kill mitten in + Schritt 4 → App muss mit unversehrter Klartext-DB weiterlaufen. +4. Android-Testgerät (eigenes, NICHT Uta): frische Installation (Neuanlage + verschlüsselt), dann Update-Szenario (bestehende Klartext-DB migriert), + dann Push-Test (Isolate liest verschlüsselte DB; secure_storage-Zugriff + aus dem Background-Isolate explizit verifizieren – bekanntes Risiko). +5. Erst wenn 1–4 grün: Release, Uta informieren (ihr Gerät migriert beim + ersten Start automatisch; vorher ihr Key-Backup verifizieren!). + +## Bewusst NICHT im Scope + +- `auth_log.txt`, `SharedPreferences`, Media-Cache bleiben Klartext (keine + Geheimnisse bzw. nur Cache; einzeln bewerten, falls Bernd es wünscht). +- Passphrase-basierter Schlüssel (Nutzer-Eingabe): bewusst nein – Schlüssel + liegt im Keystore, gleiche Vertrauensstufe wie der Rest der App-Daten, + aber Datei-Exfiltration allein reicht dann nicht mehr.