817f71790ba4

add vault.ts unlockWithKey (bypass Argon2id, use pre-derived key) and getDerivedKeyHex

time
2026-05-05 00:18 UTC · 5 months ago
machine
koh2
parent
567532481e30
1 file src/background/vault.ts+42 −0
src/background/vault.ts+42 −0
@@ -702,6 +702,48 @@702702   return derivedKey !== null;703703 }704704 705+// Opens the vault using a pre-derived AES-256 key (skipping Argon2id).706+// Used by Android biometric unlock — the key was derived on the native side.707+export async function unlockWithKey(708+  masterKeyHex: string,709+): Promise<{ ok: true } | { ok: false; error: string }> {710+  try {711+    const keyBytes = unhex(masterKeyHex);712+    const masterKey = await crypto.subtle.importKey(713+      "raw",714+      keyBytes,715+      { name: "AES-GCM" },716+      false,717+      ["decrypt"],718+    );719+    const payload = await tryDecryptSlot(await loadSlot(SLOT_A), masterKey);720+    if (!payload) return { ok: false, error: "invalid_key" };721+722+    derivedKey = masterKey;723+    vaultMode = "real";724+    entries = payload.entries;725+    duressConfigured = payload.duressConfigured;726+    buildDomainIndexSync(entries);727+    await loadSettings();728+    touchAutoLock();729+    return { ok: true };730+  } catch {731+    return { ok: false, error: "invalid_key" };732+  }733+}734+735+// Returns the current in-memory derived key as a hex string.736+// Used by the biometric enable flow in Settings to store the key in Android Keystore.737+export function getDerivedKeyHex(): string {738+  if (!derivedKey) throw new Error("vault_not_unlocked");739+  return hex(derivedKeyBytes());740+}741+742+function derivedKeyBytes(): Uint8Array {743+  const buf = derivedKey!.exportKey("raw") as ArrayBuffer;744+  return new Uint8Array(buf);745+}746+705747 export function getEntries(): VaultEntry[] {706748   if (!derivedKey) throw new Error("vault locked");707749   return entries.filter((entry) => !entry.deletedAt);

view file