mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-28 10:12:07 +03:00
fix(sub): randomize fresh panel subscription paths (#6375)
* fix(sub): randomize fresh panel subscription paths Seed distinct cryptographically random paths for base64, JSON, and Clash subscriptions when a panel database is first created. Persist them so restarts keep published URLs stable while upgrades preserve existing settings. Generated-by: OpenCode:gpt-5.6-sol * fix(sub): regenerate paths on settings reset Keep subscription paths unpredictable after a factory reset, close the test database on failure, and update the builder, OpenAPI, and localized docs to describe panel-specific paths instead of obsolete fixed defaults. Generated-by: OpenCode:gpt-5.6-sol
This commit is contained in:
@@ -18,7 +18,7 @@ icon: Rss
|
||||
| ------------- | ------- | --------------------------------------------------------------- |
|
||||
| `subPort` | `2096` | Порт прослушивания (отдельный от панели). |
|
||||
| `subListen` | _(все)_ | Адрес привязки. |
|
||||
| `subPath` | `/sub/` | Базовый путь для необработанных URL подписок. |
|
||||
| `subPath` | _(случайный для каждой панели)_ | Базовый путь для необработанных URL подписок. |
|
||||
| `subDomain` | _(нет)_ | Публичный хост; если задан, сервер отвечает только для этого Host. |
|
||||
| `subCertFile` / `subKeyFile` | _(нет)_ | Сертификат + ключ TLS — когда заданы, сервер работает по **HTTPS**. |
|
||||
| `subEncrypt` | `true` | Кодировать тело необработанной подписки в base64. |
|
||||
@@ -27,7 +27,7 @@ icon: Rss
|
||||
URL подписки выглядит так:
|
||||
|
||||
```text
|
||||
https://<sub-host>:<sub-port>/sub/<sub-id>
|
||||
https://<sub-host>:<sub-port>/<sub-path>/<sub-id>
|
||||
```
|
||||
|
||||
где `<sub-id>` — это **Sub ID** клиента.
|
||||
@@ -44,13 +44,13 @@ https://<sub-host>:<sub-port>/sub/<sub-id>
|
||||
|
||||
| Формат | Путь | Включается | Вывод |
|
||||
| --------------------- | --------- | ---------------- | --------------------------------------------------- |
|
||||
| **Необработанные ссылки** | `/sub/` | всегда (если включён) | Список ссылок `vless://`, `vmess://`, … (закодированных в base64, когда включён `subEncrypt`). |
|
||||
| **JSON** | `/json/` | `subJsonEnable` | Полные клиентские конфигурации Xray. |
|
||||
| **Clash / Mihomo** | `/clash/` | `subClashEnable` | YAML-профиль. |
|
||||
| **Необработанные ссылки** | `subPath` | всегда (если включён) | Список ссылок `vless://`, `vmess://`, … (закодированных в base64, когда включён `subEncrypt`). |
|
||||
| **JSON** | `subJsonPath` | `subJsonEnable` | Полные клиентские конфигурации Xray. |
|
||||
| **Clash / Mihomo** | `subClashPath` | `subClashEnable` | YAML-профиль. |
|
||||
|
||||
В подписке появляются только включённые входящие соединения, использующие
|
||||
**VLESS, VMess, Trojan, Shadowsocks или Hysteria2**, упорядоченные по их индексу
|
||||
сортировки подписки. Запрос `/sub/` с заголовком `Accept: text/html` (или
|
||||
сортировки подписки. Запрос `subPath` с заголовком `Accept: text/html` (или
|
||||
`?html=1`) возвращает удобочитаемую информационную страницу вместо
|
||||
необработанного тела.
|
||||
|
||||
|
||||
@@ -311,11 +311,12 @@ _openapi:
|
||||
title: >-
|
||||
Return every protocol URL (vless://, vmess://, trojan://, ss://,
|
||||
hysteria://, hy2://) for clients matching the subscription ID. Same
|
||||
result set as /sub/<subId>, but as a JSON array — no base64. When an
|
||||
inbound has streamSettings.externalProxy set, one URL is emitted per
|
||||
external proxy. Empty array when the subId has no enabled clients.
|
||||
result set as the configured subPath endpoint, but as a JSON array — no
|
||||
base64. When an inbound has streamSettings.externalProxy set, one URL is
|
||||
emitted per external proxy. Empty array when the subId has no enabled
|
||||
clients.
|
||||
url: >-
|
||||
#return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-subsubid-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
|
||||
#return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-the-configured-subpath-endpoint-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
|
||||
- depth: 2
|
||||
title: >-
|
||||
Return every URL for one client across all attached inbounds — the same
|
||||
@@ -593,11 +594,12 @@ _openapi:
|
||||
- content: >-
|
||||
Return every protocol URL (vless://, vmess://, trojan://, ss://,
|
||||
hysteria://, hy2://) for clients matching the subscription ID. Same
|
||||
result set as /sub/<subId>, but as a JSON array — no base64. When an
|
||||
inbound has streamSettings.externalProxy set, one URL is emitted per
|
||||
external proxy. Empty array when the subId has no enabled clients.
|
||||
result set as the configured subPath endpoint, but as a JSON array —
|
||||
no base64. When an inbound has streamSettings.externalProxy set, one
|
||||
URL is emitted per external proxy. Empty array when the subId has no
|
||||
enabled clients.
|
||||
id: >-
|
||||
return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-subsubid-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
|
||||
return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-the-configured-subpath-endpoint-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
|
||||
- content: >-
|
||||
Return every URL for one client across all attached inbounds — the
|
||||
same strings the Copy URL button copies in the panel UI. Supported
|
||||
@@ -672,4 +674,4 @@ export default function Layout(props) {
|
||||
<Comp 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/add","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/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/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/links/{email}","method":"get"}]} showTitle />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ title: Сервер подписок
|
||||
description: >-
|
||||
Отдельный HTTP/HTTPS-сервер, который отдаёт клиентам ссылки на подписки
|
||||
прокси (стандартные, JSON и Clash). Сервер слушает на собственном порту (по
|
||||
умолчанию 10882) и настраивается в разделе Settings → Subscription. Пути
|
||||
настраиваемы; значения по умолчанию показаны ниже. Все конечные точки подписок
|
||||
устанавливают заголовки ответа, по которым клиентские приложения считывают
|
||||
информацию о трафике и сроке действия.
|
||||
умолчанию 2096) и настраивается в разделе Settings → Subscription. Новые
|
||||
панели генерируют случайные префиксы путей для каждого формата; все пути можно
|
||||
изменить. Все конечные точки подписок устанавливают заголовки ответа, по
|
||||
которым клиентские приложения считывают информацию о трафике и сроке действия.
|
||||
full: true
|
||||
_openapi:
|
||||
preload:
|
||||
@@ -16,45 +16,46 @@ _openapi:
|
||||
title: >-
|
||||
Return base64-encoded subscription links for all enabled clients
|
||||
matching the subscription ID. When the request has an Accept: text/html
|
||||
header or ?html=1, renders a styled info page instead. Default path:
|
||||
/sub/:subid.
|
||||
header or ?html=1, renders a styled info page instead. The path prefix is
|
||||
configured by subPath.
|
||||
url: >-
|
||||
#return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-default-path-subsubid
|
||||
#return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-with-formatinfo-returns-the-page-view-model-as-json-traffic-expiry-online-status-no-links-for-live-polling-the-path-prefix-is-configured-by-subpath
|
||||
- depth: 2
|
||||
title: >-
|
||||
Return subscription as a JSON array of proxy configs (one per enabled
|
||||
client). Only when JSON subscription is enabled in settings. Default
|
||||
path: /json/:subid.
|
||||
client). Only when JSON subscription is enabled in settings. The path
|
||||
prefix is configured by subJsonPath.
|
||||
url: >-
|
||||
#return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-default-path-jsonsubid
|
||||
#return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-the-path-prefix-is-configured-by-subjsonpath
|
||||
- depth: 2
|
||||
title: >-
|
||||
Return subscription as a Clash/Mihomo-compatible YAML config, including
|
||||
configured global Clash routing rules. Only when Clash subscription is
|
||||
enabled in settings. Default path: /clash/:subid.
|
||||
enabled in settings. The path prefix is configured by subClashPath.
|
||||
url: >-
|
||||
#return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-default-path-clashsubid
|
||||
#return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-the-path-prefix-is-configured-by-subclashpath
|
||||
structuredData:
|
||||
headings:
|
||||
- content: >-
|
||||
Return base64-encoded subscription links for all enabled clients
|
||||
matching the subscription ID. When the request has an Accept:
|
||||
text/html header or ?html=1, renders a styled info page instead.
|
||||
Default path: /sub/:subid.
|
||||
text/html header or ?html=1, renders a styled info page instead. The
|
||||
path prefix is configured by subPath.
|
||||
id: >-
|
||||
return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-default-path-subsubid
|
||||
return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-with-formatinfo-returns-the-page-view-model-as-json-traffic-expiry-online-status-no-links-for-live-polling-the-path-prefix-is-configured-by-subpath
|
||||
- content: >-
|
||||
Return subscription as a JSON array of proxy configs (one per enabled
|
||||
client). Only when JSON subscription is enabled in settings. Default
|
||||
path: /json/:subid.
|
||||
client). Only when JSON subscription is enabled in settings. The path
|
||||
prefix is configured by subJsonPath.
|
||||
id: >-
|
||||
return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-default-path-jsonsubid
|
||||
return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-the-path-prefix-is-configured-by-subjsonpath
|
||||
- content: >-
|
||||
Return subscription as a Clash/Mihomo-compatible YAML config,
|
||||
including configured global Clash routing rules. Only when Clash
|
||||
subscription is enabled in settings. Default path: /clash/:subid.
|
||||
subscription is enabled in settings. The path prefix is configured by
|
||||
subClashPath.
|
||||
id: >-
|
||||
return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-default-path-clashsubid
|
||||
return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-the-path-prefix-is-configured-by-subclashpath
|
||||
contents: []
|
||||
---
|
||||
|
||||
@@ -70,4 +71,4 @@ export default function Layout(props) {
|
||||
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/{subPath}{subid}","method":"get"},{"path":"/{jsonPath}{subid}","method":"get"},{"path":"/{clashPath}{subid}","method":"get"}]} showTitle />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user