Merge pull request #278 from aiko-chan-ai/dev
feat(SessionManager): New feature from Discord
This commit is contained in:
commit
8b2d138bdd
@ -15,6 +15,7 @@ const ClientSettingManager = require('../managers/ClientSettingManager');
|
||||
const DeveloperPortalManager = require('../managers/DeveloperPortalManager');
|
||||
const GuildManager = require('../managers/GuildManager');
|
||||
const RelationshipsManager = require('../managers/RelationshipsManager');
|
||||
const SessionManager = require('../managers/SessionManager');
|
||||
const UserManager = require('../managers/UserManager');
|
||||
const VoiceStateManager = require('../managers/VoiceStateManager');
|
||||
const ShardClientUtil = require('../sharding/ShardClientUtil');
|
||||
@ -156,6 +157,12 @@ class Client extends BaseClient {
|
||||
*/
|
||||
this.guilds = new GuildManager(this);
|
||||
|
||||
/**
|
||||
* All of the sessions of the client
|
||||
* @type {SessionManager}
|
||||
*/
|
||||
this.sessions = new SessionManager(this);
|
||||
|
||||
/**
|
||||
* All of the {@link Channel}s that the client is currently handling, mapped by their ids -
|
||||
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
|
||||
|
@ -104,6 +104,8 @@ const Messages = {
|
||||
STAGE_CHANNEL_RESOLVE: 'Could not resolve channel to a stage channel.',
|
||||
GUILD_SCHEDULED_EVENT_RESOLVE: 'Could not resolve the guild scheduled event.',
|
||||
|
||||
REQUIRE_PASSWORD: 'You must provide a password.',
|
||||
|
||||
MISSING_VALUE: (where, type) => `Missing value for ${where} (${type})`,
|
||||
|
||||
INVALID_TYPE: (name, expected, an = false) => `Supplied ${name} is not a${an ? 'n' : ''} ${expected}.`,
|
||||
|
@ -60,6 +60,7 @@ exports.PresenceManager = require('./managers/PresenceManager');
|
||||
exports.ReactionManager = require('./managers/ReactionManager');
|
||||
exports.ReactionUserManager = require('./managers/ReactionUserManager');
|
||||
exports.RoleManager = require('./managers/RoleManager');
|
||||
exports.SessionManager = require('./managers/SessionManager');
|
||||
exports.StageInstanceManager = require('./managers/StageInstanceManager');
|
||||
exports.ThreadManager = require('./managers/ThreadManager');
|
||||
exports.ThreadMemberManager = require('./managers/ThreadMemberManager');
|
||||
@ -137,6 +138,7 @@ exports.ReactionCollector = require('./structures/ReactionCollector');
|
||||
exports.ReactionEmoji = require('./structures/ReactionEmoji');
|
||||
exports.RichPresenceAssets = require('./structures/Presence').RichPresenceAssets;
|
||||
exports.Role = require('./structures/Role').Role;
|
||||
exports.Session = require('./structures/Session');
|
||||
// RPC
|
||||
exports.getUUID = require('./structures/RichPresence').getUUID;
|
||||
exports.CustomStatus = require('./structures/RichPresence').CustomStatus;
|
||||
|
52
src/managers/SessionManager.js
Normal file
52
src/managers/SessionManager.js
Normal file
@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
|
||||
const CachedManager = require('./CachedManager');
|
||||
const { Error } = require('../errors/DJSError');
|
||||
const Session = require('../structures/Session');
|
||||
/**
|
||||
* Manages API methods for users and stores their cache.
|
||||
* @extends {CachedManager}
|
||||
*/
|
||||
class SessionManager extends CachedManager {
|
||||
constructor(client, iterable) {
|
||||
super(client, Session, iterable);
|
||||
}
|
||||
/**
|
||||
* Fetch all sessions of the client.
|
||||
* @returns {Promise<SessionManager>}
|
||||
*/
|
||||
fetch() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.client.api.auth.session
|
||||
.get()
|
||||
.then(data => {
|
||||
const allData = data.user_sessions;
|
||||
for (const session of allData) {
|
||||
this._add(new Session(this.client, session), true);
|
||||
}
|
||||
resolve(this);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout the client (remote).
|
||||
* @param {string} password User's password
|
||||
* @param {string | null} mfaCode MFA code (if 2FA is enabled)
|
||||
* @returns {Promise<undefined>}
|
||||
*/
|
||||
logoutAllDevices(password, mfaCode) {
|
||||
password = password || this.client.password;
|
||||
if (!password || typeof password !== 'string') throw new Error('REQUIRE_PASSWORD');
|
||||
return this.client.api.auth.sessions.logout({
|
||||
data: {
|
||||
session_id_hashes: this.cache.map(session => session.id),
|
||||
password,
|
||||
code: typeof mfaCode === 'string' ? mfaCode : undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SessionManager;
|
83
src/structures/Session.js
Normal file
83
src/structures/Session.js
Normal file
@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
const Base = require('./Base');
|
||||
|
||||
/**
|
||||
* @typedef {Object} SessionClientInfo
|
||||
* @property {string} location Location of the client (using IP address)
|
||||
* @property {string} platform Platform of the client
|
||||
* @property {string} os Operating system of the client
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a Client OAuth2 Application Team.
|
||||
* @extends {Base}
|
||||
*/
|
||||
class Session extends Base {
|
||||
constructor(client, data) {
|
||||
super(client);
|
||||
this._patch(data);
|
||||
}
|
||||
|
||||
_patch(data) {
|
||||
if ('id_hash' in data) {
|
||||
/**
|
||||
* The session hash id
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = data.id_hash;
|
||||
}
|
||||
if ('approx_last_used_time' in data) {
|
||||
this.approxLastUsedTime = data.approx_last_used_time;
|
||||
}
|
||||
if ('client_info' in data) {
|
||||
/**
|
||||
* The client info
|
||||
* @type {SessionClientInfo}
|
||||
*/
|
||||
this.clientInfo = data.client_info;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp the client was last used at.
|
||||
* @type {number}
|
||||
* @readonly
|
||||
*/
|
||||
get createdTimestamp() {
|
||||
return this.createdAt.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* The time the client was last used at.
|
||||
* @type {Date}
|
||||
* @readonly
|
||||
*/
|
||||
get createdAt() {
|
||||
return new Date(this.approxLastUsedTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout the client (remote).
|
||||
* @param {string} password User's password
|
||||
* @param {string | null} mfaCode MFA code (if 2FA is enabled)
|
||||
* @returns {Promise<undefined>}
|
||||
*/
|
||||
logout(password, mfaCode) {
|
||||
password = password || this.client.password;
|
||||
if (!password || typeof password !== 'string') throw new Error('REQUIRE_PASSWORD', 'You must provide a password.');
|
||||
return this.client.api.auth.sessions.logout({
|
||||
data: {
|
||||
session_id_hashes: [this.id],
|
||||
password,
|
||||
code: typeof mfaCode === 'string' ? mfaCode : undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return super.toJSON();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Session;
|
22
typings/index.d.ts
vendored
22
typings/index.d.ts
vendored
@ -163,6 +163,28 @@ import {
|
||||
} from './rawDataTypes';
|
||||
// @ts-ignore
|
||||
//#region Classes
|
||||
|
||||
export abstract class SessionManager extends CachedManager {
|
||||
constructor(client: Client, iterable?: Iterable<unknown>);
|
||||
public fetch(): Promise<SessionManager>;
|
||||
public logoutAllDevices(password?: string, mfaCode?: string): Promise<undefined>;
|
||||
}
|
||||
|
||||
export abstract class Session extends Base {
|
||||
constructor(client: Client);
|
||||
public id?: string;
|
||||
public clientInfo?: SessionClientInfo;
|
||||
public readonly createdTimestamp: number;
|
||||
public readonly createdAt: Date;
|
||||
public logout(password?: string, mfaCode?: string): Promise<undefined>;
|
||||
}
|
||||
|
||||
export interface SessionClientInfo {
|
||||
location?: string;
|
||||
platform?: string;
|
||||
os?: string;
|
||||
}
|
||||
|
||||
export abstract class DiscordAuthWebsocket extends EventEmitter {
|
||||
constructor(options?: DiscordAuthWebsocketOptions);
|
||||
public fingerprint?: string;
|
||||
|
Loading…
Reference in New Issue
Block a user