djs-selfbot-v13 3.1.7 → 3.1.8

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.
Files changed (149) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +18 -45
  3. package/package.json +8 -37
  4. package/src/client/BaseClient.js +2 -3
  5. package/src/client/Client.js +187 -539
  6. package/src/client/actions/Action.js +18 -13
  7. package/src/client/actions/ActionsManager.js +7 -1
  8. package/src/client/actions/AutoModerationActionExecution.js +1 -0
  9. package/src/client/actions/AutoModerationRuleCreate.js +1 -0
  10. package/src/client/actions/AutoModerationRuleDelete.js +1 -0
  11. package/src/client/actions/AutoModerationRuleUpdate.js +1 -0
  12. package/src/client/actions/MessageCreate.js +0 -4
  13. package/src/client/actions/PresenceUpdate.js +17 -16
  14. package/src/client/websocket/WebSocketManager.js +11 -31
  15. package/src/client/websocket/WebSocketShard.js +39 -38
  16. package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
  17. package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
  18. package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
  19. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +16 -13
  20. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
  21. package/src/client/websocket/handlers/GUILD_CREATE.js +7 -0
  22. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +1 -0
  23. package/src/client/websocket/handlers/READY.js +47 -137
  24. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +7 -5
  25. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +6 -4
  26. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +32 -9
  27. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +2 -8
  28. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
  29. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -0
  30. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +1 -5
  31. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -0
  32. package/src/client/websocket/handlers/index.js +15 -20
  33. package/src/errors/Messages.js +24 -69
  34. package/src/index.js +12 -43
  35. package/src/managers/ApplicationCommandManager.js +9 -12
  36. package/src/managers/ApplicationCommandPermissionsManager.js +3 -11
  37. package/src/managers/ChannelManager.js +3 -4
  38. package/src/managers/ClientUserSettingManager.js +161 -279
  39. package/src/managers/GuildBanManager.js +1 -1
  40. package/src/managers/GuildChannelManager.js +2 -0
  41. package/src/managers/GuildForumThreadManager.js +22 -28
  42. package/src/managers/GuildMemberManager.js +40 -216
  43. package/src/managers/GuildSettingManager.js +22 -15
  44. package/src/managers/MessageManager.js +42 -44
  45. package/src/managers/PermissionOverwriteManager.js +1 -1
  46. package/src/managers/ReactionUserManager.js +5 -5
  47. package/src/managers/RelationshipManager.js +81 -74
  48. package/src/managers/ThreadManager.js +12 -45
  49. package/src/managers/ThreadMemberManager.js +1 -1
  50. package/src/managers/UserManager.js +6 -10
  51. package/src/managers/UserNoteManager.js +53 -0
  52. package/src/rest/APIRequest.js +42 -20
  53. package/src/rest/DiscordAPIError.js +17 -16
  54. package/src/rest/RESTManager.js +1 -21
  55. package/src/rest/RequestHandler.js +35 -21
  56. package/src/structures/ApplicationCommand.js +19 -456
  57. package/src/structures/ApplicationRoleConnectionMetadata.js +3 -0
  58. package/src/structures/AutoModerationRule.js +5 -5
  59. package/src/structures/AutocompleteInteraction.js +1 -0
  60. package/src/structures/BaseGuildTextChannel.js +10 -12
  61. package/src/structures/BaseGuildVoiceChannel.js +16 -18
  62. package/src/structures/{Call.js → CallState.js} +17 -12
  63. package/src/structures/CategoryChannel.js +2 -0
  64. package/src/structures/Channel.js +2 -3
  65. package/src/structures/ClientPresence.js +12 -8
  66. package/src/structures/ClientUser.js +117 -336
  67. package/src/structures/ContextMenuInteraction.js +1 -1
  68. package/src/structures/DMChannel.js +29 -92
  69. package/src/structures/ForumChannel.js +0 -10
  70. package/src/structures/GroupDMChannel.js +387 -0
  71. package/src/structures/Guild.js +135 -271
  72. package/src/structures/GuildAuditLogs.js +0 -5
  73. package/src/structures/GuildChannel.js +16 -2
  74. package/src/structures/GuildMember.js +27 -145
  75. package/src/structures/Interaction.js +1 -62
  76. package/src/structures/Invite.js +35 -52
  77. package/src/structures/Message.js +228 -202
  78. package/src/structures/MessageAttachment.js +11 -0
  79. package/src/structures/MessageButton.js +1 -67
  80. package/src/structures/MessageEmbed.js +1 -1
  81. package/src/structures/MessageMentions.js +3 -2
  82. package/src/structures/MessagePayload.js +4 -46
  83. package/src/structures/MessageReaction.js +1 -1
  84. package/src/structures/MessageSelectMenu.js +1 -252
  85. package/src/structures/Modal.js +75 -180
  86. package/src/structures/Presence.js +2 -2
  87. package/src/structures/RichPresence.js +14 -34
  88. package/src/structures/Role.js +18 -2
  89. package/src/structures/SelectMenuInteraction.js +2 -151
  90. package/src/structures/Team.js +0 -49
  91. package/src/structures/TextInputComponent.js +0 -70
  92. package/src/structures/ThreadChannel.js +0 -19
  93. package/src/structures/User.js +117 -345
  94. package/src/structures/UserContextMenuInteraction.js +2 -2
  95. package/src/structures/VoiceState.js +74 -39
  96. package/src/structures/WebEmbed.js +38 -52
  97. package/src/structures/Webhook.js +17 -11
  98. package/src/structures/interfaces/Application.js +146 -23
  99. package/src/structures/interfaces/TextBasedChannel.js +411 -256
  100. package/src/util/ApplicationFlags.js +1 -1
  101. package/src/util/AttachmentFlags.js +38 -0
  102. package/src/util/Constants.js +106 -284
  103. package/src/util/Formatters.js +16 -2
  104. package/src/util/InviteFlags.js +29 -0
  105. package/src/util/LimitedCollection.js +1 -1
  106. package/src/util/Options.js +48 -68
  107. package/src/util/Permissions.js +5 -0
  108. package/src/util/PurchasedFlags.js +2 -0
  109. package/src/util/RemoteAuth.js +221 -356
  110. package/src/util/RoleFlags.js +37 -0
  111. package/src/util/Sweepers.js +1 -1
  112. package/src/util/Util.js +76 -36
  113. package/typings/enums.d.ts +18 -73
  114. package/typings/index.d.ts +873 -1225
  115. package/typings/rawDataTypes.d.ts +68 -9
  116. package/src/client/actions/InteractionCreate.js +0 -115
  117. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +0 -23
  118. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +0 -11
  119. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +0 -55
  120. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  121. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  122. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  123. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  124. package/src/client/websocket/handlers/INTERACTION_CREATE.js +0 -16
  125. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +0 -18
  126. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +0 -30
  127. package/src/client/websocket/handlers/MESSAGE_ACK.js +0 -16
  128. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  129. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  130. package/src/managers/DeveloperPortalManager.js +0 -104
  131. package/src/managers/GuildApplicationCommandManager.js +0 -28
  132. package/src/managers/GuildFolderManager.js +0 -24
  133. package/src/managers/SessionManager.js +0 -57
  134. package/src/rest/CaptchaSolver.js +0 -132
  135. package/src/structures/ClientApplication.js +0 -204
  136. package/src/structures/DeveloperPortalApplication.js +0 -520
  137. package/src/structures/GuildFolder.js +0 -75
  138. package/src/structures/InteractionResponse.js +0 -114
  139. package/src/structures/PartialGroupDMChannel.js +0 -433
  140. package/src/structures/Session.js +0 -81
  141. package/src/util/Voice.js +0 -1456
  142. package/src/util/arRPC/index.js +0 -229
  143. package/src/util/arRPC/process/detectable.json +0 -1
  144. package/src/util/arRPC/process/index.js +0 -102
  145. package/src/util/arRPC/process/native/index.js +0 -5
  146. package/src/util/arRPC/process/native/linux.js +0 -37
  147. package/src/util/arRPC/process/native/win32.js +0 -25
  148. package/src/util/arRPC/transports/ipc.js +0 -281
  149. package/src/util/arRPC/transports/websocket.js +0 -128
