Skip to main content

aster_forge_auth/
time.rs

1//! Clock abstraction for deterministic expiry and concurrency tests.
2
3use std::time::{SystemTime, UNIX_EPOCH};
4
5use crate::{AuthError, Result};
6
7/// Time source used by token issuance and validation.
8pub trait Clock: Send + Sync {
9    /// Returns the current Unix timestamp in seconds.
10    ///
11    /// # Errors
12    ///
13    /// Returns [`AuthError`](crate::AuthError) if the system clock cannot be represented.
14    fn now_unix_seconds(&self) -> Result<i64>;
15}
16
17/// Production clock backed by `SystemTime`.
18#[derive(Debug, Default, Clone, Copy)]
19pub struct SystemClock;
20
21impl Clock for SystemClock {
22    fn now_unix_seconds(&self) -> Result<i64> {
23        let duration = SystemTime::now()
24            .duration_since(UNIX_EPOCH)
25            .map_err(|_| AuthError::InvalidPolicy)?;
26        i64::try_from(duration.as_secs()).map_err(|_| AuthError::InvalidPolicy)
27    }
28}
29
30/// Fixed clock for deterministic tests and product integration tests.
31#[derive(Debug, Clone, Copy)]
32pub struct FixedClock {
33    seconds: i64,
34}
35
36impl FixedClock {
37    /// Creates a clock at a Unix timestamp.
38    #[must_use]
39    pub const fn new(seconds: i64) -> Self {
40        Self { seconds }
41    }
42
43    /// Returns the configured timestamp.
44    #[must_use]
45    pub const fn seconds(self) -> i64 {
46        self.seconds
47    }
48}
49
50impl Clock for FixedClock {
51    fn now_unix_seconds(&self) -> Result<i64> {
52        Ok(self.seconds)
53    }
54}