p2panda_encryption/key_bundle/
lifetime.rs1use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8const DEFAULT_LIFETIME: u64 = 60 * 60 * 24 * 28 * 3;
10
11const DEFAULT_LIFETIME_MARGIN: u64 = 60 * 60;
14
15#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
19pub struct Lifetime {
20 not_before: u64,
21 not_after: u64,
22}
23
24impl Lifetime {
25 pub fn new(t: u64) -> Self {
30 let lifetime_margin: u64 = DEFAULT_LIFETIME_MARGIN;
31 let now = SystemTime::now()
32 .duration_since(UNIX_EPOCH)
33 .expect("SystemTime before UNIX EPOCH!")
34 .as_secs();
35 let not_before = now - lifetime_margin;
36 let not_after = now + t;
37 Self {
38 not_before,
39 not_after,
40 }
41 }
42
43 pub fn verify(&self) -> Result<(), LifetimeError> {
45 let is_valid = match SystemTime::now()
46 .duration_since(UNIX_EPOCH)
47 .map(|duration| duration.as_secs())
48 {
49 Ok(elapsed) => self.not_before < elapsed && elapsed < self.not_after,
50 Err(err) => return Err(LifetimeError::SystemTime(err)),
51 };
52
53 if is_valid {
54 Ok(())
55 } else {
56 Err(LifetimeError::InvalidLifetime)
57 }
58 }
59
60 pub fn verify_with_window(&self, window: Duration) -> Result<(), LifetimeError> {
75 let is_valid = match SystemTime::now()
76 .duration_since(UNIX_EPOCH)
77 .map(|duration| duration.as_secs())
78 {
79 Ok(elapsed) => {
80 let elapsed = elapsed + window.as_secs();
81 self.not_before < elapsed && elapsed < self.not_after
82 }
83 Err(err) => return Err(LifetimeError::SystemTime(err)),
84 };
85
86 if is_valid {
87 Ok(())
88 } else {
89 Err(LifetimeError::InvalidLifetime)
90 }
91 }
92}
93
94impl Default for Lifetime {
95 fn default() -> Self {
96 Lifetime::new(DEFAULT_LIFETIME)
97 }
98}
99
100impl Ord for Lifetime {
101 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
102 self.not_after.cmp(&other.not_after)
103 }
104}
105
106impl PartialOrd for Lifetime {
107 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
108 Some(self.cmp(other))
109 }
110}
111
112#[cfg(any(test, feature = "test_utils"))]
113impl Lifetime {
114 pub fn from_range(not_before: u64, not_after: u64) -> Self {
115 Self {
116 not_before,
117 not_after,
118 }
119 }
120}
121
122#[derive(Debug, Error)]
123pub enum LifetimeError {
124 #[error("lifetime of pre-key is not valid")]
125 InvalidLifetime,
126
127 #[error(transparent)]
128 SystemTime(std::time::SystemTimeError),
129}
130
131#[cfg(test)]
132mod tests {
133 use std::time::{Duration, SystemTime, UNIX_EPOCH};
134
135 use super::Lifetime;
136
137 #[test]
138 fn verify() {
139 let now = SystemTime::now()
140 .duration_since(UNIX_EPOCH)
141 .expect("SystemTime before UNIX EPOCH!")
142 .as_secs();
143
144 let lifetime = Lifetime::default();
146 assert!(lifetime.verify().is_ok());
147
148 let lifetime = Lifetime::new(60);
150 assert!(lifetime.verify().is_ok());
151 assert!(
152 lifetime
153 .verify_with_window(Duration::from_secs(120))
154 .is_err()
155 );
156
157 let lifetime = Lifetime::from_range(now - 60, now + 60);
159 assert!(lifetime.verify().is_ok());
160
161 let lifetime = Lifetime::from_range(now + 60, now + 60); assert!(lifetime.verify().is_err());
164
165 let lifetime = Lifetime::from_range(now - 120, now - 60); assert!(lifetime.verify().is_err());
167 }
168}