Skip to main content

salvo_csrf/
session_store.rs

1use salvo_core::{Depot, Error, Request, Response};
2use salvo_session::SessionDepotExt;
3
4use super::{CsrfCipher, CsrfStore};
5
6/// A `CsrfStore` implementation that stores the CSRF proof in a session.
7#[derive(Debug)]
8pub struct SessionStore {
9    name: String,
10}
11impl Default for SessionStore {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl SessionStore {
18    /// Create a new `SessionStore`.
19    #[must_use]
20    pub fn new() -> Self {
21        Self {
22            name: "salvo.csrf".into(),
23        }
24    }
25}
26
27impl CsrfStore for SessionStore {
28    type Error = Error;
29    async fn load<C: CsrfCipher>(&self, _req: &mut Request, depot: &mut Depot, _cipher: &C) -> Option<(String, String)> {
30        depot
31            .session()
32            .and_then(|s| s.get::<String>(&self.name))
33            .and_then(|s| s.split_once('.').map(|(t, p)| (t.into(), p.into())))
34    }
35    async fn save(
36        &self,
37        _req: &mut Request,
38        depot: &mut Depot,
39        _res: &mut Response,
40        token: &str,
41        proof: &str,
42    ) -> Result<(), Self::Error> {
43        let Some(session) = depot.session_mut() else {
44            return Err(Error::other(
45                "session is not available in depot; add SessionHandler before Csrf<_, SessionStore>",
46            ));
47        };
48        session.insert(&self.name, format!("{token}.{proof}"))?;
49        Ok(())
50    }
51}