1use actix_web::{
2 body::MessageBody,
3 cookie::{time::Duration, Cookie, SameSite},
4 dev::{ServiceRequest, ServiceResponse},
5 http::header::{HeaderName, HeaderValue},
6 middleware::Next,
7 Error,
8};
9
10use crate::{
11 app::App,
12 maybe_auth::MaybeAuth,
13 sessions::authenticate_by_session_token,
14 token_actions::AuthTokenAction,
15 users::UserID, AppTypes,
16};
17
18pub async fn middleware<A: App>(
19 mut request: ServiceRequest,
20 next: Next<impl MessageBody>,
21) -> Result<ServiceResponse<impl MessageBody>, Error>
22 where A: actix_web::FromRequest<Error = <A as AppTypes>::Error>,
23{
24 let mut app = request.extract::<A>()
25 .await?;
26
27 let auth = authenticate_by_session_token(&mut app, &request)
29 .await?;
30
31 match &auth {
32 MaybeAuth::Authenticated(auth) => {
33 log::debug!("Authenticated as user #{}, session #{} ({})", auth.user.id(), auth.session_id, auth.user_state);
34 }
35 MaybeAuth::Unauthenticated => {
36 log::debug!("Not authenticated");
37 }
38 }
39
40 auth.insert_into_request(&request);
42
43 let mut response = next.call(request)
45 .await?;
46
47 response.headers_mut().append(
50 HeaderName::from_static("cache-control"),
51 HeaderValue::from_static("no-cache=\"Set-Cookie, Set-Cookie2\""),
52 );
53
54 let cookie_name = A::session_token_cookie_name(&app);
58
59 match AuthTokenAction::take_from_request(response.request()) {
60 AuthTokenAction::Issue(token) => {
61 log::debug!("Issuing session cookie");
62
63 let mut cookie = Cookie::new(cookie_name, &token.0);
66
67 cookie.set_http_only(true);
69
70 cookie.set_secure(true);
72
73 cookie.set_same_site(if A::session_token_cookie_same_site_strict(&app) {
74 SameSite::Strict
77 } else {
78 SameSite::Lax
82 });
83
84 let duration = Duration::hours(A::session_expire_after_hours(&app) as i64);
87 cookie.set_max_age(duration);
88
89 response.response_mut()
90 .add_cookie(&cookie)?;
91 }
92 AuthTokenAction::Revoke => {
93 log::debug!("Revoking session cookie");
94
95 let cookie = Cookie::new(cookie_name, "");
97 response.response_mut()
98 .add_removal_cookie(&cookie)?;
99 }
100 AuthTokenAction::DoNothing => {}
101 }
102
103 Ok(response)
104}