feat(wasm): persist/restore device key under master key; org_unwrap_key reads DEVICE_STATE
- device.rs: add PersistedDeviceState (serde mirror), export_state_bytes (plaintext JSON in Zeroizing<Vec<u8>>, NOT a wasm_bindgen export), import_state_bytes (repopulates DEVICE_STATE with Zeroizing<String> keys), signing_seed (extracts ed25519 seed via core::device::extract_ed25519_seed) - lib.rs: add persist_device_key (#[wasm_bindgen], encrypts state bytes under master key via relicario_core::crypto::encrypt; ciphertext only reaches JS), restore_device_key (#[wasm_bindgen], decrypts inside WASM then calls import_state_bytes; plaintext never leaves WASM) - lib.rs: refactor org_unwrap_key to drop device_private_openssh param; reads seed from DEVICE_STATE via device::signing_seed() - lib.rs: update org_unwrap_key_yields_a_session_that_decrypts_org_blobs to new signature (register_device first, use signing_pub for wrap_org_key) - lib.rs: add device_persist_tests module (4 tests: round-trip, org-unwrap post-restore, ciphertext-not-plaintext, no-device-error) - lib.rs: add DEVICE_TEST_LOCK static to serialize DEVICE_STATE-touching tests - lib.rs: add #[derive(Debug)] to SessionHandle - wasm.d.ts: update org_unwrap_key sig; declare persist_device_key + restore_device_key All gates: cargo test -p relicario-wasm (15/15), cargo test -p relicario-core (no regression), cargo build --target wasm32-unknown-unknown (clean), clippy -D warnings (clean). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014s527M917W47LDrfQ4t47g
This commit is contained in:
15
extension/src/wasm.d.ts
vendored
15
extension/src/wasm.d.ts
vendored
@@ -87,9 +87,22 @@ declare module 'relicario-wasm' {
|
||||
export function wasm_generate_recovery_qr(handle: SessionHandle, passphrase: string): string;
|
||||
export function wasm_unwrap_recovery_qr(payload_b64: string, passphrase: string): Uint8Array;
|
||||
|
||||
export function org_unwrap_key(keys_blob: Uint8Array, device_private_openssh: string): SessionHandle;
|
||||
/** Unwrap an ECIES-wrapped org master key using the registered device key in DEVICE_STATE. */
|
||||
export function org_unwrap_key(keys_blob: Uint8Array): SessionHandle;
|
||||
export function org_manifest_decrypt(handle: SessionHandle, encrypted: Uint8Array): unknown;
|
||||
export function org_manifest_encrypt(handle: SessionHandle, manifest_json: string): Uint8Array;
|
||||
/**
|
||||
* Encrypt the registered device key under the vault master key.
|
||||
* Returns CIPHERTEXT — the device private key never crosses to JS.
|
||||
* Store the returned bytes in chrome.storage.local as `device_key_enc`.
|
||||
*/
|
||||
export function persist_device_key(handle: SessionHandle): Uint8Array;
|
||||
/**
|
||||
* Decrypt a persisted device-key blob under the master key and repopulate
|
||||
* DEVICE_STATE. Decryption happens inside WASM; plaintext never reaches JS.
|
||||
* Call at unlock time with the `device_key_enc` blob from chrome.storage.local.
|
||||
*/
|
||||
export function restore_device_key(handle: SessionHandle, encrypted: Uint8Array): void;
|
||||
// Pluggable second factor: key-file bindings (Task 3)
|
||||
export function unlock_with_secret(passphrase: string, secret: Uint8Array, salt: Uint8Array, params_json: string): SessionHandle;
|
||||
export function keyfile_encode(secret: Uint8Array): Uint8Array;
|
||||
|
||||
Reference in New Issue
Block a user