From 8078d0618d076d913feb03f78673860cfec00f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?U=C4=9Fur=20Erkan?= Date: Thu, 4 Nov 2021 14:32:16 +0300 Subject: [PATCH] Add socks proxy support to proxy feature - Socks proxy support implemented. - Monitor proxy agent create flow refactored and moved under proxy class. Thanks for suggestion @thomasleveil --- server/model/monitor.js | 31 +++--------- server/proxy.js | 75 ++++++++++++++++++++++++++++- src/components/ProxyDialog.vue | 3 ++ src/components/settings/Proxies.vue | 3 +- src/pages/EditMonitor.vue | 2 +- 5 files changed, 85 insertions(+), 29 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index f938ca80b..f9c025d11 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -1,6 +1,4 @@ const https = require("https"); -const HttpProxyAgent = require("http-proxy-agent"); -const HttpsProxyAgent = require("https-proxy-agent"); const dayjs = require("dayjs"); const utc = require("dayjs/plugin/utc"); let timezone = require("dayjs/plugin/timezone"); @@ -13,6 +11,7 @@ const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalCli const { R } = require("redbean-node"); const { BeanModel } = require("redbean-node/dist/bean-model"); const { Notification } = require("../notification"); +const { Proxy } = require("../proxy"); const { demoMode } = require("../config"); const version = require("../../package.json").version; const apicache = require("../modules/apicache"); @@ -204,31 +203,13 @@ class Monitor extends BeanModel { const proxy = await R.load("proxy", this.proxy_id); if (proxy && proxy.active) { - const httpProxyAgentOptions = { - protocol: proxy.protocol, - host: proxy.host, - port: proxy.port, - }; - const httpsProxyAgentOptions = { - ...httpsAgentOptions, - protocol: proxy.protocol, - hostname: proxy.host, - port: proxy.port, - }; - - if (proxy.auth) { - httpProxyAgentOptions.auth = `${proxy.username}:${proxy.password}`; - httpsProxyAgentOptions.auth = `${proxy.username}:${proxy.password}`; - } - - debug(`[${this.name}] HTTP options: ${JSON.stringify({ - "http": httpProxyAgentOptions, - "https": httpsProxyAgentOptions, - })}`); + const { httpAgent, httpsAgent } = Proxy.createAgents(proxy, { + httpsAgentOptions: httpsAgentOptions, + }); options.proxy = false; - options.httpAgent = new HttpProxyAgent(httpProxyAgentOptions); - options.httpsAgent = new HttpsProxyAgent(httpsProxyAgentOptions); + options.httpAgent = httpAgent; + options.httpsAgent = httpsAgent; } } diff --git a/server/proxy.js b/server/proxy.js index df3831538..392a0af7f 100644 --- a/server/proxy.js +++ b/server/proxy.js @@ -1,7 +1,13 @@ const { R } = require("redbean-node"); +const HttpProxyAgent = require("http-proxy-agent"); +const HttpsProxyAgent = require("https-proxy-agent"); +const SocksProxyAgent = require("socks-proxy-agent"); +const { debug } = require("../src/util"); class Proxy { + static SUPPORTED_PROXY_PROTOCOLS = ["http", "https", "socks", "socks5", "socks4"] + /** * Saves and updates given proxy entity * @@ -25,8 +31,11 @@ class Proxy { } // Make sure given proxy protocol is supported - if (!["http", "https"].includes(proxy.protocol)) { - throw new Error(`Unsupported proxy protocol "${proxy.protocol}. Supported protocols are http and https."`); + if (!this.SUPPORTED_PROXY_PROTOCOLS.includes(proxy.protocol)) { + throw new Error(` + Unsupported proxy protocol "${proxy.protocol}. + Supported protocols are ${this.SUPPORTED_PROXY_PROTOCOLS.join(", ")}."` + ); } // When proxy is default update deactivate old default proxy @@ -73,6 +82,68 @@ class Proxy { // Delete proxy from list await R.trash(bean); } + + /** + * Create HTTP and HTTPS agents related with given proxy bean object + * + * @param proxy proxy bean object + * @param options http and https agent options + * @return {{httpAgent: Agent, httpsAgent: Agent}} + */ + static createAgents(proxy, options) { + const { httpAgentOptions, httpsAgentOptions } = options || {}; + let agent; + let httpAgent; + let httpsAgent; + + const proxyOptions = { + protocol: proxy.protocol, + host: proxy.host, + port: proxy.port, + }; + + if (proxy.auth) { + proxyOptions.auth = `${proxy.username}:${proxy.password}`; + } + + debug(`Proxy Options: ${JSON.stringify(proxyOptions)}`); + debug(`HTTP Agent Options: ${JSON.stringify(httpAgentOptions)}`); + debug(`HTTPS Agent Options: ${JSON.stringify(httpsAgentOptions)}`); + + switch (proxy.protocol) { + case "http": + case "https": + httpAgent = new HttpProxyAgent({ + ...httpAgentOptions || {}, + ...proxyOptions + }); + + httpsAgent = new HttpsProxyAgent({ + ...httpsAgentOptions || {}, + ...proxyOptions, + }); + break; + case "socks": + case "socks5": + case "socks4": + agent = new SocksProxyAgent({ + ...httpAgentOptions, + ...httpsAgentOptions, + ...proxyOptions, + }); + + httpAgent = agent; + httpsAgent = agent; + break; + + default: throw new Error(`Unsupported proxy protocol provided. ${proxy.protocol}`); + } + + return { + httpAgent, + httpsAgent + }; + } } /** diff --git a/src/components/ProxyDialog.vue b/src/components/ProxyDialog.vue index 372cc64b4..32fa04cb5 100644 --- a/src/components/ProxyDialog.vue +++ b/src/components/ProxyDialog.vue @@ -15,6 +15,9 @@ diff --git a/src/components/settings/Proxies.vue b/src/components/settings/Proxies.vue index 344cbb6e0..4608f3aa4 100644 --- a/src/components/settings/Proxies.vue +++ b/src/components/settings/Proxies.vue @@ -11,7 +11,8 @@ diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index 47e685285..42454e522 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -237,7 +237,7 @@