diff --git a/package-lock.json b/package-lock.json index af25ed983..2ce0f9a87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "eventemitter2": "^6.4.9", "express": "^4.21.2", "express-async-errors": "^3.1.1", + "fetch-socks": "^1.3.2", "fluent-ffmpeg": "^2.1.3", "form-data": "^4.0.1", "https-proxy-agent": "^7.0.6", @@ -8578,6 +8579,22 @@ "reusify": "^1.0.4" } }, + "node_modules/fetch-socks": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fetch-socks/-/fetch-socks-1.3.2.tgz", + "integrity": "sha512-vkH5+Zgj2yEbU57Cei0iyLgTZ4OkEKJj56Xu3ViB5dpsl599JgEooQ3x6NVagIFRHWnWJ+7K0MO0aIV1TMgvnw==", + "license": "MIT", + "dependencies": { + "socks": "^2.8.2", + "undici": ">=6" + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", diff --git a/package.json b/package.json index eadb1e18e..56e32fcc8 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "fluent-ffmpeg": "^2.1.3", "form-data": "^4.0.1", "https-proxy-agent": "^7.0.6", + "fetch-socks": "^1.3.2", "i18next": "^23.7.19", "jimp": "^1.6.0", "json-schema": "^0.4.0", diff --git a/src/utils/makeProxyAgent.ts b/src/utils/makeProxyAgent.ts index ac64b9dec..989fc95e4 100644 --- a/src/utils/makeProxyAgent.ts +++ b/src/utils/makeProxyAgent.ts @@ -1,3 +1,4 @@ +import { socksDispatcher } from 'fetch-socks'; import { HttpsProxyAgent } from 'https-proxy-agent'; import { SocksProxyAgent } from 'socks-proxy-agent'; import { ProxyAgent } from 'undici'; @@ -18,12 +19,23 @@ function selectProxyAgent(proxyUrl: string): HttpsProxyAgent | SocksProx // the end so, we add the protocol constants without the `:` to avoid confusion. const PROXY_HTTP_PROTOCOL = 'http:'; const PROXY_SOCKS_PROTOCOL = 'socks:'; + const PROXY_SOCKS5_PROTOCOL = 'socks5:'; switch (url.protocol) { case PROXY_HTTP_PROTOCOL: return new HttpsProxyAgent(url); case PROXY_SOCKS_PROTOCOL: - return new SocksProxyAgent(url); + case PROXY_SOCKS5_PROTOCOL: { + let urlSocks = ''; + + if (url.username && url.password) { + urlSocks = `socks://${url.username}:${url.password}@${url.hostname}:${url.port}`; + } else { + urlSocks = `socks://${url.hostname}:${url.port}`; + } + + return new SocksProxyAgent(urlSocks); + } default: throw new Error(`Unsupported proxy protocol: ${url.protocol}`); } @@ -44,7 +56,7 @@ export function makeProxyAgent(proxy: Proxy | string): HttpsProxyAgent | return selectProxyAgent(proxyUrl); } -export function makeProxyAgentUndici(proxy: Proxy | string): ProxyAgent { +export function makeProxyAgentUndici(proxy: Proxy | string) { let proxyUrl: string; let protocol: string; @@ -55,15 +67,14 @@ export function makeProxyAgentUndici(proxy: Proxy | string): ProxyAgent { } else { const { host, password, port, protocol: proto, username } = proxy; protocol = (proto || 'http').replace(':', ''); - - if (protocol === 'socks') { - protocol = 'socks5'; - } + if (protocol === 'socks') protocol = 'socks5'; const auth = username && password ? `${username}:${password}@` : ''; proxyUrl = `${protocol}://${auth}${host}:${port}`; } + protocol = protocol.toLowerCase(); + const PROXY_HTTP_PROTOCOL = 'http'; const PROXY_HTTPS_PROTOCOL = 'https'; const PROXY_SOCKS4_PROTOCOL = 'socks4'; @@ -72,10 +83,25 @@ export function makeProxyAgentUndici(proxy: Proxy | string): ProxyAgent { switch (protocol) { case PROXY_HTTP_PROTOCOL: case PROXY_HTTPS_PROTOCOL: - case PROXY_SOCKS4_PROTOCOL: - case PROXY_SOCKS5_PROTOCOL: return new ProxyAgent(proxyUrl); + case PROXY_SOCKS4_PROTOCOL: + case PROXY_SOCKS5_PROTOCOL: { + let type: 4 | 5 = 5; + + if (PROXY_SOCKS4_PROTOCOL === protocol) type = 4; + + const url = new URL(proxyUrl); + + return socksDispatcher({ + type: type, + host: url.hostname, + port: Number(url.port), + userId: url.username || undefined, + password: url.password || undefined, + }); + } + default: throw new Error(`Unsupported proxy protocol: ${protocol}`); }