mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-06 19:46:52 +03:00
Compare commits
64 Commits
0.7.2
...
ea1273e05e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea1273e05e | ||
|
|
5fc3c95928 | ||
|
|
dd3e70153a | ||
|
|
622e092317 | ||
|
|
c045f8f224 | ||
|
|
b45088dad7 | ||
|
|
82345047cb | ||
|
|
0a4ed367bc | ||
|
|
c3f322ae61 | ||
|
|
eb9239696e | ||
|
|
5b3421498e | ||
|
|
6a48a060e1 | ||
|
|
14f704fcb8 | ||
|
|
ff43f477e9 | ||
|
|
576e58fd17 | ||
|
|
d72c98a254 | ||
|
|
7a497f1e31 | ||
|
|
d52f6e26ae | ||
|
|
68c61aed50 | ||
|
|
626ac981eb | ||
|
|
352d10a047 | ||
|
|
031c419ffb | ||
|
|
c13fdf5785 | ||
|
|
1b7ab606ba | ||
|
|
2bf208ecac | ||
|
|
e256e4bee5 | ||
|
|
32c385b309 | ||
|
|
56829c74c8 | ||
|
|
9d78cd2ce4 | ||
|
|
d9ce3b361e | ||
|
|
c67aadf267 | ||
|
|
ac4d7570f3 | ||
|
|
86897fd0af | ||
|
|
230ffbce46 | ||
|
|
dd5ddd1a14 | ||
|
|
cc947f9734 | ||
|
|
f8510cd828 | ||
|
|
23cbe7be4a | ||
|
|
f168fb7e31 | ||
|
|
fe84b3154f | ||
|
|
d09fdc0b95 | ||
|
|
835cd85970 | ||
|
|
8a3b41ec9c | ||
|
|
10d7617739 | ||
|
|
68010ed5f7 | ||
|
|
557e3666eb | ||
|
|
01bff8ccfb | ||
|
|
675a6af89c | ||
|
|
f1a6ff3469 | ||
|
|
d4b3377d68 | ||
|
|
d2ef640d76 | ||
|
|
47457f2c27 | ||
|
|
8a29e176f2 | ||
|
|
9653310208 | ||
|
|
3540610c78 | ||
|
|
fb54d62a7f | ||
|
|
288b8d4cc2 | ||
|
|
e014396ae2 | ||
|
|
694e4ca35a | ||
|
|
788c539e16 | ||
|
|
743cba8936 | ||
|
|
d1d703764c | ||
|
|
2efd415305 | ||
|
|
407b19b3ed |
@@ -34,6 +34,7 @@ vless://4d21ce62-8723-4c4d-93e3-d586b107aa40@127.0.0.1:51394?type=ws&encryption=
|
|||||||
# gRPC
|
# gRPC
|
||||||
vless://974b39e3-f7bf-42b9-933c-16699c635e77@127.0.0.1:15633?type=grpc&encryption=none&serviceName=TunService&authority=&security=none#vless-gRPC-none
|
vless://974b39e3-f7bf-42b9-933c-16699c635e77@127.0.0.1:15633?type=grpc&encryption=none&serviceName=TunService&authority=&security=none#vless-gRPC-none
|
||||||
vless://651e7eca-5152-46f1-baf2-d502e0af7b27@127.0.0.1:28535?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=reality&pbk=nhZ7NiKfcqESa5ZeBFfsq9o18W-OWOAHLln9UmuVXSk&fp=chrome&sni=google.com&sid=11cbaeaa&spx=%2F#vless-gRPC-reality
|
vless://651e7eca-5152-46f1-baf2-d502e0af7b27@127.0.0.1:28535?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=reality&pbk=nhZ7NiKfcqESa5ZeBFfsq9o18W-OWOAHLln9UmuVXSk&fp=chrome&sni=google.com&sid=11cbaeaa&spx=%2F#vless-gRPC-reality
|
||||||
|
vless://221ff905-b783-41a0-a6a6-8089eaf3b34b@abc.def.xyz:443?security=reality&type=grpc&headerType=&authority=abc.def.xyz&serviceName=name&mode=gun&sni=abc.def.xyz&fp=chrome&pbk=C3nhDJw02ZU_rjx4GbC54Sp79-ysF5lWIQVWdY4FOnE&sid=#vless-gRPC-reality-mode
|
||||||
vless://af1f8b5f-26c9-4fe8-8ce7-6d6366c5c9ce@127.0.0.1:47904?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com#vless-gRPC-tls
|
vless://af1f8b5f-26c9-4fe8-8ce7-6d6366c5c9ce@127.0.0.1:47904?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com#vless-gRPC-tls
|
||||||
vless://95f2c4bb-abcb-47ba-bfad-e181c03e4659@127.0.0.1:34530?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&allowInsecure=1&sni=google.com#vless-gRPC-tls-insecure
|
vless://95f2c4bb-abcb-47ba-bfad-e181c03e4659@127.0.0.1:34530?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&allowInsecure=1&sni=google.com#vless-gRPC-tls-insecure
|
||||||
vless://bd39490f-9a4f-49b2-96b6-824190cf89e9@127.0.0.1:27779?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com&ech=AF3%2BDQBZAAAgACBc%2FiNdo4QkTt9eQCQgkOiJVSfA9G6UWAyipaBFtBD%2FVQAkAAEAAQABAAIAAQADAAIAAQACAAIAAgADAAMAAQADAAIAAwADAApnb29nbGUuY29tAAA%3D#vless-gRPC-tls-ech
|
vless://bd39490f-9a4f-49b2-96b6-824190cf89e9@127.0.0.1:27779?type=grpc&encryption=none&serviceName=TunService&authority=authority&security=tls&fp=chrome&alpn=h2%2Chttp%2F1.1&sni=google.com&ech=AF3%2BDQBZAAAgACBc%2FiNdo4QkTt9eQCQgkOiJVSfA9G6UWAyipaBFtBD%2FVQAkAAEAAQABAAIAAQADAAIAAQACAAIAAgADAAMAAQADAAIAAwADAApnb29nbGUuY29tAAA%3D#vless-gRPC-tls-ech
|
||||||
@@ -81,4 +82,38 @@ trojan://ou8pLSyx9N@127.0.0.1:17737?type=httpupgrade&path=%2Fhttpupgradepath&hos
|
|||||||
|
|
||||||
# XHTTP
|
# XHTTP
|
||||||
trojan://VEetltxLtw@127.0.0.1:59072?type=xhttp&path=%2Fxhttppath&host=google.com&mode=auto&security=none#trojan-xhttp
|
trojan://VEetltxLtw@127.0.0.1:59072?type=xhttp&path=%2Fxhttppath&host=google.com&mode=auto&security=none#trojan-xhttp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Hysteria2
|
||||||
|
|
||||||
|
hysteria2://
|
||||||
|
```
|
||||||
|
# With password
|
||||||
|
hysteria2://password@example.com:443/#hysteria2-password
|
||||||
|
hysteria2://password@example.com:443/?insecure=1#hysteria2-password-insecure
|
||||||
|
|
||||||
|
# With SNI
|
||||||
|
hysteria2://password@example.com:443/?sni=example.com#hysteria2-password-sni
|
||||||
|
|
||||||
|
# With obfuscation
|
||||||
|
hysteria2://password@example.com:443/?obfs=salamander&obfs-password=obfspassword#hysteria2-obfs
|
||||||
|
|
||||||
|
# All parameters combined
|
||||||
|
hysteria2://mypassword@example.com:8443/?sni=example.com&obfs=salamander&obfs-password=obfspass&insecure=1#hysteria2-all-params
|
||||||
|
```
|
||||||
|
|
||||||
|
hy2://
|
||||||
|
```
|
||||||
|
# With password
|
||||||
|
hy2://password@example.com:443/#hysteria2-password
|
||||||
|
hy2://password@example.com:443/?insecure=1#hysteria2-password-insecure
|
||||||
|
|
||||||
|
# With SNI
|
||||||
|
hy2://password@example.com:443/?sni=example.com#hysteria2-password-sni
|
||||||
|
|
||||||
|
# With obfuscation
|
||||||
|
hy2://password@example.com:443/?obfs=salamander&obfs-password=obfspassword#hysteria2-obfs
|
||||||
|
|
||||||
|
# All parameters combined
|
||||||
|
hy2://mypassword@example.com:8443/?sni=example.com&obfs=salamander&obfs-password=obfspass&insecure=1#hysteria2-all-params
|
||||||
```
|
```
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PODKOP\n"
|
"Project-Id-Version: PODKOP\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-23 17:43+0300\n"
|
"POT-Creation-Date: 2025-12-01 14:30+0200\n"
|
||||||
"PO-Revision-Date: 2025-10-23 17:43+0300\n"
|
"PO-Revision-Date: 2025-12-01 14:30+0200\n"
|
||||||
"Last-Translator: divocat <divocatt@gmail.com>\n"
|
"Last-Translator: divocat <divocatt@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
@@ -16,23 +16,23 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:342
|
#: src/podkop/tabs/dashboard/initController.ts:345
|
||||||
msgid "✔ Enabled"
|
msgid "✔ Enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:353
|
#: src/podkop/tabs/dashboard/initController.ts:356
|
||||||
msgid "✔ Running"
|
msgid "✔ Running"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:343
|
#: src/podkop/tabs/dashboard/initController.ts:346
|
||||||
msgid "✘ Disabled"
|
msgid "✘ Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:354
|
#: src/podkop/tabs/dashboard/initController.ts:357
|
||||||
msgid "✘ Stopped"
|
msgid "✘ Stopped"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:304
|
#: src/podkop/tabs/dashboard/initController.ts:307
|
||||||
msgid "Active Connections"
|
msgid "Active Connections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -40,15 +40,19 @@ msgstr ""
|
|||||||
msgid "Additional marking rules found"
|
msgid "Additional marking rules found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247
|
||||||
|
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:175
|
||||||
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:356
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:420
|
||||||
msgid "At least one valid domain must be specified. Comments-only content is not allowed."
|
msgid "At least one valid domain must be specified. Comments-only content is not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:437
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:501
|
||||||
msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed."
|
msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -72,16 +76,17 @@ msgstr ""
|
|||||||
msgid "Browser is using FakeIP correctly"
|
msgid "Browser is using FakeIP correctly"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:329
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:348
|
||||||
msgid "Cache File Path"
|
msgid "Cache File Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:343
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:362
|
||||||
msgid "Cache file path cannot be empty"
|
msgid "Cache file path cannot be empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:27
|
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:27
|
||||||
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:28
|
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:28
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:27
|
||||||
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:25
|
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:25
|
||||||
msgid "Cannot receive checks result"
|
msgid "Cannot receive checks result"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -89,6 +94,7 @@ msgstr ""
|
|||||||
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:15
|
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:15
|
||||||
#: src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts:15
|
#: src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts:15
|
||||||
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:13
|
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:13
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:15
|
||||||
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:13
|
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:13
|
||||||
msgid "Checking, please wait"
|
msgid "Checking, please wait"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -113,11 +119,11 @@ msgstr ""
|
|||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:211
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:275
|
||||||
msgid "Community Lists"
|
msgid "Community Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:316
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:335
|
||||||
msgid "Config File Path"
|
msgid "Config File Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -173,16 +179,16 @@ msgstr ""
|
|||||||
msgid "Disable autostart"
|
msgid "Disable autostart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:265
|
||||||
msgid "Disable QUIC"
|
msgid "Disable QUIC"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:266
|
||||||
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
|
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:302
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:366
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:382
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:446
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -190,17 +196,17 @@ msgstr ""
|
|||||||
msgid "DNS on router"
|
msgid "DNS on router"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:179
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:243
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15
|
||||||
msgid "DNS over HTTPS (DoH)"
|
msgid "DNS over HTTPS (DoH)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:180
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:244
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16
|
||||||
msgid "DNS over TLS (DoT)"
|
msgid "DNS over TLS (DoT)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:176
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:240
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12
|
||||||
msgid "DNS Protocol Type"
|
msgid "DNS Protocol Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -209,7 +215,7 @@ msgstr ""
|
|||||||
msgid "DNS Rewrite TTL"
|
msgid "DNS Rewrite TTL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:189
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:253
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24
|
||||||
msgid "DNS Server"
|
msgid "DNS Server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -222,16 +228,16 @@ msgstr ""
|
|||||||
msgid "Do not panic, everything can be fixed, just..."
|
msgid "Do not panic, everything can be fixed, just..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:166
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:230
|
||||||
msgid "Domain Resolver"
|
msgid "Domain Resolver"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:307
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:326
|
||||||
msgid "Dont Touch My DHCP!"
|
msgid "Dont Touch My DHCP!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:238
|
#: src/podkop/tabs/dashboard/initController.ts:241
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:272
|
#: src/podkop/tabs/dashboard/initController.ts:275
|
||||||
msgid "Downlink"
|
msgid "Downlink"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -239,24 +245,21 @@ msgstr ""
|
|||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:269
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:288
|
||||||
msgid "Download Lists via Proxy/VPN"
|
msgid "Download Lists via Proxy/VPN"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:278
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:297
|
||||||
msgid "Download Lists via specific proxy section"
|
msgid "Download Lists via specific proxy section"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:270
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:289
|
||||||
msgid "Downloading all lists via main Proxy/VPN"
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:298
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:279
|
|
||||||
msgid "Downloading all lists via specific Proxy/VPN"
|
msgid "Downloading all lists via specific Proxy/VPN"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:303
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:367
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:383
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:447
|
||||||
msgid "Dynamic List"
|
msgid "Dynamic List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -264,11 +267,11 @@ msgstr ""
|
|||||||
msgid "Enable autostart"
|
msgid "Enable autostart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:167
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:231
|
||||||
msgid "Enable built-in DNS resolver for domains handled by this section"
|
msgid "Enable built-in DNS resolver for domains handled by this section"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:575
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:639
|
||||||
msgid "Enable Mixed Proxy"
|
msgid "Enable Mixed Proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -276,7 +279,7 @@ msgstr ""
|
|||||||
msgid "Enable Output Network Interface"
|
msgid "Enable Output Network Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:576
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:640
|
||||||
msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies"
|
msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -284,27 +287,47 @@ msgstr ""
|
|||||||
msgid "Enable YACD"
|
msgid "Enable YACD"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246
|
||||||
|
msgid "Enable YACD WAN Access"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65
|
||||||
msgid "Enter complete outbound configuration in JSON format"
|
msgid "Enter complete outbound configuration in JSON format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:338
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:402
|
||||||
msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //"
|
msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:312
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:376
|
||||||
msgid "Enter domain names without protocols, e.g. example.com or sub.example.com"
|
msgid "Enter domain names without protocols, e.g. example.com or sub.example.com"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:392
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:456
|
||||||
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:365
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:114
|
||||||
|
msgid "Every 1 minute"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:115
|
||||||
|
msgid "Every 3 minutes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:113
|
||||||
|
msgid "Every 30 seconds"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:116
|
||||||
|
msgid "Every 5 minutes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:384
|
||||||
msgid "Exclude NTP"
|
msgid "Exclude NTP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:385
|
||||||
msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN"
|
msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -312,20 +335,21 @@ msgstr ""
|
|||||||
msgid "Failed to copy!"
|
msgid "Failed to copy!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:226
|
#: src/podkop/tabs/diagnostic/initController.ts:227
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:230
|
#: src/podkop/tabs/diagnostic/initController.ts:231
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:260
|
#: src/podkop/tabs/diagnostic/initController.ts:261
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:264
|
#: src/podkop/tabs/diagnostic/initController.ts:265
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:298
|
#: src/podkop/tabs/diagnostic/initController.ts:299
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:302
|
#: src/podkop/tabs/diagnostic/initController.ts:303
|
||||||
msgid "Failed to execute!"
|
msgid "Failed to execute!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/methods/custom/getDashboardSections.ts:117
|
#: src/podkop/methods/custom/getDashboardSections.ts:117
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:59
|
||||||
msgid "Fastest"
|
msgid "Fastest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:550
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:614
|
||||||
msgid "Fully Routed IPs"
|
msgid "Fully Routed IPs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -333,7 +357,7 @@ msgstr ""
|
|||||||
msgid "Get global check"
|
msgid "Get global check"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:221
|
#: src/podkop/tabs/diagnostic/initController.ts:222
|
||||||
msgid "Global check"
|
msgid "Global check"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -366,11 +390,63 @@ msgstr ""
|
|||||||
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:76
|
||||||
|
msgid "Invalid HY2 URL: insecure must be 0 or 1"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:62
|
||||||
|
msgid "Invalid HY2 URL: invalid port number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:32
|
||||||
|
msgid "Invalid HY2 URL: missing credentials/server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:49
|
||||||
|
msgid "Invalid HY2 URL: missing host"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:43
|
||||||
|
msgid "Invalid HY2 URL: missing host & port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:38
|
||||||
|
msgid "Invalid HY2 URL: missing password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:53
|
||||||
|
msgid "Invalid HY2 URL: missing port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:19
|
||||||
|
msgid "Invalid HY2 URL: must not contain spaces"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:12
|
||||||
|
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:99
|
||||||
|
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:113
|
||||||
|
msgid "Invalid HY2 URL: parsing failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:106
|
||||||
|
msgid "Invalid HY2 URL: sni cannot be empty"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:88
|
||||||
|
msgid "Invalid HY2 URL: unsupported obfs type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateIp.ts:11
|
#: src/validators/validateIp.ts:11
|
||||||
msgid "Invalid IP address"
|
msgid "Invalid IP address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateOutboundJson.ts:19
|
#: src/validators/validateOutboundJson.ts:9
|
||||||
msgid "Invalid JSON format"
|
msgid "Invalid JSON format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -466,7 +542,8 @@ msgstr ""
|
|||||||
msgid "Invalid Trojan URL: parsing failed"
|
msgid "Invalid Trojan URL: parsing failed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateUrl.ts:18
|
#: src/validators/validateUrl.ts:8
|
||||||
|
#: src/validators/validateUrl.ts:31
|
||||||
msgid "Invalid URL format"
|
msgid "Invalid URL format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -482,19 +559,19 @@ msgstr ""
|
|||||||
msgid "Issues detected"
|
msgid "Issues detected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:452
|
#: src/podkop/tabs/diagnostic/initController.ts:453
|
||||||
msgid "Latest"
|
msgid "Latest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:276
|
||||||
msgid "List Update Frequency"
|
msgid "List Update Frequency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:458
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:522
|
||||||
msgid "Local Domain Lists"
|
msgid "Local Domain Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:481
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:545
|
||||||
msgid "Local Subnet Lists"
|
msgid "Local Subnet Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -502,11 +579,11 @@ msgstr ""
|
|||||||
msgid "Main DNS"
|
msgid "Main DNS"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:308
|
#: src/podkop/tabs/dashboard/initController.ts:311
|
||||||
msgid "Memory Usage"
|
msgid "Memory Usage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:586
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:650
|
||||||
msgid "Mixed Proxy Port"
|
msgid "Mixed Proxy Port"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -514,7 +591,11 @@ msgstr ""
|
|||||||
msgid "Monitored Interfaces"
|
msgid "Monitored Interfaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:120
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:140
|
||||||
|
msgid "Must be a number in the range of 50 - 1000"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:184
|
||||||
msgid "Network Interface"
|
msgid "Network Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -526,10 +607,17 @@ msgstr ""
|
|||||||
msgid "Not implement yet"
|
msgid "Not implement yet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:75
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:81
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:100
|
||||||
|
msgid "Not responding"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:55
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:55
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:63
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:63
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:71
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:71
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:79
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:79
|
||||||
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:87
|
||||||
msgid "Not running"
|
msgid "Not running"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -545,11 +633,7 @@ msgstr ""
|
|||||||
msgid "Outbound Configuration"
|
msgid "Outbound Configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateOutboundJson.ts:11
|
#: src/podkop/tabs/diagnostic/initController.ts:443
|
||||||
msgid "Outbound JSON must contain at least \"type\", \"server\" and \"server_port\" fields"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:442
|
|
||||||
msgid "Outdated"
|
msgid "Outdated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -561,26 +645,27 @@ msgstr ""
|
|||||||
msgid "Path cannot be empty"
|
msgid "Path cannot be empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:347
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366
|
||||||
msgid "Path must be absolute (start with /)"
|
msgid "Path must be absolute (start with /)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:356
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:375
|
||||||
msgid "Path must contain at least one directory (like /tmp/cache.db)"
|
msgid "Path must contain at least one directory (like /tmp/cache.db)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:351
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:370
|
||||||
msgid "Path must end with cache.db"
|
msgid "Path must end with cache.db"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:95
|
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:103
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:103
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:111
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:111
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:119
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:119
|
||||||
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:127
|
||||||
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:135
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:340
|
#: src/podkop/tabs/dashboard/initController.ts:343
|
||||||
msgid "Podkop"
|
msgid "Podkop"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -588,7 +673,7 @@ msgstr ""
|
|||||||
msgid "Podkop Settings"
|
msgid "Podkop Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:308
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:327
|
||||||
msgid "Podkop will not modify your DHCP configuration"
|
msgid "Podkop will not modify your DHCP configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -604,15 +689,15 @@ msgstr ""
|
|||||||
msgid "Proxy traffic is routed via FakeIP"
|
msgid "Proxy traffic is routed via FakeIP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:245
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:309
|
||||||
msgid "Regional options cannot be used together"
|
msgid "Regional options cannot be used together"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:504
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:568
|
||||||
msgid "Remote Domain Lists"
|
msgid "Remote Domain Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:527
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:591
|
||||||
msgid "Remote Subnet Lists"
|
msgid "Remote Subnet Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -628,7 +713,7 @@ msgstr ""
|
|||||||
msgid "Router DNS is routed through sing-box"
|
msgid "Router DNS is routed through sing-box"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:376
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:395
|
||||||
msgid "Routing Excluded IPs"
|
msgid "Routing Excluded IPs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -660,15 +745,19 @@ msgstr ""
|
|||||||
msgid "Run Diagnostic"
|
msgid "Run Diagnostic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:264
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:328
|
||||||
msgid "Russia inside restrictions"
|
msgid "Russia inside restrictions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257
|
||||||
|
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36
|
||||||
msgid "Sections"
|
msgid "Sections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:212
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:276
|
||||||
msgid "Select a predefined list for routing"
|
msgid "Select a predefined list for routing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -680,7 +769,7 @@ msgstr ""
|
|||||||
msgid "Select DNS protocol to use"
|
msgid "Select DNS protocol to use"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:258
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:277
|
||||||
msgid "Select how often the domain or subnet lists are updated automatically"
|
msgid "Select how often the domain or subnet lists are updated automatically"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -688,32 +777,32 @@ msgstr ""
|
|||||||
msgid "Select how to configure the proxy"
|
msgid "Select how to configure the proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:121
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:185
|
||||||
msgid "Select network interface for VPN connection"
|
msgid "Select network interface for VPN connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:190
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:254
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25
|
||||||
msgid "Select or enter DNS server address"
|
msgid "Select or enter DNS server address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:330
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:349
|
||||||
msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing"
|
msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:317
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:336
|
||||||
msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing"
|
msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:177
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:241
|
||||||
msgid "Select the DNS protocol type for the domain resolver"
|
msgid "Select the DNS protocol type for the domain resolver"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:300
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:364
|
||||||
msgid "Select the list type for adding custom domains"
|
msgid "Select the list type for adding custom domains"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:380
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:444
|
||||||
msgid "Select the list type for adding custom subnets"
|
msgid "Select the list type for adding custom subnets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -729,7 +818,7 @@ msgstr ""
|
|||||||
msgid "Select the WAN interfaces to be monitored"
|
msgid "Select the WAN interfaces to be monitored"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:337
|
#: src/podkop/tabs/dashboard/initController.ts:340
|
||||||
msgid "Services info"
|
msgid "Services info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -737,12 +826,12 @@ msgstr ""
|
|||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:289
|
#: src/podkop/tabs/diagnostic/initController.ts:290
|
||||||
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:116
|
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:116
|
||||||
msgid "Show sing-box config"
|
msgid "Show sing-box config"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:351
|
#: src/podkop/tabs/dashboard/initController.ts:354
|
||||||
msgid "Sing-box"
|
msgid "Sing-box"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -767,31 +856,31 @@ msgid "Sing-box service exist"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67
|
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67
|
||||||
msgid "Sing-box version >= 1.12.4"
|
msgid "Sing-box version is compatible (newer than 1.12.4)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89
|
||||||
msgid "Source Network Interface"
|
msgid "Source Network Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:377
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:396
|
||||||
msgid "Specify a local IP address to be excluded from routing"
|
msgid "Specify a local IP address to be excluded from routing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:551
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:615
|
||||||
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
|
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:505
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:569
|
||||||
msgid "Specify remote URLs to download and use domain lists"
|
msgid "Specify remote URLs to download and use domain lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:528
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:592
|
||||||
msgid "Specify remote URLs to download and use subnet lists"
|
msgid "Specify remote URLs to download and use subnet lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:459
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:523
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:482
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:546
|
||||||
msgid "Specify the path to the list file located on the router filesystem"
|
msgid "Specify the path to the list file located on the router filesystem"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -807,7 +896,7 @@ msgstr ""
|
|||||||
msgid "Successfully copied!"
|
msgid "Successfully copied!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:301
|
#: src/podkop/tabs/dashboard/initController.ts:304
|
||||||
msgid "System info"
|
msgid "System info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -823,27 +912,36 @@ msgstr ""
|
|||||||
msgid "Test latency"
|
msgid "Test latency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:304
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:368
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:448
|
||||||
msgid "Text List"
|
msgid "Text List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:384
|
|
||||||
msgid "Text List (comma/space/newline separated)"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46
|
||||||
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111
|
||||||
|
msgid "The interval between connectivity tests"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:124
|
||||||
|
msgid "The maximum difference in response times (ms) allowed when comparing servers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:147
|
||||||
|
msgid "The URL used to test server connectivity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69
|
||||||
msgid "Time in seconds for DNS record caching (default: 60)"
|
msgid "Time in seconds for DNS record caching (default: 60)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:235
|
#: src/podkop/tabs/dashboard/initController.ts:238
|
||||||
msgid "Traffic"
|
msgid "Traffic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:265
|
#: src/podkop/tabs/dashboard/initController.ts:268
|
||||||
msgid "Traffic Total"
|
msgid "Traffic Total"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -859,22 +957,22 @@ msgstr ""
|
|||||||
msgid "TTL value cannot be empty"
|
msgid "TTL value cannot be empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:181
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:245
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17
|
||||||
msgid "UDP (Unprotected DNS)"
|
msgid "UDP (Unprotected DNS)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:174
|
||||||
msgid "UDP over TCP"
|
msgid "UDP over TCP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:37
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:38
|
#: src/podkop/tabs/diagnostic/initController.ts:38
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:39
|
#: src/podkop/tabs/diagnostic/initController.ts:39
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:40
|
#: src/podkop/tabs/diagnostic/initController.ts:40
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:41
|
#: src/podkop/tabs/diagnostic/initController.ts:41
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:42
|
#: src/podkop/tabs/diagnostic/initController.ts:42
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:416
|
#: src/podkop/tabs/diagnostic/initController.ts:43
|
||||||
|
#: src/podkop/tabs/diagnostic/initController.ts:417
|
||||||
msgid "unknown"
|
msgid "unknown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -882,16 +980,16 @@ msgstr ""
|
|||||||
msgid "Unknown error"
|
msgid "Unknown error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:237
|
#: src/podkop/tabs/dashboard/initController.ts:240
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:268
|
#: src/podkop/tabs/dashboard/initController.ts:271
|
||||||
msgid "Uplink"
|
msgid "Uplink"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateProxyUrl.ts:29
|
#: src/validators/validateProxyUrl.ts:37
|
||||||
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://"
|
msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateUrl.ts:13
|
#: src/validators/validateUrl.ts:17
|
||||||
msgid "URL must use one of the following protocols:"
|
msgid "URL must use one of the following protocols:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -899,31 +997,43 @@ msgstr ""
|
|||||||
msgid "URLTest"
|
msgid "URLTest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110
|
||||||
|
msgid "URLTest Check Interval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87
|
||||||
msgid "URLTest Proxy Links"
|
msgid "URLTest Proxy Links"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:299
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:146
|
||||||
|
msgid "URLTest Testing URL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:123
|
||||||
|
msgid "URLTest Tolerance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:363
|
||||||
msgid "User Domain List Type"
|
msgid "User Domain List Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:311
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:375
|
||||||
msgid "User Domains"
|
msgid "User Domains"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:337
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:401
|
||||||
msgid "User Domains List"
|
msgid "User Domains List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:379
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:443
|
||||||
msgid "User Subnet List Type"
|
msgid "User Subnet List Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:391
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:455
|
||||||
msgid "User Subnets"
|
msgid "User Subnets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:417
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:481
|
||||||
msgid "User Subnets List"
|
msgid "User Subnets List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -931,24 +1041,25 @@ msgstr ""
|
|||||||
#: src/validators/validateDns.ts:18
|
#: src/validators/validateDns.ts:18
|
||||||
#: src/validators/validateDomain.ts:13
|
#: src/validators/validateDomain.ts:13
|
||||||
#: src/validators/validateDomain.ts:30
|
#: src/validators/validateDomain.ts:30
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:111
|
||||||
#: src/validators/validateIp.ts:8
|
#: src/validators/validateIp.ts:8
|
||||||
#: src/validators/validateOutboundJson.ts:17
|
#: src/validators/validateOutboundJson.ts:7
|
||||||
#: src/validators/validatePath.ts:16
|
#: src/validators/validatePath.ts:16
|
||||||
#: src/validators/validateShadowsocksUrl.ts:95
|
#: src/validators/validateShadowsocksUrl.ts:95
|
||||||
#: src/validators/validateSocksUrl.ts:80
|
#: src/validators/validateSocksUrl.ts:80
|
||||||
#: src/validators/validateSubnet.ts:38
|
#: src/validators/validateSubnet.ts:38
|
||||||
#: src/validators/validateTrojanUrl.ts:59
|
#: src/validators/validateTrojanUrl.ts:59
|
||||||
#: src/validators/validateUrl.ts:16
|
#: src/validators/validateUrl.ts:28
|
||||||
#: src/validators/validateVlessUrl.ts:108
|
#: src/validators/validateVlessUrl.ts:108
|
||||||
msgid "Valid"
|
msgid "Valid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:370
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:434
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:449
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:513
|
||||||
msgid "Validation errors:"
|
msgid "Validation errors:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:255
|
#: src/podkop/tabs/diagnostic/initController.ts:256
|
||||||
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:107
|
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:107
|
||||||
msgid "View logs"
|
msgid "View logs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -957,14 +1068,18 @@ msgstr ""
|
|||||||
msgid "Visit Wiki"
|
msgid "Visit Wiki"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:247
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:311
|
||||||
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
|
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:266
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:330
|
||||||
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:256
|
||||||
|
msgid "YACD Secret Key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127
|
||||||
msgid "You can select Output Network Interface, by default autodetect"
|
msgid "You can select Output Network Interface, by default autodetect"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PODKOP\n"
|
"Project-Id-Version: PODKOP\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-23 20:43+0300\n"
|
"POT-Creation-Date: 2025-12-01 16:30+0200\n"
|
||||||
"PO-Revision-Date: 2025-10-23 20:43+0300\n"
|
"PO-Revision-Date: 2025-12-01 16:30+0200\n"
|
||||||
"Last-Translator: divocat\n"
|
"Last-Translator: divocat\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -35,6 +35,9 @@ msgstr "Активные соединения"
|
|||||||
msgid "Additional marking rules found"
|
msgid "Additional marking rules found"
|
||||||
msgstr "Найдены дополнительные правила маркировки"
|
msgstr "Найдены дополнительные правила маркировки"
|
||||||
|
|
||||||
|
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
|
||||||
|
msgstr "Обеспечивает доступ к YACD из WAN. Убедитесь, что в брандмауэре открыт соответствующий порт."
|
||||||
|
|
||||||
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
||||||
msgstr "Применимо для SOCKS и Shadowsocks прокси"
|
msgstr "Применимо для SOCKS и Shadowsocks прокси"
|
||||||
|
|
||||||
@@ -182,9 +185,6 @@ msgstr "Скачивать списки через Proxy/VPN"
|
|||||||
msgid "Download Lists via specific proxy section"
|
msgid "Download Lists via specific proxy section"
|
||||||
msgstr "Скачивать списки через выбранную секцию"
|
msgstr "Скачивать списки через выбранную секцию"
|
||||||
|
|
||||||
msgid "Downloading all lists via main Proxy/VPN"
|
|
||||||
msgstr "Загрузка всех списков через основной прокси/VPN"
|
|
||||||
|
|
||||||
msgid "Downloading all lists via specific Proxy/VPN"
|
msgid "Downloading all lists via specific Proxy/VPN"
|
||||||
msgstr "Загрузка всех списков через указанный прокси/VPN"
|
msgstr "Загрузка всех списков через указанный прокси/VPN"
|
||||||
|
|
||||||
@@ -209,6 +209,9 @@ msgstr "Включить смешанный прокси-сервер, разр
|
|||||||
msgid "Enable YACD"
|
msgid "Enable YACD"
|
||||||
msgstr "Включить YACD"
|
msgstr "Включить YACD"
|
||||||
|
|
||||||
|
msgid "Enable YACD WAN Access"
|
||||||
|
msgstr "Включить доступ YACD WAN"
|
||||||
|
|
||||||
msgid "Enter complete outbound configuration in JSON format"
|
msgid "Enter complete outbound configuration in JSON format"
|
||||||
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
|
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
|
||||||
|
|
||||||
@@ -221,6 +224,18 @@ msgstr "Введите доменные имена без протоколов,
|
|||||||
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
||||||
msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса"
|
msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса"
|
||||||
|
|
||||||
|
msgid "Every 1 minute"
|
||||||
|
msgstr "Каждую минуту"
|
||||||
|
|
||||||
|
msgid "Every 3 minutes"
|
||||||
|
msgstr "Каждые 3 минуты"
|
||||||
|
|
||||||
|
msgid "Every 30 seconds"
|
||||||
|
msgstr "Каждые 30 секунд"
|
||||||
|
|
||||||
|
msgid "Every 5 minutes"
|
||||||
|
msgstr "Каждые 5 минут"
|
||||||
|
|
||||||
msgid "Exclude NTP"
|
msgid "Exclude NTP"
|
||||||
msgstr "Исключить NTP"
|
msgstr "Исключить NTP"
|
||||||
|
|
||||||
@@ -266,6 +281,45 @@ msgstr "Неверный домен"
|
|||||||
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
||||||
msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y"
|
msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: insecure must be 0 or 1"
|
||||||
|
msgstr "Неверный URL Hysteria2: параметр insecure должен быть 0 или 1"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: invalid port number"
|
||||||
|
msgstr "Неверный URL Hysteria2: неверный номер порта"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing credentials/server"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствуют учетные данные/сервер"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing host"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствует хост"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing host & port"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствуют хост и порт"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing password"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствует пароль"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing port"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствует порт"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: must not contain spaces"
|
||||||
|
msgstr "Неверный URL Hysteria2: не должен содержать пробелов"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
|
||||||
|
msgstr "Неверный URL Hysteria2: должен начинаться с hysteria2:// или hy2://"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
|
||||||
|
msgstr "Неверный URL Hysteria2: требуется obfs-password, когда установлен obfs"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: parsing failed"
|
||||||
|
msgstr "Неверный URL Hysteria2: ошибка разбора"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: sni cannot be empty"
|
||||||
|
msgstr "Неверный URL Hysteria2: sni не может быть пустым"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: unsupported obfs type"
|
||||||
|
msgstr "Неверный URL Hysteria2: неподдерживаемый тип obfs"
|
||||||
|
|
||||||
msgid "Invalid IP address"
|
msgid "Invalid IP address"
|
||||||
msgstr "Неверный IP-адрес"
|
msgstr "Неверный IP-адрес"
|
||||||
|
|
||||||
@@ -377,6 +431,9 @@ msgstr "Порт смешанного прокси"
|
|||||||
msgid "Monitored Interfaces"
|
msgid "Monitored Interfaces"
|
||||||
msgstr "Наблюдаемые интерфейсы"
|
msgstr "Наблюдаемые интерфейсы"
|
||||||
|
|
||||||
|
msgid "Must be a number in the range of 50 - 1000"
|
||||||
|
msgstr "Должно быть числом от 50 до 1000"
|
||||||
|
|
||||||
msgid "Network Interface"
|
msgid "Network Interface"
|
||||||
msgstr "Сетевой интерфейс"
|
msgstr "Сетевой интерфейс"
|
||||||
|
|
||||||
@@ -386,6 +443,9 @@ msgstr "Другие правила маркировки не найдены"
|
|||||||
msgid "Not implement yet"
|
msgid "Not implement yet"
|
||||||
msgstr "Ещё не реализовано"
|
msgstr "Ещё не реализовано"
|
||||||
|
|
||||||
|
msgid "Not responding"
|
||||||
|
msgstr "Не отвечает"
|
||||||
|
|
||||||
msgid "Not running"
|
msgid "Not running"
|
||||||
msgstr "Не запущено"
|
msgstr "Не запущено"
|
||||||
|
|
||||||
@@ -398,9 +458,6 @@ msgstr "Конфигурация Outbound"
|
|||||||
msgid "Outbound Configuration"
|
msgid "Outbound Configuration"
|
||||||
msgstr "Конфигурация исходящего соединения"
|
msgstr "Конфигурация исходящего соединения"
|
||||||
|
|
||||||
msgid "Outbound JSON must contain at least \"type\", \"server\" and \"server_port\" fields"
|
|
||||||
msgstr "JSON должен содержать поля \"type\", \"server\" и \"server_port\""
|
|
||||||
|
|
||||||
msgid "Outdated"
|
msgid "Outdated"
|
||||||
msgstr "Устаревшая"
|
msgstr "Устаревшая"
|
||||||
|
|
||||||
@@ -485,6 +542,9 @@ msgstr "Запустить диагностику"
|
|||||||
msgid "Russia inside restrictions"
|
msgid "Russia inside restrictions"
|
||||||
msgstr "Ограничения Russia inside"
|
msgstr "Ограничения Russia inside"
|
||||||
|
|
||||||
|
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
|
||||||
|
msgstr "Секретный ключ для аутентификации удаленного доступа к YACD при включенном доступе через WAN."
|
||||||
|
|
||||||
msgid "Sections"
|
msgid "Sections"
|
||||||
msgstr "Секции"
|
msgstr "Секции"
|
||||||
|
|
||||||
@@ -560,8 +620,8 @@ msgstr "Процесс sing-box запущен"
|
|||||||
msgid "Sing-box service exist"
|
msgid "Sing-box service exist"
|
||||||
msgstr "Сервис sing-box существует"
|
msgstr "Сервис sing-box существует"
|
||||||
|
|
||||||
msgid "Sing-box version >= 1.12.4"
|
msgid "Sing-box version is compatible (newer than 1.12.4)"
|
||||||
msgstr "Версия sing-box >= 1.12.4"
|
msgstr "Версия Sing-box совместима (новее 1.12.4)"
|
||||||
|
|
||||||
msgid "Source Network Interface"
|
msgid "Source Network Interface"
|
||||||
msgstr "Сетевой интерфейс источника"
|
msgstr "Сетевой интерфейс источника"
|
||||||
@@ -605,12 +665,18 @@ msgstr "Тестирование задержки"
|
|||||||
msgid "Text List"
|
msgid "Text List"
|
||||||
msgstr "Текстовый список"
|
msgstr "Текстовый список"
|
||||||
|
|
||||||
msgid "Text List (comma/space/newline separated)"
|
|
||||||
msgstr "Текстовый список (через запятую, пробел или новую строку)"
|
|
||||||
|
|
||||||
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
||||||
msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера"
|
msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера"
|
||||||
|
|
||||||
|
msgid "The interval between connectivity tests"
|
||||||
|
msgstr "Интервал между тестами подключения"
|
||||||
|
|
||||||
|
msgid "The maximum difference in response times (ms) allowed when comparing servers"
|
||||||
|
msgstr "Максимально допустимая разница во времени отклика (мс) при сравнении серверов"
|
||||||
|
|
||||||
|
msgid "The URL used to test server connectivity"
|
||||||
|
msgstr "URL-адрес, используемый для проверки подключения к серверу"
|
||||||
|
|
||||||
msgid "Time in seconds for DNS record caching (default: 60)"
|
msgid "Time in seconds for DNS record caching (default: 60)"
|
||||||
msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)"
|
msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)"
|
||||||
|
|
||||||
@@ -644,8 +710,8 @@ msgstr "Неизвестная ошибка"
|
|||||||
msgid "Uplink"
|
msgid "Uplink"
|
||||||
msgstr "Исходящий"
|
msgstr "Исходящий"
|
||||||
|
|
||||||
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://"
|
msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
|
||||||
msgstr "URL должен начинаться с vless://, ss://, trojan:// или socks4/5://"
|
msgstr "URL должен начинаться с vless://, ss://, trojan://, socks4/5:// или hysteria2:// hy2://"
|
||||||
|
|
||||||
msgid "URL must use one of the following protocols:"
|
msgid "URL must use one of the following protocols:"
|
||||||
msgstr "URL должен использовать один из следующих протоколов:"
|
msgstr "URL должен использовать один из следующих протоколов:"
|
||||||
@@ -653,9 +719,18 @@ msgstr "URL должен использовать один из следующи
|
|||||||
msgid "URLTest"
|
msgid "URLTest"
|
||||||
msgstr "URLTest"
|
msgstr "URLTest"
|
||||||
|
|
||||||
|
msgid "URLTest Check Interval"
|
||||||
|
msgstr "Интервал проверки URLTest"
|
||||||
|
|
||||||
msgid "URLTest Proxy Links"
|
msgid "URLTest Proxy Links"
|
||||||
msgstr "Ссылки прокси для URLTest"
|
msgstr "Ссылки прокси для URLTest"
|
||||||
|
|
||||||
|
msgid "URLTest Testing URL"
|
||||||
|
msgstr "URLTest ссылка для проверки"
|
||||||
|
|
||||||
|
msgid "URLTest Tolerance"
|
||||||
|
msgstr "URLTest допустимое отклонение"
|
||||||
|
|
||||||
msgid "User Domain List Type"
|
msgid "User Domain List Type"
|
||||||
msgstr "Тип пользовательского списка доменов"
|
msgstr "Тип пользовательского списка доменов"
|
||||||
|
|
||||||
@@ -692,5 +767,8 @@ msgstr "Предупреждение: %s нельзя использовать
|
|||||||
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
||||||
msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных."
|
msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных."
|
||||||
|
|
||||||
|
msgid "YACD Secret Key"
|
||||||
|
msgstr "Секретный ключ YACD"
|
||||||
|
|
||||||
msgid "You can select Output Network Interface, by default autodetect"
|
msgid "You can select Output Network Interface, by default autodetect"
|
||||||
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически."
|
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически."
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
'require uci';
|
'require uci';
|
||||||
'require ui';
|
'require ui';
|
||||||
|
|
||||||
|
if (typeof structuredClone !== 'function')
|
||||||
|
globalThis.structuredClone = (obj) => JSON.parse(JSON.stringify(obj));
|
||||||
|
|
||||||
export * from './validators';
|
export * from './validators';
|
||||||
export * from './helpers';
|
export * from './helpers';
|
||||||
export * from './podkop';
|
export * from './podkop';
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { getConfigSections } from './getConfigSections';
|
||||||
|
|
||||||
|
export async function getClashApiSecret() {
|
||||||
|
const sections = await getConfigSections();
|
||||||
|
|
||||||
|
const settings = sections.find((section) => section['.type'] === 'settings');
|
||||||
|
|
||||||
|
return settings?.yacd_secret_key || '';
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import { getConfigSections } from './getConfigSections';
|
import { getConfigSections } from './getConfigSections';
|
||||||
import { getDashboardSections } from './getDashboardSections';
|
import { getDashboardSections } from './getDashboardSections';
|
||||||
|
import { getClashApiSecret } from './getClashApiSecret';
|
||||||
|
|
||||||
export const CustomPodkopMethods = {
|
export const CustomPodkopMethods = {
|
||||||
getConfigSections,
|
getConfigSections,
|
||||||
getDashboardSections,
|
getDashboardSections,
|
||||||
|
getClashApiSecret,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,15 +29,15 @@ export const PodkopShellMethods = {
|
|||||||
Podkop.AvailableClashAPIMethods.GET_PROXIES,
|
Podkop.AvailableClashAPIMethods.GET_PROXIES,
|
||||||
]),
|
]),
|
||||||
getClashApiProxyLatency: async (tag: string) =>
|
getClashApiProxyLatency: async (tag: string) =>
|
||||||
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
callBaseMethod<Podkop.GetClashApiProxyLatency>(
|
||||||
Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY,
|
Podkop.AvailableMethods.CLASH_API,
|
||||||
tag,
|
[Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, tag, '5000'],
|
||||||
]),
|
),
|
||||||
getClashApiGroupLatency: async (tag: string) =>
|
getClashApiGroupLatency: async (tag: string) =>
|
||||||
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
callBaseMethod<Podkop.GetClashApiGroupLatency>(
|
||||||
Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY,
|
Podkop.AvailableMethods.CLASH_API,
|
||||||
tag,
|
[Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, tag, '10000'],
|
||||||
]),
|
),
|
||||||
setClashApiGroupProxy: async (group: string, proxy: string) =>
|
setClashApiGroupProxy: async (group: string, proxy: string) =>
|
||||||
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
callBaseMethod<unknown>(Podkop.AvailableMethods.CLASH_API, [
|
||||||
Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY,
|
Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { CustomPodkopMethods, PodkopShellMethods } from '../../methods';
|
|||||||
import { logger, socket, store, StoreType } from '../../services';
|
import { logger, socket, store, StoreType } from '../../services';
|
||||||
import { renderSections, renderWidget } from './partials';
|
import { renderSections, renderWidget } from './partials';
|
||||||
import { fetchServicesInfo } from '../../fetchers';
|
import { fetchServicesInfo } from '../../fetchers';
|
||||||
|
import { getClashApiSecret } from '../../methods/custom/getClashApiSecret';
|
||||||
|
|
||||||
// Fetchers
|
// Fetchers
|
||||||
|
|
||||||
@@ -38,8 +39,10 @@ async function fetchDashboardSections() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function connectToClashSockets() {
|
async function connectToClashSockets() {
|
||||||
|
const clashApiSecret = await getClashApiSecret();
|
||||||
|
|
||||||
socket.subscribe(
|
socket.subscribe(
|
||||||
`${getClashWsUrl()}/traffic?token=`,
|
`${getClashWsUrl()}/traffic?token=${clashApiSecret}`,
|
||||||
(msg) => {
|
(msg) => {
|
||||||
const parsedMsg = JSON.parse(msg);
|
const parsedMsg = JSON.parse(msg);
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ async function connectToClashSockets() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
socket.subscribe(
|
socket.subscribe(
|
||||||
`${getClashWsUrl()}/connections?token=`,
|
`${getClashWsUrl()}/connections?token=${clashApiSecret}`,
|
||||||
(msg) => {
|
(msg) => {
|
||||||
const parsedMsg = JSON.parse(msg);
|
const parsedMsg = JSON.parse(msg);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export enum DIAGNOSTICS_CHECKS {
|
|||||||
SINGBOX = 'SINGBOX',
|
SINGBOX = 'SINGBOX',
|
||||||
NFT = 'NFT',
|
NFT = 'NFT',
|
||||||
FAKEIP = 'FAKEIP',
|
FAKEIP = 'FAKEIP',
|
||||||
|
OUTBOUNDS = 'OUTBOUNDS',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DIAGNOSTICS_CHECKS_MAP: Record<
|
export const DIAGNOSTICS_CHECKS_MAP: Record<
|
||||||
@@ -26,8 +27,13 @@ export const DIAGNOSTICS_CHECKS_MAP: Record<
|
|||||||
title: getCheckTitle('Nftables'),
|
title: getCheckTitle('Nftables'),
|
||||||
code: DIAGNOSTICS_CHECKS.NFT,
|
code: DIAGNOSTICS_CHECKS.NFT,
|
||||||
},
|
},
|
||||||
[DIAGNOSTICS_CHECKS.FAKEIP]: {
|
[DIAGNOSTICS_CHECKS.OUTBOUNDS]: {
|
||||||
order: 4,
|
order: 4,
|
||||||
|
title: getCheckTitle('Outbounds'),
|
||||||
|
code: DIAGNOSTICS_CHECKS.OUTBOUNDS,
|
||||||
|
},
|
||||||
|
[DIAGNOSTICS_CHECKS.FAKEIP]: {
|
||||||
|
order: 5,
|
||||||
title: getCheckTitle('FakeIP'),
|
title: getCheckTitle('FakeIP'),
|
||||||
code: DIAGNOSTICS_CHECKS.FAKEIP,
|
code: DIAGNOSTICS_CHECKS.FAKEIP,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import { DIAGNOSTICS_CHECKS_MAP } from './contstants';
|
||||||
|
import { PodkopShellMethods } from '../../../methods';
|
||||||
|
import { updateCheckStore } from './updateCheckStore';
|
||||||
|
import { getMeta } from '../helpers/getMeta';
|
||||||
|
import { getDashboardSections } from '../../../methods/custom/getDashboardSections';
|
||||||
|
import { IDiagnosticsChecksItem } from '../../../services';
|
||||||
|
|
||||||
|
export async function runSectionsCheck() {
|
||||||
|
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS;
|
||||||
|
|
||||||
|
updateCheckStore({
|
||||||
|
order,
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description: _('Checking, please wait'),
|
||||||
|
state: 'loading',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const sections = await getDashboardSections();
|
||||||
|
|
||||||
|
if (!sections.success) {
|
||||||
|
updateCheckStore({
|
||||||
|
order,
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description: _('Cannot receive checks result'),
|
||||||
|
state: 'error',
|
||||||
|
items: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
throw new Error('Sections checks failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = (await Promise.all(
|
||||||
|
sections.data.map(async (section) => {
|
||||||
|
async function getLatency() {
|
||||||
|
if (section.withTagSelect) {
|
||||||
|
const latencyGroup = await PodkopShellMethods.getClashApiGroupLatency(
|
||||||
|
section.code,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedOutbound = section.outbounds.find(
|
||||||
|
(item) => item.selected,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isUrlTest = selectedOutbound?.type === 'URLTest';
|
||||||
|
|
||||||
|
const success = latencyGroup.success && !latencyGroup.data.message;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
if (isUrlTest) {
|
||||||
|
const latency = Object.values(latencyGroup.data)
|
||||||
|
.map((item) => (item ? `${item}ms` : 'n/a'))
|
||||||
|
.join(' / ');
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
latency: `[${_('Fastest')}] ${latency}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedProxyDelay =
|
||||||
|
latencyGroup.data?.[selectedOutbound?.code ?? ''];
|
||||||
|
|
||||||
|
if (selectedProxyDelay) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
latency: `[${selectedOutbound?.displayName ?? ''}] ${selectedProxyDelay}ms`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
latency: `[${selectedOutbound?.displayName ?? ''}] ${_('Not responding')}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
latency: _('Not responding'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const latencyProxy = await PodkopShellMethods.getClashApiProxyLatency(
|
||||||
|
section.code,
|
||||||
|
);
|
||||||
|
|
||||||
|
const success = latencyProxy.success && !latencyProxy.data.message;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
latency: `${latencyProxy.data.delay} ms`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
latency: _('Not responding'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { latency, success } = await getLatency();
|
||||||
|
|
||||||
|
return {
|
||||||
|
state: success ? 'success' : 'error',
|
||||||
|
key: section.displayName,
|
||||||
|
value: latency,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
)) as Array<IDiagnosticsChecksItem>;
|
||||||
|
|
||||||
|
const allGood = items.every((item) => item.state === 'success');
|
||||||
|
|
||||||
|
const atLeastOneGood = items.some((item) => item.state === 'success');
|
||||||
|
|
||||||
|
const { state, description } = getMeta({ atLeastOneGood, allGood });
|
||||||
|
|
||||||
|
updateCheckStore({
|
||||||
|
order,
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
items,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error('Sections checks failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,7 +64,7 @@ export async function runSingBoxCheck() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
state: data.sing_box_version_ok ? 'success' : 'error',
|
state: data.sing_box_version_ok ? 'success' : 'error',
|
||||||
key: _('Sing-box version >= 1.12.4'),
|
key: _('Sing-box version is compatible (newer than 1.12.4)'),
|
||||||
value: '',
|
value: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -72,6 +72,14 @@ export const initialDiagnosticStore: Pick<
|
|||||||
items: [],
|
items: [],
|
||||||
state: 'skipped',
|
state: 'skipped',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: DIAGNOSTICS_CHECKS.OUTBOUNDS,
|
||||||
|
title: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.title,
|
||||||
|
order: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.order,
|
||||||
|
description: _('Not running'),
|
||||||
|
items: [],
|
||||||
|
state: 'skipped',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: DIAGNOSTICS_CHECKS.FAKEIP,
|
code: DIAGNOSTICS_CHECKS.FAKEIP,
|
||||||
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
||||||
@@ -112,6 +120,14 @@ export const loadingDiagnosticsChecksStore: Pick<
|
|||||||
items: [],
|
items: [],
|
||||||
state: 'skipped',
|
state: 'skipped',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: DIAGNOSTICS_CHECKS.OUTBOUNDS,
|
||||||
|
title: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.title,
|
||||||
|
order: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.order,
|
||||||
|
description: _('Pending'),
|
||||||
|
items: [],
|
||||||
|
state: 'skipped',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: DIAGNOSTICS_CHECKS.FAKEIP,
|
code: DIAGNOSTICS_CHECKS.FAKEIP,
|
||||||
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { renderModal } from '../../../partials';
|
|||||||
import { PODKOP_LUCI_APP_VERSION } from '../../../constants';
|
import { PODKOP_LUCI_APP_VERSION } from '../../../constants';
|
||||||
import { showToast } from '../../../helpers/showToast';
|
import { showToast } from '../../../helpers/showToast';
|
||||||
import { renderWikiDisclaimer } from './partials/renderWikiDisclaimer';
|
import { renderWikiDisclaimer } from './partials/renderWikiDisclaimer';
|
||||||
|
import { runSectionsCheck } from './checks/runSectionsCheck';
|
||||||
|
|
||||||
async function fetchSystemInfo() {
|
async function fetchSystemInfo() {
|
||||||
const systemInfo = await PodkopShellMethods.getSystemInfo();
|
const systemInfo = await PodkopShellMethods.getSystemInfo();
|
||||||
@@ -414,9 +415,9 @@ function renderDiagnosticSystemInfoWidget() {
|
|||||||
function getPodkopVersionRow(): IRenderSystemInfoRow {
|
function getPodkopVersionRow(): IRenderSystemInfoRow {
|
||||||
const loading = diagnosticsSystemInfo.loading;
|
const loading = diagnosticsSystemInfo.loading;
|
||||||
const unknown = diagnosticsSystemInfo.podkop_version === _('unknown');
|
const unknown = diagnosticsSystemInfo.podkop_version === _('unknown');
|
||||||
const hasActualVersion = Boolean(
|
const hasActualVersion =
|
||||||
diagnosticsSystemInfo.podkop_latest_version,
|
Boolean(diagnosticsSystemInfo.podkop_latest_version) &&
|
||||||
);
|
diagnosticsSystemInfo.podkop_latest_version !== 'unknown';
|
||||||
const version = normalizeCompiledVersion(
|
const version = normalizeCompiledVersion(
|
||||||
diagnosticsSystemInfo.podkop_version,
|
diagnosticsSystemInfo.podkop_version,
|
||||||
);
|
);
|
||||||
@@ -518,6 +519,8 @@ async function runChecks() {
|
|||||||
|
|
||||||
await runNftCheck();
|
await runNftCheck();
|
||||||
|
|
||||||
|
await runSectionsCheck();
|
||||||
|
|
||||||
await runFakeIPCheck();
|
await runFakeIPCheck();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('[DIAGNOSTIC]', 'runChecks - e', e);
|
logger.error('[DIAGNOSTIC]', 'runChecks - e', e);
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ export namespace Podkop {
|
|||||||
export type ConfigSection = ConfigBaseSection & {
|
export type ConfigSection = ConfigBaseSection & {
|
||||||
'.name': string;
|
'.name': string;
|
||||||
'.type': 'settings' | 'section';
|
'.type': 'settings' | 'section';
|
||||||
|
yacd_secret_key?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface MethodSuccessResponse<T> {
|
export interface MethodSuccessResponse<T> {
|
||||||
@@ -196,4 +197,11 @@ export namespace Podkop {
|
|||||||
openwrt_version: string;
|
openwrt_version: string;
|
||||||
device_model: string;
|
device_model: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetClashApiProxyLatency {
|
||||||
|
delay: number;
|
||||||
|
message?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetClashApiGroupLatency = Record<string, number>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { validateHysteria2Url } from '../validateHysteriaUrl.js';
|
||||||
|
|
||||||
|
const validUrls = [
|
||||||
|
// Basic password-only
|
||||||
|
['password basic', 'hysteria2://pass@example.com:443/#hy2-basic'],
|
||||||
|
|
||||||
|
// insecure=1
|
||||||
|
[
|
||||||
|
'insecure allowed',
|
||||||
|
'hysteria2://pass@example.com:443/?insecure=1#hy2-insecure',
|
||||||
|
],
|
||||||
|
|
||||||
|
// SNI
|
||||||
|
['SNI param', 'hysteria2://pass@example.com:443/?sni=google.com#hy2-sni'],
|
||||||
|
|
||||||
|
// Obfuscation
|
||||||
|
[
|
||||||
|
'Obfs + password',
|
||||||
|
'hysteria2://mypassword@1.1.1.1:8443/?obfs=salamander&obfs-password=abc123#hy2-obfs',
|
||||||
|
],
|
||||||
|
|
||||||
|
// All params
|
||||||
|
[
|
||||||
|
'All options combined',
|
||||||
|
'hysteria2://pw@8.8.8.8:8443/?sni=example.com&obfs=salamander&obfs-password=hello&insecure=1#hy2-full',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Explicit obfs=none (valid)
|
||||||
|
['obfs none = ok', 'hysteria2://pw@example.com:443/?obfs=none#hy2-none'],
|
||||||
|
];
|
||||||
|
|
||||||
|
const invalidUrls = [
|
||||||
|
['No prefix', 'pw@example.com:443'],
|
||||||
|
['Missing password', 'hysteria2://@example.com:443/'],
|
||||||
|
['Missing host', 'hysteria2://pw@:443/'],
|
||||||
|
['Missing port', 'hysteria2://pw@example.com/'],
|
||||||
|
['Non-numeric port', 'hysteria2://pw@example.com:port/'],
|
||||||
|
['Port out of range', 'hysteria2://pw@example.com:99999/'],
|
||||||
|
|
||||||
|
// Obfuscation errors
|
||||||
|
['Unknown obfs type', 'hysteria2://pw@example.com:443/?obfs=weird'],
|
||||||
|
[
|
||||||
|
'obfs without obfs-password',
|
||||||
|
'hysteria2://pw@example.com:443/?obfs=salamander',
|
||||||
|
],
|
||||||
|
|
||||||
|
// insecure only accepts 0/1
|
||||||
|
['invalid insecure', 'hysteria2://pw@example.com:443/?insecure=5'],
|
||||||
|
|
||||||
|
// SNI empty
|
||||||
|
['empty sni', 'hysteria2://pw@example.com:443/?sni='],
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('validateHysteria2Url', () => {
|
||||||
|
describe.each(validUrls)('Valid HY2 URL: %s', (_desc, url) => {
|
||||||
|
it(`returns valid=true for "${url}"`, () => {
|
||||||
|
const res = validateHysteria2Url(url);
|
||||||
|
expect(res.valid).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe.each(invalidUrls)('Invalid HY2 URL: %s', (_desc, url) => {
|
||||||
|
it(`returns valid=false for "${url}"`, () => {
|
||||||
|
const res = validateHysteria2Url(url);
|
||||||
|
expect(res.valid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('detects invalid port range', () => {
|
||||||
|
const res = validateHysteria2Url('hysteria2://pw@example.com:70000/');
|
||||||
|
expect(res.valid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -16,6 +16,7 @@ const invalidUrls = [
|
|||||||
['Unsupported protocol (ftp)', 'ftp://example.com'],
|
['Unsupported protocol (ftp)', 'ftp://example.com'],
|
||||||
['Unsupported protocol (ws)', 'ws://example.com'],
|
['Unsupported protocol (ws)', 'ws://example.com'],
|
||||||
['Empty string', ''],
|
['Empty string', ''],
|
||||||
|
['Without tld', 'https://google'],
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('validateUrl', () => {
|
describe('validateUrl', () => {
|
||||||
|
|||||||
117
fe-app-podkop/src/validators/validateHysteriaUrl.ts
Normal file
117
fe-app-podkop/src/validators/validateHysteriaUrl.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import { ValidationResult } from './types';
|
||||||
|
import { parseQueryString } from '../helpers/parseQueryString';
|
||||||
|
|
||||||
|
export function validateHysteria2Url(url: string): ValidationResult {
|
||||||
|
try {
|
||||||
|
const isHY2 = url.startsWith('hysteria2://');
|
||||||
|
const isHY2Short = url.startsWith('hy2://');
|
||||||
|
|
||||||
|
if (!isHY2 && !isHY2Short) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: must start with hysteria2:// or hy2://'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/\s/.test(url)) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: must not contain spaces'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = isHY2 ? 'hysteria2://' : 'hy2://';
|
||||||
|
const body = url.slice(prefix.length);
|
||||||
|
|
||||||
|
const [mainPart] = body.split('#');
|
||||||
|
const [authHostPort, queryString] = mainPart.split('?');
|
||||||
|
|
||||||
|
if (!authHostPort)
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: missing credentials/server'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const [passwordPart, hostPortPart] = authHostPort.split('@');
|
||||||
|
|
||||||
|
if (!passwordPart)
|
||||||
|
return { valid: false, message: _('Invalid HY2 URL: missing password') };
|
||||||
|
|
||||||
|
if (!hostPortPart)
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: missing host & port'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const [host, port] = hostPortPart.split(':');
|
||||||
|
|
||||||
|
if (!host) {
|
||||||
|
return { valid: false, message: _('Invalid HY2 URL: missing host') };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!port) {
|
||||||
|
return { valid: false, message: _('Invalid HY2 URL: missing port') };
|
||||||
|
}
|
||||||
|
|
||||||
|
const cleanedPort = port.replace('/', '');
|
||||||
|
const portNum = Number(cleanedPort);
|
||||||
|
|
||||||
|
if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: invalid port number'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryString) {
|
||||||
|
const params = parseQueryString(queryString);
|
||||||
|
const paramsKeys = Object.keys(params);
|
||||||
|
|
||||||
|
if (
|
||||||
|
paramsKeys.includes('insecure') &&
|
||||||
|
!['0', '1'].includes(params.insecure)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: insecure must be 0 or 1'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const validObfsTypes = ['none', 'salamander'];
|
||||||
|
|
||||||
|
if (
|
||||||
|
paramsKeys.includes('obfs') &&
|
||||||
|
!validObfsTypes.includes(params.obfs)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: unsupported obfs type'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
paramsKeys.includes('obfs') &&
|
||||||
|
params.obfs !== 'none' &&
|
||||||
|
!params['obfs-password']
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _(
|
||||||
|
'Invalid HY2 URL: obfs-password required when obfs is set',
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paramsKeys.includes('sni') && !params.sni) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _('Invalid HY2 URL: sni cannot be empty'),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: true, message: _('Valid') };
|
||||||
|
} catch (_e) {
|
||||||
|
return { valid: false, message: _('Invalid HY2 URL: parsing failed') };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,8 @@
|
|||||||
import { ValidationResult } from './types';
|
import { ValidationResult } from './types';
|
||||||
|
|
||||||
// TODO refactor current validation and add tests
|
|
||||||
export function validateOutboundJson(value: string): ValidationResult {
|
export function validateOutboundJson(value: string): ValidationResult {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(value);
|
JSON.parse(value);
|
||||||
|
|
||||||
if (!parsed.type || !parsed.server || !parsed.server_port) {
|
|
||||||
return {
|
|
||||||
valid: false,
|
|
||||||
message: _(
|
|
||||||
'Outbound JSON must contain at least "type", "server" and "server_port" fields',
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { valid: true, message: _('Valid') };
|
return { valid: true, message: _('Valid') };
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { validateShadowsocksUrl } from './validateShadowsocksUrl';
|
|||||||
import { validateVlessUrl } from './validateVlessUrl';
|
import { validateVlessUrl } from './validateVlessUrl';
|
||||||
import { validateTrojanUrl } from './validateTrojanUrl';
|
import { validateTrojanUrl } from './validateTrojanUrl';
|
||||||
import { validateSocksUrl } from './validateSocksUrl';
|
import { validateSocksUrl } from './validateSocksUrl';
|
||||||
|
import { validateHysteria2Url } from './validateHysteriaUrl';
|
||||||
|
|
||||||
// TODO refactor current validation and add tests
|
// TODO refactor current validation and add tests
|
||||||
export function validateProxyUrl(url: string): ValidationResult {
|
export function validateProxyUrl(url: string): ValidationResult {
|
||||||
@@ -24,10 +25,17 @@ export function validateProxyUrl(url: string): ValidationResult {
|
|||||||
return validateSocksUrl(trimmedUrl);
|
return validateSocksUrl(trimmedUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
trimmedUrl.startsWith('hysteria2://') ||
|
||||||
|
trimmedUrl.startsWith('hy2://')
|
||||||
|
) {
|
||||||
|
return validateHysteria2Url(trimmedUrl);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
message: _(
|
message: _(
|
||||||
'URL must start with vless://, ss://, trojan://, or socks4/5://',
|
'URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://',
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,31 @@ import { ValidationResult } from './types';
|
|||||||
|
|
||||||
export function validateUrl(
|
export function validateUrl(
|
||||||
url: string,
|
url: string,
|
||||||
protocols: string[] = ['http:', 'https:'],
|
protocols = ['http:', 'https:'],
|
||||||
): ValidationResult {
|
): ValidationResult {
|
||||||
try {
|
if (!url.length) {
|
||||||
const parsedUrl = new URL(url);
|
|
||||||
|
|
||||||
if (!protocols.includes(parsedUrl.protocol)) {
|
|
||||||
return {
|
|
||||||
valid: false,
|
|
||||||
message: `${_('URL must use one of the following protocols:')} ${protocols.join(', ')}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return { valid: true, message: _('Valid') };
|
|
||||||
} catch (_e) {
|
|
||||||
return { valid: false, message: _('Invalid URL format') };
|
return { valid: false, message: _('Invalid URL format') };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasValidProtocol = protocols.some((p) => url.indexOf(p + '//') === 0);
|
||||||
|
|
||||||
|
if (!hasValidProtocol)
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message:
|
||||||
|
_('URL must use one of the following protocols:') +
|
||||||
|
' ' +
|
||||||
|
protocols.join(', '),
|
||||||
|
};
|
||||||
|
|
||||||
|
const regex = new RegExp(
|
||||||
|
`^(?:${protocols.map((p) => p.replace(':', '')).join('|')})://` +
|
||||||
|
`(?:[A-Za-z0-9-]+\\.)+[A-Za-z]{2,}(?::\\d+)?(?:/[^\\s]*)?$`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (regex.test(url)) {
|
||||||
|
return { valid: true, message: _('Valid') };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: false, message: _('Invalid URL format') };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,18 +58,22 @@ function validateDNS(value) {
|
|||||||
|
|
||||||
// src/validators/validateUrl.ts
|
// src/validators/validateUrl.ts
|
||||||
function validateUrl(url, protocols = ["http:", "https:"]) {
|
function validateUrl(url, protocols = ["http:", "https:"]) {
|
||||||
try {
|
if (!url.length) {
|
||||||
const parsedUrl = new URL(url);
|
|
||||||
if (!protocols.includes(parsedUrl.protocol)) {
|
|
||||||
return {
|
|
||||||
valid: false,
|
|
||||||
message: `${_("URL must use one of the following protocols:")} ${protocols.join(", ")}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return { valid: true, message: _("Valid") };
|
|
||||||
} catch (_e) {
|
|
||||||
return { valid: false, message: _("Invalid URL format") };
|
return { valid: false, message: _("Invalid URL format") };
|
||||||
}
|
}
|
||||||
|
const hasValidProtocol = protocols.some((p) => url.indexOf(p + "//") === 0);
|
||||||
|
if (!hasValidProtocol)
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("URL must use one of the following protocols:") + " " + protocols.join(", ")
|
||||||
|
};
|
||||||
|
const regex = new RegExp(
|
||||||
|
`^(?:${protocols.map((p) => p.replace(":", "")).join("|")})://(?:[A-Za-z0-9-]+\\.)+[A-Za-z]{2,}(?::\\d+)?(?:/[^\\s]*)?$`
|
||||||
|
);
|
||||||
|
if (regex.test(url)) {
|
||||||
|
return { valid: true, message: _("Valid") };
|
||||||
|
}
|
||||||
|
return { valid: false, message: _("Invalid URL format") };
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/validators/validatePath.ts
|
// src/validators/validatePath.ts
|
||||||
@@ -323,15 +327,7 @@ function validateVlessUrl(url) {
|
|||||||
// src/validators/validateOutboundJson.ts
|
// src/validators/validateOutboundJson.ts
|
||||||
function validateOutboundJson(value) {
|
function validateOutboundJson(value) {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(value);
|
JSON.parse(value);
|
||||||
if (!parsed.type || !parsed.server || !parsed.server_port) {
|
|
||||||
return {
|
|
||||||
valid: false,
|
|
||||||
message: _(
|
|
||||||
'Outbound JSON must contain at least "type", "server" and "server_port" fields'
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return { valid: true, message: _("Valid") };
|
return { valid: true, message: _("Valid") };
|
||||||
} catch {
|
} catch {
|
||||||
return { valid: false, message: _("Invalid JSON format") };
|
return { valid: false, message: _("Invalid JSON format") };
|
||||||
@@ -452,6 +448,92 @@ function validateSocksUrl(url) {
|
|||||||
return { valid: true, message: _("Valid") };
|
return { valid: true, message: _("Valid") };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/validators/validateHysteriaUrl.ts
|
||||||
|
function validateHysteria2Url(url) {
|
||||||
|
try {
|
||||||
|
const isHY2 = url.startsWith("hysteria2://");
|
||||||
|
const isHY2Short = url.startsWith("hy2://");
|
||||||
|
if (!isHY2 && !isHY2Short) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: must start with hysteria2:// or hy2://")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (/\s/.test(url)) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: must not contain spaces")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const prefix = isHY2 ? "hysteria2://" : "hy2://";
|
||||||
|
const body = url.slice(prefix.length);
|
||||||
|
const [mainPart] = body.split("#");
|
||||||
|
const [authHostPort, queryString] = mainPart.split("?");
|
||||||
|
if (!authHostPort)
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: missing credentials/server")
|
||||||
|
};
|
||||||
|
const [passwordPart, hostPortPart] = authHostPort.split("@");
|
||||||
|
if (!passwordPart)
|
||||||
|
return { valid: false, message: _("Invalid HY2 URL: missing password") };
|
||||||
|
if (!hostPortPart)
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: missing host & port")
|
||||||
|
};
|
||||||
|
const [host, port] = hostPortPart.split(":");
|
||||||
|
if (!host) {
|
||||||
|
return { valid: false, message: _("Invalid HY2 URL: missing host") };
|
||||||
|
}
|
||||||
|
if (!port) {
|
||||||
|
return { valid: false, message: _("Invalid HY2 URL: missing port") };
|
||||||
|
}
|
||||||
|
const cleanedPort = port.replace("/", "");
|
||||||
|
const portNum = Number(cleanedPort);
|
||||||
|
if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: invalid port number")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (queryString) {
|
||||||
|
const params = parseQueryString(queryString);
|
||||||
|
const paramsKeys = Object.keys(params);
|
||||||
|
if (paramsKeys.includes("insecure") && !["0", "1"].includes(params.insecure)) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: insecure must be 0 or 1")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const validObfsTypes = ["none", "salamander"];
|
||||||
|
if (paramsKeys.includes("obfs") && !validObfsTypes.includes(params.obfs)) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: unsupported obfs type")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (paramsKeys.includes("obfs") && params.obfs !== "none" && !params["obfs-password"]) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _(
|
||||||
|
"Invalid HY2 URL: obfs-password required when obfs is set"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (paramsKeys.includes("sni") && !params.sni) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: _("Invalid HY2 URL: sni cannot be empty")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { valid: true, message: _("Valid") };
|
||||||
|
} catch (_e) {
|
||||||
|
return { valid: false, message: _("Invalid HY2 URL: parsing failed") };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// src/validators/validateProxyUrl.ts
|
// src/validators/validateProxyUrl.ts
|
||||||
function validateProxyUrl(url) {
|
function validateProxyUrl(url) {
|
||||||
const trimmedUrl = url.trim();
|
const trimmedUrl = url.trim();
|
||||||
@@ -467,10 +549,13 @@ function validateProxyUrl(url) {
|
|||||||
if (/^socks(4|4a|5):\/\//.test(trimmedUrl)) {
|
if (/^socks(4|4a|5):\/\//.test(trimmedUrl)) {
|
||||||
return validateSocksUrl(trimmedUrl);
|
return validateSocksUrl(trimmedUrl);
|
||||||
}
|
}
|
||||||
|
if (trimmedUrl.startsWith("hysteria2://") || trimmedUrl.startsWith("hy2://")) {
|
||||||
|
return validateHysteria2Url(trimmedUrl);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
message: _(
|
message: _(
|
||||||
"URL must start with vless://, ss://, trojan://, or socks4/5://"
|
"URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -563,14 +648,14 @@ var PodkopShellMethods = {
|
|||||||
getClashApiProxies: async () => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
|
getClashApiProxies: async () => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
|
||||||
Podkop.AvailableClashAPIMethods.GET_PROXIES
|
Podkop.AvailableClashAPIMethods.GET_PROXIES
|
||||||
]),
|
]),
|
||||||
getClashApiProxyLatency: async (tag) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
|
getClashApiProxyLatency: async (tag) => callBaseMethod(
|
||||||
Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY,
|
Podkop.AvailableMethods.CLASH_API,
|
||||||
tag
|
[Podkop.AvailableClashAPIMethods.GET_PROXY_LATENCY, tag, "5000"]
|
||||||
]),
|
),
|
||||||
getClashApiGroupLatency: async (tag) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
|
getClashApiGroupLatency: async (tag) => callBaseMethod(
|
||||||
Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY,
|
Podkop.AvailableMethods.CLASH_API,
|
||||||
tag
|
[Podkop.AvailableClashAPIMethods.GET_GROUP_LATENCY, tag, "10000"]
|
||||||
]),
|
),
|
||||||
setClashApiGroupProxy: async (group, proxy) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
|
setClashApiGroupProxy: async (group, proxy) => callBaseMethod(Podkop.AvailableMethods.CLASH_API, [
|
||||||
Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY,
|
Podkop.AvailableClashAPIMethods.SET_GROUP_PROXY,
|
||||||
group,
|
group,
|
||||||
@@ -735,10 +820,18 @@ async function getDashboardSections() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/podkop/methods/custom/getClashApiSecret.ts
|
||||||
|
async function getClashApiSecret() {
|
||||||
|
const sections = await getConfigSections();
|
||||||
|
const settings = sections.find((section) => section[".type"] === "settings");
|
||||||
|
return settings?.yacd_secret_key || "";
|
||||||
|
}
|
||||||
|
|
||||||
// src/podkop/methods/custom/index.ts
|
// src/podkop/methods/custom/index.ts
|
||||||
var CustomPodkopMethods = {
|
var CustomPodkopMethods = {
|
||||||
getConfigSections,
|
getConfigSections,
|
||||||
getDashboardSections
|
getDashboardSections,
|
||||||
|
getClashApiSecret
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/constants.ts
|
// src/constants.ts
|
||||||
@@ -1004,8 +1097,13 @@ var DIAGNOSTICS_CHECKS_MAP = {
|
|||||||
title: getCheckTitle("Nftables"),
|
title: getCheckTitle("Nftables"),
|
||||||
code: "NFT" /* NFT */
|
code: "NFT" /* NFT */
|
||||||
},
|
},
|
||||||
["FAKEIP" /* FAKEIP */]: {
|
["OUTBOUNDS" /* OUTBOUNDS */]: {
|
||||||
order: 4,
|
order: 4,
|
||||||
|
title: getCheckTitle("Outbounds"),
|
||||||
|
code: "OUTBOUNDS" /* OUTBOUNDS */
|
||||||
|
},
|
||||||
|
["FAKEIP" /* FAKEIP */]: {
|
||||||
|
order: 5,
|
||||||
title: getCheckTitle("FakeIP"),
|
title: getCheckTitle("FakeIP"),
|
||||||
code: "FAKEIP" /* FAKEIP */
|
code: "FAKEIP" /* FAKEIP */
|
||||||
}
|
}
|
||||||
@@ -1074,6 +1172,14 @@ var initialDiagnosticStore = {
|
|||||||
items: [],
|
items: [],
|
||||||
state: "skipped"
|
state: "skipped"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: "OUTBOUNDS" /* OUTBOUNDS */,
|
||||||
|
title: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.title,
|
||||||
|
order: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.order,
|
||||||
|
description: _("Not running"),
|
||||||
|
items: [],
|
||||||
|
state: "skipped"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: "FAKEIP" /* FAKEIP */,
|
code: "FAKEIP" /* FAKEIP */,
|
||||||
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
||||||
@@ -1110,6 +1216,14 @@ var loadingDiagnosticsChecksStore = {
|
|||||||
items: [],
|
items: [],
|
||||||
state: "skipped"
|
state: "skipped"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code: "OUTBOUNDS" /* OUTBOUNDS */,
|
||||||
|
title: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.title,
|
||||||
|
order: DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS.order,
|
||||||
|
description: _("Pending"),
|
||||||
|
items: [],
|
||||||
|
state: "skipped"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: "FAKEIP" /* FAKEIP */,
|
code: "FAKEIP" /* FAKEIP */,
|
||||||
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
title: DIAGNOSTICS_CHECKS_MAP.FAKEIP.title,
|
||||||
@@ -1859,8 +1973,9 @@ async function fetchDashboardSections() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function connectToClashSockets() {
|
async function connectToClashSockets() {
|
||||||
|
const clashApiSecret = await getClashApiSecret();
|
||||||
socket.subscribe(
|
socket.subscribe(
|
||||||
`${getClashWsUrl()}/traffic?token=`,
|
`${getClashWsUrl()}/traffic?token=${clashApiSecret}`,
|
||||||
(msg) => {
|
(msg) => {
|
||||||
const parsedMsg = JSON.parse(msg);
|
const parsedMsg = JSON.parse(msg);
|
||||||
store.set({
|
store.set({
|
||||||
@@ -1887,7 +2002,7 @@ async function connectToClashSockets() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
socket.subscribe(
|
socket.subscribe(
|
||||||
`${getClashWsUrl()}/connections?token=`,
|
`${getClashWsUrl()}/connections?token=${clashApiSecret}`,
|
||||||
(msg) => {
|
(msg) => {
|
||||||
const parsedMsg = JSON.parse(msg);
|
const parsedMsg = JSON.parse(msg);
|
||||||
store.set({
|
store.set({
|
||||||
@@ -2492,7 +2607,7 @@ async function runSingBoxCheck() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
state: data.sing_box_version_ok ? "success" : "error",
|
state: data.sing_box_version_ok ? "success" : "error",
|
||||||
key: _("Sing-box version >= 1.12.4"),
|
key: _("Sing-box version is compatible (newer than 1.12.4)"),
|
||||||
value: ""
|
value: ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -3685,6 +3800,105 @@ function renderWikiDisclaimer(kind) {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts
|
||||||
|
async function runSectionsCheck() {
|
||||||
|
const { order, title, code } = DIAGNOSTICS_CHECKS_MAP.OUTBOUNDS;
|
||||||
|
updateCheckStore({
|
||||||
|
order,
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description: _("Checking, please wait"),
|
||||||
|
state: "loading",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
const sections = await getDashboardSections();
|
||||||
|
if (!sections.success) {
|
||||||
|
updateCheckStore({
|
||||||
|
order,
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description: _("Cannot receive checks result"),
|
||||||
|
state: "error",
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
throw new Error("Sections checks failed");
|
||||||
|
}
|
||||||
|
const items = await Promise.all(
|
||||||
|
sections.data.map(async (section) => {
|
||||||
|
async function getLatency() {
|
||||||
|
if (section.withTagSelect) {
|
||||||
|
const latencyGroup = await PodkopShellMethods.getClashApiGroupLatency(
|
||||||
|
section.code
|
||||||
|
);
|
||||||
|
const selectedOutbound = section.outbounds.find(
|
||||||
|
(item) => item.selected
|
||||||
|
);
|
||||||
|
const isUrlTest = selectedOutbound?.type === "URLTest";
|
||||||
|
const success3 = latencyGroup.success && !latencyGroup.data.message;
|
||||||
|
if (success3) {
|
||||||
|
if (isUrlTest) {
|
||||||
|
const latency2 = Object.values(latencyGroup.data).map((item) => item ? `${item}ms` : "n/a").join(" / ");
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
latency: `[${_("Fastest")}] ${latency2}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const selectedProxyDelay = latencyGroup.data?.[selectedOutbound?.code ?? ""];
|
||||||
|
if (selectedProxyDelay) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
latency: `[${selectedOutbound?.displayName ?? ""}] ${selectedProxyDelay}ms`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
latency: `[${selectedOutbound?.displayName ?? ""}] ${_("Not responding")}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
latency: _("Not responding")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const latencyProxy = await PodkopShellMethods.getClashApiProxyLatency(
|
||||||
|
section.code
|
||||||
|
);
|
||||||
|
const success2 = latencyProxy.success && !latencyProxy.data.message;
|
||||||
|
if (success2) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
latency: `${latencyProxy.data.delay} ms`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
latency: _("Not responding")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const { latency, success } = await getLatency();
|
||||||
|
return {
|
||||||
|
state: success ? "success" : "error",
|
||||||
|
key: section.displayName,
|
||||||
|
value: latency
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const allGood = items.every((item) => item.state === "success");
|
||||||
|
const atLeastOneGood = items.some((item) => item.state === "success");
|
||||||
|
const { state, description } = getMeta({ atLeastOneGood, allGood });
|
||||||
|
updateCheckStore({
|
||||||
|
order,
|
||||||
|
code,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
items
|
||||||
|
});
|
||||||
|
if (!atLeastOneGood) {
|
||||||
|
throw new Error("Sections checks failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// src/podkop/tabs/diagnostic/initController.ts
|
// src/podkop/tabs/diagnostic/initController.ts
|
||||||
async function fetchSystemInfo() {
|
async function fetchSystemInfo() {
|
||||||
const systemInfo = await PodkopShellMethods.getSystemInfo();
|
const systemInfo = await PodkopShellMethods.getSystemInfo();
|
||||||
@@ -4032,9 +4246,7 @@ function renderDiagnosticSystemInfoWidget() {
|
|||||||
function getPodkopVersionRow() {
|
function getPodkopVersionRow() {
|
||||||
const loading = diagnosticsSystemInfo.loading;
|
const loading = diagnosticsSystemInfo.loading;
|
||||||
const unknown = diagnosticsSystemInfo.podkop_version === _("unknown");
|
const unknown = diagnosticsSystemInfo.podkop_version === _("unknown");
|
||||||
const hasActualVersion = Boolean(
|
const hasActualVersion = Boolean(diagnosticsSystemInfo.podkop_latest_version) && diagnosticsSystemInfo.podkop_latest_version !== "unknown";
|
||||||
diagnosticsSystemInfo.podkop_latest_version
|
|
||||||
);
|
|
||||||
const version = normalizeCompiledVersion(
|
const version = normalizeCompiledVersion(
|
||||||
diagnosticsSystemInfo.podkop_version
|
diagnosticsSystemInfo.podkop_version
|
||||||
);
|
);
|
||||||
@@ -4118,6 +4330,7 @@ async function runChecks() {
|
|||||||
await runDnsCheck();
|
await runDnsCheck();
|
||||||
await runSingBoxCheck();
|
await runSingBoxCheck();
|
||||||
await runNftCheck();
|
await runNftCheck();
|
||||||
|
await runSectionsCheck();
|
||||||
await runFakeIPCheck();
|
await runFakeIPCheck();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("[DIAGNOSTIC]", "runChecks - e", e);
|
logger.error("[DIAGNOSTIC]", "runChecks - e", e);
|
||||||
@@ -4624,6 +4837,10 @@ function insertIf(condition, elements) {
|
|||||||
function insertIfObj(condition, object) {
|
function insertIfObj(condition, object) {
|
||||||
return condition ? object : {};
|
return condition ? object : {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/main.ts
|
||||||
|
if (typeof structuredClone !== "function")
|
||||||
|
globalThis.structuredClone = (obj) => JSON.parse(JSON.stringify(obj));
|
||||||
return baseclass.extend({
|
return baseclass.extend({
|
||||||
ALLOWED_WITH_RUSSIA_INSIDE,
|
ALLOWED_WITH_RUSSIA_INSIDE,
|
||||||
BOOTSTRAP_DNS_SERVER_OPTIONS,
|
BOOTSTRAP_DNS_SERVER_OPTIONS,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function createSectionContent(section) {
|
|||||||
_("URLTest Proxy Links"),
|
_("URLTest Proxy Links"),
|
||||||
);
|
);
|
||||||
o.depends("proxy_config_type", "urltest");
|
o.depends("proxy_config_type", "urltest");
|
||||||
o.placeholder = "vless://, ss://, trojan://, socks4/5:// links";
|
o.placeholder = "vless://, ss://, trojan://, socks4/5://, hy2/hysteria2:// links";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.validate = function (section_id, value) {
|
o.validate = function (section_id, value) {
|
||||||
// Optional
|
// Optional
|
||||||
@@ -104,6 +104,70 @@ function createSectionContent(section) {
|
|||||||
return validation.message;
|
return validation.message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
o = section.option(
|
||||||
|
form.ListValue,
|
||||||
|
"urltest_check_interval",
|
||||||
|
_("URLTest Check Interval"),
|
||||||
|
_("The interval between connectivity tests")
|
||||||
|
);
|
||||||
|
o.value("30s", _("Every 30 seconds"));
|
||||||
|
o.value("1m", _("Every 1 minute"));
|
||||||
|
o.value("3m", _("Every 3 minutes"));
|
||||||
|
o.value("5m", _("Every 5 minutes"));
|
||||||
|
o.default = "3m";
|
||||||
|
o.depends("proxy_config_type", "urltest");
|
||||||
|
|
||||||
|
o = section.option(
|
||||||
|
form.Value,
|
||||||
|
"urltest_tolerance",
|
||||||
|
_("URLTest Tolerance"),
|
||||||
|
_("The maximum difference in response times (ms) allowed when comparing servers")
|
||||||
|
);
|
||||||
|
o.default = "50";
|
||||||
|
o.rmempty = false;
|
||||||
|
o.depends("proxy_config_type", "urltest");
|
||||||
|
o.validate = function (section_id, value) {
|
||||||
|
if (!value || value.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = parseFloat(value);
|
||||||
|
|
||||||
|
if (/^[0-9]+$/.test(value) && !isNaN(parsed) && isFinite(parsed) && parsed >= 50 && parsed <= 1000) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _('Must be a number in the range of 50 - 1000');
|
||||||
|
};
|
||||||
|
|
||||||
|
o = section.option(
|
||||||
|
form.Value,
|
||||||
|
"urltest_testing_url",
|
||||||
|
_("URLTest Testing URL"),
|
||||||
|
_("The URL used to test server connectivity")
|
||||||
|
);
|
||||||
|
o.value("https://www.gstatic.com/generate_204", "https://www.gstatic.com/generate_204 (Google)");
|
||||||
|
o.value("https://cp.cloudflare.com/generate_204", "https://cp.cloudflare.com/generate_204 (Cloudflare)");
|
||||||
|
o.value("https://captive.apple.com", "https://captive.apple.com (Apple)");
|
||||||
|
o.value("https://connectivity-check.ubuntu.com", "https://connectivity-check.ubuntu.com (Ubuntu)")
|
||||||
|
o.default = "https://www.gstatic.com/generate_204";
|
||||||
|
o.rmempty = false;
|
||||||
|
o.depends("proxy_config_type", "urltest");
|
||||||
|
|
||||||
|
o.validate = function (section_id, value) {
|
||||||
|
if (!value || value.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validation = main.validateUrl(value);
|
||||||
|
|
||||||
|
if (validation.valid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return validation.message;
|
||||||
|
};
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
"enable_udp_over_tcp",
|
"enable_udp_over_tcp",
|
||||||
@@ -381,7 +445,7 @@ function createSectionContent(section) {
|
|||||||
);
|
);
|
||||||
o.value("disabled", _("Disabled"));
|
o.value("disabled", _("Disabled"));
|
||||||
o.value("dynamic", _("Dynamic List"));
|
o.value("dynamic", _("Dynamic List"));
|
||||||
o.value("text", _("Text List (comma/space/newline separated)"));
|
o.value("text", _("Text List"));
|
||||||
o.default = "disabled";
|
o.default = "disabled";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
|
|||||||
@@ -240,6 +240,25 @@ function createSettingsContent(section) {
|
|||||||
o.default = "0";
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
|
o = section.option(
|
||||||
|
form.Flag,
|
||||||
|
"enable_yacd_wan_access",
|
||||||
|
_("Enable YACD WAN Access"),
|
||||||
|
_("Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."),
|
||||||
|
);
|
||||||
|
o.depends("enable_yacd", "1");
|
||||||
|
o.default = "0";
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
|
o = section.option(
|
||||||
|
form.Value,
|
||||||
|
"yacd_secret_key",
|
||||||
|
_("YACD Secret Key"),
|
||||||
|
_("Secret key for authenticating remote access to YACD when WAN access is enabled."),
|
||||||
|
);
|
||||||
|
o.depends("enable_yacd_wan_access", "1");
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
o = section.option(
|
o = section.option(
|
||||||
form.Flag,
|
form.Flag,
|
||||||
"disable_quic",
|
"disable_quic",
|
||||||
@@ -267,7 +286,7 @@ function createSettingsContent(section) {
|
|||||||
form.Flag,
|
form.Flag,
|
||||||
"download_lists_via_proxy",
|
"download_lists_via_proxy",
|
||||||
_("Download Lists via Proxy/VPN"),
|
_("Download Lists via Proxy/VPN"),
|
||||||
_("Downloading all lists via main Proxy/VPN"),
|
_("Downloading all lists via specific Proxy/VPN"),
|
||||||
);
|
);
|
||||||
o.default = "0";
|
o.default = "0";
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PODKOP\n"
|
"Project-Id-Version: PODKOP\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-23 20:43+0300\n"
|
"POT-Creation-Date: 2025-12-01 16:30+0200\n"
|
||||||
"PO-Revision-Date: 2025-10-23 20:43+0300\n"
|
"PO-Revision-Date: 2025-12-01 16:30+0200\n"
|
||||||
"Last-Translator: divocat\n"
|
"Last-Translator: divocat\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -35,6 +35,9 @@ msgstr "Активные соединения"
|
|||||||
msgid "Additional marking rules found"
|
msgid "Additional marking rules found"
|
||||||
msgstr "Найдены дополнительные правила маркировки"
|
msgstr "Найдены дополнительные правила маркировки"
|
||||||
|
|
||||||
|
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
|
||||||
|
msgstr "Обеспечивает доступ к YACD из WAN. Убедитесь, что в брандмауэре открыт соответствующий порт."
|
||||||
|
|
||||||
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
||||||
msgstr "Применимо для SOCKS и Shadowsocks прокси"
|
msgstr "Применимо для SOCKS и Shadowsocks прокси"
|
||||||
|
|
||||||
@@ -182,9 +185,6 @@ msgstr "Скачивать списки через Proxy/VPN"
|
|||||||
msgid "Download Lists via specific proxy section"
|
msgid "Download Lists via specific proxy section"
|
||||||
msgstr "Скачивать списки через выбранную секцию"
|
msgstr "Скачивать списки через выбранную секцию"
|
||||||
|
|
||||||
msgid "Downloading all lists via main Proxy/VPN"
|
|
||||||
msgstr "Загрузка всех списков через основной прокси/VPN"
|
|
||||||
|
|
||||||
msgid "Downloading all lists via specific Proxy/VPN"
|
msgid "Downloading all lists via specific Proxy/VPN"
|
||||||
msgstr "Загрузка всех списков через указанный прокси/VPN"
|
msgstr "Загрузка всех списков через указанный прокси/VPN"
|
||||||
|
|
||||||
@@ -209,6 +209,9 @@ msgstr "Включить смешанный прокси-сервер, разр
|
|||||||
msgid "Enable YACD"
|
msgid "Enable YACD"
|
||||||
msgstr "Включить YACD"
|
msgstr "Включить YACD"
|
||||||
|
|
||||||
|
msgid "Enable YACD WAN Access"
|
||||||
|
msgstr "Включить доступ YACD WAN"
|
||||||
|
|
||||||
msgid "Enter complete outbound configuration in JSON format"
|
msgid "Enter complete outbound configuration in JSON format"
|
||||||
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
|
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
|
||||||
|
|
||||||
@@ -221,6 +224,18 @@ msgstr "Введите доменные имена без протоколов,
|
|||||||
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
||||||
msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса"
|
msgstr "Введите подсети в нотации CIDR (например, 103.21.244.0/22) или отдельные IP-адреса"
|
||||||
|
|
||||||
|
msgid "Every 1 minute"
|
||||||
|
msgstr "Каждую минуту"
|
||||||
|
|
||||||
|
msgid "Every 3 minutes"
|
||||||
|
msgstr "Каждые 3 минуты"
|
||||||
|
|
||||||
|
msgid "Every 30 seconds"
|
||||||
|
msgstr "Каждые 30 секунд"
|
||||||
|
|
||||||
|
msgid "Every 5 minutes"
|
||||||
|
msgstr "Каждые 5 минут"
|
||||||
|
|
||||||
msgid "Exclude NTP"
|
msgid "Exclude NTP"
|
||||||
msgstr "Исключить NTP"
|
msgstr "Исключить NTP"
|
||||||
|
|
||||||
@@ -266,6 +281,45 @@ msgstr "Неверный домен"
|
|||||||
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
||||||
msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y"
|
msgstr "Неверный формат. Используйте X.X.X.X или X.X.X.X/Y"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: insecure must be 0 or 1"
|
||||||
|
msgstr "Неверный URL Hysteria2: параметр insecure должен быть 0 или 1"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: invalid port number"
|
||||||
|
msgstr "Неверный URL Hysteria2: неверный номер порта"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing credentials/server"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствуют учетные данные/сервер"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing host"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствует хост"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing host & port"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствуют хост и порт"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing password"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствует пароль"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: missing port"
|
||||||
|
msgstr "Неверный URL Hysteria2: отсутствует порт"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: must not contain spaces"
|
||||||
|
msgstr "Неверный URL Hysteria2: не должен содержать пробелов"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
|
||||||
|
msgstr "Неверный URL Hysteria2: должен начинаться с hysteria2:// или hy2://"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
|
||||||
|
msgstr "Неверный URL Hysteria2: требуется obfs-password, когда установлен obfs"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: parsing failed"
|
||||||
|
msgstr "Неверный URL Hysteria2: ошибка разбора"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: sni cannot be empty"
|
||||||
|
msgstr "Неверный URL Hysteria2: sni не может быть пустым"
|
||||||
|
|
||||||
|
msgid "Invalid HY2 URL: unsupported obfs type"
|
||||||
|
msgstr "Неверный URL Hysteria2: неподдерживаемый тип obfs"
|
||||||
|
|
||||||
msgid "Invalid IP address"
|
msgid "Invalid IP address"
|
||||||
msgstr "Неверный IP-адрес"
|
msgstr "Неверный IP-адрес"
|
||||||
|
|
||||||
@@ -377,6 +431,9 @@ msgstr "Порт смешанного прокси"
|
|||||||
msgid "Monitored Interfaces"
|
msgid "Monitored Interfaces"
|
||||||
msgstr "Наблюдаемые интерфейсы"
|
msgstr "Наблюдаемые интерфейсы"
|
||||||
|
|
||||||
|
msgid "Must be a number in the range of 50 - 1000"
|
||||||
|
msgstr "Должно быть числом от 50 до 1000"
|
||||||
|
|
||||||
msgid "Network Interface"
|
msgid "Network Interface"
|
||||||
msgstr "Сетевой интерфейс"
|
msgstr "Сетевой интерфейс"
|
||||||
|
|
||||||
@@ -386,6 +443,9 @@ msgstr "Другие правила маркировки не найдены"
|
|||||||
msgid "Not implement yet"
|
msgid "Not implement yet"
|
||||||
msgstr "Ещё не реализовано"
|
msgstr "Ещё не реализовано"
|
||||||
|
|
||||||
|
msgid "Not responding"
|
||||||
|
msgstr "Не отвечает"
|
||||||
|
|
||||||
msgid "Not running"
|
msgid "Not running"
|
||||||
msgstr "Не запущено"
|
msgstr "Не запущено"
|
||||||
|
|
||||||
@@ -398,9 +458,6 @@ msgstr "Конфигурация Outbound"
|
|||||||
msgid "Outbound Configuration"
|
msgid "Outbound Configuration"
|
||||||
msgstr "Конфигурация исходящего соединения"
|
msgstr "Конфигурация исходящего соединения"
|
||||||
|
|
||||||
msgid "Outbound JSON must contain at least \"type\", \"server\" and \"server_port\" fields"
|
|
||||||
msgstr "JSON должен содержать поля \"type\", \"server\" и \"server_port\""
|
|
||||||
|
|
||||||
msgid "Outdated"
|
msgid "Outdated"
|
||||||
msgstr "Устаревшая"
|
msgstr "Устаревшая"
|
||||||
|
|
||||||
@@ -485,6 +542,9 @@ msgstr "Запустить диагностику"
|
|||||||
msgid "Russia inside restrictions"
|
msgid "Russia inside restrictions"
|
||||||
msgstr "Ограничения Russia inside"
|
msgstr "Ограничения Russia inside"
|
||||||
|
|
||||||
|
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
|
||||||
|
msgstr "Секретный ключ для аутентификации удаленного доступа к YACD при включенном доступе через WAN."
|
||||||
|
|
||||||
msgid "Sections"
|
msgid "Sections"
|
||||||
msgstr "Секции"
|
msgstr "Секции"
|
||||||
|
|
||||||
@@ -560,8 +620,8 @@ msgstr "Процесс sing-box запущен"
|
|||||||
msgid "Sing-box service exist"
|
msgid "Sing-box service exist"
|
||||||
msgstr "Сервис sing-box существует"
|
msgstr "Сервис sing-box существует"
|
||||||
|
|
||||||
msgid "Sing-box version >= 1.12.4"
|
msgid "Sing-box version is compatible (newer than 1.12.4)"
|
||||||
msgstr "Версия sing-box >= 1.12.4"
|
msgstr "Версия Sing-box совместима (новее 1.12.4)"
|
||||||
|
|
||||||
msgid "Source Network Interface"
|
msgid "Source Network Interface"
|
||||||
msgstr "Сетевой интерфейс источника"
|
msgstr "Сетевой интерфейс источника"
|
||||||
@@ -605,12 +665,18 @@ msgstr "Тестирование задержки"
|
|||||||
msgid "Text List"
|
msgid "Text List"
|
||||||
msgstr "Текстовый список"
|
msgstr "Текстовый список"
|
||||||
|
|
||||||
msgid "Text List (comma/space/newline separated)"
|
|
||||||
msgstr "Текстовый список (через запятую, пробел или новую строку)"
|
|
||||||
|
|
||||||
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
||||||
msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера"
|
msgstr "DNS-сервер, используемый для поиска IP-адреса вышестоящего DNS-сервера"
|
||||||
|
|
||||||
|
msgid "The interval between connectivity tests"
|
||||||
|
msgstr "Интервал между тестами подключения"
|
||||||
|
|
||||||
|
msgid "The maximum difference in response times (ms) allowed when comparing servers"
|
||||||
|
msgstr "Максимально допустимая разница во времени отклика (мс) при сравнении серверов"
|
||||||
|
|
||||||
|
msgid "The URL used to test server connectivity"
|
||||||
|
msgstr "URL-адрес, используемый для проверки подключения к серверу"
|
||||||
|
|
||||||
msgid "Time in seconds for DNS record caching (default: 60)"
|
msgid "Time in seconds for DNS record caching (default: 60)"
|
||||||
msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)"
|
msgstr "Время в секундах для кэширования DNS записей (по умолчанию: 60)"
|
||||||
|
|
||||||
@@ -644,8 +710,8 @@ msgstr "Неизвестная ошибка"
|
|||||||
msgid "Uplink"
|
msgid "Uplink"
|
||||||
msgstr "Исходящий"
|
msgstr "Исходящий"
|
||||||
|
|
||||||
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://"
|
msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
|
||||||
msgstr "URL должен начинаться с vless://, ss://, trojan:// или socks4/5://"
|
msgstr "URL должен начинаться с vless://, ss://, trojan://, socks4/5:// или hysteria2:// hy2://"
|
||||||
|
|
||||||
msgid "URL must use one of the following protocols:"
|
msgid "URL must use one of the following protocols:"
|
||||||
msgstr "URL должен использовать один из следующих протоколов:"
|
msgstr "URL должен использовать один из следующих протоколов:"
|
||||||
@@ -653,9 +719,18 @@ msgstr "URL должен использовать один из следующи
|
|||||||
msgid "URLTest"
|
msgid "URLTest"
|
||||||
msgstr "URLTest"
|
msgstr "URLTest"
|
||||||
|
|
||||||
|
msgid "URLTest Check Interval"
|
||||||
|
msgstr "Интервал проверки URLTest"
|
||||||
|
|
||||||
msgid "URLTest Proxy Links"
|
msgid "URLTest Proxy Links"
|
||||||
msgstr "Ссылки прокси для URLTest"
|
msgstr "Ссылки прокси для URLTest"
|
||||||
|
|
||||||
|
msgid "URLTest Testing URL"
|
||||||
|
msgstr "URLTest ссылка для проверки"
|
||||||
|
|
||||||
|
msgid "URLTest Tolerance"
|
||||||
|
msgstr "URLTest допустимое отклонение"
|
||||||
|
|
||||||
msgid "User Domain List Type"
|
msgid "User Domain List Type"
|
||||||
msgstr "Тип пользовательского списка доменов"
|
msgstr "Тип пользовательского списка доменов"
|
||||||
|
|
||||||
@@ -692,5 +767,8 @@ msgstr "Предупреждение: %s нельзя использовать
|
|||||||
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
||||||
msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных."
|
msgstr "Предупреждение: Russia inside может быть использован только с %s. %s уже есть в Russia inside и будет удален из выбранных."
|
||||||
|
|
||||||
|
msgid "YACD Secret Key"
|
||||||
|
msgstr "Секретный ключ YACD"
|
||||||
|
|
||||||
msgid "You can select Output Network Interface, by default autodetect"
|
msgid "You can select Output Network Interface, by default autodetect"
|
||||||
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически."
|
msgstr "Вы можете выбрать выходной сетевой интерфейс, по умолчанию он определяется автоматически."
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PODKOP\n"
|
"Project-Id-Version: PODKOP\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2025-10-23 17:43+0300\n"
|
"POT-Creation-Date: 2025-12-01 14:30+0200\n"
|
||||||
"PO-Revision-Date: 2025-10-23 17:43+0300\n"
|
"PO-Revision-Date: 2025-12-01 14:30+0200\n"
|
||||||
"Last-Translator: divocat <divocatt@gmail.com>\n"
|
"Last-Translator: divocat <divocatt@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
@@ -16,23 +16,23 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:342
|
#: src/podkop/tabs/dashboard/initController.ts:345
|
||||||
msgid "✔ Enabled"
|
msgid "✔ Enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:353
|
#: src/podkop/tabs/dashboard/initController.ts:356
|
||||||
msgid "✔ Running"
|
msgid "✔ Running"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:343
|
#: src/podkop/tabs/dashboard/initController.ts:346
|
||||||
msgid "✘ Disabled"
|
msgid "✘ Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:354
|
#: src/podkop/tabs/dashboard/initController.ts:357
|
||||||
msgid "✘ Stopped"
|
msgid "✘ Stopped"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:304
|
#: src/podkop/tabs/dashboard/initController.ts:307
|
||||||
msgid "Active Connections"
|
msgid "Active Connections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -40,15 +40,19 @@ msgstr ""
|
|||||||
msgid "Additional marking rules found"
|
msgid "Additional marking rules found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247
|
||||||
|
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:175
|
||||||
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
msgid "Applicable for SOCKS and Shadowsocks proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:356
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:420
|
||||||
msgid "At least one valid domain must be specified. Comments-only content is not allowed."
|
msgid "At least one valid domain must be specified. Comments-only content is not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:437
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:501
|
||||||
msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed."
|
msgid "At least one valid subnet or IP must be specified. Comments-only content is not allowed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -72,16 +76,17 @@ msgstr ""
|
|||||||
msgid "Browser is using FakeIP correctly"
|
msgid "Browser is using FakeIP correctly"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:329
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:348
|
||||||
msgid "Cache File Path"
|
msgid "Cache File Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:343
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:362
|
||||||
msgid "Cache file path cannot be empty"
|
msgid "Cache file path cannot be empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:27
|
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:27
|
||||||
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:28
|
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:28
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:27
|
||||||
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:25
|
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:25
|
||||||
msgid "Cannot receive checks result"
|
msgid "Cannot receive checks result"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -89,6 +94,7 @@ msgstr ""
|
|||||||
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:15
|
#: src/podkop/tabs/diagnostic/checks/runDnsCheck.ts:15
|
||||||
#: src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts:15
|
#: src/podkop/tabs/diagnostic/checks/runFakeIPCheck.ts:15
|
||||||
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:13
|
#: src/podkop/tabs/diagnostic/checks/runNftCheck.ts:13
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:15
|
||||||
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:13
|
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:13
|
||||||
msgid "Checking, please wait"
|
msgid "Checking, please wait"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -113,11 +119,11 @@ msgstr ""
|
|||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:211
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:275
|
||||||
msgid "Community Lists"
|
msgid "Community Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:316
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:335
|
||||||
msgid "Config File Path"
|
msgid "Config File Path"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -173,16 +179,16 @@ msgstr ""
|
|||||||
msgid "Disable autostart"
|
msgid "Disable autostart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:265
|
||||||
msgid "Disable QUIC"
|
msgid "Disable QUIC"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:247
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:266
|
||||||
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
|
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:302
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:366
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:382
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:446
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -190,17 +196,17 @@ msgstr ""
|
|||||||
msgid "DNS on router"
|
msgid "DNS on router"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:179
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:243
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:15
|
||||||
msgid "DNS over HTTPS (DoH)"
|
msgid "DNS over HTTPS (DoH)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:180
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:244
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:16
|
||||||
msgid "DNS over TLS (DoT)"
|
msgid "DNS over TLS (DoT)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:176
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:240
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:12
|
||||||
msgid "DNS Protocol Type"
|
msgid "DNS Protocol Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -209,7 +215,7 @@ msgstr ""
|
|||||||
msgid "DNS Rewrite TTL"
|
msgid "DNS Rewrite TTL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:189
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:253
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:24
|
||||||
msgid "DNS Server"
|
msgid "DNS Server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -222,16 +228,16 @@ msgstr ""
|
|||||||
msgid "Do not panic, everything can be fixed, just..."
|
msgid "Do not panic, everything can be fixed, just..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:166
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:230
|
||||||
msgid "Domain Resolver"
|
msgid "Domain Resolver"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:307
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:326
|
||||||
msgid "Dont Touch My DHCP!"
|
msgid "Dont Touch My DHCP!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:238
|
#: src/podkop/tabs/dashboard/initController.ts:241
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:272
|
#: src/podkop/tabs/dashboard/initController.ts:275
|
||||||
msgid "Downlink"
|
msgid "Downlink"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -239,24 +245,21 @@ msgstr ""
|
|||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:269
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:288
|
||||||
msgid "Download Lists via Proxy/VPN"
|
msgid "Download Lists via Proxy/VPN"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:278
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:297
|
||||||
msgid "Download Lists via specific proxy section"
|
msgid "Download Lists via specific proxy section"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:270
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:289
|
||||||
msgid "Downloading all lists via main Proxy/VPN"
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:298
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:279
|
|
||||||
msgid "Downloading all lists via specific Proxy/VPN"
|
msgid "Downloading all lists via specific Proxy/VPN"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:303
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:367
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:383
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:447
|
||||||
msgid "Dynamic List"
|
msgid "Dynamic List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -264,11 +267,11 @@ msgstr ""
|
|||||||
msgid "Enable autostart"
|
msgid "Enable autostart"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:167
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:231
|
||||||
msgid "Enable built-in DNS resolver for domains handled by this section"
|
msgid "Enable built-in DNS resolver for domains handled by this section"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:575
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:639
|
||||||
msgid "Enable Mixed Proxy"
|
msgid "Enable Mixed Proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -276,7 +279,7 @@ msgstr ""
|
|||||||
msgid "Enable Output Network Interface"
|
msgid "Enable Output Network Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:576
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:640
|
||||||
msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies"
|
msgid "Enable the mixed proxy, allowing this section to route traffic through both HTTP and SOCKS proxies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -284,27 +287,47 @@ msgstr ""
|
|||||||
msgid "Enable YACD"
|
msgid "Enable YACD"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:246
|
||||||
|
msgid "Enable YACD WAN Access"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:65
|
||||||
msgid "Enter complete outbound configuration in JSON format"
|
msgid "Enter complete outbound configuration in JSON format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:338
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:402
|
||||||
msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //"
|
msgid "Enter domain names separated by commas, spaces, or newlines. You can add comments using //"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:312
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:376
|
||||||
msgid "Enter domain names without protocols, e.g. example.com or sub.example.com"
|
msgid "Enter domain names without protocols, e.g. example.com or sub.example.com"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:392
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:456
|
||||||
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
msgid "Enter subnets in CIDR notation (e.g. 103.21.244.0/22) or single IP addresses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:365
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:114
|
||||||
|
msgid "Every 1 minute"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:115
|
||||||
|
msgid "Every 3 minutes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:113
|
||||||
|
msgid "Every 30 seconds"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:116
|
||||||
|
msgid "Every 5 minutes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:384
|
||||||
msgid "Exclude NTP"
|
msgid "Exclude NTP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:385
|
||||||
msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN"
|
msgid "Exclude NTP protocol traffic from the tunnel to prevent it from being routed through the proxy or VPN"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -312,20 +335,21 @@ msgstr ""
|
|||||||
msgid "Failed to copy!"
|
msgid "Failed to copy!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:226
|
#: src/podkop/tabs/diagnostic/initController.ts:227
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:230
|
#: src/podkop/tabs/diagnostic/initController.ts:231
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:260
|
#: src/podkop/tabs/diagnostic/initController.ts:261
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:264
|
#: src/podkop/tabs/diagnostic/initController.ts:265
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:298
|
#: src/podkop/tabs/diagnostic/initController.ts:299
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:302
|
#: src/podkop/tabs/diagnostic/initController.ts:303
|
||||||
msgid "Failed to execute!"
|
msgid "Failed to execute!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/methods/custom/getDashboardSections.ts:117
|
#: src/podkop/methods/custom/getDashboardSections.ts:117
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:59
|
||||||
msgid "Fastest"
|
msgid "Fastest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:550
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:614
|
||||||
msgid "Fully Routed IPs"
|
msgid "Fully Routed IPs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -333,7 +357,7 @@ msgstr ""
|
|||||||
msgid "Get global check"
|
msgid "Get global check"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:221
|
#: src/podkop/tabs/diagnostic/initController.ts:222
|
||||||
msgid "Global check"
|
msgid "Global check"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -366,11 +390,63 @@ msgstr ""
|
|||||||
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
msgid "Invalid format. Use X.X.X.X or X.X.X.X/Y"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:76
|
||||||
|
msgid "Invalid HY2 URL: insecure must be 0 or 1"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:62
|
||||||
|
msgid "Invalid HY2 URL: invalid port number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:32
|
||||||
|
msgid "Invalid HY2 URL: missing credentials/server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:49
|
||||||
|
msgid "Invalid HY2 URL: missing host"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:43
|
||||||
|
msgid "Invalid HY2 URL: missing host & port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:38
|
||||||
|
msgid "Invalid HY2 URL: missing password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:53
|
||||||
|
msgid "Invalid HY2 URL: missing port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:19
|
||||||
|
msgid "Invalid HY2 URL: must not contain spaces"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:12
|
||||||
|
msgid "Invalid HY2 URL: must start with hysteria2:// or hy2://"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:99
|
||||||
|
msgid "Invalid HY2 URL: obfs-password required when obfs is set"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:113
|
||||||
|
msgid "Invalid HY2 URL: parsing failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:106
|
||||||
|
msgid "Invalid HY2 URL: sni cannot be empty"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:88
|
||||||
|
msgid "Invalid HY2 URL: unsupported obfs type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateIp.ts:11
|
#: src/validators/validateIp.ts:11
|
||||||
msgid "Invalid IP address"
|
msgid "Invalid IP address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateOutboundJson.ts:19
|
#: src/validators/validateOutboundJson.ts:9
|
||||||
msgid "Invalid JSON format"
|
msgid "Invalid JSON format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -466,7 +542,8 @@ msgstr ""
|
|||||||
msgid "Invalid Trojan URL: parsing failed"
|
msgid "Invalid Trojan URL: parsing failed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateUrl.ts:18
|
#: src/validators/validateUrl.ts:8
|
||||||
|
#: src/validators/validateUrl.ts:31
|
||||||
msgid "Invalid URL format"
|
msgid "Invalid URL format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -482,19 +559,19 @@ msgstr ""
|
|||||||
msgid "Issues detected"
|
msgid "Issues detected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:452
|
#: src/podkop/tabs/diagnostic/initController.ts:453
|
||||||
msgid "Latest"
|
msgid "Latest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:276
|
||||||
msgid "List Update Frequency"
|
msgid "List Update Frequency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:458
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:522
|
||||||
msgid "Local Domain Lists"
|
msgid "Local Domain Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:481
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:545
|
||||||
msgid "Local Subnet Lists"
|
msgid "Local Subnet Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -502,11 +579,11 @@ msgstr ""
|
|||||||
msgid "Main DNS"
|
msgid "Main DNS"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:308
|
#: src/podkop/tabs/dashboard/initController.ts:311
|
||||||
msgid "Memory Usage"
|
msgid "Memory Usage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:586
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:650
|
||||||
msgid "Mixed Proxy Port"
|
msgid "Mixed Proxy Port"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -514,7 +591,11 @@ msgstr ""
|
|||||||
msgid "Monitored Interfaces"
|
msgid "Monitored Interfaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:120
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:140
|
||||||
|
msgid "Must be a number in the range of 50 - 1000"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:184
|
||||||
msgid "Network Interface"
|
msgid "Network Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -526,10 +607,17 @@ msgstr ""
|
|||||||
msgid "Not implement yet"
|
msgid "Not implement yet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:75
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:81
|
||||||
|
#: src/podkop/tabs/diagnostic/checks/runSectionsCheck.ts:100
|
||||||
|
msgid "Not responding"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:55
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:55
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:63
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:63
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:71
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:71
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:79
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:79
|
||||||
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:87
|
||||||
msgid "Not running"
|
msgid "Not running"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -545,11 +633,7 @@ msgstr ""
|
|||||||
msgid "Outbound Configuration"
|
msgid "Outbound Configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateOutboundJson.ts:11
|
#: src/podkop/tabs/diagnostic/initController.ts:443
|
||||||
msgid "Outbound JSON must contain at least \"type\", \"server\" and \"server_port\" fields"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:442
|
|
||||||
msgid "Outdated"
|
msgid "Outdated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -561,26 +645,27 @@ msgstr ""
|
|||||||
msgid "Path cannot be empty"
|
msgid "Path cannot be empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:347
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:366
|
||||||
msgid "Path must be absolute (start with /)"
|
msgid "Path must be absolute (start with /)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:356
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:375
|
||||||
msgid "Path must contain at least one directory (like /tmp/cache.db)"
|
msgid "Path must contain at least one directory (like /tmp/cache.db)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:351
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:370
|
||||||
msgid "Path must end with cache.db"
|
msgid "Path must end with cache.db"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:95
|
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:103
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:103
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:111
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:111
|
||||||
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:119
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:119
|
||||||
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:127
|
||||||
|
#: src/podkop/tabs/diagnostic/diagnostic.store.ts:135
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:340
|
#: src/podkop/tabs/dashboard/initController.ts:343
|
||||||
msgid "Podkop"
|
msgid "Podkop"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -588,7 +673,7 @@ msgstr ""
|
|||||||
msgid "Podkop Settings"
|
msgid "Podkop Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:308
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:327
|
||||||
msgid "Podkop will not modify your DHCP configuration"
|
msgid "Podkop will not modify your DHCP configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -604,15 +689,15 @@ msgstr ""
|
|||||||
msgid "Proxy traffic is routed via FakeIP"
|
msgid "Proxy traffic is routed via FakeIP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:245
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:309
|
||||||
msgid "Regional options cannot be used together"
|
msgid "Regional options cannot be used together"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:504
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:568
|
||||||
msgid "Remote Domain Lists"
|
msgid "Remote Domain Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:527
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:591
|
||||||
msgid "Remote Subnet Lists"
|
msgid "Remote Subnet Lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -628,7 +713,7 @@ msgstr ""
|
|||||||
msgid "Router DNS is routed through sing-box"
|
msgid "Router DNS is routed through sing-box"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:376
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:395
|
||||||
msgid "Routing Excluded IPs"
|
msgid "Routing Excluded IPs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -660,15 +745,19 @@ msgstr ""
|
|||||||
msgid "Run Diagnostic"
|
msgid "Run Diagnostic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:264
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:328
|
||||||
msgid "Russia inside restrictions"
|
msgid "Russia inside restrictions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:257
|
||||||
|
msgid "Secret key for authenticating remote access to YACD when WAN access is enabled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js:36
|
||||||
msgid "Sections"
|
msgid "Sections"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:212
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:276
|
||||||
msgid "Select a predefined list for routing"
|
msgid "Select a predefined list for routing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -680,7 +769,7 @@ msgstr ""
|
|||||||
msgid "Select DNS protocol to use"
|
msgid "Select DNS protocol to use"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:258
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:277
|
||||||
msgid "Select how often the domain or subnet lists are updated automatically"
|
msgid "Select how often the domain or subnet lists are updated automatically"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -688,32 +777,32 @@ msgstr ""
|
|||||||
msgid "Select how to configure the proxy"
|
msgid "Select how to configure the proxy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:121
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:185
|
||||||
msgid "Select network interface for VPN connection"
|
msgid "Select network interface for VPN connection"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:190
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:254
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:25
|
||||||
msgid "Select or enter DNS server address"
|
msgid "Select or enter DNS server address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:330
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:349
|
||||||
msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing"
|
msgid "Select or enter path for sing-box cache file. Change this ONLY if you know what you are doing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:317
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:336
|
||||||
msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing"
|
msgid "Select path for sing-box config file. Change this ONLY if you know what you are doing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:177
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:241
|
||||||
msgid "Select the DNS protocol type for the domain resolver"
|
msgid "Select the DNS protocol type for the domain resolver"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:300
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:364
|
||||||
msgid "Select the list type for adding custom domains"
|
msgid "Select the list type for adding custom domains"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:380
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:444
|
||||||
msgid "Select the list type for adding custom subnets"
|
msgid "Select the list type for adding custom subnets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -729,7 +818,7 @@ msgstr ""
|
|||||||
msgid "Select the WAN interfaces to be monitored"
|
msgid "Select the WAN interfaces to be monitored"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:337
|
#: src/podkop/tabs/dashboard/initController.ts:340
|
||||||
msgid "Services info"
|
msgid "Services info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -737,12 +826,12 @@ msgstr ""
|
|||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:289
|
#: src/podkop/tabs/diagnostic/initController.ts:290
|
||||||
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:116
|
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:116
|
||||||
msgid "Show sing-box config"
|
msgid "Show sing-box config"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:351
|
#: src/podkop/tabs/dashboard/initController.ts:354
|
||||||
msgid "Sing-box"
|
msgid "Sing-box"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -767,31 +856,31 @@ msgid "Sing-box service exist"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67
|
#: src/podkop/tabs/diagnostic/checks/runSingBoxCheck.ts:67
|
||||||
msgid "Sing-box version >= 1.12.4"
|
msgid "Sing-box version is compatible (newer than 1.12.4)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:89
|
||||||
msgid "Source Network Interface"
|
msgid "Source Network Interface"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:377
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:396
|
||||||
msgid "Specify a local IP address to be excluded from routing"
|
msgid "Specify a local IP address to be excluded from routing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:551
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:615
|
||||||
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
|
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:505
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:569
|
||||||
msgid "Specify remote URLs to download and use domain lists"
|
msgid "Specify remote URLs to download and use domain lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:528
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:592
|
||||||
msgid "Specify remote URLs to download and use subnet lists"
|
msgid "Specify remote URLs to download and use subnet lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:459
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:523
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:482
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:546
|
||||||
msgid "Specify the path to the list file located on the router filesystem"
|
msgid "Specify the path to the list file located on the router filesystem"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -807,7 +896,7 @@ msgstr ""
|
|||||||
msgid "Successfully copied!"
|
msgid "Successfully copied!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:301
|
#: src/podkop/tabs/dashboard/initController.ts:304
|
||||||
msgid "System info"
|
msgid "System info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -823,27 +912,36 @@ msgstr ""
|
|||||||
msgid "Test latency"
|
msgid "Test latency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:304
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:368
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:448
|
||||||
msgid "Text List"
|
msgid "Text List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:384
|
|
||||||
msgid "Text List (comma/space/newline separated)"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:46
|
||||||
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
msgid "The DNS server used to look up the IP address of an upstream DNS server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:111
|
||||||
|
msgid "The interval between connectivity tests"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:124
|
||||||
|
msgid "The maximum difference in response times (ms) allowed when comparing servers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:147
|
||||||
|
msgid "The URL used to test server connectivity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:69
|
||||||
msgid "Time in seconds for DNS record caching (default: 60)"
|
msgid "Time in seconds for DNS record caching (default: 60)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:235
|
#: src/podkop/tabs/dashboard/initController.ts:238
|
||||||
msgid "Traffic"
|
msgid "Traffic"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:265
|
#: src/podkop/tabs/dashboard/initController.ts:268
|
||||||
msgid "Traffic Total"
|
msgid "Traffic Total"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -859,22 +957,22 @@ msgstr ""
|
|||||||
msgid "TTL value cannot be empty"
|
msgid "TTL value cannot be empty"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:181
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:245
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:17
|
||||||
msgid "UDP (Unprotected DNS)"
|
msgid "UDP (Unprotected DNS)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:174
|
||||||
msgid "UDP over TCP"
|
msgid "UDP over TCP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:37
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:38
|
#: src/podkop/tabs/diagnostic/initController.ts:38
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:39
|
#: src/podkop/tabs/diagnostic/initController.ts:39
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:40
|
#: src/podkop/tabs/diagnostic/initController.ts:40
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:41
|
#: src/podkop/tabs/diagnostic/initController.ts:41
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:42
|
#: src/podkop/tabs/diagnostic/initController.ts:42
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:416
|
#: src/podkop/tabs/diagnostic/initController.ts:43
|
||||||
|
#: src/podkop/tabs/diagnostic/initController.ts:417
|
||||||
msgid "unknown"
|
msgid "unknown"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -882,16 +980,16 @@ msgstr ""
|
|||||||
msgid "Unknown error"
|
msgid "Unknown error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:237
|
#: src/podkop/tabs/dashboard/initController.ts:240
|
||||||
#: src/podkop/tabs/dashboard/initController.ts:268
|
#: src/podkop/tabs/dashboard/initController.ts:271
|
||||||
msgid "Uplink"
|
msgid "Uplink"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateProxyUrl.ts:29
|
#: src/validators/validateProxyUrl.ts:37
|
||||||
msgid "URL must start with vless://, ss://, trojan://, or socks4/5://"
|
msgid "URL must start with vless://, ss://, trojan://, socks4/5://, or hysteria2://hy2://"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/validators/validateUrl.ts:13
|
#: src/validators/validateUrl.ts:17
|
||||||
msgid "URL must use one of the following protocols:"
|
msgid "URL must use one of the following protocols:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -899,31 +997,43 @@ msgstr ""
|
|||||||
msgid "URLTest"
|
msgid "URLTest"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:110
|
||||||
|
msgid "URLTest Check Interval"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:87
|
||||||
msgid "URLTest Proxy Links"
|
msgid "URLTest Proxy Links"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:299
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:146
|
||||||
|
msgid "URLTest Testing URL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:123
|
||||||
|
msgid "URLTest Tolerance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:363
|
||||||
msgid "User Domain List Type"
|
msgid "User Domain List Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:311
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:375
|
||||||
msgid "User Domains"
|
msgid "User Domains"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:337
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:401
|
||||||
msgid "User Domains List"
|
msgid "User Domains List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:379
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:443
|
||||||
msgid "User Subnet List Type"
|
msgid "User Subnet List Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:391
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:455
|
||||||
msgid "User Subnets"
|
msgid "User Subnets"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:417
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:481
|
||||||
msgid "User Subnets List"
|
msgid "User Subnets List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -931,24 +1041,25 @@ msgstr ""
|
|||||||
#: src/validators/validateDns.ts:18
|
#: src/validators/validateDns.ts:18
|
||||||
#: src/validators/validateDomain.ts:13
|
#: src/validators/validateDomain.ts:13
|
||||||
#: src/validators/validateDomain.ts:30
|
#: src/validators/validateDomain.ts:30
|
||||||
|
#: src/validators/validateHysteriaUrl.ts:111
|
||||||
#: src/validators/validateIp.ts:8
|
#: src/validators/validateIp.ts:8
|
||||||
#: src/validators/validateOutboundJson.ts:17
|
#: src/validators/validateOutboundJson.ts:7
|
||||||
#: src/validators/validatePath.ts:16
|
#: src/validators/validatePath.ts:16
|
||||||
#: src/validators/validateShadowsocksUrl.ts:95
|
#: src/validators/validateShadowsocksUrl.ts:95
|
||||||
#: src/validators/validateSocksUrl.ts:80
|
#: src/validators/validateSocksUrl.ts:80
|
||||||
#: src/validators/validateSubnet.ts:38
|
#: src/validators/validateSubnet.ts:38
|
||||||
#: src/validators/validateTrojanUrl.ts:59
|
#: src/validators/validateTrojanUrl.ts:59
|
||||||
#: src/validators/validateUrl.ts:16
|
#: src/validators/validateUrl.ts:28
|
||||||
#: src/validators/validateVlessUrl.ts:108
|
#: src/validators/validateVlessUrl.ts:108
|
||||||
msgid "Valid"
|
msgid "Valid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:370
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:434
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:449
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:513
|
||||||
msgid "Validation errors:"
|
msgid "Validation errors:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/podkop/tabs/diagnostic/initController.ts:255
|
#: src/podkop/tabs/diagnostic/initController.ts:256
|
||||||
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:107
|
#: src/podkop/tabs/diagnostic/partials/renderAvailableActions.ts:107
|
||||||
msgid "View logs"
|
msgid "View logs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -957,14 +1068,18 @@ msgstr ""
|
|||||||
msgid "Visit Wiki"
|
msgid "Visit Wiki"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:247
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:311
|
||||||
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
|
msgid "Warning: %s cannot be used together with %s. Previous selections have been removed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:266
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/section.js:330
|
||||||
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
msgid "Warning: Russia inside can only be used with %s. %s already in Russia inside and have been removed from selection."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:256
|
||||||
|
msgid "YACD Secret Key"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127
|
#: ../luci-app-podkop/htdocs/luci-static/resources/view/podkop/settings.js:127
|
||||||
msgid "You can select Output Network Interface, by default autodetect"
|
msgid "You can select Output Network Interface, by default autodetect"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ check_required_file "$PODKOP_LIB/helpers.sh"
|
|||||||
check_required_file "$PODKOP_LIB/sing_box_config_manager.sh"
|
check_required_file "$PODKOP_LIB/sing_box_config_manager.sh"
|
||||||
check_required_file "$PODKOP_LIB/sing_box_config_facade.sh"
|
check_required_file "$PODKOP_LIB/sing_box_config_facade.sh"
|
||||||
check_required_file "$PODKOP_LIB/logging.sh"
|
check_required_file "$PODKOP_LIB/logging.sh"
|
||||||
|
check_required_file "$PODKOP_LIB/rulesets.sh"
|
||||||
. /lib/config/uci.sh
|
. /lib/config/uci.sh
|
||||||
. /lib/functions.sh
|
. /lib/functions.sh
|
||||||
. "$PODKOP_LIB/constants.sh"
|
. "$PODKOP_LIB/constants.sh"
|
||||||
@@ -26,6 +27,7 @@ check_required_file "$PODKOP_LIB/logging.sh"
|
|||||||
. "$PODKOP_LIB/sing_box_config_manager.sh"
|
. "$PODKOP_LIB/sing_box_config_manager.sh"
|
||||||
. "$PODKOP_LIB/sing_box_config_facade.sh"
|
. "$PODKOP_LIB/sing_box_config_facade.sh"
|
||||||
. "$PODKOP_LIB/logging.sh"
|
. "$PODKOP_LIB/logging.sh"
|
||||||
|
. "$PODKOP_LIB/rulesets.sh"
|
||||||
|
|
||||||
config_load "$PODKOP_CONFIG"
|
config_load "$PODKOP_CONFIG"
|
||||||
|
|
||||||
@@ -123,36 +125,19 @@ start_main() {
|
|||||||
|
|
||||||
# base
|
# base
|
||||||
route_table_rule_mark
|
route_table_rule_mark
|
||||||
create_nft_table
|
create_nft_rules
|
||||||
sing_box_uci
|
sing_box_configure_service
|
||||||
|
|
||||||
# sing-box
|
# sing-box
|
||||||
sing_box_init_config
|
sing_box_init_config
|
||||||
config_foreach add_cron_job "section"
|
config_foreach add_cron_job "section"
|
||||||
/etc/init.d/sing-box start
|
/etc/init.d/sing-box start
|
||||||
|
|
||||||
local exclude_ntp
|
|
||||||
config_get_bool exclude_ntp "settings" "exclude_ntp" "0"
|
|
||||||
if [ "$exclude_ntp" -eq 1 ]; then
|
|
||||||
log "NTP traffic exclude for proxy"
|
|
||||||
nft insert rule inet "$NFT_TABLE_NAME" mangle udp dport 123 return
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Nice"
|
log "Nice"
|
||||||
list_update &
|
list_update &
|
||||||
echo $! > /var/run/podkop_list_update.pid
|
echo $! > /var/run/podkop_list_update.pid
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
|
||||||
start_main
|
|
||||||
config_get_bool dont_touch_dhcp "settings" "dont_touch_dhcp" 0
|
|
||||||
if [ "$dont_touch_dhcp" -eq 0 ]; then
|
|
||||||
dnsmasq_add_resolver
|
|
||||||
fi
|
|
||||||
uci_set "podkop" "settings" "shutdown_correctly" 0
|
|
||||||
uci commit "podkop" && config_load "$PODKOP_CONFIG"
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_main() {
|
stop_main() {
|
||||||
log "Stopping the podkop"
|
log "Stopping the podkop"
|
||||||
|
|
||||||
@@ -188,13 +173,27 @@ stop_main() {
|
|||||||
/etc/init.d/sing-box stop
|
/etc/init.d/sing-box stop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
start_main
|
||||||
|
|
||||||
|
config_get_bool dont_touch_dhcp "settings" "dont_touch_dhcp" 0
|
||||||
|
if [ "$dont_touch_dhcp" -eq 0 ]; then
|
||||||
|
dnsmasq_configure
|
||||||
|
fi
|
||||||
|
|
||||||
|
uci_set "podkop" "settings" "shutdown_correctly" 0
|
||||||
|
uci commit "podkop" && config_load "$PODKOP_CONFIG"
|
||||||
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
local dont_touch_dhcp
|
local dont_touch_dhcp
|
||||||
config_get_bool dont_touch_dhcp "settings" "dont_touch_dhcp" 0
|
config_get_bool dont_touch_dhcp "settings" "dont_touch_dhcp" 0
|
||||||
if [ "$dont_touch_dhcp" -eq 0 ]; then
|
if [ "$dont_touch_dhcp" -eq 0 ]; then
|
||||||
dnsmasq_restore
|
dnsmasq_restore
|
||||||
fi
|
fi
|
||||||
|
|
||||||
stop_main
|
stop_main
|
||||||
|
|
||||||
uci_set "podkop" "settings" "shutdown_correctly" 1
|
uci_set "podkop" "settings" "shutdown_correctly" 1
|
||||||
uci commit "podkop" && config_load "$PODKOP_CONFIG"
|
uci commit "podkop" && config_load "$PODKOP_CONFIG"
|
||||||
}
|
}
|
||||||
@@ -279,12 +278,10 @@ nft_init_interfaces_set() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
create_nft_table() {
|
create_nft_rules() {
|
||||||
log "Create nft table"
|
log "Create nft table"
|
||||||
nft_create_table "$NFT_TABLE_NAME"
|
nft_create_table "$NFT_TABLE_NAME"
|
||||||
|
|
||||||
nft_init_interfaces_set
|
|
||||||
|
|
||||||
log "Create localv4 set"
|
log "Create localv4 set"
|
||||||
nft_create_ipv4_set "$NFT_TABLE_NAME" "$NFT_LOCALV4_SET_NAME"
|
nft_create_ipv4_set "$NFT_TABLE_NAME" "$NFT_LOCALV4_SET_NAME"
|
||||||
nft add element inet "$NFT_TABLE_NAME" localv4 '{
|
nft add element inet "$NFT_TABLE_NAME" localv4 '{
|
||||||
@@ -326,7 +323,14 @@ create_nft_table() {
|
|||||||
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "@$NFT_COMMON_SET_NAME" meta l4proto tcp meta mark set 0x105 counter
|
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "@$NFT_COMMON_SET_NAME" meta l4proto tcp meta mark set 0x105 counter
|
||||||
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "@$NFT_COMMON_SET_NAME" meta l4proto udp meta mark set 0x105 counter
|
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "@$NFT_COMMON_SET_NAME" meta l4proto udp meta mark set 0x105 counter
|
||||||
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "$SB_FAKEIP_INET4_RANGE" meta l4proto tcp meta mark set 0x105 counter
|
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "$SB_FAKEIP_INET4_RANGE" meta l4proto tcp meta mark set 0x105 counter
|
||||||
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "$SB_FAKEIP_INET4_RANGE" meta l4proto tcp meta mark set 0x105 counter
|
nft add rule inet "$NFT_TABLE_NAME" mangle_output ip daddr "$SB_FAKEIP_INET4_RANGE" meta l4proto udp meta mark set 0x105 counter
|
||||||
|
|
||||||
|
local exclude_ntp
|
||||||
|
config_get_bool exclude_ntp "settings" "exclude_ntp" "0"
|
||||||
|
if [ "$exclude_ntp" -eq 1 ]; then
|
||||||
|
log "NTP traffic exclude for proxy"
|
||||||
|
nft insert rule inet "$NFT_TABLE_NAME" mangle udp dport 123 return
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
backup_dnsmasq_config_option() {
|
backup_dnsmasq_config_option() {
|
||||||
@@ -340,7 +344,7 @@ backup_dnsmasq_config_option() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
dnsmasq_add_resolver() {
|
dnsmasq_configure() {
|
||||||
local shutdown_correctly
|
local shutdown_correctly
|
||||||
config_get shutdown_correctly "settings" "shutdown_correctly"
|
config_get shutdown_correctly "settings" "shutdown_correctly"
|
||||||
if [ "$shutdown_correctly" -eq 0 ]; then
|
if [ "$shutdown_correctly" -eq 0 ]; then
|
||||||
@@ -472,42 +476,55 @@ remove_cron_job() {
|
|||||||
list_update() {
|
list_update() {
|
||||||
echolog "🔄 Starting lists update..."
|
echolog "🔄 Starting lists update..."
|
||||||
|
|
||||||
|
local nslookup_timeout=3
|
||||||
|
local nslookup_attempts=10
|
||||||
|
local curl_timeout=5
|
||||||
|
local curl_attempts=10
|
||||||
|
local curl_max_timeout=10
|
||||||
|
local delay=3
|
||||||
local i
|
local i
|
||||||
|
|
||||||
for i in $(seq 1 60); do
|
# DNS Check
|
||||||
if nslookup -timeout=1 openwrt.org > /dev/null 2>&1; then
|
for i in $(seq 1 $nslookup_timeout); do
|
||||||
|
if nslookup -timeout=$nslookup_timeout openwrt.org > /dev/null 2>&1; then
|
||||||
echolog "✅ DNS check passed"
|
echolog "✅ DNS check passed"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
log "DNS is unavailable [$i/60]"
|
echolog "DNS is unavailable [$i/$nslookup_attempts]"
|
||||||
sleep 3
|
sleep $delay
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$i" -eq 60 ]; then
|
if [ "$i" -eq $nslookup_attempts ]; then
|
||||||
echolog "❌ DNS check failed after 60 attempts"
|
echolog "❌ DNS check failed after $nslookup_attempts attempts"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for i in $(seq 1 60); do
|
# Github Check
|
||||||
config_get_bool download_lists_via_proxy "settings" "download_lists_via_proxy" "0"
|
for i in $(seq 1 $curl_attempts); do
|
||||||
if [ "$download_lists_via_proxy" -eq 1 ]; then
|
local service_proxy_address
|
||||||
if http_proxy="http://127.0.0.1:4534" https_proxy="http://127.0.0.1:4534" curl -s -m 3 https://github.com > /dev/null; then
|
service_proxy_address="$(get_service_proxy_address)"
|
||||||
|
|
||||||
|
if [ -n "$http_proxy_address" ]; then
|
||||||
|
if curl -s -x "http://$service_proxy_address" -m $curl_timeout https://github.com > /dev/null; then
|
||||||
echolog "✅ GitHub connection check passed (via proxy)"
|
echolog "✅ GitHub connection check passed (via proxy)"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if curl -s -m 3 https://github.com > /dev/null; then
|
if curl -s -m $curl_timeout https://github.com > /dev/null; then
|
||||||
echolog "✅ GitHub connection check passed"
|
echolog "✅ GitHub connection check passed"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echolog "GitHub is unavailable [$i/60]"
|
echolog "GitHub is unavailable [$i/$curl_attempts] (max-timeout=$curl_timeout)"
|
||||||
sleep 3
|
if [ "$curl_timeout" -lt $curl_max_timeout ]; then
|
||||||
|
curl_timeout=$((curl_timeout + 1))
|
||||||
|
fi
|
||||||
|
sleep $delay
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$i" -eq 60 ]; then
|
if [ "$i" -eq $curl_attempts ]; then
|
||||||
echolog "❌ GitHub connection check failed after 60 attempts"
|
echolog "❌ GitHub connection check failed after $curl_attempts attempts"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -525,30 +542,30 @@ list_update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# sing-box funcs
|
# sing-box funcs
|
||||||
|
sing_box_configure_service() {
|
||||||
sing_box_uci() {
|
|
||||||
local sing_box_enabled sing_box_user sing_box_config_path sing_box_conffile
|
local sing_box_enabled sing_box_user sing_box_config_path sing_box_conffile
|
||||||
sing_box_enabled=$(uci get "sing-box.main.enabled")
|
sing_box_enabled="$(uci_get "sing-box" "main" "enabled")"
|
||||||
sing_box_user=$(uci get "sing-box.main.user")
|
sing_box_user="$(uci_get "sing-box" "main" "user")"
|
||||||
|
|
||||||
if [ "$sing_box_enabled" -ne 1 ]; then
|
if [ "$sing_box_enabled" -ne 1 ]; then
|
||||||
uci set "sing-box.main.enabled=1"
|
uci_set "sing-box" "main" "enabled" 1
|
||||||
uci commit "sing-box"
|
uci_commit "sing-box"
|
||||||
log "sing-box service has been enabled"
|
log "sing-box service has been enabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$sing_box_user" != "root" ]; then
|
if [ "$sing_box_user" != "root" ]; then
|
||||||
uci set "sing-box.main.user=root"
|
uci_set "sing-box" "main" "user" "root"
|
||||||
uci commit "sing-box"
|
uci_commit "sing-box"
|
||||||
log "sing-box service user has been changed to root"
|
log "sing-box service user has been changed to root"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
config_get sing_box_config_path "settings" "config_path"
|
config_get sing_box_config_path "settings" "config_path"
|
||||||
sing_box_conffile=$(uci get "sing-box.main.conffile")
|
sing_box_conffile="$(uci_get "sing-box" "main" "conffile")"
|
||||||
log "sing-box config path: $sing_box_config_path" "debug"
|
log "sing-box config path: $sing_box_config_path" "debug"
|
||||||
log "sing-box service conffile: $sing_box_conffile" "debug"
|
log "sing-box service conffile: $sing_box_conffile" "debug"
|
||||||
if [ "$sing_box_conffile" != "$sing_box_config_path" ]; then
|
if [ "$sing_box_conffile" != "$sing_box_config_path" ]; then
|
||||||
uci set "sing-box.main.conffile=$sing_box_config_path"
|
uci_set "sing-box" "main" "conffile" "$sing_box_config_path"
|
||||||
uci commit "sing-box"
|
uci_commit "sing-box"
|
||||||
log "Configuration file path has been set to $sing_box_config_path"
|
log "Configuration file path has been set to $sing_box_config_path"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -627,9 +644,12 @@ configure_outbound_handler() {
|
|||||||
urltest)
|
urltest)
|
||||||
log "Detected proxy configuration type: urltest" "debug"
|
log "Detected proxy configuration type: urltest" "debug"
|
||||||
local urltest_proxy_links udp_over_tcp i urltest_tag selector_tag outbound_tag outbound_tags \
|
local urltest_proxy_links udp_over_tcp i urltest_tag selector_tag outbound_tag outbound_tags \
|
||||||
urltest_outbounds selector_outbounds
|
urltest_outbounds selector_outbounds urltest_check_interval urltest_tolerance urltest_testing_url
|
||||||
config_get urltest_proxy_links "$section" "urltest_proxy_links"
|
config_get urltest_proxy_links "$section" "urltest_proxy_links"
|
||||||
config_get udp_over_tcp "$section" "enable_udp_over_tcp"
|
config_get udp_over_tcp "$section" "enable_udp_over_tcp"
|
||||||
|
config_get urltest_check_interval "$section" "urltest_check_interval" "3m"
|
||||||
|
config_get urltest_tolerance "$section" "urltest_tolerance" 50
|
||||||
|
config_get urltest_testing_url "$section" "urltest_testing_url" "https://www.gstatic.com/generate_204"
|
||||||
|
|
||||||
if [ -z "$urltest_proxy_links" ]; then
|
if [ -z "$urltest_proxy_links" ]; then
|
||||||
log "URLTest proxy links is not set. Aborted." "fatal"
|
log "URLTest proxy links is not set. Aborted." "fatal"
|
||||||
@@ -652,7 +672,8 @@ configure_outbound_handler() {
|
|||||||
selector_tag="$(get_outbound_tag_by_section "$section")"
|
selector_tag="$(get_outbound_tag_by_section "$section")"
|
||||||
urltest_outbounds="$(comma_string_to_json_array "$outbound_tags")"
|
urltest_outbounds="$(comma_string_to_json_array "$outbound_tags")"
|
||||||
selector_outbounds="$(comma_string_to_json_array "$outbound_tags,$urltest_tag")"
|
selector_outbounds="$(comma_string_to_json_array "$outbound_tags,$urltest_tag")"
|
||||||
config="$(sing_box_cm_add_urltest_outbound "$config" "$urltest_tag" "$urltest_outbounds")"
|
config="$(sing_box_cm_add_urltest_outbound "$config" "$urltest_tag" "$urltest_outbounds" \
|
||||||
|
"$urltest_testing_url" "$urltest_check_interval" "$urltest_tolerance")"
|
||||||
config="$(sing_box_cm_add_selector_outbound "$config" "$selector_tag" "$selector_outbounds" "$urltest_tag")"
|
config="$(sing_box_cm_add_selector_outbound "$config" "$selector_tag" "$selector_outbounds" "$urltest_tag")"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -767,7 +788,7 @@ sing_box_configure_route() {
|
|||||||
configure_common_reject_route_rule
|
configure_common_reject_route_rule
|
||||||
|
|
||||||
local routing_excluded_ips
|
local routing_excluded_ips
|
||||||
config_get_bool routing_excluded_ips "settings" "routing_excluded_ips"
|
config_get routing_excluded_ips "settings" "routing_excluded_ips"
|
||||||
if [ -n "$routing_excluded_ips" ]; then
|
if [ -n "$routing_excluded_ips" ]; then
|
||||||
rule_tag="$(gen_id)"
|
rule_tag="$(gen_id)"
|
||||||
config=$(sing_box_cm_add_route_rule "$config" "$rule_tag" "$SB_TPROXY_INBOUND_TAG" "$SB_DIRECT_OUTBOUND_TAG")
|
config=$(sing_box_cm_add_route_rule "$config" "$rule_tag" "$SB_TPROXY_INBOUND_TAG" "$SB_DIRECT_OUTBOUND_TAG")
|
||||||
@@ -861,66 +882,37 @@ configure_routing_for_section_lists() {
|
|||||||
|
|
||||||
if [ "$user_domain_list_type" != "disabled" ]; then
|
if [ "$user_domain_list_type" != "disabled" ]; then
|
||||||
log "Processing user domains routing rules for '$section' section"
|
log "Processing user domains routing rules for '$section' section"
|
||||||
prepare_common_ruleset "$section" "domains" "$route_rule_tag"
|
configure_user_domain_list "$section" "$route_rule_tag"
|
||||||
configure_user_domain_or_subnets_list "$section" "domains" "$route_rule_tag"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$user_subnet_list_type" != "disabled" ]; then
|
if [ "$user_subnet_list_type" != "disabled" ]; then
|
||||||
log "Processing user subnets routing rules for '$section' section"
|
log "Processing user subnets routing rules for '$section' section"
|
||||||
prepare_common_ruleset "$section" "subnets" "$route_rule_tag"
|
configure_user_subnet_list "$section" "$route_rule_tag"
|
||||||
configure_user_domain_or_subnets_list "$section" "subnets" "$route_rule_tag"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$local_domain_lists" ]; then
|
if [ -n "$local_domain_lists" ]; then
|
||||||
log "Processing local domains routing rules for '$section' section"
|
log "Processing local domains routing rules for '$section' section"
|
||||||
configure_local_domain_or_subnet_lists "$section" "domains" "$route_rule_tag"
|
configure_local_domain_lists "$section" "$route_rule_tag"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$local_subnet_lists" ]; then
|
if [ -n "$local_subnet_lists" ]; then
|
||||||
log "Processing local subnets routing rules for '$section' section"
|
log "Processing local subnets routing rules for '$section' section"
|
||||||
configure_local_domain_or_subnet_lists "$section" "subnets" "$route_rule_tag"
|
configure_local_subnet_lists "$section" "$route_rule_tag"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$remote_domain_lists" ]; then
|
if [ -n "$remote_domain_lists" ]; then
|
||||||
log "Processing remote domains routing rules for '$section' section"
|
log "Processing remote domains routing rules for '$section' section"
|
||||||
prepare_common_ruleset "$section" "domains" "$route_rule_tag"
|
|
||||||
config_list_foreach "$section" "remote_domain_lists" configure_remote_domain_or_subnet_list_handler \
|
config_list_foreach "$section" "remote_domain_lists" configure_remote_domain_or_subnet_list_handler \
|
||||||
"domains" "$section" "$route_rule_tag"
|
"domains" "$section" "$route_rule_tag"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$remote_subnet_lists" ]; then
|
if [ -n "$remote_subnet_lists" ]; then
|
||||||
log "Processing remote subnets routing rules for '$section' section"
|
log "Processing remote subnets routing rules for '$section' section"
|
||||||
prepare_common_ruleset "$section" "subnets" "$route_rule_tag"
|
|
||||||
config_list_foreach "$section" "remote_subnet_lists" configure_remote_domain_or_subnet_list_handler \
|
config_list_foreach "$section" "remote_subnet_lists" configure_remote_domain_or_subnet_list_handler \
|
||||||
"subnets" "$section" "$route_rule_tag"
|
"subnets" "$section" "$route_rule_tag"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_common_ruleset() {
|
|
||||||
local section="$1"
|
|
||||||
local type="$2"
|
|
||||||
local route_rule_tag="$3"
|
|
||||||
|
|
||||||
log "Preparing a common $type ruleset for '$section' section" "debug"
|
|
||||||
ruleset_tag=$(get_ruleset_tag "$section" "common" "$type")
|
|
||||||
ruleset_filename="$ruleset_tag.json"
|
|
||||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
|
||||||
if file_exists "$ruleset_filepath"; then
|
|
||||||
log "Ruleset $ruleset_filepath already exists. Skipping." "debug"
|
|
||||||
else
|
|
||||||
sing_box_cm_create_local_source_ruleset "$ruleset_filepath"
|
|
||||||
config=$(sing_box_cm_add_local_ruleset "$config" "$ruleset_tag" "source" "$ruleset_filepath")
|
|
||||||
config=$(sing_box_cm_patch_route_rule "$config" "$route_rule_tag" "rule_set" "$ruleset_tag")
|
|
||||||
case "$type" in
|
|
||||||
domains)
|
|
||||||
config=$(sing_box_cm_patch_dns_route_rule "$config" "$SB_FAKEIP_DNS_RULE_TAG" "rule_set" "$ruleset_tag")
|
|
||||||
;;
|
|
||||||
subnets) ;;
|
|
||||||
*) log "Unsupported remote rule set type: $type" "error" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
configure_community_list_handler() {
|
configure_community_list_handler() {
|
||||||
local tag="$1"
|
local tag="$1"
|
||||||
local section="$2"
|
local section="$2"
|
||||||
@@ -938,99 +930,113 @@ configure_community_list_handler() {
|
|||||||
config=$(sing_box_cm_patch_dns_route_rule "$config" "$SB_FAKEIP_DNS_RULE_TAG" "rule_set" "$ruleset_tag")
|
config=$(sing_box_cm_patch_dns_route_rule "$config" "$SB_FAKEIP_DNS_RULE_TAG" "rule_set" "$ruleset_tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_user_domain_or_subnets_list() {
|
prepare_source_ruleset() {
|
||||||
local section="$1"
|
local section="$1"
|
||||||
local type="$2"
|
local name="$2"
|
||||||
|
local type="$3"
|
||||||
|
local route_rule_tag="$4"
|
||||||
|
|
||||||
local items ruleset_tag ruleset_filename ruleset_filepath json_array
|
log "Preparing a $name $type rule set for '$section' section" "debug"
|
||||||
case "$type" in
|
ruleset_tag=$(get_ruleset_tag "$section" "$name" "$type")
|
||||||
domains)
|
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_tag.json"
|
||||||
local user_domain_list_type
|
create_source_rule_set "$ruleset_filepath"
|
||||||
config_get user_domain_list_type "$section" "user_domain_list_type"
|
case $? in
|
||||||
case "$user_domain_list_type" in
|
0)
|
||||||
dynamic) config_get items "$section" "user_domains" ;;
|
config=$(sing_box_cm_add_local_ruleset "$config" "$ruleset_tag" "source" "$ruleset_filepath")
|
||||||
text) config_get items "$section" "user_domains_text" ;;
|
config=$(sing_box_cm_patch_route_rule "$config" "$route_rule_tag" "rule_set" "$ruleset_tag")
|
||||||
esac
|
case "$type" in
|
||||||
;;
|
domains)
|
||||||
subnets)
|
config=$(sing_box_cm_patch_dns_route_rule "$config" "$SB_FAKEIP_DNS_RULE_TAG" "rule_set" "$ruleset_tag")
|
||||||
local user_subnet_list_type
|
;;
|
||||||
config_get user_subnet_list_type "$section" "user_subnet_list_type"
|
subnets) ;;
|
||||||
case "$user_subnet_list_type" in
|
*)
|
||||||
dynamic) config_get items "$section" "user_subnets" ;;
|
log "Unsupported remote rule set type: $type" "error"
|
||||||
text) config_get items "$section" "user_subnets_text" ;;
|
return 1
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
3) log "Source rule set $ruleset_filepath already exists, skipping." "debug" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_user_domain_list() {
|
||||||
|
local section="$1"
|
||||||
|
local route_rule_tag="$2"
|
||||||
|
|
||||||
|
prepare_source_ruleset "$section" "user" "domains" "$route_rule_tag"
|
||||||
|
|
||||||
|
local user_domain_list_type items json_array
|
||||||
|
config_get user_domain_list_type "$section" "user_domain_list_type"
|
||||||
|
case "$user_domain_list_type" in
|
||||||
|
dynamic) config_get items "$section" "user_domains" ;;
|
||||||
|
text) config_get items "$section" "user_domains_text" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
ruleset_tag=$(get_ruleset_tag "$section" "common" "$type")
|
items="$(parse_domain_or_subnet_string_to_commas_string "$items" "domains")"
|
||||||
ruleset_filename="$ruleset_tag.json"
|
|
||||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
|
||||||
items="$(parse_domain_or_subnet_string_to_commas_string "$items" "$type")"
|
|
||||||
json_array="$(comma_string_to_json_array "$items")"
|
json_array="$(comma_string_to_json_array "$items")"
|
||||||
case "$type" in
|
patch_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array"
|
||||||
domains) sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array" ;;
|
|
||||||
subnets)
|
|
||||||
sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$items"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_local_domain_or_subnet_lists() {
|
configure_user_subnet_list() {
|
||||||
local section="$1"
|
local section="$1"
|
||||||
local type="$2"
|
local route_rule_tag="$2"
|
||||||
local route_rule_tag="$3"
|
|
||||||
|
|
||||||
local ruleset_tag ruleset_filename ruleset_filepath
|
prepare_source_ruleset "$section" "user" "subnets" "$route_rule_tag"
|
||||||
ruleset_tag="$(get_ruleset_tag "$section" "local" "$type")"
|
|
||||||
ruleset_filename="$ruleset_tag.json"
|
|
||||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
|
||||||
|
|
||||||
sing_box_cm_create_local_source_ruleset "$ruleset_filepath"
|
local user_subnet_list_type items json_array
|
||||||
config=$(sing_box_cm_add_local_ruleset "$config" "$ruleset_tag" "source" "$ruleset_filepath")
|
config_get user_subnet_list_type "$section" "user_subnet_list_type"
|
||||||
config=$(sing_box_cm_patch_route_rule "$config" "$route_rule_tag" "rule_set" "$ruleset_tag")
|
case "$user_subnet_list_type" in
|
||||||
|
dynamic) config_get items "$section" "user_subnets" ;;
|
||||||
case "$type" in
|
text) config_get items "$section" "user_subnets_text" ;;
|
||||||
domains)
|
|
||||||
config_list_foreach "$section" "local_domain_lists" import_local_domain_or_subnet_list "$type" \
|
|
||||||
"$section" "$ruleset_filepath"
|
|
||||||
config=$(sing_box_cm_patch_dns_route_rule "$config" "$SB_FAKEIP_DNS_RULE_TAG" "rule_set" "$ruleset_tag")
|
|
||||||
;;
|
|
||||||
subnets)
|
|
||||||
config_list_foreach "$section" "local_subnet_lists" import_local_domain_or_subnet_list "$type" \
|
|
||||||
"$section" "$ruleset_filepath"
|
|
||||||
;;
|
|
||||||
*) log "Unsupported local rule set type: $type" "error" ;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
items="$(parse_domain_or_subnet_string_to_commas_string "$items" "subnets")"
|
||||||
|
json_array="$(comma_string_to_json_array "$items")"
|
||||||
|
patch_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
||||||
|
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$items"
|
||||||
}
|
}
|
||||||
|
|
||||||
import_local_domain_or_subnet_list() {
|
configure_local_domain_lists() {
|
||||||
local filepath="$1"
|
local section="$1"
|
||||||
local type="$2"
|
local route_rule_tag="$2"
|
||||||
local section="$3"
|
|
||||||
local ruleset_filepath="$4"
|
|
||||||
|
|
||||||
if ! file_exists "$filepath"; then
|
prepare_source_ruleset "$section" "local" "domains" "$route_rule_tag"
|
||||||
log "File $filepath not found" "error"
|
|
||||||
|
config_list_foreach "$section" "local_domain_lists" import_local_domain_list_handler "$ruleset_filepath"
|
||||||
|
}
|
||||||
|
|
||||||
|
import_local_domain_list_handler() {
|
||||||
|
local local_domain_list_filepath="$1"
|
||||||
|
local ruleset_filepath="$2"
|
||||||
|
|
||||||
|
if ! file_exists "$local_domain_list_filepath"; then
|
||||||
|
log "Local domain list file $local_domain_list_filepath not found" "error"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local items json_array
|
import_plain_domain_list_to_local_source_ruleset_chunked "$local_domain_list_filepath" "$ruleset_filepath"
|
||||||
items="$(parse_domain_or_subnet_file_to_comma_string "$filepath" "$type")"
|
}
|
||||||
|
|
||||||
if [ -z "$items" ]; then
|
configure_local_subnet_lists() {
|
||||||
log "No valid $type found in $filepath" "warn"
|
local section="$1"
|
||||||
return 0
|
local route_rule_tag="$2"
|
||||||
|
|
||||||
|
prepare_source_ruleset "$section" "local" "subnets" "$route_rule_tag"
|
||||||
|
|
||||||
|
config_list_foreach "$section" "local_subnet_lists" import_local_subnets_list_handler "$ruleset_filepath"
|
||||||
|
}
|
||||||
|
|
||||||
|
import_local_subnets_list_handler() {
|
||||||
|
local local_subnet_list_filepath="$1"
|
||||||
|
local ruleset_filepath="$2"
|
||||||
|
|
||||||
|
if ! file_exists "$local_subnet_list_filepath"; then
|
||||||
|
log "Local subnet list file $local_subnet_list_filepath not found" "error"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
json_array="$(comma_string_to_json_array "$items")"
|
import_plain_subnet_list_to_local_source_ruleset_chunked "$local_subnet_list_filepath" "$ruleset_filepath"
|
||||||
case "$type" in
|
nft_add_set_elements_from_file_chunked "$local_subnet_list_filepath" "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME"
|
||||||
domains) sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array" ;;
|
|
||||||
subnets)
|
|
||||||
sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$items"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_remote_domain_or_subnet_list_handler() {
|
configure_remote_domain_or_subnet_list_handler() {
|
||||||
@@ -1041,9 +1047,10 @@ configure_remote_domain_or_subnet_list_handler() {
|
|||||||
|
|
||||||
local file_extension
|
local file_extension
|
||||||
file_extension=$(url_get_file_extension "$url")
|
file_extension=$(url_get_file_extension "$url")
|
||||||
|
log "Detected file extension: '$file_extension'" "debug"
|
||||||
case "$file_extension" in
|
case "$file_extension" in
|
||||||
json | srs)
|
json | srs)
|
||||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
log "Creating a remote $type ruleset from the source URL" "info"
|
||||||
local basename ruleset_tag format detour update_interval
|
local basename ruleset_tag format detour update_interval
|
||||||
basename=$(url_get_basename "$url")
|
basename=$(url_get_basename "$url")
|
||||||
ruleset_tag=$(get_ruleset_tag "$section" "$basename" "remote-$type")
|
ruleset_tag=$(get_ruleset_tag "$section" "$basename" "remote-$type")
|
||||||
@@ -1062,7 +1069,7 @@ configure_remote_domain_or_subnet_list_handler() {
|
|||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Detected file extension: '$file_extension' → no processing needed, managed on list_update" "debug"
|
prepare_source_ruleset "$section" "remote" "$type" "$route_rule_tag"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -1075,16 +1082,39 @@ sing_box_configure_experimental() {
|
|||||||
config_get cache_file "settings" "cache_path" "/tmp/sing-box/cache.db"
|
config_get cache_file "settings" "cache_path" "/tmp/sing-box/cache.db"
|
||||||
config=$(sing_box_cm_configure_cache_file "$config" true "$cache_file" true)
|
config=$(sing_box_cm_configure_cache_file "$config" true "$cache_file" true)
|
||||||
|
|
||||||
local enable_yacd external_controller_ui
|
|
||||||
config_get_bool enable_yacd "settings" "enable_yacd" 0
|
|
||||||
log "Configuring Clash API"
|
log "Configuring Clash API"
|
||||||
|
local enable_yacd enable_yacd_wan_access clash_api_controller_address
|
||||||
|
config_get_bool enable_yacd "settings" "enable_yacd" 0
|
||||||
|
config_get_bool enable_yacd_wan_access "settings" "enable_yacd_wan_access" 0
|
||||||
|
|
||||||
|
if [ "$enable_yacd" -eq 1 ] && [ "$enable_yacd_wan_access" -eq 1 ]; then
|
||||||
|
clash_api_controller_address="0.0.0.0"
|
||||||
|
else
|
||||||
|
clash_api_controller_address="$(get_service_listen_address)"
|
||||||
|
if [ -z "$clash_api_controller_address" ]; then
|
||||||
|
log "Could not determine the listening IP address for the Clash API controller. It will run only on localhost." "warn"
|
||||||
|
clash_api_controller_address="127.0.0.1"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$enable_yacd" -eq 1 ]; then
|
if [ "$enable_yacd" -eq 1 ]; then
|
||||||
log "YACD is enabled, enabling Clash API with downloadable YACD" "debug"
|
log "YACD is enabled, enabling Clash API with downloadable YACD" "debug"
|
||||||
local external_controller_ui="ui"
|
local yacd_secret_key external_controller_ui
|
||||||
config=$(sing_box_cm_configure_clash_api "$config" "$SB_CLASH_API_CONTROLLER" "$external_controller_ui")
|
config_get yacd_secret_key "settings" "yacd_secret_key"
|
||||||
|
external_controller_ui="ui"
|
||||||
|
|
||||||
|
config=$(
|
||||||
|
sing_box_cm_configure_clash_api \
|
||||||
|
"$config" \
|
||||||
|
"$clash_api_controller_address:$SB_CLASH_API_CONTROLLER_PORT" \
|
||||||
|
"$external_controller_ui" \
|
||||||
|
"$yacd_secret_key"
|
||||||
|
)
|
||||||
else
|
else
|
||||||
log "YACD is disabled, enabling Clash API in online mode" "debug"
|
log "YACD is disabled, enabling Clash API in online mode" "debug"
|
||||||
config=$(sing_box_cm_configure_clash_api "$config" "$SB_CLASH_API_CONTROLLER")
|
config=$(
|
||||||
|
sing_box_cm_configure_clash_api "$config" "$clash_api_controller_address:$SB_CLASH_API_CONTROLLER_PORT"
|
||||||
|
)
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1113,8 +1143,13 @@ sing_box_additional_inbounds() {
|
|||||||
configure_section_mixed_proxy() {
|
configure_section_mixed_proxy() {
|
||||||
local section="$1"
|
local section="$1"
|
||||||
|
|
||||||
local mixed_inbound_enabled mixed_proxy_port mixed_inbound_tag mixed_outbound_tag
|
local mixed_inbound_enabled mixed_proxy_port mixed_inbound_tag mixed_outbound_tag mixed_proxy_address
|
||||||
config_get_bool mixed_inbound_enabled "$section" "mixed_proxy_enabled" 0
|
config_get_bool mixed_inbound_enabled "$section" "mixed_proxy_enabled" 0
|
||||||
|
mixed_proxy_address="$(get_service_listen_address)"
|
||||||
|
if [ -z "$mixed_proxy_address" ]; then
|
||||||
|
log "Could not determine the listening IP address for the Mixed Proxy. The proxy will not be created." "warn"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
config_get mixed_proxy_port "$section" "mixed_proxy_port"
|
config_get mixed_proxy_port "$section" "mixed_proxy_port"
|
||||||
if [ "$mixed_inbound_enabled" -eq 1 ]; then
|
if [ "$mixed_inbound_enabled" -eq 1 ]; then
|
||||||
mixed_inbound_tag="$(get_inbound_tag_by_section "$section-mixed")"
|
mixed_inbound_tag="$(get_inbound_tag_by_section "$section-mixed")"
|
||||||
@@ -1123,7 +1158,7 @@ configure_section_mixed_proxy() {
|
|||||||
sing_box_cf_add_mixed_inbound_and_route_rule \
|
sing_box_cf_add_mixed_inbound_and_route_rule \
|
||||||
"$config" \
|
"$config" \
|
||||||
"$mixed_inbound_tag" \
|
"$mixed_inbound_tag" \
|
||||||
"$SB_MIXED_INBOUND_ADDRESS" \
|
"$mixed_proxy_address" \
|
||||||
"$mixed_proxy_port" \
|
"$mixed_proxy_port" \
|
||||||
"$mixed_outbound_tag"
|
"$mixed_outbound_tag"
|
||||||
)
|
)
|
||||||
@@ -1209,7 +1244,7 @@ import_community_service_subnet_list_handler() {
|
|||||||
*) return 0 ;;
|
*) return 0 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
local tmpfile http_proxy_address subnets
|
local tmpfile http_proxy_address
|
||||||
tmpfile=$(mktemp)
|
tmpfile=$(mktemp)
|
||||||
http_proxy_address="$(get_service_proxy_address)"
|
http_proxy_address="$(get_service_proxy_address)"
|
||||||
|
|
||||||
@@ -1220,14 +1255,13 @@ import_community_service_subnet_list_handler() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
subnets="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "subnets")"
|
|
||||||
rm -f "$tmpfile"
|
|
||||||
|
|
||||||
if [ "$service" = "discord" ]; then
|
if [ "$service" = "discord" ]; then
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_DISCORD_SET_NAME" "$subnets"
|
nft_add_set_elements_from_file_chunked "$tmpfile" "$NFT_TABLE_NAME" "$NFT_DISCORD_SET_NAME"
|
||||||
else
|
else
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$subnets"
|
nft_add_set_elements_from_file_chunked "$tmpfile" "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
rm -f "$tmpfile"
|
||||||
}
|
}
|
||||||
|
|
||||||
import_domains_from_remote_domain_lists() {
|
import_domains_from_remote_domain_lists() {
|
||||||
@@ -1248,17 +1282,41 @@ import_domains_from_remote_domain_list_handler() {
|
|||||||
|
|
||||||
local file_extension
|
local file_extension
|
||||||
file_extension=$(url_get_file_extension "$url")
|
file_extension=$(url_get_file_extension "$url")
|
||||||
|
log "Detected file extension: '$file_extension'" "debug"
|
||||||
case "$file_extension" in
|
case "$file_extension" in
|
||||||
json | srs)
|
json | srs)
|
||||||
log "Detected file extension: '$file_extension' → no update needed, sing-box manages updates" "debug"
|
log "No update needed - sing-box manages updates automatically."
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
log "Import domains from a remote plain-text list"
|
||||||
import_domains_or_subnets_from_remote_file "$url" "$section" "domains"
|
import_domains_from_remote_plain_file "$url" "$section"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import_domains_from_remote_plain_file() {
|
||||||
|
local url="$1"
|
||||||
|
local section="$2"
|
||||||
|
|
||||||
|
local tmpfile http_proxy_address items json_array
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
http_proxy_address="$(get_service_proxy_address)"
|
||||||
|
|
||||||
|
download_to_file "$url" "$tmpfile" "$http_proxy_address"
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
||||||
|
log "Download $url list failed" "error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
convert_crlf_to_lf "$tmpfile"
|
||||||
|
ruleset_tag=$(get_ruleset_tag "$section" "remote" "domains")
|
||||||
|
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_tag.json"
|
||||||
|
import_plain_domain_list_to_local_source_ruleset_chunked "$tmpfile" "$ruleset_filepath"
|
||||||
|
|
||||||
|
rm -f "$tmpfile"
|
||||||
|
}
|
||||||
|
|
||||||
import_subnets_from_remote_subnet_lists() {
|
import_subnets_from_remote_subnet_lists() {
|
||||||
local section="$1"
|
local section="$1"
|
||||||
local remote_subnet_lists
|
local remote_subnet_lists
|
||||||
@@ -1277,81 +1335,46 @@ import_subnets_from_remote_subnet_list_handler() {
|
|||||||
|
|
||||||
local file_extension
|
local file_extension
|
||||||
file_extension="$(url_get_file_extension "$url")"
|
file_extension="$(url_get_file_extension "$url")"
|
||||||
|
log "Detected file extension: '$file_extension'" "debug"
|
||||||
case "$file_extension" in
|
case "$file_extension" in
|
||||||
json)
|
json)
|
||||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
log "Import subnets from a remote JSON list" "info"
|
||||||
import_subnets_from_remote_json_file "$url"
|
import_subnets_from_remote_json_file "$url"
|
||||||
;;
|
;;
|
||||||
srs)
|
srs)
|
||||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
log "Import subnets from a remote SRS list" "info"
|
||||||
import_subnets_from_remote_srs_file "$url"
|
import_subnets_from_remote_srs_file "$url"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
log "Import subnets from a remote plain-text list" "info"
|
||||||
import_domains_or_subnets_from_remote_file "$url" "$section" "subnets"
|
import_subnets_from_remote_plain_file "$url" "$section"
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
import_domains_or_subnets_from_remote_file() {
|
|
||||||
local url="$1"
|
|
||||||
local section="$2"
|
|
||||||
local type="$3"
|
|
||||||
|
|
||||||
local tmpfile http_proxy_address items json_array
|
|
||||||
tmpfile=$(mktemp)
|
|
||||||
http_proxy_address="$(get_service_proxy_address)"
|
|
||||||
|
|
||||||
download_to_file "$url" "$tmpfile" "$http_proxy_address"
|
|
||||||
|
|
||||||
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
|
||||||
log "Download $url list failed" "error"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
items="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "$type")"
|
|
||||||
rm -f "$tmpfile"
|
|
||||||
|
|
||||||
if [ -z "$items" ]; then
|
|
||||||
log "No valid $type found in $url" "warn"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
ruleset_tag=$(get_ruleset_tag "$section" "common" "$type")
|
|
||||||
ruleset_filename="$ruleset_tag.json"
|
|
||||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
|
||||||
json_array="$(comma_string_to_json_array "$items")"
|
|
||||||
case "$type" in
|
|
||||||
domains) sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array" ;;
|
|
||||||
subnets)
|
|
||||||
sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$items"
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
import_subnets_from_remote_json_file() {
|
import_subnets_from_remote_json_file() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
local tmpfile subnets http_proxy_address
|
local json_tmpfile subnets_tmpfile http_proxy_address
|
||||||
tmpfile="$(mktemp)"
|
json_tmpfile="$(mktemp)"
|
||||||
|
subnets_tmpfile="$(mktemp)"
|
||||||
http_proxy_address="$(get_service_proxy_address)"
|
http_proxy_address="$(get_service_proxy_address)"
|
||||||
|
|
||||||
download_to_stream "$url" "$http_proxy_address" | jq -r '.rules[].ip_cidr[]?' > "$tmpfile"
|
download_to_file "$url" "$json_tmpfile" "$http_proxy_address"
|
||||||
|
|
||||||
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
if [ $? -ne 0 ] || [ ! -s "$json_tmpfile" ]; then
|
||||||
log "Download $url list failed" "error"
|
log "Download $url list failed" "error"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
subnets="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "subnets")"
|
extract_ip_cidr_from_json_ruleset_to_file "$json_tmpfile" "$subnets_tmpfile"
|
||||||
rm -f "$tmpfile"
|
nft_add_set_elements_from_file_chunked "$subnets_tmpfile" "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME"
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$subnets"
|
rm -f "$json_tmpfile" "$subnets_tmpfile"
|
||||||
}
|
}
|
||||||
|
|
||||||
import_subnets_from_remote_srs_file() {
|
import_subnets_from_remote_srs_file() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
|
|
||||||
local binary_tmpfile json_tmpfile subnets_tmpfile subnets http_proxy_address
|
local binary_tmpfile json_tmpfile subnets_tmpfile http_proxy_address
|
||||||
binary_tmpfile="$(mktemp)"
|
binary_tmpfile="$(mktemp)"
|
||||||
json_tmpfile="$(mktemp)"
|
json_tmpfile="$(mktemp)"
|
||||||
subnets_tmpfile="$(mktemp)"
|
subnets_tmpfile="$(mktemp)"
|
||||||
@@ -1364,15 +1387,39 @@ import_subnets_from_remote_srs_file() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! decompile_srs_file "$binary_tmpfile" "$json_tmpfile"; then
|
if ! decompile_binary_ruleset "$binary_tmpfile" "$json_tmpfile"; then
|
||||||
log "Failed to decompile SRS file" "error"
|
log "Failed to decompile binary rule set file" "error"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
jq -r '.rules[].ip_cidr[]' "$json_tmpfile" > "$subnets_tmpfile"
|
extract_ip_cidr_from_json_ruleset_to_file "$json_tmpfile" "$subnets_tmpfile"
|
||||||
subnets="$(parse_domain_or_subnet_file_to_comma_string "$subnets_tmpfile" "subnets")"
|
nft_add_set_elements_from_file_chunked "$subnets_tmpfile" "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME"
|
||||||
rm -f "$binary_tmpfile" "$json_tmpfile" "$subnets_tmpfile"
|
rm -f "$binary_tmpfile" "$json_tmpfile" "$subnets_tmpfile"
|
||||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME" "$subnets"
|
}
|
||||||
|
|
||||||
|
import_subnets_from_remote_plain_file() {
|
||||||
|
local url="$1"
|
||||||
|
local section="$2"
|
||||||
|
|
||||||
|
local tmpfile http_proxy_address items json_array
|
||||||
|
tmpfile=$(mktemp)
|
||||||
|
http_proxy_address="$(get_service_proxy_address)"
|
||||||
|
|
||||||
|
download_to_file "$url" "$tmpfile" "$http_proxy_address"
|
||||||
|
|
||||||
|
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
||||||
|
log "Download $url list failed" "error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
convert_crlf_to_lf "$tmpfile"
|
||||||
|
|
||||||
|
ruleset_tag=$(get_ruleset_tag "$section" "remote" "subnets")
|
||||||
|
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_tag.json"
|
||||||
|
import_plain_subnet_list_to_local_source_ruleset_chunked "$tmpfile" "$ruleset_filepath"
|
||||||
|
nft_add_set_elements_from_file_chunked "$tmpfile" "$NFT_TABLE_NAME" "$NFT_COMMON_SET_NAME"
|
||||||
|
|
||||||
|
rm -f "$tmpfile"
|
||||||
}
|
}
|
||||||
|
|
||||||
## Support functions
|
## Support functions
|
||||||
@@ -1455,6 +1502,23 @@ section_has_enabled_lists() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_service_listen_address() {
|
||||||
|
local service_listen_address
|
||||||
|
|
||||||
|
service_listen_address="$(uci_get "network" "lan" "ipaddr")"
|
||||||
|
|
||||||
|
if [ -z "$service_listen_address" ]; then
|
||||||
|
config_get service_listen_address "settings" "service_listen_address" # TODO(ampetelin): Remove after testing
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$service_listen_address" ]; then
|
||||||
|
log "Failed to determine the listening IP address. Please open an issue to report this problem: https://github.com/itdoginfo/podkop/issues" "error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$service_listen_address"
|
||||||
|
}
|
||||||
|
|
||||||
## nftables
|
## nftables
|
||||||
nft_list_all_traffic_from_ip() {
|
nft_list_all_traffic_from_ip() {
|
||||||
local ip="$1"
|
local ip="$1"
|
||||||
@@ -1626,7 +1690,7 @@ check_logs() {
|
|||||||
nolog "Logs not found"
|
nolog "Logs not found"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
ы
|
|
||||||
# Find the last occurrence of "Starting podkop"
|
# Find the last occurrence of "Starting podkop"
|
||||||
local start_line
|
local start_line
|
||||||
start_line=$(echo "$logs" | grep -n "podkop.*Starting podkop" | tail -n 1 | cut -d: -f1)
|
start_line=$(echo "$logs" | grep -n "podkop.*Starting podkop" | tail -n 1 | cut -d: -f1)
|
||||||
@@ -1684,16 +1748,11 @@ show_config() {
|
|||||||
tmp_config=$(mktemp)
|
tmp_config=$(mktemp)
|
||||||
|
|
||||||
sed -e 's/\(option proxy_string\).*/\1 '\''MASKED'\''/g' \
|
sed -e 's/\(option proxy_string\).*/\1 '\''MASKED'\''/g' \
|
||||||
-e 's/\(option outbound_json\).*/\1 '\''MASKED'\''/g' \
|
-e '/option outbound_json/,/^}/c\ option outbound_json '\''MASKED'\''' \
|
||||||
-e 's/\(option second_proxy_string\).*/\1 '\''MASKED'\''/g' \
|
|
||||||
-e 's/\(option second_outbound_json\).*/\1 '\''MASKED'\''/g' \
|
|
||||||
-e 's/\(vless:\/\/[^@]*@\)/vless:\/\/MASKED@/g' \
|
|
||||||
-e 's/\(ss:\/\/[^@]*@\)/ss:\/\/MASKED@/g' \
|
|
||||||
-e 's/\(pbk=[^&]*\)/pbk=MASKED/g' \
|
|
||||||
-e 's/\(sid=[^&]*\)/sid=MASKED/g' \
|
|
||||||
-e 's/\(option dns_server '\''[^'\'']*\.dns\.nextdns\.io'\''\)/option dns_server '\''MASKED.dns.nextdns.io'\''/g' \
|
|
||||||
-e "s|\(option dns_server 'dns\.nextdns\.io\)/[^']*|\1/MASKED|" \
|
|
||||||
-e 's/\(list urltest_proxy_links\).*/\1 '\''MASKED'\''/g' \
|
-e 's/\(list urltest_proxy_links\).*/\1 '\''MASKED'\''/g' \
|
||||||
|
-e "s@\\(option dns_server '[^/]*\\)/[^']*'@\\1/MASKED'@g" \
|
||||||
|
-e "s@\\(option domain_resolver_dns_server '[^/]*\\)/[^']*'@\\1/MASKED'@g" \
|
||||||
|
-e 's/\(option yacd_secret_key\).*/\1 '\''MASKED'\''/g' \
|
||||||
"$PODKOP_CONFIG" > "$tmp_config"
|
"$PODKOP_CONFIG" > "$tmp_config"
|
||||||
|
|
||||||
cat "$tmp_config"
|
cat "$tmp_config"
|
||||||
@@ -2073,13 +2132,28 @@ check_fakeip() {
|
|||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
clash_api() {
|
clash_api() {
|
||||||
local CLASH_URL="127.0.0.1:9090"
|
|
||||||
local TEST_URL="https://www.gstatic.com/generate_204"
|
|
||||||
local action="$1"
|
local action="$1"
|
||||||
|
local clash_api_controller_address CLASH_URL TEST_URL
|
||||||
|
clash_api_controller_address="$(get_service_listen_address)"
|
||||||
|
if [ -z "$clash_api_controller_address" ]; then
|
||||||
|
clash_api_controller_address="127.0.0.1"
|
||||||
|
fi
|
||||||
|
CLASH_URL="$clash_api_controller_address:$SB_CLASH_API_CONTROLLER_PORT"
|
||||||
|
TEST_URL="https://www.gstatic.com/generate_204"
|
||||||
|
|
||||||
|
local enable_yacd_wan_access yacd_secret_key auth_header
|
||||||
|
config_get_bool enable_yacd_wan_access "settings" "enable_yacd_wan_access" 0
|
||||||
|
config_get yacd_secret_key "settings" "yacd_secret_key"
|
||||||
|
|
||||||
|
if [ "$enable_yacd_wan_access" -eq 1 ]; then
|
||||||
|
auth_header="Authorization: Bearer $yacd_secret_key"
|
||||||
|
else
|
||||||
|
auth_header=""
|
||||||
|
fi
|
||||||
|
|
||||||
case "$action" in
|
case "$action" in
|
||||||
get_proxies)
|
get_proxies)
|
||||||
curl -s "$CLASH_URL/proxies" | jq .
|
curl -s --header "$auth_header" "$CLASH_URL/proxies" | jq .
|
||||||
;;
|
;;
|
||||||
|
|
||||||
get_proxy_latency)
|
get_proxy_latency)
|
||||||
@@ -2092,6 +2166,7 @@ clash_api() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
curl -G -s "$CLASH_URL/proxies/$proxy_tag/delay" \
|
curl -G -s "$CLASH_URL/proxies/$proxy_tag/delay" \
|
||||||
|
--header "$auth_header" \
|
||||||
--data-urlencode "url=$TEST_URL" \
|
--data-urlencode "url=$TEST_URL" \
|
||||||
--data-urlencode "timeout=$timeout" | jq .
|
--data-urlencode "timeout=$timeout" | jq .
|
||||||
;;
|
;;
|
||||||
@@ -2106,6 +2181,7 @@ clash_api() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
curl -G -s "$CLASH_URL/group/$group_tag/delay" \
|
curl -G -s "$CLASH_URL/group/$group_tag/delay" \
|
||||||
|
--header "$auth_header" \
|
||||||
--data-urlencode "url=$TEST_URL" \
|
--data-urlencode "url=$TEST_URL" \
|
||||||
--data-urlencode "timeout=$timeout" | jq .
|
--data-urlencode "timeout=$timeout" | jq .
|
||||||
;;
|
;;
|
||||||
@@ -2120,8 +2196,11 @@ clash_api() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
local response
|
local response
|
||||||
response=$(curl -X PUT -s -w "\n%{http_code}" "$CLASH_URL/proxies/$group_tag" \
|
response=$(
|
||||||
--data-raw "{\"name\":\"$proxy_tag\"}")
|
curl -X PUT -s -w "\n%{http_code}" "$CLASH_URL/proxies/$group_tag" \
|
||||||
|
--header "$auth_header" \
|
||||||
|
--data-raw "{\"name\":\"$proxy_tag\"}"
|
||||||
|
)
|
||||||
|
|
||||||
local http_code
|
local http_code
|
||||||
local body
|
local body
|
||||||
@@ -2279,9 +2358,9 @@ global_check() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$sing_box_version_ok" -eq 1 ]; then
|
if [ "$sing_box_version_ok" -eq 1 ]; then
|
||||||
print_global "✅ Sing-box version >= 1.12.4"
|
print_global "✅ Sing-box version is compatible (newer than 1.12.4)"
|
||||||
else
|
else
|
||||||
print_global "❌ Sing-box version >= 1.12.4"
|
print_global "❌ Sing-box version is not compatible (older than 1.12.4)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$sing_box_service_exist" -eq 1 ]; then
|
if [ "$sing_box_service_exist" -eq 1 ]; then
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ SB_TPROXY_INBOUND_PORT=1602
|
|||||||
SB_DNS_INBOUND_TAG="dns-in"
|
SB_DNS_INBOUND_TAG="dns-in"
|
||||||
SB_DNS_INBOUND_ADDRESS="127.0.0.42"
|
SB_DNS_INBOUND_ADDRESS="127.0.0.42"
|
||||||
SB_DNS_INBOUND_PORT=53
|
SB_DNS_INBOUND_PORT=53
|
||||||
SB_MIXED_INBOUND_ADDRESS="0.0.0.0" # TODO(ampetelin): maybe to determine address?
|
|
||||||
SB_SERVICE_MIXED_INBOUND_TAG="service-mixed-in"
|
SB_SERVICE_MIXED_INBOUND_TAG="service-mixed-in"
|
||||||
SB_SERVICE_MIXED_INBOUND_ADDRESS="127.0.0.1"
|
SB_SERVICE_MIXED_INBOUND_ADDRESS="127.0.0.1"
|
||||||
SB_SERVICE_MIXED_INBOUND_PORT=4534
|
SB_SERVICE_MIXED_INBOUND_PORT=4534
|
||||||
@@ -47,7 +46,7 @@ SB_DIRECT_OUTBOUND_TAG="direct-out"
|
|||||||
# Route
|
# Route
|
||||||
SB_REJECT_RULE_TAG="reject-rule-tag"
|
SB_REJECT_RULE_TAG="reject-rule-tag"
|
||||||
# Experimental
|
# Experimental
|
||||||
SB_CLASH_API_CONTROLLER="0.0.0.0:9090"
|
SB_CLASH_API_CONTROLLER_PORT=9090
|
||||||
|
|
||||||
## Lists
|
## Lists
|
||||||
GITHUB_RAW_URL="https://raw.githubusercontent.com/itdoginfo/allow-domains/main"
|
GITHUB_RAW_URL="https://raw.githubusercontent.com/itdoginfo/allow-domains/main"
|
||||||
|
|||||||
@@ -105,37 +105,6 @@ get_domain_resolver_tag() {
|
|||||||
echo "$section-$postfix"
|
echo "$section-$postfix"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Constructs and returns a ruleset tag using section, name, optional type, and a fixed postfix
|
|
||||||
get_ruleset_tag() {
|
|
||||||
local section="$1"
|
|
||||||
local name="$2"
|
|
||||||
local type="$3"
|
|
||||||
local postfix="ruleset"
|
|
||||||
|
|
||||||
if [ -n "$type" ]; then
|
|
||||||
echo "$section-$name-$type-$postfix"
|
|
||||||
else
|
|
||||||
echo "$section-$name-$postfix"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Determines the ruleset format based on the file extension (json → source, srs → binary)
|
|
||||||
get_ruleset_format_by_file_extension() {
|
|
||||||
local file_extension="$1"
|
|
||||||
|
|
||||||
local format
|
|
||||||
case "$file_extension" in
|
|
||||||
json) format="source" ;;
|
|
||||||
srs) format="binary" ;;
|
|
||||||
*)
|
|
||||||
log "Unsupported file extension: .$file_extension" "error"
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "$format"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Converts a comma-separated string into a JSON array string
|
# Converts a comma-separated string into a JSON array string
|
||||||
comma_string_to_json_array() {
|
comma_string_to_json_array() {
|
||||||
local input="$1"
|
local input="$1"
|
||||||
@@ -156,6 +125,12 @@ url_decode() {
|
|||||||
printf '%b' "$(echo "$encoded" | sed 's/+/ /g; s/%/\\x/g')"
|
printf '%b' "$(echo "$encoded" | sed 's/+/ /g; s/%/\\x/g')"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Returns the scheme (protocol) part of a URL
|
||||||
|
url_get_scheme() {
|
||||||
|
local url="$1"
|
||||||
|
echo "${url%%://*}"
|
||||||
|
}
|
||||||
|
|
||||||
# Extracts the userinfo (username[:password]) part from a URL
|
# Extracts the userinfo (username[:password]) part from a URL
|
||||||
url_get_userinfo() {
|
url_get_userinfo() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
@@ -165,13 +140,23 @@ url_get_userinfo() {
|
|||||||
# Extracts the host part from a URL
|
# Extracts the host part from a URL
|
||||||
url_get_host() {
|
url_get_host() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*@##' -e 's#\([:/].*\|$\)##p'
|
|
||||||
|
url="${url#*://}"
|
||||||
|
url="${url#*@}"
|
||||||
|
url="${url%%[/?#]*}"
|
||||||
|
|
||||||
|
echo "${url%%:*}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extracts the port number from a URL
|
# Extracts the port number from a URL
|
||||||
url_get_port() {
|
url_get_port() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*@##' -e 's#^[^/]*:\([0-9][0-9]*\).*#\1#p'
|
|
||||||
|
url="${url#*://}"
|
||||||
|
url="${url#*@}"
|
||||||
|
url="${url%%[/?#]*}"
|
||||||
|
|
||||||
|
[[ "$url" == *:* ]] && echo "${url#*:}" || echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extracts the path from a URL (without query or fragment; returns "/" if empty)
|
# Extracts the path from a URL (without query or fragment; returns "/" if empty)
|
||||||
@@ -268,25 +253,6 @@ migration_rename_config_key() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Download URL content directly
|
|
||||||
download_to_stream() {
|
|
||||||
local url="$1"
|
|
||||||
local http_proxy_address="$2"
|
|
||||||
local retries="${3:-3}"
|
|
||||||
local wait="${4:-2}"
|
|
||||||
|
|
||||||
for attempt in $(seq 1 "$retries"); do
|
|
||||||
if [ -n "$http_proxy_address" ]; then
|
|
||||||
http_proxy="http://$http_proxy_address" https_proxy="http://$http_proxy_address" wget -qO- "$url" | sed 's/\r$//' && break
|
|
||||||
else
|
|
||||||
wget -qO- "$url" | sed 's/\r$//' && break
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Attempt $attempt/$retries to download $url failed" "warn"
|
|
||||||
sleep "$wait"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# Download URL to file
|
# Download URL to file
|
||||||
download_to_file() {
|
download_to_file() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
@@ -305,29 +271,17 @@ download_to_file() {
|
|||||||
log "Attempt $attempt/$retries to download $url failed" "warn"
|
log "Attempt $attempt/$retries to download $url failed" "warn"
|
||||||
sleep "$wait"
|
sleep "$wait"
|
||||||
done
|
done
|
||||||
|
|
||||||
if grep -q $'\r' "$filepath"; then
|
|
||||||
log "Downloaded file has Windows line endings (CRLF). Converting to Unix (LF)"
|
|
||||||
sed -i 's/\r$//' "$filepath"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Decompiles a sing-box SRS binary file into a JSON ruleset file
|
# Converts Windows-style line endings (CRLF) to Unix-style (LF)
|
||||||
decompile_srs_file() {
|
convert_crlf_to_lf() {
|
||||||
local binary_filepath="$1"
|
local filepath="$1"
|
||||||
local output_filepath="$2"
|
|
||||||
|
|
||||||
log "Decompiling $binary_filepath to $output_filepath" "debug"
|
if grep -q $'\r' "$filepath"; then
|
||||||
|
log "File '$filepath' contains CRLF line endings. Converting to LF..." "debug"
|
||||||
if ! file_exists "$binary_filepath"; then
|
local tmpfile
|
||||||
log "File $binary_filepath not found" "error"
|
tmpfile=$(mktemp)
|
||||||
return 1
|
tr -d '\r' < "$filepath" > "$tmpfile" && mv "$tmpfile" "$filepath" || rm -f "$tmpfile"
|
||||||
fi
|
|
||||||
|
|
||||||
sing-box rule-set decompile "$binary_filepath" -o "$output_filepath"
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
log "Decompilation command failed for $binary_filepath" "error"
|
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,4 +353,4 @@ parse_domain_or_subnet_file_to_comma_string() {
|
|||||||
done < "$filepath"
|
done < "$filepath"
|
||||||
|
|
||||||
echo "$result"
|
echo "$result"
|
||||||
}
|
}
|
||||||
@@ -27,4 +27,44 @@ nft_add_set_elements() {
|
|||||||
local elements="$3"
|
local elements="$3"
|
||||||
|
|
||||||
nft add element inet "$table" "$set" "{ $elements }"
|
nft add element inet "$table" "$set" "{ $elements }"
|
||||||
|
}
|
||||||
|
|
||||||
|
nft_add_set_elements_from_file_chunked() {
|
||||||
|
local filepath="$1"
|
||||||
|
local nft_table_name="$2"
|
||||||
|
local nft_set_name="$3"
|
||||||
|
local chunk_size="${4:-5000}"
|
||||||
|
|
||||||
|
local array count
|
||||||
|
count=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||||
|
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
|
||||||
|
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
|
||||||
|
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$array" ]; then
|
||||||
|
array="$line"
|
||||||
|
else
|
||||||
|
array="$array,$line"
|
||||||
|
fi
|
||||||
|
|
||||||
|
count=$((count + 1))
|
||||||
|
|
||||||
|
if [ "$count" = "$chunk_size" ]; then
|
||||||
|
log "Adding $count elements to nft set $nft_set_name" "debug"
|
||||||
|
nft_add_set_elements "$nft_table_name" "$nft_set_name" "$array"
|
||||||
|
array=""
|
||||||
|
count=0
|
||||||
|
fi
|
||||||
|
done < "$filepath"
|
||||||
|
|
||||||
|
if [ -n "$array" ]; then
|
||||||
|
log "Adding $count elements to nft set $nft_set_name" "debug"
|
||||||
|
nft_add_set_elements "$nft_table_name" "$nft_set_name" "$array"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
180
podkop/files/usr/lib/rulesets.sh
Normal file
180
podkop/files/usr/lib/rulesets.sh
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
# Constructs and returns a ruleset tag using section, name, optional type, and a fixed postfix
|
||||||
|
get_ruleset_tag() {
|
||||||
|
local section="$1"
|
||||||
|
local name="$2"
|
||||||
|
local type="$3"
|
||||||
|
local postfix="ruleset"
|
||||||
|
|
||||||
|
if [ -n "$type" ]; then
|
||||||
|
echo "$section-$name-$type-$postfix"
|
||||||
|
else
|
||||||
|
echo "$section-$name-$postfix"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Creates a new ruleset JSON file if it doesn't already exist
|
||||||
|
create_source_rule_set() {
|
||||||
|
local ruleset_filepath="$1"
|
||||||
|
|
||||||
|
if file_exists "$ruleset_filepath"; then
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -n '{version: 3, rules: []}' > "$ruleset_filepath"
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Patch a source ruleset JSON file for sing-box by appending a new ruleset object containing the provided key
|
||||||
|
# and value.
|
||||||
|
# Arguments:
|
||||||
|
# filepath: path to the JSON file to patch
|
||||||
|
# key: the ruleset key to insert (e.g., "ip_cidr")
|
||||||
|
# value: a JSON array of values to assign to the key
|
||||||
|
# Example:
|
||||||
|
# patch_source_ruleset_rules "/tmp/sing-box/ruleset.json" "ip_cidr" '["1.1.1.1","2.2.2.2"]'
|
||||||
|
#######################################
|
||||||
|
patch_source_ruleset_rules() {
|
||||||
|
local filepath="$1"
|
||||||
|
local key="$2"
|
||||||
|
local value="$3"
|
||||||
|
|
||||||
|
local tmpfile=$(mktemp)
|
||||||
|
|
||||||
|
jq --arg key "$key" --argjson value "$value" \
|
||||||
|
'( .rules | map(has($key)) | index(true) ) as $idx |
|
||||||
|
if $idx != null then
|
||||||
|
.rules[$idx][$key] = (.rules[$idx][$key] + $value | unique)
|
||||||
|
else
|
||||||
|
.rules += [{ ($key): $value }]
|
||||||
|
end' "$filepath" > "$tmpfile"
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
rm -f "$tmpfile"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv "$tmpfile" "$filepath"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Imports a plain domain list into a ruleset in chunks, validating domains and appending them as domain_suffix rules
|
||||||
|
import_plain_domain_list_to_local_source_ruleset_chunked() {
|
||||||
|
local plain_list_filepath="$1"
|
||||||
|
local ruleset_filepath="$2"
|
||||||
|
local chunk_size="${3:-5000}"
|
||||||
|
|
||||||
|
local array count json_array
|
||||||
|
count=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||||
|
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
|
||||||
|
if ! is_domain_suffix "$line"; then
|
||||||
|
log "'$line' is not a valid domain" "debug"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$array" ]; then
|
||||||
|
array="$line"
|
||||||
|
else
|
||||||
|
array="$array,$line"
|
||||||
|
fi
|
||||||
|
|
||||||
|
count=$((count + 1))
|
||||||
|
|
||||||
|
if [ "$count" = "$chunk_size" ]; then
|
||||||
|
log "Adding $count elements to rule set at $ruleset_filepath" "debug"
|
||||||
|
json_array="$(comma_string_to_json_array "$array")"
|
||||||
|
patch_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array"
|
||||||
|
array=""
|
||||||
|
count=0
|
||||||
|
fi
|
||||||
|
done < "$plain_list_filepath"
|
||||||
|
|
||||||
|
if [ -n "$array" ]; then
|
||||||
|
log "Adding $count elements to rule set at $ruleset_filepath" "debug"
|
||||||
|
json_array="$(comma_string_to_json_array "$array")"
|
||||||
|
patch_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Imports a plain IPv4/CIDR list into a ruleset in chunks, validating entries and appending them as ip_cidr rules
|
||||||
|
import_plain_subnet_list_to_local_source_ruleset_chunked() {
|
||||||
|
local plain_list_filepath="$1"
|
||||||
|
local ruleset_filepath="$2"
|
||||||
|
local chunk_size="${3:-5000}"
|
||||||
|
|
||||||
|
local array count json_array
|
||||||
|
count=0
|
||||||
|
while IFS= read -r line; do
|
||||||
|
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||||
|
|
||||||
|
[ -z "$line" ] && continue
|
||||||
|
|
||||||
|
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
|
||||||
|
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$array" ]; then
|
||||||
|
array="$line"
|
||||||
|
else
|
||||||
|
array="$array,$line"
|
||||||
|
fi
|
||||||
|
|
||||||
|
count=$((count + 1))
|
||||||
|
|
||||||
|
if [ "$count" = "$chunk_size" ]; then
|
||||||
|
log "Adding $count elements to ruleset at $ruleset_filepath" "debug"
|
||||||
|
json_array="$(comma_string_to_json_array "$array")"
|
||||||
|
patch_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
||||||
|
array=""
|
||||||
|
count=0
|
||||||
|
fi
|
||||||
|
done < "$plain_list_filepath"
|
||||||
|
|
||||||
|
if [ -n "$array" ]; then
|
||||||
|
log "Adding $count elements to ruleset at $ruleset_filepath" "debug"
|
||||||
|
json_array="$(comma_string_to_json_array "$array")"
|
||||||
|
patch_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determines the ruleset format based on the file extension (json → source, srs → binary)
|
||||||
|
get_ruleset_format_by_file_extension() {
|
||||||
|
local file_extension="$1"
|
||||||
|
|
||||||
|
local format
|
||||||
|
case "$file_extension" in
|
||||||
|
json) format="source" ;;
|
||||||
|
srs) format="binary" ;;
|
||||||
|
*)
|
||||||
|
log "Unsupported file extension: .$file_extension" "error"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "$format"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Decompiles a sing-box SRS binary file into a JSON ruleset file
|
||||||
|
decompile_binary_ruleset() {
|
||||||
|
local binary_filepath="$1"
|
||||||
|
local output_filepath="$2"
|
||||||
|
|
||||||
|
log "Decompiling $binary_filepath to $output_filepath" "debug"
|
||||||
|
sing-box rule-set decompile "$binary_filepath" -o "$output_filepath"
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
log "Decompilation command failed for $binary_filepath" "error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extracts all ip_cidr entries from a JSON ruleset file and writes them to an output file.
|
||||||
|
extract_ip_cidr_from_json_ruleset_to_file() {
|
||||||
|
local json_file="$1"
|
||||||
|
local output_file="$2"
|
||||||
|
|
||||||
|
log "Extracting ip_cidr entries from $json_file to $output_file" "debug"
|
||||||
|
jq -r '.rules[].ip_cidr[]' "$json_file" > "$output_file"
|
||||||
|
}
|
||||||
@@ -64,7 +64,8 @@ sing_box_cf_add_proxy_outbound() {
|
|||||||
url=$(url_decode "$url")
|
url=$(url_decode "$url")
|
||||||
url=$(url_strip_fragment "$url")
|
url=$(url_strip_fragment "$url")
|
||||||
|
|
||||||
local scheme="${url%%://*}"
|
local scheme
|
||||||
|
scheme="$(url_get_scheme "$url")"
|
||||||
case "$scheme" in
|
case "$scheme" in
|
||||||
socks4 | socks4a | socks5)
|
socks4 | socks4a | socks5)
|
||||||
local tag host port version userinfo username password udp_over_tcp
|
local tag host port version userinfo username password udp_over_tcp
|
||||||
@@ -146,6 +147,21 @@ sing_box_cf_add_proxy_outbound() {
|
|||||||
config=$(_add_outbound_security "$config" "$tag" "$url")
|
config=$(_add_outbound_security "$config" "$tag" "$url")
|
||||||
config=$(_add_outbound_transport "$config" "$tag" "$url")
|
config=$(_add_outbound_transport "$config" "$tag" "$url")
|
||||||
;;
|
;;
|
||||||
|
hysteria2 | hy2)
|
||||||
|
local tag host port password obfuscator_type obfuscator_password upload_mbps download_mbps
|
||||||
|
tag=$(get_outbound_tag_by_section "$section")
|
||||||
|
host=$(url_get_host "$url")
|
||||||
|
port="$(url_get_port "$url")"
|
||||||
|
password=$(url_get_userinfo "$url")
|
||||||
|
obfuscator_type=$(url_get_query_param "$url" "obfs")
|
||||||
|
obfuscator_password=$(url_get_query_param "$url" "obfs-password")
|
||||||
|
upload_mbps=$(url_get_query_param "$url" "upmbps")
|
||||||
|
download_mbps=$(url_get_query_param "$url" "downmbps")
|
||||||
|
|
||||||
|
config=$(sing_box_cm_add_hysteria2_outbound "$config" "$tag" "$host" "$port" "$password" "$obfuscator_type" \
|
||||||
|
"$obfuscator_password" "$upload_mbps" "$download_mbps")
|
||||||
|
config=$(_add_outbound_security "$config" "$tag" "$url")
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
log "Unsupported proxy $scheme type. Aborted." "fatal"
|
log "Unsupported proxy $scheme type. Aborted." "fatal"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -160,13 +176,20 @@ _add_outbound_security() {
|
|||||||
local outbound_tag="$2"
|
local outbound_tag="$2"
|
||||||
local url="$3"
|
local url="$3"
|
||||||
|
|
||||||
local security
|
local security scheme
|
||||||
security=$(url_get_query_param "$url" "security")
|
security=$(url_get_query_param "$url" "security")
|
||||||
|
if [ -z "$security" ]; then
|
||||||
|
scheme="$(url_get_scheme "$url")"
|
||||||
|
if [ "$scheme" = "hysteria2" ] || [ "$scheme" = "hy2" ]; then
|
||||||
|
security="tls"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
case "$security" in
|
case "$security" in
|
||||||
tls | reality)
|
tls | reality)
|
||||||
local sni insecure alpn fingerprint public_key short_id
|
local sni insecure alpn fingerprint public_key short_id
|
||||||
sni=$(url_get_query_param "$url" "sni")
|
sni=$(url_get_query_param "$url" "sni")
|
||||||
insecure=$(url_get_query_param "$url" "allowInsecure")
|
insecure=$(_get_insecure_query_param_from_url "$url")
|
||||||
alpn=$(comma_string_to_json_array "$(url_get_query_param "$url" "alpn")")
|
alpn=$(comma_string_to_json_array "$(url_get_query_param "$url" "alpn")")
|
||||||
fingerprint=$(url_get_query_param "$url" "fp")
|
fingerprint=$(url_get_query_param "$url" "fp")
|
||||||
public_key=$(url_get_query_param "$url" "pbk")
|
public_key=$(url_get_query_param "$url" "pbk")
|
||||||
@@ -193,6 +216,18 @@ _add_outbound_security() {
|
|||||||
echo "$config"
|
echo "$config"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_get_insecure_query_param_from_url() {
|
||||||
|
local url="$1"
|
||||||
|
|
||||||
|
local insecure
|
||||||
|
insecure=$(url_get_query_param "$url" "allowInsecure")
|
||||||
|
if [ -z "$insecure" ]; then
|
||||||
|
insecure=$(url_get_query_param "$url" "insecure")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$insecure"
|
||||||
|
}
|
||||||
|
|
||||||
_add_outbound_transport() {
|
_add_outbound_transport() {
|
||||||
local config="$1"
|
local config="$1"
|
||||||
local outbound_tag="$2"
|
local outbound_tag="$2"
|
||||||
@@ -214,7 +249,12 @@ _add_outbound_transport() {
|
|||||||
;;
|
;;
|
||||||
grpc)
|
grpc)
|
||||||
# TODO(ampetelin): Add handling of optional gRPC parameters; example links are needed.
|
# TODO(ampetelin): Add handling of optional gRPC parameters; example links are needed.
|
||||||
config=$(sing_box_cm_set_grpc_transport_for_outbound "$config" "$outbound_tag")
|
local grpc_service_name
|
||||||
|
grpc_service_name=$(url_get_query_param "$url" "serviceName")
|
||||||
|
|
||||||
|
config=$(
|
||||||
|
sing_box_cm_set_grpc_transport_for_outbound "$config" "$outbound_tag" "$grpc_service_name"
|
||||||
|
)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Unknown transport '$transport' detected." "error"
|
log "Unknown transport '$transport' detected." "error"
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ SERVICE_TAG="__service_tag"
|
|||||||
#######################################
|
#######################################
|
||||||
# Configure the logging section of a sing-box JSON configuration.
|
# Configure the logging section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string, JSON configuration
|
||||||
# disabled: boolean, true to disable logging
|
# disabled: boolean, true to disable logging
|
||||||
# level: string, e.g., "info", "debug", "warn"
|
# level: string, log level. One of: trace debug info warn error fatal panic.
|
||||||
# timestamp: boolean, true to include timestamps
|
# timestamp: boolean, true to include timestamps
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
@@ -50,7 +50,7 @@ sing_box_cm_configure_log() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Configure the DNS section of a sing-box JSON configuration.
|
# Configure the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# final: string, default dns server tag
|
# final: string, default dns server tag
|
||||||
# strategy: string, default domain strategy for resolving the domain names
|
# strategy: string, default domain strategy for resolving the domain names
|
||||||
# independent_cache: boolean, whether to use an independent DNS cache
|
# independent_cache: boolean, whether to use an independent DNS cache
|
||||||
@@ -82,12 +82,12 @@ sing_box_cm_configure_dns() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a UDP DNS server to the DNS section of a sing-box JSON configuration.
|
# Add a UDP DNS server to the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the DNS server
|
# tag: string, identifier for the DNS server
|
||||||
# server_address: string, IP address or hostname of the DNS server
|
# server_address: string, IP address or hostname of the DNS server
|
||||||
# server_port: string or number, port of the DNS server
|
# server_port: string or integer, port of the DNS server
|
||||||
# domain_resolver: string, domain resolver to use for resolving domain names
|
# domain_resolver: string, domain resolver to use for resolving domain names (optional)
|
||||||
# detour: string, tag of the upstream outbound
|
# detour: string, tag of the upstream outbound (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -122,12 +122,12 @@ sing_box_cm_add_udp_dns_server() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a TLS DNS server to the DNS section of a sing-box JSON configuration.
|
# Add a TLS DNS server to the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the DNS server
|
# tag: string, identifier for the DNS server
|
||||||
# server_address: string, IP address or hostname of the DNS server
|
# server_address: string, IP address or hostname of the DNS server
|
||||||
# server_port: string or number, port of the DNS server
|
# server_port: string or integer, port of the DNS server
|
||||||
# domain_resolver: string, domain resolver to use for resolving domain names
|
# domain_resolver: string, domain resolver to use for resolving domain names (optional)
|
||||||
# detour: string, tag of the upstream outbound
|
# detour: string, tag of the upstream outbound (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -162,14 +162,14 @@ sing_box_cm_add_tls_dns_server() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add an HTTPS DNS server to the DNS section of a sing-box JSON configuration.
|
# Add an HTTPS DNS server to the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the DNS server
|
# tag: string, identifier for the DNS server
|
||||||
# server_address: string, IP address or hostname of the DNS server
|
# server_address: string, IP address or hostname of the DNS server
|
||||||
# server_port: string or number, port of the DNS server
|
# server_port: string or integer, port of the DNS server
|
||||||
# path: string, optional URL path for HTTPS DNS requests
|
# path: string, URL path for HTTPS DNS requests (optional)
|
||||||
# headers: string, optional additional headers for HTTPS DNS requests
|
# headers: string, additional headers for HTTPS DNS requests (optional)
|
||||||
# domain_resolver: string, domain resolver to use for resolving domain names
|
# domain_resolver: string, domain resolver to use for resolving domain names (optional)
|
||||||
# detour: string, tag of the upstream outbound
|
# detour: string, tag of the upstream outbound (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -210,7 +210,7 @@ sing_box_cm_add_https_dns_server() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a FakeIP DNS server to the DNS section of a sing-box JSON configuration.
|
# Add a FakeIP DNS server to the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the DNS server
|
# tag: string, identifier for the DNS server
|
||||||
# inet4_range: string, IPv4 range used for fake IP mapping
|
# inet4_range: string, IPv4 range used for fake IP mapping
|
||||||
# Outputs:
|
# Outputs:
|
||||||
@@ -236,7 +236,7 @@ sing_box_cm_add_fakeip_dns_server() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a DNS routing rule to the DNS section of a sing-box JSON configuration.
|
# Add a DNS routing rule to the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# server: string, target DNS server for the rule
|
# server: string, target DNS server for the rule
|
||||||
# tag: string, identifier for the route rule
|
# tag: string, identifier for the route rule
|
||||||
# Outputs:
|
# Outputs:
|
||||||
@@ -263,10 +263,10 @@ sing_box_cm_add_dns_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Patch a DNS routing rule in the DNS section of a sing-box JSON configuration.
|
# Patch a DNS routing rule in the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier of the rule to patch
|
# tag: string, identifier of the rule to patch
|
||||||
# key: string, the key in the rule to update or add
|
# key: string, the key in the rule to update or add
|
||||||
# value: JSON value to assign to the key
|
# value: string, JSON value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -304,9 +304,9 @@ sing_box_cm_patch_dns_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a DNS reject rule to the DNS section of a sing-box JSON configuration.
|
# Add a DNS reject rule to the DNS section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# key: string, the key to set for the reject rule
|
# key: string, the key to set for the reject rule
|
||||||
# value: JSON value to assign to the key
|
# value: string, JSON value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -331,10 +331,10 @@ sing_box_cm_add_dns_reject_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a TProxy inbound to the inbounds section of a sing-box JSON configuration.
|
# Add a TProxy inbound to the inbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the inbound
|
# tag: string, identifier for the inbound
|
||||||
# listen_address: string, IP address to listen on
|
# listen_address: string, IP address to listen on
|
||||||
# listen_port: number, port to listen on
|
# listen_port: integer, port to listen on
|
||||||
# tcp_fast_open: boolean, enable or disable TCP Fast Open
|
# tcp_fast_open: boolean, enable or disable TCP Fast Open
|
||||||
# udp_fragment: boolean, enable or disable UDP fragmentation
|
# udp_fragment: boolean, enable or disable UDP fragmentation
|
||||||
# Outputs:
|
# Outputs:
|
||||||
@@ -369,10 +369,10 @@ sing_box_cm_add_tproxy_inbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Direct inbound to the inbounds section of a sing-box JSON configuration.
|
# Add a Direct inbound to the inbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the inbound
|
# tag: string, identifier for the inbound
|
||||||
# listen_address: string, IP address to listen on
|
# listen_address: string, IP address to listen on
|
||||||
# listen_port: number, port to listen on
|
# listen_port: integer, port to listen on
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -399,10 +399,10 @@ sing_box_cm_add_direct_inbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Mixed inbound to the inbounds section of a sing-box JSON configuration.
|
# Add a Mixed inbound to the inbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the inbound
|
# tag: string, identifier for the inbound
|
||||||
# listen_address: string, IP address to listen on
|
# listen_address: string, IP address to listen on
|
||||||
# listen_port: number, port to listen on
|
# listen_port: integer, port to listen on
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -429,7 +429,7 @@ sing_box_cm_add_mixed_inbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Direct outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a Direct outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
@@ -451,15 +451,15 @@ sing_box_cm_add_direct_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a SOCKS outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a SOCKS outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# server_address: string, IP address or hostname of the SOCKS server
|
# server_address: string, IP address or hostname of the SOCKS server
|
||||||
# server_port: number, port of the SOCKS server
|
# server_port: integer, port of the SOCKS server
|
||||||
# version: string, optional SOCKS version
|
# version: string, SOCKS version (optional)
|
||||||
# username: string, optional username for authentication
|
# username: string, username for authentication (optional)
|
||||||
# password: string, optional password for authentication
|
# password: string, password for authentication (optional)
|
||||||
# network: string, optional network type (e.g., "tcp")
|
# network: string, network type (e.g., "tcp") (optional)
|
||||||
# udp_over_tcp: number, optional version for UDP over TCP
|
# udp_over_tcp: integer, version for UDP over TCP (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -509,16 +509,16 @@ sing_box_cm_add_socks_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Shadowsocks outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a Shadowsocks outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# server_address: string, IP address or hostname of the Shadowsocks server
|
# server_address: string, IP address or hostname of the Shadowsocks server
|
||||||
# server_port: number, port of the Shadowsocks server
|
# server_port: integer, port of the Shadowsocks server
|
||||||
# method: string, encryption method
|
# method: string, encryption method
|
||||||
# password: string, password for encryption
|
# password: string, password for encryption
|
||||||
# network: string, optional network type (e.g., "tcp")
|
# network: string, network type (e.g., "tcp") (optional)
|
||||||
# udp_over_tcp: number, optional version for UDP over TCP
|
# udp_over_tcp: integer, version for UDP over TCP (optional)
|
||||||
# plugin: string, optional plugin name
|
# plugin: string, plugin name (optional)
|
||||||
# plugin_opts: string, optional plugin options
|
# plugin_opts: string, plugin options (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -573,14 +573,14 @@ sing_box_cm_add_shadowsocks_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a VLESS outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a VLESS outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# server_address: string, IP address or hostname of the VLESS server
|
# server_address: string, IP address or hostname of the VLESS server
|
||||||
# server_port: number, port of the VLESS server
|
# server_port: integer, port of the VLESS server
|
||||||
# uuid: string, user UUID
|
# uuid: string, user UUID
|
||||||
# flow: string, optional flow setting
|
# flow: string, flow setting (optional)
|
||||||
# network: string, optional network type (e.g., "tcp")
|
# network: string, network type (e.g., "tcp") (optional)
|
||||||
# packet_encoding: string, optional packet encoding method
|
# packet_encoding: string, packet encoding method (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -624,12 +624,12 @@ sing_box_cm_add_vless_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Trojan outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a Trojan outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: string, JSON configuration
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# server_address: string, IP address or hostname of the Trojan server
|
# server_address: string, IP address or hostname of the Trojan server
|
||||||
# server_port: number, port of the Trojan server
|
# server_port: integer, port of the Trojan server
|
||||||
# password: string, password for authentication
|
# password: string, password for authentication
|
||||||
# network: string, optional network type (e.g., "tcp")
|
# network: string, network type (e.g., "tcp") (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -661,15 +661,76 @@ sing_box_cm_add_trojan_outbound() {
|
|||||||
)]'
|
)]'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Add a Hysteria2 outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
|
# Arguments:
|
||||||
|
# config: string (JSON), sing-box configuration to modify
|
||||||
|
# tag: string, identifier for the outbound
|
||||||
|
# server_address: string, IP address or hostname of the Hysteria2 server
|
||||||
|
# server_port: integer, port of the Hysteria2 server
|
||||||
|
# password: string, password for authentication
|
||||||
|
# obfuscator_type: string, obfuscation type (optional)
|
||||||
|
# obfuscator_password: string, obfuscation password (optional)
|
||||||
|
# upload_mbps: integer, upload bandwidth limit in Mbps (optional)
|
||||||
|
# download_mbps: integer, download bandwidth limit in Mbps (optional)
|
||||||
|
# network: string, network type (e.g., "udp") (optional)
|
||||||
|
# Outputs:
|
||||||
|
# Writes updated JSON configuration to stdout
|
||||||
|
# Example:
|
||||||
|
# CONFIG=$(sing_box_cm_add_hysteria2_outbound "$CONFIG" "hysteria2-out" "example.com" 443 "supersecret" \
|
||||||
|
# "salamander" "obfs-pass" "50" "200" "udp")
|
||||||
|
#######################################
|
||||||
|
sing_box_cm_add_hysteria2_outbound() {
|
||||||
|
local config="$1"
|
||||||
|
local tag="$2"
|
||||||
|
local server_address="$3"
|
||||||
|
local server_port="$4"
|
||||||
|
local password="$5"
|
||||||
|
local obfuscator_type="$6"
|
||||||
|
local obfuscator_password="$7"
|
||||||
|
local upload_mbps="$8"
|
||||||
|
local download_mbps="$9"
|
||||||
|
local network="${10}"
|
||||||
|
|
||||||
|
echo "$config" | jq \
|
||||||
|
--arg tag "$tag" \
|
||||||
|
--arg server_address "$server_address" \
|
||||||
|
--arg server_port "$server_port" \
|
||||||
|
--arg password "$password" \
|
||||||
|
--arg obfuscator_type "$obfuscator_type" \
|
||||||
|
--arg obfuscator_password "$obfuscator_password" \
|
||||||
|
--arg upload_mbps "$upload_mbps" \
|
||||||
|
--arg download_mbps "$download_mbps" \
|
||||||
|
--arg network "$network" \
|
||||||
|
'.outbounds += [(
|
||||||
|
{
|
||||||
|
type: "hysteria2",
|
||||||
|
tag: $tag,
|
||||||
|
server: $server_address,
|
||||||
|
server_port: ($server_port | tonumber),
|
||||||
|
password: $password
|
||||||
|
}
|
||||||
|
+ (if $obfuscator_type != "" and $obfuscator_password != "" then {
|
||||||
|
obfs: {
|
||||||
|
type: $obfuscator_type,
|
||||||
|
password: $obfuscator_password
|
||||||
|
}
|
||||||
|
} else {} end)
|
||||||
|
+ (if $upload_mbps != "" then {up_mbps: ($upload_mbps | tonumber)} else {} end)
|
||||||
|
+ (if $download_mbps != "" then {down_mbps: ($download_mbps | tonumber)} else {} end)
|
||||||
|
+ (if $network != "" then {network: $network} else {} end)
|
||||||
|
)]'
|
||||||
|
}
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Set gRPC transport settings for an outbound in a sing-box JSON configuration.
|
# Set gRPC transport settings for an outbound in a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier of the outbound to modify
|
# tag: string, identifier of the outbound to modify
|
||||||
# service_name: string, optional gRPC service name
|
# service_name: string, gRPC service name (optional)
|
||||||
# idle_timeout: string or number, optional idle timeout
|
# idle_timeout: string or integer, idle timeout (optional)
|
||||||
# ping_timeout: string or number, optional ping timeout
|
# ping_timeout: string or integer, ping timeout (optional)
|
||||||
# permit_without_stream: boolean, optional flag for permitting without stream
|
# permit_without_stream: boolean, flag for permitting without stream (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -709,12 +770,12 @@ sing_box_cm_set_grpc_transport_for_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Set WebSocket transport settings for an outbound in a sing-box JSON configuration.
|
# Set WebSocket transport settings for an outbound in a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier of the outbound to modify
|
# tag: string, identifier of the outbound to modify
|
||||||
# path: string, WebSocket path
|
# path: string, WebSocket path
|
||||||
# host: string, optional Host header for WebSocket
|
# host: string, Host header for WebSocket (optional)
|
||||||
# max_early_data: number, optional maximum early data
|
# max_early_data: integer, maximum early data (optional)
|
||||||
# early_data_header_name: string, optional header name for early data
|
# early_data_header_name: string, header name for early data (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -759,14 +820,14 @@ sing_box_cm_set_ws_transport_for_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Set TLS settings for an outbound in a sing-box JSON configuration.
|
# Set TLS settings for an outbound in a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier of the outbound to modify
|
# tag: string, identifier of the outbound to modify
|
||||||
# server_name: string, optional, used to verify the hostname on the returned certificates
|
# server_name: string, used to verify the hostname on the returned certificates (optional)
|
||||||
# insecure: boolean, accept any server certificate
|
# insecure: boolean, accept any server certificate (optional)
|
||||||
# alpn: JSON value or null, optional supported application level protocols
|
# alpn: string, JSON value, supported application level protocols (optional)
|
||||||
# utls_fingerprint: string, optional uTLS fingerprint
|
# utls_fingerprint: string, uTLS fingerprint (optional)
|
||||||
# reality_public_key: string, optional Reality public key
|
# reality_public_key: string, Reality public key (optional)
|
||||||
# reality_short_id: string, optional Reality short ID
|
# reality_short_id: string, Reality short ID (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -825,7 +886,7 @@ sing_box_cm_set_tls_for_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Direct outbound with a specific network interface to a sing-box JSON configuration.
|
# Add a Direct outbound with a specific network interface to a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# interface: string, network interface to bind the outbound
|
# interface: string, network interface to bind the outbound
|
||||||
# domain_resolver: string, tag of the domain resolver to be used for this outbound (optional)
|
# domain_resolver: string, tag of the domain resolver to be used for this outbound (optional)
|
||||||
@@ -857,9 +918,9 @@ sing_box_cm_add_interface_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a raw outbound JSON object to the outbounds section of a sing-box configuration.
|
# Add a raw outbound JSON object to the outbounds section of a sing-box configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the outbound
|
# tag: string, identifier for the outbound
|
||||||
# raw_outbound: JSON object, the raw outbound configuration to add
|
# raw_outbound: string, JSON object, the raw outbound configuration to add
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -881,14 +942,14 @@ sing_box_cm_add_raw_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a URLTest outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a URLTest outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the URLTest outbound
|
# tag: string, identifier for the URLTest outbound
|
||||||
# outbounds: JSON array of outbound tags to test
|
# outbounds: string, JSON array of outbound tags to test
|
||||||
# url: URL to probe (optional)
|
# url: string, URL to probe (optional)
|
||||||
# interval: test interval (e.g., "10s") (optional)
|
# interval: string, test interval (e.g., "10s") (optional)
|
||||||
# tolerance: max latency difference tolerated (optional)
|
# tolerance: string or integer, max latency difference tolerated (optional)
|
||||||
# idle_timeout: idle timeout duration (optional)
|
# idle_timeout: string or integer, idle timeout duration (optional)
|
||||||
# interrupt_exist_connections: flag to interrupt existing connections ("true"/"false") (optional)
|
# interrupt_exist_connections: boolean, flag to interrupt existing connections ("true"/"false") (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -929,11 +990,11 @@ sing_box_cm_add_urltest_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a Selector outbound to the outbounds section of a sing-box JSON configuration.
|
# Add a Selector outbound to the outbounds section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the Selector outbound
|
# tag: string, identifier for the Selector outbound
|
||||||
# outbounds: JSON array of outbound tags to choose from
|
# outbounds: string (JSON), array of outbound tags to choose from
|
||||||
# default: default outbound tag if none selected (optional)
|
# default: string, default outbound tag if none selected
|
||||||
# interrupt_exist_connections: flag to interrupt existing connections ("true"/"false") (optional)
|
# interrupt_exist_connections: boolean, flag to interrupt existing connections ("true"/"false") (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -965,11 +1026,11 @@ sing_box_cm_add_selector_outbound() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Configure the route section of a sing-box JSON configuration.
|
# Configure the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# final: string, final outbound tag for unmatched traffic
|
# final: string, final outbound tag for unmatched traffic
|
||||||
# auto_detect_interface: boolean, enable or disable automatic interface detection
|
# auto_detect_interface: boolean, enable or disable automatic interface detection
|
||||||
# default_domain_resolver: string, default DNS resolver for domain-based routing
|
# default_domain_resolver: string, default DNS resolver for domain-based routing
|
||||||
# default_interface: string, default network interface to use when auto detection is disabled
|
# default_interface: string, default network interface to use when auto detection is disabled (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1001,7 +1062,7 @@ sing_box_cm_configure_route() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a routing rule to the route section of a sing-box JSON configuration.
|
# Add a routing rule to the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the route rule
|
# tag: string, identifier for the route rule
|
||||||
# inbound: string, inbound tag to match
|
# inbound: string, inbound tag to match
|
||||||
# outbound: string, outbound tag to route matched traffic to
|
# outbound: string, outbound tag to route matched traffic to
|
||||||
@@ -1032,10 +1093,10 @@ sing_box_cm_add_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Patch a routing rule in the route section of a sing-box JSON configuration.
|
# Patch a routing rule in the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier of the route rule to patch
|
# tag: string, identifier of the route rule to patch
|
||||||
# key: string, the key in the rule to update or add
|
# key: string, the key in the rule to update or add
|
||||||
# value: JSON value to assign to the key
|
# value: string (JSON), value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1071,9 +1132,9 @@ sing_box_cm_patch_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a reject rule to the route section of a sing-box JSON configuration.
|
# Add a reject rule to the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# key: string, the key to set for the reject rule
|
# key: string, the key to set for the reject rule
|
||||||
# value: JSON value to assign to the key
|
# value: string (JSON), value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1098,9 +1159,9 @@ sing_box_cm_add_reject_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a hijack-dns rule to the route section of a sing-box JSON configuration.
|
# Add a hijack-dns rule to the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# key: string, the key to set for the hijack-dns rule
|
# key: string, the key to set for the hijack-dns rule
|
||||||
# value: JSON value to assign to the key
|
# value: string (JSON), value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1125,7 +1186,7 @@ sing_box_cm_add_hijack_dns_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a route-options rule to the route section of a sing-box JSON configuration.
|
# Add a route-options rule to the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the route-options rule
|
# tag: string, identifier for the route-options rule
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
@@ -1148,9 +1209,9 @@ sing_box_cm_add_options_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a sniff rule to the route section of a sing-box JSON configuration.
|
# Add a sniff rule to the route section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# key: string, the key to set for the sniff rule
|
# key: string, the key to set for the sniff rule
|
||||||
# value: JSON value to assign to the key
|
# value: string (JSON), value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1176,7 +1237,7 @@ sing_box_cm_sniff_route_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add an inline ruleset to the route.rule_set section of a sing-box JSON configuration.
|
# Add an inline ruleset to the route.rule_set section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the inline ruleset
|
# tag: string, identifier for the inline ruleset
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
@@ -1198,10 +1259,10 @@ sing_box_cm_add_inline_ruleset() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add or update a rule in an inline ruleset within the route.rule_set section of a sing-box JSON configuration.
|
# Add or update a rule in an inline ruleset within the route.rule_set section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier of the inline ruleset
|
# tag: string, identifier of the inline ruleset
|
||||||
# key: string, the key in the ruleset to update or add
|
# key: string, the key in the ruleset to update or add
|
||||||
# value: JSON value to assign to the key
|
# value: string (JSON), value to assign to the key
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1238,7 +1299,7 @@ sing_box_cm_add_inline_ruleset_rule() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a local ruleset to the route.rule_set section of a sing-box JSON configuration.
|
# Add a local ruleset to the route.rule_set section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the local ruleset
|
# tag: string, identifier for the local ruleset
|
||||||
# format: string, format of the local ruleset ("source" or "binary")
|
# format: string, format of the local ruleset ("source" or "binary")
|
||||||
# path: string, file path to the local ruleset
|
# path: string, file path to the local ruleset
|
||||||
@@ -1269,12 +1330,12 @@ sing_box_cm_add_local_ruleset() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Add a remote ruleset to the route.rule_set section of a sing-box JSON configuration.
|
# Add a remote ruleset to the route.rule_set section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# tag: string, identifier for the remote ruleset
|
# tag: string, identifier for the remote ruleset
|
||||||
# format: string, format of the remote ruleset ("source" or "binary")
|
# format: string, format of the remote ruleset ("source" or "binary")
|
||||||
# url: string, URL to download the ruleset from
|
# url: string, URL to download the ruleset from
|
||||||
# download_detour: string, optional detour tag for downloading
|
# download_detour: string, detour tag for downloading (optional)
|
||||||
# update_interval: string, optional update interval for the ruleset
|
# update_interval: string, update interval for the ruleset (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1310,7 +1371,7 @@ sing_box_cm_add_remote_ruleset() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Configure the experimental cache_file section of a sing-box JSON configuration.
|
# Configure the experimental cache_file section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# enabled: boolean, enable or disable file caching
|
# enabled: boolean, enable or disable file caching
|
||||||
# path: string, file path for cache storage
|
# path: string, file path for cache storage
|
||||||
# store_fakeip: boolean, whether to store fake IPs in the cache
|
# store_fakeip: boolean, whether to store fake IPs in the cache
|
||||||
@@ -1339,9 +1400,10 @@ sing_box_cm_configure_cache_file() {
|
|||||||
#######################################
|
#######################################
|
||||||
# Configure the experimental clash_api section of a sing-box JSON configuration.
|
# Configure the experimental clash_api section of a sing-box JSON configuration.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# external_controller: API listening address; Clash API will be disabled if empty
|
# external_controller: string, API listening address; Clash API will be disabled if empty
|
||||||
# external_ui: Optional path to static web resources to serve at http://{{external-controller}}/ui
|
# external_ui: string, path to static web resources to serve at http://{{external-controller}}/ui (optional)
|
||||||
|
# secret: string, secret for the RESTful API Authenticate by specifying HTTP header (optional)
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes updated JSON configuration to stdout
|
# Writes updated JSON configuration to stdout
|
||||||
# Example:
|
# Example:
|
||||||
@@ -1351,65 +1413,23 @@ sing_box_cm_configure_clash_api() {
|
|||||||
local config="$1"
|
local config="$1"
|
||||||
local external_controller="$2"
|
local external_controller="$2"
|
||||||
local external_ui="$3"
|
local external_ui="$3"
|
||||||
|
local secret="$4"
|
||||||
|
|
||||||
echo "$config" | jq \
|
echo "$config" | jq \
|
||||||
--arg external_controller "$external_controller" \
|
--arg external_controller "$external_controller" \
|
||||||
--arg external_ui "$external_ui" \
|
--arg external_ui "$external_ui" \
|
||||||
|
--arg secret "$secret" \
|
||||||
'.experimental.clash_api = {
|
'.experimental.clash_api = {
|
||||||
external_controller: $external_controller,
|
external_controller: $external_controller,
|
||||||
}
|
}
|
||||||
+ (if $external_ui != "" then { external_ui: $external_ui } else {} end)'
|
+ (if $external_ui != "" then { external_ui: $external_ui } else {} end)
|
||||||
}
|
+ (if $secret != "" then { secret: $secret } else {} end)'
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Create a local source ruleset JSON file for sing-box.
|
|
||||||
# Arguments:
|
|
||||||
# filepath: path to the JSON file to create
|
|
||||||
# Example:
|
|
||||||
# sing_box_cm_create_local_source_ruleset "/tmp/sing-box/ruleset.json"
|
|
||||||
#######################################
|
|
||||||
sing_box_cm_create_local_source_ruleset() {
|
|
||||||
local filepath="$1"
|
|
||||||
|
|
||||||
jq -n '{version: 3, rules: []}' > "$filepath"
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Patch a local source ruleset JSON file for sing-box by adding unique! values to a given key.
|
|
||||||
# Arguments:
|
|
||||||
# filepath: path to the JSON file to patch
|
|
||||||
# key: the ruleset key to update (e.g., "ip_cidr")
|
|
||||||
# value: a JSON array of values to add to the key
|
|
||||||
# Example:
|
|
||||||
# sing_box_cm_patch_local_source_ruleset_rules "/tmp/sing-box/ruleset.json" "ip_cidr" '["1.1.1.1","2.2.2.2"]'
|
|
||||||
#######################################
|
|
||||||
sing_box_cm_patch_local_source_ruleset_rules() {
|
|
||||||
local filepath="$1"
|
|
||||||
local key="$2"
|
|
||||||
local value="$3"
|
|
||||||
|
|
||||||
value=$(_normalize_arg "$value")
|
|
||||||
|
|
||||||
local content
|
|
||||||
content="$(cat "$filepath")"
|
|
||||||
|
|
||||||
echo "$content" | jq \
|
|
||||||
--arg key "$key" \
|
|
||||||
--argjson value "$value" '
|
|
||||||
([.rules[]?[$key][]] | unique) as $existing
|
|
||||||
| ($value - $existing) as $value
|
|
||||||
| if ($value | length) > 0 then
|
|
||||||
.rules += [{($key): $value}]
|
|
||||||
else
|
|
||||||
.
|
|
||||||
end
|
|
||||||
' > "$filepath"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Save a sing-box JSON configuration to a file, removing service-specific tags.
|
# Save a sing-box JSON configuration to a file, removing service-specific tags.
|
||||||
# Arguments:
|
# Arguments:
|
||||||
# config: JSON configuration (string)
|
# config: string (JSON), sing-box configuration to modify
|
||||||
# file_path: string, path to save the configuration file
|
# file_path: string, path to save the configuration file
|
||||||
# Outputs:
|
# Outputs:
|
||||||
# Writes the cleaned JSON configuration to the specified file
|
# Writes the cleaned JSON configuration to the specified file
|
||||||
|
|||||||
Reference in New Issue
Block a user