Skip to content

Furnic/usernames#13

Open
nfurfaro wants to merge 8 commits into
mainfrom
furnic/usernames
Open

Furnic/usernames#13
nfurfaro wants to merge 8 commits into
mainfrom
furnic/usernames

Conversation

@nfurfaro

@nfurfaro nfurfaro commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an Account panel to the web UI so users can view and edit their username and sync password at any time — not just on first launch.

Note: The remote sync server must be redeployed with the updated spec-forest-sync crate for this to work. The ChangePassword wire message is new and will be
rejected by older server builds.

  • New Account button (user icon) in the gallery header opens a modal with:
    • Username — view and edit (persisted to DB, used for branch naming and attribution)
    • Sync status — green/red indicator when a sync server is configured
    • Change password — only shown when connected to a sync server; requires current password, enforces 8-char minimum, confirms new password
  • Full-stack ChangePassword flow: frontend → REST endpoint → WebSocket protocol → sync server
  • Security: brute-force protection (account lockout on repeated failures) and minimum password length validation on both server and client

What changed

ChangePassword and PasswordChanged wire messages added to the protocol. The sync server handles password changes with verification, argon2 hashing, account lockout on repeated failures, and fresh token issuance. The client-side SyncHandle gets a change_password() method with PasswordChanged handling in the receive loop. A new POST /api/sync/change-password REST endpoint bridges the frontend to the sync protocol. On the frontend, a new AccountPanel component provides username editing, sync status display, and password management, wired into the gallery header via App.tsx and SpecGallery.tsx.

Closes #6

@freesig freesig left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Passwords sent in plaintext over WebSocket

ClientMessage::ChangePassword sends current_password and new_password as plaintext strings over the wire. These should ideally be hashed client-side before transmission so that raw passwords never travel over the WebSocket connection — even with TLS, defense-in-depth matters (logging, memory dumps, intermediary proxies, etc.).

@freesig

freesig commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

When changing the user name it looks like it's just changed locally and not on the sync server?

}
ServerMessage::PasswordChanged => {
// Acknowledgment only — the subsequent AuthToken resolves the pending auth oneshot
None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If the sync server crashes or the connection drops between sending PasswordChanged and the subsequent AuthToken, the auth oneshot in change_password() will hang indefinitely (or until the WebSocket close is detected and tears things down).

Since PasswordChanged is purely informational and nothing reads it, consider either:

  1. Removing the PasswordChanged message entirely and just relying on the AuthToken response to signal success, or
  2. Having PasswordChanged itself resolve the pending auth oneshot (and treat AuthToken as a bonus refresh), so the client isn't dependent on two messages arriving in sequence.

pub db_path: String,
pub sync_url: Option<String>,
pub log_prompts: Option<String>,
pub user_name: Option<String>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This field is always set to None in both main.rs files — there's no CLI flag wired up to populate it, so the priority logic added below (config.user_name > DB setting) is dead code from the user's perspective.

I'd suggest removing user_name from ServerConfig entirely for now rather than shipping an unused field. The DB-based persistence already works, and the username is editable via the new Account panel. If we need a CLI override later we can add it then with the actual --user-name flag.

@freesig

freesig commented Apr 6, 2026

Copy link
Copy Markdown
Collaborator

Might be worth adding an integration test for this workflow

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.

Need to be able to see and edit username and password in the web UI

2 participants