Fixed Trojan issue

This commit is contained in:
Peng-YM 2020-09-14 10:12:53 +08:00
parent 8504738ee1
commit a0d8e79d3c
2 changed files with 3012 additions and 2980 deletions

View File

@ -59,7 +59,6 @@ $app.route("/api/sub/:name").get(getSub).patch(updateSub).delete(deleteSub);
$app.route("/api/sub").get(getAllSubs).post(newSub).delete(deleteAllSubs); $app.route("/api/sub").get(getAllSubs).post(newSub).delete(deleteAllSubs);
// refresh // refresh
$app.post("/api/refresh", refreshResource); $app.post("/api/refresh", refreshResource);
@ -85,7 +84,9 @@ $app.start();
async function IP_API(req, res) { async function IP_API(req, res) {
const server = decodeURIComponent(req.params.server); const server = decodeURIComponent(req.params.server);
const result = await $.http.get(`http://ip-api.com/json/${server}?lang=zh-CN`).then(resp => JSON.parse(resp.body)); const result = await $.http
.get(`http://ip-api.com/json/${server}?lang=zh-CN`)
.then((resp) => JSON.parse(resp.body));
res.json(result); res.json(result);
} }
@ -112,7 +113,7 @@ async function downloadResource(url) {
// refresh resource // refresh resource
async function refreshResource(req, res) { async function refreshResource(req, res) {
const Base64 = new Base64Code(); const Base64 = new Base64Code();
const {url} = req.body; const { url } = req.body;
const raw = await downloadResource(url); const raw = await downloadResource(url);
$.write(raw, `#${Base64.safeEncode(url)}`); $.write(raw, `#${Base64.safeEncode(url)}`);
res.json({ res.json({
@ -122,7 +123,7 @@ async function refreshResource(req, res) {
// download subscription, for APP only // download subscription, for APP only
async function downloadSub(req, res) { async function downloadSub(req, res) {
const {name} = req.params; const { name } = req.params;
const platform = req.query.target || getPlatformFromHeaders(req.headers); const platform = req.query.target || getPlatformFromHeaders(req.headers);
const allSubs = $.read(SUBS_KEY); const allSubs = $.read(SUBS_KEY);
if (allSubs[name]) { if (allSubs[name]) {
@ -147,7 +148,7 @@ async function downloadSub(req, res) {
async function parseSub(sub, platform) { async function parseSub(sub, platform) {
let raw; let raw;
const key = new Base64Code().safeEncode(sub.url); const key = new Base64Code().safeEncode(sub.url);
if (platform === "Raw" || platform === 'URI') { if (platform === "Raw" || platform === "URI") {
const cache = $.read(`#${key}`); const cache = $.read(`#${key}`);
if (!cache) { if (!cache) {
raw = await downloadResource(sub.url); raw = await downloadResource(sub.url);
@ -210,7 +211,7 @@ async function parseSub(sub, platform) {
let script; let script;
// process script // process script
if (item.type.indexOf("Script") !== -1) { if (item.type.indexOf("Script") !== -1) {
const {mode, content} = item.args; const { mode, content } = item.args;
if (mode === "link") { if (mode === "link") {
// if this is remote script, download it // if this is remote script, download it
script = await $.http script = await $.http
@ -239,12 +240,9 @@ async function parseSub(sub, platform) {
$filter.setFilter(filter(item.args)); $filter.setFilter(filter(item.args));
} }
try { try {
proxies = $filter.process(proxies); proxies = $filter.process(proxies);
} catch (err) { } catch (err) {
$.error( $.error(`Failed to apply filter "${item.type}"!\n REASON: ${err}`);
`Failed to apply filter "${item.type}"!\n REASON: ${err}`
);
} }
} }
} else if (item.type.indexOf("Operator") !== -1) { } else if (item.type.indexOf("Operator") !== -1) {
@ -263,7 +261,7 @@ async function parseSub(sub, platform) {
try { try {
proxies = $operator.process(proxies); proxies = $operator.process(proxies);
} catch (err) { } catch (err) {
`Failed to apply operator "${item.type}"!\n REASON: ${err}` `Failed to apply operator "${item.type}"!\n REASON: ${err}`;
} }
} }
} }
@ -275,7 +273,7 @@ async function parseSub(sub, platform) {
Loon_Producer, Loon_Producer,
Surge_Producer, Surge_Producer,
Raw_Producer, Raw_Producer,
URI_Producer URI_Producer,
]); ]);
return $parser.produce(proxies); return $parser.produce(proxies);
} }
@ -321,7 +319,7 @@ function getFlowHeaders(headers, proxies) {
// Subscriptions // Subscriptions
async function getSub(req, res) { async function getSub(req, res) {
const {name} = req.params; const { name } = req.params;
const sub = $.read(SUBS_KEY)[name]; const sub = $.read(SUBS_KEY)[name];
if (sub) { if (sub) {
res.json({ res.json({
@ -362,7 +360,7 @@ async function newSub(req, res) {
} }
async function updateSub(req, res) { async function updateSub(req, res) {
const {name} = req.params; const { name } = req.params;
$.info(`Updating subscription: ${name}`); $.info(`Updating subscription: ${name}`);
let sub = req.body; let sub = req.body;
const allSubs = $.read(SUBS_KEY); const allSubs = $.read(SUBS_KEY);
@ -401,7 +399,7 @@ async function updateSub(req, res) {
} }
async function deleteSub(req, res) { async function deleteSub(req, res) {
const {name} = req.params; const { name } = req.params;
// delete from subscriptions // delete from subscriptions
let allSubs = $.read(SUBS_KEY); let allSubs = $.read(SUBS_KEY);
delete allSubs[name]; delete allSubs[name];
@ -436,7 +434,7 @@ async function deleteAllSubs(req, res) {
// Collections // Collections
async function downloadCollection(req, res) { async function downloadCollection(req, res) {
const {name} = req.params; const { name } = req.params;
const collection = $.read(COLLECTIONS_KEY)[name]; const collection = $.read(COLLECTIONS_KEY)[name];
const platform = getPlatformFromHeaders(req.headers); const platform = getPlatformFromHeaders(req.headers);
if (collection) { if (collection) {
@ -463,7 +461,7 @@ async function downloadCollection(req, res) {
} }
async function getCollection(req, res) { async function getCollection(req, res) {
const {name} = req.params; const { name } = req.params;
const collection = $.read(COLLECTIONS_KEY)[name]; const collection = $.read(COLLECTIONS_KEY)[name];
if (collection) { if (collection) {
res.json({ res.json({
@ -504,7 +502,7 @@ async function newCollection(req, res) {
} }
async function updateCollection(req, res) { async function updateCollection(req, res) {
const {name} = req.params; const { name } = req.params;
let collection = req.body; let collection = req.body;
const allCol = $.read(COLLECTIONS_KEY); const allCol = $.read(COLLECTIONS_KEY);
if (allCol[name]) { if (allCol[name]) {
@ -529,7 +527,7 @@ async function updateCollection(req, res) {
} }
async function deleteCollection(req, res) { async function deleteCollection(req, res) {
const {name} = req.params; const { name } = req.params;
let allCol = $.read(COLLECTIONS_KEY); let allCol = $.read(COLLECTIONS_KEY);
delete allCol[name]; delete allCol[name];
$.write(allCol, COLLECTIONS_KEY); $.write(allCol, COLLECTIONS_KEY);
@ -579,7 +577,7 @@ function ProxyParser(targetPlatform) {
if (line.startsWith("#")) continue; // skip comments if (line.startsWith("#")) continue; // skip comments
let matched = false; let matched = false;
for (const p of parsers) { for (const p of parsers) {
const {patternTest, func} = p; const { patternTest, func } = p;
// some lines with weird format may produce errors! // some lines with weird format may produce errors!
let patternMatched; let patternMatched;
@ -601,7 +599,8 @@ function ProxyParser(targetPlatform) {
} }
// skip unsupported proxies // skip unsupported proxies
// if proxy.supported is undefined, assume that all platforms are supported. // if proxy.supported is undefined, assume that all platforms are supported.
if (proxy.supported && proxy.supported[targetPlatform] === false) continue; if (proxy.supported && proxy.supported[targetPlatform] === false)
continue;
result.push(proxy); result.push(proxy);
break; break;
} catch (err) { } catch (err) {
@ -634,7 +633,7 @@ function ProxyParser(targetPlatform) {
return ""; return "";
} }
}) })
.filter(v => v.length > 0) // discard empty lines .filter((v) => v.length > 0) // discard empty lines
.join("\n"); .join("\n");
} }
} }
@ -658,15 +657,20 @@ function ProxyParser(targetPlatform) {
raw = raw raw = raw
.replace(/ - /g, " - ") .replace(/ - /g, " - ")
.replace(/:(?!\s)/g, ": ") .replace(/:(?!\s)/g, ": ")
.replace(/\,\"/g, ", \"") .replace(/\,\"/g, ', "')
.replace(/: {/g, ": {, ") .replace(/: {/g, ": {, ")
.replace(/, (host|path|tls|mux|skip)/g, ", $1") .replace(/, (host|path|tls|mux|skip)/g, ", $1")
.replace(/{name: /g, "{name: \"") .replace(/{name: /g, '{name: "')
.replace(/, server:/g, "\", server:") .replace(/, server:/g, '", server:')
.replace(/{|}/g, "") .replace(/{|}/g, "")
.replace(/,/g, "\n ") .replace(/,/g, "\n ");
} }
raw = raw.replace(/ -\n.*name/g, " - name").replace(/\$|\`/g, "").split("proxy-providers:")[0].split("proxy-groups:")[0].replace(/\"(name|type|server|port|cipher|password|)\"/g, "$1") raw = raw
.replace(/ -\n.*name/g, " - name")
.replace(/\$|\`/g, "")
.split("proxy-providers:")[0]
.split("proxy-groups:")[0]
.replace(/\"(name|type|server|port|cipher|password|)\"/g, "$1");
const proxies = YAML.eval(raw).proxies; const proxies = YAML.eval(raw).proxies;
output = proxies.map((p) => JSON.stringify(p)); output = proxies.map((p) => JSON.stringify(p));
} else if (raw.indexOf("ssd://") === 0) { } else if (raw.indexOf("ssd://") === 0) {
@ -693,8 +697,12 @@ function ProxyParser(targetPlatform) {
let hostname = server.server; let hostname = server.server;
port = server.port ? server.port : port; port = server.port ? server.port : port;
let tag = server.remarks ? server.remarks : i; let tag = server.remarks ? server.remarks : i;
let plugin = server.plugin_options ? "/?plugin=" + encodeURIComponent(server.plugin + ";" + server.plugin_options) : "" let plugin = server.plugin_options
output[i] = "ss://" + userinfo + "@" + hostname + ":" + port + plugin + "#" + tag ? "/?plugin=" +
encodeURIComponent(server.plugin + ";" + server.plugin_options)
: "";
output[i] =
"ss://" + userinfo + "@" + hostname + ":" + port + plugin + "#" + tag;
} }
} else { } else {
// check if content is based64 encoded // check if content is based64 encoded
@ -767,7 +775,7 @@ function ProxyOperator() {
return output; return output;
} }
return {setOperator, process}; return { setOperator, process };
} }
/**************************** URI Format ***************************************/ /**************************** URI Format ***************************************/
@ -836,7 +844,7 @@ function URI_SS() {
mode: "websocket", mode: "websocket",
host: params["obfs-host"], host: params["obfs-host"],
path: params.path || "", path: params.path || "",
tls: params.tls tls: params.tls,
}; };
break; break;
default: default:
@ -845,7 +853,7 @@ function URI_SS() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
// Parse URI SSR format, such as ssr://xxx // Parse URI SSR format, such as ssr://xxx
@ -907,7 +915,7 @@ function URI_SSR() {
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
// V2rayN URI VMess format // V2rayN URI VMess format
@ -991,7 +999,7 @@ function URI_VMess() {
return proxy; return proxy;
} }
}; };
return {patternTest, func}; return { patternTest, func };
} }
// Trojan URI format // Trojan URI format
@ -1023,7 +1031,7 @@ function URI_Trojan() {
supported, supported,
}; };
}; };
return {patternTest, func}; return { patternTest, func };
} }
/**************************** Clash ***************************************/ /**************************** Clash ***************************************/
@ -1032,7 +1040,7 @@ function Clash_All() {
return line.indexOf("{") !== -1; return line.indexOf("{") !== -1;
}; };
const func = (line) => JSON.parse(line); const func = (line) => JSON.parse(line);
return {patternTest, func}; return { patternTest, func };
} }
/**************************** Quantumult X ***************************************/ /**************************** Quantumult X ***************************************/
@ -1090,7 +1098,7 @@ function QX_SS() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function QX_SSR() { function QX_SSR() {
@ -1129,7 +1137,7 @@ function QX_SSR() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function QX_VMess() { function QX_VMess() {
@ -1165,7 +1173,7 @@ function QX_VMess() {
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function QX_Trojan() { function QX_Trojan() {
@ -1187,7 +1195,7 @@ function QX_Trojan() {
proxy.scert = !JSON.parse(params["tls-verification"] || "true"); proxy.scert = !JSON.parse(params["tls-verification"] || "true");
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function QX_Http() { function QX_Http() {
@ -1214,7 +1222,7 @@ function QX_Http() {
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function getQXParams(line) { function getQXParams(line) {
@ -1262,7 +1270,7 @@ function Loon_SS() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Loon_SSR() { function Loon_SSR() {
@ -1293,7 +1301,7 @@ function Loon_SSR() {
"obfs-param": params[8].match(/{(.*)}/)[1], "obfs-param": params[8].match(/{(.*)}/)[1],
}; };
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Loon_VMess() { function Loon_VMess() {
@ -1341,7 +1349,7 @@ function Loon_VMess() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Loon_Trojan() { function Loon_Trojan() {
@ -1372,7 +1380,7 @@ function Loon_Trojan() {
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Loon_Http() { function Loon_Http() {
@ -1403,7 +1411,7 @@ function Loon_Http() {
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
/**************************** Surge ***************************************/ /**************************** Surge ***************************************/
@ -1433,7 +1441,7 @@ function Surge_SS() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Surge_VMess() { function Surge_VMess() {
@ -1469,7 +1477,7 @@ function Surge_VMess() {
} }
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Surge_Trojan() { function Surge_Trojan() {
@ -1492,7 +1500,7 @@ function Surge_Trojan() {
}; };
}; };
return {patternTest, func}; return { patternTest, func };
} }
function Surge_Http() { function Surge_Http() {
@ -1519,7 +1527,7 @@ function Surge_Http() {
if (params.password !== "none") proxy.password = params.password; if (params.password !== "none") proxy.password = params.password;
return proxy; return proxy;
}; };
return {patternTest, func}; return { patternTest, func };
} }
function getSurgeParams(line) { function getSurgeParams(line) {
@ -1551,7 +1559,7 @@ function QX_Producer() {
obfs_opts = `,obfs=${proxy["plugin-opts"].mode},obfs-host=${proxy["plugin-opts"].host}`; obfs_opts = `,obfs=${proxy["plugin-opts"].mode},obfs-host=${proxy["plugin-opts"].host}`;
} }
if (proxy.plugin === "v2ray-plugin") { if (proxy.plugin === "v2ray-plugin") {
const {tls, host, path} = proxy["plugin-opts"]; const { tls, host, path } = proxy["plugin-opts"];
obfs_opts = `,obfs=${tls ? "wss" : "ws"},obfs-host=${host}${ obfs_opts = `,obfs=${tls ? "wss" : "ws"},obfs-host=${host}${
path ? ",obfs-uri=" + path : "" path ? ",obfs-uri=" + path : ""
}`; }`;
@ -1608,7 +1616,7 @@ function QX_Producer() {
case "trojan": case "trojan":
return `trojan=${proxy.server}:${proxy.port},password=${ return `trojan=${proxy.server}:${proxy.port},password=${
proxy.password proxy.password
},tls-host=${proxy.sni},tls-verification=${ }${proxy.sni ? ",tls-host=" + proxy.sni : ""},tls-verification=${
proxy.scert ? "false" : "true" proxy.scert ? "false" : "true"
}${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${ }${proxy.tfo ? ",fast-open=true" : ",fast-open=false"}${
proxy.udp ? ",udp-relay=true" : ",udp-relay=false" proxy.udp ? ",udp-relay=true" : ",udp-relay=false"
@ -1630,7 +1638,7 @@ function QX_Producer() {
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}` `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
); );
}; };
return {targetPlatform, output}; return { targetPlatform, output };
} }
function Loon_Producer() { function Loon_Producer() {
@ -1642,7 +1650,7 @@ function Loon_Producer() {
obfs_opts = ",,"; obfs_opts = ",,";
if (proxy.plugin) { if (proxy.plugin) {
if (proxy.plugin === "obfs") { if (proxy.plugin === "obfs") {
const {mode, host} = proxy["plugin-opts"]; const { mode, host } = proxy["plugin-opts"];
obfs_opts = `,${mode},${host}`; obfs_opts = `,${mode},${host}`;
} else { } else {
throw new Error( throw new Error(
@ -1671,7 +1679,11 @@ function Loon_Producer() {
proxy.cipher === "auto" ? "none" : proxy.cipher proxy.cipher === "auto" ? "none" : proxy.cipher
},"${proxy.uuid}",over-tls:${proxy.tls}${obfs_opts}`; },"${proxy.uuid}",over-tls:${proxy.tls}${obfs_opts}`;
case "trojan": case "trojan":
return `${proxy.name}=trojan,${proxy.server},${proxy.port},"${proxy.password}",tls-name:${proxy.sni},skip-cert-verify:${proxy.scert}`; return `${proxy.name}=trojan,${proxy.server},${proxy.port},"${
proxy.password
}"${proxy.sni ? ",tls-name:" + proxy.sni : ""},skip-cert-verify:${
proxy.scert || "false"
}`;
case "http": case "http":
tls_opts = ""; tls_opts = "";
const base = `${proxy.name}=${proxy.tls ? "http" : "https"},${ const base = `${proxy.name}=${proxy.tls ? "http" : "https"},${
@ -1687,7 +1699,7 @@ function Loon_Producer() {
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}` `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
); );
}; };
return {targetPlatform, output}; return { targetPlatform, output };
} }
function Surge_Producer() { function Surge_Producer() {
@ -1730,7 +1742,7 @@ function Surge_Producer() {
case "trojan": case "trojan":
return `${proxy.name}=trojan,${proxy.server},${proxy.port},password=${ return `${proxy.name}=trojan,${proxy.server},${proxy.port},password=${
proxy.password proxy.password
},sni=${proxy.sni},tfo=${proxy.tfo || "false"}`; }${proxy.sni ? ",sni=" + proxy.sni : ""},tfo=${proxy.tfo || "false"}`;
case "http": case "http":
tls_opts = ",tls=false"; tls_opts = ",tls=false";
if (proxy.tls) { if (proxy.tls) {
@ -1746,7 +1758,7 @@ function Surge_Producer() {
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}` `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`
); );
}; };
return {targetPlatform, output}; return { targetPlatform, output };
} }
function Raw_Producer() { function Raw_Producer() {
@ -1754,7 +1766,7 @@ function Raw_Producer() {
const output = (proxy) => { const output = (proxy) => {
return JSON.stringify(proxy); return JSON.stringify(proxy);
}; };
return {targetPlatform, output}; return { targetPlatform, output };
} }
function URI_Producer() { function URI_Producer() {
@ -1765,29 +1777,49 @@ function URI_Producer() {
switch (proxy.type) { switch (proxy.type) {
case "ss": case "ss":
const userinfo = `${proxy.cipher}:${proxy.password}`; const userinfo = `${proxy.cipher}:${proxy.password}`;
result = `ss://${Base64.safeEncode(userinfo)}@${proxy.server}:${proxy.port}/`; result = `ss://${Base64.safeEncode(userinfo)}@${proxy.server}:${
proxy.port
}/`;
if (proxy.plugin) { if (proxy.plugin) {
result += "?plugin="; result += "?plugin=";
const opts = proxy['plugin-opts']; const opts = proxy["plugin-opts"];
switch (proxy.plugin) { switch (proxy.plugin) {
case "obfs": case "obfs":
result += encodeURIComponent(`simple-obfs;obfs=${opts.mode}${opts.host ? ";obfs-host=" + opts.host : ""}`); result += encodeURIComponent(
break `simple-obfs;obfs=${opts.mode}${
opts.host ? ";obfs-host=" + opts.host : ""
}`
);
break;
case "v2ray-plugin": case "v2ray-plugin":
result += encodeURIComponent(`v2ray-plugin;obfs=${opts.mode}${opts.host ? ";obfs-host" + opts.host : ""}${opts.tls ? ";tls" : ""}`); result += encodeURIComponent(
break `v2ray-plugin;obfs=${opts.mode}${
opts.host ? ";obfs-host" + opts.host : ""
}${opts.tls ? ";tls" : ""}`
);
break;
default: default:
console.log(`FUCK`); console.log(`FUCK`);
throw new Error(`Unsupported plugin option: ${proxy.plugin}`); throw new Error(`Unsupported plugin option: ${proxy.plugin}`);
} }
} }
result += `#${encodeURIComponent(proxy.name)}`; result += `#${encodeURIComponent(proxy.name)}`;
break break;
case "ssr": case "ssr":
result = `${proxy.server}:${proxy.port}:${proxy.protocol}:${proxy.cipher}:${proxy.obfs}:${Base64.safeEncode(proxy.password)}/`; result = `${proxy.server}:${proxy.port}:${proxy.protocol}:${
result += `?remarks=${proxy.name}${proxy['obfs-param'] ? "&obfsparam=" + Base64.safeEncode(proxy['obfs-param']) : ""}${proxy['protocol-param'] ? "&protocolparam=" + Base64.safeEncode(proxy['protocol-param']) : ""}`; proxy.cipher
}:${proxy.obfs}:${Base64.safeEncode(proxy.password)}/`;
result += `?remarks=${proxy.name}${
proxy["obfs-param"]
? "&obfsparam=" + Base64.safeEncode(proxy["obfs-param"])
: ""
}${
proxy["protocol-param"]
? "&protocolparam=" + Base64.safeEncode(proxy["protocol-param"])
: ""
}`;
result = "vmess://" + Base64.safeEncode(result); result = "vmess://" + Base64.safeEncode(result);
break break;
case "vmess": case "vmess":
// V2RayN URI format // V2RayN URI format
result = { result = {
@ -1798,29 +1830,29 @@ function URI_Producer() {
type: "", type: "",
aid: 0, aid: 0,
net: proxy.network || "tcp", net: proxy.network || "tcp",
tls: proxy.tls ? "tls" : "" tls: proxy.tls ? "tls" : "",
} };
// obfs // obfs
if (proxy.network === 'ws') { if (proxy.network === "ws") {
result.path = proxy['ws-path'] || "/"; result.path = proxy["ws-path"] || "/";
result.host = proxy['ws-headers'].Host || proxy.server; result.host = proxy["ws-headers"].Host || proxy.server;
} }
result = Base64.safeEncode(JSON.stringify(result)); result = Base64.safeEncode(JSON.stringify(result));
break break;
case "trojan": case "trojan":
result = `trojan://${proxy.password}@${proxy.server}:${proxy.port}#${proxy.name}`; result = `trojan://${proxy.password}@${proxy.server}:${proxy.port}#${proxy.name}`;
break break;
default: default:
throw new Error(`Cannot handle proxy type: ${proxy.type}`); throw new Error(`Cannot handle proxy type: ${proxy.type}`);
} }
return result; return result;
}; };
return {targetPlatform, output}; return { targetPlatform, output };
} }
/**************************** Operators ***************************************/ /**************************** Operators ***************************************/
// force to set some properties (e.g., scert, udp, tfo, etc.) // force to set some properties (e.g., scert, udp, tfo, etc.)
function SetPropertyOperator({key, value}) { function SetPropertyOperator({ key, value }) {
return { return {
name: "Set Property Operator", name: "Set Property Operator",
func: (proxies) => { func: (proxies) => {
@ -1912,7 +1944,7 @@ function KeywordRenameOperator(keywords) {
name: "Keyword Rename Operator", name: "Keyword Rename Operator",
func: (proxies) => { func: (proxies) => {
return proxies.map((proxy) => { return proxies.map((proxy) => {
for (const {old, now} of keywords) { for (const { old, now } of keywords) {
proxy.name = proxy.name.replaceAll(old, now).trim(); proxy.name = proxy.name.replaceAll(old, now).trim();
} }
return proxy; return proxy;
@ -1928,7 +1960,7 @@ function RegexRenameOperator(regex) {
name: "Regex Rename Operator", name: "Regex Rename Operator",
func: (proxies) => { func: (proxies) => {
return proxies.map((proxy) => { return proxies.map((proxy) => {
for (const {expr, now} of regex) { for (const { expr, now } of regex) {
proxy.name = proxy.name.replace(new RegExp(expr, "g"), now).trim(); proxy.name = proxy.name.replace(new RegExp(expr, "g"), now).trim();
} }
return proxy; return proxy;
@ -2003,7 +2035,7 @@ function ScriptOperator(script) {
/**************************** Filters ***************************************/ /**************************** Filters ***************************************/
// filter by keywords // filter by keywords
function KeywordFilter({keywords = [], keep = true}) { function KeywordFilter({ keywords = [], keep = true }) {
return { return {
name: "Keyword Filter", name: "Keyword Filter",
func: (proxies) => { func: (proxies) => {
@ -2058,7 +2090,7 @@ function RegionFilter(regions) {
} }
// filter by regex // filter by regex
function RegexFilter({regex = [], keep = true}) { function RegexFilter({ regex = [], keep = true }) {
return { return {
name: "Regex Filter", name: "Regex Filter",
func: (proxies) => { func: (proxies) => {
@ -2396,21 +2428,21 @@ function ENV() {
} }
function HTTP(defaultOptions = {}) { function HTTP(defaultOptions = {}) {
const {isQX, isLoon, isSurge} = ENV(); const { isQX, isLoon, isSurge } = ENV();
const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"]; const methods = ["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"];
function send(method, options) { function send(method, options) {
options = options.hasOwnProperty("url") ? options : {url: options}; options = options.hasOwnProperty("url") ? options : { url: options };
options.url = defaultOptions.baseURL ? defaultOptions.baseURL + options.url : options.url; options.url = defaultOptions.baseURL
options = {...defaultOptions, ...options}; ? defaultOptions.baseURL + options.url
: options.url;
options = { ...defaultOptions, ...options };
const timeout = options.timeout; const timeout = options.timeout;
const events = { const events = {
...{ ...{
onRequest: () => { onRequest: () => {},
},
onResponse: (resp) => resp, onResponse: (resp) => resp,
onTimeout: () => { onTimeout: () => {},
},
}, },
...options.events, ...options.events,
}; };
@ -2419,7 +2451,7 @@ function HTTP(defaultOptions = {}) {
let worker; let worker;
if (isQX) { if (isQX) {
worker = $task.fetch({method, ...options}); worker = $task.fetch({ method, ...options });
} else { } else {
worker = new Promise((resolve, reject) => { worker = new Promise((resolve, reject) => {
const request = isSurge || isLoon ? $httpClient : require("request"); const request = isSurge || isLoon ? $httpClient : require("request");
@ -2465,7 +2497,7 @@ function HTTP(defaultOptions = {}) {
} }
function API(name = "untitled", debug = false) { function API(name = "untitled", debug = false) {
const {isQX, isLoon, isSurge, isNode, isJSBox, isScriptable} = ENV(); const { isQX, isLoon, isSurge, isNode, isJSBox, isScriptable } = ENV();
return new (class { return new (class {
constructor(name, debug) { constructor(name, debug) {
this.name = name; this.name = name;
@ -2513,7 +2545,7 @@ function API(name = "untitled", debug = false) {
this.node.fs.writeFileSync( this.node.fs.writeFileSync(
fpath, fpath,
JSON.stringify({}), JSON.stringify({}),
{flag: "wx"}, { flag: "wx" },
(err) => console.log(err) (err) => console.log(err)
); );
} }
@ -2525,7 +2557,7 @@ function API(name = "untitled", debug = false) {
this.node.fs.writeFileSync( this.node.fs.writeFileSync(
fpath, fpath,
JSON.stringify({}), JSON.stringify({}),
{flag: "wx"}, { flag: "wx" },
(err) => console.log(err) (err) => console.log(err)
); );
this.cache = {}; this.cache = {};
@ -2546,13 +2578,13 @@ function API(name = "untitled", debug = false) {
this.node.fs.writeFileSync( this.node.fs.writeFileSync(
`${this.name}.json`, `${this.name}.json`,
data, data,
{flag: "w"}, { flag: "w" },
(err) => console.log(err) (err) => console.log(err)
); );
this.node.fs.writeFileSync( this.node.fs.writeFileSync(
"root.json", "root.json",
JSON.stringify(this.root), JSON.stringify(this.root),
{flag: "w"}, { flag: "w" },
(err) => console.log(err) (err) => console.log(err)
); );
} }
@ -2630,7 +2662,7 @@ function API(name = "untitled", debug = false) {
let opts = {}; let opts = {};
if (openURL) opts["openUrl"] = openURL; if (openURL) opts["openUrl"] = openURL;
if (mediaURL) opts["mediaUrl"] = mediaURL; if (mediaURL) opts["mediaUrl"] = mediaURL;
if (JSON.stringify(opts) === '{}') { if (JSON.stringify(opts) === "{}") {
$notification.post(title, subtitle, content); $notification.post(title, subtitle, content);
} else { } else {
$notification.post(title, subtitle, content, opts); $notification.post(title, subtitle, content, opts);
@ -2682,7 +2714,7 @@ function API(name = "untitled", debug = false) {
/*********************************** Mini Express *************************************/ /*********************************** Mini Express *************************************/
function express(port = 3000) { function express(port = 3000) {
const {isNode} = ENV(); const { isNode } = ENV();
const DEFAULT_HEADERS = { const DEFAULT_HEADERS = {
"Content-Type": "text/plain;charset=UTF-8", "Content-Type": "text/plain;charset=UTF-8",
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
@ -2696,9 +2728,9 @@ function express(port = 3000) {
const express_ = require("express"); const express_ = require("express");
const bodyParser = require("body-parser"); const bodyParser = require("body-parser");
const app = express_(); const app = express_();
app.use(bodyParser.json({verify: rawBodySaver})); app.use(bodyParser.json({ verify: rawBodySaver }));
app.use(bodyParser.urlencoded({verify: rawBodySaver, extended: true})); app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
app.use(bodyParser.raw({verify: rawBodySaver, type: "*/*"})); app.use(bodyParser.raw({ verify: rawBodySaver, type: "*/*" }));
app.use((req, res, next) => { app.use((req, res, next) => {
res.set(DEFAULT_HEADERS); res.set(DEFAULT_HEADERS);
next(); next();
@ -2730,19 +2762,19 @@ function express(port = 3000) {
// dispatch url to route // dispatch url to route
const dispatch = (request, start = 0) => { const dispatch = (request, start = 0) => {
let {method, url, headers, body} = request; let { method, url, headers, body } = request;
if (/json/i.test(headers["Content-Type"])) { if (/json/i.test(headers["Content-Type"])) {
body = JSON.parse(body); body = JSON.parse(body);
} }
method = method.toUpperCase(); method = method.toUpperCase();
const {path, query} = extractURL(url); const { path, query } = extractURL(url);
let handler = null; let handler = null;
let i; let i;
for (i = start; i < handlers.length; i++) { for (i = start; i < handlers.length; i++) {
if (handlers[i].method === "ALL" || method === handlers[i].method) { if (handlers[i].method === "ALL" || method === handlers[i].method) {
const {pattern} = handlers[i]; const { pattern } = handlers[i];
if (patternMatched(pattern, path)) { if (patternMatched(pattern, path)) {
handler = handlers[i]; handler = handlers[i];
break; break;
@ -2786,7 +2818,7 @@ function express(port = 3000) {
METHODS_NAMES.forEach((method) => { METHODS_NAMES.forEach((method) => {
app[method.toLowerCase()] = (pattern, callback) => { app[method.toLowerCase()] = (pattern, callback) => {
// add handler // add handler
handlers.push({method, pattern, callback}); handlers.push({ method, pattern, callback });
}; };
}); });
@ -2796,7 +2828,7 @@ function express(port = 3000) {
METHODS_NAMES.forEach((method) => { METHODS_NAMES.forEach((method) => {
chainApp[method.toLowerCase()] = (callback) => { chainApp[method.toLowerCase()] = (callback) => {
// add handler // add handler
handlers.push({method, pattern, callback}); handlers.push({ method, pattern, callback });
return chainApp; return chainApp;
}; };
}); });
@ -2821,7 +2853,7 @@ function express(port = 3000) {
function Response() { function Response() {
let statusCode = 200; let statusCode = 200;
const {isQX, isLoon, isSurge} = ENV(); const { isQX, isLoon, isSurge } = ENV();
const headers = DEFAULT_HEADERS; const headers = DEFAULT_HEADERS;
const STATUS_CODE_MAP = { const STATUS_CODE_MAP = {
200: "HTTP/1.1 200 OK", 200: "HTTP/1.1 200 OK",

File diff suppressed because one or more lines are too long