feat: SQLCipher-Verschluesselung der pyramid.sqlite (M1) via neue Storage-Fassade app_database.dart

- AppDatabase.open()/openForPush() kapseln Factory, Schluessel (Keystore),
  Klartext->SQLCipher-Migration (Backup/Verify/atomarer Tausch) und PRAGMAs
- Android/Windows/Linux verschluesselt, iOS/macOS bewusst Klartext
- 5 neue Tests mit echter SQLCipher-DLL; Windows-Praxistest mit echter DB
  erfolgreich (23 Tabellen verifiziert, E2EE intakt); Android UNGETESTET
This commit is contained in:
Bernd Steckmeister
2026-07-06 12:31:38 +02:00
parent cead62ccb2
commit f64398d3c6
10 changed files with 787 additions and 49 deletions
+74
View File
@@ -13,6 +13,80 @@ Schritt (und beim Abbruch mitten im Schritt den Zwischenstand). Format:
---
## 2026-07-06 SQLCipher-Migration UMGESETZT + auf Windows mit echter DB praxisgetestet (M1, Bernds Prio 1)
**Erledigt:** Der M1-Punkt „Sichere Speicherung von Access-Token & Krypto-DB"
ist nach `docs/SQLCIPHER_MIGRATION.md` umgesetzt (PC-Session laut
Entscheidung 1 in `ANTWORTEN_BERND.md`):
- **Neue Storage-Fassade `lib/core/app_database.dart`** (erster Baustein im
Sinne des M2-Modularitäts-Leitsatzes): kapselt Factory-Wahl, SQLCipher-
Schlüssel (32 Zufallsbytes, hex im Keystore via flutter_secure_storage,
Eintrag `db_cipher_key`, mit Read-Back-Verifikation gegen stilles
Write-Versagen), Klartext→SQLCipher-Migration und die vorher duplizierten
PRAGMAs. `matrix_client.dart` und `background_push.dart` rufen nur noch
`AppDatabase.open()` / `AppDatabase.openForPush()`.
- **Migration exakt nach Plan:** Marker gegen Push-Isolate-Race →
WAL-Checkpoint → Byte-Backup `.premigration` (nach 7 Tagen auto-gelöscht) →
`sqlcipher_export` in NEUE Datei → Verifikation (integrity_check +
Zeilenzahlen ALLER Tabellen) → atomarer rename-Tausch. Jeder Fehlpfad lässt
die Klartext-DB unangetastet (App läuft dann unverschlüsselt weiter,
Fehler im auth_log). Absturz zwischen Löschen und Umbenennen wird beim
nächsten Start aus dem Byte-Backup repariert.
- **Wichtige Plan-Korrektur:** Die Plan-Annahme „sqlcipher_flutter_libs hat
keine Desktop-Binaries" ist seit 0.6.x überholt das Plugin baut SQLCipher
auf Windows als `sqlite3.dll` MIT (im Build-Output verifiziert, nur dieses
eine sqlite-Plugin ist im Build). Deshalb verschlüsseln Windows/Linux
ebenfalls (kein Test-Override nötig); iOS/macOS bleiben bewusst Klartext
(Pod-Kollision mit firebase_messaging, kein Release-Ziel). Laufzeit-Wächter
`PRAGMA cipher_version` verhindert, dass je stillschweigend die falsche
Bibliothek benutzt wird; verschlüsselte DB ohne Cipher-Lib/Schlüssel ist
ein harter Fehler mit Klartext-Meldung NIE stille Neuanlage.
- **Tests `test/app_database_test.dart`** (5 neue, gesamt 29, alle grün):
fahren die ECHTE Migration mit der SQLCipher-DLL aus dem Build-Output
cipher_version-Wächter, Header-Erkennung, Migration mit Zeilenzahl-
Verifikation, falscher Schlüssel scheitert sofort, erzwungener Fehlschlag
lässt das Klartext-Original intakt.
- **Praxistest Windows (`flutter run -d windows`), echte Daten:** Bernds
gewachsene 14-MB-DB (inkl. 4 MB WAL) wurde beim Start migriert
(auth_log: „23 Tabellen verifiziert"), Session blieb eingeloggt, E2EE
nachweislich intakt (App entschlüsselte live to_device-Events von
@uta, forwardete Room-Keys). Zweiter Start öffnet die verschlüsselte DB
ohne erneute Migration, sauberer Quit per `q`. DB-Header jetzt zufällig
(verschlüsselt), `.premigration` = Klartext-Original. Zusätzliche manuelle
Sicherung liegt als `pyramid.sqlite*.claude-vormigration-20260706` im
App-Verzeichnis (kann nach ein paar Tagen weg).
- `sqlite3` als direkte Dependency ergänzt (war schon transitiv im Lockfile
kein neues externes Paket), für `open.overrideFor`/`openCipherOnAndroid`.
- `flutter analyze` sauber (nur der bekannte, bewusst zurückgestellte
onUpdate-Hinweis).
**UNGETESTET (Android deshalb ROADMAP-Punkt NICHT abgehakt):** Migration
auf echtem Android-Gerät, Push-Isolate liest verschlüsselte DB
(`databaseFactoryFfiNoIsolate` + `openCipherOnAndroid`), flutter_secure_storage
aus dem Background-Isolate (bekanntes Risiko, Code steigt dann kontrolliert
mit Platzhalter-Notification aus). Testplan Punkt 4 in
`docs/SQLCIPHER_MIGRATION.md`; erst danach Release + Uta (vorher ihr
Key-Backup verifizieren).
**Offen/Nächster Schritt:** M2-Call-Pilot (Entscheidung 2: Call-Fassade nach
`docs/M2_MODULE_SCHNITT.md`), danach Härtetest nach `docs/PC_TESTPLAN.md`.
**Stolperfallen:** (1) Plan-Annahmen über Paket-Fähigkeiten VOR der Umsetzung
gegen den Pub-Cache/Build-Output prüfen die „keine Desktop-Binaries"-Annahme
hätte unnötig einen Test-Override-Sonderpfad erzeugt. (2) `sqfliteFfiInit()`
war auf Windows faktisch wirkungslos fürs DB-Isolate (Override wirkt nur im
aufrufenden Isolate; das Worker-Isolate lädt die exe-nachbarschaftliche
`sqlite3.dll` und die IST hier SQLCipher). Für eigene Overrides deshalb
`createDatabaseFactoryFfi(ffiInit: ...)` benutzen, das läuft IM DB-Isolate.
(3) Beim Schlüssel-Anlegen im Keystore IMMER read-back-verifizieren, bevor
damit verschlüsselt wird ein still verlorener Schlüssel wäre Totalverlust.
(4) `flutter_test` findet keine `sqlite3.dll` neben dem Tester-Binary die
DLL aus `build/windows/x64/runner/*/` explizit laden; Tests überspringen sich
selbst, wenn kein Build-Output da ist (Pi-tauglich).
---
## 2026-07-06 Fable-5-Review (aa): autopilot.sh fest auf nordmann-Konto (uncommittete Änderung geprüft, E-Mail-Leak vor Publikation gefixt, committet)
**Erledigt:** Session-Start nach Arbeitszyklus zeigte echten neuen Anlass (also