#![warn(missing_docs)]
use serde::Deserialize;
use serde::Serialize;
use crate::consts::DEFAULT_TTL_MS;
use crate::consts::MAX_TTL_MS;
use crate::consts::TS_OFFSET_TOLERANCE_MS;
use crate::dht::Did;
use crate::error::Result;
use crate::session::Session;
use crate::session::SessionSk;
use crate::utils::get_epoch_ms;
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct MessageVerification {
pub session: Session,
pub ttl_ms: u64,
pub ts_ms: u128,
pub sig: Vec<u8>,
}
fn pack_msg(data: &[u8], ts_ms: u128, ttl_ms: u64) -> Vec<u8> {
let mut msg = vec![];
msg.extend_from_slice(&ts_ms.to_be_bytes());
msg.extend_from_slice(&ttl_ms.to_be_bytes());
msg.extend_from_slice(data);
msg
}
impl MessageVerification {
pub fn new(data: &[u8], session_sk: &SessionSk) -> Result<Self> {
let ts_ms = get_epoch_ms();
let ttl_ms = DEFAULT_TTL_MS;
let msg = pack_msg(data, ts_ms, ttl_ms);
let verification = MessageVerification {
session: session_sk.session(),
sig: session_sk.sign(&msg)?,
ttl_ms,
ts_ms,
};
Ok(verification)
}
pub fn verify(&self, data: &[u8]) -> bool {
let msg = pack_msg(data, self.ts_ms, self.ttl_ms);
self.session
.verify(&msg, &self.sig)
.map_err(|e| {
tracing::warn!("MessageVerification verify failed: {:?}", e);
})
.is_ok()
}
}
pub trait MessageVerificationExt {
fn verification_data(&self) -> Result<Vec<u8>>;
fn verification(&self) -> &MessageVerification;
fn is_expired(&self) -> bool {
if self.verification().ttl_ms > MAX_TTL_MS {
return false;
}
let now = get_epoch_ms();
if self.verification().ts_ms - TS_OFFSET_TOLERANCE_MS > now {
return false;
}
now > self.verification().ts_ms + self.verification().ttl_ms as u128
}
fn verify(&self) -> bool {
if self.is_expired() {
tracing::warn!("message expired");
return false;
}
let Ok(data) = self.verification_data() else {
tracing::warn!("MessageVerificationExt verify get verification_data failed");
return false;
};
self.verification().verify(&data)
}
fn signer(&self) -> Did {
self.verification().session.account_did()
}
}