mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-05 20:32:27 +00:00
feat(sync): storage-credential sync data layer (push/pull/clear)
Wires the encrypted-sync core (0abb82b9) to the live client + active signer and
adds the storage-credential sync service. No UI yet — the Storage pane toggle is
the next increment.
- js/nostr/encryptedSyncFacade.js: default encryptedSync instance bound to
nostrClient (write set via getDeletePublishRelays, read relays, pool) and the
active signer's signEvent. Keeps the core pure/testable.
- js/services/storageService.js: exportAccountRecord / importAccountRecord — get
the on-disk account record and restore it on another device. Import REPLACES
the local record (same-pubkey envelope unlocks with the same signer); cross-
device merge is a follow-up.
- js/services/storageSyncService.js: enable/disable/push/pull under d-tag
"bitvid:storage-connections", with a per-pubkey opt-in flag (off by default).
enable() pushes immediately; disable() wipes the published note.
tests/storage-sync-service.test.mjs: enable-pushes-exported-record, pull-restores
on a fresh device, disable-clears, empty-record-doesn't-publish. Mutation-verified
(skip-import and skip-clear both fail).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
0abb82b933
commit
6f7f419636
4 files changed
+366
No files matched your search
@@ -611,6 +611,42 @@ export class StorageService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the raw on-disk account record for a pubkey, for opt-in encrypted
|
||||
* cross-login sync (todo #15). The record is already self-protected
|
||||
* (encryptedMasterKey envelope + per-connection AES-GCM payloads) but its
|
||||
* `meta` is plaintext (bucket/endpoint names), so callers MUST re-encrypt the
|
||||
* whole record to self before publishing. Returns null when nothing is stored.
|
||||
*/
|
||||
async exportAccountRecord(pubkey) {
|
||||
if (!pubkey) {
|
||||
return null;
|
||||
}
|
||||
const account = await this._getAccount(pubkey);
|
||||
return account || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an account record previously exported via {@link exportAccountRecord}
|
||||
* (e.g. pulled from the user's encrypted Nostr note on a second device). The
|
||||
* record is encrypted-to-self by the SAME pubkey, so its envelope unlocks with
|
||||
* the same signer. This REPLACES the local record for the pubkey; the next
|
||||
* unlock decrypts the imported master key. (Merge across devices is a follow-up.)
|
||||
*/
|
||||
async importAccountRecord(pubkey, record) {
|
||||
if (!pubkey) {
|
||||
throw new Error("Pubkey required to import storage account record.");
|
||||
}
|
||||
if (!record || typeof record !== "object" || !record.encryptedMasterKey) {
|
||||
throw new Error("Invalid storage account record.");
|
||||
}
|
||||
const toSave = { ...record, pubkey };
|
||||
await this._saveAccount(toSave);
|
||||
// Drop any in-memory master key so the next unlock uses the imported envelope.
|
||||
this.lock(pubkey);
|
||||
return toSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a connection as default for uploads (updates metadata).
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user