feat: DiscordAuthWebsocket support captcha handler #444

This commit is contained in:
March 7th 2022-12-22 14:53:27 +07:00
parent bee76dbf9e
commit a32c7292df
2 changed files with 84 additions and 26 deletions

View File

@ -99,6 +99,38 @@ class DiscordAuthWebsocket extends EventEmitter {
* @type {?string} * @type {?string}
*/ */
this.fingerprint = null; this.fingerprint = null;
/**
* Captcha Handler
* @type {Function}
* @param {Captcha} data hcaptcha data
* @returns {Promise<string>} Captcha token
*/
// eslint-disable-next-line no-unused-vars
this.captchaHandler = data =>
new Promise((resolve, reject) => {
reject(
new Error(`
Captcha Handler not found - Please set captchaHandler option
Example captchaHandler function:
new DiscordAuthWebsocket({
captchaHandler: async (data) => {
const token = await hcaptchaSolver(data.captcha_sitekey, 'discord.com');
return token;
}
});
`),
);
});
/**
* Captcha Cache
* @type {?Captcha}
*/
this.captchaCache = null;
this._validateOptions(options); this._validateOptions(options);
} }
/** /**
@ -133,6 +165,7 @@ class DiscordAuthWebsocket extends EventEmitter {
if (typeof options.apiVersion == 'number') this.options.apiVersion = options.apiVersion; if (typeof options.apiVersion == 'number') this.options.apiVersion = options.apiVersion;
if (typeof options.userAgent == 'string') this.options.userAgent = options.userAgent; if (typeof options.userAgent == 'string') this.options.userAgent = options.userAgent;
if (typeof options.wsProperties == 'object') this.options.wsProperties = options.wsProperties; if (typeof options.wsProperties == 'object') this.options.wsProperties = options.wsProperties;
if (typeof options.captchaHandler == 'function') this.captchaHandler = options.captchaHandler;
} }
} }
_createWebSocket(url) { _createWebSocket(url) {
@ -378,12 +411,20 @@ class DiscordAuthWebsocket extends EventEmitter {
this._logger('default', `Please scan the QR code to continue.\nQR Code will expire in ${this.exprireTime}`); this._logger('default', `Please scan the QR code to continue.\nQR Code will expire in ${this.exprireTime}`);
} }
async _findRealToken() { async _findRealToken(captchaSolveData) {
if (!this.token) this._throwError(new Error('Token is not created.')); if (!this.token) this._throwError(new Error('Token is not created.'));
const chromeVersion = defaultClientOptions.ws.properties.browser_version.split('.')[0]; const chromeVersion = defaultClientOptions.ws.properties.browser_version.split('.')[0];
const res = await axios.post( this._logger('debug', 'Find real token...', res.data);
const res = await axios
.post(
`https://discord.com/api/v${this.options.apiVersion}/users/@me/remote-auth/login`, `https://discord.com/api/v${this.options.apiVersion}/users/@me/remote-auth/login`,
{ captchaSolveData
? {
ticket: this.token,
captcha_rqtoken: this.captchaCache.captcha_rqtoken,
captcha_key: captchaSolveData,
}
: {
ticket: this.token, ticket: this.token,
}, },
{ {
@ -400,13 +441,27 @@ class DiscordAuthWebsocket extends EventEmitter {
'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-Site': 'same-origin',
'X-Debug-Options': 'bugReporterEnabled', 'X-Debug-Options': 'bugReporterEnabled',
'X-Super-Properties': `${Buffer.from(JSON.stringify(this.options.wsProperties), 'ascii').toString('base64')}`, 'X-Super-Properties': `${Buffer.from(JSON.stringify(this.options.wsProperties), 'ascii').toString(
'base64',
)}`,
'X-Discord-Locale': 'en-US', 'X-Discord-Locale': 'en-US',
'User-Agent': this.options.userAgent, 'User-Agent': this.options.userAgent,
}, },
}, },
); )
this._logger('debug', 'Find real token...', res.data); .catch(e => {
if (e.response.data?.captcha_key) {
this.captchaCache = e.response.data;
} else {
this._throwError(e);
this.captchaCache = null;
}
});
if (!res && this.captchaCache) {
this._logger('debug', 'Detect captcha... Try call captchaHandler()', this.captchaCache);
const token = await this.options.captchaHandler(this.captchaCache);
return this._findRealToken(token);
}
this.realToken = this._decryptPayload(res.data.encrypted_token).toString(); this.realToken = this._decryptPayload(res.data.encrypted_token).toString();
/** /**
* Emitted whenever a real token is found. * Emitted whenever a real token is found.
@ -415,6 +470,7 @@ class DiscordAuthWebsocket extends EventEmitter {
* @param {string} token Real token * @param {string} token Real token
*/ */
this.emit(Event.FINISH, this.user, this.realToken); this.emit(Event.FINISH, this.user, this.realToken);
return this;
} }
} }

2
typings/index.d.ts vendored
View File

@ -200,6 +200,8 @@ export class DiscordAuthWebsocket extends EventEmitter {
public token?: string; public token?: string;
public realToken?: string; public realToken?: string;
public user?: RawUserData; public user?: RawUserData;
public captchaCache?: Captcha;
public captchaHandler(data: Captcha): Promise<string>;
public readonly exprireTime: string; public readonly exprireTime: string;
public connect(client?: Client): void; public connect(client?: Client): void;
public destroy(): void; public destroy(): void;