Files
relicario/crates/relicario-wasm/src/session.rs

58 lines
1.7 KiB
Rust

//! Opaque session-handle bridge. The master key never leaves WASM linear
//! memory; JS receives only a u32 handle that it passes back on every
//! subsequent call.
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, SessionData>> = RefCell::new(HashMap::new());
static NEXT_HANDLE: RefCell<u32> = const { RefCell::new(1) };
}
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;
*n = n.wrapping_add(1);
if *n == 0 { *n = 1; } // avoid reserving 0 as a valid handle
h
});
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(|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 {
SESSIONS.with(|s| s.borrow_mut().remove(&handle).is_some())
}
/// For tests only — empty the table and wipe all sessions.
#[cfg(test)]
pub fn clear() {
SESSIONS.with(|s| s.borrow_mut().clear());
}