use actix_web::{
body::MessageBody,
cookie::{time::Duration, Cookie, SameSite},
dev::{ServiceRequest, ServiceResponse},
http::header::{HeaderName, HeaderValue},
middleware::Next,
Error,
};
use crate::{
app::{App, AppTypes},
maybe_auth::MaybeAuth,
sessions::authenticate_by_session_token,
token_actions::AuthTokenAction,
users::HasUserID,
};
pub async fn middleware<A: App>(
mut request: ServiceRequest,
next: Next<impl MessageBody>,
) -> Result<ServiceResponse<impl MessageBody>, Error>
where A: actix_web::FromRequest<Error = <A as AppTypes>::Error>,
{
let mut app = request.extract::<A>()
.await?;
let auth = authenticate_by_session_token(&mut app, &request)
.await?;
match &auth {
MaybeAuth::Authenticated(auth) => {
log::debug!("Authenticated as user {}, session {} ({})", auth.user.id(), auth.session_id, auth.user_state);
}
MaybeAuth::Unauthenticated => {
log::debug!("Not authenticated");
}
}
auth.insert_into_request(&request);
let mut response = next.call(request)
.await?;
response.headers_mut().append(
HeaderName::from_static("cache-control"),
HeaderValue::from_static("no-cache=\"Set-Cookie, Set-Cookie2\""),
);
match AuthTokenAction::take_from_request(response.request()) {
AuthTokenAction::Issue(token) => {
log::debug!("Issuing session cookie");
let mut cookie = new_session_cookie(&app, token.expose());
let duration = Duration::hours(app.session_expire_after_hours() as i64);
cookie.set_max_age(duration);
response.response_mut()
.add_cookie(&cookie)?;
}
AuthTokenAction::Revoke => {
log::debug!("Revoking session cookie");
let cookie = new_session_cookie(&app, "");
response.response_mut()
.add_removal_cookie(&cookie)?;
}
AuthTokenAction::DoNothing => {}
}
Ok(response)
}
fn new_session_cookie<'a, A: App>(app: &'a A, token: &'a str) -> Cookie<'a> {
let cookie_name = app.session_token_cookie_name();
let mut cookie = Cookie::new(cookie_name, token);
if let Some(domain) = app.session_token_cookie_domain() {
cookie.set_domain(domain);
}
cookie.set_path(app.session_token_cookie_path());
cookie.set_http_only(true);
cookie.set_secure(true);
cookie.set_same_site(if app.session_token_cookie_same_site_strict() {
SameSite::Strict
} else {
SameSite::Lax
});
cookie
}