feat: User Required Action

This commit is contained in:
Elysia 2023-07-27 17:52:12 +07:00
parent 004dbca726
commit eb9d68bcc9
12 changed files with 109 additions and 14 deletions

View File

@ -240,8 +240,6 @@ class Client extends BaseClient {
*/ */
this.password = this.options.password; this.password = this.options.password;
this.session_id = null;
if (this.options.messageSweepInterval > 0) { if (this.options.messageSweepInterval > 0) {
process.emitWarning( process.emitWarning(
'The message sweeping client options are deprecated, use the global sweepers instead.', 'The message sweeping client options are deprecated, use the global sweepers instead.',
@ -260,7 +258,7 @@ class Client extends BaseClient {
* @readonly * @readonly
*/ */
get sessionId() { 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 'X-Context-Properties': 'eyJsb2NhdGlvbiI6Ik1hcmtkb3duIExpbmsifQ==', // Markdown Link
}, },
data: { data: {
session_id: this.session_id, session_id: this.sessionId,
}, },
}); });
} }

View File

@ -4,6 +4,7 @@ let ClientUser;
const { VoiceConnection } = require('@discordjs/voice'); const { VoiceConnection } = require('@discordjs/voice');
const chalk = require('chalk'); const chalk = require('chalk');
const { Events, Opcodes } = require('../../../util/Constants'); const { Events, Opcodes } = require('../../../util/Constants');
const Util = require('../../../util/Util');
const { VoiceConnection: VoiceConnection_patch } = require('../../../util/Voice'); const { VoiceConnection: VoiceConnection_patch } = require('../../../util/Voice');
let firstReady = false; let firstReady = false;
@ -41,6 +42,7 @@ function patchVoice(client) {
} }
module.exports = async (client, { d: data }, shard) => { module.exports = async (client, { d: data }, shard) => {
Util.clientRequiredAction(client, data.required_action);
if (!firstReady) { if (!firstReady) {
if (client.options.checkUpdate) { if (client.options.checkUpdate) {
client.once('update', (currentVersion, newVersion) => { client.once('update', (currentVersion, newVersion) => {
@ -99,7 +101,6 @@ module.exports = async (client, { d: data }, shard) => {
firstReady = true; firstReady = true;
} }
client.session_id = data.session_id;
if (client.user) { if (client.user) {
client.user._patch(data.user); client.user._patch(data.user);
} else { } else {

View File

@ -0,0 +1,5 @@
'use strict';
const Util = require('../../../util/Util');
module.exports = (client, { d: data }) => Util.clientRequiredAction(client, data.required_action);

View File

@ -61,6 +61,7 @@ const handlers = Object.fromEntries([
['USER_GUILD_SETTINGS_UPDATE', require('./USER_GUILD_SETTINGS_UPDATE')], ['USER_GUILD_SETTINGS_UPDATE', require('./USER_GUILD_SETTINGS_UPDATE')],
// USER_SETTINGS_PROTO_UPDATE // opcode 0 // USER_SETTINGS_PROTO_UPDATE // opcode 0
['USER_NOTE_UPDATE', require('./USER_NOTE_UPDATE')], ['USER_NOTE_UPDATE', require('./USER_NOTE_UPDATE')],
['USER_REQUIRED_ACTION_UPDATE', require('./USER_REQUIRED_ACTION_UPDATE')],
['USER_UPDATE', require('./USER_UPDATE')], ['USER_UPDATE', require('./USER_UPDATE')],
['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')], ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')],
['TYPING_START', require('./TYPING_START')], ['TYPING_START', require('./TYPING_START')],

View File

@ -824,7 +824,7 @@ class ApplicationCommand extends Base {
application_id: this.applicationId, application_id: this.applicationId,
guild_id: message.guildId, guild_id: message.guildId,
channel_id: message.channelId, channel_id: message.channelId,
session_id: this.client.session_id, session_id: this.client.sessionId,
data: { data: {
version: this.version, version: this.version,
id: this.id, id: this.id,
@ -962,7 +962,7 @@ class ApplicationCommand extends Base {
application_id: this.applicationId, application_id: this.applicationId,
guild_id: message.guildId, guild_id: message.guildId,
channel_id: message.channelId, channel_id: message.channelId,
session_id: this.client.session_id, session_id: this.client.sessionId,
data: { data: {
version: this.version, version: this.version,
id: this.id, id: this.id,

View File

@ -338,7 +338,7 @@ class Invite extends Base {
}; };
await this.client.api.invites(this.code).post({ await this.client.api.invites(this.code).post({
data: { data: {
session_id: this.client.session_id, session_id: this.client.sessionId,
}, },
headers: { headers: {
'X-Context-Properties': Buffer.from(JSON.stringify(dataHeader), 'utf8').toString('base64'), 'X-Context-Properties': Buffer.from(JSON.stringify(dataHeader), 'utf8').toString('base64'),

View File

@ -181,7 +181,7 @@ class MessageButton extends BaseMessageComponent {
channel_id: message.channel.id, channel_id: message.channel.id,
message_id: message.id, message_id: message.id,
application_id: message.applicationId ?? message.author.id, application_id: message.applicationId ?? message.author.id,
session_id: message.client.session_id, session_id: message.client.sessionId,
message_flags: message.flags.bitfield, message_flags: message.flags.bitfield,
data: { data: {
component_type: MessageComponentTypes.BUTTON, component_type: MessageComponentTypes.BUTTON,

View File

@ -247,7 +247,7 @@ class MessagePayload {
this.options.activity.type this.options.activity.type
) { ) {
const type = ActivityFlags.resolve(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; const partyId = this.options.activity.partyId;
activity = { activity = {
type, type,

View File

@ -337,7 +337,7 @@ class MessageSelectMenu extends BaseMessageComponent {
channel_id: message.channel.id, channel_id: message.channel.id,
message_id: message.id, message_id: message.id,
application_id: message.applicationId ?? message.author.id, application_id: message.applicationId ?? message.author.id,
session_id: message.client.session_id, session_id: message.client.sessionId,
message_flags: message.flags.bitfield, message_flags: message.flags.bitfield,
data: { data: {
component_type: MessageComponentTypes[this.type], component_type: MessageComponentTypes[this.type],

View File

@ -234,7 +234,7 @@ class Modal {
channel_id: channel, channel_id: channel,
data: dataFinal, data: dataFinal,
nonce, nonce,
session_id: this.client.session_id, session_id: this.client.sessionId,
}; };
await this.client.api.interactions.post({ await this.client.api.interactions.post({
data: postData, data: postData,

View File

@ -195,7 +195,7 @@ class Options extends null {
proxy: '', proxy: '',
ws: { ws: {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
// capabilities: 16381, capabilities: 0, // https://discord-userdoccers.vercel.app/topics/gateway#gateway-capabilities
properties: { properties: {
os: 'Windows', os: 'Windows',
browser: 'Discord Client', browser: 'Discord Client',
@ -206,7 +206,7 @@ class Options extends null {
system_locale: 'en-US', system_locale: 'en-US',
browser_user_agent: defaultUA, browser_user_agent: defaultUA,
browser_version: '22.3.12', browser_version: '22.3.12',
client_build_number: 213510, client_build_number: 215527,
native_build_number: 34898, native_build_number: 34898,
client_event_source: null, client_event_source: null,
}, },

View File

@ -755,6 +755,96 @@ class Util extends null {
static calculateUserDefaultAvatarIndex(userId) { static calculateUserDefaultAvatarIndex(userId) {
return Number(BigInt(userId) >> 22n) % 6; 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; module.exports = Util;