Skip to content

feat: enhanced settings popup — password, token, log level, retention#347

Merged
Oaklight merged 1 commit into
masterfrom
worktree-feature+settings-popup
Jul 7, 2026
Merged

feat: enhanced settings popup — password, token, log level, retention#347
Oaklight merged 1 commit into
masterfrom
worktree-feature+settings-popup

Conversation

@Oaklight

Copy link
Copy Markdown
Owner

Summary

Expanded the Settings popup from 2 items (theme/language) to 7 operational controls, plus admin token management and password change.

New features

Feature UI Backend i18n
Admin password change 3 inputs (current/new/confirm) PUT /admin/api/config/password — rate-limited, hot-reloads
Admin token copy + auto-rotate Masked display, copy button, configurable countdown (5/15/30/60 min) POST /admin/api/token/rotate — new internal_token + recalculated admin_token
Log level 3-option select (Normal/Verbose/Debug) Extends PUT /admin/api/config/server, hot-reloads setup_logging()
Auto-refresh interval Select (1s–30s, off) Pure frontend, localStorage
Credential visibility Toggle checkbox Extends PUT /admin/api/config/server
Log retention Two number inputs (success/error caps) Extends PUT /admin/api/config/server, hot-reloads PersistenceManager caps
CLI set-password llm-rosetta-gateway set-password Direct config file edit, no current password (recovery) N/A

Backend changes

  • AuthState: added _recalculate_admin_token(), rotate_internal_token(), change_password() methods (refactored from inline HMAC)
  • _sync_auth_middleware(): now syncs admin password on config hot-reload
  • _reload_gateway_config(): hot-reloads log level + retention caps
  • PersistenceManager: added success_max/error_max setters
  • GET /admin/api/config: now includes debug section in response

Test plan

  • ruff check + ruff format + ty check all pass
  • 2062 tests pass
  • Playwright: settings popup renders all controls
  • Password change: login → change → logout → login with new
  • Token copy + countdown + auto-rotate
  • Log retention save + verify caps update
  • CLI: llm-rosetta-gateway set-password

@elena-oaklight

elena-oaklight Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Consolidated review — Elena, Milo, Clementine


🔴 Fix before merge

1. Timing-safe password comparison (auth.py)
change_password uses != for string comparison — timing side-channel. One-line fix:

if not hmac.compare_digest(current, auth_state.admin_password):

hmac is already imported.

2. Backend minimum password length
Frontend enforces < 4 chars, but neither the change_password route nor CLI set-password validate length server-side. A direct API call can set an arbitrarily short password. Add a guard in both:

if len(new_password) < 4:
    return {"error": "Password too short"}, 400

🟡 Recommended

3. Retention floor in PersistenceManager setters
max(50000, ...) / max(5000, ...) guard is only in put_server_settings. Other callers can set success_max / error_max to any value directly. Move the floor into the setters:

@success_max.setter
def success_max(self, value: int) -> None:
    self._success_max = max(50000, value)

4. Countdown font rendering
.settings-token-row sets font-family: var(--mono) and .countdown inherits it — "后轮换" renders in monospace. Fix: wrap ${mins}:${secs} in <span class="countdown-time"> and split the CSS:

.settings-token-row .countdown {
  font-family: var(--sans, system-ui, sans-serif);
}
.settings-token-row .countdown .countdown-time {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

🟢 Low priority

5. Inline style cleanup — token row and rotate select have inline style="display:flex;..." that could be lifted into classes. Fine to defer.


✅ Previously raised (Jun 29), now resolved

Item Status
request.json() async consistency ✅ Confirmed sync (httpserver, not aiohttp)
rotate_token persistence — ephemeral by design ✅ Documented in docstring
Backend retention floor at API boundary max() guard added (50 000 / 5 000)

✅ What's solid

  • AuthState refactor — _recalculate_admin_token() as single HMAC source of truth
  • Rate-limit reuse on change_password
  • _sync_auth_middleware syncing admin password on hot-reload
  • CLI set-password with getpass, no current-password requirement (correct for recovery)
  • Full bilingual i18n (en/zh)
  • 2062 tests pass, CI green

@milo-oaklight milo-oaklight Bot deleted a comment from elena-oaklight Bot Jul 7, 2026
@milo-oaklight milo-oaklight Bot deleted a comment from elena-oaklight Bot Jul 7, 2026
@milo-oaklight milo-oaklight Bot deleted a comment from elena-oaklight Bot Jul 7, 2026
milo-oaklight Bot added a commit that referenced this pull request Jul 7, 2026
Replace == / != with hmac.compare_digest in:
- admin_login: password verification
- change_password: current password verification
- check_admin_auth: admin token verification

Prevents timing side-channel attacks on auth credentials.

Follow-up to review on #347.
Settings popup expanded from 2 to 7 operational controls:
- Admin password change (current password required, rate-limited)
- Admin token copy + force-rotate + auto-rotate countdown
  (configurable 5/15/30/60 min, monospace digits with CJK text)
- Log level selector (Normal / Verbose / Debug with bodies)
- Auto-refresh interval (1s-30s or off, localStorage)
- Credential visibility toggle
- Log retention caps (success min 50k, error min 5k)

Backend:
- AuthState: _recalculate_admin_token(), rotate_internal_token(),
  change_password() with timing-safe comparisons
- PUT /admin/api/config/password — rate-limited password change
- POST /admin/api/token/rotate — ephemeral token rotation
- PUT /admin/api/config/server — extended for credential_visible,
  request_log caps, verbose, log_bodies with backend floor guards
- _sync_auth_middleware: syncs admin password on hot-reload
- _reload_gateway_config: hot-reloads log level + retention caps
- PersistenceManager: success_max/error_max setters

CLI:
- llm-rosetta-gateway set-password — forgot-password recovery
  (no current password, interactive getpass, min 4 chars)

Full bilingual i18n (en/zh) for all new strings.
@Oaklight Oaklight force-pushed the worktree-feature+settings-popup branch from bdf3979 to 6bd2f31 Compare July 7, 2026 23:25
@Oaklight Oaklight merged commit 0c452a5 into master Jul 7, 2026
4 checks passed
@Oaklight Oaklight deleted the worktree-feature+settings-popup branch July 7, 2026 23:31
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.

1 participant