conrad_core/
request.rs

1use crate::{
2    auth::{self, Authenticator},
3    database::DatabaseAdapter,
4    errors::AuthError,
5    Session, ValidationSuccess,
6};
7use cookie::CookieJar;
8use http::{HeaderMap, Method};
9use tracing::info;
10use url::Url;
11
12pub struct Request<'a, D, U> {
13    auth: &'a Authenticator<D, U>,
14    stored_session_id: Option<String>,
15    validated_user: Option<ValidationSuccess<U>>,
16}
17
18impl<'a, D, U> Request<'a, D, U>
19where
20    D: DatabaseAdapter<U>,
21{
22    pub(crate) fn new(
23        auth: &'a Authenticator<D, U>,
24        cookies: &CookieJar,
25        method: &Method,
26        headers: &HeaderMap,
27        origin_url: &Url,
28    ) -> Self {
29        Self {
30            stored_session_id: auth::parse_request_headers(cookies, method, headers, origin_url)
31                .map(|session_id| session_id.to_string()),
32            auth,
33            validated_user: None,
34        }
35    }
36
37    pub fn set_session(&mut self, cookies: &mut CookieJar, session: Option<Session>) {
38        let session_id = session.clone().map(|s| s.session_id);
39        if self.stored_session_id == session_id {
40            return;
41        }
42        self.validated_user = None;
43        self.stored_session_id = session_id;
44        let cookie = auth::create_session_cookie(session.clone());
45        cookies.add(cookie);
46        if let Some(session) = session {
47            info!(session.session_id, "session cookie stored");
48        } else {
49            info!("session cookie deleted");
50        }
51    }
52
53    fn set_session_cookie(&mut self, cookies: &mut CookieJar, session: Option<Session>) {
54        let session_id = session.clone().map(|s| s.session_id);
55        if self.stored_session_id == session_id {
56            return;
57        }
58        self.stored_session_id = session_id;
59        let cookie = auth::create_session_cookie(session.clone());
60        cookies.add(cookie);
61        if let Some(session) = session {
62            info!(session.session_id, "session cookie stored");
63        } else {
64            info!("session cookie deleted");
65        }
66    }
67}
68
69impl<'a, D, U> Request<'a, D, U>
70where
71    D: DatabaseAdapter<U>,
72    U: Clone,
73{
74    pub async fn validate_user(
75        &mut self,
76        cookies: &mut CookieJar,
77    ) -> Result<Option<ValidationSuccess<U>>, AuthError> {
78        if let Some(validated_user) = &self.validated_user {
79            info!("using cached result for session validation");
80            return Ok(Some(validated_user.clone()));
81        }
82        match &self.stored_session_id {
83            Some(stored_session_id) => {
84                let res = self.auth.validate_session_user(stored_session_id).await;
85                let info = match res {
86                    Ok(info) => info,
87                    Err(_) => {
88                        self.set_session_cookie(cookies, None);
89                        return Ok(None);
90                    }
91                };
92                if info.session.fresh {
93                    self.set_session_cookie(cookies, Some(info.session.clone()));
94                }
95                Ok(Some(info))
96            }
97            None => {
98                self.set_session_cookie(cookies, None);
99                Ok(None)
100            }
101        }
102    }
103}