Кнопка 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/
dist/
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
# This file is distributed under the same license as the TACHYON package.
# Dushnilin, 2026.
@@ -2665,3 +2665,28 @@ msgstr "Разрешить небезопасный TLS"
msgid "Skip TLS certificate verification"
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);
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(
"settings",
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
# This file is distributed under the same license as the TACHYON package.
# Dushnilin, 2026.
@@ -2665,3 +2665,28 @@ msgstr "Разрешить небезопасный TLS"
msgid "Skip TLS certificate verification"
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_nfqws2_strategy_json: [ "diagnostics/runtime.uc", "validate-nfqws2-strategy-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_postinst: [ "service/package.uc", "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";
// 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) {
path = as_string(path);
let slash = rindex(path, "/");
@@ -2283,16 +2295,16 @@ function add_awg_endpoint(config, section) {
s3: int_option(section, "awg_s3", "0"),
s4: int_option(section, "awg_s4", "0")
};
let i1 = option(section, "awg_i1", "");
let i2 = option(section, "awg_i2", "");
let i3 = option(section, "awg_i3", "");
let i4 = option(section, "awg_i4", "");
let i5 = option(section, "awg_i5", "");
let i1 = uci_bin_to_hex(option(section, "awg_i1", ""));
let i2 = uci_bin_to_hex(option(section, "awg_i2", ""));
let i3 = uci_bin_to_hex(option(section, "awg_i3", ""));
let i4 = uci_bin_to_hex(option(section, "awg_i4", ""));
let i5 = uci_bin_to_hex(option(section, "awg_i5", ""));
if (i1 != "") amnezia.i1 = i1;
if (i2 != "") amnezia.i2 = i2;
if (i3 != "") amnezia.i3 = i3;
if (i4 != "") amnezia.i4 = i4;
if (i5 != "") amnezia.i5 = i5;
if (i3 != "" && i3 != "0") amnezia.i3 = i3;
if (i4 != "" && i4 != "0") amnezia.i4 = i4;
if (i5 != "" && i5 != "0") amnezia.i5 = i5;
endpoint.amnezia = amnezia;