axess_core/testing/
mock_refresh_store.rs1use crate::authn::ids::UserId;
18use crate::session::refresh::{RefreshToken, RefreshTokenId, RefreshTokenStore, TokenFamilyId};
19use crate::store::{MemoryStore, Store};
20use chrono::Utc;
21use std::time::Duration;
22
23#[derive(Clone, Default)]
25pub struct MemoryRefreshTokenStore {
26 inner: MemoryStore<RefreshTokenId, RefreshToken>,
27}
28
29pub type MemoryRefreshStoreError = std::convert::Infallible;
33
34impl MemoryRefreshTokenStore {
35 pub fn new() -> Self {
37 Self::default()
38 }
39}
40
41impl RefreshTokenStore for MemoryRefreshTokenStore {
42 type Error = MemoryRefreshStoreError;
43
44 async fn store_token(&self, token: &RefreshToken) -> Result<(), Self::Error> {
45 let ttl = (token.expires_at - Utc::now())
50 .to_std()
51 .unwrap_or(Duration::ZERO);
52 self.inner.put(&token.id, token, ttl).await
53 }
54
55 async fn find_token(&self, token_hash: &str) -> Result<Option<RefreshToken>, Self::Error> {
56 let found = self
59 .inner
60 .snapshot()
61 .into_iter()
62 .find(|(_, t)| t.token_hash == token_hash)
63 .map(|(_, t)| t);
64 Ok(found)
65 }
66
67 async fn revoke_token(&self, token_id: &RefreshTokenId) -> Result<(), Self::Error> {
68 self.inner.update(token_id, |t| t.revoked = true);
69 Ok(())
70 }
71
72 async fn revoke_user_tokens(&self, user_id: &UserId) -> Result<(), Self::Error> {
73 for (id, token) in self.inner.snapshot() {
74 if &token.user_id == user_id {
75 self.inner.update(&id, |t| t.revoked = true);
76 }
77 }
78 Ok(())
79 }
80
81 async fn revoke_family(
82 &self,
83 user_id: &UserId,
84 family_id: &TokenFamilyId,
85 ) -> Result<(), Self::Error> {
86 for (id, token) in self.inner.snapshot() {
87 if &token.user_id == user_id && token.family_id.as_ref() == Some(family_id) {
88 self.inner.update(&id, |t| t.revoked = true);
89 }
90 }
91 Ok(())
92 }
93
94 async fn active_tokens(&self, user_id: &UserId) -> Result<Vec<RefreshToken>, Self::Error> {
95 let mut tokens: Vec<RefreshToken> = self
96 .inner
97 .snapshot()
98 .into_iter()
99 .filter(|(_, t)| &t.user_id == user_id && !t.revoked)
100 .map(|(_, t)| t)
101 .collect();
102 tokens.sort_by_key(|t| t.issued_at);
103 Ok(tokens)
104 }
105
106 async fn issue_with_eviction(
114 &self,
115 evict_ids: &[RefreshTokenId],
116 new_token: &RefreshToken,
117 ) -> Result<(), Self::Error> {
118 for id in evict_ids {
119 self.revoke_token(id).await?;
120 }
121 self.store_token(new_token).await
122 }
123
124 async fn rotate_token(
125 &self,
126 parent_id: &RefreshTokenId,
127 new_token: &RefreshToken,
128 ) -> Result<(), Self::Error> {
129 self.revoke_token(parent_id).await?;
130 self.store_token(new_token).await
131 }
132}