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.
This commit is contained in:
Claude 2026-08-13 02:10:29 +00:00 committed by Jonas Rabenstein
commit 1a0ee71e6b
2 changed files with 23 additions and 0 deletions

View file

@ -35,6 +35,10 @@ pub async fn start(State(state): State<AppState>) -> 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)

View file

@ -38,6 +38,7 @@ pub async fn athlete_for_session(db: &PgPool, token: &str) -> Result<Option<(i64
FROM sessions s
JOIN athletes a ON a.id = s.athlete_id
WHERE s.token_hash = $1
AND s.created_at > now() - interval '1 day'
"#,
)
.bind(&hash)
@ -89,6 +90,7 @@ pub async fn session_athlete(db: &PgPool, token: &str) -> Result<Option<SessionA
JOIN athletes a
ON a.id = s.athlete_id
WHERE s.token_hash = $1
AND s.created_at > 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);