Skip to main content

axum_security/cookie/store/
mod.rs

1mod memory;
2
3use std::{pin::Pin, sync::Arc};
4
5use axum::response::{IntoResponse, Response};
6pub use memory::MemStore;
7
8use crate::cookie::{CookieSession, SessionId};
9
10pub trait CookieStore: Send + Sync + 'static {
11    type State: Send + Sync + 'static;
12    type Error: IntoResponse + Send + 'static;
13
14    fn spawn_maintenance_task(&self) -> bool {
15        true
16    }
17
18    fn store_session(
19        &self,
20        session: CookieSession<Self::State>,
21    ) -> impl Future<Output = Result<(), Self::Error>> + Send;
22
23    fn remove_session(
24        &self,
25        id: &SessionId,
26    ) -> impl Future<Output = Result<Option<CookieSession<Self::State>>, Self::Error>> + Send;
27
28    fn load_session(
29        &self,
30        id: &SessionId,
31    ) -> impl Future<Output = Result<Option<CookieSession<Self::State>>, Self::Error>> + Send;
32
33    fn remove_before(&self, deadline: u64) -> impl Future<Output = Result<(), Self::Error>> + Send;
34}
35
36#[allow(clippy::type_complexity)]
37trait DynStore<S>: Send + Sync + 'static {
38    fn spawn_maintenance_task(&self) -> bool;
39
40    fn store_session(
41        &self,
42        session: CookieSession<S>,
43    ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>>;
44
45    fn remove_session<'a>(
46        &'a self,
47        id: &'a SessionId,
48    ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<S>>, Response>> + Send + 'a>>;
49
50    fn load_session<'a>(
51        &'a self,
52        id: &'a SessionId,
53    ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<S>>, Response>> + Send + 'a>>;
54
55    fn remove_before(
56        &self,
57        deadline: u64,
58    ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>>;
59}
60
61impl<T> DynStore<T::State> for T
62where
63    T: CookieStore,
64{
65    fn spawn_maintenance_task(&self) -> bool {
66        <T as CookieStore>::spawn_maintenance_task(self)
67    }
68
69    fn store_session(
70        &self,
71        session: CookieSession<T::State>,
72    ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>> {
73        Box::pin(async move {
74            <T as CookieStore>::store_session(self, session)
75                .await
76                .map_err(IntoResponse::into_response)
77        })
78    }
79
80    fn remove_session<'a>(
81        &'a self,
82        id: &'a SessionId,
83    ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<T::State>>, Response>> + Send + 'a>>
84    {
85        Box::pin(async move {
86            <T as CookieStore>::remove_session(self, id)
87                .await
88                .map_err(IntoResponse::into_response)
89        })
90    }
91
92    fn load_session<'a>(
93        &'a self,
94        id: &'a SessionId,
95    ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<T::State>>, Response>> + Send + 'a>>
96    {
97        Box::pin(async move {
98            <T as CookieStore>::load_session(self, id)
99                .await
100                .map_err(IntoResponse::into_response)
101        })
102    }
103
104    fn remove_before(
105        &self,
106        deadline: u64,
107    ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>> {
108        Box::pin(async move {
109            <T as CookieStore>::remove_before(self, deadline)
110                .await
111                .map_err(IntoResponse::into_response)
112        })
113    }
114}
115
116pub(crate) struct ErasedStore<S>(Arc<dyn DynStore<S>>);
117
118impl<S: 'static> ErasedStore<S> {
119    pub fn new(store: S) -> ErasedStore<S::State>
120    where
121        S: CookieStore,
122    {
123        ErasedStore(Arc::new(store))
124    }
125
126    pub fn spawn_maintenance_task(&self) -> bool {
127        self.0.spawn_maintenance_task()
128    }
129
130    pub async fn store_session(&self, session: CookieSession<S>) -> Result<(), Response> {
131        self.0.store_session(session).await
132    }
133
134    pub async fn remove_session(
135        &self,
136        id: &SessionId,
137    ) -> Result<Option<CookieSession<S>>, Response> {
138        self.0.remove_session(id).await
139    }
140
141    pub async fn load_session(&self, id: &SessionId) -> Result<Option<CookieSession<S>>, Response> {
142        self.0.load_session(id).await
143    }
144
145    pub async fn remove_before(&self, deadline: u64) -> Result<(), Response> {
146        self.0.remove_before(deadline).await
147    }
148}
149
150impl<S> Clone for ErasedStore<S> {
151    fn clone(&self) -> Self {
152        ErasedStore(self.0.clone())
153    }
154}