- auth: impersonate stores empty data instead of raw cookie; unimpersonate
issues a fresh session rather than replaying a stored token
- api/index.php: restore rate limiting (10 req/min auth, 120 general)
- nova.js: 401 redirects to login instead of silently returning error;
escHtml now escapes single quotes to prevent onclick XSS
- accounts: wrap ownership-change 4-write path in beginTransaction/commit;
restore audit body on account.update
- reseller/user login cards: use $_pname instead of hardcoded 'NovaCPX'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Enforce portal role isolation: admin/reseller/user can only auth on their own port
- Admin/reseller impersonation: Login As with cookie handoff + Return banner in user panel
- Account ownership: admin can reassign accounts to resellers, DNS NS follows
- accounts/update: ownership change cascades package + NS to new owner
- users.php endpoint: admin list/filter by role (reseller dropdown)
- Docker launch fix: uDockerUpdateParams defined before call
- Nova.loading() spinners: login, SSL, PHP switch/save, backup create, docker launch/actions
- Logo consistency: gradient CPX text on all login pages, novacpx_logo_html() in all sidebars
- BackupManager: fix DB class name, table name, column name
- DNSManager: fix settings keys (ns1_hostname/ns2_hostname)
- docker.php: resolve account_id from user uid for all actions
- Auth: impersonate sets cookie + stores return_token for seamless round-trip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#26 Mobile responsive:
- Hamburger button (SVG) in topbar for all three panels (admin/user/reseller)
- Sidebar overlay div for click-outside-to-close on mobile
- nova.js: DOMContentLoaded toggle handler with overlay and auto-close on nav click
- nova.css: sidebar-overlay, page-header, panel/panel-header, table, btn-success/warning/danger/secondary/xs,
badge-muted; mobile media query shows toggle, fixes stats-grid/modal/panel-header layout
#27 Custom error pages:
- /errors/404.php and /errors/500.php with NovaCPX dark theme matching panel design
- Apache ErrorDocument 400/401/403/404/500/503 for ports 8880/8881/8882 with Alias /errors
#28 API rate limiting:
- api_rate_limits table (migration 004) with per-IP per-bucket counters
- api/index.php: 10 req/min for auth endpoint, 120 req/min for all others
- Returns X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset headers
- Returns 429 Too Many Requests when exceeded; rate limit failure is non-fatal
#29 Session Manager:
- sessions.php endpoint: list/revoke/revoke-user/revoke-all
- Admin panel Sessions page: table of active sessions with user, role, IP, browser, timestamps
- Revoke single session, revoke all for user, revoke all sessions (self-evicts)
- New firewall.php endpoint: status, enable/disable, add-rule (full UFW
syntax: action/direction/port/proto/from/to/comment), delete-rule by
number, quick allow-port/deny-port, allow-ip/block-ip with DB storage,
ip-lists, reset to defaults, default-policy, set-logging, f2b-status
(all jails with banned counts), f2b-jail detail, f2b-ban, f2b-unban
(single jail or all), f2b-reload, f2b-restart, raw ufw command (whitelisted)
- admin.js: full firewall page — UFW status badge + enable/disable toggle,
default policy dropdowns, numbered rules table with delete, quick rule
inline form, full add-rule modal, trusted IP chip list, blocked IP chip
list, Fail2Ban jails table with banned counts, per-jail banned IP modal
with individual unban buttons, manual ban modal, logging level control
- nova.js: add Nova.escHtml() used across all new pages
- admin.js: remove git_remote field from admin settings panel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>