use std::sync::Arc; use actix_web::body::{BoxBody, MessageBody}; use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::middleware::Next; use actix_web::web::Data; use actix_web::{Error, HttpResponse}; use export::AppState; use crate::auth::session::cookie::{append_cookie, read_cookie_header}; const SKIP_PREFIXES: [&str; 8] = [ "/healthz", "/readyz", "/api/docs", "/api/v1/auth/", "/api/v1/internal", "/assets", "/pages", "/swagger", ]; pub async fn revalidate( request: ServiceRequest, next: Next, ) -> Result, Error> where B: MessageBody + 'static, { if SKIP_PREFIXES .iter() .any(|prefix| request.path().starts_with(prefix)) { return Ok(next.call(request).await?.map_into_boxed_body()); } let Some(state) = request .app_data::>() .map(|value| value.get_ref().clone()) else { return Ok(next.call(request).await?.map_into_boxed_body()); }; let Some(verifier) = request .app_data::>>() .map(|value| value.get_ref().clone()) else { return Ok(next.call(request).await?.map_into_boxed_body()); }; let token = read_cookie_header(request.headers(), &state.config.jwt.session_cookie).map(str::to_owned); let Some(token) = token else { return Ok(next.call(request).await?.map_into_boxed_body()); }; let Ok(claims) = verifier.verify_access(&token).await else { return Ok(next.call(request).await?.map_into_boxed_body()); }; let Some(session_id) = claims.sid.as_deref().map(str::to_owned) else { return Ok(next.call(request).await?.map_into_boxed_body()); }; let Some(kenauth) = state.kenauth.as_ref().cloned() else { return Ok(next.call(request).await?.map_into_boxed_body()); }; let key = format!("auth:recheck:{}:{}", session_id, claims.security_version); if export::redis::get_string(&state.redis, &key) .await .ok() .flatten() .is_some() { return Ok(next.call(request).await?.map_into_boxed_body()); } match kenauth .get_session(claims.sub, claims.security_version, &session_id) .await { Ok(_) => { let _ = export::redis::set_string(&state.redis, &key, "1", state.config.jwt.recheck_secs) .await; Ok(next.call(request).await?.map_into_boxed_body()) } Err(auth::client::error::KenAuthError::Unauthenticated) | Err(auth::client::error::KenAuthError::NotFound) => { let mut response = HttpResponse::Unauthorized().json(serde_json::json!({ "code": 401, "message": "session_revoked", "data": null, "error": null, "error_code": "session_revoked", "request_id": null, "log_id": null, })); append_cookie( &mut response, &token::clear_session_cookie(&state.config.jwt), ); Ok(request.into_response(response)) } Err(_) => Ok(next.call(request).await?.map_into_boxed_body()), } }