//! 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; thread_local! { static SESSIONS: RefCell>> = RefCell::new(HashMap::new()); static NEXT_HANDLE: RefCell = const { RefCell::new(1) }; } pub fn insert(key: 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, key); }); handle } pub fn with(handle: u32, f: F) -> Option where F: FnOnce(&Zeroizing<[u8; 32]>) -> R, { SESSIONS.with(|s| s.borrow().get(&handle).map(f)) } 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()); }