3x-ui/web/service
GenSpark AI Developer 6a5cac385d feat(socks): guard client-lifecycle paths against account-based inbounds
Account-based inbounds (Socks/Mixed/HTTP) keep their credentials in
`settings.accounts[]` — an array of plain {user, pass} objects — while
every other inbound (vless/vmess/trojan/shadowsocks/hysteria/…) keeps
them in `settings.clients[]`, the rich Client struct with id, email,
sub-id, totalGB, expiry, traffic-reset cadence, etc.

The whole client lifecycle on InboundService (AddInboundClient,
UpdateInboundClient, DelInboundClient, CopyInboundClients) was written
against the latter shape, and several of those methods do an unchecked
`settings["clients"].([]any)` cast on the way in. If anything ever
managed to call them against a SOCKS5 inbound the panel would panic
straight out of the goroutine.

In practice the UI itself can't get there — `dbinbound.isMultiUser()`
returns false for SOCKS, which already gates the ClientRowTable,
"add client" menu, copy-clients menu, etc. — but the HTTP API is
addressable directly, the Telegram bot path is independent, and a
future feature could easily plug into one of those entry points and
hit the cast. Defense in depth is cheap here.

Backend
-------
* Add `model.IsAccountBased(p Protocol) bool` covering Socks, Mixed
  and HTTP. WireGuard is *not* in the set — its peers live under
  `settings.peers[]` and are managed through a separate code path
  that already knows about them.

* AddInboundClient / UpdateInboundClient / DelInboundClient now load
  the target inbound up front and bail out with a clear, actionable
  error when the protocol is account-based, instead of falling into
  the unchecked clients cast. The error message points the caller at
  the right escape hatch ("update the inbound directly with
  settings.accounts[] instead").

* CopyInboundClients refuses account-based inbounds on either side
  of the copy — neither direction has well-defined semantics
  (downcasting a rich client to {user, pass} silently drops
  sub-id/totalGB/expiry; upcasting the other way invents fields the
  runtime can't honor).

Tests
-----
* TestIsAccountBased pins the protocol set, including the explicit
  WireGuard-excluded and lowercase-invariant cases.

* TestAddInboundClient_RejectsSocks, TestUpdateInboundClient_RejectsSocks,
  TestDelInboundClient_RejectsSocks: the three guards must fire on a
  SOCKS inbound seeded with a realistic settings.accounts[] payload.

* TestCopyInboundClients_RejectsSocksSource and ...Target: both
  directions are refused.

* TestAddInboundClient_AllowsVless: sanity check that the guard does
  not fire on a client-based protocol — if this ever flipped the
  feature would be broken for everyone, not just SOCKS users.

Other scenarios reviewed (no code changes needed):
* Routing rules — keyed off inbound tag, protocol-agnostic.
* Balancers — outbound-tag based, untouched by inbound protocol.
* Outbound side — frontend already exposes SOCKS as an outbound
  with user/pass through the existing OutboundFormModal.
* Depletion / traffic reset / disable-invalid-clients — driven by
  SQL queries on the client_traffics table, which is naturally empty
  for account-based inbounds (they never create rows there).
* SetInboundEnable — operates on the inbound table directly, no
  per-client surgery, safe for SOCKS.
* Sub-link generators (sub/subService, subJsonService, subClashService)
  — already return empty for SOCKS/Mixed/HTTP/Tunnel/WireGuard.
* Frontend client modals (ClientFormModal, ClientRowTable,
  ClientBulkModal, CopyClientsModal) — gated upstream by
  `dbInbound.isMultiUser()`, which is false for SOCKS.
2026-05-25 15:55:34 +00:00
..
api_token.go feat(api-tokens): manage multiple named tokens; add tab/section anchor URLs 2026-05-13 16:34:31 +02:00
config.json feat(inbounds): align tunnel, tun, and hysteria UI with Xray docs 2026-05-13 22:44:08 +02:00
custom_geo.go fix(security): SSRF-guard node and remote HTTP clients 2026-05-13 13:33:53 +02:00
custom_geo_test.go v3 2026-05-10 02:13:42 +02:00
inbound.go feat(socks): guard client-lifecycle paths against account-based inbounds 2026-05-25 15:55:34 +00:00
inbound_socks_guards_test.go feat(socks): guard client-lifecycle paths against account-based inbounds 2026-05-25 15:55:34 +00:00
metric_history.go feat(panel): xray metrics dashboard with observatory probe history 2026-05-12 02:17:45 +02:00
node.go fix(security): SSRF-guard node and remote HTTP clients 2026-05-13 13:33:53 +02:00
nord.go feat(xray/nord): searchable server list + colored load tag, surface API errors 2026-05-11 10:06:01 +02:00
outbound.go fix(outbound): probe UDP-based outbounds over UDP instead of TCP 2026-05-15 12:29:53 +02:00
panel.go Security hardening: sessions, SSRF, CSP nonce, CSRF logout, trusted proxies (#4275) 2026-05-13 12:52:52 +02:00
panel_other.go feat: add panel update functionality via web GUI (#4117) 2026-04-28 18:46:55 +02:00
panel_test.go feat: add panel update functionality via web GUI (#4117) 2026-04-28 18:46:55 +02:00
panel_unix.go feat: add panel update functionality via web GUI (#4117) 2026-04-28 18:46:55 +02:00
port_conflict.go feat(socks): complete backend integration for SOCKS5 inbound 2026-05-25 15:05:20 +00:00
port_conflict_test.go feat(socks): complete backend integration for SOCKS5 inbound 2026-05-25 15:05:20 +00:00
server.go Security hardening: sessions, SSRF, CSP nonce, CSRF logout, trusted proxies (#4275) 2026-05-13 12:52:52 +02:00
server_vlessenc_test.go Feat: clarify VLESS encryption auth selection (#4271) 2026-05-12 11:39:28 +02:00
setting.go Add possibility to remove client email from sub (#4297) 2026-05-13 19:04:17 +02:00
setting_security_test.go feat(api-tokens): manage multiple named tokens; add tab/section anchor URLs 2026-05-13 16:34:31 +02:00
tgbot.go feat(socks): complete backend integration for SOCKS5 inbound 2026-05-25 15:05:20 +00:00
tgbot_test.go Implement CSRF protection and security hardening across the application (#4179) 2026-05-07 23:36:11 +02:00
traffic_writer.go Fix: traffic writer restart freeze (#4265) 2026-05-12 11:36:05 +02:00
traffic_writer_test.go Fix: traffic writer restart freeze (#4265) 2026-05-12 11:36:05 +02:00
url_safety.go Security hardening: sessions, SSRF, CSP nonce, CSRF logout, trusted proxies (#4275) 2026-05-13 12:52:52 +02:00
user.go fix(auth): invalidate sessions when 2FA is enabled, fix dev 401 loop 2026-05-13 14:08:16 +02:00
warp.go fix(warp): set license against Cloudflare API and surface errors inline 2026-05-13 21:13:16 +02:00
websocket.go v3 2026-05-10 02:13:42 +02:00
xray.go fix(nodes): bind form-encoded posts and skip node inbounds in central xray 2026-05-10 11:32:06 +02:00
xray_metrics.go Security hardening: sessions, SSRF, CSP nonce, CSRF logout, trusted proxies (#4275) 2026-05-13 12:52:52 +02:00
xray_setting.go v3 2026-05-10 02:13:42 +02:00
xray_setting_test.go xray-setting: pin api routing rule to index 0 on save (#4124) 2026-04-28 17:49:39 +02:00