use wasm_bindgen::prelude::*;
use crate::document::Manifest;
use crate::hardbinding::{self, Algorithm, DataHash, Exclusion, Sha2};
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(html: &[u8], store: &[u8]) -> Result<Vec<u8>, JsError> {
crate::document::embed(html, store).map_err(js_err)
}
#[wasm_bindgen(js_name = embedReference)]
pub fn embed_reference(html: &[u8], href: &str) -> Result<Vec<u8>, JsError> {
crate::document::embed_reference(html, href).map_err(js_err)
}
#[wasm_bindgen(js_name = remove)]
pub fn remove(html: &[u8]) -> Result<Vec<u8>, JsError> {
crate::document::remove(html).map_err(js_err)
}
#[wasm_bindgen(js_name = extract)]
pub fn extract(html: &[u8]) -> Result<JsValue, JsError> {
let manifest = match crate::document::extract(html) {
Ok(m) => m,
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, &"start".into(), &(manifest.start() as u32).into());
let _ = js_sys::Reflect::set(&out, &"length".into(), &(manifest.length() as u32).into());
match &manifest {
Manifest::Embedded { store, .. } => {
let _ = js_sys::Reflect::set(&out, &"kind".into(), &"embedded".into());
let _ = js_sys::Reflect::set(
&out,
&"store".into(),
&js_sys::Uint8Array::from(&store[..]).into(),
);
}
Manifest::Referenced { href, .. } => {
let _ = js_sys::Reflect::set(&out, &"kind".into(), &"referenced".into());
let _ = js_sys::Reflect::set(&out, &"href".into(), &href.as_str().into());
}
}
Ok(out.into())
}
#[wasm_bindgen(js_name = computeDataHash)]
pub fn compute_data_hash(html: &[u8], alg: &str) -> Result<JsValue, JsError> {
let dh = hardbinding::compute_data_hash(html, algorithm(alg)?, &Sha2).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(
html: &[u8],
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(html, &dh, &Sha2).map_err(js_err)
}
#[wasm_bindgen(js_name = inlineHashBeforeEmbed)]
pub fn inline_hash_before_embed(html: &[u8], alg: &str) -> Result<Vec<u8>, JsError> {
Ok(hardbinding::inline_hash_before_embed(
html,
algorithm(alg)?,
&Sha2,
))
}