qol(http): replaced all explicit header setting with axum cookie jar

This commit is contained in:
2026-07-15 14:41:54 +01:00
parent ce064ba9c8
commit 7262a06f28
3 changed files with 46 additions and 38 deletions
+1
View File
@@ -37,3 +37,4 @@ rubato = "3.0.0"
chrono = "0.4.45"
regex = "1"
thiserror = "2.0.18"
axum-extra = { version = "0.12.6", features = ["cookie"] }
+11 -38
View File
@@ -6,6 +6,7 @@ use std::{
},
};
use axum_extra::extract::{CookieJar, cookie::Cookie};
use regex::Regex;
// The Rust `regex` crate is guaranteed linear-time and therefore does NOT
@@ -206,22 +207,6 @@ struct CreateStreamKeyBody {
label: String,
}
fn extract_session_token(headers: &HeaderMap) -> Option<String> {
// Check bare `session` header first (curl / API clients)
if let Some(v) = headers.get("session") {
return Some(v.to_str().ok()?.to_string());
}
// Fall back to Cookie header (browsers)
let cookie_header = headers.get("cookie")?.to_str().ok()?;
cookie_header
.split(';')
.find_map(|pair| {
let pair = pair.trim();
pair.strip_prefix("session=")
})
.map(|v| v.to_string())
}
struct AuthUser(entity::users::Model);
impl FromRequestParts<Arc<HttpServer>> for AuthUser {
@@ -231,9 +216,10 @@ impl FromRequestParts<Arc<HttpServer>> for AuthUser {
parts: &mut Parts,
state: &Arc<HttpServer>,
) -> Result<Self, HttpError> {
let token = extract_session_token(&parts.headers).ok_or(HttpError::Unauthorized)?;
let jar = CookieJar::from_request_parts(parts, state).await.unwrap();
let session = jar.get("session").ok_or(HttpError::Unauthorized)?;
let user = users::Entity::find_by_auth_session(&state.db, token)
let user = users::Entity::find_by_auth_session(&state.db, session.to_string())
.await?
.ok_or(HttpError::Unauthorized)?;
@@ -306,6 +292,7 @@ struct LoginResponse {
async fn login_handler(
State(state): State<Arc<HttpServer>>,
Json(payload): Json<LoginForm>,
jar: CookieJar,
) -> Result<impl IntoResponse, HttpError> {
let user = users::Entity::find_by_username(&state.db, payload.username.clone())
.await?
@@ -323,16 +310,8 @@ async fn login_handler(
let auth = auth_session::Entity::create(&state.db, user.id).await?;
let token = auth.value;
let mut meow = Response::new("".to_string());
// TODO: Replace with axum cookie jar https://docs.rs/axum-extra/latest/axum_extra/extract/cookie/struct.CookieJar.html
meow.headers_mut().insert(
SET_COOKIE,
format!("session={token}; SameSite=Strict; Path=/; Max-Age=2592000")
.parse()
.unwrap(),
);
*meow.status_mut() = StatusCode::OK;
Ok(meow)
let jar = jar.add(Cookie::new("session", token));
Ok((StatusCode::OK, jar))
}
#[derive(Deserialize)]
@@ -345,7 +324,8 @@ struct CreateUserForm {
async fn create_user_handler(
State(state): State<Arc<HttpServer>>,
Json(payload): Json<CreateUserForm>,
) -> Result<(HeaderMap, StatusCode), HttpError> {
jar: CookieJar,
) -> Result<impl IntoResponse, HttpError> {
if state.config.signup_code.is_empty() || payload.ref_token != state.config.signup_code {
warn!(username = %payload.username, "signup rejected: invalid signup code");
return Err(HttpError::Unauthorized);
@@ -372,15 +352,8 @@ async fn create_user_handler(
let session = auth_session::Entity::create(&state.db, user.id).await?;
let token = session.value;
let mut headers = HeaderMap::new();
// TODO: Replace with axum cookie jar https://docs.rs/axum-extra/latest/axum_extra/extract/cookie/struct.CookieJar.html
headers.insert(
SET_COOKIE,
format!("session={token}; HttpOnly; SameSite=Strict; Path=/")
.parse()
.unwrap(),
);
Ok((headers, StatusCode::OK))
let jar = jar.add(Cookie::new("session", token));
Ok((jar, StatusCode::OK))
}
async fn stream_handler(