Server-side session TTL enforcement

- session_exists() now rejects rows older than 30 days,
  matching the client cookie max-age.
- Opportunistic cleanup of expired rows on session_exists()
  calls, preventing unbounded growth of sessions.db from
  orphaned tokens (PWA reinstalls, manual cookie clears).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 23:28:39 +00:00
parent 5b4a299414
commit 6c2af55e7e
+7 -3
View File
@@ -4,7 +4,7 @@ import sqlite3
import subprocess import subprocess
import hashlib import hashlib
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime, timedelta
from dotenv import load_dotenv from dotenv import load_dotenv
from sentence_transformers import SentenceTransformer from sentence_transformers import SentenceTransformer
import anthropic import anthropic
@@ -132,6 +132,7 @@ When making factual claims about Aaron — his history, credentials, locations,
# Auth configuration # Auth configuration
import os import os
SESSION_PASSWORD = os.getenv("AARON_AI_PASSWORD", "changeme") SESSION_PASSWORD = os.getenv("AARON_AI_PASSWORD", "changeme")
SESSION_MAX_AGE_SECONDS = 60 * 60 * 24 * 30
SESSIONS_DB = str(Path.home() / "aaronai" / "sessions.db") SESSIONS_DB = str(Path.home() / "aaronai" / "sessions.db")
def _init_sessions(): def _init_sessions():
@@ -163,7 +164,10 @@ def delete_session(token: str):
def session_exists(token: str) -> bool: def session_exists(token: str) -> bool:
conn = _connect_sessions() conn = _connect_sessions()
row = conn.execute("SELECT 1 FROM sessions WHERE token = ?", (token,)).fetchone() cutoff = (datetime.now() - timedelta(seconds=SESSION_MAX_AGE_SECONDS)).isoformat()
conn.execute("DELETE FROM sessions WHERE created_at < ?", (cutoff,))
conn.commit()
row = conn.execute("SELECT 1 FROM sessions WHERE token = ? AND created_at >= ?", (token, cutoff)).fetchone()
conn.close() conn.close()
return row is not None return row is not None
@@ -381,7 +385,7 @@ async def login(request: Request, response: Response):
httponly=True, httponly=True,
secure=True, secure=True,
samesite="lax", samesite="lax",
max_age=60 * 60 * 24 * 30 max_age=SESSION_MAX_AGE_SECONDS
) )
response.body = b'{"ok": true}' response.body = b'{"ok": true}'
response.status_code = 200 response.status_code = 200