From 1a0ee71e6b0217face87d306be720c74af0f9cb1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Aug 2026 02:10:29 +0000 Subject: [PATCH] sessions: expire after 1 day Sessions previously had no expiry at all: a county_session cookie was valid forever until an explicit /logout. Both session lookups now reject rows older than 1 day (created_at-based, not sliding), and db::delete_expired_sessions prunes expired rows so the table doesn't grow unbounded; it's called during the existing OAuth-start housekeeping alongside the oauth_states cleanup. --- src/auth.rs | 4 ++++ src/db.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/auth.rs b/src/auth.rs index bd9077a..bdafeb0 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -35,6 +35,10 @@ pub async fn start(State(state): State) -> impl IntoResponse { return "internal error".into_response(); } + if let Err(error) = db::delete_expired_sessions(&state.db).await { + tracing::error!(%error, "cannot clean expired sessions"); + } + if let Err(error) = sqlx::query("INSERT INTO oauth_states(state) VALUES ($1)") .bind(&oauth_state) .execute(&state.db) diff --git a/src/db.rs b/src/db.rs index 98233b0..760e9b6 100644 --- a/src/db.rs +++ b/src/db.rs @@ -38,6 +38,7 @@ pub async fn athlete_for_session(db: &PgPool, token: &str) -> Result now() - interval '1 day' "#, ) .bind(&hash) @@ -89,6 +90,7 @@ pub async fn session_athlete(db: &PgPool, token: &str) -> Result now() - interval '1 day' "#, ) .bind(&hash) @@ -343,6 +345,23 @@ pub async fn mark_activity_processed( Ok(()) } +/// Remove sessions past their 1-day validity window. +/// +/// Expired sessions are already rejected by `session_athlete` / +/// `athlete_for_session`; this just keeps the table from growing forever. +pub async fn delete_expired_sessions(db: &PgPool) -> Result<()> { + sqlx::query( + r#" + DELETE FROM sessions + WHERE created_at <= now() - interval '1 day' + "#, + ) + .execute(db) + .await?; + + Ok(()) +} + pub async fn delete_session(db: &PgPool, token: &str) -> Result<()> { let hash = hash_token(token);