use crate::client::{decrypt, decrypt_batch, encrypt, encrypt_batch};
#[cfg(all(feature = "offline", feature = "insecure"))]
use crate::client::{decrypt_global, encrypt_global};
use crate::data::json::builder::PEPJSONBuilder;
use crate::data::json::data::{EncryptedPEPJSONValue, PEPJSONValue};
use crate::data::json::structure::JSONStructure;
use crate::data::json::utils;
use crate::data::traits::Transcryptable;
use crate::factors::wasm::contexts::{
WASMEncryptionContext, WASMPseudonymizationDomain, WASMTranscryptionInfo,
};
use crate::factors::wasm::secrets::{WASMEncryptionSecret, WASMPseudonymizationSecret};
use crate::factors::TranscryptionInfo;
#[cfg(all(feature = "offline", feature = "insecure"))]
use crate::keys::wasm::types::WASMGlobalPublicKeys;
#[cfg(all(feature = "insecure", feature = "offline"))]
use crate::keys::wasm::types::WASMGlobalSecretKeys;
use crate::keys::wasm::types::WASMSessionKeys;
#[cfg(all(feature = "offline", feature = "insecure"))]
use crate::keys::GlobalPublicKeys;
use crate::keys::SessionKeys;
#[cfg(feature = "batch")]
use crate::transcryptor::transcrypt_batch;
use serde_json::Value;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(js_name = PEPJSONValue)]
#[derive(Clone)]
pub struct WASMPEPJSONValue(pub(crate) PEPJSONValue);
#[wasm_bindgen(js_class = PEPJSONValue)]
impl WASMPEPJSONValue {
#[wasm_bindgen(js_name = fromValue)]
pub fn from_value(value: JsValue) -> Result<WASMPEPJSONValue, JsValue> {
let json_value: Value = serde_wasm_bindgen::from_value(value)
.map_err(|e| JsValue::from_str(&format!("Invalid JSON value: {}", e)))?;
Ok(Self(PEPJSONValue::from_value(&json_value)))
}
#[wasm_bindgen(js_name = toJson)]
pub fn to_json(&self) -> Result<JsValue, JsValue> {
let json_value = self
.0
.to_value()
.map_err(|e| JsValue::from_str(&format!("Conversion failed: {}", e)))?;
serde_wasm_bindgen::to_value(&json_value)
.map_err(|e| JsValue::from_str(&format!("Failed to convert to JS: {}", e)))
}
#[wasm_bindgen]
pub fn structure(&self) -> WASMJSONStructure {
WASMJSONStructure(self.0.structure())
}
#[wasm_bindgen(js_name = padTo)]
pub fn pad_to(&self, structure: &WASMJSONStructure) -> Result<WASMPEPJSONValue, JsValue> {
self.0
.pad_to(&structure.0)
.map(Self)
.map_err(|e| JsValue::from_str(&format!("Padding failed: {}", e)))
}
}
#[wasm_bindgen(js_name = EncryptedPEPJSONValue)]
#[derive(Clone)]
pub struct WASMEncryptedPEPJSONValue(pub(crate) EncryptedPEPJSONValue);
#[wasm_bindgen(js_class = EncryptedPEPJSONValue)]
impl WASMEncryptedPEPJSONValue {
#[wasm_bindgen]
pub fn structure(&self) -> WASMJSONStructure {
WASMJSONStructure(self.0.structure())
}
#[wasm_bindgen]
pub fn transcrypt(
&self,
from_domain: &WASMPseudonymizationDomain,
to_domain: &WASMPseudonymizationDomain,
from_session: &WASMEncryptionContext,
to_session: &WASMEncryptionContext,
pseudonymization_secret: &WASMPseudonymizationSecret,
encryption_secret: &WASMEncryptionSecret,
) -> Result<WASMEncryptedPEPJSONValue, JsValue> {
let transcryption_info = TranscryptionInfo::new(
&from_domain.0,
&to_domain.0,
&from_session.0,
&to_session.0,
&pseudonymization_secret.0,
&encryption_secret.0,
);
let transcrypted = self.0.transcrypt(&transcryption_info);
Ok(WASMEncryptedPEPJSONValue(transcrypted))
}
#[wasm_bindgen(js_name = toJSON)]
pub fn to_json(&self) -> Result<String, JsValue> {
serde_json::to_string(&self.0)
.map_err(|e| JsValue::from_str(&format!("Serialization failed: {}", e)))
}
#[wasm_bindgen(js_name = fromJSON)]
pub fn from_json(json_str: &str) -> Result<WASMEncryptedPEPJSONValue, JsValue> {
let value: EncryptedPEPJSONValue = serde_json::from_str(json_str)
.map_err(|e| JsValue::from_str(&format!("Deserialization failed: {}", e)))?;
Ok(WASMEncryptedPEPJSONValue(value))
}
}
#[wasm_bindgen(js_name = JSONStructure)]
#[derive(Clone)]
pub struct WASMJSONStructure(pub(crate) JSONStructure);
#[wasm_bindgen(js_class = JSONStructure)]
impl WASMJSONStructure {
#[wasm_bindgen(js_name = toString)]
pub fn to_json_string(&self) -> String {
format!("{:?}", self.0)
}
#[wasm_bindgen(js_name = equals)]
pub fn equals(&self, other: &WASMJSONStructure) -> bool {
self.0 == other.0
}
#[wasm_bindgen(js_name = toJSON)]
pub fn to_json(&self) -> Result<String, JsValue> {
serde_json::to_string(&self.0)
.map_err(|e| JsValue::from_str(&format!("Serialization failed: {}", e)))
}
}
#[derive(Default)]
#[wasm_bindgen(js_name = PEPJSONBuilder)]
pub struct WASMPEPJSONBuilder {
builder: PEPJSONBuilder,
}
#[wasm_bindgen(js_class = PEPJSONBuilder)]
impl WASMPEPJSONBuilder {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::default()
}
#[wasm_bindgen(js_name = fromJson)]
pub fn from_json(
value: JsValue,
pseudonyms: Vec<String>,
) -> Result<WASMPEPJSONBuilder, JsValue> {
let json_value: Value = serde_wasm_bindgen::from_value(value)
.map_err(|e| JsValue::from_str(&format!("Invalid JSON value: {}", e)))?;
let pseudonym_refs: Vec<&str> = pseudonyms.iter().map(|s| s.as_str()).collect();
let builder = PEPJSONBuilder::from_json(&json_value, &pseudonym_refs)
.ok_or_else(|| JsValue::from_str("Invalid object or pseudonym field not a string"))?;
Ok(Self { builder })
}
#[wasm_bindgen]
pub fn attribute(mut self, key: &str, value: JsValue) -> Result<WASMPEPJSONBuilder, JsValue> {
let json_value: Value = serde_wasm_bindgen::from_value(value)
.map_err(|e| JsValue::from_str(&format!("Invalid JSON value: {}", e)))?;
self.builder = self.builder.attribute(key, json_value);
Ok(self)
}
#[wasm_bindgen]
pub fn pseudonym(mut self, key: &str, value: &str) -> WASMPEPJSONBuilder {
self.builder = self.builder.pseudonym(key, value);
self
}
#[wasm_bindgen]
pub fn build(self) -> WASMPEPJSONValue {
WASMPEPJSONValue(self.builder.build())
}
}
#[wasm_bindgen(js_name = encryptJson)]
pub fn wasm_encrypt_json(
value: &WASMPEPJSONValue,
session_keys: &WASMSessionKeys,
) -> WASMEncryptedPEPJSONValue {
let mut rng = rand::rng();
let keys: SessionKeys = (*session_keys).into();
let encrypted = encrypt(&value.0, &keys, &mut rng);
WASMEncryptedPEPJSONValue(encrypted)
}
#[cfg(feature = "batch")]
#[wasm_bindgen(js_name = encryptJsonBatch)]
pub fn wasm_encrypt_json_batch(
values: Vec<WASMPEPJSONValue>,
session_keys: &WASMSessionKeys,
) -> Result<Vec<WASMEncryptedPEPJSONValue>, JsValue> {
let mut rng = rand::rng();
let keys: SessionKeys = (*session_keys).into();
let rust_values: Vec<PEPJSONValue> = values.into_iter().map(|v| v.0).collect();
let encrypted = encrypt_batch(&rust_values, &keys, &mut rng)
.map_err(|e| JsValue::from_str(&format!("{}", e)))?;
Ok(encrypted
.into_iter()
.map(WASMEncryptedPEPJSONValue)
.collect())
}
#[wasm_bindgen(js_name = decryptJson)]
pub fn wasm_decrypt_json(
encrypted: &WASMEncryptedPEPJSONValue,
session_keys: &WASMSessionKeys,
) -> Result<WASMPEPJSONValue, JsValue> {
let keys: SessionKeys = (*session_keys).into();
#[cfg(feature = "elgamal3")]
let decrypted = decrypt(&encrypted.0, &keys)
.ok_or_else(|| JsValue::from_str("Decryption failed: key mismatch"))?;
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt(&encrypted.0, &keys);
Ok(WASMPEPJSONValue(decrypted))
}
#[cfg(feature = "batch")]
#[wasm_bindgen(js_name = decryptJsonBatch)]
pub fn wasm_decrypt_json_batch(
encrypted: Vec<WASMEncryptedPEPJSONValue>,
session_keys: &WASMSessionKeys,
) -> Result<Vec<WASMPEPJSONValue>, JsValue> {
let keys: SessionKeys = (*session_keys).into();
let rust_encrypted: Vec<EncryptedPEPJSONValue> = encrypted.into_iter().map(|v| v.0).collect();
let decrypted =
decrypt_batch(&rust_encrypted, &keys).map_err(|e| JsValue::from_str(&format!("{}", e)))?;
Ok(decrypted.into_iter().map(WASMPEPJSONValue).collect())
}
#[cfg(feature = "batch")]
#[wasm_bindgen(js_name = transcryptJsonBatch)]
pub fn wasm_transcrypt_json_batch(
values: Vec<WASMEncryptedPEPJSONValue>,
transcryption_info: &WASMTranscryptionInfo,
) -> Result<Vec<WASMEncryptedPEPJSONValue>, JsValue> {
let mut rng = rand::rng();
let mut rust_values: Vec<EncryptedPEPJSONValue> = values.into_iter().map(|v| v.0).collect();
let transcrypted = transcrypt_batch(&mut rust_values, &transcryption_info.0, &mut rng)
.map_err(|e| JsValue::from_str(&format!("{}", e)))?;
Ok(transcrypted
.into_vec()
.into_iter()
.map(WASMEncryptedPEPJSONValue)
.collect())
}
#[cfg(all(feature = "offline", feature = "insecure"))]
#[wasm_bindgen(js_name = encryptJsonGlobal)]
pub fn wasm_encrypt_json_global(
value: &WASMPEPJSONValue,
global_keys: &WASMGlobalPublicKeys,
) -> WASMEncryptedPEPJSONValue {
let mut rng = rand::rng();
let keys = GlobalPublicKeys {
pseudonym: (*global_keys.pseudonym().0).into(),
attribute: (*global_keys.attribute().0).into(),
};
WASMEncryptedPEPJSONValue(encrypt_global(&value.0, &keys, &mut rng))
}
#[cfg(all(feature = "insecure", feature = "offline"))]
#[wasm_bindgen(js_name = decryptJsonGlobal)]
pub fn wasm_decrypt_json_global(
encrypted: &WASMEncryptedPEPJSONValue,
global_secret_keys: &WASMGlobalSecretKeys,
) -> Result<WASMPEPJSONValue, JsValue> {
let keys = crate::keys::GlobalSecretKeys {
pseudonym: global_secret_keys.pseudonym().0 .0.into(),
attribute: global_secret_keys.attribute().0 .0.into(),
};
#[cfg(feature = "elgamal3")]
let decrypted = decrypt_global(&encrypted.0, &keys)
.ok_or_else(|| JsValue::from_str("Decryption failed: key mismatch"))?;
#[cfg(not(feature = "elgamal3"))]
let decrypted = decrypt_global(&encrypted.0, &keys);
Ok(WASMPEPJSONValue(decrypted))
}
#[wasm_bindgen(js_name = boolToByte)]
pub fn wasm_bool_to_byte(b: bool) -> u8 {
utils::bool_to_byte(b)
}
#[wasm_bindgen(js_name = byteToBool)]
pub fn wasm_byte_to_bool(byte: u8) -> Result<bool, JsValue> {
utils::byte_to_bool(byte).map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen(js_name = numberToBytes)]
pub fn wasm_number_to_bytes(n: f64) -> Vec<u8> {
let num = serde_json::Number::from_f64(n).unwrap_or(serde_json::Number::from(0));
utils::number_to_bytes(&num).to_vec()
}
#[wasm_bindgen(js_name = bytesToNumber)]
pub fn wasm_bytes_to_number(bytes: Vec<u8>) -> Result<f64, JsValue> {
if bytes.len() != 9 {
return Err(JsValue::from_str("Expected exactly 9 bytes"));
}
let arr: [u8; 9] = bytes
.try_into()
.map_err(|_| JsValue::from_str("Invalid byte array"))?;
let num = utils::bytes_to_number(&arr);
Ok(num.as_f64().unwrap_or(0.0))
}
#[wasm_bindgen(js_name = unifyStructures)]
pub fn wasm_unify_structures(
structures: Vec<WASMJSONStructure>,
) -> Result<WASMJSONStructure, JsValue> {
let rust_structures: Vec<JSONStructure> = structures.into_iter().map(|s| s.0).collect();
crate::data::json::structure::unify_structures(&rust_structures)
.map(WASMJSONStructure)
.map_err(|e| JsValue::from_str(&format!("Unification failed: {}", e)))
}