Commit Graph

2 Commits

Author SHA1 Message Date
chiguyong 67c0d67262 fix(auth,chat): P0 security fixes + stop-generation button + doc sync
U1: whoami cold-start security — add is_active check (disabled users
now get 401, not 200) and replace create_token_pair with create_access_token
to avoid minting a discarded refresh token (token-amplification risk).

U2: list_active_by_provider now filters expired sessions (expires_at > now)
matching its docstring promise; previously only checked revoked = 0.

U3: Fix asyncio.run() crash in test_revoke_other_user_session_returns_404
(converted to async). Add U1/U2 verification tests (disabled-user whoami,
no-refresh-leak, expired-session filtering, provider filtering) and
strengthen admin route tests (404 boundary, non-admin 403 on /admin/sessions).

U4: Update CLAUDE.md/AGENTS.md Request Flow — CostAwareRouter 3-layer
diagram replaced with actual RequestPreprocessor architecture (@board/@team
prefix intercepts then @skill: prefix then trivial-input regex then default
REACT). ExecutionMode list expanded to all 7 values.

U5: Frontend stop-generation button — ChatInput.vue shows a stop button
when isGenerating is true; chat store gains stopGeneration() that sends
{type:"cancel"} over WebSocket (backend portal.py already handles cancel).

Tests: 120 auth tests pass (unit + integration). ruff clean. vue-tsc clean.
2026-06-21 11:36:58 +08:00
chiguyong b418c3dc95 feat(auth): U3 SessionService + validation cache
Adds the central business-logic layer for ``auth_sessions`` so routes,
the auth middleware, and the admin endpoints can call a single service
instead of touching the table directly.

Server
- session_service.SessionService: CRUD + lifecycle for auth_sessions.
  - create() enforces the per-user cap (default 10): the oldest
    active session is evicted with reason=session_cap_eviction.
  - rotate() swaps a refresh token, adds the old hash to the
    denylist, and raises SessionReuseDetected (revoking all sessions
    for the user) when the old token is replayed.
  - revoke() / revoke_by_refresh_token() / revoke_all_for_user()
    with explicit reasons: user_terminated, admin_revoked,
    password_changed, reuse_detected, session_cap_eviction.
  - touch() bumps last_active_at (called on /auth/whoami).
- session_cache.SessionValidationCache: bounded LRU+TTL wrapper
  (default 30s/1k entries) around SessionService.is_session_valid.
  The middleware hits this on every request carrying a V2 sid claim;
  one SQLite round-trip per 30s per session instead of per request.
- get_session_service() / get_validation_cache() module-level
  singletons overridable in tests via set_session_service() /
  set_validation_cache().

Tests
- tests/unit/auth/test_session_service.py: 15 cases covering
  create/rotate/revoke/list/cap-eviction/reuse-detection/expired
  sessions.

Refs: U3 in docs/plans/2026-06-20-002-feat-centralized-auth-token-persistence-plan.md
2026-06-21 01:58:30 +08:00