use wasm_bindgen::prelude::*;
use crate::hardbinding::{self, Algorithm, DataHash, Exclusion, RustCrypto, UnicodeNfc};
fn js_err(e: crate::Error) -> JsError {
match e.code() {
Some(code) => JsError::new(&format!("{e} [{code}]")),
None => JsError::new(&e.to_string()),
}
}
fn algorithm(alg: &str) -> Result<Algorithm, JsError> {
Algorithm::from_id(alg).map_err(js_err)
}
#[wasm_bindgen(js_name = embed)]
pub fn embed(text: &str, payload: &[u8]) -> Result<String, JsError> {
crate::wrapper::embed(text, payload).map_err(js_err)
}
#[wasm_bindgen(js_name = encode)]
pub fn encode(payload: &[u8]) -> Result<String, JsError> {
crate::wrapper::encode(payload).map_err(js_err)
}
#[wasm_bindgen(js_name = encodePadded)]
pub fn encode_padded(payload: &[u8]) -> Result<String, JsError> {
crate::wrapper::encode_padded(payload).map_err(js_err)
}
#[wasm_bindgen(js_name = targetLength)]
pub fn target_length(manifest_len: usize) -> usize {
crate::wrapper::target_length(manifest_len)
}
#[wasm_bindgen(js_name = extract)]
pub fn extract(text: &str) -> Result<JsValue, JsError> {
let w = match crate::wrapper::extract(text) {
Ok(w) => w,
Err(crate::Error::NotFound) => return Ok(JsValue::NULL),
Err(e) => return Err(js_err(e)),
};
let out = js_sys::Object::new();
let _ = js_sys::Reflect::set(
&out,
&"payload".into(),
&js_sys::Uint8Array::from(&w.payload[..]).into(),
);
let _ = js_sys::Reflect::set(&out, &"version".into(), &w.version.into());
let _ = js_sys::Reflect::set(&out, &"start".into(), &(w.start as u32).into());
let _ = js_sys::Reflect::set(&out, &"length".into(), &(w.length as u32).into());
Ok(out.into())
}
#[wasm_bindgen(js_name = strip)]
pub fn strip(text: &str, start: usize, length: usize) -> Result<String, JsError> {
crate::wrapper::strip(text, start..start + length).map_err(js_err)
}
#[wasm_bindgen(js_name = computeDataHash)]
pub fn compute_data_hash(text: &str, alg: &str) -> Result<JsValue, JsError> {
let dh = hardbinding::compute_data_hash(text, algorithm(alg)?, &RustCrypto, &UnicodeNfc)
.map_err(js_err)?;
let out = js_sys::Object::new();
let _ = js_sys::Reflect::set(&out, &"alg".into(), &dh.alg.as_str().into());
let _ = js_sys::Reflect::set(
&out,
&"hash".into(),
&js_sys::Uint8Array::from(&dh.hash[..]).into(),
);
let ranges = js_sys::Array::new();
for e in &dh.exclusions {
let r = js_sys::Object::new();
let _ = js_sys::Reflect::set(&r, &"start".into(), &(e.start as u32).into());
let _ = js_sys::Reflect::set(&r, &"length".into(), &(e.length as u32).into());
ranges.push(&r);
}
let _ = js_sys::Reflect::set(&out, &"exclusions".into(), &ranges);
Ok(out.into())
}
#[wasm_bindgen(js_name = verifyDataHash)]
pub fn verify_data_hash(
text: &str,
hash: &[u8],
exclusion_starts: Vec<u32>,
exclusion_lengths: Vec<u32>,
alg: &str,
) -> Result<(), JsError> {
if exclusion_starts.len() != exclusion_lengths.len() {
return Err(JsError::new(
"exclusion_starts and exclusion_lengths must be the same length",
));
}
let dh = DataHash {
exclusions: exclusion_starts
.iter()
.zip(&exclusion_lengths)
.map(|(&start, &length)| Exclusion {
start: start as usize,
length: length as usize,
})
.collect(),
alg: algorithm(alg)?.id().to_string(),
hash: hash.to_vec(),
name: None,
};
hardbinding::verify_data_hash(text, &dh, &RustCrypto, &UnicodeNfc).map_err(js_err)
}