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:
+74
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user