1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // Copyright by contributors to this project.
3 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
4 
5 use crate::{client::MlsError, time::MlsTime};
6 use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize};
7 
8 #[derive(Clone, Debug, PartialEq, Eq, MlsSize, MlsEncode, MlsDecode, Default)]
9 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
10 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11 #[non_exhaustive]
12 pub struct Lifetime {
13     pub not_before: u64,
14     pub not_after: u64,
15 }
16 
17 impl Lifetime {
new(not_before: u64, not_after: u64) -> Lifetime18     pub fn new(not_before: u64, not_after: u64) -> Lifetime {
19         Lifetime {
20             not_before,
21             not_after,
22         }
23     }
24 
seconds(s: u64) -> Result<Self, MlsError>25     pub fn seconds(s: u64) -> Result<Self, MlsError> {
26         #[cfg(feature = "std")]
27         let not_before = MlsTime::now().seconds_since_epoch();
28         #[cfg(not(feature = "std"))]
29         // There is no clock on no_std, this is here just so that we can run tests.
30         let not_before = 3600u64;
31 
32         let not_after = not_before.checked_add(s).ok_or(MlsError::TimeOverflow)?;
33 
34         Ok(Lifetime {
35             // Subtract 1 hour to address time difference between machines
36             not_before: not_before - 3600,
37             not_after,
38         })
39     }
40 
days(d: u32) -> Result<Self, MlsError>41     pub fn days(d: u32) -> Result<Self, MlsError> {
42         Self::seconds((d * 86400) as u64)
43     }
44 
years(y: u8) -> Result<Self, MlsError>45     pub fn years(y: u8) -> Result<Self, MlsError> {
46         Self::days(365 * y as u32)
47     }
48 
within_lifetime(&self, time: MlsTime) -> bool49     pub(crate) fn within_lifetime(&self, time: MlsTime) -> bool {
50         let since_epoch = time.seconds_since_epoch();
51         since_epoch >= self.not_before && since_epoch <= self.not_after
52     }
53 }
54 
55 #[cfg(test)]
56 mod tests {
57     use core::time::Duration;
58 
59     use super::*;
60     use assert_matches::assert_matches;
61 
62     #[test]
test_lifetime_overflow()63     fn test_lifetime_overflow() {
64         let res = Lifetime::seconds(u64::MAX);
65         assert_matches!(res, Err(MlsError::TimeOverflow))
66     }
67 
68     #[test]
test_seconds()69     fn test_seconds() {
70         let seconds = 10;
71         let lifetime = Lifetime::seconds(seconds).unwrap();
72         assert_eq!(lifetime.not_after - lifetime.not_before, 3610);
73     }
74 
75     #[test]
test_days()76     fn test_days() {
77         let days = 2;
78         let lifetime = Lifetime::days(days).unwrap();
79 
80         assert_eq!(
81             lifetime.not_after - lifetime.not_before,
82             86400u64 * days as u64 + 3600
83         );
84     }
85 
86     #[test]
test_years()87     fn test_years() {
88         let years = 2;
89         let lifetime = Lifetime::years(years).unwrap();
90 
91         assert_eq!(
92             lifetime.not_after - lifetime.not_before,
93             86400 * 365 * years as u64 + 3600
94         );
95     }
96 
97     #[test]
test_bounds()98     fn test_bounds() {
99         let test_lifetime = Lifetime {
100             not_before: 5,
101             not_after: 10,
102         };
103 
104         assert!(!test_lifetime
105             .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(4))));
106 
107         assert!(!test_lifetime
108             .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(11))));
109 
110         assert!(test_lifetime
111             .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(5))));
112 
113         assert!(test_lifetime
114             .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(10))));
115 
116         assert!(test_lifetime
117             .within_lifetime(MlsTime::from_duration_since_epoch(Duration::from_secs(6))));
118     }
119 }
120