Entwurf für Cloud-Speicherung und Synchronisierung
Status: Die Schritte 1-4 sind seit 2026-09-17 implementiert; für Schritt 5 liegt eine reproduzierbare Ausgangsmessung vor.
Dauerhafte Outbox-/Inbox-Empfangsbestätigungen, Änderungsmarkierungen, eine
prozesslokale Synchronisierungssitzung und ein anbieterunabhängiger Runner mit
Fehlerinjektion über MemoryTransport sind in crates/core/src/sync.rs
implementiert. Dateiadapter für OneDrive/Google Drive, die Token-Erneuerung und
der CLI-Befehl cloud sync sind implementiert und mit lokalen Testdaten getestet.
Echte Anbieterkonten wurden nicht validiert. Die mobile AppAuth-Anmeldung und die
Steuerung der Synchronisierung im Vordergrund sind implementiert; die native
Einwilligung erfordert Plattformregistrierungen.
Den aktuellen Autorisierungsumfang beschreibt
Cloud-Autorisierung. Dieses Dokument erweitert die
Anforderung für OneDrive/Google Drive um die Vorgabe, dass gleichzeitig aktive
Geräte die Datenbankdateien der jeweils anderen Geräte weder beschädigen noch
sperren dürfen.
Entscheidung
SQLite bleibt als gerätelokaler transaktionaler Speicher erhalten. Hinzu kommt ein anbieterunabhängiges Synchronisierungsprotokoll, das unveränderliche, authentifizierte verschlüsselte Objekte über Cloud-APIs austauscht. Jedes Gerät besitzt seine eigene Datenbank, Identität, sein eigenes Passwort und einen lokalen Schreibprozess. Cloud-Speicher ist ein nicht vertrauenswürdiger Objekttransport, keine eingebundene Datenbank.
Die aktive memories.db, Journal-, WAL-, SHM- und Sperrdateien dürfen niemals in
einem von der Cloud verwalteten Synchronisierungsverzeichnis liegen. Die Datenbank
darf nicht über ein entferntes Dateisystem geöffnet werden. Der standardmäßige
Speicherort für Anwendungsdaten des Betriebssystems bleibt erhalten. Die Erkennung
und Zurückweisung bekannter OneDrive-/Drive-Wurzelverzeichnisse ist eine künftige
Schutzmaßnahme für die Konfiguration und wird derzeit nicht erzwungen; beliebige
Synchronisierungsclients und Einhängepunkte lassen sich nicht zuverlässig erkennen.
flowchart LR
A[Device A local SQLite] --> QA[Durable outgoing queue]
QA --> C[OneDrive or Google Drive encrypted objects]
C --> VB[Download and verify]
VB --> B[Device B local SQLite]
B --> QB[Durable outgoing queue]
QB --> C
C --> VA[Download and verify]
VA --> A
Bestehendes Verhalten und Grenzen
crates/core/src/store.rs: Eine exklusive Betriebssystemsperre weist einen zweiten lokalen Speicherbesitzer zurück. SQLite verwendetjournal_mode=DELETE,synchronous=FULLund transaktionale Aktualisierungen des verschlüsselten Zustands samt signierten Prüfpunkten. Dies schützt kooperierende lokale Prozesse; es ist keine verteilte Sperre über unabhängige Dateireplikate hinweg.- Jeder Speichervorgang serialisiert und verschlüsselt den vollständigen
State; beim Entsperren wird die gesamte Prüfpunkt-Historie geprüft. Größere Bibliotheken erhöhen den Schreibaufwand und die Startzeit. Dies ist eine Skalierungsfrage, kein Beleg dafür, dass SQLite selbst ersetzt werden muss. Für diese Bewertung wurde kein Benchmark mit Arbeitslasten durchgeführt. - Die Datenbankinitialisierung hält die Betriebssystemsperre des Ziels, während
sie im selben Verzeichnis eine private temporäre Datenbank aufbaut. Sie schreibt
den anfänglichen verschlüsselten Zustand und Prüfpunkt fest, schließt SQLite,
synchronisiert die Datei und veröffentlicht sie, ohne ein bestehendes Ziel zu
ersetzen. Nach einem Absturz vor der Veröffentlichung steht der endgültige Pfad
für einen erneuten Versuch zur Verfügung. Zurückgelassene
.memories-init-*- Dateien können nach einem Absturz verbleiben; sie werden niemals als aktive Datenbank geladen und nicht automatisch gelöscht. Serviceverarbeitet Änderungen an geklontem Zustand und schreibt sie fest, bevor es sie akzeptiert.Vault::mergevalidiert einen Kandidaten, bevor es den aktuellen Tresor ersetzt. Signierte Revisionshistorien bewahren bereits gleichzeitige Änderungen und Löschmarkierungen.- Desktop-IPC akzeptiert bis zu 16 gleichzeitige Anfragen; die Zustandsverarbeitung hält den Service-Mutex. Auf Mobilgeräten werden einzelne Service-Sperren und eine kurze Registry-Abfrage verwendet. Eine Cloud-HTTP-Anfrage direkt innerhalb dieser kritischen Abschnitte würde andere Vorgänge verzögern, einschließlich des Sperrens. Dies ist eine Blockierung, kein nachgewiesener zyklischer Deadlock. Cloud-Worker müssen Service-Sperren vor Netzwerk-I/O freigeben; die Verarbeitung von Desktop-Anfragen verwendet jetzt eine begrenzte Anzahl gleichzeitiger Verbindungen.
- Bestehende Synchronisierungsexporte sind empfängerbezogen verschlüsselte Umschläge des gesamten Tresors. Ein neu bei der Cloud authentifiziertes Gerät benötigt weiterhin eine Gerätefreigabe, bevor es einen Tresor entschlüsseln oder importieren kann. Eine Cloud-Anmeldung darf die kryptografische Gerätekopplung nicht ersetzen.
Datenbankalternativen
| Option | Eignung für dieses Repository | Entscheidung |
|---|---|---|
| Lokales SQLite plus unveränderliche Cloud-Objekte | Verwendet Transaktionen, Verschlüsselung, Audit und Konfliktbehandlung weiter; kein Server erforderlich | Empfohlen |
| redb oder LMDB als lokaler Speicher | Eingebetteter transaktionaler Speicher kann funktionieren, aber ein Wechsel der Engine ermöglicht weder geräteübergreifendes Zusammenführen noch Cloud-Sperren | Noch keine Migration gerechtfertigt |
| Eine gemeinsame Datenbank oder ein verschlüsseltes Archiv in einem Synchronisierungsordner | Unabhängige Datei-Uploads können Versionen überschreiben; begleitende Sperren und Journale sind nicht koordiniert | Für aktive Synchronisierung ablehnen |
| PostgreSQL plus eine dedizierte Synchronisierungs-API | Zentralisiert serverseitige Nebenläufigkeit, erfordert aber einen betriebenen Dienst und ein separates Offline-/Verschlüsselungsprotokoll | Nur erwägen, wenn die Produktanforderungen einen Server umfassen |
| CRDT-Bibliotheken wie Automerge oder Yjs | Potenziell nützlich für zukünftige gemeinsame Textbearbeitung; ersetzen weder dauerhaften Speicher noch signierte Berechtigungsprüfungen | Nicht für Zugangsdaten oder Richtlinienänderungen einführen |
SQLite auf WAL umzustellen ist keine Lösung für Cloud-Synchronisierung. WAL kann nach entsprechenden Messungen später die lokale Nebenläufigkeit von Lesezugriffen verbessern, erfordert aber die Koordination auf demselben Host und beseitigt nicht die Notwendigkeit eines einzigen lokalen Schreibprozesses.
Vertrag für Cloud-Objekte
Zunächst wird das bestehende Umschlagformat für den gesamten Tresor verwendet; Speicherung, Kryptografie und Synchronisierungsgranularität sollten nicht gleichzeitig geändert werden. Inkrementelle verschlüsselte Revisionen/Blöcke werden erst ergänzt, nachdem sich der Pfad für unveränderliche Umschläge bewährt hat.
- Jeden Umschlag genau einmal erzeugen und seine exakten Bytes vor dem Upload in der lokalen Outbox dauerhaft speichern. Als logische ID dient SHA-256 des vollständigen Chiffretextobjekts. Wiederholungsversuche verwenden dieselben Bytes; erneutes Verschlüsseln bei jedem Versuch erzeugt ein neues Objekt.
- Objekte und Veröffentlichungsdeskriptoren sind unveränderlich. Es gibt keine
gemeinsam beschreibbare
latest.json, keine gemeinsame Sperrdatei, keine globale Cloud-Sequenz und kein Überschreiben der Datenbank. Jeder zukünftige veränderliche Kopf/Cache dient nur als Hinweis und lässt sich durch Auflisten der Objekte wiederherstellen. - Zuerst die Datenobjekte veröffentlichen, dann einen unveränderlichen signierten Deskriptor, der Formatversion, undurchsichtige Tresorreferenz, Absender, Empfänger, Objekthashes und -längen sowie gerätespezifische Vorgänger/Sequenzen bindet. In Dateinamen Chiffretextkennungen verwenden, keine Klartexttitel, Kontonamen oder Passwort-Hashes.
- Ein Deskriptor kann vor seinen Abhängigkeiten sichtbar werden, weil Cloud-Auflistung und -Zustellung verzögert oder umgeordnet werden können. Er bleibt ausstehend, bis jedes Objekt vorhanden und validiert ist. Niemals einen Teil importieren oder seinen angewendeten Zustand vorziehen, solange Abhängigkeiten fehlen.
- Vor dem Festschreiben Länge, Chiffretexthash, Signatur, Empfänger, Tresorumfang, aktuelle Autorisierung und bestehende Historieninvarianten prüfen. ETags und Hashes des Anbieters sind Transportmetadaten, keine kryptografische Autorität.
- Wiederholt eingespielte Objekte und doppelte Anbieterdateien sind harmlos: anhand der verifizierten logischen Objekt-ID deduplizieren, nicht anhand des Dateinamens. Fehlende Cloud-Dateien bedeuten niemals eine Löschung auf Anwendungsebene; eine Löschung ist eine signierte Löschmarkierung.
Ein Cloud-Anbieter kann Objekte löschen oder zurückhalten. Lokal bekannte Köpfe/ Prüfpunkte können bestimmte Rücksetzungen erkennen, aber ein neues Gerät ohne vertrauenswürdigen neueren Prüfpunkt kann nicht nachweisen, dass es den neuesten Zustand besitzt. Dieser Entwurf bietet Integrität und explizite Konflikte, jedoch keine garantierte Verfügbarkeit oder Aktualität gegenüber einem bösartigen Anbieter.
Transaktionen und Worker-Lebenszyklus
Der lokale Schreibprozess besitzt Anwendungszustand, Prüfpunktaktualisierungen, Outbox-/Inbox-Zustand und Synchronisierungsbestätigungen. Rund um die Netzwerkaktivität werden zwei kurze kritische Abschnitte verwendet:
- Lokal vorbereiten: Autorisieren, einen konsistenten Export erfassen und den exakten verschlüsselten Upload-Auftrag samt Generations-/Sitzungsbindung festschreiben. Eine Benutzeränderung und ihre Änderungs-/Exportmarkierung müssen atomar festgeschrieben werden, damit ein Absturz keine Arbeit verliert.
- Ohne Sperre übertragen: Ein separater Worker führt OAuth-Erneuerung,
Upload, Download, Paginierung und Wiederholungsversuche aus, ohne den
Service-Mutex oder eine Datenbank-Schreibtransaktion zu halten. Nebenläufigkeit,
Antwortgrößen, Wiederholungsversuche sowie Verbindungs-/Lesefristen begrenzen.
Anbieter-Drosselung und
Retry-Afterbeachten. - Lokal festschreiben: Den Schreibprozess erneut übernehmen, Autorisierung und Sitzungsgeneration prüfen und in den aktuellen Zustand statt in eine alte erfasste Kopie zusammenführen. Dann Zustand, Prüfpunkt, angewendete IDs und Inbox-Status gemeinsam festschreiben. Ein Cursor für die Anbieter-Auflistung darf erst weitergeschaltet werden, wenn die entdeckte Arbeit dauerhaft gespeichert ist.
Sperren/Abmelden bricht Aufträge ab und macht verspätete Ergebnisse ungültig. In einer ungültig gewordenen Sitzung darf kein neues Entschlüsseln/Importieren abgeschlossen werden. Ein Abbruch kann einen vom Anbieter bereits akzeptierten Chiffretext-Upload nicht zurückholen. Unvollständige Aufträge bleiben fortsetzbar; ein erfolgreicher Upload bedeutet dauerhafte Speicherung in der Cloud, keine Bestätigung durch ein anderes Gerät.
OAuth-Tokens bleiben verschlüsselt und gerätelokal; sie sind von Cloud-Objekten, Gerätefreigabepaketen, exportierten Backups, Suche und MCP ausgeschlossen. Eine Refresh-Token-Rotation muss dauerhaft gespeichert werden, bevor nachfolgende Vorgänge das neue Token verwenden; gleichzeitige Erneuerungen werden pro Konto serialisiert, ohne während des HTTP-Austauschs die Service-Sperre zu halten. Niemals eine öffentliche Operation zum Lesen von Tokens für Worker hinzufügen.
Anbieterspezifisches Verhalten
| Anbieter | Anwendungsspeicher | Anforderungen an Upload/Wiederholungsversuche |
|---|---|---|
| OneDrive | Microsoft-Graph-Anwendungsordner, Files.ReadWrite.AppFolder |
Unveränderliche Objektnamen und das Upload-Sitzungs-Konfliktverhalten fail verwenden; ein vorhandenes Objekt herunterladen/verifizieren, statt es zu ersetzen. Bedingte Anfragen nur verwenden, wenn der betreffende Endpunkt deren Unterstützung dokumentiert. |
| Google Drive | appDataFolder, Berechtigungsumfang drive.appdata |
Datei-IDs vorab erzeugen und mit den Aufträgen dauerhaft speichern, um mehrdeutige Erstellungsvorgänge sicher wiederholen zu können; Dateinamen nicht als eindeutig behandeln. Nach einem Konflikt bestehende IDs/Inhalte prüfen. |
Beide Adapter müssen Paginierung, fortsetzbare Übertragungen, begrenzte Downloads, Wiederherstellung nach verlorenen Antworten und anbieterspezifische Fehlerbehandlung implementieren. Nicht voraussetzen, dass Drive Dateisystem-Umbenennung/-Sperren oder dieselbe Vorbedingungssemantik wie Graph unterstützt. Umgeleitete Download-URLs und URLs für fortsetzbare Uploads erfordern explizite Regeln für die Weitergabe von Zugangsdaten, damit OAuth-Bearer-Tokens nicht an beliebige Hosts gesendet werden.
Der anfängliche Entwurf mit Anwendungsordnern dient den gekoppelten Geräten eines Benutzers, die mit demselben Anbieterkonto und derselben Anwendung verbunden sind. Google-App-Datenspeicher unterstützt keine Dateifreigabe zwischen verschiedenen Konten. Das Teilen von Tresoren zwischen Benutzern benötigt einen expliziten Transport-/Freigabeentwurf; es darf OAuth-Berechtigungsumfänge nicht stillschweigend erweitern. OneDrive und Google Drive sind bei gleichzeitiger Aktivierung unabhängige Replikate, keine gegenseitig synchronisierten Ordner. Ausstehende und erfolgreiche Übertragungen separat verfolgen.
OAuth-Clientregistrierungen und die Konfiguration der Anbietereinwilligung sind vor der Überprüfung mit echten Konten erforderlich. Die CLI-Autorisierung sollte Browser-OAuth mit PKCE, State-Validierung und einem Loopback-Callback verwenden. Mobilgeräte benötigen ihren unterstützten nativen Autorisierungsablauf und die zugehörige Lebenszyklusbehandlung; Annahmen zu Desktop-Callbacks dürfen nicht unverändert auf Mobilgeräte übertragen werden.
Konflikte, Wiederherstellung und Aufbewahrung
- Beide gleichzeitig entstandenen Zugangsdaten-/Kartenrevisionen bewahren. Vor der Verwendung eine explizite Auswahl oder Auflösung verlangen; weder den neuesten Uhrzeitstempel auswählen noch Passwortzeichenfolgen zusammenführen. Bestehende Regeln für Richtlinienverzweigungen und die Quarantäne alter Epochen weiterverwenden.
- Ein Prüfsummen-/Signaturfehler weist das eingehende Objekt zurück und bewahrt den bisherigen lokalen Zustand. Im Status zwischen beschädigter Eingabe, fehlenden Abhängigkeiten, abgelaufener Anmeldung, Kontingent und Inhaltskonflikt unterscheiden, statt alles als Sperrfehler zu melden. Eine Antwort, deren Bytes nicht ihrem Hash entsprechen, bleibt mit zunehmenden Wartezeiten erneut abrufbar. Hash-verifizierte, aber ungültige Objekte erhalten separate Ablehnungsbestätigungen; sie zählen niemals als erfolgreich angewendete Abhängigkeiten. Ablehnungen verhindern die Meldung einer erfolgreichen Synchronisierung und bleiben im Cloud-Status nach Anbieter sichtbar. Das Trennen eines Anbieters löscht seine Ablehnungsbestätigungen, damit eine spätere Verbindung erneut scannen kann. Alte Bestätigungen, die Ablehnungen mit erfolgreichen Importen vermischten, werden einmalig gelöscht; die bestehenden Bestätigungen signierter Pakete verhindern weiterhin doppelte Importe.
- Die Verzeichniserkennung hat ein Inbox-Budget von 4096 Einträgen plus 16 reservierte Plätze für Abhängigkeiten. Verifizierte Deskriptoren planen fehlende Objekte direkt anhand ihres Hashes vor gewöhnlichen Downloads ein. Nicht referenzierte Umschlagpuffer dürfen unter Druck verworfen und beim Eintreffen ihres Deskriptors erneut abgerufen werden. Eine unvollständige Verzeichnisseite schaltet den Cursor niemals über IDs hinaus, die nicht aufgenommen wurden.
- Jedes Festschreiben des Zustands entfernt eingereihte Exporte an Empfänger, deren aktueller Tresorzugriff widerrufen wurde. Worker validieren ihre Sitzung zwischen Objektoperationen, auch nach der Zuteilung einer Anbieter-ID. Google-Datei-IDs werden vor dem ersten Upload in der verschlüsselten Outbox gespeichert, sodass verlorene Bestätigungen und Neustarts dasselbe unveränderliche Anbieterobjekt wiederverwenden.
- Alte Cloud-Objekte zunächst behalten. Sichere Bereinigung benötigt gerätespezifische Bestätigungen, eine Richtlinie für Offline-Geräte, Widerrufsbehandlung und eine Aufbewahrungsrichtlinie für die Wiederherstellung. Das Fehlen in Auflistungen und verstrichene Zeit allein reichen nicht aus.
- Unabhängige verschlüsselte Backups behalten. Synchronisierung mehrerer Geräte verteilt auch gültige Löschungen und ersetzt keine Wiederherstellung auf einen bestimmten Zeitpunkt.
- Vor einer Schemamigration einen Wiederherstellungspfad ergänzen: lokal sperren, ein verifiziertes Backup behalten, transaktional migrieren, verifizieren und dann aktivieren. Eine fehlgeschlagene Migration muss den bisherigen Speicher nutzbar lassen.
Implementierungsreihenfolge
- Abgeschlossen. Begrenzte Schreibanfragen (
CloudSyncEnqueue/CloudSyncWork/CloudSyncAck) und dauerhafte Outbox-/Inbox-Bestätigungen innerhalb des verschlüsseltenState. SQLite-Verschlüsselung,journal_mode=DELETEund das Speichern des Gesamtzustands sind unverändert. Keine WAL- oder Datenbank-Engine-Migration. - Abgeschlossen, nur lokaler Transport. Anbieterunabhängiger Runner für
unveränderliche Objekte (
sync::execute) mit Fehlerinjektion überMemoryTransport. Tests decken das Wiederholen mit exakten Bytes, erneutes Öffnen nach dem Festschreiben, die Verifizierung doppelter Schreibvorgänge, Deskriptoren vor Daten, beschädigte Objekte, Ungültigmachung durch Sperren/Abmelden und zwei gekoppelte Geräte ab. Dieser Testtransport verwendet keine echten Cloud-Konten. - Abgeschlossen, nur lokale Testdaten. Token-Erneuerung, Adapter für
unveränderliche OneDrive-/Google-Drive-Objekte, Daemon
CloudSyncRun(HTTP außerhalb der Schreibsperre) undmemories cloud sync. Echte Microsoft-/ Google-Konten wurden nicht autorisiert. - Implementiert, echte native Einwilligung ausstehend. Die mobile Anmeldung verwendet AppAuth; die Synchronisierung im Vordergrund nutzt denselben Core-Runner. Der Wechsel in den Hintergrund sperrt alle Handles und bricht verspätete Ergebnisse ab. Widget- und native FFI-Regressionstests decken den Abbruch ab; die Einwilligung mit echten Anbietern/Geräten bleibt eine Freigabebedingung. Eine Hintergrundplanung ist bewusst nicht aktiviert.
- Ausgangsmessung verfügbar. Siehe Leistung für den Release-Benchmark mit temporären Testdaten zu Bibliotheksgröße, Speicher-/ Entsperr-/Suchlatenz und Synchronisierungsdatenverkehr. Falls nötig, den lokalen Gesamtzustands-Blob zu verschlüsselten Tresor-/Revisions-/Schlüsselzeilen mit transaktionalen Bestätigungen migrieren und danach inkrementelle Cloud-Objekte einführen. Signierte IDs, Revisionshistorie, Chiffretextvertraulichkeit und Backup-Wiederherstellung bewahren.
Validierungsnachweise und verbleibende Freigabebedingungen
Unter Windows testet crates/core/tests/storage_resilience.rs temporäre Speicher
und Unterprozesse. Bei dieser Bewertung bestanden drei Szenarien:
- Ein separater Prozess wird zurückgewiesen, solange ein anderer den Speicher besitzt; das Beenden des Besitzers gibt die Betriebssystemsperre frei und der ursprüngliche verschlüsselte Zustand kann erneut geöffnet werden.
- Ein Kindprozess beginnt eine SQLite-Schreibtransaktion, erzwingt das Schreiben
geänderter Seiten in ein Rollback-Journal und wird vor dem Festschreiben
beendet.
Store::unlockvalidiert den ursprünglichen Zustand/Prüfpunkt undPRAGMA integrity_checkgibtokzurück. - Zwei autorisierte Geräte bearbeiten dasselbe Asset unabhängig voneinander. Beide Zusammenführungsreihenfolgen konvergieren, wiederholtes Einspielen ist idempotent, beide Köpfe bleiben erhalten und ein eingehender Snapshot mit einem fehlenden Elternknoten wird zurückgewiesen, ohne den gültigen Zustand zu ändern.
Der absichtlich ignorierte Helfer wird ausdrücklich durch übergeordnete Tests gestartet. Ausführen:
cargo test -p memories-core --test storage_resilience --locked -j 1 -- --test-threads=1
cargo test -p memories-core --lib store::tests --locked -j 1 -- --test-threads=1
Initialisierungsregressionstests in store.rs beenden einen Unterprozess nach der
Vorbereitung, aber vor der Veröffentlichung, und erstellen/entsperren anschließend
den endgültigen Speicher erneut. Sie prüfen außerdem, dass die Zielsperre gehalten
bleibt und dass ein bestehendes oder neu erschienenes Ziel niemals überschrieben
wird. OAuth-Tests decken das Ungültigmachen verspäteter Ergebnisse nach dem Sperren
ab.
Dies sind lokale Prozessabsturz- und Modelltests, kein Nachweis gegen tatsächliche Stromausfälle, Datenträger-/Controllerfehler, Dateiersetzung durch Cloud-Clients oder das Verhalten echter Anbieter. Fehler bei vollem Datenträger, große Bibliotheken, Stromausfall während der Veröffentlichung und die Grenzen zwischen Cloud-Wiederholungsversuchen und Veröffentlichung müssen noch getestet werden. Bei dieser Bewertung wurde kein echtes Cloud-Konto autorisiert oder beschrieben.
Referenzen
Offizielle Dokumentation, geprüft am 2026-09-09: