Some checks are pending
Build / Calculate version (push) Waiting to run
Build / Build binary (push) Blocked by required conditions
Build / Build Darwin binaries (push) Blocked by required conditions
Build / Build Windows binaries (push) Blocked by required conditions
Build / Build Android (push) Blocked by required conditions
Build / Publish Android (push) Blocked by required conditions
Build / Build Apple clients (push) Blocked by required conditions
Build / Upload builds (push) Blocked by required conditions
- New UserManager service with HTTPS auth, credential sync, traffic tracking, and kick API - Integrates into all 10 protocol inbounds (hysteria2, tuic, vless, vmess, trojan, shadowsocks, http, socks, mixed, naive) - Each inbound auto-detects user_manager from service context, falls back to static config - Auth server contract: POST /api/auth, GET /api/credentials, POST /api/traffic
3.7 KiB
3.7 KiB
Upstream Changes
UserManager — External Authentication & Traffic Tracking
A new user_manager service that turns sing-box into a universal proxy server for external auth servers.
New files
adapter/user_manager.go—UserManagerinterface:Authenticate,GetCredentials,ReportTraffic,GetTraffic,ListTraffic,KickUseroption/user_manager.go—UserManagerOptions:auth_server,cache_ttl,refresh_interval,report_interval,report_traffic,api_secret,api_listen,timeoutservice/usermanager/manager.go— full implementation:- On-demand HTTPS auth (
POST /api/auth) with in-memory TTL cache - Periodic credential sync (
GET /api/credentials) populates per-protocol user lists - Per-user traffic counters (
atomic.Int64) reported viaPOST /api/traffic ConnectionTrackerimpl wrapping conns with byte counters (RoutedConnection/RoutedPacketConnection)- HTTP API on configurable
api_listen:GET /traffic— all users trafficGET /traffic/{user}— single userPOST /kick/{user}— evict user from auth cache
- Bearer token auth on all API endpoints via
api_secret
- On-demand HTTPS auth (
service/usermanager/registry.go— service registrationinclude/usermanager.go— include build hookconstant/proxy.go—TypeUserManagerconstant
Modified files — Protocol inbound integration
All 10 protocol inbounds detect the global user_manager from service context and use it when present:
| Protocol | Type | Approach |
|---|---|---|
| hysteria2 | Service-based | service.UpdateUsers with password credentials, 30s refresh loop |
| tuic | Service-based | service.UpdateUsers with UUID+password (format "uuid:password"), 30s refresh loop |
| vless | Service-based | service.UpdateUsers with UUID credentials, 30s refresh loop |
| vmess | Service-based | service.UpdateUsers with UUID credentials, 30s refresh loop |
| trojan | Service-based | service.UpdateUsers with password credentials, 30s refresh loop |
| shadowsocks (multi) | Service-based | service.UpdateUsersWithPasswords with password credentials, 30s refresh loop |
| http | Authenticator-based | *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop |
| socks | Authenticator-based | *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop |
| mixed | Authenticator-based | *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop |
| naive | Authenticator-based | *auth.Authenticator rebuilt from GetCredentials, 30s refresh loop; skips "missing users" check when user_manager is configured |
Each inbound falls back to its original static config when no user_manager service is registered.
Credential format per protocol
| Protocol | UserInfo.Credential format |
|---|---|
| hysteria2 | password |
| tuic | uuid:password |
| vless | uuid |
| vmess | uuid |
| trojan | password |
| shadowsocks | password (method from static config) |
| http | password (username from UserInfo.Username) |
| socks | password (username from UserInfo.Username) |
| mixed | password (username from UserInfo.Username) |
| naive | password (username from UserInfo.Username) |
Auth server API contract
The auth server (auth_server) must implement:
POST /api/auth— body{"protocol":"...", "credential":"...", "addr":"..."}, returns{"ok":true, "id":"username"}GET /api/credentials— returns{"credentials":[{"protocol":"...", "credential":"...", "username":"..."}]}POST /api/traffic(optional, whenreport_traffic=true) — body{"traffic":{"user1":{"tx":123,"rx":456}}}