From 7e4a3ccd578823ce351b8e445bacedf68c3b56f3 Mon Sep 17 00:00:00 2001 From: March 7th <71698422+aiko-chan-ai@users.noreply.github.com> Date: Tue, 8 Nov 2022 13:27:44 +0700 Subject: [PATCH] fix: Package (read description) - Security update + Update Discord Version + Update WS identify data - Fix Captcha Handler --- README.md | 2 +- src/client/Client.js | 9 ++++++--- src/errors/Messages.js | 1 + src/rest/APIRequest.js | 9 +++++++-- src/rest/RequestHandler.js | 17 ++++++++++++++++- src/structures/Guild.js | 37 ++++++++++++++++++++++++++++++++++--- src/structures/Invite.js | 9 ++------- src/util/Options.js | 7 ++++--- typings/index.d.ts | 1 + 9 files changed, 72 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index dc248f8..4271cd7 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ - [X] Guild: Fetch Members, Join / Leave, Roles, Channels, etc. - [X] Interactions: Slash Commands, Click Buttons, Menu (classic), Modal, Context Menu, etc. - [X] Voice: Connect, Disconnect, Mute, Deafen, Call, Play Audio, etc. -- [X] Captcha Handler (Must not use due to safety concerns) +- [X] Captcha Handler - [X] Documentation - [ ] Video stream - [ ] Everything diff --git a/src/client/Client.js b/src/client/Client.js index 5b575f3..69292d2 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -848,6 +848,12 @@ class Client extends BaseClient { * @param {string} url Discord Auth URL * @param {Object} options Oauth2 options * @returns {Promise} + * @example + * client.authorizeURL(`https://discord.com/api/oauth2/authorize?client_id=botID&permissions=8&scope=applications.commands%20bot`, { + guild_id: "guildID", + permissions: "62221393", // your permissions + authorize: true + }) */ async authorizeURL(url, options = {}) { const reg = /(api\/)*oauth2\/authorize/gim; @@ -893,9 +899,6 @@ class Client extends BaseClient { */ _validateOptions(options = this.options) { const captchaService = ['2captcha']; - if (options && options.captchaService) { - options.captchaService = undefined; - } if (typeof options.intents === 'undefined') { throw new TypeError('CLIENT_MISSING_INTENTS'); } else { diff --git a/src/errors/Messages.js b/src/errors/Messages.js index 3e5972d..1efc427 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -207,6 +207,7 @@ const Messages = { NITRO_REQUIRED: 'This feature is only available for Nitro users.', NITRO_BOOST_REQUIRED: feature => `This feature (${feature}) is only available for Nitro Boost users.`, ONLY_ME: 'This feature is only available for self.', + MISSING_CAPTCHA_SERVICE: 'This feature is only available for enabled captcha handler.', GUILD_FORUM_MESSAGE_REQUIRED: 'You must provide a message to create a guild forum thread', }; diff --git a/src/rest/APIRequest.js b/src/rest/APIRequest.js index 043e0d3..4d1c645 100644 --- a/src/rest/APIRequest.js +++ b/src/rest/APIRequest.js @@ -46,12 +46,17 @@ class APIRequest { : `${this.client.options.http.api}/v${this.client.options.http.version}`; const url = API + this.path; + const chromeVersion = this.client.options.ws.properties.browser_version.split('.')[0]; + let headers = { ...this.client.options.http.headers, Accept: '*/*', 'Accept-Language': 'en-US,en;q=0.9', 'Cache-Control': 'no-cache', Pragma: 'no-cache', + 'Sec-Ch-Ua': `"Google Chrome";v="${chromeVersion}", "Chromium";v="${chromeVersion}", "Not=A?Brand";v="24"`, + 'Sec-Ch-Ua-Mobile': '?0', + 'Sec-Ch-Ua-Platform': '"Windows"', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-origin', @@ -101,8 +106,8 @@ class APIRequest { headers = Object.assign(headers, body.getHeaders()); } - if (headers['Content-Type'] === 'application/json' && captchaKey && typeof captchaKey == 'string' && body) { - body = JSON.parse(body); + if (headers['Content-Type'] === 'application/json' && captchaKey && typeof captchaKey == 'string') { + body = JSON.parse(body || '{}'); body.captcha_key = captchaKey; body = JSON.stringify(body); } diff --git a/src/rest/RequestHandler.js b/src/rest/RequestHandler.js index fcec6ad..2c559fb 100644 --- a/src/rest/RequestHandler.js +++ b/src/rest/RequestHandler.js @@ -10,6 +10,15 @@ const { Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING, API_RESPONSE, API_REQUEST }, } = require('../util/Constants'); +const captchaMessage = [ + 'incorrect-captcha', + 'response-already-used', + 'captcha-required', + 'invalid-input-response', + 'invalid-response', + 'You need to update your app', +]; + function parseResponse(res) { if (res.headers.get('content-type').startsWith('application/json')) return res.json(); return res.arrayBuffer(); // Cre: TheDevYellowy @@ -343,7 +352,12 @@ class RequestHandler { let data; try { data = await parseResponse(res); - if (data?.captcha_service && this.manager.client.options.captchaService) { + if ( + data?.captcha_service && + this.manager.client.options.captchaService && + request.retries < 4 && + captchaMessage.includes(data.captcha_key[0]) + ) { // Retry the request after a captcha is solved this.manager.client.emit( DEBUG, @@ -362,6 +376,7 @@ class RequestHandler { Route : ${request.route} Key : ${captcha}`, ); + request.retries++; return this.execute(request, captcha); } } catch (err) { diff --git a/src/structures/Guild.js b/src/structures/Guild.js index 4ba7d17..82cc4da 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -10,7 +10,6 @@ const Integration = require('./Integration'); const Webhook = require('./Webhook'); const WelcomeScreen = require('./WelcomeScreen'); const { Error } = require('../errors'); -// Disable: const GuildApplicationCommandManager = require('../managers/GuildApplicationCommandManager'); const GuildBanManager = require('../managers/GuildBanManager'); const GuildChannelManager = require('../managers/GuildChannelManager'); const GuildEmojiManager = require('../managers/GuildEmojiManager'); @@ -33,6 +32,7 @@ const { PremiumTiers, } = require('../util/Constants'); const DataResolver = require('../util/DataResolver'); +const Permissions = require('../util/Permissions'); const SystemChannelFlags = require('../util/SystemChannelFlags'); const Util = require('../util/Util'); @@ -1494,8 +1494,39 @@ class Guild extends AnonymousGuild { }); } - addBot() { - console.log('Test only (Addbot)'); + /** + * Add Bot to the guild + * @param {UserResolvable} bot Bot user / BotId / ApplicationId + * @param {?PermissionsResolvable} permissions Permissions + * @returns {Promise} + */ + addBot(bot, permissions) { + if (!this.me.permissions.has('MANAGE_WEBHOOKS')) { + throw new Error('MISSING_PERMISSIONS', 'MANAGE_WEBHOOKS'); + } + if (!this.me.permissions.has('MANAGE_GUILD')) { + throw new Error('MISSING_PERMISSIONS', 'MANAGE_GUILD'); + } + if (!this.client.options.captchaService) throw new Error('MISSING_CAPTCHA_SERVICE'); + const botId = this.client.users.resolveId(bot); + const permission = new Permissions(Permissions.resolve(permissions ?? 0n)); + if (!botId) throw new TypeError('INVALID_BOT_ID'); + // Check permission + const selfPerm = this.me.permissions.toArray(); + for (const perm of permission.toArray()) { + if (!selfPerm.includes(perm)) { + throw new Error('MISSING_PERMISSIONS', perm); + } + } + // Add bot + return this.client.authorizeURL( + `https://discord.com/api/oauth2/authorize?client_id=${botId}&permissions=${permission.bitfield}&scope=applications.commands%20bot`, + { + guild_id: this.id, + permissions: `${permission.bitfield}`, + authorize: true, + }, + ); } toJSON() { diff --git a/src/structures/Invite.js b/src/structures/Invite.js index 210cae5..63edd1c 100644 --- a/src/structures/Invite.js +++ b/src/structures/Invite.js @@ -321,14 +321,13 @@ class Invite extends Base { /** * Join this Guild using this invite. * @param {boolean} autoVerify Whether to automatically verify member - * @param {string} [captcha] The captcha key to add * @returns {Promise} * @example * await client.fetchInvite('code').then(async invite => { * await invite.acceptInvite(); * }); */ - async acceptInvite(autoVerify = true, captcha = null) { + async acceptInvite(autoVerify = true) { if (!this.guild) throw new Error('INVITE_NO_GUILD'); const dataHeader = { location: 'Join Guild', @@ -337,11 +336,7 @@ class Invite extends Base { location_channel_type: ChannelTypes[this.channel?.type] ?? 0, }; await this.client.api.invites(this.code).post({ - data: captcha - ? { - captcha_key: captcha, - } - : {}, + data: {}, headers: { 'X-Context-Properties': Buffer.from(JSON.stringify(dataHeader), 'utf8').toString('base64'), }, diff --git a/src/util/Options.js b/src/util/Options.js index f92af78..47dc935 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -188,13 +188,14 @@ class Options extends null { referrer_current: '', referring_domain_current: '', release_channel: 'stable', - client_build_number: 156668, + client_build_number: 156904, client_event_source: null, }, - // ? capabilities: 1021, + // ? capabilities: 2045, version: 9, client_state: { - guild_hashes: {}, + api_code_version: 0, + guild_versions: {}, highest_last_message_id: '0', read_state_version: 0, user_guild_settings_version: -1, diff --git a/typings/index.d.ts b/typings/index.d.ts index 6523d1b..403f91b 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1404,6 +1404,7 @@ export class GuildAuditLogsEntry< public targetType: TTargetType; public toJSON(): unknown; public addIntegration(applicationId: Snowflake): Promise; + public addBot(bot: UserResolvable | Snowflake, permissions?: PermissionResolvable): Promise; } export class GuildBan extends Base {