import '../security/secret_store.dart'; /// The per-identity key scope for [account]: empty for the original identity /// (account 0, so its data keeps the legacy un-namespaced keys), otherwise a /// distinct namespace. Used by the per-identity stores (chats, profile, name /// cache) so switching identity never mixes one identity's data into another. String socialAccountScope(int account) => account == 0 ? '' : 'acct$account'; /// Remembers which social identity ("account") of the root seed is active, and /// how many the user has created, so identities can be switched and listed. /// /// Each account is a pseudonymous Nostr identity deterministically derived from /// the SAME root seed (see `NostrKeyDerivation.deriveFromSeed`), so switching /// never adds anything to back up — the one seed still regenerates them all. /// Keystore-backed: no plaintext at rest. class SocialAccountStore { SocialAccountStore(this._store); final SecretStore _store; static const _activeKey = 'tane.social.account.active'; static const _maxKey = 'tane.social.account.max'; /// The active account index (0 = the original identity). Future active() async => _readInt(_activeKey); /// The highest account index ever created (so the list is 0..max and a new /// identity takes max + 1). At least the active one always exists. Future maxCreated() async { final max = await _readInt(_maxKey); final activeIdx = await active(); return max > activeIdx ? max : activeIdx; } /// Switches the active identity to [account] (must already be within /// 0..maxCreated, or be maxCreated + 1 for a freshly created one). Future setActive(int account) async { if (account < 0) { throw ArgumentError.value(account, 'account', 'must be >= 0'); } await _store.write(_activeKey, '$account'); if (account > await _readInt(_maxKey)) { await _store.write(_maxKey, '$account'); } } /// Creates a brand-new identity (the next index) and makes it active. Returns /// the new account index. Future createNew() async { final next = await maxCreated() + 1; await setActive(next); return next; } Future _readInt(String key) async { final raw = await _store.read(key); if (raw == null || raw.isEmpty) return 0; return int.tryParse(raw) ?? 0; } }