1use 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)]
23pub struct CookieSessionRecord {
24 version: usize,
25 public_key: PublicKey,
26 created_at: u64,
27 name: String,
29 user_agent: String,
31 capabilities: Vec<Capability>,
32}
33
34impl CookieSessionRecord {
35 pub fn new(
37 public_key: &PublicKey,
38 capabilities: Capabilities,
39 user_agent: Option<String>,
40 ) -> Self {
41 Self {
42 version: 0,
43 public_key: public_key.clone(),
44 created_at: Timestamp::now().as_u64(),
45 capabilities: capabilities.into(),
46 user_agent: user_agent.as_deref().unwrap_or("").to_string(),
47 name: user_agent.as_deref().unwrap_or("").to_string(),
48 }
49 }
50
51 pub fn public_key(&self) -> &PublicKey {
55 &self.public_key
56 }
57
58 pub fn capabilities(&self) -> &[Capability] {
60 &self.capabilities
61 }
62
63 pub fn created_at(&self) -> u64 {
65 self.created_at
66 }
67
68 pub fn set_created_at(&mut self, created_at: u64) -> &mut Self {
72 self.created_at = created_at;
73 self
74 }
75
76 pub fn set_capabilities(&mut self, capabilities: Capabilities) -> &mut Self {
78 self.capabilities = capabilities.into();
79
80 self
81 }
82
83 pub fn serialize(&self) -> Vec<u8> {
87 to_allocvec(self).expect("CookieSessionRecord::serialize")
88 }
89
90 pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
92 if bytes.is_empty() {
93 return Err(Error::EmptyPayload);
94 }
95
96 if bytes[0] > 0 {
97 return Err(Error::UnknownVersion);
98 }
99
100 Ok(from_bytes(bytes)?)
101 }
102
103 }
105
106#[derive(thiserror::Error, Debug, PartialEq)]
107pub enum Error {
109 #[error("Empty payload")]
110 EmptyPayload,
112 #[error("Unknown version")]
113 UnknownVersion,
115 #[error(transparent)]
116 Parsing(#[from] postcard::Error),
118}
119
120#[cfg(test)]
121mod tests {
122 use crate::{capabilities::Capability, crypto::Keypair};
123
124 use super::*;
125
126 #[test]
127 fn serialize() {
128 let keypair = Keypair::from_secret(&[0; 32]);
129 let public_key = keypair.public_key();
130 let capabilities = Capabilities::builder().cap(Capability::root()).finish();
131
132 let session = CookieSessionRecord {
133 user_agent: "foo".to_string(),
134 capabilities: capabilities.into(),
135 created_at: 0,
136 public_key,
137 version: 0,
138 name: "".to_string(),
139 };
140
141 let serialized = session.serialize();
142
143 assert_eq!(
144 serialized,
145 [
146 0, 59, 106, 39, 188, 206, 182, 164, 45, 98, 163, 168, 208, 42, 111, 13, 115, 101,
147 50, 21, 119, 29, 226, 67, 166, 58, 192, 72, 161, 139, 89, 218, 41, 0, 0, 3, 102,
148 111, 111, 1, 4, 47, 58, 114, 119
149 ]
150 );
151
152 let deserialized = CookieSessionRecord::deserialize(&serialized).unwrap();
153
154 assert_eq!(deserialized, session)
155 }
156
157 #[test]
158 fn deserialize() {
159 let result = CookieSessionRecord::deserialize(&[]);
160
161 assert_eq!(result, Err(Error::EmptyPayload));
162 }
163}