mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 11:33:30 +01:00
Overhaul Permissions utilities (EvaluatedPermissions no more)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
const os = require('os');
|
const os = require('os');
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
const Constants = require('../util/Constants');
|
const Constants = require('../util/Constants');
|
||||||
|
const Permissions = require('../util/Permissions');
|
||||||
const Util = require('../util/Util');
|
const Util = require('../util/Util');
|
||||||
const RESTManager = require('./rest/RESTManager');
|
const RESTManager = require('./rest/RESTManager');
|
||||||
const ClientDataManager = require('./ClientDataManager');
|
const ClientDataManager = require('./ClientDataManager');
|
||||||
@@ -398,7 +399,7 @@ class Client extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
generateInvite(permissions) {
|
generateInvite(permissions) {
|
||||||
if (permissions) {
|
if (permissions) {
|
||||||
if (permissions instanceof Array) permissions = this.resolver.resolvePermissions(permissions);
|
if (permissions instanceof Array) permissions = Permissions.resolve(permissions);
|
||||||
} else {
|
} else {
|
||||||
permissions = 0;
|
permissions = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,82 +155,6 @@ class ClientDataResolver {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Data that can be resolved to give a permission number. This can be:
|
|
||||||
* * A string
|
|
||||||
* * A permission number
|
|
||||||
*
|
|
||||||
* Possible strings:
|
|
||||||
* ```js
|
|
||||||
* [
|
|
||||||
* 'CREATE_INSTANT_INVITE',
|
|
||||||
* 'KICK_MEMBERS',
|
|
||||||
* 'BAN_MEMBERS',
|
|
||||||
* 'ADMINISTRATOR',
|
|
||||||
* 'MANAGE_CHANNELS',
|
|
||||||
* 'MANAGE_GUILD',
|
|
||||||
* 'ADD_REACTIONS', // add reactions to messages
|
|
||||||
* 'READ_MESSAGES',
|
|
||||||
* 'SEND_MESSAGES',
|
|
||||||
* 'SEND_TTS_MESSAGES',
|
|
||||||
* 'MANAGE_MESSAGES',
|
|
||||||
* 'EMBED_LINKS',
|
|
||||||
* 'ATTACH_FILES',
|
|
||||||
* 'READ_MESSAGE_HISTORY',
|
|
||||||
* 'MENTION_EVERYONE',
|
|
||||||
* 'EXTERNAL_EMOJIS', // use external emojis
|
|
||||||
* 'CONNECT', // connect to voice
|
|
||||||
* 'SPEAK', // speak on voice
|
|
||||||
* 'MUTE_MEMBERS', // globally mute members on voice
|
|
||||||
* 'DEAFEN_MEMBERS', // globally deafen members on voice
|
|
||||||
* 'MOVE_MEMBERS', // move member's voice channels
|
|
||||||
* 'USE_VAD', // use voice activity detection
|
|
||||||
* 'CHANGE_NICKNAME',
|
|
||||||
* 'MANAGE_NICKNAMES', // change nicknames of others
|
|
||||||
* 'MANAGE_ROLES_OR_PERMISSIONS',
|
|
||||||
* 'MANAGE_WEBHOOKS',
|
|
||||||
* 'MANAGE_EMOJIS'
|
|
||||||
* ]
|
|
||||||
* ```
|
|
||||||
* @typedef {string|number} PermissionResolvable
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves a PermissionResolvable to a permission number
|
|
||||||
* @param {PermissionResolvable} permission The permission resolvable to resolve
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
resolvePermission(permission) {
|
|
||||||
if (typeof permission === 'string') permission = Constants.PermissionFlags[permission];
|
|
||||||
if (typeof permission !== 'number' || permission < 1) throw new Error(Constants.Errors.NOT_A_PERMISSION);
|
|
||||||
return permission;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn an array of permissions into a valid Discord permission bitfield
|
|
||||||
* @param {PermissionResolvable[]} permissions Permissions to resolve together
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
resolvePermissions(permissions) {
|
|
||||||
let bitfield = 0;
|
|
||||||
for (const permission of permissions) bitfield |= this.resolvePermission(permission);
|
|
||||||
return bitfield;
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPermission(bitfield, name, explicit = false) {
|
|
||||||
const permission = this.resolvePermission(name);
|
|
||||||
if (!explicit && (bitfield & Constants.PermissionFlags.ADMINISTRATOR) > 0) return true;
|
|
||||||
return (bitfield & permission) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializePermissions(bitfield) {
|
|
||||||
const serializedPermissions = {};
|
|
||||||
for (const name in Constants.PermissionFlags) {
|
|
||||||
serializedPermissions[name] = this.hasPermission(bitfield, name);
|
|
||||||
}
|
|
||||||
return serializedPermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data that can be resolved to give a string. This can be:
|
* Data that can be resolved to give a string. This can be:
|
||||||
* * A string
|
* * A string
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const querystring = require('querystring');
|
const querystring = require('querystring');
|
||||||
const long = require('long');
|
const long = require('long');
|
||||||
|
const Permissions = require('../../util/Permissions');
|
||||||
const Constants = require('../../util/Constants');
|
const Constants = require('../../util/Constants');
|
||||||
const Collection = require('../../util/Collection');
|
const Collection = require('../../util/Collection');
|
||||||
const Snowflake = require('../../util/Snowflake');
|
const Snowflake = require('../../util/Snowflake');
|
||||||
@@ -581,7 +582,7 @@ class RESTMethods {
|
|||||||
if (_data.permissions) {
|
if (_data.permissions) {
|
||||||
let perms = 0;
|
let perms = 0;
|
||||||
for (let perm of _data.permissions) {
|
for (let perm of _data.permissions) {
|
||||||
if (typeof perm === 'string') perm = Constants.PermissionFlags[perm];
|
if (typeof perm === 'string') perm = Permissions.FLAGS[perm];
|
||||||
perms |= perm;
|
perms |= perm;
|
||||||
}
|
}
|
||||||
data.permissions = perms;
|
data.permissions = perms;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ module.exports = {
|
|||||||
// Utilities
|
// Utilities
|
||||||
Collection: require('./util/Collection'),
|
Collection: require('./util/Collection'),
|
||||||
Constants: require('./util/Constants'),
|
Constants: require('./util/Constants'),
|
||||||
|
EvaluatedPermissions: require('./util/Permissions'),
|
||||||
|
Permissions: require('./util/Permissions'),
|
||||||
Snowflake: require('./util/Snowflake'),
|
Snowflake: require('./util/Snowflake'),
|
||||||
SnowflakeUtil: require('./util/Snowflake'),
|
SnowflakeUtil: require('./util/Snowflake'),
|
||||||
Util: Util,
|
Util: Util,
|
||||||
@@ -27,7 +29,6 @@ module.exports = {
|
|||||||
ClientUser: require('./structures/ClientUser'),
|
ClientUser: require('./structures/ClientUser'),
|
||||||
DMChannel: require('./structures/DMChannel'),
|
DMChannel: require('./structures/DMChannel'),
|
||||||
Emoji: require('./structures/Emoji'),
|
Emoji: require('./structures/Emoji'),
|
||||||
EvaluatedPermissions: require('./structures/EvaluatedPermissions'),
|
|
||||||
Game: require('./structures/Presence').Game,
|
Game: require('./structures/Presence').Game,
|
||||||
GroupDMChannel: require('./structures/GroupDMChannel'),
|
GroupDMChannel: require('./structures/GroupDMChannel'),
|
||||||
Guild: require('./structures/Guild'),
|
Guild: require('./structures/Guild'),
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
const Constants = require('../util/Constants');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The final evaluated permissions for a member in a channel
|
|
||||||
*/
|
|
||||||
class EvaluatedPermissions {
|
|
||||||
constructor(member, raw) {
|
|
||||||
/**
|
|
||||||
* The member this permissions refer to
|
|
||||||
* @type {GuildMember}
|
|
||||||
*/
|
|
||||||
this.member = member;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A number representing the packed permissions
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
this.raw = raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an object mapping permission name, e.g. `READ_MESSAGES` to a boolean - whether the user
|
|
||||||
* can perform this or not.
|
|
||||||
* @returns {Object<string, boolean>}
|
|
||||||
*/
|
|
||||||
serialize() {
|
|
||||||
const serializedPermissions = {};
|
|
||||||
for (const permissionName in Constants.PermissionFlags) {
|
|
||||||
serializedPermissions[permissionName] = this.hasPermission(permissionName);
|
|
||||||
}
|
|
||||||
return serializedPermissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the user has a certain permission, e.g. `READ_MESSAGES`.
|
|
||||||
* @param {PermissionResolvable} permission The permission to check for
|
|
||||||
* @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permission
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
hasPermission(permission, explicit = false) {
|
|
||||||
permission = this.member.client.resolver.resolvePermission(permission);
|
|
||||||
if (!explicit && (this.raw & Constants.PermissionFlags.ADMINISTRATOR) > 0) return true;
|
|
||||||
return (this.raw & permission) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the user has all specified permissions.
|
|
||||||
* @param {PermissionResolvable[]} permissions The permissions to check for
|
|
||||||
* @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
hasPermissions(permissions, explicit = false) {
|
|
||||||
return permissions.every(p => this.hasPermission(p, explicit));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the user has all specified permissions, and lists any missing permissions.
|
|
||||||
* @param {PermissionResolvable[]} permissions The permissions to check for
|
|
||||||
* @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
|
|
||||||
* @returns {PermissionResolvable[]}
|
|
||||||
*/
|
|
||||||
missingPermissions(permissions, explicit = false) {
|
|
||||||
return permissions.filter(p => !this.hasPermission(p, explicit));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = EvaluatedPermissions;
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
const Channel = require('./Channel');
|
const Channel = require('./Channel');
|
||||||
const Role = require('./Role');
|
const Role = require('./Role');
|
||||||
const PermissionOverwrites = require('./PermissionOverwrites');
|
const PermissionOverwrites = require('./PermissionOverwrites');
|
||||||
const EvaluatedPermissions = require('./EvaluatedPermissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const Constants = require('../util/Constants');
|
|
||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,12 +50,12 @@ class GuildChannel extends Channel {
|
|||||||
* Gets the overall set of permissions for a user in this channel, taking into account roles and permission
|
* Gets the overall set of permissions for a user in this channel, taking into account roles and permission
|
||||||
* overwrites.
|
* overwrites.
|
||||||
* @param {GuildMemberResolvable} member The user that you want to obtain the overall permissions for
|
* @param {GuildMemberResolvable} member The user that you want to obtain the overall permissions for
|
||||||
* @returns {?EvaluatedPermissions}
|
* @returns {?Permissions}
|
||||||
*/
|
*/
|
||||||
permissionsFor(member) {
|
permissionsFor(member) {
|
||||||
member = this.client.resolver.resolveGuildMember(this.guild, member);
|
member = this.client.resolver.resolveGuildMember(this.guild, member);
|
||||||
if (!member) return null;
|
if (!member) return null;
|
||||||
if (member.id === this.guild.ownerID) return new EvaluatedPermissions(member, Constants.ALL_PERMISSIONS);
|
if (member.id === this.guild.ownerID) return new Permissions(member, Permissions.ALL);
|
||||||
|
|
||||||
let permissions = 0;
|
let permissions = 0;
|
||||||
|
|
||||||
@@ -71,10 +70,10 @@ class GuildChannel extends Channel {
|
|||||||
}
|
}
|
||||||
permissions |= allow;
|
permissions |= allow;
|
||||||
|
|
||||||
const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR);
|
const admin = Boolean(permissions & Permissions.FLAGS.ADMINISTRATOR);
|
||||||
if (admin) permissions = Constants.ALL_PERMISSIONS;
|
if (admin) permissions = Permissions.ALL;
|
||||||
|
|
||||||
return new EvaluatedPermissions(member, permissions);
|
return new Permissions(member, permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
overwritesFor(member, verified = false, roles = null) {
|
overwritesFor(member, verified = false, roles = null) {
|
||||||
@@ -151,14 +150,14 @@ class GuildChannel extends Channel {
|
|||||||
|
|
||||||
for (const perm in options) {
|
for (const perm in options) {
|
||||||
if (options[perm] === true) {
|
if (options[perm] === true) {
|
||||||
payload.allow |= Constants.PermissionFlags[perm] || 0;
|
payload.allow |= Permissions.FLAGS[perm] || 0;
|
||||||
payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
|
payload.deny &= ~(Permissions.FLAGS[perm] || 0);
|
||||||
} else if (options[perm] === false) {
|
} else if (options[perm] === false) {
|
||||||
payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
|
payload.allow &= ~(Permissions.FLAGS[perm] || 0);
|
||||||
payload.deny |= Constants.PermissionFlags[perm] || 0;
|
payload.deny |= Permissions.FLAGS[perm] || 0;
|
||||||
} else if (options[perm] === null) {
|
} else if (options[perm] === null) {
|
||||||
payload.allow &= ~(Constants.PermissionFlags[perm] || 0);
|
payload.allow &= ~(Permissions.FLAGS[perm] || 0);
|
||||||
payload.deny &= ~(Constants.PermissionFlags[perm] || 0);
|
payload.deny &= ~(Permissions.FLAGS[perm] || 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +293,7 @@ class GuildChannel extends Channel {
|
|||||||
*/
|
*/
|
||||||
get deletable() {
|
get deletable() {
|
||||||
return this.id !== this.guild.id &&
|
return this.id !== this.guild.id &&
|
||||||
this.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_CHANNELS);
|
this.permissionsFor(this.client.user).hasPermission(Permissions.FLAGS.MANAGE_CHANNELS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const TextBasedChannel = require('./interface/TextBasedChannel');
|
const TextBasedChannel = require('./interface/TextBasedChannel');
|
||||||
const Role = require('./Role');
|
const Role = require('./Role');
|
||||||
const EvaluatedPermissions = require('./EvaluatedPermissions');
|
const Permissions = require('../util/Permissions');
|
||||||
const Constants = require('../util/Constants');
|
const Constants = require('../util/Constants');
|
||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
const Presence = require('./Presence').Presence;
|
const Presence = require('./Presence').Presence;
|
||||||
@@ -241,20 +241,17 @@ class GuildMember {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The overall set of permissions for the guild member, taking only roles into account
|
* The overall set of permissions for the guild member, taking only roles into account
|
||||||
* @type {EvaluatedPermissions}
|
* @type {Permissions}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get permissions() {
|
get permissions() {
|
||||||
if (this.user.id === this.guild.ownerID) return new EvaluatedPermissions(this, Constants.ALL_PERMISSIONS);
|
if (this.user.id === this.guild.ownerID) return new Permissions(this, Permissions.ALL);
|
||||||
|
|
||||||
let permissions = 0;
|
let permissions = 0;
|
||||||
const roles = this.roles;
|
const roles = this.roles;
|
||||||
for (const role of roles.values()) permissions |= role.permissions;
|
for (const role of roles.values()) permissions |= role.permissions;
|
||||||
|
|
||||||
const admin = Boolean(permissions & Constants.PermissionFlags.ADMINISTRATOR);
|
return new Permissions(this, permissions);
|
||||||
if (admin) permissions = Constants.ALL_PERMISSIONS;
|
|
||||||
|
|
||||||
return new EvaluatedPermissions(this, permissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -266,7 +263,7 @@ class GuildMember {
|
|||||||
if (this.user.id === this.guild.ownerID) return false;
|
if (this.user.id === this.guild.ownerID) return false;
|
||||||
if (this.user.id === this.client.user.id) return false;
|
if (this.user.id === this.client.user.id) return false;
|
||||||
const clientMember = this.guild.member(this.client.user);
|
const clientMember = this.guild.member(this.client.user);
|
||||||
if (!clientMember.hasPermission(Constants.PermissionFlags.KICK_MEMBERS)) return false;
|
if (!clientMember.hasPermission(Permissions.FLAGS.KICK_MEMBERS)) return false;
|
||||||
return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
|
return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,14 +276,14 @@ class GuildMember {
|
|||||||
if (this.user.id === this.guild.ownerID) return false;
|
if (this.user.id === this.guild.ownerID) return false;
|
||||||
if (this.user.id === this.client.user.id) return false;
|
if (this.user.id === this.client.user.id) return false;
|
||||||
const clientMember = this.guild.member(this.client.user);
|
const clientMember = this.guild.member(this.client.user);
|
||||||
if (!clientMember.hasPermission(Constants.PermissionFlags.BAN_MEMBERS)) return false;
|
if (!clientMember.hasPermission(Permissions.FLAGS.BAN_MEMBERS)) return false;
|
||||||
return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
|
return clientMember.highestRole.comparePositionTo(this.highestRole) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns `channel.permissionsFor(guildMember)`. Returns evaluated permissions for a member in a guild channel.
|
* Returns `channel.permissionsFor(guildMember)`. Returns evaluated permissions for a member in a guild channel.
|
||||||
* @param {ChannelResolvable} channel Guild channel to use as context
|
* @param {ChannelResolvable} channel Guild channel to use as context
|
||||||
* @returns {?EvaluatedPermissions}
|
* @returns {?Permissions}
|
||||||
*/
|
*/
|
||||||
permissionsIn(channel) {
|
permissionsIn(channel) {
|
||||||
channel = this.client.resolver.resolveChannel(channel);
|
channel = this.client.resolver.resolveChannel(channel);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const MessageReaction = require('./MessageReaction');
|
|||||||
const Util = require('../util/Util');
|
const Util = require('../util/Util');
|
||||||
const Collection = require('../util/Collection');
|
const Collection = require('../util/Collection');
|
||||||
const Constants = require('../util/Constants');
|
const Constants = require('../util/Constants');
|
||||||
|
const Permissions = require('../util/Permissions');
|
||||||
let GuildMember;
|
let GuildMember;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -334,7 +335,7 @@ class Message {
|
|||||||
*/
|
*/
|
||||||
get deletable() {
|
get deletable() {
|
||||||
return this.author.id === this.client.user.id || (this.guild &&
|
return this.author.id === this.client.user.id || (this.guild &&
|
||||||
this.channel.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_MESSAGES)
|
this.channel.permissionsFor(this.client.user).hasPermission(Permissions.FLAGS.MANAGE_MESSAGES)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +346,7 @@ class Message {
|
|||||||
*/
|
*/
|
||||||
get pinnable() {
|
get pinnable() {
|
||||||
return !this.guild ||
|
return !this.guild ||
|
||||||
this.channel.permissionsFor(this.client.user).hasPermission(Constants.PermissionFlags.MANAGE_MESSAGES);
|
this.channel.permissionsFor(this.client.user).hasPermission(Permissions.FLAGS.MANAGE_MESSAGES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const Constants = require('../util/Constants');
|
const Permissions = require('../util/Permissions');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a role on Discord
|
* Represents a role on Discord
|
||||||
@@ -118,7 +118,7 @@ class Role {
|
|||||||
get editable() {
|
get editable() {
|
||||||
if (this.managed) return false;
|
if (this.managed) return false;
|
||||||
const clientMember = this.guild.member(this.client.user);
|
const clientMember = this.guild.member(this.client.user);
|
||||||
if (!clientMember.hasPermission(Constants.PermissionFlags.MANAGE_ROLES_OR_PERMISSIONS)) return false;
|
if (!clientMember.hasPermission(Permissions.FLAGS.MANAGE_ROLES_OR_PERMISSIONS)) return false;
|
||||||
return clientMember.highestRole.comparePositionTo(this) > 0;
|
return clientMember.highestRole.comparePositionTo(this) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -371,39 +371,6 @@ exports.DefaultAvatars = {
|
|||||||
RED: '1cbd08c76f8af6dddce02c5138971129',
|
RED: '1cbd08c76f8af6dddce02c5138971129',
|
||||||
};
|
};
|
||||||
|
|
||||||
const PermissionFlags = exports.PermissionFlags = {
|
|
||||||
CREATE_INSTANT_INVITE: 1 << 0,
|
|
||||||
KICK_MEMBERS: 1 << 1,
|
|
||||||
BAN_MEMBERS: 1 << 2,
|
|
||||||
ADMINISTRATOR: 1 << 3,
|
|
||||||
MANAGE_CHANNELS: 1 << 4,
|
|
||||||
MANAGE_GUILD: 1 << 5,
|
|
||||||
ADD_REACTIONS: 1 << 6,
|
|
||||||
|
|
||||||
READ_MESSAGES: 1 << 10,
|
|
||||||
SEND_MESSAGES: 1 << 11,
|
|
||||||
SEND_TTS_MESSAGES: 1 << 12,
|
|
||||||
MANAGE_MESSAGES: 1 << 13,
|
|
||||||
EMBED_LINKS: 1 << 14,
|
|
||||||
ATTACH_FILES: 1 << 15,
|
|
||||||
READ_MESSAGE_HISTORY: 1 << 16,
|
|
||||||
MENTION_EVERYONE: 1 << 17,
|
|
||||||
EXTERNAL_EMOJIS: 1 << 18,
|
|
||||||
|
|
||||||
CONNECT: 1 << 20,
|
|
||||||
SPEAK: 1 << 21,
|
|
||||||
MUTE_MEMBERS: 1 << 22,
|
|
||||||
DEAFEN_MEMBERS: 1 << 23,
|
|
||||||
MOVE_MEMBERS: 1 << 24,
|
|
||||||
USE_VAD: 1 << 25,
|
|
||||||
|
|
||||||
CHANGE_NICKNAME: 1 << 26,
|
|
||||||
MANAGE_NICKNAMES: 1 << 27,
|
|
||||||
MANAGE_ROLES_OR_PERMISSIONS: 1 << 28,
|
|
||||||
MANAGE_WEBHOOKS: 1 << 29,
|
|
||||||
MANAGE_EMOJIS: 1 << 30,
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.Colors = {
|
exports.Colors = {
|
||||||
DEFAULT: 0x000000,
|
DEFAULT: 0x000000,
|
||||||
AQUA: 0x1ABC9C,
|
AQUA: 0x1ABC9C,
|
||||||
@@ -431,8 +398,3 @@ exports.Colors = {
|
|||||||
DARK_BUT_NOT_BLACK: 0x2C2F33,
|
DARK_BUT_NOT_BLACK: 0x2C2F33,
|
||||||
NOT_QUITE_BLACK: 0x23272A,
|
NOT_QUITE_BLACK: 0x23272A,
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ALL_PERMISSIONS = 0;
|
|
||||||
for (const key in PermissionFlags) _ALL_PERMISSIONS |= PermissionFlags[key];
|
|
||||||
exports.ALL_PERMISSIONS = _ALL_PERMISSIONS;
|
|
||||||
exports.DEFAULT_PERMISSIONS = 104324097;
|
|
||||||
|
|||||||
249
src/util/Permissions.js
Normal file
249
src/util/Permissions.js
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
const Constants = require('../util/Constants');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structure that makes it easy to interact with a permission bitfield. All {@link GuildMember}s have a set of
|
||||||
|
* permissions in their guild, and each channel in the guild may also have {@link PermissionOverwrites} for the member
|
||||||
|
* that override their default permissions.
|
||||||
|
*/
|
||||||
|
class Permissions {
|
||||||
|
/**
|
||||||
|
* @param {GuildMember} [member] Member the permissions are for __**(deprecated)**__
|
||||||
|
* @param {number} bitfield Permissions bitfield to read from
|
||||||
|
*/
|
||||||
|
constructor(member, bitfield) {
|
||||||
|
/**
|
||||||
|
* Member the permissions are for
|
||||||
|
* @type {GuildMember}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
this.member = typeof member === 'object' ? member : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitfield of the packed permissions
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.bitfield = typeof member === 'object' ? bitfield : member;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitfield of the packed permissions
|
||||||
|
* @type {number}
|
||||||
|
* @see {@link Permissions#bitfield}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
get raw() {
|
||||||
|
return this.bitfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
set raw(raw) {
|
||||||
|
this.bitfield = raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the bitfield has a permission, or multiple permissions.
|
||||||
|
* @param {PermissionResolvable|PermissionResolvable[]} permission Permission(s) to check for
|
||||||
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
has(permission, checkAdmin = true) {
|
||||||
|
if (permission instanceof Array) return permission.every(p => this.has(p, checkAdmin));
|
||||||
|
permission = this.constructor.resolve(permission);
|
||||||
|
if (checkAdmin && (this.bitfield & this.constructor.FLAGS.ADMINISTRATOR) > 0) return true;
|
||||||
|
return (this.bitfield & permission) === permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all given permissions that are missing from the bitfield.
|
||||||
|
* @param {PermissionResolvable[]} permissions Permissions to check for
|
||||||
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
|
* @returns {PermissionResolvable[]}
|
||||||
|
*/
|
||||||
|
missing(permissions, checkAdmin = true) {
|
||||||
|
return permissions.filter(p => !this.has(p, checkAdmin));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds permissions to this one, creating a new instance to represent the new bitfield.
|
||||||
|
* @param {...PermissionResolvable} permissions Permissions to add
|
||||||
|
* @returns {Permissions}
|
||||||
|
*/
|
||||||
|
add(...permissions) {
|
||||||
|
let total = 0;
|
||||||
|
for (let p = 0; p < permissions.length; p++) {
|
||||||
|
const perm = this.constructor.resolve(permissions[p]);
|
||||||
|
if ((this.bitfield & perm) !== perm) total |= perm;
|
||||||
|
}
|
||||||
|
return new this.constructor(this.bitfield | total);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes permissions to this one, creating a new instance to represent the new bitfield.
|
||||||
|
* @param {...PermissionResolvable} permissions Permissions to remove
|
||||||
|
* @returns {Permissions}
|
||||||
|
*/
|
||||||
|
remove(...permissions) {
|
||||||
|
let total = 0;
|
||||||
|
for (let p = 0; p < permissions.length; p++) {
|
||||||
|
const perm = this.constructor.resolve(permissions[p]);
|
||||||
|
if ((this.bitfield & perm) === perm) total |= perm;
|
||||||
|
}
|
||||||
|
return new this.constructor(this.bitfield & ~total);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an object mapping permission name (like `READ_MESSAGES`) to a {@link boolean} indicating whether the
|
||||||
|
* permission is available.
|
||||||
|
* @param {boolean} [checkAdmin=true] Whether to allow the administrator permission to override
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
serialize(checkAdmin = true) {
|
||||||
|
const serialized = {};
|
||||||
|
for (const perm in this.constructor.FLAGS) serialized[perm] = this.has(perm, checkAdmin);
|
||||||
|
return serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the user has a certain permission, e.g. `READ_MESSAGES`.
|
||||||
|
* @param {PermissionResolvable} permission The permission to check for
|
||||||
|
* @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permission
|
||||||
|
* @returns {boolean}
|
||||||
|
* @see {@link Permissions#has}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
hasPermission(permission, explicit = false) {
|
||||||
|
return this.has(permission, !explicit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the user has all specified permissions.
|
||||||
|
* @param {PermissionResolvable[]} permissions The permissions to check for
|
||||||
|
* @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
|
||||||
|
* @returns {boolean}
|
||||||
|
* @see {@link Permissions#has}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
hasPermissions(permissions, explicit = false) {
|
||||||
|
return this.has(permissions, !explicit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the user has all specified permissions, and lists any missing permissions.
|
||||||
|
* @param {PermissionResolvable[]} permissions The permissions to check for
|
||||||
|
* @param {boolean} [explicit=false] Whether to require the user to explicitly have the exact permissions
|
||||||
|
* @returns {PermissionResolvable[]}
|
||||||
|
* @see {@link Permissions#missing}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
missingPermissions(permissions, explicit = false) {
|
||||||
|
return this.missing(permissions, !explicit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that can be resolved to give a permission number. This can be:
|
||||||
|
* - A string (see {@link Permissions.flags})
|
||||||
|
* - A permission number
|
||||||
|
* @typedef {string|number} PermissionResolvable
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves permissions to their numeric form.
|
||||||
|
* @param {PermissionResolvable|Permissions[]} permission - Permission(s) to resolve
|
||||||
|
* @returns {number|number[]}
|
||||||
|
*/
|
||||||
|
static resolve(permission) {
|
||||||
|
if (permission instanceof Array) return permission.map(p => this.resolve(p));
|
||||||
|
if (typeof permission === 'string') permission = this.FLAGS[permission];
|
||||||
|
if (typeof permission !== 'number' || permission < 1) throw new RangeError(Constants.Errors.NOT_A_PERMISSION);
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numeric permission flags. All available properties:
|
||||||
|
* - `ADMINISTRATOR` (implicitly has *all* permissions, and bypasses all channel overwrites)
|
||||||
|
* - `CREATE_INSTANT_INVITE` (create invitations to the guild)
|
||||||
|
* - `KICK_MEMBERS`
|
||||||
|
* - `BAN_MEMBERS`
|
||||||
|
* - `MANAGE_CHANNELS` (edit and reorder channels)
|
||||||
|
* - `MANAGE_GUILD` (edit the guild information, region, etc.)
|
||||||
|
* - `ADD_REACTIONS` (add new reactions to messages)
|
||||||
|
* - `READ_MESSAGES`
|
||||||
|
* - `SEND_MESSAGES`
|
||||||
|
* - `SEND_TTS_MESSAGES`
|
||||||
|
* - `MANAGE_MESSAGES` (delete messages and reactions)
|
||||||
|
* - `EMBED_LINKS` (links posted will have a preview embedded)
|
||||||
|
* - `ATTACH_FILES`
|
||||||
|
* - `READ_MESSAGE_HISTORY` (view messages that were posted prior to opening Discord)
|
||||||
|
* - `MENTION_EVERYONE`
|
||||||
|
* - `USE_EXTERNAL_EMOJIS` (use emojis from different guilds)
|
||||||
|
* - `EXTERNAL_EMOJIS` __**(deprecated)**__
|
||||||
|
* - `CONNECT` (connect to a voice channel)
|
||||||
|
* - `SPEAK` (speak in a voice channel)
|
||||||
|
* - `MUTE_MEMBERS` (mute members across all voice channels)
|
||||||
|
* - `DEAFEN_MEMBERS` (deafen members across all voice channels)
|
||||||
|
* - `MOVE_MEMBERS` (move members between voice channels)
|
||||||
|
* - `USE_VAD` (use voice activity detection)
|
||||||
|
* - `CHANGE_NICKNAME`
|
||||||
|
* - `MANAGE_NICKNAMES` (change other members' nicknames)
|
||||||
|
* - `MANAGE_ROLES`
|
||||||
|
* - `MANAGE_ROLES_OR_PERMISSIONS` __**(deprecated)**__
|
||||||
|
* - `MANAGE_WEBHOOKS`
|
||||||
|
* - `MANAGE_EMOJIS'
|
||||||
|
* @type {Object}
|
||||||
|
* @see {@link https://discordapp.com/developers/docs/topics/permissions}
|
||||||
|
*/
|
||||||
|
Permissions.FLAGS = {
|
||||||
|
CREATE_INSTANT_INVITE: 1 << 0,
|
||||||
|
KICK_MEMBERS: 1 << 1,
|
||||||
|
BAN_MEMBERS: 1 << 2,
|
||||||
|
ADMINISTRATOR: 1 << 3,
|
||||||
|
MANAGE_CHANNELS: 1 << 4,
|
||||||
|
MANAGE_GUILD: 1 << 5,
|
||||||
|
ADD_REACTIONS: 1 << 6,
|
||||||
|
|
||||||
|
READ_MESSAGES: 1 << 10,
|
||||||
|
SEND_MESSAGES: 1 << 11,
|
||||||
|
SEND_TTS_MESSAGES: 1 << 12,
|
||||||
|
MANAGE_MESSAGES: 1 << 13,
|
||||||
|
EMBED_LINKS: 1 << 14,
|
||||||
|
ATTACH_FILES: 1 << 15,
|
||||||
|
READ_MESSAGE_HISTORY: 1 << 16,
|
||||||
|
MENTION_EVERYONE: 1 << 17,
|
||||||
|
EXTERNAL_EMOJIS: 1 << 18,
|
||||||
|
USE_EXTERNAL_EMOJIS: 1 << 18,
|
||||||
|
|
||||||
|
CONNECT: 1 << 20,
|
||||||
|
SPEAK: 1 << 21,
|
||||||
|
MUTE_MEMBERS: 1 << 22,
|
||||||
|
DEAFEN_MEMBERS: 1 << 23,
|
||||||
|
MOVE_MEMBERS: 1 << 24,
|
||||||
|
USE_VAD: 1 << 25,
|
||||||
|
|
||||||
|
CHANGE_NICKNAME: 1 << 26,
|
||||||
|
MANAGE_NICKNAMES: 1 << 27,
|
||||||
|
MANAGE_ROLES: 1 << 28,
|
||||||
|
MANAGE_ROLES_OR_PERMISSIONS: 1 << 28,
|
||||||
|
MANAGE_WEBHOOKS: 1 << 29,
|
||||||
|
MANAGE_EMOJIS: 1 << 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitfield representing every permission combined
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Permissions.ALL = Object.values(Permissions.FLAGS).reduce((all, p) => all | p, 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitfield representing the default permissions for users
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
Permissions.DEFAULT = 104324097;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The final evaluated permissions for a member in a channel
|
||||||
|
* @class EvaluatedPermissions
|
||||||
|
* @see {@link Permissions}
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = Permissions;
|
||||||
Reference in New Issue
Block a user