Кнопка Generate WARP Config: исправление binary UCI и стилизация

- Добавлен генератор WARP конфигурации (warp_generator.uc)
- Исправлена запись binary UCI значений (<b 0x...>) в поля awg_i1-i5:
  warp_generator.uc использует to_hex(), section.js очищает значения перед записью
- generator.uc: добавлена защита uci_bin_to_hex() при чтении awg параметров
- generator.uc: поля awg_i3/i4/i5 со значением '0' пропускаются
- section.js: кнопка Generate WARP Config переработана в стиле Tachyon UI
  (cbi-button-neutral, состояния loading/success/error с анимациями)
This commit is contained in:
Dushnilin
2026-07-17 22:22:08 +03:00
parent ad03951a1d
commit 387a78aebb
7 changed files with 573 additions and 11 deletions
+1
View File
@@ -8,3 +8,4 @@ sandbox/
.wsl-build/ .wsl-build/
dist/ dist/
build-out/ build-out/
scratch/
+26 -1
View File
@@ -1,4 +1,4 @@
# RU translations for TACHYON package. # RU translations for TACHYON package.
# Copyright (C) 2026 THE TACHYON COPYRIGHT HOLDER # Copyright (C) 2026 THE TACHYON COPYRIGHT HOLDER
# This file is distributed under the same license as the TACHYON package. # This file is distributed under the same license as the TACHYON package.
# Dushnilin, 2026. # Dushnilin, 2026.
@@ -2665,3 +2665,28 @@ msgstr "Разрешить небезопасный TLS"
msgid "Skip TLS certificate verification" msgid "Skip TLS certificate verification"
msgstr "Пропустить проверку TLS сертификата" msgstr "Пропустить проверку TLS сертификата"
msgid "AmneziaWG Generator"
msgstr "Генератор AmneziaWG"
msgid "Automatically generate a Cloudflare WARP account and configure all AmneziaWG settings."
msgstr "Автоматически сгенерировать аккаунт Cloudflare WARP и настроить все параметры AmneziaWG."
msgid "Generate WARP Config"
msgstr "Сгенерировать конфиг WARP"
msgid "Generating..."
msgstr "Генерация..."
msgid "Failed to generate WARP config: "
msgstr "Не удалось сгенерировать конфиг WARP: "
msgid "WARP Configuration generated and loaded successfully!"
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
msgid "Failed to parse WARP config: "
msgstr "Не удалось разобрать конфиг WARP: "
msgid "Error running generator: "
msgstr "Ошибка при запуске генератора: "
@@ -7199,6 +7199,164 @@ function createSectionContent(section) {
}; };
configureTextareaOption(o, analyzeByedpiStrategy); configureTextareaOption(o, analyzeByedpiStrategy);
o = section.taboption(
"settings",
form.Button,
"_generate_warp",
_("AmneziaWG Generator"),
_("Automatically generate a Cloudflare WARP account and configure all AmneziaWG settings.")
);
o.modalonly = true;
o.inputtitle = _("Generate WARP Config");
o.depends("action", "awg");
// Custom render: beautiful gradient button with loading / success / error states
o.renderWidget = function(section_id) {
if (!document.getElementById("tachyon-warp-btn-css")) {
const s = document.createElement("style");
s.id = "tachyon-warp-btn-css";
s.textContent = `
.twg-spinner {
width: 13px; height: 13px;
border: 1.5px solid currentColor;
border-top-color: transparent;
border-radius: 50%;
display: none;
flex-shrink: 0;
animation: twg-spin 0.7s linear infinite;
opacity: 0.6;
}
.twg-loading .twg-spinner { display: inline-block; }
.twg-loading .twg-icon { display: none; }
.twg-icon { flex-shrink: 0; }
.twg-btn.twg-loading { opacity: 0.65; }
.twg-btn.twg-success { color: #4caf50 !important; border-color: #4caf50 !important; }
.twg-btn.twg-error { color: #ef5350 !important; border-color: #ef5350 !important; animation: twg-shake 0.4s ease; }
@keyframes twg-spin { to { transform: rotate(360deg); } }
@keyframes twg-shake {
0%,100% { transform: translateX(0); }
20% { transform: translateX(-5px); }
60% { transform: translateX(5px); }
80% { transform: translateX(-3px); }
}
`;
document.head.appendChild(s);
}
const spinner = E("span", { "class": "twg-spinner" });
const icon = E("span", { "class": "twg-icon" }, ["↺"]);
const label = E("span", { "class": "twg-label" }, [_("Generate WARP Config")]);
const btn = E("button", {
"class": "btn cbi-button cbi-button-neutral twg-btn",
"type": "button",
"style": "display:inline-flex;align-items:center;gap:8px;"
}, [spinner, icon, label]);
btn.addEventListener("click", (ev) => this.onclick && this.onclick.call(this, ev, section_id));
return btn;
};
o.onclick = function(ev, section_id) {
const btn = ev.target.closest(".twg-btn");
const label = btn ? btn.querySelector(".twg-label") : null;
const origText = _("Generate WARP Config");
const setState = (state, text) => {
if (!btn) return;
btn.className = "btn cbi-button cbi-button-neutral twg-btn" + (state ? " twg-" + state : "");
btn.disabled = (state === "loading");
if (label && text) label.textContent = text;
};
const showStatusModal = (title, msg, isError) =>
ui.addNotification(title, E("p", {}, msg), isError ? "danger" : "success");
const resetAfter = (ms) =>
setTimeout(() => setState("", origText), ms);
setState("loading", _("Generating…"));
fs.exec("/usr/bin/tachyon", ["generate_warp"])
.then(function(response) {
if (!response || (response.code ?? 0) !== 0 || !response.stdout) {
setState("error", _("Error"));
resetAfter(2500);
showStatusModal(_("Error"), _("Failed to generate WARP config: ") + (response?.stderr || "Unknown error"), true);
return;
}
try {
const data = JSON.parse(response.stdout);
if (!data.success) {
setState("error", _("Error"));
resetAfter(2500);
showStatusModal(_("Error"), _("Failed to generate WARP config: ") + (data.message || "Unknown error"), true);
return;
}
const getControlWidget = (opt) => {
const widget = document.getElementById(`widget.cbid.${UCI_PACKAGE}.${section_id}.${opt}`);
if (!widget) return null;
if (/^(INPUT|SELECT|TEXTAREA)$/.test(widget.tagName)) return widget;
return widget.querySelector("input:not([type='hidden']), select, textarea");
};
const stripUciBinary = (val) => {
if (typeof val !== "string") return val;
return val.replace(/<b 0x/g, "").replace(/>/g, "").replace(/\s/g, "");
};
const setWidgetValue = (opt, val) => {
const widget = getControlWidget(opt);
if (widget) {
widget.value = val;
widget.dispatchEvent(new Event("input", { bubbles: true }));
widget.dispatchEvent(new Event("change", { bubbles: true }));
}
uci.set(UCI_PACKAGE, section_id, opt, val);
};
setWidgetValue("awg_local_address", data.local_address);
setWidgetValue("awg_private_key", data.private_key);
setWidgetValue("awg_peer_public_key", data.peer_public_key);
setWidgetValue("awg_server_address", data.server_address);
setWidgetValue("awg_server_port", data.server_port);
setWidgetValue("awg_jc", `${data.awg_jc}`);
setWidgetValue("awg_jmin", `${data.awg_jmin}`);
setWidgetValue("awg_jmax", `${data.awg_jmax}`);
setWidgetValue("awg_s1", `${data.awg_s1}`);
setWidgetValue("awg_s2", `${data.awg_s2}`);
setWidgetValue("awg_h1", `${data.awg_h1}`);
setWidgetValue("awg_h2", `${data.awg_h2}`);
setWidgetValue("awg_h3", `${data.awg_h3}`);
setWidgetValue("awg_h4", `${data.awg_h4}`);
setWidgetValue("awg_s3", `${data.awg_s3}`);
setWidgetValue("awg_s4", `${data.awg_s4}`);
setWidgetValue("awg_i1", stripUciBinary(data.awg_i1));
setWidgetValue("awg_i2", stripUciBinary(data.awg_i2));
setWidgetValue("awg_i3", stripUciBinary(data.awg_i3));
setWidgetValue("awg_i4", stripUciBinary(data.awg_i4));
setWidgetValue("awg_i5", stripUciBinary(data.awg_i5));
setState("success", _("Generated!"));
resetAfter(2500);
showStatusModal(_("Success"), _("WARP Configuration generated and loaded successfully!"), false);
} catch (err) {
setState("error", _("Error"));
resetAfter(2500);
showStatusModal(_("Error"), _("Failed to parse WARP config: ") + err.message, true);
}
})
.catch(function(error) {
setState("error", _("Error"));
resetAfter(2500);
showStatusModal(_("Error"), _("Error running generator: ") + error.message, true);
});
};
o = section.taboption( o = section.taboption(
"settings", "settings",
form.Value, form.Value,
+26 -1
View File
@@ -1,4 +1,4 @@
# RU translations for TACHYON package. # RU translations for TACHYON package.
# Copyright (C) 2026 THE TACHYON COPYRIGHT HOLDER # Copyright (C) 2026 THE TACHYON COPYRIGHT HOLDER
# This file is distributed under the same license as the TACHYON package. # This file is distributed under the same license as the TACHYON package.
# Dushnilin, 2026. # Dushnilin, 2026.
@@ -2665,3 +2665,28 @@ msgstr "Разрешить небезопасный TLS"
msgid "Skip TLS certificate verification" msgid "Skip TLS certificate verification"
msgstr "Пропустить проверку TLS сертификата" msgstr "Пропустить проверку TLS сертификата"
msgid "AmneziaWG Generator"
msgstr "Генератор AmneziaWG"
msgid "Automatically generate a Cloudflare WARP account and configure all AmneziaWG settings."
msgstr "Автоматически сгенерировать аккаунт Cloudflare WARP и настроить все параметры AmneziaWG."
msgid "Generate WARP Config"
msgstr "Сгенерировать конфиг WARP"
msgid "Generating..."
msgstr "Генерация..."
msgid "Failed to generate WARP config: "
msgstr "Не удалось сгенерировать конфиг WARP: "
msgid "WARP Configuration generated and loaded successfully!"
msgstr "Конфигурация WARP успешно сгенерирована и загружена!"
msgid "Failed to parse WARP config: "
msgstr "Не удалось разобрать конфиг WARP: "
msgid "Error running generator: "
msgstr "Ошибка при запуске генератора: "
+1
View File
@@ -208,6 +208,7 @@ function command_spec(command) {
validate_nfqws_strategy_json: [ "diagnostics/runtime.uc", "validate-nfqws-strategy-json", 1 ], validate_nfqws_strategy_json: [ "diagnostics/runtime.uc", "validate-nfqws-strategy-json", 1 ],
validate_nfqws2_strategy_json: [ "diagnostics/runtime.uc", "validate-nfqws2-strategy-json", 1 ], validate_nfqws2_strategy_json: [ "diagnostics/runtime.uc", "validate-nfqws2-strategy-json", 1 ],
validate_byedpi_strategy_json: [ "providers/byedpi/validator.uc", "validate-json", 1 ], validate_byedpi_strategy_json: [ "providers/byedpi/validator.uc", "validate-json", 1 ],
generate_warp: [ "service/warp_generator.uc", "", 1 ],
package_prerm: [ "service/package.uc", "prerm", 1 ], package_prerm: [ "service/package.uc", "prerm", 1 ],
package_postinst: [ "service/package.uc", "postinst", 0 ], package_postinst: [ "service/package.uc", "postinst", 0 ],
luci_postinst: [ "service/package.uc", "luci-postinst", 0 ] luci_postinst: [ "service/package.uc", "luci-postinst", 0 ]
@@ -0,0 +1,340 @@
#!/usr/bin/env ucode
let fs = require("fs");
function as_string(value) {
return value == null ? "" : "" + value;
}
function trim(str) {
return replace(as_string(str), /^[ \t\r\n]+|[ \t\r\n]+$/g, "");
}
function write_json(value) {
print(sprintf("%J", value), "\n");
}
// Convert <b 0x...> ucode binary literals to plain hex string
function to_hex(s) {
s = replace(as_string(s), "<b 0x", "");
s = replace(s, ">", "");
return s;
}
function error_response(message) {
write_json({
success: false,
message: as_string(message)
});
}
function exec_output(command) {
let pipe = fs.popen(command, "r");
if (!pipe) return "";
let data = pipe.read("all");
pipe.close();
return data == null ? "" : trim(data);
}
function contains(arr, val) {
for (let x in arr) {
if (x == val) return true;
}
return false;
}
function call_api(method, url, auth_header, body_file) {
let resolve_ips = [ "162.159.192.1", "162.159.193.1", "188.114.98.1", "188.114.99.1" ];
let proxy_opts = [ "", "-x socks5h://127.0.0.1:4534" ];
let last_res = "";
for (let proxy in proxy_opts) {
for (let ip in resolve_ips) {
let auth_str = auth_header != "" ? "-H 'Authorization: Bearer " + auth_header + "' " : "";
let data_str = body_file != "" ? "-d @" + body_file + " " : "";
let cmd = "curl -s --connect-timeout 6 --max-time 12 " + proxy + " --resolve api.cloudflareclient.com:443:" + ip + " -X " + method + " -H 'Content-Type: application/json' -H 'User-Agent: okhttp/3.12.1' " + auth_str + data_str + url;
let res = exec_output(cmd);
if (res != "") {
try {
let parsed = json(res);
if (parsed) {
return parsed;
}
} catch(e) {}
last_res = res;
}
}
}
return last_res != "" ? { success: false, message: last_res } : null;
}
// Query current proxy selection from Clash API for automatic rate limit rotation if proxy is used
let original_server = "";
let available_servers = [];
let clash_data_str = exec_output("curl -s http://192.168.2.1:9090/proxies/MAIN-out");
if (clash_data_str != "") {
try {
let parsed = json(clash_data_str);
if (parsed) {
original_server = parsed.now || "";
available_servers = parsed.all || [];
}
} catch(e) {}
}
function restore_original_server() {
if (original_server != "") {
let body = { name: original_server };
let tmp_file = "/tmp/restore_clash.json";
fs.writefile(tmp_file, sprintf("%J", body));
exec_output("curl -s -X PUT -H 'Content-Type: application/json' -d @" + tmp_file + " http://192.168.2.1:9090/proxies/MAIN-out");
fs.unlink(tmp_file);
}
}
function switch_server(srv_name) {
let body = { name: srv_name };
let tmp_file = "/tmp/switch_clash.json";
fs.writefile(tmp_file, sprintf("%J", body));
exec_output("curl -s -X PUT -H 'Content-Type: application/json' -d @" + tmp_file + " http://192.168.2.1:9090/proxies/MAIN-out");
fs.unlink(tmp_file);
exec_output("sleep 1.5");
}
// 1. Generate WireGuard keys
let keypair_data = exec_output("/usr/bin/sing-box generate wg-keypair 2>/dev/null");
let private_key = null;
let public_key = null;
for (let line in split(keypair_data, "\n")) {
let m_priv = match(line, /^PrivateKey:\s*(.+)$/);
if (m_priv) private_key = trim(m_priv[1]);
let m_pub = match(line, /^PublicKey:\s*(.+)$/);
if (m_pub) public_key = trim(m_pub[1]);
}
// Fallback to wg genkey/pubkey if sing-box generate wg-keypair fails
if (!private_key || !public_key) {
let priv = exec_output("wg genkey 2>/dev/null");
if (priv != "") {
private_key = priv;
public_key = exec_output("echo '" + priv + "' | wg pubkey 2>/dev/null");
}
}
if (!private_key || !public_key) {
restore_original_server();
error_response("Failed to generate WireGuard keypair");
exit(1);
}
// 2. Perform registration
let install_id = "";
let fcm_token = "";
let tos = exec_output("date -u +'%Y-%m-%dT%H:%M:%SZ' 2>/dev/null") || "2026-07-17T20:52:00Z";
let serial_number = exec_output("head -c 8 /dev/urandom | hexdump -ve '1/1 \"%02x\"' 2>/dev/null") || "abcdef1234567890";
let reg_request = {
key: public_key,
install_id: install_id,
fcm_token: fcm_token,
tos: tos,
model: "PC",
serial_number: serial_number,
locale: "en_US"
};
let tmp_req_file = exec_output("mktemp 2>/dev/null") || "/tmp/warp_req.json";
if (fs.writefile(tmp_req_file, sprintf("%J", reg_request)) == null) {
restore_original_server();
error_response("Failed to write temporary registration request file");
exit(1);
}
let api_prefixes = [
"v0i1909051800",
"v0a1909051800",
"v0b1909051800",
"v0c1909051800",
"v0d1909051800",
"v0e1909051800",
"v0f1909051800",
"v0g1909051800",
"v0h1909051800",
"v0i1604021500",
"v0a1604021500"
];
let response_data = null;
let last_error = "";
let chosen_prefix = "";
let server_try_index = 0;
for (let prefix in api_prefixes) {
let url = "https://api.cloudflareclient.com/" + prefix + "/reg";
let parsed = call_api("POST", url, "", tmp_req_file);
if (!parsed) {
last_error = "Timeout or connection failure (prefix: " + prefix + ")";
continue;
}
if (parsed.success && parsed.result) {
response_data = parsed.result;
chosen_prefix = prefix;
break;
}
let msg = parsed.message || (parsed.errors ? parsed.errors[0].message : "Unsuccessful registration");
let code = parsed.errors ? parsed.errors[0].code : null;
if (code == 1015 || index(as_string(msg), "1015") >= 0) {
// Rotate proxy server if available
if (length(available_servers) > 0 && server_try_index < 4) {
let next_srv = available_servers[(server_try_index + 1) % length(available_servers)];
server_try_index++;
switch_server(next_srv);
// Retry request with rotated proxy server
parsed = call_api("POST", url, "", tmp_req_file);
if (parsed && parsed.success && parsed.result) {
response_data = parsed.result;
chosen_prefix = prefix;
break;
}
msg = parsed ? (parsed.message || (parsed.errors ? parsed.errors[0].message : "Unsuccessful registration")) : "Timeout after proxy rotation";
code = parsed && parsed.errors ? parsed.errors[0].code : null;
}
if (code == 1015 || index(as_string(msg), "1015") >= 0) {
msg = "Rate limit exceeded (Cloudflare error 1015). Cloudflare blocks registrations from this IP. Please switch your active server in the Tachyon Dashboard tab and try again.";
}
}
last_error = msg;
}
fs.unlink(tmp_req_file);
if (!response_data) {
restore_original_server();
error_response("Failed to register with Cloudflare WARP API: " + last_error);
exit(1);
}
// 3. Make sure warp_enabled is true
if (!response_data.warp_enabled) {
let patch_body = { warp_enabled: true };
let tmp_patch = exec_output("mktemp 2>/dev/null") || "/tmp/warp_patch.json";
fs.writefile(tmp_patch, sprintf("%J", patch_body));
let url = "https://api.cloudflareclient.com/" + chosen_prefix + "/reg/" + response_data.id;
call_api("PATCH", url, response_data.token, tmp_patch);
fs.unlink(tmp_patch);
}
// 4. Optionally apply WARP+ license key if provided as first arg
let license_key = ARGV[0] || "";
if (license_key != "") {
let patch_body = { license_key: license_key };
let tmp_patch = exec_output("mktemp 2>/dev/null") || "/tmp/warp_patch.json";
fs.writefile(tmp_patch, sprintf("%J", patch_body));
let url = "https://api.cloudflareclient.com/" + chosen_prefix + "/reg/" + response_data.id;
call_api("PATCH", url, response_data.token, tmp_patch);
fs.unlink(tmp_patch);
}
// Restore original proxy server selection
restore_original_server();
// 5. Select fastest endpoint IP using TCP latency probes (via curl)
let probe_ips = [
"162.159.192.1", "162.159.192.6",
"162.159.193.1", "162.159.193.6",
"188.114.98.1", "188.114.98.6",
"188.114.99.1", "188.114.99.6",
"8.6.112.0"
];
// Try to resolve engage.cloudflareclient.com and add resolved IPs
let resolved_ips = exec_output("nslookup engage.cloudflareclient.com 2>/dev/null | grep -E 'Address[ 0-9]*:' | awk '{print $2}'");
for (let ip in split(resolved_ips, "\n")) {
ip = trim(ip);
if (ip != "" && index(ip, "127.0.0.") < 0 && index(ip, ":") < 0 && !contains(probe_ips, ip)) {
push(probe_ips, ip);
}
}
let best_ip = "162.159.192.1";
let best_time = 9999.0;
for (let ip in probe_ips) {
ip = trim(ip);
if (ip == "") continue;
let cmd = "curl -w '%{time_connect}' -o /dev/null -s --max-time 1.0 https://" + ip;
let t_str = exec_output(cmd);
let t = (t_str || "9999.0") * 1.0;
if (t > 0.0 && t < best_time) {
best_time = t;
best_ip = ip;
}
}
let warp_ports = [
854, 859, 864, 878, 880, 890, 891, 894, 903, 908,
928, 934, 939, 942, 943, 945, 946, 955, 968, 987,
988, 1002, 1010, 1014, 1018, 1070, 1074, 1180, 1387, 1843,
2371, 2506, 3138, 3476, 3581, 3854, 4177, 4198, 4233, 5279,
5956, 7103, 7152, 7156, 7281, 7559, 8319, 8742, 8854, 8886, 2408
];
let random_port = warp_ports[time() % length(warp_ports)];
// 6. Formulate CPS packets
let warp_cps_payloads = [
"<b 0xce000000010897a297ecc34cd6dd000044d0ec2e2e1ea2991f467ace4222129b5a098823784694b4897b9986ae0b7280135fa85e196d9ad980b150122129ce2a9379531b0fd3e871ca5fdb883c369832f730e272d7b8b74f393f9f0fa43f11e510ecb2219a52984410c204cf875585340c62238e14ad04dff382f2c200e0ee22fe743b9c6b8b043121c5710ec289f471c91ee414fca8b8be8419ae8ce7ffc53837f6ade262891895f3f4cecd31bc93ac5599e18e4f01b472362b8056c3172b513051f8322d1062997ef4a383b01706598d08d48c221d30e74c7ce000cdad36b706b1bf9b0607c32ec4b3203a4ee21ab64df336212b9758280803fcab14933b0e7ee1e04a7becce3e2633f4852585c567894a5f9efe9706a151b615856647e8b7dba69ab357b3982f554549bef9256111b2d67afde0b496f16962d4957ff654232aa9e845b61463908309cfd9de0a6abf5f425f577d7e5f6440652aa8da5f73588e82e9470f3b21b27b28c649506ae1a7f5f15b876f56abc4615f49911549b9bb39dd804fde182bd2dcec0c33bad9b138ca07d4a4a1650a2c2686acea05727e2a78962a840ae428f55627516e73c83dd8893b02358e81b524b4d99fda6df52b3a8d7a5291326e7ac9d773c5b43b8444554ef5aea104a738ed650aa979674bbed38da58ac29d87c29d387d80b526065baeb073ce65f075ccb56e47533aef357dceaa8293a523c5f6f790be90e4731123d3c6152a70576e90b4ab5bc5ead01576c68ab633ff7d36dcde2a0b2c68897e1acfc4d6483aaaeb635dd63c96b2b6a7a2bfe042f6aed82e5363aa850aace12ee3b1a93f30d8ab9537df483152a5527faca21efc9981b304f11fc95336f5b9637b174c5a0659e2b22e159a9fed4b8e93047371175b1d6d9cc8ab745f3b2281537d1c75fb9451871864efa5d184c38c185fd203de206751b92620f7c369e031d2041e152040920ac2c5ab5340bfc9d0561176abf10a147287ea90758575ac6a9f5ac9f390d0d5b23ee12af583383d994e22c0cf42383834bcd3ada1b3825a0664d8f3fb678261d57601ddf94a8a68a7c273a18c08aa99c7ad8c6c42eab67718843597ec9930457359dfdfbce024afc2dcf9348579a57d8d3490b2fa99f278f1c37d87dad9b221acd575192ffae1784f8e60ec7cee4068b6b988f0433d96d6a1b1865f4e155e9fe020279f434f3bf1bd117b717b92f6cd1cc9bea7d45978bcc3f24bda631a36910110a6ec06da35f8966c9279d130347594f13e9e07514fa370754d1424c0a1545c5070ef9fb2acd14233e8a50bfc5978b5bdf8bc1714731f798d21e2004117c61f2989dd44f0cf027b27d4019e81ed4b5c31db347c4a3a4d85048d7093cf16753d7b0d15e078f5c7a5205dc2f87e330a1f716738dce1c6180e9d02869b5546f1c4d2748f8c90d9693cba4e0079297d22fd61402dea32ff0eb69ebd65a5d0b687d87e3a8b2c42b648aa723c7c7daf37abcc4bb85caea2ee8f55bec20e913b3324ab8f5c3304f820d42ad1b9f2ffc1a3af9927136b4419e1e579ab4c2ae3c776d293d397d575df181e6cae0a4ada5d67ecea171cca3288d57c7bbdaee3befe745fb7d634f70386d873b90c4d6c6596bb65af68f9e5121e67ebf0d89d3c909ceedfb32ce9575a7758ff080724e1ab5d5f43074ecb53a479af21ed03d7b6899c36631c0166f9d47e5e1d4528a5d3d3f744029c4b1c190cbfbad06f5f83f7ad0429fa9a2719c56ffe3783460e166de2d8>",
"<b 0xc7000000010809a1ed4edbbe7615000044d017a61a0d774f04290f119e701ef0035df2b0ed571b0b575e6a07246b856eb6ec036fef07f1e07b861251ad737abeb67e64be714c1dcd865312b1b6c35c089c997aeb5c18f808696fe97289513945d84ca846467603e94e44224877f2c1d3261e4ac18740be4bd064369c94fc08978d99b54bf615250998639010c1284248e1d73004b81fcb20b559d8a17eced7eab3964b5b88ca7a3b8579fc8c1c934189e77143b4ac434138114b1048651b56545b87acbef0952763538f3ddeb37cfc6d58b4881c3b719d7ff78f6ee1324a2914a32381c05a64c700466d280be007253bb030d179c4f1b3dc221e1974e2ee6d6e2b9e8d709159b5ef22e1783dbba845c20ca1c83b066c73835920ad70b806df0aee0351e3fc9ab1e42e8b2a30fe235ff0612eee19744949cecee0463b76514ad90c1f7ceaa557c18586ab561d49482e73c85d0143785da14a441bf82f78783b61cccd44aecb1947516e79b5ca5a6b3a8aed6040fae0eeabdc55a88dc19ade832d99fca90c7a629cacc07192d7e47e3c6a271b95b0ea3392562a06a1cab79f40ea92916ebee197b7b5f14b251824e1ed20ff2ca80b1f03a43e45157589bc61b978e97851025b3b7ccc17d291e1cb60fe48a5c26829dce11dd23c2e73265a9ebf8617c985e4fee4681e863f990061f4dea465a7d2524bd0edcf4b48d4b8f25fc359b15babd2637284a4774077dca60091f1a781cfee1bef9713dd5943a579d7470bc5970542fbb27fdf77880a8d8751b1f642c7a3f019a05ab94bf63d3525ef34e9290b5c8d477f2714e6d6e3e4d35c1983f5e16fda57fcdf071b513f8f088dbe8d5a97577d17a5383a496c3f313adfdd47c962bbaebd6aa13b46439eb742622c29ca067db0ec1853064c3cbbffe0a215a19fce47d49703ed58ebbd89721172d256d1cf30188106fb2f863186511401fad54d087aa2fb3d1b85768db386bd7102e8060ac157bac011acdcdae2799b9aee1467c3424013455bd028fcaacdc3c77d28ea199967d617ea7d0d0815f3cc407934a76d1293dccba210d1709a13e5dd67c9ba47cd113f5bdd740358eff13164159fd09bc2f7ec6cfa64d9df7e2e2f88706b0ff3a92ccf6f078456cfe0bdd89292cfe2680badc1eac9f7d36efe8eb6912c7b164508d13e6c0911c15f73c233cbe4fc70ff2ade1e1be4bbb738e0939159e2078a9438f05b756a003371f4861481c38f1cdd2d7b06deb62869e9fe79a8abaa920646fa2e8fa28f0d80c136376c7b56046bae4c05c0cdf64efb8c47bbfc5a1a4c0b045061ef0d71618e0d206a1d7f245fd5c03191b152673ba8dff8e1b8de7c50234a93cba91e3888adb228cc02beded4b1c0946797d3ef02dec2edb6ad0ac21f89f4be364c317da7c22440e9f358d512203f4b7ab20388af68b8915d0152db2c8a0687bfaea870f7529bb92a22b35bd79bc6d490591406346ecd78342ee3563c4883a8251679691c2d4e963397e24653520795511b018915374c954bddb940a9d7a16d1c8bd798fc7dbfb0599a7074e13f87e14efa8d511bb2579ec029b1bda18fe971b30fbe19e986ff2686a69bf3f1bb929de93ae70345ebca998b11e0a2b41890cba628d8f6e7c4e94790735e5299b4ff07cd3080f7d53c9cbe1911d2cd5925b3213e033c272506a87886cf761a283a779564d3241e3c28f632e166b5d756e1786ce077614c4444e3f2aed5decb3613b925ea3e558c21d4faf8ba54edd0f3a5d4>",
"<b 0xc10000000114367096bb0fb3f58f3a3fb8aaacd61d63a1c8a40e14f7374b8a62dccba6431716c3abf6f5afbcfb39bd008000047c32e268567c652e6f4db58bff759bc8c5aaca183b87cb4d22938fe7d8dca22a679a79e4d9ee62e4bbb3a380dd78d4e8e48f26b38a1d42d76b371a5a9a0444827a69d1ab5872a85749f65a4104e931740b4dc1e2dd77733fc7fac4f93011cd622f2bb47e85f71992e2d585f8dc765a7a12ddeb879746a267393ad023d267c4bd79f258703e27345155268bd3cc0506ebd72e2e3c6b5b0f005299cd94b67ddabe30389c4f9b5c2d512dcc298c14f14e9b7f931e1dc397926c31fbb7cebfc668349c218672501031ecce151d4cb03c4c660b6c6fe7754e75446cd7de09a8c81030c5f6fb377203f551864f3d83e27de7b86499736cbbb549b2f37f436db1cae0a4ea39930f0534aacdd1e3534bc87877e2afabe959ced261f228d6362e6fd277c88c312d966c8b9f67e4a92e757773db0b0862fb8108d1d8fa262a40a1b4171961f0704c8ba314da2482ac8ed9bd28d4b50f7432d89fd800c25a50c5e2f5c0710544fef5273401116aa0572366d8e49ad758fcb29e6a92912e644dbe227c247cb3417eabfab2db16796b2fba420de3b1dc94e8361f1f324a331ddaf1e626553138860757fd0bf687566108b77b70fb9f8f8962eca599c4a70ed373666961a8cb506b96756d9e28b94122b20f16b54f118c0e603ce0b831efea614ad836df6cf9affbdd09596412547496967da758cec9080295d853b0861670b71d9abde0d562b1a6de82782a5b0c14d297f27283a895abc889a5f6703f0e6eb95f67b2da45f150d0d8ab805612d570c2d5cb6997ac3a7756226c2f5c8982ffbd480c5004b0660a3c9468945efde90864019a2b519458724b55d766e16b0da25c0557c01f3c11ddeb024b62e303640e17fdd57dedb3aeb4a2c1b7c93059f9c1d7118d77caac1cd0f6556e46cbc991c1bb16970273dea833d01e5090d061a0c6d25af2415cd2878af97f6d0e7f1f936247b394ecb9bd484da6be936dee9b0b92dc90101a1b4295e97a9772f2263eb09431995aa173df4ca2abd687d87706f0f93eaa5e13cbe3b574fa3cfe94502ace25265778da6960d561381769c24e0cbd7aac73c16f95ae74ff7ec38124f7c722b9cb151d4b6841343f29be8f35145e1b27021056820fed77003df8554b4155716c8cf6049ef5e318481460a8ce3be7c7bfac695255be84dc491c19e9dedc449dd3471728cd2a3ee51324ccb3eef121e3e08f8e18f0006ea8957371d9f2f739f0b89e4db11e5c6430ada61572e589519fbad4498b460ce6e4407fc2d8f2dd4293a50a0cb8fcaaf35cd9a8cc097e3603fbfa08d9036f52b3e7fcce11b83ad28a4ac12dba0395a0cc871cefd1a2856fffb3f28d82ce35cf80579974778bab13d9b3578d8c75a2d196087a2cd439aff2bb33f2db24ac175fff4ed91d36a4cdbfaf3f83074f03894ea40f17034629890da3efdbb41141b38368ab532209b69f057ddc559c19bc8ae62bf3fd564c9a35d9a83d14a95834a92bae6d9a29ae5e8ece07910d16433e4c6230c9bd7d68b47de0de9843988af6cdc88b5301820443bd4d0537778bf6b4c1dd067fcf14b81015f2a67c7f2a28f9cb7e0684d3cb4b1c24d9b343122a086611b489532f1c3a26779da1706c6759d96d8ab>"
];
function generate_random_hex(len) {
return exec_output("head -c " + int(len) + " /dev/urandom | hexdump -ve '1/1 \"%02x\"' 2>/dev/null") || "";
}
function generate_extra_cps() {
let rand_val = (time() + int(exec_output("echo $PPID 2>/dev/null") || "1")) % 3 + 1;
let result = "";
for (let i = 0; i < rand_val; i++) {
let length = (time() + i * 7) % 48 + 16;
result += "<b 0x" + generate_random_hex(length) + ">";
}
return result;
}
let i1 = to_hex(warp_cps_payloads[time() % length(warp_cps_payloads)]);
let i2 = to_hex(generate_extra_cps());
let i3 = to_hex(generate_extra_cps());
let i4 = to_hex(generate_extra_cps());
let i5 = to_hex(generate_extra_cps());
// 7. Output result
write_json({
success: true,
local_address: response_data.config.interface.addresses.v4 + "/32 " + response_data.config.interface.addresses.v6 + "/128",
private_key: private_key,
peer_public_key: response_data.config.peers[0].public_key,
server_address: best_ip,
server_port: random_port,
awg_jc: 4,
awg_jmin: 40,
awg_jmax: 70,
awg_s1: 0, awg_s2: 0, awg_s3: 0, awg_s4: 0,
awg_h1: 1, awg_h2: 2, awg_h3: 3, awg_h4: 4,
awg_i1: i1,
awg_i2: i2,
awg_i3: i3,
awg_i4: i4,
awg_i5: i5
});
+20 -8
View File
@@ -48,6 +48,18 @@ let url_query_params = runtime_url.query_params;
const CONFIG_NAME = "tachyon"; const CONFIG_NAME = "tachyon";
// Convert a UCI value that may be a binary buffer (<b 0x...>) to a plain hex string.
// UCI stores values written as '<b 0x...>' strings as binary, which when
// serialized back to JSON appear as '<b 0x...>' — invalid for sing-box.
function uci_bin_to_hex(val) {
if (val == null || val == "") return "";
// Coerce to string — binary buffer becomes "<b 0x...>"
let s = replace("" + val, "<b 0x", "");
s = replace(s, ">", "");
s = replace(s, " ", "");
return s;
}
function parent_dir(path) { function parent_dir(path) {
path = as_string(path); path = as_string(path);
let slash = rindex(path, "/"); let slash = rindex(path, "/");
@@ -2283,16 +2295,16 @@ function add_awg_endpoint(config, section) {
s3: int_option(section, "awg_s3", "0"), s3: int_option(section, "awg_s3", "0"),
s4: int_option(section, "awg_s4", "0") s4: int_option(section, "awg_s4", "0")
}; };
let i1 = option(section, "awg_i1", ""); let i1 = uci_bin_to_hex(option(section, "awg_i1", ""));
let i2 = option(section, "awg_i2", ""); let i2 = uci_bin_to_hex(option(section, "awg_i2", ""));
let i3 = option(section, "awg_i3", ""); let i3 = uci_bin_to_hex(option(section, "awg_i3", ""));
let i4 = option(section, "awg_i4", ""); let i4 = uci_bin_to_hex(option(section, "awg_i4", ""));
let i5 = option(section, "awg_i5", ""); let i5 = uci_bin_to_hex(option(section, "awg_i5", ""));
if (i1 != "") amnezia.i1 = i1; if (i1 != "") amnezia.i1 = i1;
if (i2 != "") amnezia.i2 = i2; if (i2 != "") amnezia.i2 = i2;
if (i3 != "") amnezia.i3 = i3; if (i3 != "" && i3 != "0") amnezia.i3 = i3;
if (i4 != "") amnezia.i4 = i4; if (i4 != "" && i4 != "0") amnezia.i4 = i4;
if (i5 != "") amnezia.i5 = i5; if (i5 != "" && i5 != "0") amnezia.i5 = i5;
endpoint.amnezia = amnezia; endpoint.amnezia = amnezia;