pubky_common/
session.rs

1//! Pubky homeserver session struct.
2
3use postcard::{from_bytes, to_allocvec};
4use serde::{Deserialize, Serialize};
5
6extern crate alloc;
7use alloc::vec::Vec;
8
9use crate::{
10    capabilities::{Capabilities, Capability},
11    crypto::PublicKey,
12    timestamp::Timestamp,
13};
14
15#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
16/// Pubky homeserver session struct.
17pub struct SessionInfo {
18    version: usize,
19    public_key: PublicKey,
20    created_at: u64,
21    /// Deprecated. Will always be empty.
22    name: String,
23    /// Deprecated. Will always be empty.
24    user_agent: String,
25    capabilities: Vec<Capability>,
26}
27
28impl SessionInfo {
29    /// Create a new session.
30    pub fn new(
31        public_key: &PublicKey,
32        capabilities: Capabilities,
33        user_agent: Option<String>,
34    ) -> Self {
35        Self {
36            version: 0,
37            public_key: public_key.clone(),
38            created_at: Timestamp::now().as_u64(),
39            capabilities: capabilities.to_vec(),
40            user_agent: user_agent.as_deref().unwrap_or("").to_string(),
41            name: user_agent.as_deref().unwrap_or("").to_string(),
42        }
43    }
44
45    // === Getters ===
46
47    /// Returns the public_key of this session authorizes for.
48    pub fn public_key(&self) -> &PublicKey {
49        &self.public_key
50    }
51
52    /// Returns the capabilities this session provide on this session's public_key's resources.
53    pub fn capabilities(&self) -> &[Capability] {
54        &self.capabilities
55    }
56
57    /// Returns the timestamp when this session was created.
58    pub fn created_at(&self) -> u64 {
59        self.created_at
60    }
61
62    // === Setters ===
63
64    /// Set the timestamp when this session was created.
65    pub fn set_created_at(&mut self, created_at: u64) -> &mut Self {
66        self.created_at = created_at;
67        self
68    }
69
70    /// Set this session's capabilities.
71    pub fn set_capabilities(&mut self, capabilities: Capabilities) -> &mut Self {
72        self.capabilities = capabilities.to_vec();
73
74        self
75    }
76
77    // === Public Methods ===
78
79    /// Serialize this session to its canonical binary representation.
80    pub fn serialize(&self) -> Vec<u8> {
81        to_allocvec(self).expect("SessionInfo::serialize")
82    }
83
84    /// Deserialize this session from its canonical binary representation.
85    pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
86        if bytes.is_empty() {
87            return Err(Error::EmptyPayload);
88        }
89
90        if bytes[0] > 0 {
91            return Err(Error::UnknownVersion);
92        }
93
94        Ok(from_bytes(bytes)?)
95    }
96
97    // TODO: add `can_read()`, `can_write()` and `is_root()` methods
98}
99
100#[derive(thiserror::Error, Debug, PartialEq)]
101/// Error deserializing a [SessionInfo].
102pub enum Error {
103    #[error("Empty payload")]
104    /// Empty payload
105    EmptyPayload,
106    #[error("Unknown version")]
107    /// Unknown version
108    UnknownVersion,
109    #[error(transparent)]
110    /// Error parsing the binary representation.
111    Parsing(#[from] postcard::Error),
112}
113
114#[cfg(test)]
115mod tests {
116    use crate::{capabilities::Capability, crypto::Keypair};
117
118    use super::*;
119
120    #[test]
121    fn serialize() {
122        let keypair = Keypair::from_secret(&[0; 32]);
123        let public_key = keypair.public_key();
124        let capabilities = Capabilities::builder().cap(Capability::root()).finish();
125
126        let session = SessionInfo {
127            user_agent: "foo".to_string(),
128            capabilities: capabilities.to_vec(),
129            created_at: 0,
130            public_key,
131            version: 0,
132            name: "".to_string(),
133        };
134
135        let serialized = session.serialize();
136
137        assert_eq!(
138            serialized,
139            [
140                0, 59, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13, 115, 101,
141                50, 21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41, 0, 0, 3, 102,
142                111, 111, 1, 4, 47, 58, 114, 119
143            ]
144        );
145
146        let deserialized = SessionInfo::deserialize(&serialized).unwrap();
147
148        assert_eq!(deserialized, session)
149    }
150
151    #[test]
152    fn deserialize() {
153        let result = SessionInfo::deserialize(&[]);
154
155        assert_eq!(result, Err(Error::EmptyPayload));
156    }
157}