feat: captcha solver with proxy

i dont like it
This commit is contained in:
Elysia 2023-06-02 11:09:08 +07:00
parent 2e0889459c
commit 18e7f8171f
5 changed files with 68 additions and 7 deletions

View File

@ -1033,6 +1033,9 @@ class Client extends BaseClient {
if (options && typeof options.captchaSolver !== 'function') { if (options && typeof options.captchaSolver !== 'function') {
throw new TypeError('CLIENT_INVALID_OPTION', 'captchaSolver', 'a 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') { if (options && typeof options.DMSync !== 'boolean') {
throw new TypeError('CLIENT_INVALID_OPTION', 'DMSync', 'a boolean'); throw new TypeError('CLIENT_INVALID_OPTION', 'DMSync', 'a boolean');
} }

View File

@ -1,11 +1,46 @@
'use strict'; '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 { module.exports = class CaptchaSolver {
constructor(service, key, defaultCaptchaSolver) { constructor(service, key, defaultCaptchaSolver, proxyString = '') {
this.service = 'custom'; this.service = 'custom';
this.solver = undefined; this.solver = undefined;
this.defaultCaptchaSolver = defaultCaptchaSolver; this.defaultCaptchaSolver = defaultCaptchaSolver;
this.key = null; this.key = null;
this.proxy = proxyString.length ? proxyParser(proxyString) : null;
this._setup(service, key); this._setup(service, key);
} }
_missingModule(name) { _missingModule(name) {
@ -23,12 +58,22 @@ module.exports = class CaptchaSolver {
this.solve = (data, userAgent) => this.solve = (data, userAgent) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
const siteKey = data.captcha_sitekey; const siteKey = data.captcha_sitekey;
const postD = data.captcha_rqdata 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, data: data.captcha_rqdata,
userAgent, userAgent,
};
} }
: undefined;
this.solver this.solver
.hcaptcha(siteKey, 'https://discord.com/channels/@me', postD) .hcaptcha(siteKey, 'https://discord.com/channels/@me', postD)
.then(res => { .then(res => {
@ -51,6 +96,15 @@ module.exports = class CaptchaSolver {
this.solve = (captchaData, userAgent) => this.solve = (captchaData, userAgent) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
if (userAgent) client.setUserAgent(userAgent); 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 client
.createWithTask( .createWithTask(
client.task({ client.task({

View File

@ -32,6 +32,7 @@ class RESTManager {
this.client.options.captchaService, this.client.options.captchaService,
this.client.options.captchaKey, this.client.options.captchaKey,
this.client.options.captchaSolver, this.client.options.captchaSolver,
this.client.options.captchaWithProxy ? this.client.options.proxy : '',
); );
} }

View File

@ -42,6 +42,7 @@ const { defaultUA } = require('../util/Constants');
* @property {string} [captchaService=null] Captcha service to use for solving captcha {@link captchaServices} * @property {string} [captchaService=null] Captcha service to use for solving captcha {@link captchaServices}
* @property {string} [captchaKey=null] Captcha service key * @property {string} [captchaKey=null] Captcha service key
* @property {string} [captchaRetryLimit=3] Captcha retry limit * @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 {string} [password=null] Your Discord account password
* @property {boolean} [usingNewAttachmentAPI=true] Use new attachment API * @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 * @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: '', captchaService: '',
captchaKey: null, captchaKey: null,
captchaRetryLimit: 3, captchaRetryLimit: 3,
captchaWithProxy: false,
DMSync: false, DMSync: false,
patchVoice: false, patchVoice: false,
password: null, password: null,

1
typings/index.d.ts vendored
View File

@ -5075,6 +5075,7 @@ export interface ClientOptions {
captchaKey?: string; captchaKey?: string;
captchaSolver?: (data: Captcha, userAgent: string) => Promise<string>; captchaSolver?: (data: Captcha, userAgent: string) => Promise<string>;
captchaRetryLimit?: number; captchaRetryLimit?: number;
captchaWithProxy?: boolean;
interactionTimeout?: number; interactionTimeout?: number;
usingNewAttachmentAPI?: boolean; usingNewAttachmentAPI?: boolean;
} }