fix: resolve crash on geoip_country selection and harden hosts list download (1.3.20)
This commit is contained in:
@@ -8214,13 +8214,21 @@ function createSectionContent(section) {
|
|||||||
tdCheck.appendChild(cb);
|
tdCheck.appendChild(cb);
|
||||||
tr.appendChild(tdCheck);
|
tr.appendChild(tdCheck);
|
||||||
|
|
||||||
const tdUrl = E("td", { class: "cbi-section-table-cell" });
|
const tdUrl = E("td", {
|
||||||
|
class: "cbi-section-table-cell",
|
||||||
|
style: "word-break:break-all;overflow-wrap:anywhere;font-size:12px;line-height:1.3;max-width:320px;",
|
||||||
|
});
|
||||||
|
let displayUrl = url;
|
||||||
|
try {
|
||||||
|
displayUrl = decodeURIComponent(url);
|
||||||
|
} catch(e) {}
|
||||||
const urlSpan = E(
|
const urlSpan = E(
|
||||||
"span",
|
"span",
|
||||||
{
|
{
|
||||||
style: isOff ? "text-decoration:line-through;opacity:0.6;" : "",
|
style: isOff ? "text-decoration:line-through;opacity:0.6;" : "",
|
||||||
|
title: url,
|
||||||
},
|
},
|
||||||
url,
|
displayUrl,
|
||||||
);
|
);
|
||||||
tdUrl.appendChild(urlSpan);
|
tdUrl.appendChild(urlSpan);
|
||||||
tr.appendChild(tdUrl);
|
tr.appendChild(tdUrl);
|
||||||
@@ -8292,8 +8300,10 @@ function createSectionContent(section) {
|
|||||||
class: "btn cbi-button cbi-button-action",
|
class: "btn cbi-button cbi-button-action",
|
||||||
type: "button",
|
type: "button",
|
||||||
click: function () {
|
click: function () {
|
||||||
const val = (input.value || "").trim();
|
let val = (input.value || "").trim();
|
||||||
if (!val) return;
|
if (!val) return;
|
||||||
|
val = val.replace(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/(.+)$/, "https://raw.githubusercontent.com/$1/$2/$3");
|
||||||
|
val = val.replace(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/raw\/(.+)$/, "https://raw.githubusercontent.com/$1/$2/$3");
|
||||||
let u = getUrls();
|
let u = getUrls();
|
||||||
if (u.includes(val)) {
|
if (u.includes(val)) {
|
||||||
input.value = "";
|
input.value = "";
|
||||||
@@ -8316,6 +8326,54 @@ function createSectionContent(section) {
|
|||||||
addRow.appendChild(input);
|
addRow.appendChild(input);
|
||||||
addRow.appendChild(addBtn);
|
addRow.appendChild(addBtn);
|
||||||
container.appendChild(addRow);
|
container.appendChild(addRow);
|
||||||
|
|
||||||
|
if (urls.length > 0) {
|
||||||
|
const updateRow = E("div", {
|
||||||
|
style: "margin-top:8px;display:flex;justify-content:flex-end;",
|
||||||
|
});
|
||||||
|
const updateBtn = E(
|
||||||
|
"button",
|
||||||
|
{
|
||||||
|
class: "cbi-button cbi-button-action",
|
||||||
|
type: "button",
|
||||||
|
click: function () {
|
||||||
|
updateBtn.disabled = true;
|
||||||
|
updateBtn.textContent = _("Updating…");
|
||||||
|
fs.exec("/usr/bin/tachyon", ["hosts_list_update"])
|
||||||
|
.then(function (res) {
|
||||||
|
updateBtn.disabled = false;
|
||||||
|
updateBtn.textContent = _("Update Lists Now");
|
||||||
|
let ok = false;
|
||||||
|
let msg = "";
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(res.stdout || "{}");
|
||||||
|
if (data.success) {
|
||||||
|
ok = true;
|
||||||
|
msg = _("Successfully updated %d hosts entries").format(data.entries);
|
||||||
|
} else {
|
||||||
|
msg = _("Update failed: ") + (data.error || res.stderr || "");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
msg = res.stdout || res.stderr || _("Finished with code ") + res.code;
|
||||||
|
}
|
||||||
|
ui.addNotification(
|
||||||
|
null,
|
||||||
|
E("p", {}, msg),
|
||||||
|
ok ? "info" : "danger"
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
updateBtn.disabled = false;
|
||||||
|
updateBtn.textContent = _("Update Lists Now");
|
||||||
|
ui.addNotification(null, E("p", {}, err.message || err), "danger");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_("Update Lists Now"),
|
||||||
|
);
|
||||||
|
updateRow.appendChild(updateBtn);
|
||||||
|
container.appendChild(updateRow);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render();
|
render();
|
||||||
|
|||||||
@@ -67,12 +67,33 @@ function enabled_hosts_sections() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function command_exists(name) {
|
||||||
|
return system("command -v " + shell_quote(name) + " >/dev/null 2>&1") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hash12(str) {
|
||||||
|
str = as_string(str);
|
||||||
|
let h1 = 5381;
|
||||||
|
let h2 = 52711;
|
||||||
|
for (let i = 0; i < length(str); i++) {
|
||||||
|
let code = ord(str, i);
|
||||||
|
h1 = ((h1 * 33) + code) % 2147483647;
|
||||||
|
h2 = ((h2 * 31) + code) % 2147483647;
|
||||||
|
}
|
||||||
|
return sprintf("%08x%04x", h1, h2 % 65536);
|
||||||
|
}
|
||||||
|
|
||||||
function http_get_to_file(url, output_path) {
|
function http_get_to_file(url, output_path) {
|
||||||
run("mkdir -p " + shell_quote(HOSTS_TMP_DIR));
|
mkdir_p(HOSTS_TMP_DIR);
|
||||||
let cmd = "wget -q -O " + shell_quote(output_path) + " --timeout=" + CONNECT_TIMEOUT + " " + shell_quote(url) + " 2>&1";
|
let cmd;
|
||||||
|
if (command_exists("curl")) {
|
||||||
|
cmd = "curl -fsSL --connect-timeout 10 -m " + CONNECT_TIMEOUT + " -o " + shell_quote(output_path) + " " + shell_quote(url) + " 2>&1";
|
||||||
|
} else {
|
||||||
|
cmd = "wget -q -O " + shell_quote(output_path) + " --timeout=" + CONNECT_TIMEOUT + " " + shell_quote(url) + " 2>&1";
|
||||||
|
}
|
||||||
log("Running: " + cmd);
|
log("Running: " + cmd);
|
||||||
let result = run(cmd);
|
let result = run(cmd);
|
||||||
log("wget exit: " + as_string(result) + " file_exists: " + as_string(fs.stat(output_path) != null));
|
log("download exit: " + as_string(result) + " file_exists: " + as_string(fs.stat(output_path) != null));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +160,8 @@ function parse_hosts_file(path) {
|
|||||||
function write_hosts_cache(entries, source_urls) {
|
function write_hosts_cache(entries, source_urls) {
|
||||||
mkdir_p(HOSTS_CACHE_DIR);
|
mkdir_p(HOSTS_CACHE_DIR);
|
||||||
|
|
||||||
let tmp_path = HOSTS_CACHE_FILE + ".tmp." + as_string(getpid());
|
let pid = fs.readlink("/proc/self") || "0";
|
||||||
|
let tmp_path = HOSTS_CACHE_FILE + ".tmp." + pid;
|
||||||
let fh = fs.open(tmp_path, "w");
|
let fh = fs.open(tmp_path, "w");
|
||||||
if (fh == null) {
|
if (fh == null) {
|
||||||
log("Failed to open " + tmp_path + " for writing", "error");
|
log("Failed to open " + tmp_path + " for writing", "error");
|
||||||
@@ -217,7 +239,10 @@ function hosts_list_update(target_url) {
|
|||||||
|
|
||||||
for (let url in urls) {
|
for (let url in urls) {
|
||||||
let label = "hosts list from " + url;
|
let label = "hosts list from " + url;
|
||||||
let safe_name = replace(replace(url, /:/g, "_"), /[^a-zA-Z0-9_]/g, "_");
|
let clean = replace(replace(url, /:/g, "_"), /[^a-zA-Z0-9_]/g, "_");
|
||||||
|
if (length(clean) > 40)
|
||||||
|
clean = substr(clean, 0, 40);
|
||||||
|
let safe_name = clean + "_" + hash12(url);
|
||||||
let tmp_file = HOSTS_TMP_DIR + "/list-" + safe_name + ".txt";
|
let tmp_file = HOSTS_TMP_DIR + "/list-" + safe_name + ".txt";
|
||||||
|
|
||||||
if (download_with_retry(url, tmp_file, label) != null) {
|
if (download_with_retry(url, tmp_file, label) != null) {
|
||||||
|
|||||||
@@ -549,6 +549,14 @@ function dscp_value(section) {
|
|||||||
return list_option_value_from_array(dscp_list(section));
|
return list_option_value_from_array(dscp_list(section));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function contains(arr, val) {
|
||||||
|
if (type(arr) != "array") return false;
|
||||||
|
for (let item in arr) {
|
||||||
|
if (item == val) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function geoip_country_list(section) {
|
function geoip_country_list(section) {
|
||||||
let raw = whitespace_list_value(section, "geoip_country");
|
let raw = whitespace_list_value(section, "geoip_country");
|
||||||
let result = [];
|
let result = [];
|
||||||
|
|||||||
@@ -180,42 +180,99 @@ function query_params(value) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function github_to_jsdelivr(url) {
|
function normalize_github_raw(url) {
|
||||||
url = as_string(url);
|
url = as_string(url);
|
||||||
if (index(url, "github.com/") < 0)
|
let marker = "github.com/";
|
||||||
return "";
|
let marker_idx = index(url, marker);
|
||||||
|
if (marker_idx < 0)
|
||||||
|
return url;
|
||||||
|
|
||||||
let path = substr(url, index(url, "github.com/") + 11);
|
let path_part = substr(url, marker_idx + length(marker));
|
||||||
let slash1 = index(path, "/");
|
let slash1 = index(path_part, "/");
|
||||||
if (slash1 < 0) return "";
|
if (slash1 < 0) return url;
|
||||||
let owner = substr(path, 0, slash1);
|
let owner = substr(path_part, 0, slash1);
|
||||||
let rest = substr(path, slash1 + 1);
|
let rest = substr(path_part, slash1 + 1);
|
||||||
let slash2 = index(rest, "/");
|
let slash2 = index(rest, "/");
|
||||||
if (slash2 < 0) return "";
|
if (slash2 < 0) return url;
|
||||||
let repo = substr(rest, 0, slash2);
|
let repo = substr(rest, 0, slash2);
|
||||||
let tail = substr(rest, slash2 + 1);
|
let tail = substr(rest, slash2 + 1);
|
||||||
|
|
||||||
let slash3 = index(tail, "/");
|
let clean_tail = tail;
|
||||||
if (slash3 < 0) return "";
|
let q = index(clean_tail, "?");
|
||||||
let segment3 = substr(tail, 0, slash3);
|
if (q >= 0) clean_tail = substr(clean_tail, 0, q);
|
||||||
let file = substr(tail, slash3 + 1);
|
let h = index(clean_tail, "#");
|
||||||
if (file == "") return "";
|
if (h >= 0) clean_tail = substr(clean_tail, 0, h);
|
||||||
|
|
||||||
let ref = "";
|
if (index(clean_tail, "blob/") == 0) {
|
||||||
if (segment3 == "releases" && index(tail, "releases/download/") == 0) {
|
let subpath = substr(clean_tail, 5);
|
||||||
let dl_path = substr(tail, 17);
|
return "https://raw.githubusercontent.com/" + owner + "/" + repo + "/" + subpath;
|
||||||
let dl_slash = index(dl_path, "/");
|
}
|
||||||
if (dl_slash < 0) return "";
|
if (index(clean_tail, "raw/") == 0) {
|
||||||
ref = substr(dl_path, 0, dl_slash);
|
let subpath = substr(clean_tail, 4);
|
||||||
file = substr(dl_path, dl_slash + 1);
|
return "https://raw.githubusercontent.com/" + owner + "/" + repo + "/" + subpath;
|
||||||
} else if (segment3 == "raw") {
|
}
|
||||||
ref = substr(tail, slash3 + 1);
|
|
||||||
let raw_slash = index(ref, "/");
|
return url;
|
||||||
if (raw_slash < 0) return "";
|
}
|
||||||
file = substr(ref, raw_slash + 1);
|
|
||||||
ref = substr(ref, 0, raw_slash);
|
function github_to_jsdelivr(url) {
|
||||||
|
url = as_string(url);
|
||||||
|
let marker_gh = "github.com/";
|
||||||
|
let marker_raw = "raw.githubusercontent.com/";
|
||||||
|
let idx_gh = index(url, marker_gh);
|
||||||
|
let idx_raw = index(url, marker_raw);
|
||||||
|
|
||||||
|
if (idx_gh < 0 && idx_raw < 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
let owner = "", repo = "", ref = "", file = "";
|
||||||
|
|
||||||
|
if (idx_raw >= 0) {
|
||||||
|
let path_part = substr(url, idx_raw + length(marker_raw));
|
||||||
|
let slash1 = index(path_part, "/");
|
||||||
|
if (slash1 < 0) return "";
|
||||||
|
owner = substr(path_part, 0, slash1);
|
||||||
|
let rest = substr(path_part, slash1 + 1);
|
||||||
|
let slash2 = index(rest, "/");
|
||||||
|
if (slash2 < 0) return "";
|
||||||
|
repo = substr(rest, 0, slash2);
|
||||||
|
let tail = substr(rest, slash2 + 1);
|
||||||
|
let slash3 = index(tail, "/");
|
||||||
|
if (slash3 < 0) return "";
|
||||||
|
ref = substr(tail, 0, slash3);
|
||||||
|
file = substr(tail, slash3 + 1);
|
||||||
} else {
|
} else {
|
||||||
ref = segment3;
|
let path_part = substr(url, idx_gh + length(marker_gh));
|
||||||
|
let slash1 = index(path_part, "/");
|
||||||
|
if (slash1 < 0) return "";
|
||||||
|
owner = substr(path_part, 0, slash1);
|
||||||
|
let rest = substr(path_part, slash1 + 1);
|
||||||
|
let slash2 = index(rest, "/");
|
||||||
|
if (slash2 < 0) return "";
|
||||||
|
repo = substr(rest, 0, slash2);
|
||||||
|
let tail = substr(rest, slash2 + 1);
|
||||||
|
|
||||||
|
let slash3 = index(tail, "/");
|
||||||
|
if (slash3 < 0) return "";
|
||||||
|
let segment3 = substr(tail, 0, slash3);
|
||||||
|
let remainder = substr(tail, slash3 + 1);
|
||||||
|
if (remainder == "") return "";
|
||||||
|
|
||||||
|
if (segment3 == "releases" && index(tail, "releases/download/") == 0) {
|
||||||
|
let dl_path = substr(tail, 17);
|
||||||
|
let dl_slash = index(dl_path, "/");
|
||||||
|
if (dl_slash < 0) return "";
|
||||||
|
ref = substr(dl_path, 0, dl_slash);
|
||||||
|
file = substr(dl_path, dl_slash + 1);
|
||||||
|
} else if (segment3 == "raw" || segment3 == "blob") {
|
||||||
|
let raw_slash = index(remainder, "/");
|
||||||
|
if (raw_slash < 0) return "";
|
||||||
|
ref = substr(remainder, 0, raw_slash);
|
||||||
|
file = substr(remainder, raw_slash + 1);
|
||||||
|
} else {
|
||||||
|
ref = segment3;
|
||||||
|
file = remainder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref == "" || file == "")
|
if (ref == "" || file == "")
|
||||||
@@ -228,6 +285,8 @@ function download_candidates(value) {
|
|||||||
if (value == "")
|
if (value == "")
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
|
value = normalize_github_raw(value);
|
||||||
|
|
||||||
let candidates = [ value ];
|
let candidates = [ value ];
|
||||||
let is_github = index(value, "github.com") >= 0 ||
|
let is_github = index(value, "github.com") >= 0 ||
|
||||||
index(value, "raw.githubusercontent.com") >= 0 ||
|
index(value, "raw.githubusercontent.com") >= 0 ||
|
||||||
@@ -264,5 +323,7 @@ return {
|
|||||||
userinfo,
|
userinfo,
|
||||||
path,
|
path,
|
||||||
query_params,
|
query_params,
|
||||||
|
normalize_github_raw,
|
||||||
|
github_to_jsdelivr,
|
||||||
download_candidates
|
download_candidates
|
||||||
};
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
|
TACHYON_LIB="${TACHYON_LIB:-$ROOT_DIR/tachyon/files/usr/lib}"
|
||||||
WORK_DIR="$(mktemp -d)"
|
WORK_DIR="$(mktemp -d)"
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
@@ -66,6 +66,14 @@ function assert(val, msg) {
|
|||||||
let index = connections.item_index_from_cursor(cursor, "tachyon");
|
let index = connections.item_index_from_cursor(cursor, "tachyon");
|
||||||
assert(index.subscription_url.by_name.sub1.url == "https://example.com/sub.txt", "parse subscription URL");
|
assert(index.subscription_url.by_name.sub1.url == "https://example.com/sub.txt", "parse subscription URL");
|
||||||
assert(index.urltest.by_name.group1.ports[0] == "80", "parse urltest group ports");
|
assert(index.urltest.by_name.group1.ports[0] == "80", "parse urltest group ports");
|
||||||
|
|
||||||
|
// geoip_country_list and geoip_country_mode tests
|
||||||
|
let geo_res = connections.geoip_country_list({ geoip_country: [ "ru", "de", "ru" ] });
|
||||||
|
assert(geo_res[0] == "ru" && geo_res[1] == "de" && length(geo_res) == 2, "geoip list de-duplicate");
|
||||||
|
assert(connections.geoip_country_list({ geoip_country: "non-ru" })[0] == "ru", "geoip non-ru alias");
|
||||||
|
assert(connections.geoip_country_mode({ geoip_country: "non-ru" }) == "exclude", "geoip mode for non-ru");
|
||||||
|
assert(connections.geoip_country_mode({ geoip_mode: "exclude" }) == "exclude", "geoip mode exclude");
|
||||||
|
assert(connections.geoip_country_mode({ geoip_mode: "include" }) == "include", "geoip mode include");
|
||||||
'
|
'
|
||||||
|
|
||||||
printf 'config/connections checks passed\n'
|
printf 'config/connections checks passed\n'
|
||||||
|
|||||||
+15
-1
@@ -2,7 +2,7 @@
|
|||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
|
TACHYON_LIB="${TACHYON_LIB:-$ROOT_DIR/tachyon/files/usr/lib}"
|
||||||
|
|
||||||
ucode -L "$TACHYON_LIB" -e '
|
ucode -L "$TACHYON_LIB" -e '
|
||||||
let url = require("core.url");
|
let url = require("core.url");
|
||||||
@@ -31,6 +31,20 @@ assert(url.strip_fragment("http://example.com") == "http://example.com", "strip
|
|||||||
// strip_anchored_scheme
|
// strip_anchored_scheme
|
||||||
assert(url.strip_anchored_scheme("http://example.com") == "example.com", "strip anchored http");
|
assert(url.strip_anchored_scheme("http://example.com") == "example.com", "strip anchored http");
|
||||||
assert(url.strip_anchored_scheme("example.com") == "example.com", "strip no scheme");
|
assert(url.strip_anchored_scheme("example.com") == "example.com", "strip no scheme");
|
||||||
|
|
||||||
|
// normalize_github_raw
|
||||||
|
assert(url.normalize_github_raw("https://github.com/owner/repo/blob/main/path/to/hosts") == "https://raw.githubusercontent.com/owner/repo/main/path/to/hosts", "normalize blob url");
|
||||||
|
assert(url.normalize_github_raw("https://github.com/owner/repo/raw/main/path/to/hosts") == "https://raw.githubusercontent.com/owner/repo/main/path/to/hosts", "normalize raw url");
|
||||||
|
assert(url.normalize_github_raw("https://raw.githubusercontent.com/owner/repo/main/path/to/hosts") == "https://raw.githubusercontent.com/owner/repo/main/path/to/hosts", "keep raw url");
|
||||||
|
assert(url.normalize_github_raw("https://example.com/hosts.txt") == "https://example.com/hosts.txt", "keep non-github url");
|
||||||
|
|
||||||
|
// github_to_jsdelivr
|
||||||
|
assert(url.github_to_jsdelivr("https://github.com/owner/repo/blob/main/path/to/hosts") == "https://cdn.jsdelivr.net/gh/owner/repo@main/path/to/hosts", "jsdelivr from blob");
|
||||||
|
assert(url.github_to_jsdelivr("https://raw.githubusercontent.com/owner/repo/main/path/to/hosts") == "https://cdn.jsdelivr.net/gh/owner/repo@main/path/to/hosts", "jsdelivr from raw");
|
||||||
|
|
||||||
|
// download_candidates
|
||||||
|
let candidates = url.download_candidates("https://github.com/owner/repo/blob/main/hosts");
|
||||||
|
assert(candidates[0] == "https://raw.githubusercontent.com/owner/repo/main/hosts", "download_candidates first entry normalized");
|
||||||
'
|
'
|
||||||
|
|
||||||
printf 'core/url checks passed\n'
|
printf 'core/url checks passed\n'
|
||||||
|
|||||||
+33
-3
@@ -2,14 +2,16 @@
|
|||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
HOSTS_UC="$ROOT_DIR/tachyon/files/usr/lib/components/hosts.uc"
|
HOSTS_UC="${HOSTS_UC:-$ROOT_DIR/tachyon/files/usr/lib/components/hosts.uc}"
|
||||||
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
|
TACHYON_LIB="${TACHYON_LIB:-$ROOT_DIR/tachyon/files/usr/lib}"
|
||||||
TMP_DIR="$(mktemp -d)"
|
TMP_DIR="$(mktemp -d)"
|
||||||
PASS=0
|
PASS=0
|
||||||
FAIL=0
|
FAIL=0
|
||||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||||
|
|
||||||
mkdir -p "$TMP_DIR"
|
mkdir -p "$TMP_DIR/cache" "$TMP_DIR/tmp"
|
||||||
|
export TACHYON_HOSTS_CACHE_DIR="$TMP_DIR/cache"
|
||||||
|
export TACHYON_HOSTS_TMP_DIR="$TMP_DIR/tmp"
|
||||||
|
|
||||||
ucode() {
|
ucode() {
|
||||||
command ucode -L "$TACHYON_LIB" "$@"
|
command ucode -L "$TACHYON_LIB" "$@"
|
||||||
@@ -72,6 +74,34 @@ echo "=== Test: hosts_list_status with no URLs ==="
|
|||||||
output=$(ucode "$HOSTS_UC" list-status 2>/dev/null || true)
|
output=$(ucode "$HOSTS_UC" list-status 2>/dev/null || true)
|
||||||
assert_eq "false" "$(echo "$output" | grep -o '"cache_exists":[a-z]*' | cut -d: -f2)" "cache_exists should be false initially"
|
assert_eq "false" "$(echo "$output" | grep -o '"cache_exists":[a-z]*' | cut -d: -f2)" "cache_exists should be false initially"
|
||||||
|
|
||||||
|
# --- Test 5: Safe name length for long percent-encoded URLs ---
|
||||||
|
echo "=== Test: safe_name length for long URLs ==="
|
||||||
|
long_url_safe_len=$(ucode -e '
|
||||||
|
let common = require("core.common");
|
||||||
|
let as_string = common.as_string;
|
||||||
|
function hash12(str) {
|
||||||
|
str = as_string(str);
|
||||||
|
let h1 = 5381;
|
||||||
|
let h2 = 52711;
|
||||||
|
for (let i = 0; i < length(str); i++) {
|
||||||
|
let code = ord(str, i);
|
||||||
|
h1 = ((h1 * 33) + code) % 2147483647;
|
||||||
|
h2 = ((h2 * 31) + code) % 2147483647;
|
||||||
|
}
|
||||||
|
return sprintf("%08x%04x", h1, h2 % 65536);
|
||||||
|
}
|
||||||
|
let url = "https://raw.githubusercontent.com/V3nilla/IPSets-For-Bypass-in-Russia/main/%D0%A0%D0%B0%D0%B7%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0%20%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B0%20%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81%D0%BE%D0%B2(%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%20-%20ChatGPT)/hosts";
|
||||||
|
let clean = replace(replace(url, /:/g, "_"), /[^a-zA-Z0-9_]/g, "_");
|
||||||
|
if (length(clean) > 40) clean = substr(clean, 0, 40);
|
||||||
|
let safe_name = clean + "_" + hash12(url);
|
||||||
|
print(length(safe_name));
|
||||||
|
')
|
||||||
|
if [ "$long_url_safe_len" -le 60 ]; then
|
||||||
|
pass
|
||||||
|
else
|
||||||
|
fail "safe_name too long: $long_url_safe_len"
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== Results: $PASS passed, $FAIL failed ==="
|
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||||
[ "$FAIL" -eq 0 ] || exit 1
|
[ "$FAIL" -eq 0 ] || exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user