From 3ffcc60ee8a17ada0522a0f310e74a0eab198d93 Mon Sep 17 00:00:00 2001 From: Ada Date: Sun, 1 Feb 2026 15:22:32 -0800 Subject: [PATCH] feat(vault): vault storage (user-isolated, multi-account) --- src/config/index.ts | 11 +++++++---- src/screens/MeScreen.tsx | 1 + src/screens/VaultScreen.tsx | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/config/index.ts b/src/config/index.ts index b09ca54..cd88aff 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -67,9 +67,9 @@ export const API_ENDPOINTS = { // ============================================================================= // Vault storage (user-isolated, multi-account) // ============================================================================= -// - AsyncStorage keys for vault state (S0 share, initialized flag). -// - User-scoped: each account has its own keys so vault state is isolated. -// - Store: use getVaultStorageKeys(userId) and write to INITIALIZED / SHARE_DEVICE. +// - AsyncStorage keys for vault state (S0 share, initialized flag, mnemonic part backup). +// - User-scoped: each account has its own keys so vault/mnemonic state is isolated. +// - Store: use getVaultStorageKeys(userId) and write to INITIALIZED / SHARE_DEVICE / MNEMONIC_PART_LOCAL. // - Clear: use same keys in multiRemove (e.g. MeScreen Reset Vault State). // - Multi-account: same device, multiple users → each has independent vault (no cross-user leakage). @@ -79,21 +79,24 @@ const VAULT_KEY_PREFIX = 'sentinel_vault'; export const VAULT_STORAGE_KEYS = { INITIALIZED: 'sentinel_vault_initialized', SHARE_DEVICE: 'sentinel_vault_s0', + MNEMONIC_PART_LOCAL: 'sentinel_mnemonic_part_local', } as const; /** * Returns vault storage keys for the given user (user isolation). - * - Use for: reading S0, writing S0 after mnemonic, clearing on Reset Vault State. + * - Use for: reading/writing S0, mnemonic part backup, clearing on Reset Vault State. * - userId null → guest namespace (_guest). userId set → per-user namespace (_u{userId}). */ export function getVaultStorageKeys(userId: number | string | null): { INITIALIZED: string; SHARE_DEVICE: string; + MNEMONIC_PART_LOCAL: string; } { const suffix = userId != null ? `_u${userId}` : '_guest'; return { INITIALIZED: `${VAULT_KEY_PREFIX}_initialized${suffix}`, SHARE_DEVICE: `${VAULT_KEY_PREFIX}_s0${suffix}`, + MNEMONIC_PART_LOCAL: `sentinel_mnemonic_part_local${suffix}`, }; } diff --git a/src/screens/MeScreen.tsx b/src/screens/MeScreen.tsx index 7f97aba..e06ed9b 100644 --- a/src/screens/MeScreen.tsx +++ b/src/screens/MeScreen.tsx @@ -315,6 +315,7 @@ export default function MeScreen() { await AsyncStorage.multiRemove([ vaultKeys.INITIALIZED, vaultKeys.SHARE_DEVICE, + vaultKeys.MNEMONIC_PART_LOCAL, ]); setResetVaultFeedback({ status: 'success', diff --git a/src/screens/VaultScreen.tsx b/src/screens/VaultScreen.tsx index 749701e..56d59c4 100644 --- a/src/screens/VaultScreen.tsx +++ b/src/screens/VaultScreen.tsx @@ -258,7 +258,7 @@ export default function VaultScreen() { setProgressIndex(0); progressAnim.setValue(0); setTimeout(() => setShowMnemonic(true), 200); - AsyncStorage.setItem('sentinel_mnemonic_part_local', parts[0].join(' ')).catch(() => { + AsyncStorage.setItem(vaultKeys.MNEMONIC_PART_LOCAL, parts[0].join(' ')).catch(() => { // Best-effort local store; UI remains available }); };