mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-06 05:05:01 +03:00
fix(clients): reject dot names and recover legacy clients (#7062)
Reject reserved dot-segment client names and recover legacy records through query aliases. Preserve token scopes and path identity precedence, and update the generated API reference.
This commit is contained in:
committed by
GitHub
parent
2541080c91
commit
cd176faf4e
@@ -28,6 +28,10 @@ _openapi:
|
||||
title: Fetch one client by email, including the inbound IDs and external config
|
||||
IDs it is attached to.
|
||||
url: '#fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to'
|
||||
- depth: 2
|
||||
title: Fetch one client by email, including the inbound IDs and external config
|
||||
IDs it is attached to.
|
||||
url: '#fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to-1'
|
||||
- depth: 2
|
||||
title: Fetch clients by subscription ID.
|
||||
url: '#fetch-clients-by-subscription-id'
|
||||
@@ -48,10 +52,19 @@ _openapi:
|
||||
inbound. Body is the JSON client payload — supply the full set of fields
|
||||
you want to keep (the server replaces the row, it does not patch).
|
||||
url: '#update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch'
|
||||
- depth: 2
|
||||
title: Update an existing client by email. Changes propagate to every attached
|
||||
inbound. Body is the JSON client payload — supply the full set of fields
|
||||
you want to keep (the server replaces the row, it does not patch).
|
||||
url: '#update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch-1'
|
||||
- depth: 2
|
||||
title: Delete a client by email. Removes it from every attached inbound and
|
||||
drops its traffic record unless keepTraffic=1 is passed.
|
||||
url: '#delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed'
|
||||
- depth: 2
|
||||
title: Delete a client by email. Removes it from every attached inbound and
|
||||
drops its traffic record unless keepTraffic=1 is passed.
|
||||
url: '#delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed-1'
|
||||
- depth: 2
|
||||
title: Attach an existing client to one or more additional inbounds. Body is
|
||||
JSON.
|
||||
@@ -324,6 +337,9 @@ _openapi:
|
||||
- content: Fetch one client by email, including the inbound IDs and external
|
||||
config IDs it is attached to.
|
||||
id: fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to
|
||||
- content: Fetch one client by email, including the inbound IDs and external
|
||||
config IDs it is attached to.
|
||||
id: fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to-1
|
||||
- content: Fetch clients by subscription ID.
|
||||
id: fetch-clients-by-subscription-id
|
||||
- content: Fetch clients by Telegram user ID. Returns an array since multiple
|
||||
@@ -340,9 +356,17 @@ _openapi:
|
||||
fields you want to keep (the server replaces the row, it does not
|
||||
patch).
|
||||
id: update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
|
||||
- content: Update an existing client by email. Changes propagate to every attached
|
||||
inbound. Body is the JSON client payload — supply the full set of
|
||||
fields you want to keep (the server replaces the row, it does not
|
||||
patch).
|
||||
id: update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch-1
|
||||
- content: Delete a client by email. Removes it from every attached inbound and
|
||||
drops its traffic record unless keepTraffic=1 is passed.
|
||||
id: delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
|
||||
- content: Delete a client by email. Removes it from every attached inbound and
|
||||
drops its traffic record unless keepTraffic=1 is passed.
|
||||
id: delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed-1
|
||||
- content: Attach an existing client to one or more additional inbounds. Body is
|
||||
JSON.
|
||||
id: attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
|
||||
@@ -564,6 +588,9 @@ _openapi:
|
||||
tunnel) contribute nothing.'
|
||||
id: return-every-url-for-one-client-across-all-attached-inbounds-one-per-advertised-endpoint-the-managed-hosts-of-the-inbound-else-its-streamsettingsexternalproxy-entries-else-its-own-address-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-mtproto-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing
|
||||
contents:
|
||||
- content: Query-parameter alias for the path endpoint. Use email=. or email=.. to
|
||||
manage legacy reserved names without URL dot-segment normalization.
|
||||
heading: fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to-1
|
||||
- content: Matches the exact subscription ID and orders results by client ID.
|
||||
Returns an array of the same payloads as GET /clients/get/:email,
|
||||
since multiple clients can share a subscription ID. Includes disabled,
|
||||
@@ -572,11 +599,14 @@ _openapi:
|
||||
email lookup. Requires an admin token or a panel login session.
|
||||
heading: fetch-clients-by-subscription-id
|
||||
- content: >-
|
||||
Fields the server fills in when they are omitted — a valid value sent
|
||||
by the caller is never overwritten. Re-adding an email that already
|
||||
exists, with its stored `subId`, reuses the stored `id`, `password`,
|
||||
`auth` and `secret` instead of minting new ones, so the identity stays
|
||||
in sync across its inbounds.
|
||||
Client email must not be exactly `.` or `..`. Existing reserved-name
|
||||
clients can be read, renamed to a valid name, or deleted using the
|
||||
query-parameter /get, /update and /del aliases. Fields the server
|
||||
fills in when they are omitted — a valid value sent by the caller is
|
||||
never overwritten. Re-adding an email that already exists, with its
|
||||
stored `subId`, reuses the stored `id`, `password`, `auth` and
|
||||
`secret` instead of minting new ones, so the identity stays in sync
|
||||
across its inbounds.
|
||||
|
||||
|
||||
- **VLESS / VMess** — `id`, a fresh UUID
|
||||
@@ -650,6 +680,17 @@ _openapi:
|
||||
without an `inbound <id>:` prefix and leaves the inbound edits in
|
||||
place.'
|
||||
heading: update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
|
||||
- content: 'Query-parameter alias for the path endpoint. Use email=. or email=..
|
||||
to manage legacy reserved names without URL dot-segment normalization.
|
||||
The inbounds are applied concurrently and independently: one that
|
||||
fails no longer stops the others. Every inbound error names the
|
||||
inbound it came from (`inbound 7: <message>`), and several failures
|
||||
are reported together, one per line. So a `success:false` response can
|
||||
still have applied the edit to the remaining inbounds. The client
|
||||
record is written after the inbounds, so a failure there is reported
|
||||
without an `inbound <id>:` prefix and leaves the inbound edits in
|
||||
place.'
|
||||
heading: update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch-1
|
||||
- content: 'The inbounds are applied concurrently and independently: one that
|
||||
fails no longer stops the others. Every inbound error names the
|
||||
inbound it came from (`inbound 7: <message>`), and several failures
|
||||
@@ -660,6 +701,18 @@ _openapi:
|
||||
inbounds, so a failure there is reported without an `inbound <id>:`
|
||||
prefix and leaves the client already removed from every inbound.'
|
||||
heading: delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
|
||||
- content: 'Query-parameter alias for the path endpoint. Use email=. or email=..
|
||||
to manage legacy reserved names without URL dot-segment normalization.
|
||||
The inbounds are applied concurrently and independently: one that
|
||||
fails no longer stops the others. Every inbound error names the
|
||||
inbound it came from (`inbound 7: <message>`), and several failures
|
||||
are reported together, one per line. So a `success:false` response can
|
||||
still have removed the client from the remaining inbounds; the client
|
||||
record is kept in that case, so re-running the call retries exactly
|
||||
the leftovers. The record and traffic rows are dropped after the
|
||||
inbounds, so a failure there is reported without an `inbound <id>:`
|
||||
prefix and leaves the client already removed from every inbound.'
|
||||
heading: delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed-1
|
||||
- content: 'A WireGuard client brings its stored `allowedIPs` into the new inbound
|
||||
instead of being given a fresh address, so the call fails with
|
||||
`inbound <id>: wireguard: allowedIPs entry <entry> overlaps <address>
|
||||
@@ -685,7 +738,7 @@ export default function Layout(props) {
|
||||
return (
|
||||
<>
|
||||
{props.children}
|
||||
<OpenAPIPage document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/clients/list","method":"get"},{"path":"/panel/api/clients/list/paged","method":"get"},{"path":"/panel/api/clients/get/{email}","method":"get"},{"path":"/panel/api/clients/get/subId/{subId}","method":"get"},{"path":"/panel/api/clients/get/tgId/{tgId}","method":"get"},{"path":"/panel/api/clients/add","method":"post"},{"path":"/panel/api/clients/renewalPreview","method":"post"},{"path":"/panel/api/clients/update/{email}","method":"post"},{"path":"/panel/api/clients/del/{email}","method":"post"},{"path":"/panel/api/clients/{email}/attach","method":"post"},{"path":"/panel/api/clients/{email}/detach","method":"post"},{"path":"/panel/api/clients/{email}/externalLinks","method":"post"},{"path":"/panel/api/clients/resetAllTraffics","method":"post"},{"path":"/panel/api/clients/delDepleted","method":"post"},{"path":"/panel/api/clients/delOrphans","method":"post"},{"path":"/panel/api/clients/export","method":"get"},{"path":"/panel/api/clients/import","method":"post"},{"path":"/panel/api/clients/bulkAdjust","method":"post"},{"path":"/panel/api/clients/bulkEnable","method":"post"},{"path":"/panel/api/clients/bulkDisable","method":"post"},{"path":"/panel/api/clients/bulkDel","method":"post"},{"path":"/panel/api/clients/bulkCreate","method":"post"},{"path":"/panel/api/clients/groups/bulkAdd","method":"post"},{"path":"/panel/api/clients/groups/bulkRemove","method":"post"},{"path":"/panel/api/clients/bulkAttach","method":"post"},{"path":"/panel/api/clients/bulkDetach","method":"post"},{"path":"/panel/api/clients/bulkResetTraffic","method":"post"},{"path":"/panel/api/clients/groups","method":"get"},{"path":"/panel/api/clients/groups/{name}/emails","method":"get"},{"path":"/panel/api/clients/groups/create","method":"post"},{"path":"/panel/api/clients/groups/rename","method":"post"},{"path":"/panel/api/clients/groups/delete","method":"post"},{"path":"/panel/api/clients/groups/resetTraffic","method":"post"},{"path":"/panel/api/clients/resetTraffic/{email}","method":"post"},{"path":"/panel/api/clients/updateTraffic/{email}","method":"post"},{"path":"/panel/api/clients/ips/{email}","method":"post"},{"path":"/panel/api/clients/clearIps/{email}","method":"post"},{"path":"/panel/api/clients/hwids/{email}","method":"post"},{"path":"/panel/api/clients/hwids/{email}","method":"delete"},{"path":"/panel/api/clients/hwids/{email}/{id}","method":"delete"},{"path":"/panel/api/clients/onlines","method":"post"},{"path":"/panel/api/clients/onlinesByGuid","method":"post"},{"path":"/panel/api/clients/clientIpsByGuid","method":"post"},{"path":"/panel/api/clients/activeInbounds","method":"post"},{"path":"/panel/api/clients/lastOnline","method":"post"},{"path":"/panel/api/clients/traffic/{email}","method":"get"},{"path":"/panel/api/clients/subLinks/{subId}","method":"get"},{"path":"/panel/api/clients/happLink/{id}","method":"post"},{"path":"/panel/api/clients/links/{email}","method":"get"}]} showTitle />
|
||||
<OpenAPIPage document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/clients/list","method":"get"},{"path":"/panel/api/clients/list/paged","method":"get"},{"path":"/panel/api/clients/get/{email}","method":"get"},{"path":"/panel/api/clients/get","method":"get"},{"path":"/panel/api/clients/get/subId/{subId}","method":"get"},{"path":"/panel/api/clients/get/tgId/{tgId}","method":"get"},{"path":"/panel/api/clients/add","method":"post"},{"path":"/panel/api/clients/renewalPreview","method":"post"},{"path":"/panel/api/clients/update/{email}","method":"post"},{"path":"/panel/api/clients/update","method":"post"},{"path":"/panel/api/clients/del/{email}","method":"post"},{"path":"/panel/api/clients/del","method":"post"},{"path":"/panel/api/clients/{email}/attach","method":"post"},{"path":"/panel/api/clients/{email}/detach","method":"post"},{"path":"/panel/api/clients/{email}/externalLinks","method":"post"},{"path":"/panel/api/clients/resetAllTraffics","method":"post"},{"path":"/panel/api/clients/delDepleted","method":"post"},{"path":"/panel/api/clients/delOrphans","method":"post"},{"path":"/panel/api/clients/export","method":"get"},{"path":"/panel/api/clients/import","method":"post"},{"path":"/panel/api/clients/bulkAdjust","method":"post"},{"path":"/panel/api/clients/bulkEnable","method":"post"},{"path":"/panel/api/clients/bulkDisable","method":"post"},{"path":"/panel/api/clients/bulkDel","method":"post"},{"path":"/panel/api/clients/bulkCreate","method":"post"},{"path":"/panel/api/clients/groups/bulkAdd","method":"post"},{"path":"/panel/api/clients/groups/bulkRemove","method":"post"},{"path":"/panel/api/clients/bulkAttach","method":"post"},{"path":"/panel/api/clients/bulkDetach","method":"post"},{"path":"/panel/api/clients/bulkResetTraffic","method":"post"},{"path":"/panel/api/clients/groups","method":"get"},{"path":"/panel/api/clients/groups/{name}/emails","method":"get"},{"path":"/panel/api/clients/groups/create","method":"post"},{"path":"/panel/api/clients/groups/rename","method":"post"},{"path":"/panel/api/clients/groups/delete","method":"post"},{"path":"/panel/api/clients/groups/resetTraffic","method":"post"},{"path":"/panel/api/clients/resetTraffic/{email}","method":"post"},{"path":"/panel/api/clients/updateTraffic/{email}","method":"post"},{"path":"/panel/api/clients/ips/{email}","method":"post"},{"path":"/panel/api/clients/clearIps/{email}","method":"post"},{"path":"/panel/api/clients/hwids/{email}","method":"post"},{"path":"/panel/api/clients/hwids/{email}","method":"delete"},{"path":"/panel/api/clients/hwids/{email}/{id}","method":"delete"},{"path":"/panel/api/clients/onlines","method":"post"},{"path":"/panel/api/clients/onlinesByGuid","method":"post"},{"path":"/panel/api/clients/clientIpsByGuid","method":"post"},{"path":"/panel/api/clients/activeInbounds","method":"post"},{"path":"/panel/api/clients/lastOnline","method":"post"},{"path":"/panel/api/clients/traffic/{email}","method":"get"},{"path":"/panel/api/clients/subLinks/{subId}","method":"get"},{"path":"/panel/api/clients/happLink/{id}","method":"post"},{"path":"/panel/api/clients/links/{email}","method":"get"}]} showTitle />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user