Skip to content

feat(web): house-password login on the LAN - #915

Open
frahlg wants to merge 1 commit into
agent/lan-auth-seam-rebasedfrom
agent/lan-auth-ui-rebased
Open

feat(web): house-password login on the LAN#915
frahlg wants to merge 1 commit into
agent/lan-auth-seam-rebasedfrom
agent/lan-auth-ui-rebased

Conversation

@frahlg

@frahlg frahlg commented Aug 16, 2026

Copy link
Copy Markdown
Member

Summary

Same change as #913, restacked onto #914.

#913 still sits on the old #912 tip. This PR has the login/cookie/Settings work on top of the rebased LAN-auth seam.

  • POST /api/auth/login sets an HttpOnly ftw_lan cookie (12 h, SameSite=Strict, not Secure)
  • POST /api/auth/logout drops the session
  • A valid cookie is owner, same as Bearer. Bearer still wins if both are sent
  • Sessions live in process memory. A restart logs everyone out
  • Settings → System turns the lock on and off through /api/auth/password
  • A fetch wrapper opens a password modal on 401 valid LAN password required
  • The password is never written to localStorage

Live status, energy and prices stay visible without the password.

Stack

Sits on #914 (agent/lan-auth-seam-rebased) → master. Merge #914 first.

Replaces

#913.

Test plan

  • go test ./go/internal/api/
  • node --test web/lan-auth.test.mjs web/javascript-syntax.test.mjs
  • Default: no modal, Settings works
  • Enable from Settings → System with a ≥10 character password
  • After logout: opening Settings shows the password form
  • After login, Save and support dump work
  • curl with Bearer still works

A human should look at Settings → System and the login modal (CODEOWNERS).

Session cookie after POST /api/auth/login. Settings turns
api.lan_auth on and off. Live status stays visible until a
write needs the password.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e95b2e9ea3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +333 to +337
if (!r.ok) throw new Error(body.error || "enable failed");
if (pwEl) pwEl.value = "";
if (cfEl) cfEl.value = "";
setLanMsg("LAN password is on");
refreshLanAuth();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Synchronize the settings snapshot after toggling LAN auth

After either toggle succeeds, the settings shell's currentConfig.api.lan_auth still contains the value loaded when the modal opened. Because the global Save button later replaces the entire config via POST /api/config, enabling and then saving silently turns authentication back off; worse, disabling and then saving sends the stale true value after the password was deleted, re-enabling LAN auth with no usable password and locking non-loopback users out. Update the shared config snapshot in both success paths (or reload it) before allowing a normal settings save.

Useful? React with 👍 / 👎.

@miravoss26 miravoss26 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Companion frontend PR to #914. POST /api/auth/login sets an HttpOnly session cookie (12h, SameSite=Strict, no Secure since the LAN is plain HTTP), /api/auth/logout drops it, Settings → System toggles the password, and a fetch wrapper opens a login modal on the specific 401.

What checks out:

  • Session tokens are 32 bytes from crypto/rand, hex-encoded, in-memory only (restart logs everyone out, as documented).
  • Cookie flags are correct for the environment: HttpOnly + SameSite=Strict + no Secure, and there's a test that explicitly asserts Secure is never set.
  • Bearer wins over cookie when both are present (tested).
  • Password rotation and disable both call dropAllLANSessions(), so an old session can't outlive a password change.
  • CSRF is covered twice over: SameSite=Strict on the cookie, plus the existing Origin/Sec-Fetch-Site check in Authenticate().
  • The JS side only intercepts same-origin /api/ 401s carrying the exact "valid LAN password required" message, and there's a test confirming the password never touches localStorage/sessionStorage.

One thing I can't verify from here: no CI has run on this PR at all. gh pr checks 915 comes back empty and the commit status is pending with zero check-runs. The PR body says the author ran the Go and JS suites locally, but there's no CI confirmation on this exact head. It's stacked on #914's branch rather than master, which may be why.

Code read is solid, same quality as #914. I'd want to see CI actually run green before calling this a clean merge, and #914 needs to land first since this branches off it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants