Looks up the session behind the Authorization header, if any, and makes it available to inner services through [LoggedInSession]/[OptionalSession] request extensions.
(
State(state): State<AppState>,
mut req: Request<Body>,
next: Next,
)
| 57 | /// available to inner services through [LoggedInSession]/[OptionalSession] |
| 58 | /// request extensions. |
| 59 | pub async fn session_mw( |
| 60 | State(state): State<AppState>, |
| 61 | mut req: Request<Body>, |
| 62 | next: Next, |
| 63 | ) -> Result<axum::response::Response, ApiErrorResponse> { |
| 64 | let session = match req.headers().get("Authorization").map(|v| v.to_str()) { |
| 65 | Some(Ok(token)) => state.db.get_session(token).await.map_err(|err| { |
| 66 | error!(%err, "failed fetching session"); |
| 67 | ApiErrorResponse::InternalError |
| 68 | })?, |
| 69 | // treat a malformed header the same as an absent one |
| 70 | Some(Err(_)) => None, |
| 71 | None => None, |
| 72 | }; |
| 73 | |
| 74 | let Some(session) = session else { |
| 75 | req.extensions_mut().insert(OptionalSession::none()); |
| 76 | return Ok(next.run(req).await); |
| 77 | }; |
| 78 | |
| 79 | let span = tracing::info_span!("session", user_id=%session.user.id); |
| 80 | |
| 81 | async { |
| 82 | let api_client = state |
| 83 | .oauth_api_client_cache |
| 84 | .fetch(session.user.id, &session.oauth_token.access_token); |
| 85 | |
| 86 | let logged_in_session = LoggedInSession::new(session, api_client); |
| 87 | |
| 88 | // Check if the session is broken, for example they unauthorized botloader or something along those lines. |
| 89 | let was_broken = check_broken_session(&state, &logged_in_session).await; |
| 90 | if !was_broken { |
| 91 | req.extensions_mut().insert(logged_in_session.clone()); |
| 92 | req.extensions_mut() |
| 93 | .insert(OptionalSession(Some(logged_in_session.clone()))); |
| 94 | } else { |
| 95 | info!("Found broken session before handler ran"); |
| 96 | req.extensions_mut().insert(OptionalSession(None)); |
| 97 | } |
| 98 | |
| 99 | let resp = next.run(req).await; |
| 100 | |
| 101 | // re-check after running the inner handler, as it could have changed |
| 102 | if !was_broken { |
| 103 | if check_broken_session(&state, &logged_in_session).await { |
| 104 | info!("Found broken session after handler ran"); |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | Ok(resp) |
| 109 | } |
| 110 | .instrument(span) |
| 111 | .await |
| 112 | } |
| 113 | |
| 114 | async fn check_broken_session( |
| 115 | state: &Arc<crate::app_state::InnerAppState>, |
nothing calls this directly
no test coverage detected