#[cfg(not(target_arch = "wasm32"))]
use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(target_arch = "wasm32")]
use web_time::{SystemTime, UNIX_EPOCH};
use serde::{Deserialize, Serialize};
use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize};
use crate::treesync::errors::LifetimeError;
const DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS: u64 = 60 * 60 * 24 * 28 * 3;
const DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS: u64 = 60 * 60;
const MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS: u64 =
DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS + DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS;
#[derive(
PartialEq,
Eq,
Copy,
Clone,
Debug,
TlsSerialize,
TlsSize,
TlsDeserialize,
TlsDeserializeBytes,
Serialize,
Deserialize,
)]
pub struct Lifetime {
not_before: u64,
not_after: u64,
}
impl Lifetime {
pub fn new(t: u64) -> Self {
let lifetime_margin: u64 = DEFAULT_KEY_PACKAGE_LIFETIME_MARGIN_SECONDS;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("SystemTime before UNIX EPOCH!")
.as_secs();
let not_before = now - lifetime_margin;
let not_after = now + t;
Self {
not_before,
not_after,
}
}
pub fn init(not_before: u64, not_after: u64) -> Self {
Self {
not_before,
not_after,
}
}
pub fn validate(&self) -> Result<(), LifetimeError> {
self.validate_with_time(SystemTime::now())
}
pub fn validate_with_time(&self, now: SystemTime) -> Result<(), LifetimeError> {
let duration_since_unix_epoch = now
.duration_since(UNIX_EPOCH)
.map_err(|_| LifetimeError::SystemTimeBeforeUnixEpoch)?
.as_secs();
if self.not_after <= duration_since_unix_epoch {
Err(LifetimeError::Expired {
not_after: self.not_after,
now: duration_since_unix_epoch,
})
} else if self.not_before > duration_since_unix_epoch {
Err(LifetimeError::NotValidYet {
not_before: self.not_before,
now: duration_since_unix_epoch,
})
} else {
Ok(())
}
}
pub fn has_acceptable_range(&self) -> bool {
self.not_after.saturating_sub(self.not_before) <= MAX_LEAF_NODE_LIFETIME_RANGE_SECONDS
}
pub fn not_before(&self) -> u64 {
self.not_before
}
pub fn not_after(&self) -> u64 {
self.not_after
}
}
impl Default for Lifetime {
fn default() -> Self {
Lifetime::new(DEFAULT_KEY_PACKAGE_LIFETIME_SECONDS)
}
}
#[cfg(test)]
mod tests {
use core::time::Duration;
#[cfg(not(target_arch = "wasm32"))]
use std::time::SystemTime;
#[cfg(target_arch = "wasm32")]
use web_time::SystemTime;
use tls_codec::{Deserialize, Serialize};
use super::Lifetime;
#[test]
fn lifetime() {
let ext = Lifetime::default();
ext.validate().expect("Default Lifetime should be valid");
let ext = Lifetime::new(0);
let now_plus_1s = SystemTime::now() + Duration::from_secs(1);
let e = ext
.validate_with_time(now_plus_1s)
.expect_err("Lifetime should be expired");
assert!(matches!(e, super::LifetimeError::Expired { .. }));
let five_hours_before_now = SystemTime::now() - Duration::from_hours(5);
let e = ext
.validate_with_time(five_hours_before_now)
.expect_err("Lifetime should not be valid yet");
assert!(matches!(e, super::LifetimeError::NotValidYet { .. }));
let serialized = ext
.tls_serialize_detached()
.expect("error encoding life time extension");
let ext_deserialized = Lifetime::tls_deserialize(&mut serialized.as_slice())
.expect("Error deserializing lifetime");
ext_deserialized
.validate_with_time(now_plus_1s)
.expect_err("Lifetime should be expired");
}
}