fix(RemoteAuth): Return fake token

This commit is contained in:
March 7th 2022-08-20 20:27:34 +07:00
parent cbc3fbb7b8
commit 9ec9c77703
6 changed files with 65 additions and 158 deletions

View File

@ -280,6 +280,7 @@
"name": "setImmediate", "name": "setImmediate",
"message": "Import setImmediate from `node:timers` instead" "message": "Import setImmediate from `node:timers` instead"
} }
] ],
"linebreak-style": 0
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -1,75 +0,0 @@
'use strict';
const CachedManager = require('./CachedManager');
const GuildMember = require('../structures/GuildMember');
const Message = require('../structures/Message');
const ThreadMember = require('../structures/ThreadMember');
const User = require('../structures/User');
/**
* Manages API methods for users and stores their cache.
* @extends {CachedManager}
*/
class BlockedManager extends CachedManager {
constructor(client, iterable) {
super(client, User, iterable);
}
/**
* The cache of this manager
* @type {Collection<Snowflake, User>}
* @name BlockedManager#cache
*/
/**
* Data that resolves to give a User object. This can be:
* * A User object
* * A Snowflake
* * A Message object (resolves to the message author)
* * A GuildMember object
* * A ThreadMember object
* @typedef {User|Snowflake|Message|GuildMember|ThreadMember} UserResolvable
*/
/**
* Resolves a {@link UserResolvable} to a {@link User} object.
* @param {UserResolvable} user The UserResolvable to identify
* @returns {?User}
*/
resolve(user) {
if (user instanceof GuildMember || user instanceof ThreadMember) return user.user;
if (user instanceof Message) return user.author;
return super.resolve(user);
}
/**
* Resolves a {@link UserResolvable} to a {@link User} id.
* @param {UserResolvable} user The UserResolvable to identify
* @returns {?Snowflake}
*/
resolveId(user) {
if (user instanceof ThreadMember) return user.id;
if (user instanceof GuildMember) return user.user.id;
if (user instanceof Message) return user.author.id;
return super.resolveId(user);
}
/**
* Obtains a user from Discord, or the user cache if it's already available.
* @param {UserResolvable} user The user to fetch
* @param {BaseFetchOptions} [options] Additional options for this fetch
* @returns {Promise<User>}
*/
async fetch(user, { cache = true, force = false } = {}) {
const id = this.resolveId(user);
if (!force) {
const existing = this.cache.get(id);
if (existing && !existing.partial) return existing;
}
const data = await this.client.api.users(id).get();
return this._add(data, cache);
}
}
module.exports = BlockedManager;

View File

@ -1,75 +0,0 @@
'use strict';
const CachedManager = require('./CachedManager');
const GuildMember = require('../structures/GuildMember');
const Message = require('../structures/Message');
const ThreadMember = require('../structures/ThreadMember');
const User = require('../structures/User');
/**
* Manages API methods for users and stores their cache.
* @extends {CachedManager}
*/
class FriendsManager extends CachedManager {
constructor(client, iterable) {
super(client, User, iterable);
}
/**
* The cache of this manager
* @type {Collection<Snowflake, User>}
* @name FriendsManager#cache
*/
/**
* Data that resolves to give a User object. This can be:
* * A User object
* * A Snowflake
* * A Message object (resolves to the message author)
* * A GuildMember object
* * A ThreadMember object
* @typedef {User|Snowflake|Message|GuildMember|ThreadMember} UserResolvable
*/
/**
* Resolves a {@link UserResolvable} to a {@link User} object.
* @param {UserResolvable} user The UserResolvable to identify
* @returns {?User}
*/
resolve(user) {
if (user instanceof GuildMember || user instanceof ThreadMember) return user.user;
if (user instanceof Message) return user.author;
return super.resolve(user);
}
/**
* Resolves a {@link UserResolvable} to a {@link User} id.
* @param {UserResolvable} user The UserResolvable to identify
* @returns {?Snowflake}
*/
resolveId(user) {
if (user instanceof ThreadMember) return user.id;
if (user instanceof GuildMember) return user.user.id;
if (user instanceof Message) return user.author.id;
return super.resolveId(user);
}
/**
* Obtains a user from Discord, or the user cache if it's already available.
* @param {UserResolvable} user The user to fetch
* @param {BaseFetchOptions} [options] Additional options for this fetch
* @returns {Promise<User>}
*/
async fetch(user, { cache = true, force = false } = {}) {
const id = this.resolveId(user);
if (!force) {
const existing = this.cache.get(id);
if (existing && !existing.partial) return existing;
}
const data = await this.client.api.users(id).get();
return this._add(data, cache);
}
}
module.exports = FriendsManager;

View File

