feat(wasm): manifest / item / settings encrypt+decrypt via SessionHandle
Adds six #[wasm_bindgen] functions (manifest_encrypt/decrypt, item_encrypt/decrypt, settings_encrypt/decrypt) plus a native round-trip test that verifies encrypt→core_decrypt and nonce uniqueness without calling js-sys (serde_wasm_bindgen::from_value is wasm32-only; documented in test comment).
This commit is contained in:
@@ -46,6 +46,75 @@ pub fn lock(handle: &SessionHandle) -> bool {
|
||||
|
||||
// Subsequent wasm_bindgen fns added in Tasks 19-21.
|
||||
|
||||
use serde_wasm_bindgen::to_value;
|
||||
use relicario_core::{
|
||||
decrypt_item, decrypt_manifest, decrypt_settings,
|
||||
encrypt_item, encrypt_manifest, encrypt_settings,
|
||||
Item, Manifest, VaultSettings,
|
||||
};
|
||||
|
||||
fn need_key(handle: &SessionHandle) -> Result<(), JsError> {
|
||||
if session::with(handle.0, |_| ()).is_some() { Ok(()) }
|
||||
else { Err(JsError::new("invalid or locked session handle")) }
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn manifest_decrypt(handle: &SessionHandle, encrypted: &[u8]) -> Result<JsValue, JsError> {
|
||||
need_key(handle)?;
|
||||
let out = session::with(handle.0, |k| decrypt_manifest(encrypted, k))
|
||||
.unwrap()
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
to_value(&out).map_err(|e| JsError::new(&e.to_string()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn manifest_encrypt(handle: &SessionHandle, manifest_json: &str) -> Result<Vec<u8>, JsError> {
|
||||
need_key(handle)?;
|
||||
let m: Manifest = serde_json::from_str(manifest_json)
|
||||
.map_err(|e| JsError::new(&format!("manifest json: {e}")))?;
|
||||
session::with(handle.0, |k| encrypt_manifest(&m, k))
|
||||
.unwrap()
|
||||
.map_err(|e| JsError::new(&e.to_string()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn item_decrypt(handle: &SessionHandle, encrypted: &[u8]) -> Result<JsValue, JsError> {
|
||||
need_key(handle)?;
|
||||
let out = session::with(handle.0, |k| decrypt_item(encrypted, k))
|
||||
.unwrap()
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
to_value(&out).map_err(|e| JsError::new(&e.to_string()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn item_encrypt(handle: &SessionHandle, item_json: &str) -> Result<Vec<u8>, JsError> {
|
||||
need_key(handle)?;
|
||||
let item: Item = serde_json::from_str(item_json)
|
||||
.map_err(|e| JsError::new(&format!("item json: {e}")))?;
|
||||
session::with(handle.0, |k| encrypt_item(&item, k))
|
||||
.unwrap()
|
||||
.map_err(|e| JsError::new(&e.to_string()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn settings_decrypt(handle: &SessionHandle, encrypted: &[u8]) -> Result<JsValue, JsError> {
|
||||
need_key(handle)?;
|
||||
let out = session::with(handle.0, |k| decrypt_settings(encrypted, k))
|
||||
.unwrap()
|
||||
.map_err(|e| JsError::new(&e.to_string()))?;
|
||||
to_value(&out).map_err(|e| JsError::new(&e.to_string()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn settings_encrypt(handle: &SessionHandle, settings_json: &str) -> Result<Vec<u8>, JsError> {
|
||||
need_key(handle)?;
|
||||
let s: VaultSettings = serde_json::from_str(settings_json)
|
||||
.map_err(|e| JsError::new(&format!("settings json: {e}")))?;
|
||||
session::with(handle.0, |k| encrypt_settings(&s, k))
|
||||
.unwrap()
|
||||
.map_err(|e| JsError::new(&e.to_string()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod session_tests {
|
||||
use super::*;
|
||||
@@ -70,4 +139,22 @@ mod session_tests {
|
||||
let byte = session::with(h, |k| k[0]);
|
||||
assert_eq!(byte, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn manifest_round_trip_via_handle() {
|
||||
use relicario_core::{Manifest, decrypt_manifest};
|
||||
session::clear();
|
||||
let h = session::insert(Zeroizing::new([0x55u8; 32]));
|
||||
let handle = SessionHandle(h);
|
||||
let key = Zeroizing::new([0x55u8; 32]);
|
||||
let empty = Manifest::new();
|
||||
let bytes = manifest_encrypt(&handle, &serde_json::to_string(&empty).unwrap()).unwrap();
|
||||
assert!(!bytes.is_empty());
|
||||
// Decrypt via core directly (avoids js-sys on native).
|
||||
let parsed: Manifest = decrypt_manifest(&bytes, &key).unwrap();
|
||||
assert_eq!(parsed.items.len(), 0);
|
||||
// Random nonces mean two encryptions of the same plaintext differ.
|
||||
let bytes2 = manifest_encrypt(&handle, &serde_json::to_string(&empty).unwrap()).unwrap();
|
||||
assert_ne!(bytes, bytes2, "nonces must differ");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user