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}