feat(wasm): session stores image_secret for recovery QR generation
This commit is contained in:
@@ -8,6 +8,7 @@ mod session;
|
||||
mod device;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
use relicario_core::{derive_master_key, imgsecret, KdfParams};
|
||||
|
||||
@@ -36,7 +37,8 @@ pub fn unlock(
|
||||
.map_err(|_| JsError::new("salt must be exactly 32 bytes"))?;
|
||||
let master_key = derive_master_key(passphrase.as_bytes(), &image_secret, salt_arr, ¶ms)
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
let handle = session::insert(master_key);
|
||||
let stored_secret = Zeroizing::new(image_secret);
|
||||
let handle = session::insert(master_key, stored_secret);
|
||||
Ok(SessionHandle(handle))
|
||||
}
|
||||
|
||||
@@ -492,7 +494,7 @@ mod session_tests {
|
||||
#[test]
|
||||
fn insert_then_remove_clears_entry() {
|
||||
session::clear();
|
||||
let h = session::insert(Zeroizing::new([0x11u8; 32]));
|
||||
let h = session::insert(Zeroizing::new([0x11u8; 32]), Zeroizing::new([0u8; 32]));
|
||||
assert_ne!(h, 0);
|
||||
assert!(session::remove(h));
|
||||
assert!(!session::remove(h)); // second remove false
|
||||
@@ -501,7 +503,7 @@ mod session_tests {
|
||||
#[test]
|
||||
fn with_yields_key_only_while_session_lives() {
|
||||
session::clear();
|
||||
let h = session::insert(Zeroizing::new([0x22u8; 32]));
|
||||
let h = session::insert(Zeroizing::new([0x22u8; 32]), Zeroizing::new([0u8; 32]));
|
||||
let byte = session::with(h, |k| k[0]);
|
||||
assert_eq!(byte, Some(0x22));
|
||||
session::remove(h);
|
||||
@@ -513,7 +515,7 @@ mod session_tests {
|
||||
fn manifest_round_trip_via_handle() {
|
||||
use relicario_core::{Manifest, decrypt_manifest};
|
||||
session::clear();
|
||||
let h = session::insert(Zeroizing::new([0x55u8; 32]));
|
||||
let h = session::insert(Zeroizing::new([0x55u8; 32]), Zeroizing::new([0u8; 32]));
|
||||
let handle = SessionHandle(h);
|
||||
let key = Zeroizing::new([0x55u8; 32]);
|
||||
let empty = Manifest::new();
|
||||
|
||||
@@ -6,12 +6,17 @@ use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub struct SessionData {
|
||||
pub master_key: Zeroizing<[u8; 32]>,
|
||||
pub image_secret: Zeroizing<[u8; 32]>,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static SESSIONS: RefCell<HashMap<u32, Zeroizing<[u8; 32]>>> = RefCell::new(HashMap::new());
|
||||
static SESSIONS: RefCell<HashMap<u32, SessionData>> = RefCell::new(HashMap::new());
|
||||
static NEXT_HANDLE: RefCell<u32> = const { RefCell::new(1) };
|
||||
}
|
||||
|
||||
pub fn insert(key: Zeroizing<[u8; 32]>) -> u32 {
|
||||
pub fn insert(master_key: Zeroizing<[u8; 32]>, image_secret: Zeroizing<[u8; 32]>) -> u32 {
|
||||
let handle = NEXT_HANDLE.with(|n| {
|
||||
let mut n = n.borrow_mut();
|
||||
let h = *n;
|
||||
@@ -19,15 +24,26 @@ pub fn insert(key: Zeroizing<[u8; 32]>) -> u32 {
|
||||
if *n == 0 { *n = 1; } // avoid reserving 0 as a valid handle
|
||||
h
|
||||
});
|
||||
SESSIONS.with(|s| { s.borrow_mut().insert(handle, key); });
|
||||
SESSIONS.with(|s| {
|
||||
s.borrow_mut().insert(handle, SessionData { master_key, image_secret });
|
||||
});
|
||||
handle
|
||||
}
|
||||
|
||||
/// Access the master key for a handle. Preserves original `with` signature for all existing callers.
|
||||
pub fn with<F, R>(handle: u32, f: F) -> Option<R>
|
||||
where
|
||||
F: FnOnce(&Zeroizing<[u8; 32]>) -> R,
|
||||
{
|
||||
SESSIONS.with(|s| s.borrow().get(&handle).map(f))
|
||||
SESSIONS.with(|s| s.borrow().get(&handle).map(|d| f(&d.master_key)))
|
||||
}
|
||||
|
||||
/// Access the image_secret for a handle (used by recovery QR).
|
||||
pub fn with_image_secret<F, R>(handle: u32, f: F) -> Option<R>
|
||||
where
|
||||
F: FnOnce(&Zeroizing<[u8; 32]>) -> R,
|
||||
{
|
||||
SESSIONS.with(|s| s.borrow().get(&handle).map(|d| f(&d.image_secret)))
|
||||
}
|
||||
|
||||
pub fn remove(handle: u32) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user