Panel duplicate client entries across inbounds made the first-unseen
matcher serve wrong links (e.g. Moscow Direct got :46457 instead of
:37744), nondeterministically per cache rebuild. Match candidates by
inbound port from servers.conf, falling back to legacy behavior when
no port matches.
- add api_token field handling for NL (new panel uses Bearer token, not cookie)
- modern clients API: POST /panel/api/clients/add and bulkDel via token
- fetch sub_ids via token, support find/traffic via token
- fixes create/delete for NL where py3xui login fails due to CSRF
- add _build_hysteria_link: rebuild bare panel hy2 links into
hysteria2://sub_id:auth@host:port?obfs=salamander&obfs-password=..\&sni=..
using per-server hy2 block in servers.conf (gitignored)
- add _sync_hysteria_users hook: push panel hy2 clients to the
standalone server config on create/delete (cron backstop every 2 min)
- match subscription links by protocol instead of index (fixes trojan/mixed inbounds, e.g. Poland)
- support hysteria panels in create/delete client, skip in shortid rotation
- fix link regex to match hysteria2:// scheme
- reduce links cache TTL from 7 days to 1 hour (stale cache hid servers)
- delete client: fallback to id when uuid missing
- feat(web): telegram contact button on home page
- Server health ping every 30s — dead servers excluded from all API calls, auto-recovered when back online
- Fixed py3xui client.delete() argument order (inbound_id first, client_uuid second)
- Rate limiting on /admin/login (max 10 attempts per 60s per IP)
- XSS prevention: HTML-escape all user-controlled fields in templates
- CSP headers on all HTML pages (CSP, X-Frame-Options, X-Content-Type-Options)
- CORS restricted to configured host instead of wildcard
- Secure + SameSite=Lax cookie flags for admin_token
- Bind to 127.0.0.1 instead of 0.0.0.0
- Async locks for global state (last_donation_id)
- Graceful shutdown: all background tasks cancelled on exit
- DA polling exponential backoff: 1s→max 1h, immediate 1h on 401