Add session management: see who's signed in, revoke a session

No visibility existed into who was currently signed in or a way to
force a device out. Sessions already live as files via
session-file-store, so this reads that store directly rather than
adding a new DB table: new Settings-adjacent "Sessions" page
(admin-only, alongside Users) lists every live session with the
user's name/email/resolved role, IP, a friendly "Browser on OS"
summary parsed from the user-agent, last-active time, and expiry, with
a Revoke button per row (extra confirmation if you revoke your own
current session, since that signs you out immediately).

IP and user-agent are now captured into the session at login
(auth/router.ts) since express-session doesn't track them itself.
session-file-store's own Store type doesn't declare its list()
method, so sessionStore.ts adds a narrow local interface for it rather
than losing type safety on the rest of the store.

Verified against a real session directory seeded through the actual
session-file-store APIs (not hand-written JSON): confirmed correct
field resolution including a session whose user row was later deleted
(role resolves to null instead of crashing), correctly excluded a
mid-OIDC-login session with no completed user yet, correctly excluded
an already-expired session, and confirmed revoke actually deletes the
right session file and only that one. Confirmed the real dev
database's mtime was untouched throughout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
bobbanandClaude Sonnet 5 committed 2026-09-21 20:29:29 +02:00
1 parent 1cae35a59e
commit 6d673db9ec
9 files changed
+318 -1

No files matched your search

+2
View File
@@ -14,6 +14,7 @@ import {
IconServerCog,
IconDatabase,
IconUsers,
IconDevices,
IconHistory,
IconStethoscope,
IconSettings,
@@ -46,6 +47,7 @@ const NAV_ITEMS: NavItem[] = [
{ to: "/gitea", label: "Gitea", icon: <IconBrandGit size={20} /> },
{ to: "/integrations", label: "Integrations", icon: <IconPlugConnected size={20} /> },
{ to: "/users", label: "Users", icon: <IconUsers size={20} />, minRole: "admin" },
{ to: "/sessions", label: "Sessions", icon: <IconDevices size={20} />, minRole: "admin" },
{ to: "/audit-log", label: "Audit Log", icon: <IconHistory size={20} />, minRole: "operator" },
{ to: "/diag-log", label: "Diagnostic Log", icon: <IconStethoscope size={20} />, minRole: "admin" },
{ to: "/settings", label: "Settings", icon: <IconSettings size={20} />, minRole: "admin" },