Skip to content

Commit 1da3b3f

Browse files
committed
feat: Node 运行环境支持 SOCKS5 代理
1 parent 61078b1 commit 1da3b3f

3 files changed

Lines changed: 76 additions & 8 deletions

File tree

backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.19.79",
3+
"version": "2.19.80",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"scripts": {
@@ -32,6 +32,7 @@
3232
"dns-packet": "^5.6.1",
3333
"dotenv": "^16.4.7",
3434
"express": "^4.17.1",
35+
"fetch-socks": "^1.3.2",
3536
"http-proxy-middleware": "^3.0.3",
3637
"ip-address": "^9.0.5",
3738
"js-base64": "^3.7.2",

backend/pnpm-lock.yaml

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/vendor/open-api.js

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { parse } from 'dotenv';
2+
13
/* eslint-disable no-undef */
24
const isQX = typeof $task !== 'undefined';
35
const isLoon = typeof $loon !== 'undefined';
@@ -18,6 +20,26 @@ function isPlainObject(obj) {
1820
);
1921
}
2022

23+
function parseSocks5Uri(uri) {
24+
// eslint-disable-next-line no-unused-vars
25+
let [__, username, password, server, port, query, name] = uri.match(
26+
/^socks5:\/\/(?:(.*?):(.*?)@)?(.*?)(?::(\d+?))?(\?.*?)?(?:#(.*?))?$/,
27+
);
28+
if (port) {
29+
port = parseInt(port, 10);
30+
} else {
31+
$.error(`port is not present in line: ${uri}`);
32+
throw new Error(`port is not present in line: ${uri}`);
33+
}
34+
return {
35+
type: 5,
36+
host: server,
37+
port,
38+
39+
userId: username != null ? decodeURIComponent(username) : undefined,
40+
password: password != null ? decodeURIComponent(password) : undefined,
41+
};
42+
}
2143
export class OpenAPI {
2244
constructor(name = 'untitled', debug = false) {
2345
this.name = name;
@@ -393,6 +415,7 @@ export function HTTP(defaultOptions = { baseURL: '' }) {
393415
}
394416
if (isNode) {
395417
const undici = eval("require('undici')");
418+
const { socksDispatcher } = eval("require('fetch-socks')");
396419
const {
397420
ProxyAgent,
398421
EnvHttpProxyAgent,
@@ -422,16 +445,34 @@ export function HTTP(defaultOptions = { baseURL: '' }) {
422445
).toString('base64')}`,
423446
};
424447
}
448+
let dispatcher;
449+
if (!opts.proxy) {
450+
const allProxy =
451+
eval('process.env.all_proxy') ||
452+
eval('process.env.ALL_PROXY');
453+
if (allProxy && /^socks5:\/\//.test(allProxy)) {
454+
opts.proxy = allProxy;
455+
}
456+
}
457+
if (opts.proxy) {
458+
if (/^socks5:\/\//.test(opts.proxy)) {
459+
dispatcher = socksDispatcher(
460+
parseSocks5Uri(opts.proxy),
461+
agentOpts,
462+
);
463+
} else {
464+
dispatcher = new ProxyAgent({
465+
...agentOpts,
466+
uri: opts.proxy,
467+
});
468+
}
469+
} else {
470+
dispatcher = new EnvHttpProxyAgent(agentOpts);
471+
}
425472
const response = await request(opts.url, {
426473
...opts,
427474
method: method.toUpperCase(),
428-
dispatcher: (opts.proxy
429-
? new ProxyAgent({
430-
...agentOpts,
431-
uri: opts.proxy,
432-
})
433-
: new EnvHttpProxyAgent(agentOpts)
434-
).compose(
475+
dispatcher: dispatcher.compose(
435476
interceptors.redirect({
436477
maxRedirections: 3,
437478
throwOnMaxRedirects: true,

0 commit comments

Comments
 (0)