use base64::Engine;
use base64::engine::general_purpose;
use cardano_multiplatform_lib::crypto::PrivateKey;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::str;
use std::string::ToString;
use wasm_bindgen::prelude::wasm_bindgen;
pub mod apis;
pub mod signatures;
use serde_json;
use apis::*;
use signatures::*;
use serde_json::to_string;
#[wasm_bindgen]
#[derive(Serialize, Deserialize)]
pub struct Api {
signature_voting: SignatureVotingApi,
agora: AgoraApi,
}
#[wasm_bindgen]
impl Api {
pub fn signature_voting(&self) -> SignatureVotingApi {
self.signature_voting.clone()
}
pub fn agora(&self) -> AgoraApi {
self.agora.clone()
}
pub fn new() -> Self {
Self {
signature_voting: SignatureVotingApi::new(),
agora: AgoraApi::new(),
}
}
}
#[derive(Serialize, Deserialize)]
struct VerifyRequestBody {
cose_signature_hex: String,
cose_key_hex: String,
expected_message: String,
expected_address_bech32: String,
}
#[wasm_bindgen]
#[derive(Serialize, Deserialize)]
pub struct SignedRequestResponse {
signed_request: Option<String>,
error: Option<String>,
}
#[wasm_bindgen]
impl SignedRequestResponse {
#[wasm_bindgen(constructor)]
pub fn new(signed_request: Option<String>, error_in: Option<String>) -> Self {
if signed_request.is_none() && error_in.is_none() {
panic!("SignedRequestResponse must have either signed_request or error");
}
else if signed_request.is_some() {
return Self {
signed_request: Some(signed_request.unwrap()),
error: None,
};
}
else {
return Self {
signed_request: None,
error: Some(error_in.unwrap()),
};
}
}
pub fn error(&self) -> Option<String> {
self.error.clone()
}
pub fn signed_request(&self) -> Option<String> {
self.signed_request.clone()
}
}
#[wasm_bindgen]
pub fn sign_request_with_extended_bytes(
key_bytes: &[u8],
stake_address_bech32: &str,
pay_address_bech32: &str,
endpoint: &str,
) -> SignedRequestResponse {
let message = format!(
"{}{}",
Utc::now().timestamp_millis().to_string(),
endpoint
);
let sig_result = sign_data_with_extended_bytes(key_bytes, stake_address_bech32, &message);
if sig_result.dt().is_some() {
let dt = sig_result.dt().unwrap();
let body = VerifyRequestBody {
cose_signature_hex: hex::encode(dt.signature()),
cose_key_hex: hex::encode(dt.key()),
expected_message: message,
expected_address_bech32: pay_address_bech32.to_string(),
};
let body_json = serde_json::to_string(&body).unwrap();
let signed_request: String = general_purpose::STANDARD_NO_PAD.encode(&body_json);
let sr = SignedRequestResponse {
signed_request: Some(signed_request),
error: None,
};
return sr;
}
else {
let err_res = SignedRequestResponse {
signed_request: None,
error: Some(sig_result.error()),
};
return err_res;
}
}
#[wasm_bindgen]
pub fn sign_data_with_extended_bytes(
key_bytes: &[u8],
address_bech32: &str,
message: &str,
) -> DataSignatureRes {
let key = PrivateKey::from_extended_bytes(key_bytes);
match key {
Ok(k) => {
let sig_result = sign_data_like_cip30(k, address_bech32, message);
match sig_result {
Ok(val) => DataSignatureRes::new(Some(val), None),
Err(er) => DataSignatureRes::new(None, Some(
er.as_string().unwrap_or("Signing data failed".to_string())
))
}
},
_ => DataSignatureRes::new(None, Some(
"Invalide key bytes. It needs to be PrivateKey EXTENDED bytes, compatible with Cardano Serialization/Multiplatform libraries".to_string()
))
}
}
#[wasm_bindgen]
pub fn sign_data_with_normal_bytes(
key_bytes: &[u8],
address_bech32: &str,
message: &str,
) -> DataSignatureRes {
let key = PrivateKey::from_normal_bytes(key_bytes);
match key {
Ok(k) => {
let sig_result = sign_data_like_cip30(k, address_bech32, message);
match sig_result {
Ok(val) => DataSignatureRes::new(Some(val), None),
Err(er) => DataSignatureRes::new(None, Some(
er.as_string().unwrap_or("Signing data failed".to_string())
))
}
},
_ => DataSignatureRes::new(None, Some(
"Invalide key bytes. It needs to be PrivateKey NORMAL bytes, compatible with Cardano Serialization/Multiplatform libraries".to_string()
))
}
}
#[wasm_bindgen]
pub fn sign_data_with_bech32(
key_string: &str,
address_bech32: &str,
message: &str,
) -> DataSignatureRes {
let key = PrivateKey::from_bech32(key_string);
match key {
Ok(k) => {
let sig_result = sign_data_like_cip30(k, address_bech32, message);
match sig_result {
Ok(val) => DataSignatureRes::new(Some(val), None),
Err(er) => DataSignatureRes::new(None, Some(
er.as_string().unwrap_or("Signing data failed".to_string())
))
}
},
_ => DataSignatureRes::new(None, Some(
"Invalide key string. It needs to be PrivateKey bech 32 string, compatible with Cardano Serialization/Multiplatform libraries".to_string()
))
}
}