use std::convert::{TryFrom as _, TryInto as _};
use wasm_bindgen::prelude::*;
use js_sys::Array;
use super::utils;
use super::{
ciphertext,
ciphertext::{Ciphertext, CiphertextVersion},
};
use super::{
key,
key::{KeyVersion, PrivateKey, PublicKey},
};
use super::{
password_hash,
password_hash::{PasswordHash, PasswordHashVersion},
};
use super::{
secret_sharing,
secret_sharing::{SecretSharingVersion, Share},
};
use super::{
signature,
signature::{Signature, SignatureVersion},
};
use super::{
signing_key,
signing_key::{SigningKeyPair, SigningKeyVersion, SigningPublicKey},
};
use super::Argon2Parameters;
use super::DataType;
#[wasm_bindgen(inspectable)]
#[derive(Clone)]
pub struct KeyPair {
private_key: PrivateKey,
public_key: PublicKey,
}
#[wasm_bindgen]
impl KeyPair {
#[wasm_bindgen(getter)]
pub fn private(&self) -> PrivateKey {
self.private_key.clone()
}
#[wasm_bindgen(getter)]
pub fn public(&self) -> PublicKey {
self.public_key.clone()
}
}
impl From<key::KeyPair> for KeyPair {
fn from(keypair: key::KeyPair) -> Self {
Self {
private_key: keypair.private_key,
public_key: keypair.public_key,
}
}
}
impl From<KeyPair> for key::KeyPair {
fn from(keypair: KeyPair) -> Self {
Self {
private_key: keypair.private_key,
public_key: keypair.public_key,
}
}
}
#[wasm_bindgen]
impl Argon2Parameters {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self::default()
}
#[wasm_bindgen(getter)]
pub fn bytes(&self) -> Vec<u8> {
self.into()
}
#[wasm_bindgen(js_name = "fromBytes")]
pub fn from_bytes(buffer: &[u8]) -> Result<Argon2Parameters, JsValue> {
Ok(Self::try_from(buffer)?)
}
}
#[wasm_bindgen]
impl PublicKey {
#[wasm_bindgen(getter)]
pub fn bytes(&self) -> Vec<u8> {
self.clone().into()
}
#[wasm_bindgen(js_name = "fromBytes")]
pub fn from_bytes(buffer: &[u8]) -> Result<PublicKey, JsValue> {
Ok(PublicKey::try_from(buffer)?)
}
}
#[wasm_bindgen]
impl PrivateKey {
#[wasm_bindgen(getter)]
pub fn bytes(&self) -> Vec<u8> {
self.clone().into()
}
#[wasm_bindgen(js_name = "fromBytes")]
pub fn from_bytes(buffer: &[u8]) -> Result<PrivateKey, JsValue> {
Ok(PrivateKey::try_from(buffer)?)
}
}
#[wasm_bindgen]
impl SigningPublicKey {
#[wasm_bindgen(getter)]
pub fn bytes(&self) -> Vec<u8> {
self.clone().into()
}
#[wasm_bindgen(js_name = "fromBytes")]
pub fn from_bytes(buffer: &[u8]) -> Result<SigningPublicKey, JsValue> {
Ok(SigningPublicKey::try_from(buffer)?)
}
}
#[wasm_bindgen]
impl SigningKeyPair {
#[wasm_bindgen(getter)]
pub fn bytes(&self) -> Vec<u8> {
self.clone().into()
}
#[wasm_bindgen(getter)]
pub fn public(&self) -> SigningPublicKey {
self.get_public_key()
}
#[wasm_bindgen(js_name = "fromBytes")]
pub fn from_bytes(buffer: &[u8]) -> Result<SigningKeyPair, JsValue> {
Ok(SigningKeyPair::try_from(buffer)?)
}
}
#[wasm_bindgen]
pub fn encrypt(
data: &[u8],
key: &[u8],
aad: Option<Vec<u8>>,
version: Option<CiphertextVersion>,
) -> Result<Vec<u8>, JsValue> {
Ok(ciphertext::encrypt_with_aad(
&data,
&key,
&aad.unwrap_or(Vec::new()),
version.unwrap_or(CiphertextVersion::Latest),
)?
.into())
}
#[wasm_bindgen(js_name = "encryptAsymmetric")]
pub fn encrypt_asymmetric(
data: &[u8],
public_key: PublicKey,
aad: Option<Vec<u8>>,
version: Option<CiphertextVersion>,
) -> Result<Vec<u8>, JsValue> {
Ok(ciphertext::encrypt_asymmetric_with_aad(
&data,
&public_key,
&aad.unwrap_or(Vec::new()),
version.unwrap_or(CiphertextVersion::Latest),
)?
.into())
}
#[wasm_bindgen]
pub fn decrypt(data: &[u8], key: &[u8], aad: Option<Vec<u8>>) -> Result<Vec<u8>, JsValue> {
let data_blob = Ciphertext::try_from(data)?;
Ok(data_blob.decrypt_with_aad(&key, &aad.unwrap_or(Vec::new()))?)
}
#[wasm_bindgen(js_name = "decryptAsymmetric")]
pub fn decrypt_asymmetric(
data: &[u8],
private_key: PrivateKey,
aad: Option<Vec<u8>>,
) -> Result<Vec<u8>, JsValue> {
let data_blob = Ciphertext::try_from(data)?;
Ok(data_blob.decrypt_asymmetric_with_aad(&private_key, &aad.unwrap_or(Vec::new()))?)
}
#[wasm_bindgen(js_name = "hashPassword")]
pub fn hash_password(
password: &[u8],
iterations: Option<u32>,
version: Option<PasswordHashVersion>,
) -> Vec<u8> {
password_hash::hash_password(
&password,
iterations.unwrap_or(10000),
version.unwrap_or(PasswordHashVersion::Latest),
)
.into()
}
#[wasm_bindgen(js_name = "verifyPassword")]
pub fn verify_password(password: &[u8], hash: &[u8]) -> Result<bool, JsValue> {
let password_hash = PasswordHash::try_from(hash)?;
Ok(password_hash.verify_password(&password))
}
#[wasm_bindgen(js_name = "generateKeyPair")]
pub fn generate_keypair(version: Option<KeyVersion>) -> KeyPair {
key::generate_keypair(version.unwrap_or(KeyVersion::Latest)).into()
}
#[wasm_bindgen(js_name = "generateSigningKeyPair")]
pub fn generate_signing_keypair(version: Option<SigningKeyVersion>) -> SigningKeyPair {
signing_key::generate_signing_keypair(version.unwrap_or(SigningKeyVersion::Latest)).into()
}
#[wasm_bindgen(js_name = "mixKeyExchange")]
pub fn mix_key_exchange(
private_key: &PrivateKey,
public_key: &PublicKey,
) -> Result<Vec<u8>, JsValue> {
Ok(key::mix_key_exchange(private_key, public_key)?)
}
#[wasm_bindgen]
pub fn sign(data: &[u8], keypair: &SigningKeyPair, version: Option<SignatureVersion>) -> Vec<u8> {
signature::sign(data, keypair, version.unwrap_or(SignatureVersion::Latest)).into()
}
#[wasm_bindgen(js_name = "verifySignature")]
pub fn verify_signature(
data: &[u8],
public_key: &SigningPublicKey,
signature: &[u8],
) -> Result<bool, JsValue> {
let signature: Signature = signature.try_into()?;
Ok(signature.verify(data, public_key))
}
#[wasm_bindgen(typescript_custom_section)]
const TS_OVERRIDE_GENERATE_SHARED_KEY: &str = r#"/**
* @param {number} n_shares
* @param {number} threshold
* @param {number | undefined} length
* @returns {Uint8Array[]}
*/
export function generateSharedKey(n_shares: number, threshold: number, length?: number): Uint8Array[];"#;
#[wasm_bindgen(js_name = "generateSharedKey", skip_typescript)]
pub fn generate_shared_key(
n_shares: u8,
threshold: u8,
length: Option<usize>,
version: Option<SecretSharingVersion>,
) -> Result<Array, JsValue> {
secret_sharing::generate_shared_key(
n_shares,
threshold,
length.unwrap_or(32),
version.unwrap_or(SecretSharingVersion::Latest),
)?
.into_iter()
.map(
|x| match serde_wasm_bindgen::to_value(&Into::<Vec<u8>>::into(x)) {
Ok(s) => Ok(s),
Err(e) => {
let error = js_sys::Error::new(&format!("{}", e));
error.set_name("SerializationError");
Err(error.into())
}
},
)
.collect()
}
#[wasm_bindgen(typescript_custom_section)]
const TS_OVERRIDE_JOIN_SHARES: &str = r#"/**
* @param {Uint8Array[]} shares
* @returns {Uint8Array}
*/
export function joinShares(shares: Uint8Array[]): Uint8Array;"#;
#[wasm_bindgen(js_name = "joinShares", skip_typescript)]
pub fn join_shares(shares: Array) -> Result<Vec<u8>, JsValue> {
let shares: Vec<Vec<u8>> = match serde_wasm_bindgen::from_value(JsValue::from(shares)) {
Ok(s) => s,
Err(e) => {
let error = js_sys::Error::new(&format!("{}", e));
error.set_name("DeserializationError");
return Err(error.into());
}
};
let shares: Result<Vec<_>, _> = shares
.iter()
.map(|x| Share::try_from(x.as_slice()))
.collect();
Ok(secret_sharing::join_shares(&shares?)?)
}
#[wasm_bindgen(js_name = "generateKey")]
pub fn generate_key(length: Option<usize>) -> Vec<u8> {
utils::generate_key(length.unwrap_or(32))
}
#[wasm_bindgen(js_name = "deriveKeyPbkdf2")]
pub fn derive_key_pbkdf2(
key: &[u8],
salt: Option<Vec<u8>>,
iterations: Option<u32>,
length: Option<usize>,
) -> Vec<u8> {
let salt = salt.unwrap_or_else(|| vec![0u8; 0]);
let iterations = iterations.unwrap_or(10000);
let length = length.unwrap_or(32);
utils::derive_key_pbkdf2(key, &salt, iterations, length)
}
#[wasm_bindgen(js_name = "deriveKeyArgon2")]
pub fn derive_key_argon2(key: &[u8], parameters: &Argon2Parameters) -> Result<Vec<u8>, JsValue> {
Ok(utils::derive_key_argon2(key, parameters)?)
}
#[wasm_bindgen(js_name = "validateHeader")]
pub fn validate_header(data: &[u8], data_type: DataType) -> bool {
utils::validate_header(data, data_type)
}
#[wasm_bindgen(js_name = "scryptSimple")]
pub fn scrypt_simple(password: &[u8], salt: &[u8], log_n: u8, r: u32, p: u32) -> String {
utils::scrypt_simple(password, salt, log_n, r, p)
}
#[wasm_bindgen]
pub fn base64encode(data: &[u8]) -> String {
utils::base64_encode(data)
}
#[wasm_bindgen]
pub fn base64decode(data: &str) -> Result<Vec<u8>, JsValue> {
Ok(utils::base64_decode(data)?)
}
#[wasm_bindgen(js_name = "base64urlEncode")]
pub fn base64url_encode(data: &[u8]) -> String {
utils::base64_encode_url(data)
}
#[wasm_bindgen(js_name = "base64urlDecode")]
pub fn base64url_decode(data: &str) -> Result<Vec<u8>, JsValue> {
Ok(utils::base64_decode_url(data)?)
}