refactor: cleanup

This commit is contained in:
zhom committed 2026-09-09 10:09:14 +04:00
1 parent 598d3bd513
commit dd42d46753
249 files changed
+67417 -6659

No files matched your search

+192
View File
@@ -3,10 +3,13 @@ import test from "node:test";
import {
CREDENTIALS_FIRST_FORMAT,
HOST_FIRST_FORMAT,
isFirstHopEncrypted,
pickParsedProxy,
proxyProtocolToken,
resolveAmbiguousProxyLine,
splitProxyScheme,
} from "./proxy-string.ts";
import { canonicalProxyType } from "./proxy-type.ts";
/**
* The formats themselves are exercised in Rust
@@ -38,6 +41,68 @@ test("an unknown scheme is left in the body rather than guessed at", () => {
});
});
test("a scheme that names a prototype member is still an unknown scheme", () => {
// The scheme comes from text the user pasted. An object-literal table
// answered for the whole prototype chain, so `__proto__` matched with
// Object.prototype and `constructor` with a function, both truthy, so the
// body was stripped and a non-string proxy_type reached the import preview,
// where React refuses an object as a child.
for (const hostile of [
"__proto__",
"constructor",
"toString",
"valueOf",
"hasOwnProperty",
]) {
const line = `${hostile}://1.2.3.4:8080`;
assert.deepEqual(splitProxyScheme(line), { proxyType: "http", rest: line });
}
// ...so the line still carries its five colon-parts and cannot be read as a
// four-part ambiguous one. Before, the scheme was stripped and this minted a
// proxy whose proxy_type was Object.prototype.
assert.equal(
resolveAmbiguousProxyLine(
"__proto__://1.2.3.4:8080:u:p",
HOST_FIRST_FORMAT,
),
null,
);
});
test("the protocol label shortens what needs it and prints the rest verbatim", () => {
assert.equal(proxyProtocolToken("httpstls"), "HTTP/TLS");
assert.equal(proxyProtocolToken("HTTPSTLS"), "HTTP/TLS");
assert.equal(proxyProtocolToken("socks5"), "socks5");
// An unrecognised type is the point: `proxy_type` is free text that
// POST /v1/proxies and import_proxies_json store verbatim, and the column
// must show what was actually stored rather than nothing.
assert.equal(proxyProtocolToken("weird-vendor-type"), "weird-vendor-type");
// Blank is the one empty answer, and it is the caller's cue to render a
// translated placeholder instead of an empty cell.
assert.equal(proxyProtocolToken(" "), "");
});
test("the protocol label answers for protocols only, never for a prototype", () => {
// `PROTOCOL_TOKENS[proxyType]` walked the prototype chain: "__proto__" gave
// an object, which React refuses as a child, and the throw unmounted the
// WHOLE proxy table, every proxy and every first-hop warning gone.
// "constructor", "toString" and "valueOf" gave functions, which React drops,
// leaving the protocol cell blank.
for (const hostile of [
"__proto__",
"constructor",
"toString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
]) {
const label = proxyProtocolToken(hostile);
assert.equal(typeof label, "string", `${hostile} must render as text`);
assert.equal(label, hostile);
}
});
test("host-first resolution keeps the scheme", () => {
assert.deepEqual(
resolveAmbiguousProxyLine(
@@ -127,3 +192,130 @@ test("nothing usable yields null so the plain paste stands", () => {
);
assert.equal(pickParsedProxy([]), null);
});
test("the TLS-wrapped scheme survives a paste", () => {
assert.deepEqual(splitProxyScheme("httpstls://proxy.example.com:443"), {
proxyType: "httpstls",
rest: "proxy.example.com:443",
});
assert.equal(
splitProxyScheme("HTTPSTLS://proxy.example.com:443").proxyType,
"httpstls",
);
});
test("only the types that actually encrypt the first hop say they do", () => {
// `ss` is deliberately NOT in this list: its answer depends on the cipher,
// and a type-only query carries no cipher, so it cannot claim encryption.
for (const encrypted of ["httpstls", "vless", "HTTPSTLS", "VLESS"]) {
assert.equal(isFirstHopEncrypted(encrypted), true, encrypted);
}
assert.equal(isFirstHopEncrypted("ss", "aes-256-gcm"), true);
assert.equal(isFirstHopEncrypted("SS", "chacha20-ietf-poly1305"), true);
// The REST API stores the type verbatim, so both spellings arrive, and both
// must answer identically or the UI contradicts the wire.
assert.equal(isFirstHopEncrypted("shadowsocks", "aes-256-gcm"), true);
assert.equal(isFirstHopEncrypted("shadowsocks", "none"), false);
assert.equal(isFirstHopEncrypted("shadowsocks"), false);
// `https` is the one that matters. It is a provider label on a plaintext
// CONNECT endpoint, dialed byte-for-byte like `http`, so the UI must not
// present it as encrypted.
for (const plaintext of ["http", "https", "HTTPS", "socks4", "socks5", ""]) {
assert.equal(isFirstHopEncrypted(plaintext), false, plaintext);
}
// Shadowsocks takes its cipher as free text and shadowsocks-crypto maps
// "none"/"plain" to a no-op cipher. Such a proxy was labelled "First hop
// encrypted", coloured safe, and had its credentials-in-clear warning
// suppressed, while carrying everything in the clear.
for (const nullCipher of ["none", "plain", "NONE", " None "]) {
assert.equal(
isFirstHopEncrypted("ss", nullCipher),
false,
`ss with cipher ${nullCipher} is not encrypted`,
);
}
for (const real of ["aes-256-gcm", "chacha20-ietf-poly1305"]) {
assert.equal(isFirstHopEncrypted("ss", real), true, real);
}
// An unspecified cipher is not a claim of safety either.
assert.equal(isFirstHopEncrypted("ss", null), false);
// Types whose encryption does not depend on a cipher are unaffected.
assert.equal(isFirstHopEncrypted("vless", null), true);
});
test("a padded stored type answers the same as an unpadded one", () => {
// `proxy_type` is stored verbatim, so `"ss "` is a value a proxy really
// arrives with from POST /v1/proxies or import_proxies_json. This helper
// lowercased but did not trim, while canonicalProxyType trimmed, so one such
// proxy was Shadowsocks to the form, which labelled its field "Cipher" -
// and an UNENCRYPTED first hop to the warning printed beside that field,
// about a proxy configured with aes-256-gcm. A warning that fires on a
// correct configuration is how a user learns to ignore this warning.
assert.equal(isFirstHopEncrypted("ss ", "aes-256-gcm"), true);
assert.equal(isFirstHopEncrypted(" shadowsocks", "aes-256-gcm"), true);
assert.equal(isFirstHopEncrypted("\thttpstls\n"), true);
assert.equal(isFirstHopEncrypted(" VLESS "), true);
// Padding does not buy encryption either: the cipher still decides, and the
// types that never encrypt still never do.
assert.equal(isFirstHopEncrypted(" ss ", ""), false);
assert.equal(isFirstHopEncrypted(" ss ", " none "), false);
assert.equal(isFirstHopEncrypted(" https "), false);
assert.equal(proxyProtocolToken(" httpstls "), "HTTP/TLS");
});
test("the first-hop answer never disagrees with the canonical type", () => {
// The lockstep the two helpers cannot get from a shared import: both files
// are loaded straight by `node --test`, which resolves neither `@/` nor an
// extensionless relative specifier, so neither may import the other. This
// test can import both, and it is what keeps their normalisation identical.
// Any two spellings of one type must get one answer, and it must be the
// answer the canonical spelling gets.
const spellings = [
"ss",
"SS",
" ss ",
"shadowsocks",
" Shadowsocks ",
"httpstls",
" HTTPSTLS ",
"vless",
" VLess ",
"http",
" HTTPS ",
"socks5",
" socks4 ",
"__proto__",
"",
" ",
];
const answers = new Map();
for (const spelling of spellings) {
const canonical = canonicalProxyType(spelling);
const answer = isFirstHopEncrypted(spelling, "aes-256-gcm");
assert.equal(
isFirstHopEncrypted(canonical, "aes-256-gcm"),
answer,
`${JSON.stringify(spelling)} and its canonical form ${JSON.stringify(
canonical,
)} describe different wires`,
);
if (answers.has(canonical)) {
assert.equal(
answer,
answers.get(canonical),
`${JSON.stringify(spelling)} answers differently from another ` +
`spelling of ${JSON.stringify(canonical)}`,
);
} else {
answers.set(canonical, answer);
}
}
// The corpus has to have covered both answers, or the loop proves nothing.
assert.equal(answers.get("ss"), true);
assert.equal(answers.get("httpstls"), true);
assert.equal(answers.get("http"), false);
assert.equal(answers.get("https"), false);
assert.equal(answers.get("__proto__"), false);
});