Files

42 lines
2.2 KiB
Markdown
Raw Permalink Normal View History

# Admin username change (2026-09-30)
Goal: get rid of the well-known `admin` login and of the built-in `admin/password` account.
## Design
- The JWT carries `user_id`, not the name, and no other table references `users.username`, so a rename does not invalidate sessions.
- Changing the username requires the current password and, when 2FA is enabled, a valid OTP. Wrong password/OTP counts toward the login rate limit.
## Changes
| Area | Change |
|---|---|
| API (`APP_CORE/openvpn_api_v3.py`) | `POST /api/auth/change-username`: body `new_username`, `current_password`, optional `otp`. Rules: `^[A-Za-z][A-Za-z0-9_.-]{2,31}$`, reserved names rejected (`admin`, `administrator`, `root`, `user`, `test`, `guest`), case-insensitive uniqueness (409). Helper `_current_user_id()` |
| 2FA | `setup_2fa` puts the real username into the authenticator URI (was hardcoded `admin`) |
| Bootstrap | `ensure_default_admin` no longer creates `admin/password`. With an empty `users` table it creates a user only from `OVPMON_INITIAL_ADMIN_USER` / `OVPMON_INITIAL_ADMIN_PASSWORD`; otherwise it logs an error |
| UI (`Account.vue`) | "Change Username" button and modal (OTP field shown only if 2FA is on) |
| UI (`App.vue`) | Header name synced from `/user/me` on start and on route change, and on the `ovpmon-user-changed` event; fixed the stale/hardcoded `Admin` |
## Existing installations
Rename directly in the DB (stop nothing; sessions stay valid):
```python
import sqlite3
c = sqlite3.connect("/var/lib/ovpmon/openvpn_monitor.db")
c.execute("UPDATE users SET username=? WHERE username='admin'", ("<new-login>",)); c.commit()
```
Take a DB backup first. Recovery when `users` is empty: temporarily set `OVPMON_INITIAL_ADMIN_USER/PASSWORD`, restart `ovpmon-api`, then remove the variables.
## Verification
| Check | Result |
|---|---|
| Login with new name / with `admin` | 200 / 401 |
| No token | 401 |
| `admin`, `root`, `ab`, `a/b`, `1abc` | 400 |
| Wrong current password | 401 |
| Rename to another valid name and back | 200, login with the new name works |
| Empty `users` without / with seed variables (DB copy) | no user / user created |
| Manual UI test (password change, 2FA enable) | passed; header-name bug found and fixed |