diff --git a/src/client/Client.js b/src/client/Client.js index feafc23..4619955 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -240,8 +240,6 @@ class Client extends BaseClient { */ this.password = this.options.password; - this.session_id = null; - if (this.options.messageSweepInterval > 0) { process.emitWarning( 'The message sweeping client options are deprecated, use the global sweepers instead.', @@ -260,7 +258,7 @@ class Client extends BaseClient { * @readonly */ get sessionId() { - return this.session_id; + return this.ws.shards.first()?.sessionId; } /** @@ -603,7 +601,7 @@ class Client extends BaseClient { 'X-Context-Properties': 'eyJsb2NhdGlvbiI6Ik1hcmtkb3duIExpbmsifQ==', // Markdown Link }, data: { - session_id: this.session_id, + session_id: this.sessionId, }, }); } diff --git a/src/client/websocket/handlers/READY.js b/src/client/websocket/handlers/READY.js index aa41413..6233b09 100644 --- a/src/client/websocket/handlers/READY.js +++ b/src/client/websocket/handlers/READY.js @@ -4,6 +4,7 @@ let ClientUser; const { VoiceConnection } = require('@discordjs/voice'); const chalk = require('chalk'); const { Events, Opcodes } = require('../../../util/Constants'); +const Util = require('../../../util/Util'); const { VoiceConnection: VoiceConnection_patch } = require('../../../util/Voice'); let firstReady = false; @@ -41,6 +42,7 @@ function patchVoice(client) { } module.exports = async (client, { d: data }, shard) => { + Util.clientRequiredAction(client, data.required_action); if (!firstReady) { if (client.options.checkUpdate) { client.once('update', (currentVersion, newVersion) => { @@ -99,7 +101,6 @@ module.exports = async (client, { d: data }, shard) => { firstReady = true; } - client.session_id = data.session_id; if (client.user) { client.user._patch(data.user); } else { diff --git a/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js b/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js new file mode 100644 index 00000000..ed94726 --- /dev/null +++ b/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js @@ -0,0 +1,5 @@ +'use strict'; + +const Util = require('../../../util/Util'); + +module.exports = (client, { d: data }) => Util.clientRequiredAction(client, data.required_action); diff --git a/src/client/websocket/handlers/index.js b/src/client/websocket/handlers/index.js index 0c44808..3b046e8 100644 --- a/src/client/websocket/handlers/index.js +++ b/src/client/websocket/handlers/index.js @@ -61,6 +61,7 @@ const handlers = Object.fromEntries([ ['USER_GUILD_SETTINGS_UPDATE', require('./USER_GUILD_SETTINGS_UPDATE')], // USER_SETTINGS_PROTO_UPDATE // opcode 0 ['USER_NOTE_UPDATE', require('./USER_NOTE_UPDATE')], + ['USER_REQUIRED_ACTION_UPDATE', require('./USER_REQUIRED_ACTION_UPDATE')], ['USER_UPDATE', require('./USER_UPDATE')], ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')], ['TYPING_START', require('./TYPING_START')], diff --git a/src/structures/ApplicationCommand.js b/src/structures/ApplicationCommand.js index a891ebf..7c643bb 100644 --- a/src/structures/ApplicationCommand.js +++ b/src/structures/ApplicationCommand.js @@ -824,7 +824,7 @@ class ApplicationCommand extends Base { application_id: this.applicationId, guild_id: message.guildId, channel_id: message.channelId, - session_id: this.client.session_id, + session_id: this.client.sessionId, data: { version: this.version, id: this.id, @@ -962,7 +962,7 @@ class ApplicationCommand extends Base { application_id: this.applicationId, guild_id: message.guildId, channel_id: message.channelId, - session_id: this.client.session_id, + session_id: this.client.sessionId, data: { version: this.version, id: this.id, diff --git a/src/structures/Invite.js b/src/structures/Invite.js index bbd5978..e26960d 100644 --- a/src/structures/Invite.js +++ b/src/structures/Invite.js @@ -338,7 +338,7 @@ class Invite extends Base { }; await this.client.api.invites(this.code).post({ data: { - session_id: this.client.session_id, + session_id: this.client.sessionId, }, headers: { 'X-Context-Properties': Buffer.from(JSON.stringify(dataHeader), 'utf8').toString('base64'), diff --git a/src/structures/MessageButton.js b/src/structures/MessageButton.js index 5b9455a..c3a0613 100644 --- a/src/structures/MessageButton.js +++ b/src/structures/MessageButton.js @@ -181,7 +181,7 @@ class MessageButton extends BaseMessageComponent { channel_id: message.channel.id, message_id: message.id, application_id: message.applicationId ?? message.author.id, - session_id: message.client.session_id, + session_id: message.client.sessionId, message_flags: message.flags.bitfield, data: { component_type: MessageComponentTypes.BUTTON, diff --git a/src/structures/MessagePayload.js b/src/structures/MessagePayload.js index 91ac8b7..3a42a35 100644 --- a/src/structures/MessagePayload.js +++ b/src/structures/MessagePayload.js @@ -247,7 +247,7 @@ class MessagePayload { this.options.activity.type ) { const type = ActivityFlags.resolve(this.options.activity.type); - const sessionId = this.target.client.session_id; + const sessionId = this.target.client.sessionId; const partyId = this.options.activity.partyId; activity = { type, diff --git a/src/structures/MessageSelectMenu.js b/src/structures/MessageSelectMenu.js index e597688..cfeeb52 100644 --- a/src/structures/MessageSelectMenu.js +++ b/src/structures/MessageSelectMenu.js @@ -337,7 +337,7 @@ class MessageSelectMenu extends BaseMessageComponent { channel_id: message.channel.id, message_id: message.id, application_id: message.applicationId ?? message.author.id, - session_id: message.client.session_id, + session_id: message.client.sessionId, message_flags: message.flags.bitfield, data: { component_type: MessageComponentTypes[this.type], diff --git a/src/structures/Modal.js b/src/structures/Modal.js index dd7812e..6e4aad1 100644 --- a/src/structures/Modal.js +++ b/src/structures/Modal.js @@ -234,7 +234,7 @@ class Modal { channel_id: channel, data: dataFinal, nonce, - session_id: this.client.session_id, + session_id: this.client.sessionId, }; await this.client.api.interactions.post({ data: postData, diff --git a/src/util/Options.js b/src/util/Options.js index e2ecae8..05c8dc7 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -195,7 +195,7 @@ class Options extends null { proxy: '', ws: { // eslint-disable-next-line no-undef - // capabilities: 16381, + capabilities: 0, // https://discord-userdoccers.vercel.app/topics/gateway#gateway-capabilities properties: { os: 'Windows', browser: 'Discord Client', @@ -206,7 +206,7 @@ class Options extends null { system_locale: 'en-US', browser_user_agent: defaultUA, browser_version: '22.3.12', - client_build_number: 213510, + client_build_number: 215527, native_build_number: 34898, client_event_source: null, }, diff --git a/src/util/Util.js b/src/util/Util.js index fa5b88f..b308676 100644 --- a/src/util/Util.js +++ b/src/util/Util.js @@ -755,6 +755,96 @@ class Util extends null { static calculateUserDefaultAvatarIndex(userId) { return Number(BigInt(userId) >> 22n) % 6; } + + static clientRequiredAction(client, code) { + let msg = ''; + let stopClient = false; + switch (code) { + case null: { + msg = 'All required actions have been completed.'; + break; + } + case 'AGREEMENTS': { + msg = 'You need to accept the new Terms of Service and Privacy Policy.'; + // https://discord.com/api/v9/users/@me/agreements + client.api + .users('@me') + .agreements.patch({ + data: { + terms: true, + privacy: true, + }, + }) + .then(() => { + client.emit( + 'debug', + '[USER_REQUIRED_ACTION] Successfully accepted the new Terms of Service and Privacy Policy.', + ); + }) + .catch(e => { + client.emit( + 'debug', + `[USER_REQUIRED_ACTION] Failed to accept the new Terms of Service and Privacy Policy: ${e}`, + ); + }); + break; + } + case 'REQUIRE_CAPTCHA': { + msg = 'You need to complete a captcha.'; + stopClient = true; + break; + } + case 'REQUIRE_VERIFIED_EMAIL': { + msg = 'You need to verify your email.'; + stopClient = true; + break; + } + case 'REQUIRE_REVERIFIED_EMAIL': { + msg = 'You need to reverify your email.'; + stopClient = true; + break; + } + case 'REQUIRE_VERIFIED_PHONE': { + msg = 'You need to verify your phone number.'; + stopClient = true; + break; + } + case 'REQUIRE_REVERIFIED_PHONE': { + msg = 'You need to reverify your phone number.'; + stopClient = true; + break; + } + case 'REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE': { + msg = 'You need to verify your email or verify your phone number.'; + stopClient = true; // Maybe not + break; + } + case 'REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE': { + msg = 'You need to reverify your email or verify your phone number.'; + stopClient = true; + break; + } + case 'REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE': { + msg = 'You need to verify your email or reverify your phone number.'; + stopClient = true; + break; + } + case 'REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE': { + msg = 'You need to reverify your email or reverify your phone number.'; + stopClient = true; + break; + } + default: { + msg = `Unknown required action: ${code}`; + break; + } + } + if (stopClient) { + client.emit('error', new Error(`[USER_REQUIRED_ACTION] ${msg}`)); + } else { + client.emit('debug', `[USER_REQUIRED_ACTION] ${msg}`); + } + } } module.exports = Util;