#![warn(missing_docs)]
use std::sync::Arc;
use std::sync::RwLock;
use serde::Deserialize;
use serde::Serialize;
use crate::consts::DEFAULT_SESSION_TTL_MS;
use crate::dht::Did;
use crate::ecc::signers;
use crate::ecc::PublicKey;
use crate::ecc::SecretKey;
use crate::err::Error;
use crate::err::Result;
use crate::utils;
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
pub enum Signer {
DEFAULT,
EIP191,
EdDSA,
}
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
pub enum Ttl {
Some(usize),
Never,
}
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
pub struct Authorizer {
pub did: Did,
pub pubkey: Option<PublicKey>,
}
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
pub struct AuthorizedInfo {
authorizer: Authorizer,
signer: Signer,
ttl_ms: Ttl,
ts_ms: u128,
session_id: Did,
}
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
pub struct Session {
pub sig: Vec<u8>,
pub auth: AuthorizedInfo,
}
#[derive(Debug, Clone)]
struct SessionWithKey {
session: Session,
session_key: SecretKey,
}
#[derive(Debug)]
pub struct SessionManager {
inner: Arc<RwLock<SessionWithKey>>,
}
impl Clone for SessionManager {
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
}
}
}
impl AuthorizedInfo {
pub fn to_string(&self) -> Result<String> {
serde_json::to_string(self).map_err(|_| Error::SerializeToString)
}
}
impl Session {
pub fn new(sig: &[u8], auth_info: &AuthorizedInfo) -> Self {
Self {
sig: sig.to_vec(),
auth: auth_info.clone(),
}
}
pub fn is_expired(&self) -> bool {
if let Ttl::Some(ttl_ms) = self.auth.ttl_ms {
let now = utils::get_epoch_ms();
now > self.auth.ts_ms + ttl_ms as u128
} else {
false
}
}
pub fn verify(&self) -> bool {
if self.is_expired() {
return false;
}
if let Ok(auth_str) = self.auth.to_string() {
match self.auth.signer {
Signer::DEFAULT => {
signers::default::verify(&auth_str, &self.auth.authorizer.did.into(), &self.sig)
}
Signer::EIP191 => {
signers::eip191::verify(&auth_str, &self.auth.authorizer.did.into(), &self.sig)
}
Signer::EdDSA => match self.authorizer_pubkey() {
Ok(p) => signers::ed25519::verify(
&auth_str,
&self.auth.authorizer.did.into(),
&self.sig,
p,
),
Err(_) => false,
},
}
} else {
false
}
}
pub fn did(&self) -> Result<Did> {
if !self.verify() {
Err(Error::VerifySignatureFailed)
} else {
Ok(self.auth.session_id)
}
}
pub fn authorizer_pubkey(&self) -> Result<PublicKey> {
let auth = self.auth.to_string()?;
match self.auth.signer {
Signer::DEFAULT => signers::default::recover(&auth, &self.sig),
Signer::EIP191 => signers::eip191::recover(&auth, &self.sig),
Signer::EdDSA => self
.auth
.authorizer
.pubkey
.ok_or(Error::EdDSAPublicKeyNotFound),
}
}
}
impl SessionManager {
pub fn gen_unsign_info_with_ed25519_pubkey(
ttl: Option<Ttl>,
pubkey: PublicKey,
) -> Result<(AuthorizedInfo, SecretKey)> {
Self::gen_unsign_info_with_pubkey(ttl, Some(Signer::EdDSA), pubkey)
}
pub fn gen_unsign_info_with_pubkey(
ttl: Option<Ttl>,
signer: Option<Signer>,
pubkey: PublicKey,
) -> Result<(AuthorizedInfo, SecretKey)> {
let key = SecretKey::random();
let signer = signer.unwrap_or(Signer::DEFAULT);
let authorizer = Authorizer {
did: pubkey.address().into(),
pubkey: Some(pubkey),
};
let info = AuthorizedInfo {
signer,
authorizer,
session_id: key.address().into(),
ttl_ms: ttl.unwrap_or(Ttl::Some(DEFAULT_SESSION_TTL_MS)),
ts_ms: utils::get_epoch_ms(),
};
Ok((info, key))
}
pub fn gen_unsign_info(
did: Did,
ttl: Option<Ttl>,
signer: Option<Signer>,
) -> (AuthorizedInfo, SecretKey) {
let key = SecretKey::random();
let signer = signer.unwrap_or(Signer::DEFAULT);
let authorizer = Authorizer { did, pubkey: None };
let info = AuthorizedInfo {
signer,
authorizer,
session_id: key.address().into(),
ttl_ms: ttl.unwrap_or(Ttl::Some(DEFAULT_SESSION_TTL_MS)),
ts_ms: utils::get_epoch_ms(),
};
(info, key)
}
pub fn new(sig: &[u8], auth_info: &AuthorizedInfo, session_key: &SecretKey) -> Self {
let inner = SessionWithKey {
session: Session::new(sig, auth_info),
session_key: *session_key,
};
Self {
inner: Arc::new(RwLock::new(inner)),
}
}
pub fn new_with_seckey(key: &SecretKey, ttl: Option<Ttl>) -> Result<Self> {
let (auth, s_key) = Self::gen_unsign_info(key.address().into(), ttl, None);
let sig = key.sign(&auth.to_string()?).to_vec();
Ok(Self::new(&sig, &auth, &s_key))
}
pub fn renew(&self, sig: &[u8], auth_info: &AuthorizedInfo, key: &SecretKey) -> Result<&Self> {
let new_inner = SessionWithKey {
session: Session::new(sig, auth_info),
session_key: *key,
};
let mut inner = self
.inner
.try_write()
.map_err(|_| Error::SessionTryLockFailed)?;
*inner = new_inner;
Ok(self)
}
pub fn session_key(&self) -> Result<SecretKey> {
let inner = self
.inner
.try_read()
.map_err(|_| Error::SessionTryLockFailed)?;
Ok(inner.session_key)
}
pub fn session(&self) -> Result<Session> {
let inner = self
.inner
.try_read()
.map_err(|_| Error::SessionTryLockFailed)?;
Ok(inner.session.clone())
}
pub fn sign(&self, msg: &str) -> Result<Vec<u8>> {
let key = self.session_key()?;
Ok(signers::default::sign_raw(key, msg).to_vec())
}
pub fn authorizer(&self) -> Result<Did> {
Ok(self.session()?.auth.authorizer.did)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_session_verify() {
let key = SecretKey::random();
let sm = SessionManager::new_with_seckey(&key, None).unwrap();
let session = sm.session().unwrap();
assert!(session.verify());
}
#[test]
pub fn test_authorizer_pubkey() {
let key = SecretKey::random();
let sm = SessionManager::new_with_seckey(&key, None).unwrap();
let session = sm.session().unwrap();
let pubkey = session.authorizer_pubkey().unwrap();
assert_eq!(key.pubkey(), pubkey);
}
}