Adds optional login protection for the web UI/API, intended for shared machines (e.g. an AI server).
Dual mode
No users configured → API and web UI are open, exactly as before.
≥1 user configured → every /api/* and /ws/* endpoint requires a valid session; the web UI shows a sign-in screen first.
Switches instantly when the first user is added / last user removed (no restart).
Security
bcrypt password hashing — stored as $2b$ hashes in /etc/nvcurve/users.json (mode 0600, root-owned). Plaintext is never persisted; login compares the plaintext against the hash.
24-hour sessions — HttpOnly cookie for browsers, Authorization: Bearer token for CLI/scripts. In-memory, invalidated on server restart.
Multi-user — multiple named accounts (no shared-password mode).
Brute-force lockout — 10 failed logins from an IP within 5 min → 15-min lockout.
Password is always prompted via getpass (never a CLI argument, so it never appears in the process list or sudo logs).
New CLI
sudo nvcurve user add alice # add a user (prompts for password)
nvcurve user list # list users
sudo nvcurve user set-password alice
sudo nvcurve user remove alice
New endpoints
GET /api/ping (public), GET /api/auth/status, POST /api/auth/login, POST /api/auth/logout, GET /api/auth/users.
Web UI
Sign-in screen when auth is enabled; status bar shows the signed-in user with a sign-out button; expired sessions (401) re-show the sign-in screen.
Testing
Verified with FastAPI TestClient: no-auth mode, auth-required mode, cookie + Bearer login, wrong-password 401, 24-h expiry, multi-user, logout, invalid-token 401, and the >72-byte-password edge (returns 401, not 500). Frontend builds cleanly (tsc -b + vite).
Notes
New dependency: bcrypt.
NvCurveClient.ping() now hits the public /api/ping so liveness checks work unauthenticated.
Existing HTTP API consumers will get 401 once a user is added (intended dual-mode behavior).
Added pyrightconfig.json pointing the LSP at the project .venv.
Adds optional login protection for the web UI/API, intended for shared machines (e.g. an AI server).
## Dual mode
- **No users configured** → API and web UI are open, exactly as before.
- **≥1 user configured** → every `/api/*` and `/ws/*` endpoint requires a valid session; the web UI shows a sign-in screen first.
Switches instantly when the first user is added / last user removed (no restart).
## Security
- **bcrypt** password hashing — stored as `$2b$` hashes in `/etc/nvcurve/users.json` (mode `0600`, root-owned). Plaintext is never persisted; login compares the plaintext against the hash.
- **24-hour sessions** — HttpOnly cookie for browsers, `Authorization: Bearer` token for CLI/scripts. In-memory, invalidated on server restart.
- **Multi-user** — multiple named accounts (no shared-password mode).
- **Brute-force lockout** — 10 failed logins from an IP within 5 min → 15-min lockout.
- Password is always **prompted** via `getpass` (never a CLI argument, so it never appears in the process list or sudo logs).
## New CLI
```bash
sudo nvcurve user add alice # add a user (prompts for password)
nvcurve user list # list users
sudo nvcurve user set-password alice
sudo nvcurve user remove alice
```
## New endpoints
`GET /api/ping` (public), `GET /api/auth/status`, `POST /api/auth/login`, `POST /api/auth/logout`, `GET /api/auth/users`.
## Web UI
Sign-in screen when auth is enabled; status bar shows the signed-in user with a sign-out button; expired sessions (401) re-show the sign-in screen.
## Testing
Verified with FastAPI `TestClient`: no-auth mode, auth-required mode, cookie + Bearer login, wrong-password 401, 24-h expiry, multi-user, logout, invalid-token 401, and the >72-byte-password edge (returns 401, not 500). Frontend builds cleanly (`tsc -b` + vite).
## Notes
- New dependency: `bcrypt`.
- `NvCurveClient.ping()` now hits the public `/api/ping` so liveness checks work unauthenticated.
- Existing HTTP API consumers will get 401 once a user is added (intended dual-mode behavior).
- Added `pyrightconfig.json` pointing the LSP at the project `.venv`.
Add optional login protection for the web UI/API, intended for shared
machines (e.g. AI servers). Dual mode: with no users configured the API
and web UI are open (as before); once at least one user exists, every
/api/* and /ws/* endpoint requires a valid session.
- bcrypt password hashing: passwords stored as $2b$ hashes in
/etc/nvcurve/users.json (0600, root-owned); plaintext never persisted.
- 24-hour sessions: HttpOnly cookie for browsers, Authorization: Bearer
token for CLI/scripts; in-memory, invalidated on server restart.
- Multi-user: multiple named accounts (no shared-password mode).
- New CLI: nvcurve user add|list|remove|set-password (root for mutating
ops; password always prompted, never a CLI argument).
- New endpoints: GET /api/ping (public), /api/auth/status|login|logout|users.
- Web UI: sign-in screen when auth is enabled; status bar shows the
signed-in user with sign-out; expired sessions (401) re-show sign-in.
- Brute-force lockout: 10 failed logins/IP within 5 min -> 15 min lockout.
- New dependency: bcrypt.
Also: LSP config (pyrightconfig.json) pointing at the project .venv, and
small error-handling cleanups in daemon.py/server.py.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds optional login protection for the web UI/API, intended for shared machines (e.g. an AI server).
Dual mode
/api/*and/ws/*endpoint requires a valid session; the web UI shows a sign-in screen first.Switches instantly when the first user is added / last user removed (no restart).
Security
$2b$hashes in/etc/nvcurve/users.json(mode0600, root-owned). Plaintext is never persisted; login compares the plaintext against the hash.Authorization: Bearertoken for CLI/scripts. In-memory, invalidated on server restart.getpass(never a CLI argument, so it never appears in the process list or sudo logs).New CLI
New endpoints
GET /api/ping(public),GET /api/auth/status,POST /api/auth/login,POST /api/auth/logout,GET /api/auth/users.Web UI
Sign-in screen when auth is enabled; status bar shows the signed-in user with a sign-out button; expired sessions (401) re-show the sign-in screen.
Testing
Verified with FastAPI
TestClient: no-auth mode, auth-required mode, cookie + Bearer login, wrong-password 401, 24-h expiry, multi-user, logout, invalid-token 401, and the >72-byte-password edge (returns 401, not 500). Frontend builds cleanly (tsc -b+ vite).Notes
bcrypt.NvCurveClient.ping()now hits the public/api/pingso liveness checks work unauthenticated.pyrightconfig.jsonpointing the LSP at the project.venv.Review
✅ No issues found — changes look consistent with the stated intent. Ready to be merged.