Skip to main content

rings_core/session/
model.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use super::Account;
5use crate::dht::Did;
6use crate::ecc::keys::AccountVerifier;
7use crate::ecc::keys::VerificationPublicKey;
8use crate::ecc::signers;
9use crate::ecc::PublicKey;
10use crate::error::Error;
11use crate::error::Result;
12use crate::utils;
13
14pub(super) fn pack_session(session_id: Did, ts_ms: u128, ttl_ms: u64) -> String {
15    format!("{session_id}\n{ts_ms}\n{ttl_ms}")
16}
17
18/// A serializable session proof used to verify messages signed by a delegated session key.
19#[derive(Deserialize, Serialize, PartialEq, Eq, Debug, Clone)]
20pub struct Session {
21    /// DID of the session public key.
22    pub(super) session_id: Did,
23    /// Account that authorized the session.
24    pub(super) account: Account,
25    /// Session lifetime.
26    pub(super) ttl_ms: u64,
27    /// Timestamp when the session was created.
28    pub(super) ts_ms: u128,
29    /// Account signature authorizing the session.
30    pub(super) sig: Vec<u8>,
31}
32
33impl Session {
34    /// Pack the session into a string for verification or public key recovery.
35    pub fn pack(&self) -> Vec<u8> {
36        pack_session(self.session_id, self.ts_ms, self.ttl_ms)
37            .as_bytes()
38            .to_vec()
39    }
40
41    /// Return the DID of the session public key.
42    pub fn session_did(&self) -> Did {
43        self.session_id
44    }
45
46    /// Check whether the session has expired.
47    pub fn is_expired(&self) -> bool {
48        let now = utils::get_epoch_ms();
49        now > self.ts_ms + self.ttl_ms as u128
50    }
51
52    /// Verify that the account authorized this unexpired session.
53    pub fn verify_self(&self) -> Result<()> {
54        if self.is_expired() {
55            return Err(Error::SessionExpired);
56        }
57
58        let auth_bytes = self.pack();
59        if !self
60            .account
61            .account_verifier()
62            .verify(&auth_bytes, &self.sig)
63        {
64            return Err(Error::VerifySignatureFailed);
65        }
66        Ok(())
67    }
68
69    /// Verify a message signed by this session key.
70    pub fn verify(&self, msg: &[u8], sig: impl AsRef<[u8]>) -> Result<()> {
71        self.verify_self()?;
72        if !signers::secp256k1::verify(msg, &self.session_id, sig) {
73            return Err(Error::VerifySignatureFailed);
74        }
75        Ok(())
76    }
77
78    /// Get the legacy secp256k1-compatible account public key.
79    ///
80    /// Use [`Session::account_verification_pubkey`] for typed account verification keys.
81    pub fn account_pubkey(&self) -> Result<PublicKey<33>> {
82        match self.account_verification_pubkey()? {
83            VerificationPublicKey::Secp256k1(pk)
84            | VerificationPublicKey::Eip191(pk)
85            | VerificationPublicKey::Bip137(pk) => Ok(pk),
86            VerificationPublicKey::Secp256r1(_)
87            | VerificationPublicKey::Ed25519(_)
88            | VerificationPublicKey::Bls12381(_) => Err(Error::UnknownAccount),
89        }
90    }
91
92    /// Get the typed account verification public key from the session proof.
93    pub fn account_verification_pubkey(&self) -> Result<VerificationPublicKey> {
94        self.account
95            .account_verifier()
96            .verification_key_from_signature(&self.pack(), &self.sig)
97    }
98
99    /// Get the typed account verifier.
100    pub fn account_verifier(&self) -> AccountVerifier {
101        self.account.account_verifier()
102    }
103
104    /// Get the authorizing account DID.
105    pub fn account_did(&self) -> Did {
106        self.account.account_verifier().did()
107    }
108}