@ -59,6 +59,7 @@ class CustomStatus {
* @returns {CustomStatus} * @returns {CustomStatus}
*/ */
setState(state) { setState(state) {
if (typeof state == 'string' && state.length > 128) throw new Error('State must be less than 128 characters');
this.state = state; this.state = state;
return this; return this;
} }

View File

@ -4,10 +4,14 @@ const crypto = require('crypto');
const EventEmitter = require('node:events'); const EventEmitter = require('node:events');
const { setTimeout } = require('node:timers'); const { setTimeout } = require('node:timers');
const { StringDecoder } = require('string_decoder'); const { StringDecoder } = require('string_decoder');
const axios = require('axios');
const chalk = require('chalk'); const chalk = require('chalk');
const { encode: urlsafe_b64encode } = require('safe-base64'); const { encode: urlsafe_b64encode } = require('safe-base64');
const WebSocket = require('ws'); const WebSocket = require('ws');
const { randomUA } = require('./Constants'); const { randomUA } = require('./Constants');
const Options = require('./Options');
const defaultClientOptions = Options.createDefault();
const baseURL = 'https://discord.com/ra/'; const baseURL = 'https://discord.com/ra/';
@ -34,6 +38,7 @@ const Event = {
ERROR: 'error', ERROR: 'error',
CANCEL: 'cancel', CANCEL: 'cancel',
WAIT: 'pending', WAIT: 'pending',
SUCCESS: 'success',
FINISH: 'finish', FINISH: 'finish',
CLOSED: 'closed', CLOSED: 'closed',
}; };
@ -45,6 +50,7 @@ const Event = {
* @property {?boolean} [autoLogin=false] Automatically login (DiscordJS.Client Login) ? * @property {?boolean} [autoLogin=false] Automatically login (DiscordJS.Client Login) ?
* @property {?boolean} [failIfError=true] Throw error ? * @property {?boolean} [failIfError=true] Throw error ?
* @property {?boolean} [generateQR=true] Create QR Code ? * @property {?boolean} [generateQR=true] Create QR Code ?
* @property {?number} [apiVersion=9] API Version
*/ */
/** /**
@ -77,10 +83,15 @@ class DiscordAuthWebsocket extends EventEmitter {
*/ */
this.user = null; this.user = null;
/** /**
* Token (Scan QR Code) * Temporary Token (Scan QR Code)
* @type {?string} * @type {?string}
*/ */
this.token = undefined; this.token = undefined;
/**
* Real Token (Login)
* @type {?string}
*/
this.realToken = undefined;
/** /**
* Fingerprint (QR Code) * Fingerprint (QR Code)
* @type {?string} * @type {?string}
@ -107,6 +118,7 @@ class DiscordAuthWebsocket extends EventEmitter {
autoLogin: false, autoLogin: false,
failIfError: true, failIfError: true,
generateQR: true, generateQR: true,
apiVersion: 9,
}; };
if (typeof options == 'object') { if (typeof options == 'object') {
if (typeof options.debug == 'boolean') this.options.debug = options.debug; if (typeof options.debug == 'boolean') this.options.debug = options.debug;
@ -114,6 +126,7 @@ class DiscordAuthWebsocket extends EventEmitter {
if (typeof options.autoLogin == 'boolean') this.options.autoLogin = options.autoLogin; if (typeof options.autoLogin == 'boolean') this.options.autoLogin = options.autoLogin;
if (typeof options.failIfError == 'boolean') this.options.failIfError = options.failIfError; if (typeof options.failIfError == 'boolean') this.options.failIfError = options.failIfError;
if (typeof options.generateQR == 'boolean') this.options.generateQR = options.generateQR; if (typeof options.generateQR == 'boolean') this.options.generateQR = options.generateQR;
if (typeof options.apiVersion == 'number') this.options.apiVersion = options.apiVersion;
} }
} }
_createWebSocket(url) { _createWebSocket(url) {
@ -176,14 +189,14 @@ class DiscordAuthWebsocket extends EventEmitter {
case receiveEvent.SUCCESS: { case receiveEvent.SUCCESS: {
this._logger('debug', 'Receive Token - Login Success.', message.ticket); this._logger('debug', 'Receive Token - Login Success.', message.ticket);
/** /**
* Emitted whenever a token is created. * Emitted whenever a token is created. (Fake token)
* @event DiscordAuthWebsocket#finish * @event DiscordAuthWebsocket#success
* @param {object} user Discord User * @param {object} user Discord User
* @param {string} token Discord Token * @param {string} token Discord Token (Fake)
*/ */
this.emit(Event.FINISH, this.user, message.ticket); this.emit(Event.SUCCESS, this.user, message.ticket);
this.token = message.ticket; this.token = message.ticket;
this.destroy(); this._findRealToken();
break; break;
} }
default: { default: {
@ -359,6 +372,48 @@ class DiscordAuthWebsocket extends EventEmitter {
} }
this._logger('default', `Please scan the QR code to continue.\nQR Code will expire in ${this.exprireTime}`); this._logger('default', `Please scan the QR code to continue.\nQR Code will expire in ${this.exprireTime}`);
} }
async _findRealToken() {
if (!this.token) this._throwError(new Error('Token is not created.'));
const res = await axios.post(
`https://discord.com/api/v${this.options.apiVersion}/users/@me/remote-auth/login`,
{
ticket: this.token,
},
{
headers: {
Accept: '*/*',
'Content-Type': 'application/json',
'Accept-Language': 'en-US,en;q=0.9',
'Cache-Control': 'no-cache',
Pragma: 'no-cache',
'Sec-Ch-Ua': `"Not A;Brand";v="99", "Chromium";v="${
defaultClientOptions.ws.properties.browser_version.split('.')[0]
}", "Google Chrome";v="${defaultClientOptions.ws.properties.browser_version.split('.')[0]}`,
'Sec-Ch-Ua-Mobile': '?0',
'Sec-Ch-Ua-Platform': '"Windows"',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'X-Debug-Options': 'bugReporterEnabled',
'X-Super-Properties': `${Buffer.from(JSON.stringify(defaultClientOptions.ws.properties), 'ascii').toString(
'base64',
)}`,
'X-Discord-Locale': 'en-US',
'User-Agent': randomUA(),
},
},
);
this._logger('debug', 'Find real token...', res.data);
this.realToken = this._decryptPayload(res.data.encrypted_token).toString();
/**
* Emitted whenever a real token is found.
* @event DiscordAuthWebsocket#finish
* @param {object} user User
* @param {string} token Real token
*/
this.emit(Event.FINISH, this.user, this.realToken);
}
} }
class User { class User {