feat: добавить поддержку действия WARP через эндпоинты sing-box-extended

This commit is contained in:
Dushnilin
2026-07-17 16:21:48 +03:00
parent 57ea9f1775
commit 04f5c7144f
8 changed files with 168 additions and 9 deletions
+1 -5
View File
@@ -1,14 +1,10 @@
.idea
.mimocode
fe-app-tachyon/node_modules
fe-app-tachyon/.yarn/
fe-app-tachyon/.env
.DS_Store
shellcheck-v0.10.0/
AGENTS.md
sandbox/
.wsl-build/
dist/
build-out/
build-out/
+18
View File
@@ -3640,3 +3640,21 @@ msgstr ""
#: src/tachyon/tabs/diagnostic/checks/runZapret2Check.ts:107
msgid "Zapret2 sing-box outbound is not configured"
msgstr ""
msgid "WARP Private Key"
msgstr ""
msgid "WireGuard private key from your Cloudflare WARP account"
msgstr ""
msgid "WARP Account ID"
msgstr ""
msgid "Cloudflare WARP account / device ID"
msgstr ""
msgid "WARP Access Token"
msgstr ""
msgid "Cloudflare WARP API access token"
msgstr ""
+18
View File
@@ -2539,3 +2539,21 @@ msgstr "Запуск:"
msgid "Stopping:"
msgstr "Остановка:"
msgid "WARP Private Key"
msgstr "Приватный ключ WARP"
msgid "WireGuard private key from your Cloudflare WARP account"
msgstr "Приватный ключ WireGuard от вашего аккаунта Cloudflare WARP"
msgid "WARP Account ID"
msgstr "ID аккаунта WARP"
msgid "Cloudflare WARP account / device ID"
msgstr "ID аккаунта / устройства Cloudflare WARP"
msgid "WARP Access Token"
msgstr "Токен доступа WARP"
msgid "Cloudflare WARP API access token"
msgstr "Токен доступа к API Cloudflare WARP"
@@ -425,6 +425,7 @@ const actionProvidersAvailabilityState = {
zapretInstalled: false,
zapret2Installed: false,
byedpiInstalled: false,
singBoxExtended: false,
};
let actionProvidersAvailabilityPromise = null;
let actionProvidersAvailabilityLoader = null;
@@ -468,6 +469,12 @@ function updateActionProvidersAvailabilityState(nextState) {
);
}
if (typeof nextState.singBoxExtended !== "undefined") {
actionProvidersAvailabilityState.singBoxExtended = Boolean(
nextState.singBoxExtended,
);
}
actionProvidersAvailabilityPromise = null;
}
@@ -480,6 +487,7 @@ function updateActionProvidersAvailabilityFromSystemInfo(systemInfo) {
zapretInstalled: Boolean(systemInfo.zapret_installed),
zapret2Installed: Boolean(systemInfo.zapret2_installed),
byedpiInstalled: Boolean(systemInfo.byedpi_installed),
singBoxExtended: Boolean(systemInfo.sing_box_extended),
});
}
@@ -3942,6 +3950,7 @@ function ensureActionProvidersAvailabilityLoaded() {
zapretInstalled: Boolean(capabilities?.zapretInstalled),
zapret2Installed: Boolean(capabilities?.zapret2Installed),
byedpiInstalled: Boolean(capabilities?.byedpiInstalled),
singBoxExtended: Boolean(capabilities?.singBoxExtended),
});
return actionProvidersAvailabilityState;
})
@@ -3996,6 +4005,7 @@ function ensureActionProvidersAvailabilityLoaded() {
actionProvidersAvailabilityState.zapretInstalled = false;
actionProvidersAvailabilityState.zapret2Installed = false;
actionProvidersAvailabilityState.byedpiInstalled = false;
// singBoxExtended is set via systemInfo, keep existing value
return actionProvidersAvailabilityState;
})
.finally(() => {
@@ -4017,6 +4027,10 @@ function isByedpiInstalledForUi() {
return actionProvidersAvailabilityState.byedpiInstalled;
}
function isSingBoxExtendedForUi() {
return actionProvidersAvailabilityState.singBoxExtended;
}
function getRuleConfiguredAction(section_id) {
const action = uci.get(UCI_PACKAGE, section_id, "action");
return action ? `${action}` : null;
@@ -4046,6 +4060,8 @@ function getActionOptionLabel(action) {
return "ByeDPI";
case "awg":
return "AmneziaWG";
case "warp":
return "WARP";
case "outbound":
return _("JSON outbound");
case "proxy":
@@ -4073,6 +4089,10 @@ function getRuleActionDisplayValue(section_id) {
return "AmneziaWG";
}
if (action === "warp") {
return "WARP";
}
return getActionOptionLabel(action);
}
@@ -4086,6 +4106,9 @@ function populateActionOptionValues(option) {
option.value("connection", getActionOptionLabel("connection"));
option.value("awg", getActionOptionLabel("awg"));
if (isSingBoxExtendedForUi()) {
option.value("warp", getActionOptionLabel("warp"));
}
option.value("bypass", "Bypass");
option.value("block", "Block");
option.value("dns", "DNS");
@@ -7296,6 +7319,44 @@ function createSectionContent(section) {
o.rmempty = false;
o.depends("action", "awg");
// ── WARP (Cloudflare WARP via sing-box-extended) ──────────────────────────
o = section.taboption(
"settings",
form.Value,
"warp_private_key",
_("WARP Private Key"),
_("WireGuard private key from your Cloudflare WARP account"),
);
o.modalonly = true;
o.rmempty = false;
o.depends("action", "warp");
o.validate = validateRequiredText;
o = section.taboption(
"settings",
form.Value,
"warp_account_id",
_("WARP Account ID"),
_("Cloudflare WARP account / device ID"),
);
o.modalonly = true;
o.rmempty = false;
o.depends("action", "warp");
o.validate = validateRequiredText;
o = section.taboption(
"settings",
form.Value,
"warp_access_token",
_("WARP Access Token"),
_("Cloudflare WARP API access token"),
);
o.modalonly = true;
o.rmempty = false;
o.depends("action", "warp");
o.validate = validateRequiredText;
o = section.taboption(
"settings",
form.DynamicList,
+18
View File
@@ -2539,3 +2539,21 @@ msgstr "Запуск:"
msgid "Stopping:"
msgstr "Остановка:"
msgid "WARP Private Key"
msgstr "Приватный ключ WARP"
msgid "WireGuard private key from your Cloudflare WARP account"
msgstr "Приватный ключ WireGuard от вашего аккаунта Cloudflare WARP"
msgid "WARP Account ID"
msgstr "ID аккаунта WARP"
msgid "Cloudflare WARP account / device ID"
msgstr "ID аккаунта / устройства Cloudflare WARP"
msgid "WARP Access Token"
msgstr "Токен доступа WARP"
msgid "Cloudflare WARP API access token"
msgstr "Токен доступа к API Cloudflare WARP"
+18
View File
@@ -3640,3 +3640,21 @@ msgstr ""
#: src/tachyon/tabs/diagnostic/checks/runZapret2Check.ts:107
msgid "Zapret2 sing-box outbound is not configured"
msgstr ""
msgid "WARP Private Key"
msgstr ""
msgid "WireGuard private key from your Cloudflare WARP account"
msgstr ""
msgid "WARP Account ID"
msgstr ""
msgid "Cloudflare WARP account / device ID"
msgstr ""
msgid "WARP Access Token"
msgstr ""
msgid "Cloudflare WARP API access token"
msgstr ""
+4 -2
View File
@@ -556,6 +556,8 @@ function download_section_action_available(action, byedpi_installed, zapret_inst
action = as_string(action);
if (connections.is_connections_action(action))
return true;
if (action == "awg" || action == "warp")
return true;
if (action == "byedpi")
return bool_flag(byedpi_installed);
if (action == "zapret")
@@ -807,11 +809,11 @@ function rule_action(section) {
}
function rule_action_supported(action) {
return contains([ "connection", "proxy", "outbound", "vpn", "awg", "bypass", "block", "dns", "zapret", "zapret2", "byedpi" ], as_string(action));
return contains([ "connection", "proxy", "outbound", "vpn", "awg", "warp", "bypass", "block", "dns", "zapret", "zapret2", "byedpi" ], as_string(action));
}
function server_routing_section_action_supported(action) {
return contains([ "connection", "proxy", "outbound", "vpn", "awg", "zapret", "zapret2", "byedpi" ], as_string(action));
return contains([ "connection", "proxy", "outbound", "vpn", "awg", "warp", "zapret", "zapret2", "byedpi" ], as_string(action));
}
function duration_to_seconds_value(value) {
+30 -2
View File
@@ -2287,6 +2287,32 @@ function add_awg_outbound(config, section) {
push(config.outbounds, outbound);
}
function add_warp_endpoint(config, section) {
let tag = outbound_tag(section[".name"]);
let account_id = option(section, "warp_account_id", "");
let access_token = option(section, "warp_access_token", "");
let private_key = option(section, "warp_private_key", "");
if (private_key == "")
runtime_generate_unsupported("WARP section '" + section[".name"] + "' missing warp_private_key");
if (account_id == "")
runtime_generate_unsupported("WARP section '" + section[".name"] + "' missing warp_account_id");
if (access_token == "")
runtime_generate_unsupported("WARP section '" + section[".name"] + "' missing warp_access_token");
push(config.endpoints, {
type: "warp",
tag,
name: tag,
profiles: [{
id: account_id,
auth_token: access_token,
private_key
}]
});
}
function add_zapret_outbound(config, section, sections) {
let index = enabled_action_index(sections, section, "zapret");
if (index <= 0)
@@ -2782,6 +2808,8 @@ function add_outbound_for_section(config, section, taken, sections) {
add_connections_outbound(config, section, taken);
else if (action == "awg")
add_awg_outbound(config, section);
else if (action == "warp")
add_warp_endpoint(config, section);
else if (action == "zapret")
add_zapret_outbound(config, section, sections);
else if (action == "zapret2")
@@ -2806,7 +2834,7 @@ function reserve_section_outbound_tags(sections, taken) {
for (let section in sections) {
let action = option(section, "action", "");
if (connections.is_connections_action(action) ||
action == "awg" || action == "byedpi" || action == "zapret" || action == "zapret2")
action == "awg" || action == "warp" || action == "byedpi" || action == "zapret" || action == "zapret2")
taken[outbound_tag(section[".name"])] = true;
if (!connections.is_connections_action(action))
@@ -2831,7 +2859,7 @@ function add_service_route_rules(config, sections) {
for (let section in sections) {
let action = option(section, "action", "");
if (connections.is_connections_action(action) ||
action == "awg" || action == "byedpi" || action == "zapret" || action == "zapret2") {
action == "awg" || action == "warp" || action == "byedpi" || action == "zapret" || action == "zapret2") {
first = section;
break;
}