djs-selfbot-v13 3.1.6 → 3.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -16
- package/package.json +15 -8
- package/src/client/BaseClient.js +3 -2
- package/src/client/Client.js +539 -187
- package/src/client/actions/Action.js +13 -18
- package/src/client/actions/ActionsManager.js +1 -7
- package/src/client/actions/AutoModerationActionExecution.js +0 -1
- package/src/client/actions/AutoModerationRuleCreate.js +0 -1
- package/src/client/actions/AutoModerationRuleDelete.js +0 -1
- package/src/client/actions/AutoModerationRuleUpdate.js +0 -1
- package/src/client/actions/InteractionCreate.js +115 -0
- package/src/client/actions/MessageCreate.js +4 -0
- package/src/client/actions/PresenceUpdate.js +16 -17
- package/src/client/websocket/WebSocketManager.js +31 -11
- package/src/client/websocket/WebSocketShard.js +38 -39
- package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +23 -0
- package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
- package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
- package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +13 -16
- package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
- package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +11 -0
- package/src/client/websocket/handlers/GUILD_CREATE.js +0 -7
- package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +55 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
- package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
- package/src/client/websocket/handlers/INTERACTION_CREATE.js +16 -0
- package/src/client/websocket/handlers/INTERACTION_FAILURE.js +18 -0
- package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +0 -1
- package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +30 -0
- package/src/client/websocket/handlers/MESSAGE_ACK.js +16 -0
- package/src/client/websocket/handlers/READY.js +137 -47
- package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +5 -7
- package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +4 -6
- package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +9 -32
- package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
- package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +8 -2
- package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
- package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +5 -1
- package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
- package/src/client/websocket/handlers/index.js +20 -15
- package/src/errors/Messages.js +69 -24
- package/src/index.js +43 -12
- package/src/managers/ApplicationCommandManager.js +12 -9
- package/src/managers/ApplicationCommandPermissionsManager.js +11 -3
- package/src/managers/ChannelManager.js +4 -2
- package/src/managers/ClientUserSettingManager.js +279 -161
- package/src/managers/DeveloperPortalManager.js +104 -0
- package/src/managers/GuildApplicationCommandManager.js +28 -0
- package/src/managers/GuildBanManager.js +1 -1
- package/src/managers/GuildChannelManager.js +0 -2
- package/src/managers/GuildFolderManager.js +24 -0
- package/src/managers/GuildForumThreadManager.js +28 -22
- package/src/managers/GuildMemberManager.js +216 -40
- package/src/managers/GuildSettingManager.js +15 -22
- package/src/managers/MessageManager.js +44 -42
- package/src/managers/PermissionOverwriteManager.js +1 -1
- package/src/managers/ReactionUserManager.js +5 -5
- package/src/managers/RelationshipManager.js +74 -81
- package/src/managers/SessionManager.js +57 -0
- package/src/managers/ThreadManager.js +45 -12
- package/src/managers/ThreadMemberManager.js +1 -1
- package/src/managers/UserManager.js +10 -6
- package/src/rest/APIRequest.js +20 -42
- package/src/rest/CaptchaSolver.js +132 -0
- package/src/rest/DiscordAPIError.js +16 -17
- package/src/rest/RESTManager.js +21 -1
- package/src/rest/RequestHandler.js +21 -35
- package/src/structures/ApplicationCommand.js +456 -19
- package/src/structures/ApplicationRoleConnectionMetadata.js +0 -3
- package/src/structures/AutoModerationRule.js +5 -5
- package/src/structures/AutocompleteInteraction.js +0 -1
- package/src/structures/BaseGuildTextChannel.js +12 -10
- package/src/structures/BaseGuildVoiceChannel.js +18 -16
- package/src/structures/{CallState.js → Call.js} +12 -17
- package/src/structures/CategoryChannel.js +0 -2
- package/src/structures/Channel.js +3 -2
- package/src/structures/ClientApplication.js +204 -0
- package/src/structures/ClientPresence.js +8 -12
- package/src/structures/ClientUser.js +336 -117
- package/src/structures/ContextMenuInteraction.js +1 -1
- package/src/structures/DMChannel.js +92 -29
- package/src/structures/DeveloperPortalApplication.js +520 -0
- package/src/structures/ForumChannel.js +10 -0
- package/src/structures/Guild.js +271 -135
- package/src/structures/GuildAuditLogs.js +5 -0
- package/src/structures/GuildChannel.js +2 -16
- package/src/structures/GuildFolder.js +75 -0
- package/src/structures/GuildMember.js +145 -27
- package/src/structures/Interaction.js +62 -1
- package/src/structures/InteractionResponse.js +114 -0
- package/src/structures/Invite.js +52 -35
- package/src/structures/Message.js +202 -222
- package/src/structures/MessageAttachment.js +0 -11
- package/src/structures/MessageButton.js +67 -1
- package/src/structures/MessageEmbed.js +1 -1
- package/src/structures/MessageMentions.js +2 -3
- package/src/structures/MessagePayload.js +46 -4
- package/src/structures/MessageReaction.js +1 -1
- package/src/structures/MessageSelectMenu.js +252 -1
- package/src/structures/Modal.js +180 -75
- package/src/structures/PartialGroupDMChannel.js +433 -0
- package/src/structures/Presence.js +2 -2
- package/src/structures/RichPresence.js +34 -14
- package/src/structures/Role.js +2 -18
- package/src/structures/SelectMenuInteraction.js +151 -2
- package/src/structures/Session.js +81 -0
- package/src/structures/Team.js +49 -0
- package/src/structures/TextInputComponent.js +70 -0
- package/src/structures/ThreadChannel.js +19 -0
- package/src/structures/User.js +345 -117
- package/src/structures/UserContextMenuInteraction.js +2 -2
- package/src/structures/VoiceState.js +39 -74
- package/src/structures/WebEmbed.js +52 -38
- package/src/structures/Webhook.js +11 -17
- package/src/structures/interfaces/Application.js +23 -146
- package/src/structures/interfaces/TextBasedChannel.js +256 -411
- package/src/util/ApplicationFlags.js +1 -1
- package/src/util/Constants.js +284 -106
- package/src/util/Formatters.js +2 -16
- package/src/util/LimitedCollection.js +1 -1
- package/src/util/Options.js +68 -48
- package/src/util/Permissions.js +0 -5
- package/src/util/PurchasedFlags.js +0 -2
- package/src/util/RemoteAuth.js +356 -221
- package/src/util/Sweepers.js +1 -1
- package/src/util/Util.js +36 -76
- package/src/util/Voice.js +1456 -0
- package/src/util/arRPC/index.js +229 -0
- package/src/util/arRPC/process/detectable.json +1 -0
- package/src/util/arRPC/process/index.js +102 -0
- package/src/util/arRPC/process/native/index.js +5 -0
- package/src/util/arRPC/process/native/linux.js +37 -0
- package/src/util/arRPC/process/native/win32.js +25 -0
- package/src/util/arRPC/transports/ipc.js +281 -0
- package/src/util/arRPC/transports/websocket.js +128 -0
- package/typings/enums.d.ts +73 -18
- package/typings/index.d.ts +1249 -897
- package/typings/rawDataTypes.d.ts +9 -68
- package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +0 -78
- package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +0 -12
- package/src/managers/UserNoteManager.js +0 -53
- package/src/structures/GroupDMChannel.js +0 -387
- package/src/util/AttachmentFlags.js +0 -38
- package/src/util/InviteFlags.js +0 -29
- package/src/util/RoleFlags.js +0 -37
package/src/util/RemoteAuth.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const crypto = require('node:crypto');
|
|
2
|
+
const { Buffer } = require('buffer');
|
|
3
|
+
const crypto = require('crypto');
|
|
5
4
|
const EventEmitter = require('node:events');
|
|
6
|
-
const { StringDecoder } = require('node:string_decoder');
|
|
7
5
|
const { setTimeout } = require('node:timers');
|
|
6
|
+
const { StringDecoder } = require('string_decoder');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
8
|
const fetch = require('node-fetch');
|
|
9
|
+
const { encode: urlsafe_b64encode } = require('safe-base64');
|
|
9
10
|
const WebSocket = require('ws');
|
|
10
|
-
const {
|
|
11
|
+
const { defaultUA } = require('./Constants');
|
|
11
12
|
const Options = require('./Options');
|
|
12
13
|
|
|
13
14
|
const defaultClientOptions = Options.createDefault();
|
|
@@ -21,9 +22,9 @@ const receiveEvent = {
|
|
|
21
22
|
NONCE_PROOF: 'nonce_proof',
|
|
22
23
|
PENDING_REMOTE_INIT: 'pending_remote_init',
|
|
23
24
|
HEARTBEAT_ACK: 'heartbeat_ack',
|
|
24
|
-
|
|
25
|
+
PENDING_LOGIN: 'pending_ticket',
|
|
25
26
|
CANCEL: 'cancel',
|
|
26
|
-
|
|
27
|
+
SUCCESS: 'pending_login',
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
const sendEvent = {
|
|
@@ -36,167 +37,266 @@ const Event = {
|
|
|
36
37
|
READY: 'ready',
|
|
37
38
|
ERROR: 'error',
|
|
38
39
|
CANCEL: 'cancel',
|
|
39
|
-
|
|
40
|
+
WAIT: 'pending',
|
|
41
|
+
SUCCESS: 'success',
|
|
40
42
|
FINISH: 'finish',
|
|
41
43
|
CLOSED: 'closed',
|
|
42
|
-
DEBUG: 'debug',
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
|
-
*
|
|
47
|
+
* @typedef {Object} DiscordAuthWebsocketOptions
|
|
48
|
+
* @property {?boolean} [debug=false] Log debug info
|
|
49
|
+
* @property {?boolean} [hiddenLog=false] Hide log ?
|
|
50
|
+
* @property {?boolean} [autoLogin=false] Automatically login (DiscordJS.Client Login) ?
|
|
51
|
+
* @property {?boolean} [failIfError=true] Throw error ?
|
|
52
|
+
* @property {?boolean} [generateQR=true] Create QR Code ?
|
|
53
|
+
* @property {?number} [apiVersion=9] API Version
|
|
54
|
+
* @property {?string} [userAgent] User Agent
|
|
55
|
+
* @property {?Object.<string,string>} [wsProperties] Web Socket Properties
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Discord Auth QR (Discord.RemoteAuth will be removed in the future, v13.9.0 release)
|
|
47
60
|
* @extends {EventEmitter}
|
|
48
61
|
* @abstract
|
|
49
62
|
*/
|
|
50
63
|
class DiscordAuthWebsocket extends EventEmitter {
|
|
51
|
-
#ws = null;
|
|
52
|
-
#heartbeatInterval = null;
|
|
53
|
-
#expire = null;
|
|
54
|
-
#publicKey = null;
|
|
55
|
-
#privateKey = null;
|
|
56
|
-
#ticket = null;
|
|
57
|
-
#fingerprint = '';
|
|
58
|
-
#userDecryptString = '';
|
|
59
|
-
|
|
60
64
|
/**
|
|
61
65
|
* Creates a new DiscordAuthWebsocket instance.
|
|
66
|
+
* @param {?DiscordAuthWebsocketOptions} options Options
|
|
62
67
|
*/
|
|
63
|
-
constructor() {
|
|
68
|
+
constructor(options) {
|
|
64
69
|
super();
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
/**
|
|
71
|
+
* WebSocket
|
|
72
|
+
* @type {?WebSocket}
|
|
73
|
+
*/
|
|
74
|
+
this.ws = null;
|
|
75
|
+
/**
|
|
76
|
+
* Heartbeat Interval
|
|
77
|
+
* @type {?number}
|
|
78
|
+
*/
|
|
79
|
+
this.heartbeatInterval = NaN;
|
|
80
|
+
this._expire = NaN;
|
|
81
|
+
this.key = null;
|
|
82
|
+
/**
|
|
83
|
+
* User (Scan QR Code)
|
|
84
|
+
* @type {?Object}
|
|
85
|
+
*/
|
|
86
|
+
this.user = null;
|
|
87
|
+
/**
|
|
88
|
+
* Temporary Token (Scan QR Code)
|
|
89
|
+
* @type {?string}
|
|
90
|
+
*/
|
|
91
|
+
this.token = undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Real Token (Login)
|
|
94
|
+
* @type {?string}
|
|
95
|
+
*/
|
|
96
|
+
this.realToken = undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Fingerprint (QR Code)
|
|
99
|
+
* @type {?string}
|
|
100
|
+
*/
|
|
101
|
+
this.fingerprint = null;
|
|
67
102
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Captcha Handler
|
|
105
|
+
* @type {Function}
|
|
106
|
+
* @param {Captcha} data hcaptcha data
|
|
107
|
+
* @returns {Promise<string>} Captcha token
|
|
108
|
+
*/
|
|
109
|
+
// eslint-disable-next-line no-unused-vars
|
|
110
|
+
this.captchaSolver = data =>
|
|
111
|
+
new Promise((resolve, reject) => {
|
|
112
|
+
reject(
|
|
113
|
+
new Error(`
|
|
114
|
+
Captcha Handler not found - Please set captchaSolver option
|
|
115
|
+
Example captchaSolver function:
|
|
116
|
+
|
|
117
|
+
new DiscordAuthWebsocket({
|
|
118
|
+
captchaSolver: async (data) => {
|
|
119
|
+
const token = await hcaptchaSolver(data.captcha_sitekey, 'discord.com');
|
|
120
|
+
return token;
|
|
73
121
|
}
|
|
122
|
+
});
|
|
74
123
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
get exprire() {
|
|
79
|
-
return this.#expire;
|
|
80
|
-
}
|
|
124
|
+
`),
|
|
125
|
+
);
|
|
126
|
+
});
|
|
81
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Captcha Cache
|
|
130
|
+
* @type {?Captcha}
|
|
131
|
+
*/
|
|
132
|
+
this.captchaCache = null;
|
|
133
|
+
|
|
134
|
+
this._validateOptions(options);
|
|
135
|
+
|
|
136
|
+
this.callFindRealTokenCount = 0;
|
|
137
|
+
}
|
|
82
138
|
/**
|
|
83
|
-
*
|
|
139
|
+
* Get expire time
|
|
140
|
+
* @type {string} Expire time
|
|
141
|
+
* @readonly
|
|
84
142
|
*/
|
|
85
|
-
get
|
|
86
|
-
return
|
|
143
|
+
get exprireTime() {
|
|
144
|
+
return this._expire.toLocaleString('en-US');
|
|
87
145
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
146
|
+
_validateOptions(options = {}) {
|
|
147
|
+
/**
|
|
148
|
+
* Options
|
|
149
|
+
* @type {?DiscordAuthWebsocketOptions}
|
|
150
|
+
*/
|
|
151
|
+
this.options = {
|
|
152
|
+
debug: false,
|
|
153
|
+
hiddenLog: false,
|
|
154
|
+
autoLogin: false,
|
|
155
|
+
failIfError: true,
|
|
156
|
+
generateQR: true,
|
|
157
|
+
apiVersion: 9,
|
|
158
|
+
userAgent: defaultUA,
|
|
159
|
+
wsProperties: defaultClientOptions.ws.properties,
|
|
160
|
+
captchaSolver: () => new Error('Captcha Handler not found. Please set captchaSolver option.'),
|
|
161
|
+
};
|
|
162
|
+
if (typeof options == 'object') {
|
|
163
|
+
if (typeof options.debug == 'boolean') this.options.debug = options.debug;
|
|
164
|
+
if (typeof options.hiddenLog == 'boolean') this.options.hiddenLog = options.hiddenLog;
|
|
165
|
+
if (typeof options.autoLogin == 'boolean') this.options.autoLogin = options.autoLogin;
|
|
166
|
+
if (typeof options.failIfError == 'boolean') this.options.failIfError = options.failIfError;
|
|
167
|
+
if (typeof options.generateQR == 'boolean') this.options.generateQR = options.generateQR;
|
|
168
|
+
if (typeof options.apiVersion == 'number') this.options.apiVersion = options.apiVersion;
|
|
169
|
+
if (typeof options.userAgent == 'string') this.options.userAgent = options.userAgent;
|
|
170
|
+
if (typeof options.wsProperties == 'object') this.options.wsProperties = options.wsProperties;
|
|
171
|
+
if (typeof options.captchaSolver == 'function') this.captchaSolver = options.captchaSolver;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
_createWebSocket(url) {
|
|
175
|
+
this.ws = new WebSocket(url, {
|
|
91
176
|
headers: {
|
|
92
177
|
Origin: 'https://discord.com',
|
|
93
|
-
'User-Agent':
|
|
178
|
+
'User-Agent': this.options.userAgent,
|
|
94
179
|
},
|
|
95
180
|
});
|
|
96
|
-
this
|
|
181
|
+
this._handleWebSocket();
|
|
97
182
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
* @param {Error} error Error
|
|
105
|
-
*/
|
|
106
|
-
this.emit(Event.ERROR, error);
|
|
183
|
+
_handleWebSocket() {
|
|
184
|
+
this.ws.on('error', error => {
|
|
185
|
+
this._logger('error', error);
|
|
186
|
+
});
|
|
187
|
+
this.ws.on('open', () => {
|
|
188
|
+
this._logger('debug', 'Client Connected');
|
|
107
189
|
});
|
|
108
|
-
this
|
|
109
|
-
|
|
110
|
-
* Debug Event
|
|
111
|
-
* @event DiscordAuthWebsocket#debug
|
|
112
|
-
* @param {string} msg Debug msg
|
|
113
|
-
*/
|
|
114
|
-
this.emit(Event.DEBUG, '[WS] Client Connected');
|
|
190
|
+
this.ws.on('close', () => {
|
|
191
|
+
this._logger('debug', 'Connection closed.');
|
|
115
192
|
});
|
|
116
|
-
this
|
|
117
|
-
this.
|
|
193
|
+
this.ws.on('message', message => {
|
|
194
|
+
this._handleMessage(JSON.parse(message));
|
|
118
195
|
});
|
|
119
|
-
this.#ws.on('message', this.#handleMessage.bind(this));
|
|
120
196
|
}
|
|
121
|
-
|
|
122
|
-
#handleMessage(message) {
|
|
123
|
-
message = JSON.parse(message);
|
|
197
|
+
_handleMessage(message) {
|
|
124
198
|
switch (message.op) {
|
|
125
199
|
case receiveEvent.HELLO: {
|
|
126
|
-
this
|
|
200
|
+
this._ready(message);
|
|
127
201
|
break;
|
|
128
202
|
}
|
|
129
|
-
|
|
130
203
|
case receiveEvent.NONCE_PROOF: {
|
|
131
|
-
this
|
|
204
|
+
this._receiveNonceProof(message);
|
|
132
205
|
break;
|
|
133
206
|
}
|
|
134
|
-
|
|
135
207
|
case receiveEvent.PENDING_REMOTE_INIT: {
|
|
136
|
-
this
|
|
137
|
-
/**
|
|
138
|
-
* Ready Event
|
|
139
|
-
* @event DiscordAuthWebsocket#ready
|
|
140
|
-
* @param {DiscordAuthWebsocket} client WS
|
|
141
|
-
*/
|
|
142
|
-
this.emit(Event.READY, this);
|
|
208
|
+
this._pendingRemoteInit(message);
|
|
143
209
|
break;
|
|
144
210
|
}
|
|
145
|
-
|
|
146
211
|
case receiveEvent.HEARTBEAT_ACK: {
|
|
147
|
-
this.
|
|
148
|
-
this
|
|
212
|
+
this._logger('debug', 'Heartbeat acknowledged.');
|
|
213
|
+
this._heartbeatAck();
|
|
149
214
|
break;
|
|
150
215
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
this.#pendingLogin(message);
|
|
216
|
+
case receiveEvent.PENDING_LOGIN: {
|
|
217
|
+
this._pendingLogin(message);
|
|
154
218
|
break;
|
|
155
219
|
}
|
|
156
|
-
|
|
157
220
|
case receiveEvent.CANCEL: {
|
|
221
|
+
this._logger('debug', 'Cancel login.');
|
|
158
222
|
/**
|
|
159
|
-
*
|
|
223
|
+
* Emitted whenever a user cancels the login process.
|
|
160
224
|
* @event DiscordAuthWebsocket#cancel
|
|
161
|
-
* @param {
|
|
225
|
+
* @param {object} user User (Raw)
|
|
162
226
|
*/
|
|
163
|
-
this.emit(Event.CANCEL, this);
|
|
227
|
+
this.emit(Event.CANCEL, this.user);
|
|
164
228
|
this.destroy();
|
|
165
229
|
break;
|
|
166
230
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
231
|
+
case receiveEvent.SUCCESS: {
|
|
232
|
+
this._logger('debug', 'Receive Token - Login Success.', message.ticket);
|
|
233
|
+
/**
|
|
234
|
+
* Emitted whenever a token is created. (Fake token)
|
|
235
|
+
* @event DiscordAuthWebsocket#success
|
|
236
|
+
* @param {object} user Discord User
|
|
237
|
+
* @param {string} token Discord Token (Fake)
|
|
238
|
+
*/
|
|
239
|
+
this.emit(Event.SUCCESS, this.user, message.ticket);
|
|
240
|
+
this.token = message.ticket;
|
|
241
|
+
this._findRealToken();
|
|
242
|
+
this._logger('default', 'Get token success.');
|
|
171
243
|
break;
|
|
172
244
|
}
|
|
245
|
+
default: {
|
|
246
|
+
this._logger('debug', `Unknown op: ${message.op}`, message);
|
|
247
|
+
}
|
|
173
248
|
}
|
|
174
249
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
250
|
+
_logger(type = 'default', ...message) {
|
|
251
|
+
if (this.options.hiddenLog) return;
|
|
252
|
+
switch (type.toLowerCase()) {
|
|
253
|
+
case 'error': {
|
|
254
|
+
// eslint-disable-next-line no-unused-expressions
|
|
255
|
+
this.options.failIfError
|
|
256
|
+
? this._throwError(new Error(message[0]))
|
|
257
|
+
: console.error(chalk.red(`[DiscordRemoteAuth] ERROR`), ...message);
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
case 'default': {
|
|
261
|
+
console.log(chalk.green(`[DiscordRemoteAuth]`), ...message);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
case 'debug': {
|
|
265
|
+
if (this.options.debug) console.log(chalk.yellow(`[DiscordRemoteAuth] DEBUG`), ...message);
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
_throwError(error) {
|
|
271
|
+
console.log(chalk.red(`[DiscordRemoteAuth] ERROR`), error);
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
_send(op, data) {
|
|
275
|
+
if (!this.ws) this._throwError(new Error('WebSocket is not connected.'));
|
|
178
276
|
let payload = { op: op };
|
|
179
277
|
if (data !== null) payload = { ...payload, ...data };
|
|
180
|
-
this
|
|
278
|
+
this._logger('debug', `Send Data:`, payload);
|
|
279
|
+
this.ws.send(JSON.stringify(payload));
|
|
181
280
|
}
|
|
182
|
-
|
|
183
|
-
|
|
281
|
+
_heartbeat() {
|
|
282
|
+
this._send(sendEvent.HEARTBEAT);
|
|
283
|
+
}
|
|
284
|
+
_heartbeatAck() {
|
|
184
285
|
setTimeout(() => {
|
|
185
|
-
this
|
|
186
|
-
}, this
|
|
286
|
+
this._heartbeat();
|
|
287
|
+
}, this.heartbeatInterval).unref();
|
|
187
288
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
this.
|
|
191
|
-
this
|
|
192
|
-
this
|
|
193
|
-
this
|
|
194
|
-
this
|
|
195
|
-
this.#init();
|
|
289
|
+
_ready(data) {
|
|
290
|
+
this._logger('debug', 'Attempting server handshake...');
|
|
291
|
+
this._expire = new Date(Date.now() + data.timeout_ms);
|
|
292
|
+
this.heartbeatInterval = data.heartbeat_interval;
|
|
293
|
+
this._createKey();
|
|
294
|
+
this._heartbeatAck();
|
|
295
|
+
this._init();
|
|
196
296
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
297
|
+
_createKey() {
|
|
298
|
+
if (this.key) this._throwError(new Error('Key is already created.'));
|
|
299
|
+
this.key = crypto.generateKeyPairSync('rsa', {
|
|
200
300
|
modulusLength: 2048,
|
|
201
301
|
publicKeyEncoding: {
|
|
202
302
|
type: 'spki',
|
|
@@ -207,41 +307,35 @@ class DiscordAuthWebsocket extends EventEmitter {
|
|
|
207
307
|
format: 'pem',
|
|
208
308
|
},
|
|
209
309
|
});
|
|
210
|
-
this.#privateKey = key.privateKey;
|
|
211
|
-
this.#publicKey = key.publicKey;
|
|
212
310
|
}
|
|
213
|
-
|
|
214
|
-
|
|
311
|
+
_createPublicKey() {
|
|
312
|
+
if (!this.key) this._throwError(new Error('Key is not created.'));
|
|
313
|
+
this._logger('debug', 'Generating public key...');
|
|
215
314
|
const decoder = new StringDecoder('utf-8');
|
|
216
|
-
let pub_key = decoder.write(this
|
|
315
|
+
let pub_key = decoder.write(this.key.publicKey);
|
|
217
316
|
pub_key = pub_key.split('\n').slice(1, -2).join('');
|
|
317
|
+
this._logger('debug', 'Public key generated.', pub_key);
|
|
218
318
|
return pub_key;
|
|
219
319
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.#send(sendEvent.INIT, { encoded_public_key: public_key });
|
|
320
|
+
_init() {
|
|
321
|
+
const public_key = this._createPublicKey();
|
|
322
|
+
this._send(sendEvent.INIT, { encoded_public_key: public_key });
|
|
224
323
|
}
|
|
225
|
-
|
|
226
|
-
#receiveNonceProof(data) {
|
|
324
|
+
_receiveNonceProof(data) {
|
|
227
325
|
const nonce = data.encrypted_nonce;
|
|
228
|
-
const decrypted_nonce = this
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
.replace(/\+/g, '-')
|
|
235
|
-
.replace(/\//g, '_')
|
|
236
|
-
.replace(/=+/, '')
|
|
237
|
-
.replace(/\s+$/, '');
|
|
238
|
-
this.#send(sendEvent.NONCE_PROOF, { proof: proof });
|
|
326
|
+
const decrypted_nonce = this._decryptPayload(nonce);
|
|
327
|
+
let proof = crypto.createHash('sha256').update(decrypted_nonce).digest();
|
|
328
|
+
proof = urlsafe_b64encode(proof);
|
|
329
|
+
proof = proof.replace(/\s+$/, '');
|
|
330
|
+
this._send(sendEvent.NONCE_PROOF, { proof: proof });
|
|
331
|
+
this._logger('debug', `Nonce proof decrypted:`, proof);
|
|
239
332
|
}
|
|
240
|
-
|
|
241
|
-
|
|
333
|
+
_decryptPayload(encrypted_payload) {
|
|
334
|
+
if (!this.key) this._throwError(new Error('Key is not created.'));
|
|
242
335
|
const payload = Buffer.from(encrypted_payload, 'base64');
|
|
336
|
+
this._logger('debug', `Encrypted Payload (Buffer):`, payload);
|
|
243
337
|
const decoder = new StringDecoder('utf-8');
|
|
244
|
-
const private_key = decoder.write(this
|
|
338
|
+
const private_key = decoder.write(this.key.privateKey);
|
|
245
339
|
const data = crypto.privateDecrypt(
|
|
246
340
|
{
|
|
247
341
|
key: private_key,
|
|
@@ -250,129 +344,170 @@ class DiscordAuthWebsocket extends EventEmitter {
|
|
|
250
344
|
},
|
|
251
345
|
payload,
|
|
252
346
|
);
|
|
347
|
+
this._logger('debug', `Decrypted Payload:`, data.toString());
|
|
253
348
|
return data;
|
|
254
349
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
this
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* @typedef {Object} UserRaw
|
|
262
|
-
* @property {Snowflake} id
|
|
263
|
-
* @property {string} username
|
|
264
|
-
* @property {number} discriminator
|
|
265
|
-
* @property {string} avatar
|
|
266
|
-
*/
|
|
267
|
-
|
|
350
|
+
_pendingLogin(data) {
|
|
351
|
+
const user_data = this._decryptPayload(data.encrypted_user_payload);
|
|
352
|
+
const user = new User(user_data.toString());
|
|
353
|
+
this.user = user;
|
|
268
354
|
/**
|
|
269
355
|
* Emitted whenever a user is scan QR Code.
|
|
270
356
|
* @event DiscordAuthWebsocket#pending
|
|
271
|
-
* @param {
|
|
357
|
+
* @param {object} user Discord User Raw
|
|
272
358
|
*/
|
|
273
|
-
this.emit(Event.
|
|
359
|
+
this.emit(Event.WAIT, user);
|
|
360
|
+
this._logger('debug', 'Waiting for user to finish login...');
|
|
361
|
+
this.user.prettyPrint(this);
|
|
362
|
+
this._logger('default', 'Please check your phone again to confirm login.');
|
|
274
363
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
364
|
+
_pendingRemoteInit(data) {
|
|
365
|
+
this._logger('debug', `Pending Remote Init:`, data);
|
|
366
|
+
/**
|
|
367
|
+
* Emitted whenever a url is created.
|
|
368
|
+
* @event DiscordAuthWebsocket#ready
|
|
369
|
+
* @param {string} fingerprint Fingerprint
|
|
370
|
+
* @param {string} url DiscordAuthWebsocket
|
|
371
|
+
*/
|
|
372
|
+
this.emit(Event.READY, data.fingerprint, `${baseURL}${data.fingerprint}`);
|
|
373
|
+
this.fingerprint = data.fingerprint;
|
|
374
|
+
if (this.options.generateQR) this.generateQR();
|
|
375
|
+
}
|
|
376
|
+
_awaitLogin(client) {
|
|
377
|
+
this.once(Event.FINISH, (user, token) => {
|
|
378
|
+
this._logger('debug', 'Create login state...', user, token);
|
|
379
|
+
client.login(token);
|
|
281
380
|
});
|
|
282
381
|
}
|
|
283
|
-
|
|
284
382
|
/**
|
|
285
|
-
* Connect
|
|
286
|
-
* @param {Client}
|
|
287
|
-
* @returns {
|
|
383
|
+
* Connect to DiscordAuthWebsocket.
|
|
384
|
+
* @param {?Client} client Using only for auto login.
|
|
385
|
+
* @returns {undefined}
|
|
288
386
|
*/
|
|
289
387
|
connect(client) {
|
|
290
|
-
this
|
|
291
|
-
if (client)
|
|
292
|
-
return this.#awaitLogin(client);
|
|
293
|
-
} else {
|
|
294
|
-
return Promise.resolve();
|
|
295
|
-
}
|
|
388
|
+
this._createWebSocket(wsURL);
|
|
389
|
+
if (client && this.options.autoLogin) this._awaitLogin(client);
|
|
296
390
|
}
|
|
297
|
-
|
|
298
391
|
/**
|
|
299
|
-
*
|
|
300
|
-
* @returns {
|
|
392
|
+
* Disconnect from DiscordAuthWebsocket.
|
|
393
|
+
* @returns {undefined}
|
|
301
394
|
*/
|
|
302
395
|
destroy() {
|
|
303
|
-
if (!this.ws)
|
|
396
|
+
if (!this.ws) this._throwError(new Error('WebSocket is not connected.'));
|
|
304
397
|
this.ws.close();
|
|
305
|
-
this.emit(Event.DEBUG, 'WebSocket closed.');
|
|
306
398
|
/**
|
|
307
399
|
* Emitted whenever a connection is closed.
|
|
308
400
|
* @event DiscordAuthWebsocket#closed
|
|
401
|
+
* @param {boolean} loginState Login state
|
|
309
402
|
*/
|
|
310
|
-
this.emit(Event.CLOSED);
|
|
403
|
+
this.emit(Event.CLOSED, this.token);
|
|
404
|
+
this._logger('debug', 'WebSocket closed.');
|
|
311
405
|
}
|
|
312
|
-
|
|
313
406
|
/**
|
|
314
407
|
* Generate QR code for user to scan (Terminal)
|
|
315
|
-
* @returns {
|
|
408
|
+
* @returns {undefined}
|
|
316
409
|
*/
|
|
317
410
|
generateQR() {
|
|
318
|
-
if (!this
|
|
319
|
-
require('@aikochan2k6/qrcode-terminal').generate(this.
|
|
411
|
+
if (!this.fingerprint) this._throwError(new Error('Fingerprint is not created.'));
|
|
412
|
+
require('@aikochan2k6/qrcode-terminal').generate(`${baseURL}${this.fingerprint}`, {
|
|
320
413
|
small: true,
|
|
321
414
|
});
|
|
415
|
+
this._logger('default', `Please scan the QR code to continue.\nQR Code will expire in ${this.exprireTime}`);
|
|
322
416
|
}
|
|
323
417
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
418
|
+
async _findRealToken(captchaSolveData) {
|
|
419
|
+
this.callFindRealTokenCount++;
|
|
420
|
+
if (!this.token) return this._throwError(new Error('Token is not created.'));
|
|
421
|
+
if (!captchaSolveData && this.captchaCache) return this._throwError(new Error('Captcha is not solved.'));
|
|
422
|
+
if (this.callFindRealTokenCount > 5) {
|
|
423
|
+
return this._throwError(
|
|
424
|
+
new Error(
|
|
425
|
+
`Failed to find real token (${this.callFindRealTokenCount} times) ${this.captchaCache ? '[Captcha]' : ''}`,
|
|
426
|
+
),
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
this._logger('debug', 'Find real token...');
|
|
430
|
+
const res = await (
|
|
431
|
+
await fetch(`https://discord.com/api/v${this.options.apiVersion}/users/@me/remote-auth/login`, {
|
|
432
|
+
method: 'POST',
|
|
433
|
+
headers: {
|
|
434
|
+
Accept: '*/*',
|
|
435
|
+
'Accept-Language': 'en-US',
|
|
436
|
+
'Content-Type': 'application/json',
|
|
437
|
+
'Sec-Fetch-Dest': 'empty',
|
|
438
|
+
'Sec-Fetch-Mode': 'cors',
|
|
439
|
+
'Sec-Fetch-Site': 'same-origin',
|
|
440
|
+
'X-Debug-Options': 'bugReporterEnabled',
|
|
441
|
+
'X-Super-Properties': `${Buffer.from(JSON.stringify(this.options.wsProperties), 'ascii').toString('base64')}`,
|
|
442
|
+
'X-Discord-Locale': 'en-US',
|
|
443
|
+
'User-Agent': this.options.userAgent,
|
|
444
|
+
Referer: 'https://discord.com/channels/@me',
|
|
445
|
+
Connection: 'keep-alive',
|
|
446
|
+
Origin: 'https://discord.com',
|
|
447
|
+
},
|
|
448
|
+
body: JSON.stringify(
|
|
449
|
+
captchaSolveData
|
|
450
|
+
? {
|
|
451
|
+
ticket: this.token,
|
|
452
|
+
captcha_rqtoken: this.captchaCache.captcha_rqtoken,
|
|
453
|
+
captcha_key: captchaSolveData,
|
|
454
|
+
}
|
|
455
|
+
: {
|
|
456
|
+
ticket: this.token,
|
|
457
|
+
},
|
|
458
|
+
),
|
|
360
459
|
})
|
|
361
|
-
|
|
460
|
+
).json();
|
|
461
|
+
if (res?.captcha_key) {
|
|
462
|
+
this.captchaCache = res;
|
|
463
|
+
} else if (!res.encrypted_token) {
|
|
464
|
+
this._throwError(new Error('Request failed. Please try again.', res));
|
|
465
|
+
this.captchaCache = null;
|
|
466
|
+
}
|
|
467
|
+
if (!res && this.captchaCache) {
|
|
468
|
+
this._logger('default', 'Captcha is detected. Please solve the captcha to continue.');
|
|
469
|
+
this._logger('debug', 'Try call captchaSolver()', this.captchaCache);
|
|
470
|
+
const token = await this.options.captchaSolver(this.captchaCache);
|
|
471
|
+
return this._findRealToken(token);
|
|
472
|
+
}
|
|
473
|
+
this.realToken = this._decryptPayload(res.encrypted_token).toString();
|
|
474
|
+
/**
|
|
475
|
+
* Emitted whenever a real token is found.
|
|
476
|
+
* @event DiscordAuthWebsocket#finish
|
|
477
|
+
* @param {object} user User
|
|
478
|
+
* @param {string} token Real token
|
|
479
|
+
*/
|
|
480
|
+
this.emit(Event.FINISH, this.user, this.realToken);
|
|
481
|
+
return this;
|
|
362
482
|
}
|
|
483
|
+
}
|
|
363
484
|
|
|
364
|
-
|
|
485
|
+
class User {
|
|
486
|
+
constructor(payload) {
|
|
365
487
|
const values = payload.split(':');
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
return
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
avatar
|
|
375
|
-
}
|
|
488
|
+
this.id = values[0];
|
|
489
|
+
this.username = values[3];
|
|
490
|
+
this.discriminator = values[1];
|
|
491
|
+
this.avatar = values[2];
|
|
492
|
+
return this;
|
|
493
|
+
}
|
|
494
|
+
get avatarURL() {
|
|
495
|
+
return `https://cdn.discordapp.com/avatars/${this.id}/${this.avatar}.${
|
|
496
|
+
this.avatar.startsWith('a_') ? 'gif' : 'png'
|
|
497
|
+
}`;
|
|
498
|
+
}
|
|
499
|
+
get tag() {
|
|
500
|
+
return `${this.username}#${this.discriminator}`;
|
|
501
|
+
}
|
|
502
|
+
prettyPrint(RemoteAuth) {
|
|
503
|
+
let string = `\n`;
|
|
504
|
+
string += ` ${chalk.bgBlue('User:')} `;
|
|
505
|
+
string += `${this.tag} (${this.id})\n`;
|
|
506
|
+
string += ` ${chalk.bgGreen('Avatar URL:')} `;
|
|
507
|
+
string += chalk.cyan(`${this.avatarURL}\n`);
|
|
508
|
+
string += ` ${chalk.bgMagenta('Token:')} `;
|
|
509
|
+
string += chalk.red(`${this.token ? this.token : 'Unknown'}`);
|
|
510
|
+
RemoteAuth._logger('default', string);
|
|
376
511
|
}
|
|
377
512
|
}
|
|
378
513
|
|