diff --git a/src/client/Client.js b/src/client/Client.js index e6e82e9..ba128a5 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -1033,6 +1033,9 @@ class Client extends BaseClient { if (options && typeof options.captchaSolver !== 'function') { throw new TypeError('CLIENT_INVALID_OPTION', 'captchaSolver', 'a function'); } + if (options && typeof options.captchaWithProxy !== 'boolean') { + throw new TypeError('CLIENT_INVALID_OPTION', 'captchaWithProxy', 'a boolean'); + } if (options && typeof options.DMSync !== 'boolean') { throw new TypeError('CLIENT_INVALID_OPTION', 'DMSync', 'a boolean'); } diff --git a/src/rest/CaptchaSolver.js b/src/rest/CaptchaSolver.js index 1f5c512..0c6c932 100644 --- a/src/rest/CaptchaSolver.js +++ b/src/rest/CaptchaSolver.js @@ -1,11 +1,46 @@ 'use strict'; +const proxyParser = proxy => { + const protocolSplit = proxy.split('://'); + const protocol = protocolSplit.length === 1 ? null : protocolSplit[0]; + const rest = protocolSplit.length === 1 ? protocolSplit[0] : protocolSplit[1]; + const authSplit = rest.split('@'); + if (authSplit.length === 1) { + const host = authSplit[0].split(':')[0]; + const port = Number(authSplit[0].split(':')[1]); + const proxyConfig = { + host, + port, + }; + if (protocol != null) { + proxyConfig.protocol = protocol; + } + return proxyConfig; + } + const host = authSplit[1].split(':')[0]; + const port = Number(authSplit[1].split(':')[1]); + const [username, password] = authSplit[0].split(':'); + const proxyConfig = { + host, + port, + auth: { + username, + password, + }, + }; + if (protocol != null) { + proxyConfig.protocol = protocol; + } + return proxyConfig; +}; + module.exports = class CaptchaSolver { - constructor(service, key, defaultCaptchaSolver) { + constructor(service, key, defaultCaptchaSolver, proxyString = '') { this.service = 'custom'; this.solver = undefined; this.defaultCaptchaSolver = defaultCaptchaSolver; this.key = null; + this.proxy = proxyString.length ? proxyParser(proxyString) : null; this._setup(service, key); } _missingModule(name) { @@ -23,12 +58,22 @@ module.exports = class CaptchaSolver { this.solve = (data, userAgent) => new Promise((resolve, reject) => { const siteKey = data.captcha_sitekey; - const postD = data.captcha_rqdata - ? { - data: data.captcha_rqdata, - userAgent, - } - : undefined; + let postD = {}; + if (this.proxy !== null) { + postD = { + proxytype: this.proxy.protocol?.toUpperCase(), + proxy: `${'auth' in this.proxy ? `${this.proxy.auth.username}:${this.proxy.auth.password}@` : ''}${ + this.proxy.host + }:${this.proxy.port}`, + }; + } + if (data.captcha_rqdata) { + postD = { + ...postD, + data: data.captcha_rqdata, + userAgent, + }; + } this.solver .hcaptcha(siteKey, 'https://discord.com/channels/@me', postD) .then(res => { @@ -51,6 +96,15 @@ module.exports = class CaptchaSolver { this.solve = (captchaData, userAgent) => new Promise((resolve, reject) => { if (userAgent) client.setUserAgent(userAgent); + if (this.proxy !== null) { + client.setProxy( + this.proxy.protocol, + this.proxy.host, + this.proxy.port, + 'auth' in this.proxy ? this.proxy.auth.username : undefined, + 'auth' in this.proxy ? this.proxy.auth.password : undefined, + ); + } client .createWithTask( client.task({ diff --git a/src/rest/RESTManager.js b/src/rest/RESTManager.js index dddf785..87450d6 100644 --- a/src/rest/RESTManager.js +++ b/src/rest/RESTManager.js @@ -32,6 +32,7 @@ class RESTManager { this.client.options.captchaService, this.client.options.captchaKey, this.client.options.captchaSolver, + this.client.options.captchaWithProxy ? this.client.options.proxy : '', ); } diff --git a/src/util/Options.js b/src/util/Options.js index 4e5a5f5..6c27b22 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -42,6 +42,7 @@ const { defaultUA } = require('../util/Constants'); * @property {string} [captchaService=null] Captcha service to use for solving captcha {@link captchaServices} * @property {string} [captchaKey=null] Captcha service key * @property {string} [captchaRetryLimit=3] Captcha retry limit + * @property {string} [captchaWithProxy=false] Whether to use proxy for captcha solving * @property {string} [password=null] Your Discord account password * @property {boolean} [usingNewAttachmentAPI=true] Use new attachment API * @property {string} [interactionTimeout=15000] The amount of time in milliseconds to wait for an interaction response, before rejecting @@ -166,6 +167,7 @@ class Options extends null { captchaService: '', captchaKey: null, captchaRetryLimit: 3, + captchaWithProxy: false, DMSync: false, patchVoice: false, password: null, diff --git a/typings/index.d.ts b/typings/index.d.ts index 7942a77..9734d10 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -5075,6 +5075,7 @@ export interface ClientOptions { captchaKey?: string; captchaSolver?: (data: Captcha, userAgent: string) => Promise; captchaRetryLimit?: number; + captchaWithProxy?: boolean; interactionTimeout?: number; usingNewAttachmentAPI?: boolean; }