fix(ext/sw): type-correct session.setCurrent + simplify create/attach handlers
Fixes a TS2345 that npx tsc --noEmit missed (it cannot resolve the generated wasm/relicario_wasm types, degrading SessionHandle) but the webpack build catches with real types: session.setCurrent(handle) was passed a SessionHandle|null. Capture the unlock result in a non-null `const h: SessionHandle` for the in-scope ops; `handle` remains the ownership tracker the finally block cleans up. Simplify pass: extract the shared register_device + addDevice + persist-config tail into registerDeviceAndPersistConfig (both handlers ended identically), hoist the Argon2 params literal to DEFAULT_PARAMS_JSON, and fan out the two independent read-only GETs in the attach path via Promise.all. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,32 @@ function requireWasm(): any {
|
||||
return wasm;
|
||||
}
|
||||
|
||||
const DEFAULT_PARAMS_JSON = '{"argon2_m":65536,"argon2_t":3,"argon2_p":4}';
|
||||
|
||||
/// Register this device on the remote (devices.json) and persist the vault
|
||||
/// config + reference image locally so future unlocks work. Shared by the
|
||||
/// create and attach flows — both finish with this identical tail.
|
||||
async function registerDeviceAndPersistConfig(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
w: any,
|
||||
git: GitHost,
|
||||
config: VaultConfig,
|
||||
referenceImageBytes: Uint8Array,
|
||||
deviceName: string,
|
||||
): Promise<void> {
|
||||
const keys = w.register_device(deviceName) as { signing_public_key: string };
|
||||
await devices.addDevice(git, {
|
||||
name: deviceName,
|
||||
public_key: keys.signing_public_key,
|
||||
added_at: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
await chrome.storage.local.set({
|
||||
vaultConfig: config,
|
||||
imageBase64: uint8ArrayToBase64(referenceImageBytes),
|
||||
device_name: deviceName,
|
||||
});
|
||||
}
|
||||
|
||||
export async function handleCreateVault(
|
||||
msg: { config: VaultConfig; passphrase: string; carrierImageBytes: ArrayBuffer; deviceName: string },
|
||||
state: PopupState,
|
||||
@@ -35,35 +61,25 @@ export async function handleCreateVault(
|
||||
|
||||
const salt = new Uint8Array(32);
|
||||
crypto.getRandomValues(salt);
|
||||
const paramsJson = '{"argon2_m":65536,"argon2_t":3,"argon2_p":4}';
|
||||
handle = w.unlock(msg.passphrase, referenceImageBytes, salt, paramsJson);
|
||||
// Capture the unlock result in a non-null binding for the in-scope ops;
|
||||
// `handle` stays the ownership tracker the finally block cleans up.
|
||||
const h: SessionHandle = w.unlock(msg.passphrase, referenceImageBytes, salt, DEFAULT_PARAMS_JSON);
|
||||
handle = h;
|
||||
|
||||
const encryptedManifest = new Uint8Array(w.manifest_encrypt(handle, '{"schema_version":2,"items":{}}'));
|
||||
const settingsJson = w.default_vault_settings_json();
|
||||
const encryptedSettings = new Uint8Array(w.settings_encrypt(handle, settingsJson));
|
||||
const encryptedManifest = new Uint8Array(w.manifest_encrypt(h, '{"schema_version":2,"items":{}}'));
|
||||
const encryptedSettings = new Uint8Array(w.settings_encrypt(h, w.default_vault_settings_json()));
|
||||
|
||||
const { config } = msg;
|
||||
const git = createGitHost(config.hostType, config.hostUrl, config.repoPath, config.apiToken);
|
||||
await git.writeFileCreateOnly('.relicario/salt', salt, 'init: vault salt');
|
||||
await git.writeFileCreateOnly('.relicario/params.json', new TextEncoder().encode(paramsJson), 'init: KDF parameters');
|
||||
await git.writeFileCreateOnly('.relicario/params.json', new TextEncoder().encode(DEFAULT_PARAMS_JSON), 'init: KDF parameters');
|
||||
await git.writeFileCreateOnly('manifest.enc', encryptedManifest, 'init: encrypted manifest');
|
||||
await git.writeFileCreateOnly('settings.enc', encryptedSettings, 'init: encrypted settings');
|
||||
|
||||
const keys = w.register_device(msg.deviceName) as { signing_public_key: string; deploy_public_key: string };
|
||||
await devices.addDevice(git, {
|
||||
name: msg.deviceName,
|
||||
public_key: keys.signing_public_key,
|
||||
added_at: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
|
||||
await chrome.storage.local.set({
|
||||
vaultConfig: config,
|
||||
imageBase64: uint8ArrayToBase64(referenceImageBytes),
|
||||
device_name: msg.deviceName,
|
||||
});
|
||||
await registerDeviceAndPersistConfig(w, git, config, referenceImageBytes, msg.deviceName);
|
||||
|
||||
// SW now owns the unlocked session — keeps the handle alive (enables recoveryQrAvailable).
|
||||
session.setCurrent(handle);
|
||||
session.setCurrent(h);
|
||||
state.gitHost = git;
|
||||
state.manifest = { schema_version: 2, items: {} } as Manifest;
|
||||
handle = null; // ownership transferred — do NOT lock-and-free in finally
|
||||
@@ -92,28 +108,21 @@ export async function handleAttachVault(
|
||||
const { config } = msg;
|
||||
const git = createGitHost(config.hostType, config.hostUrl, config.repoPath, config.apiToken);
|
||||
|
||||
const meta = await fetchVaultMeta(git);
|
||||
const encryptedManifest = await git.readFile('manifest.enc');
|
||||
// The vault metadata and manifest are independent read-only GETs — fan out.
|
||||
const [meta, encryptedManifest] = await Promise.all([
|
||||
fetchVaultMeta(git),
|
||||
git.readFile('manifest.enc'),
|
||||
]);
|
||||
|
||||
handle = w.unlock(msg.passphrase, referenceImageBytes, meta.salt, meta.paramsJson);
|
||||
const h: SessionHandle = w.unlock(msg.passphrase, referenceImageBytes, meta.salt, meta.paramsJson);
|
||||
handle = h;
|
||||
// manifest_decrypt verifies the passphrase + reference image — throws on AEAD failure.
|
||||
const manifest = w.manifest_decrypt(handle, encryptedManifest) as Manifest;
|
||||
const manifest = w.manifest_decrypt(h, encryptedManifest) as Manifest;
|
||||
|
||||
const keys = w.register_device(msg.deviceName) as { signing_public_key: string; deploy_public_key: string };
|
||||
await devices.addDevice(git, {
|
||||
name: msg.deviceName,
|
||||
public_key: keys.signing_public_key,
|
||||
added_at: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
|
||||
await chrome.storage.local.set({
|
||||
vaultConfig: config,
|
||||
imageBase64: uint8ArrayToBase64(referenceImageBytes),
|
||||
device_name: msg.deviceName,
|
||||
});
|
||||
await registerDeviceAndPersistConfig(w, git, config, referenceImageBytes, msg.deviceName);
|
||||
|
||||
// SW now owns the unlocked session — transfer ownership to the session.
|
||||
session.setCurrent(handle);
|
||||
session.setCurrent(h);
|
||||
state.gitHost = git;
|
||||
state.manifest = manifest;
|
||||
handle = null; // ownership transferred — do NOT lock-and-free in finally
|
||||
|
||||
Reference in New Issue
Block a user