feat(sub): auto-detect subscription format by User-Agent (Updated) (#5826)

* feat(settings): add subscription format controls

* feat(sub): auto-detect subscription formats

* fix(xray): validate balancer regexes before save

* Revert "fix(xray): validate balancer regexes before save"

This reverts commit 8a208ce71b.

* doc(endpoints): align indent spaces

* doc(settings): improve error message formatting in validateSubUserAgentRegex

- Use NewErrorf with proper formatting instead of NewError with string concatenation
- Add comment explaining the rationale for returning original pattern value
- This preserves the intentional design where empty input is stored as empty
  in the DB and inherited as the runtime default at read time

---------

Co-authored-by: Tomilla <5007859+Tomilla@users.noreply.github.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
Tomi lla
2026-07-14 19:01:40 +08:00
committed by GitHub
parent f2b17397f4
commit 129f50d92a
40 changed files with 1588 additions and 89 deletions
+9 -2
View File
@@ -1145,7 +1145,7 @@ export const sections: readonly Section[] = [
method: 'POST',
path: '/panel/api/setting/all',
summary: 'Return every panel setting: web server, Telegram bot, subscription, security, LDAP. The full JSON blob that the Settings page edits.',
response: '{\n "success": true,\n "obj": {\n "webPort": 2053,\n "webCertFile": "",\n "webKeyFile": "",\n "webBasePath": "/",\n "subPort": 10882,\n "subPath": "/sub/",\n "tgBotEnable": false,\n "tgBotToken": "",\n ...\n }\n}',
response: '{\n "success": true,\n "obj": {\n "webPort": 2053,\n "webCertFile": "",\n "webKeyFile": "",\n "webBasePath": "/",\n "subPort": 10882,\n "subPath": "/sub/",\n "subClashAutoDetect": false,\n "subClashUserAgentRegex": "",\n "subJsonEnable": false,\n "subJsonAutoDetect": false,\n "subJsonAlwaysArray": false,\n "subJsonUserAgentRegex": "",\n "subJsonPath": "/json/",\n "subJsonURI": "https://sub.example.com/json/",\n "subClashEnable": true,\n "subClashPath": "/clash/",\n "subClashURI": "https://sub.example.com/clash/",\n "tgBotEnable": false,\n "tgBotToken": "",\n ...\n }\n}',
},
{
method: 'POST',
@@ -1156,7 +1156,14 @@ export const sections: readonly Section[] = [
method: 'POST',
path: '/panel/api/setting/update',
summary: 'Persist every setting at once. The body mirrors the shape returned by /all. Invalid values (bad ports, missing cert pairs, etc.) are rejected before write.',
body: '{\n "webPort": 2053,\n "webBasePath": "/",\n "subPort": 10882,\n "subPath": "/sub/",\n "tgBotEnable": false,\n ...\n}',
body: '{\n "webPort": 2053,\n "webBasePath": "/",\n "subPort": 10882,\n "subPath": "/sub/",\n "subClashAutoDetect": false,\n "subClashUserAgentRegex": "",\n "subJsonEnable": false,\n "subJsonAutoDetect": false,\n "subJsonAlwaysArray": false,\n "subJsonUserAgentRegex": "",\n "subJsonPath": "/json/",\n "subJsonURI": "https://sub.example.com/json/",\n "subClashEnable": true,\n "subClashPath": "/clash/",\n "subClashURI": "https://sub.example.com/clash/",\n "tgBotEnable": false,\n ...\n}',
},
{
method: 'POST',
path: '/panel/api/setting/validateRegex',
summary: 'Validate any regular expression with the backend Go RE2 compiler without saving it.',
body: '{\n "regex": "(?m)^general-purpose$"\n}',
response: '{\n "success": true,\n "msg": ""\n}',
},
{
method: 'POST',