use serde::Deserialize;
use serde::Serialize;
use super::Account;
use crate::dht::Did;
use crate::ecc::keys::AccountVerifier;
use crate::ecc::keys::VerificationPublicKey;
use crate::ecc::signers;
use crate::ecc::PublicKey;
use crate::error::Error;
use crate::error::Result;
use crate::utils;
pub(super) fn pack_session(session_id: Did, ts_ms: u128, ttl_ms: u64) -> String {
format!("{session_id}\n{ts_ms}\n{ttl_ms}")
}
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
pub struct Session {
pub(super) session_id: Did,
pub(super) account: Account,
pub(super) ttl_ms: u64,
pub(super) ts_ms: u128,
pub(super) sig: Vec<u8>,
}
impl Session {
pub fn pack(&self) -> Vec<u8> {
pack_session(self.session_id, self.ts_ms, self.ttl_ms)
.as_bytes()
.to_vec()
}
pub fn session_did(&self) -> Did {
self.session_id
}
pub fn is_expired(&self) -> bool {
let now = utils::get_epoch_ms();
now > self.ts_ms + self.ttl_ms as u128
}
pub fn verify_self(&self) -> Result<()> {
if self.is_expired() {
return Err(Error::SessionExpired);
}
let auth_bytes = self.pack();
if !self
.account
.account_verifier()
.verify(&auth_bytes, &self.sig)
{
return Err(Error::VerifySignatureFailed);
}
Ok(())
}
pub fn verify(&self, msg: &[u8], sig: impl AsRef<[u8]>) -> Result<()> {
self.verify_self()?;
if !signers::secp256k1::verify(msg, &self.session_id, sig) {
return Err(Error::VerifySignatureFailed);
}
Ok(())
}
pub fn account_pubkey(&self) -> Result<PublicKey<33>> {
match self.account_verification_pubkey()? {
VerificationPublicKey::Secp256k1(pk)
| VerificationPublicKey::Eip191(pk)
| VerificationPublicKey::Bip137(pk) => Ok(pk),
VerificationPublicKey::Secp256r1(_)
| VerificationPublicKey::Ed25519(_)
| VerificationPublicKey::Bls12381(_) => Err(Error::UnknownAccount),
}
}
pub fn account_verification_pubkey(&self) -> Result<VerificationPublicKey> {
self.account
.account_verifier()
.verification_key_from_signature(&self.pack(), &self.sig)
}
pub fn account_verifier(&self) -> AccountVerifier {
self.account.account_verifier()
}
pub fn account_did(&self) -> Did {
self.account.account_verifier().did()
}
}