#![allow(unused_imports)]
use crate::{Email, IdenticationRequirement, TokenBundle};
use crate::{LightMPAATHeader, LightMPAATPayload, LightMPAATSignature, MPAATHeader, MPAATPayload, MPAATSignature};
use crate::{MResult, ServerError};
#[cfg(any(feature = "pqc-utils", feature = "ed25519-utils"))]
use crate::SignKeypair;
#[cfg(feature = "crypt-utils")]
use crate::CipherKey;
pub fn base64_encode(data: &[u8]) -> String {
use base64::{Engine as _, engine::general_purpose::URL_SAFE};
URL_SAFE.encode(data)
}
pub fn base64_decode(data: &str) -> MResult<Vec<u8>> {
use base64::{Engine as _, engine::general_purpose::URL_SAFE};
URL_SAFE.decode(data).map_err(ServerError::from_private)
}
pub fn generate<const SZ: usize>() -> [u8; SZ] {
use rand::Rng;
let mut arr: [u8; SZ] = [0; SZ];
let mut rng = rand::rng();
rng.fill(arr.as_mut_slice());
arr
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn deploy_mpaat<U: serde::Serialize, T: serde::Serialize>(
payload: T,
common_fields: Option<U>,
exp: chrono::DateTime<chrono::Utc>,
client_public: &[u8],
server_enc: Option<&CipherKey>,
server_keys: &SignKeypair,
) -> MResult<String> {
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
tracing::debug!("MPAAT (deploy): Got client public: {:?}", client_public);
tracing::debug!("MPAAT (deploy): Expires at: {:?}", exp);
let payload = MPAATPayload {
cli_pkey: client_public.to_vec(),
exp,
container: payload,
};
let (enc_payload, nonce) = if let Some(server_enc) = server_enc {
tracing::debug!("MPAAT (deploy): Encrypting with a `ekey`...");
server_enc.encrypt(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't encrypt payload with `server_enc` key!")
.with_500()
})?
} else {
tracing::debug!("MPAAT (deploy): Skip encryption...");
(
rmp_serde::to_vec(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize MPAAT payload!")
.with_500()
})?,
vec![],
)
};
let header = MPAATHeader {
authnz_pkey: server_keys.public(),
nonce,
common_public_fields: common_fields,
};
let sig = header.sign_mpaat(&enc_payload, server_keys).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't sign MPAAT with server keyring!")
.with_500()
})?;
tracing::debug!("MPAAT (deploy): Signature: {:?}", sig);
let sig = MPAATSignature { sig };
let sig = STANDARD.encode(rmp_serde::to_vec(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize MPAAT signature!")
.with_500()
})?);
let header = STANDARD.encode(rmp_serde::to_vec(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize MPAAT header!")
.with_500()
})?);
let enc_payload = URL_SAFE.encode(&enc_payload);
Ok(format!("{enc_payload}.{sig}.{header}"))
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn deploy_lmpaat<U: serde::Serialize, T: serde::Serialize>(
payload: T,
common_fields: Option<U>,
exp: chrono::DateTime<chrono::Utc>,
client_public: &[u8],
server_keys: &SignKeypair,
) -> MResult<String> {
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
tracing::debug!("LMPAAT (deploy): Got client public: {:?}", client_public);
tracing::debug!("LMPAAT (deploy): Expires at: {:?}", exp);
let payload = LightMPAATPayload { exp, container: payload };
let enc_payload = rmp_serde::to_vec(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize LMPAAT payload!")
.with_500()
})?;
let enc_payload = URL_SAFE.encode(&enc_payload);
let header = LightMPAATHeader {
cli_pkey: client_public.to_vec(),
common_public_fields: common_fields,
};
let sig = header.sign_lmpaat(&payload, server_keys).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't sign LMPAAT header!")
.with_500()
})?;
tracing::debug!("LMPAAT (deploy): Signature: {:?}", sig);
let sig = MPAATSignature { sig };
let sig = STANDARD.encode(rmp_serde::to_vec(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize LMPAAT signature!")
.with_500()
})?);
let header = STANDARD.encode(rmp_serde::to_vec(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize LMPAAT header!")
.with_500()
})?);
Ok(format!("{enc_payload}.{sig}.{header}"))
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn mpaat_extract_common_fields<U: serde::de::DeserializeOwned>(token: &str, server_keys: &SignKeypair) -> MResult<Option<U>> {
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
let parts = token.split('.').collect::<Vec<_>>();
let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let sig = STANDARD.decode(sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT signature!")
.with_500()
})?;
let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT signature!")
.with_500()
})?;
tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
let payload = URL_SAFE.decode(payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT payload!")
.with_500()
})?;
let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let header = STANDARD.decode(header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT header!")
.with_500()
})?;
let authnz_pkey = server_keys.public();
SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Token is unverified!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401()
})?;
let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT header!")
.with_500()
})?;
if header.authnz_pkey != authnz_pkey.as_slice() {
return Err(
ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401(),
);
}
Ok(header.common_public_fields)
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn mpaat_extract_payload<T, U>(
token: &str,
server_enc: Option<&CipherKey>,
server_keys: &SignKeypair,
current_dt: chrono::DateTime<chrono::Utc>,
) -> MResult<T>
where
T: serde::de::DeserializeOwned,
U: serde::de::DeserializeOwned,
{
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
let parts = token.split('.').collect::<Vec<_>>();
let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let sig = STANDARD.decode(sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT signature!")
.with_500()
})?;
let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT signature!")
.with_500()
})?;
tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
let payload = URL_SAFE.decode(payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT payload!")
.with_500()
})?;
let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let header = STANDARD.decode(header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT header!")
.with_500()
})?;
let authnz_pkey = server_keys.public();
SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Token is unverified!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401()
})?;
let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT header!")
.with_500()
})?;
if header.authnz_pkey != authnz_pkey.as_slice() {
return Err(
ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401(),
);
}
let payload = if let Some(server_enc) = server_enc {
tracing::debug!("MPAAT: Decrypting with given `ekey`...");
server_enc.decrypt::<MPAATPayload<T>>(&payload, &header.nonce).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decrypt payload with given `server_enc` key!")
.with_public("Invalid token, consider to sign in again.")
.with_401()
})?
} else {
tracing::debug!("MPAAT: Skip decryption...");
rmp_serde::from_slice::<MPAATPayload<T>>(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize payload!")
.with_public("Invalid token, consider to sign in again.")
.with_401()
})?
};
tracing::debug!("MPAAT: Expires at: {:?}", payload.exp);
if current_dt >= payload.exp {
return Err(
ServerError::from_private_str("Token is expired!")
.with_public("Invalid token, consider to sign in again.")
.with_401(),
);
}
Ok(payload.container)
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn mpaat_extract_payload_with_metadata<T, U>(
token: &str,
server_enc: Option<&CipherKey>,
server_keys: &SignKeypair,
current_dt: chrono::DateTime<chrono::Utc>,
) -> MResult<MPAATPayload<T>>
where
T: serde::de::DeserializeOwned,
U: serde::de::DeserializeOwned,
{
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
let parts = token.split('.').collect::<Vec<_>>();
let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let sig = STANDARD.decode(sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT signature!")
.with_500()
})?;
let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT signature!")
.with_500()
})?;
tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
let payload = URL_SAFE.decode(payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT payload!")
.with_500()
})?;
let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let header = STANDARD.decode(header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT header!")
.with_500()
})?;
let authnz_pkey = server_keys.public();
SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Token is unverified!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401()
})?;
let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT header!")
.with_500()
})?;
if header.authnz_pkey != authnz_pkey.as_slice() {
return Err(
ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401(),
);
}
let payload = if let Some(server_enc) = server_enc {
tracing::debug!("MPAAT: Decrypting with given `ekey`...");
server_enc.decrypt::<MPAATPayload<T>>(&payload, &header.nonce).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decrypt payload with given `server_enc` key!")
.with_public("Invalid token, consider to sign in again.")
.with_401()
})?
} else {
tracing::debug!("MPAAT: Skip decryption...");
rmp_serde::from_slice::<MPAATPayload<T>>(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize payload!")
.with_public("Invalid token, consider to sign in again.")
.with_401()
})?
};
tracing::debug!("MPAAT: Expires at: {:?}", payload.exp);
if current_dt >= payload.exp {
return Err(
ServerError::from_private_str("Token is expired!")
.with_public("Invalid token, consider to sign in again.")
.with_401(),
);
}
Ok(payload)
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn mpaat_extract_payload_with_metadata_exp_ignored<T, U>(
token: &str,
server_enc: Option<&CipherKey>,
server_keys: &SignKeypair,
) -> MResult<MPAATPayload<T>>
where
T: serde::de::DeserializeOwned,
U: serde::de::DeserializeOwned,
{
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
let parts = token.split('.').collect::<Vec<_>>();
let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let sig = STANDARD.decode(sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT signature!")
.with_500()
})?;
let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT signature!")
.with_500()
})?;
tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
let payload = URL_SAFE.decode(payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT payload!")
.with_500()
})?;
let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let header = STANDARD.decode(header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode MPAAT header!")
.with_500()
})?;
let authnz_pkey = server_keys.public();
SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Token is unverified!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401()
})?;
let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize MPAAT header!")
.with_500()
})?;
if header.authnz_pkey != authnz_pkey.as_slice() {
return Err(
ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401(),
);
}
let payload = if let Some(server_enc) = server_enc {
tracing::debug!("MPAAT: Decrypting with given `ekey`...");
server_enc.decrypt::<MPAATPayload<T>>(&payload, &header.nonce).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decrypt payload with given `server_enc` key!")
.with_public("Invalid token, consider to sign in again.")
.with_401()
})?
} else {
tracing::debug!("MPAAT: Skip decryption...");
rmp_serde::from_slice::<MPAATPayload<T>>(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize payload!")
.with_public("Invalid token, consider to sign in again.")
.with_401()
})?
};
Ok(payload)
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn lmpaat_extract_common_fields<U: serde::de::DeserializeOwned>(token: &str, server_keys: &SignKeypair) -> MResult<Option<U>> {
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
let parts = token.split('.').collect::<Vec<_>>();
let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let sig = STANDARD.decode(sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode LMPAAT signature!")
.with_500()
})?;
let sig = rmp_serde::from_slice::<LightMPAATSignature>(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize LMPAAT signature!")
.with_500()
})?;
tracing::debug!("LMPAAT: Got signature: {:?}", sig.sig);
let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
let payload = URL_SAFE.decode(payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode LMPAAT payload!")
.with_500()
})?;
let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let header = STANDARD.decode(header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode LMPAAT header!")
.with_500()
})?;
SignKeypair::verify_token(&header, &payload, &sig.sig, &server_keys.public()).map_err(|e| {
ServerError::from_private(e)
.with_private_str("LMPAAT token is unverified!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401()
})?;
let header = rmp_serde::from_slice::<LightMPAATHeader<U>>(&header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize LMPAAT header!")
.with_500()
})?;
Ok(header.common_public_fields)
}
#[cfg(all(
feature = "crypt-utils",
feature = "authnz-utils",
any(feature = "pqc-utils", feature = "ed25519-utils")
))]
pub fn lmpaat_extract_payload<T, U>(token: &str, server_keys: &SignKeypair, current_dt: chrono::DateTime<chrono::Utc>) -> MResult<T>
where
T: serde::de::DeserializeOwned,
U: serde::de::DeserializeOwned,
{
use base64::{
Engine as _,
engine::general_purpose::{STANDARD, URL_SAFE},
};
use impulse_server_kit::tracing;
let parts = token.split('.').collect::<Vec<_>>();
let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let sig = STANDARD.decode(sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode LMPAAT signature!")
.with_500()
})?;
let sig = rmp_serde::from_slice::<LightMPAATSignature>(&sig).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize LMPAAT signature!")
.with_500()
})?;
tracing::debug!("LMPAAT: Got signature: {:?}", sig.sig);
let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
let payload = URL_SAFE.decode(payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode LMPAAT payload!")
.with_500()
})?;
let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
let header = STANDARD.decode(header).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode LMPAAT header!")
.with_500()
})?;
SignKeypair::verify_token(&header, &payload, &sig.sig, &server_keys.public()).map_err(|e| {
ServerError::from_private(e)
.with_private_str("LMPAAT token is unverified!")
.with_public("Invalid token signature, consider to sign in again.")
.with_401()
})?;
let payload = rmp_serde::from_slice::<LightMPAATPayload<T>>(&payload).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't deserialize LMPAAT header!")
.with_500()
})?;
tracing::debug!("LMPAAT: Expires at: {:?}", payload.exp);
if current_dt >= payload.exp {
return Err(
ServerError::from_private_str("LMPAAT token is expired!")
.with_public("Invalid token, consider to sign in again.")
.with_401(),
);
}
Ok(payload.container)
}
pub fn split_token(token: &str, max_len: usize) -> Vec<String> {
let mut result = Vec::new();
let bytes = token.as_bytes();
let mut start = 0;
while start < bytes.len() {
let end = std::cmp::min(start + max_len, bytes.len());
result.push(token[start..end].to_string());
start = end;
}
result
}
pub fn unite_token(parts: Vec<String>) -> String {
parts.join("")
}
pub fn take_exp_from_duration(duration: chrono::TimeDelta) -> chrono::DateTime<chrono::Utc> {
chrono::Utc::now() + duration
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use crate::{
AppAuthConfiguration, CipherKey, MPAATHeader, MPAATPayload, SignKeypair, TokenBundle, deploy_mpaat, mpaat_extract_common_fields,
mpaat_extract_payload,
};
use chrono::Utc;
use serde::{Deserialize, Serialize};
#[test]
fn verify_restore() {
let keypair = SignKeypair::new_ed25519().unwrap();
let cert = keypair.pack_keypair();
assert!(SignKeypair::unpack_keypair(cert).is_ok());
}
#[test]
fn verify_sign() {
let keypair = SignKeypair::new_ed25519().unwrap();
let sig = keypair.sign_raw(b"123456");
assert!(SignKeypair::verify_raw(b"123456", &sig, &keypair.public()).is_ok());
}
#[test]
fn verify_sign_eq() {
let keypair = SignKeypair::new_ed25519().unwrap();
let val = AppAuthConfiguration {
app_name: "default".into(),
allowed_tags: vec![("user", "default").into(), ("user", "main").into()],
sign_up_opts: crate::SignUpOpts {
identify_by: crate::IdenticationRequirement::Nickname {
spaces: false,
upper_registry: true,
characters: false,
},
allow_sign_up: true,
auto_assign_tags: vec![("user", "default").into(), ("user", "main").into()],
allowed_authn: vec![],
required_authn: vec![],
},
sign_in_opts: crate::SignInOpts {
enable_fail_to_ban: None,
token_encryption_type: crate::TokenEncryptionType::ChaCha20Poly1305,
},
client_based_auth_opts: crate::ClientBasedAuthorizationOpts { enable_cba: true },
tokens_lifetime: crate::TokenLifetimes::default(),
app_pkey: None,
};
for _ in 0..1000 {
let sign1 = keypair.sign(&val).unwrap();
let sign2 = keypair.sign(&val).unwrap();
assert_eq!(sign1.as_slice(), sign2.as_slice());
}
}
#[test]
fn verify_token_signs2() {
let keypair = SignKeypair::new_ed25519().unwrap();
let dt = Utc::now().checked_add_months(chrono::Months::new(1)).unwrap();
println!("Public key: {:?}", keypair.public());
println!("Secret key: {:?}", unsafe { keypair.private() });
println!();
#[derive(Deserialize, Serialize)]
struct Payload {
data: Vec<usize>,
}
let act = deploy_mpaat(
Payload { data: vec![123] },
Some(Payload { data: vec![456] }),
dt.clone(),
&[0, 1, 2],
None,
&keypair,
)
.unwrap();
println!("{}", act);
let cf = mpaat_extract_common_fields::<Payload>(&act, &keypair);
cf.unwrap();
let pld = mpaat_extract_payload::<Payload, Payload>(&act, None, &keypair, Utc::now());
pld.unwrap();
}
#[test]
fn triple_pack_unpack() {
let triple = TokenBundle::new_with_cba("123", "456", "789");
assert_eq!(TokenBundle::unpack(&triple.pack()), Some(triple));
let triple = TokenBundle::new_basic("123", "456");
assert_eq!(TokenBundle::unpack(&triple.pack()), Some(triple));
}
}