Skip to main content

orbit_auth/
cache.rs

1use std::num::NonZeroUsize;
2use std::sync::{Arc, Mutex};
3
4use lru::LruCache;
5
6use crate::Principal;
7
8/// Opaque, keyed token fingerprint scoped to the keyring and validation context.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct CacheKey(pub(crate) [u8; 32]);
11
12impl CacheKey {
13    pub fn as_bytes(&self) -> &[u8; 32] {
14        &self.0
15    }
16}
17
18/// Successful authenticated snapshot, never a raw token. Constructed only by the validator.
19#[derive(Clone, Debug)]
20pub struct CachedPrincipal {
21    pub(crate) key: CacheKey,
22    pub(crate) principal: Arc<Principal>,
23    pub(crate) cached_at: u64,
24    pub(crate) valid_until: u64,
25}
26
27impl CachedPrincipal {
28    pub fn principal(&self) -> &Arc<Principal> {
29        &self.principal
30    }
31    pub fn valid_until(&self) -> u64 {
32        self.valid_until
33    }
34}
35
36/// Trusted optimization only; misses and failures must return `None`.
37///
38/// Preserve entries as supplied and bound memory. No invalidation guarantee is required:
39/// expiry and the current validation hook are checked on every hit. This interface does
40/// not provide an atomic replay store. Concurrent cold misses may independently decrypt.
41pub trait PrincipalCache {
42    fn get(
43        &self,
44        key: &CacheKey,
45    ) -> Option<CachedPrincipal>;
46    fn insert(
47        &self,
48        key: CacheKey,
49        entry: CachedPrincipal,
50    );
51}
52
53/// Bounded process-local decoded-principal LRU. A hit only clones an `Arc`.
54pub struct MemoryCache(Mutex<LruCache<CacheKey, CachedPrincipal>>);
55
56impl MemoryCache {
57    pub fn new(capacity: NonZeroUsize) -> Self {
58        Self(Mutex::new(LruCache::new(capacity)))
59    }
60
61    pub fn clear(&self) {
62        self.0.lock().unwrap_or_else(|error| error.into_inner()).clear();
63    }
64}
65
66impl PrincipalCache for MemoryCache {
67    fn get(
68        &self,
69        key: &CacheKey,
70    ) -> Option<CachedPrincipal> {
71        self.0
72            .lock()
73            .unwrap_or_else(|error| error.into_inner())
74            .get(key)
75            .cloned()
76    }
77
78    fn insert(
79        &self,
80        key: CacheKey,
81        entry: CachedPrincipal,
82    ) {
83        self.0
84            .lock()
85            .unwrap_or_else(|error| error.into_inner())
86            .put(key, entry);
87    }
88}