From 74d2ada067bd2fd9436710ab7ac260e0eddf1314 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 29 Jul 2026 01:03:24 +0200 Subject: Add per-instance mod management with client-side detection - New mod validation engine (src/mods.rs) with constant-pool class-file scanning: detects server-side content (block, tileentity, command, worldgen) vs client-only API (gui, renderer, forge/client) - 7 client-only mods correctly detected (AppleSkin, CraftingTweaks, Durability101, EnchantmentDescriptions, InventoryHUD, MouseTweaks, TrashSlot); 51 server-capable; 1 unknown - Routes + templating for mod upload (jar/zip), listing, delete, rescan - Multipart upload with 500MB limit (bypasses axum's default 2MB) - Per-instance mod summary card on edit page - Whitelist toggle checkbox on edit page (persisted, drives ENABLE_WHITELIST) - Dynamic Java image tag (java8/java17/java21) based on MC version - Class scan is informational-only; rejection based on metadata side=CLIENT - has_modpack flag cleanup on mod delete - Remove hx-boost from (was corrupting multipart uploads) --- src/auth.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'src/auth.rs') diff --git a/src/auth.rs b/src/auth.rs index 8fa62ec..3c89e37 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -97,15 +97,17 @@ pub async fn require_auth( mut request: Request, next: Next, ) -> Result { - let cookies = request + let raw_cookies = request .headers() .get(axum::http::header::COOKIE) .and_then(|v| v.to_str().ok()) - .unwrap_or(""); + .unwrap_or("[no cookie header]") + .to_string(); - let session_id = cookies.split(';').map(|s| s.trim()).find_map(|cookie| { + let session_id = raw_cookies.split(';').map(|s| s.trim()).find_map(|cookie| { if let Some((name, value)) = cookie.split_once('=') { - if name.trim() == SESSION_COOKIE { + let n = name.trim(); + if n == SESSION_COOKIE { Some(value.trim().to_string()) } else { None @@ -137,13 +139,18 @@ pub async fn require_auth( .ok(); if let Some(account) = account { + tracing::debug!("Auth OK for {}", account.username); request.extensions_mut().insert(account); Ok(next.run(request).await) } else { + tracing::warn!("Session {id} not found in DB (raw cookies: {raw_cookies})"); Err(Redirect::to("/login").into_response()) } } - None => Err(Redirect::to("/login").into_response()), + None => { + tracing::warn!("No session cookie found (raw cookies: {raw_cookies})"); + Err(Redirect::to("/login").into_response()) + } } } @@ -170,21 +177,19 @@ pub async fn logout( State(state): State, headers: axum::http::HeaderMap, ) -> impl IntoResponse { - if let Some(cookie_header) = headers.get(axum::http::header::COOKIE) { - if let Ok(cookie_str) = cookie_header.to_str() { + if let Some(cookie_header) = headers.get(axum::http::header::COOKIE) + && let Ok(cookie_str) = cookie_header.to_str() { for part in cookie_str.split(';') { let part = part.trim(); - if let Some((name, value)) = part.split_once('=') { - if name.trim() == SESSION_COOKIE { + if let Some((name, value)) = part.split_once('=') + && name.trim() == SESSION_COOKIE { let _ = state .db .conn() .execute("DELETE FROM sessions WHERE id = ?1", params![value.trim()]); } - } } } - } let clear_cookie = format!("{SESSION_COOKIE}=; Path=/; HttpOnly; Max-Age=0"); ( -- cgit v1.2.3