@@ -1,14 +1,13 @@
1
1
  'use strict';
2
- const { Buffer } = require('buffer');
3
- const crypto = require('crypto');
2
+
3
+ const { Buffer } = require('node:buffer');
4
+ const crypto = require('node:crypto');
4
5
  const EventEmitter = require('node:events');
6
+ const { StringDecoder } = require('node:string_decoder');
5
7
  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');
10
9
  const WebSocket = require('ws');
11
- const { defaultUA } = require('./Constants');
10
+ const { UserAgent } = require('./Constants');
12
11
  const Options = require('./Options');
13
12
 
14
13
  const defaultClientOptions = Options.createDefault();
@@ -22,9 +21,9 @@ const receiveEvent = {
22
21
  NONCE_PROOF: 'nonce_proof',
23
22
  PENDING_REMOTE_INIT: 'pending_remote_init',
24
23
  HEARTBEAT_ACK: 'heartbeat_ack',
25
- PENDING_LOGIN: 'pending_ticket',
24
+ PENDING_TICKET: 'pending_ticket',
26
25
  CANCEL: 'cancel',
27
- SUCCESS: 'pending_login',
26
+ PENDING_LOGIN: 'pending_login',
28
27
  };
29
28
 
30
29
  const sendEvent = {
@@ -37,266 +36,167 @@ const Event = {
37
36
  READY: 'ready',
38
37
  ERROR: 'error',
39
38
  CANCEL: 'cancel',
40
- WAIT: 'pending',
41
- SUCCESS: 'success',
39
+ WAIT_SCAN: 'pending',
42
40
  FINISH: 'finish',
43
41
  CLOSED: 'closed',
42
+ DEBUG: 'debug',
44
43
  };
45
44
 
46
45
  /**
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)
46
+ * Discord Auth QR
60
47
  * @extends {EventEmitter}
61
48
  * @abstract
62
49
  */
63
50
  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
+
64
60
  /**
65
61
  * Creates a new DiscordAuthWebsocket instance.
66
- * @param {?DiscordAuthWebsocketOptions} options Options
67
62
  */
68
- constructor(options) {
63
+ constructor() {
69
64
  super();
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;
102
-
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;
65
+ this.token = '';
121
66
  }
122
- });
123
-
124
- `),
125
- );
126
- });
127
-
128
- /**
129
- * Captcha Cache
130
- * @type {?Captcha}
131
- */
132
- this.captchaCache = null;
133
-
134
- this._validateOptions(options);
135
67
 
136
- this.callFindRealTokenCount = 0;
68
+ /**
69
+ * @type {string}
70
+ */
71
+ get AuthURL() {
72
+ return baseURL + this.#fingerprint;
137
73
  }
74
+
138
75
  /**
139
- * Get expire time
140
- * @type {string} Expire time
141
- * @readonly
76
+ * @type {Date}
142
77
  */
143
- get exprireTime() {
144
- return this._expire.toLocaleString('en-US');
78
+ get exprire() {
79
+ return this.#expire;
145
80
  }
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
- }
81
+
82
+ /**
83
+ * @type {UserRaw}
84
+ */
85
+ get user() {
86
+ return DiscordAuthWebsocket.decryptUser(this.#userDecryptString);
173
87
  }
174
- _createWebSocket(url) {
175
- this.ws = new WebSocket(url, {
88
+
89
+ #createWebSocket(url) {
90
+ this.#ws = new WebSocket(url, {
176
91
  headers: {
177
92
  Origin: 'https://discord.com',
178
- 'User-Agent': this.options.userAgent,
93
+ 'User-Agent': UserAgent,
179
94
  },
180
95
  });
181
- this._handleWebSocket();
96
+ this.#handleWebSocket();
182
97
  }
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');
98
+
99
+ #handleWebSocket() {
100
+ this.#ws.on('error', error => {
101
+ /**
102
+ * WS Error
103
+ * @event DiscordAuthWebsocket#error
104
+ * @param {Error} error Error
105
+ */
106
+ this.emit(Event.ERROR, error);
189
107
  });
190
- this.ws.on('close', () => {
191
- this._logger('debug', 'Connection closed.');
108
+ this.#ws.on('open', () => {
109
+ /**
110
+ * Debug Event
111
+ * @event DiscordAuthWebsocket#debug
112
+ * @param {string} msg Debug msg
113
+ */
114
+ this.emit(Event.DEBUG, '[WS] Client Connected');
192
115
  });
193
- this.ws.on('message', message => {
194
- this._handleMessage(JSON.parse(message));
116
+ this.#ws.on('close', () => {
117
+ this.emit(Event.DEBUG, '[WS] Connection closed');
195
118
  });
119
+ this.#ws.on('message', this.#handleMessage.bind(this));
196
120
  }
197
- _handleMessage(message) {
121
+
122
+ #handleMessage(message) {
123
+ message = JSON.parse(message);
198
124
  switch (message.op) {
199
125
  case receiveEvent.HELLO: {
200
- this._ready(message);
126
+ this.#ready(message);
201
127
  break;
202
128
  }
129
+
203
130
  case receiveEvent.NONCE_PROOF: {
204
- this._receiveNonceProof(message);
131
+ this.#receiveNonceProof(message);
205
132
  break;
206
133
  }
134
+
207
135
  case receiveEvent.PENDING_REMOTE_INIT: {
208
- this._pendingRemoteInit(message);
136
+ this.#fingerprint = message.fingerprint;
137
+ /**
138
+ * Ready Event
139
+ * @event DiscordAuthWebsocket#ready
140
+ * @param {DiscordAuthWebsocket} client WS
141
+ */
142
+ this.emit(Event.READY, this);
209
143
  break;
210
144
  }
145
+
211
146
  case receiveEvent.HEARTBEAT_ACK: {
212
- this._logger('debug', 'Heartbeat acknowledged.');
213
- this._heartbeatAck();
147
+ this.emit(Event.DEBUG, `Heartbeat acknowledged.`);
148
+ this.#heartbeatAck();
214
149
  break;
215
150
  }
216
- case receiveEvent.PENDING_LOGIN: {
217
- this._pendingLogin(message);
151
+
152
+ case receiveEvent.PENDING_TICKET: {
153
+ this.#pendingLogin(message);
218
154
  break;
219
155
  }
156
+
220
157
  case receiveEvent.CANCEL: {
221
- this._logger('debug', 'Cancel login.');
222
158
  /**
223
- * Emitted whenever a user cancels the login process.
159
+ * Cancel
224
160
  * @event DiscordAuthWebsocket#cancel
225
- * @param {object} user User (Raw)
161
+ * @param {DiscordAuthWebsocket} client WS
226
162
  */
227
- this.emit(Event.CANCEL, this.user);
163
+ this.emit(Event.CANCEL, this);
228
164
  this.destroy();
229
165
  break;
230
166
  }
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.');
243
- break;
244
- }
245
- default: {
246
- this._logger('debug', `Unknown op: ${message.op}`, message);
247
- }
248
- }
249
- }
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);
167
+
168
+ case receiveEvent.PENDING_LOGIN: {
169
+ this.#ticket = message.ticket;
170
+ this.#findRealToken();
266
171
  break;
267
172
  }
268
173
  }
269
174
  }
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.'));
175
+
176
+ #send(op, data) {
177
+ if (!this.#ws) return;
276
178
  let payload = { op: op };
277
179
  if (data !== null) payload = { ...payload, ...data };
278
- this._logger('debug', `Send Data:`, payload);
279
- this.ws.send(JSON.stringify(payload));
280
- }
281
- _heartbeat() {
282
- this._send(sendEvent.HEARTBEAT);
180
+ this.#ws.send(JSON.stringify(payload));
283
181
  }
284
- _heartbeatAck() {
182
+
183
+ #heartbeatAck() {
285
184
  setTimeout(() => {
286
- this._heartbeat();
287
- }, this.heartbeatInterval).unref();
185
+ this.#send(sendEvent.HEARTBEAT);
186
+ }, this.#heartbeatInterval).unref();
288
187
  }
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();
188
+
189
+ #ready(data) {
190
+ this.emit(Event.DEBUG, 'Attempting server handshake...');
191
+ this.#expire = new Date(Date.now() + data.timeout_ms);
192
+ this.#heartbeatInterval = data.heartbeat_interval;
193
+ this.#createKey();
194
+ this.#heartbeatAck();
195
+ this.#init();
296
196
  }
297
- _createKey() {
298
- if (this.key) this._throwError(new Error('Key is already created.'));
299
- this.key = crypto.generateKeyPairSync('rsa', {
197
+
198
+ #createKey() {
199
+ const key = crypto.generateKeyPairSync('rsa', {
300
200
  modulusLength: 2048,
301
201
  publicKeyEncoding: {
302
202
  type: 'spki',
@@ -307,35 +207,41 @@ new DiscordAuthWebsocket({
307
207
  format: 'pem',
308
208
  },
309
209
  });
210
+ this.#privateKey = key.privateKey;
211
+ this.#publicKey = key.publicKey;
310
212
  }
311
- _createPublicKey() {
312
- if (!this.key) this._throwError(new Error('Key is not created.'));
313
- this._logger('debug', 'Generating public key...');
213
+
214
+ #encodePublicKey() {
314
215
  const decoder = new StringDecoder('utf-8');
315
- let pub_key = decoder.write(this.key.publicKey);
216
+ let pub_key = decoder.write(this.#publicKey);
316
217
  pub_key = pub_key.split('\n').slice(1, -2).join('');
317
- this._logger('debug', 'Public key generated.', pub_key);
318
218
  return pub_key;
319
219
  }
320
- _init() {
321
- const public_key = this._createPublicKey();
322
- this._send(sendEvent.INIT, { encoded_public_key: public_key });
220
+
221
+ #init() {
222
+ const public_key = this.#encodePublicKey();
223
+ this.#send(sendEvent.INIT, { encoded_public_key: public_key });
323
224
  }
324
- _receiveNonceProof(data) {
225
+
226
+ #receiveNonceProof(data) {
325
227
  const nonce = data.encrypted_nonce;
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);
228
+ const decrypted_nonce = this.#decryptPayload(nonce);
229
+ const proof = crypto
230
+ .createHash('sha256')
231
+ .update(decrypted_nonce)
232
+ .digest()
233
+ .toString('base64')
234
+ .replace(/\+/g, '-')
235
+ .replace(/\//g, '_')
236
+ .replace(/=+/, '')
237
+ .replace(/\s+$/, '');
238
+ this.#send(sendEvent.NONCE_PROOF, { proof: proof });
332
239
  }
333
- _decryptPayload(encrypted_payload) {
334
- if (!this.key) this._throwError(new Error('Key is not created.'));
240
+
241
+ #decryptPayload(encrypted_payload) {
335
242
  const payload = Buffer.from(encrypted_payload, 'base64');
336
- this._logger('debug', `Encrypted Payload (Buffer):`, payload);
337
243
  const decoder = new StringDecoder('utf-8');
338
- const private_key = decoder.write(this.key.privateKey);
244
+ const private_key = decoder.write(this.#privateKey);
339
245
  const data = crypto.privateDecrypt(
340
246
  {
341
247
  key: private_key,
@@ -344,170 +250,129 @@ new DiscordAuthWebsocket({
344
250
  },
345
251
  payload,
346
252
  );
347
- this._logger('debug', `Decrypted Payload:`, data.toString());
348
253
  return data;
349
254
  }
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;
255
+
256
+ #pendingLogin(data) {
257
+ const user_data = this.#decryptPayload(data.encrypted_user_payload);
258
+ this.#userDecryptString = user_data.toString();
259
+
354
260
  /**
355
- * Emitted whenever a user is scan QR Code.
356
- * @event DiscordAuthWebsocket#pending
357
- * @param {object} user Discord User Raw
261
+ * @typedef {Object} UserRaw
262
+ * @property {Snowflake} id
263
+ * @property {string} username
264
+ * @property {number} discriminator
265
+ * @property {string} avatar
358
266
  */
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.');
363
- }
364
- _pendingRemoteInit(data) {
365
- this._logger('debug', `Pending Remote Init:`, data);
267
+
366
268
  /**
367
- * Emitted whenever a url is created.
368
- * @event DiscordAuthWebsocket#ready
369
- * @param {string} fingerprint Fingerprint
370
- * @param {string} url DiscordAuthWebsocket
269
+ * Emitted whenever a user is scan QR Code.
270
+ * @event DiscordAuthWebsocket#pending
271
+ * @param {UserRaw} user Discord User Raw
371
272
  */
372
- this.emit(Event.READY, data.fingerprint, `${baseURL}${data.fingerprint}`);
373
- this.fingerprint = data.fingerprint;
374
- if (this.options.generateQR) this.generateQR();
273
+ this.emit(Event.WAIT_SCAN, this.user);
375
274
  }
376
- _awaitLogin(client) {
377
- this.once(Event.FINISH, (user, token) => {
378
- this._logger('debug', 'Create login state...', user, token);
379
- client.login(token);
275
+
276
+ #awaitLogin(client) {
277
+ return new Promise(r => {
278
+ this.once(Event.FINISH, token => {
279
+ r(client.login(token));
280
+ });
380
281
  });
381
282
  }
283
+
382
284
  /**
383
- * Connect to DiscordAuthWebsocket.
384
- * @param {?Client} client Using only for auto login.
385
- * @returns {undefined}
285
+ * Connect WS
286
+ * @param {Client} [client] DiscordJS Client
287
+ * @returns {Promise<void>}
386
288
  */
387
289
  connect(client) {
388
- this._createWebSocket(wsURL);
389
- if (client && this.options.autoLogin) this._awaitLogin(client);
290
+ this.#createWebSocket(wsURL);
291
+ if (client) {
292
+ return this.#awaitLogin(client);
293
+ } else {
294
+ return Promise.resolve();
295
+ }
390
296
  }
297
+
391
298
  /**
392
- * Disconnect from DiscordAuthWebsocket.
393
- * @returns {undefined}
299
+ * Destroy client
300
+ * @returns {void}
394
301
  */
395
302
  destroy() {
396
- if (!this.ws) this._throwError(new Error('WebSocket is not connected.'));
303
+ if (!this.ws) return;
397
304
  this.ws.close();
305
+ this.emit(Event.DEBUG, 'WebSocket closed.');
398
306
  /**
399
307
  * Emitted whenever a connection is closed.
400
308
  * @event DiscordAuthWebsocket#closed
401
- * @param {boolean} loginState Login state
402
309
  */
403
- this.emit(Event.CLOSED, this.token);
404
- this._logger('debug', 'WebSocket closed.');
310
+ this.emit(Event.CLOSED);
405
311
  }
312
+
406
313
  /**
407
314
  * Generate QR code for user to scan (Terminal)
408
- * @returns {undefined}
315
+ * @returns {void}
409
316
  */
410
317
  generateQR() {
411
- if (!this.fingerprint) this._throwError(new Error('Fingerprint is not created.'));
412
- require('@aikochan2k6/qrcode-terminal').generate(`${baseURL}${this.fingerprint}`, {
318
+ if (!this.#fingerprint) return;
319
+ require('@aikochan2k6/qrcode-terminal').generate(this.AuthURL, {
413
320
  small: true,
414
321
  });
415
- this._logger('default', `Please scan the QR code to continue.\nQR Code will expire in ${this.exprireTime}`);
416
322
  }
417
323
 
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
- ),
324
+ #findRealToken() {
325
+ return fetch(`https://discord.com/api/v9/users/@me/remote-auth/login`, {
326
+ method: 'POST',
327
+ headers: {
328
+ Accept: '*/*',
329
+ 'Accept-Language': 'en-US',
330
+ 'Content-Type': 'application/json',
331
+ 'Sec-Fetch-Dest': 'empty',
332
+ 'Sec-Fetch-Mode': 'cors',
333
+ 'Sec-Fetch-Site': 'same-origin',
334
+ 'X-Debug-Options': 'bugReporterEnabled',
335
+ 'X-Super-Properties': `${Buffer.from(JSON.stringify(defaultClientOptions.ws.properties), 'ascii').toString(
336
+ 'base64',
337
+ )}`,
338
+ 'X-Discord-Locale': 'en-US',
339
+ 'User-Agent': UserAgent,
340
+ Referer: 'https://discord.com/channels/@me',
341
+ Connection: 'keep-alive',
342
+ Origin: 'https://discord.com',
343
+ },
344
+ body: JSON.stringify({
345
+ ticket: this.#ticket,
346
+ }),
347
+ })
348
+ .then(r => r.json())
349
+ .then(res => {
350
+ if (res.encrypted_token) {
351
+ this.token = this.#decryptPayload(res.encrypted_token).toString();
352
+ }
353
+ /**
354
+ * Emitted whenever a real token is found.
355
+ * @event DiscordAuthWebsocket#finish
356
+ * @param {string} token Discord Token
357
+ */
358
+ this.emit(Event.FINISH, this.token);
359
+ this.destroy();
459
360
  })
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;
361
+ .catch(() => false);
482
362
  }
483
- }
484
363
 
485
- class User {
486
- constructor(payload) {
364
+ static decryptUser(payload) {
487
365
  const values = payload.split(':');
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);
366
+ const id = values[0];
367
+ const username = values[3];
368
+ const discriminator = values[1];
369
+ const avatar = values[2];
370
+ return {
371
+ id,
372
+ username,
373
+ discriminator,
374
+ avatar,
375
+ };
511
376
  }
512
377
  }
513
378