Commit graph

2 commits

Author SHA1 Message Date
BoulderBadgeDad
21dfbb39b0 Native login (increment 3/3): login screen, set-password, Settings toggle, logout
The UI that makes opt-in login usable. Off by default → your LAN setup is unchanged
(none of this appears unless security.require_login is on).

- Login screen overlay (reuses the launch-PIN styling): username + password →
  /api/auth/login → reload into the app. Shown when /api/profiles/current reports
  login_required (checked before profile selection).
- POST /api/profiles/<id>/set-password (admin, or self) to set/clear a login
  password, distinct from the PIN.
- Settings → Security: "Login password (admin account)" field + a "Require login"
  toggle (with the anti-lockout note). Wired into the existing settings load/save.
- Sign-out button in the profile bar, revealed only in login mode (login_mode flag
  on /api/profiles/current); soulsyncLogout() → /api/auth/logout → reload.

Tests: set-password sets/clears + verifies; /api/profiles/current signals
login_required. 20 login/password tests pass; 64 script-split integrity pass.

Remaining (small follow-up): a password field in the Manage Profiles edit form so
admins can set OTHER profiles' passwords from the UI (the endpoint already exists).
2026-06-10 22:10:33 -07:00
BoulderBadgeDad
92cbef90f9 Native login (increment 2/3): login/logout endpoints + require_login gate
The backend auth for opt-in username/password mode (security.require_login, default
off → zero change; the launch PIN + picker behave exactly as today).

- core/security/login_gate.py: pure gate (mirrors launch_lock) — when login mode is
  on, an unauthenticated session reaches only the page shell, /api/auth/login,
  /api/auth/logout, /api/profiles/current, /api/setup/status, and the key-authed
  /api/v1 API. Deliberately does NOT expose the profile list pre-auth (you type your
  name, not pick from a roster).
- _enforce_login before_request enforces it; _enforce_launch_pin no-ops when login
  mode is on (login replaces the shared PIN, per design).
- POST /api/auth/login (username = profile name, case-insensitive; brute-force
  limited per IP; generic error so names don't leak) + POST /api/auth/logout.
- Anti-lockout: the settings save refuses to turn ON login mode until the admin
  account has a password.

Tests: gate blocks→login→access→logout→blocked; case-insensitive username; wrong
password / passwordless profile / unknown user all 401 generically; login list not
exposed pre-auth; can't enable login without an admin password. 12 tests pass. Next:
the login screen + set-password UI + the toggle (increment 3).
2026-06-10 22:01:53 -07:00