From 7513b4528ca1b6cf03b8af147feb73ea42a4f8e6 Mon Sep 17 00:00:00 2001 From: ckohen Date: Sat, 16 Oct 2021 15:27:52 -0700 Subject: [PATCH] feat(Permissions): add checkAdmin to permission overwrite checks (#6847) --- src/structures/GuildChannel.js | 23 +++++++++++++++-------- src/structures/Role.js | 5 +++-- src/structures/ThreadChannel.js | 5 +++-- typings/index.d.ts | 20 +++++++++++++------- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/structures/GuildChannel.js b/src/structures/GuildChannel.js index fb35e4d72..40beb25f5 100644 --- a/src/structures/GuildChannel.js +++ b/src/structures/GuildChannel.js @@ -153,13 +153,14 @@ class GuildChannel extends Channel { /** * Gets the overall set of permissions for a member or role in this channel, taking into account channel overwrites. * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for + * @param {boolean} [checkAdmin=true] Whether having `ADMINISTRATOR` will return all permissions * @returns {?Readonly} */ - permissionsFor(memberOrRole) { + permissionsFor(memberOrRole, checkAdmin = true) { const member = this.guild.members.resolve(memberOrRole); - if (member) return this.memberPermissions(member); + if (member) return this.memberPermissions(member, checkAdmin); const role = this.guild.roles.resolve(memberOrRole); - return role && this.rolePermissions(role); + return role && this.rolePermissions(role, checkAdmin); } overwritesFor(member, verified = false, roles = null) { @@ -191,16 +192,19 @@ class GuildChannel extends Channel { /** * Gets the overall set of permissions for a member in this channel, taking into account channel overwrites. * @param {GuildMember} member The member to obtain the overall permissions for + * @param {boolean} checkAdmin=true Whether having `ADMINISTRATOR` will return all permissions * @returns {Readonly} * @private */ - memberPermissions(member) { - if (member.id === this.guild.ownerId) return new Permissions(Permissions.ALL).freeze(); + memberPermissions(member, checkAdmin) { + if (checkAdmin && member.id === this.guild.ownerId) return new Permissions(Permissions.ALL).freeze(); const roles = member.roles.cache; const permissions = new Permissions(roles.map(role => role.permissions)); - if (permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); + if (checkAdmin && permissions.has(Permissions.FLAGS.ADMINISTRATOR)) { + return new Permissions(Permissions.ALL).freeze(); + } const overwrites = this.overwritesFor(member, true, roles); @@ -217,11 +221,14 @@ class GuildChannel extends Channel { /** * Gets the overall set of permissions for a role in this channel, taking into account channel overwrites. * @param {Role} role The role to obtain the overall permissions for + * @param {boolean} checkAdmin Whether having `ADMINISTRATOR` will return all permissions * @returns {Readonly} * @private */ - rolePermissions(role) { - if (role.permissions.has(Permissions.FLAGS.ADMINISTRATOR)) return new Permissions(Permissions.ALL).freeze(); + rolePermissions(role, checkAdmin) { + if (checkAdmin && role.permissions.has(Permissions.FLAGS.ADMINISTRATOR)) { + return new Permissions(Permissions.ALL).freeze(); + } const everyoneOverwrites = this.permissionOverwrites.cache.get(this.guild.id); const roleOverwrites = this.permissionOverwrites.cache.get(role.id); diff --git a/src/structures/Role.js b/src/structures/Role.js index 5e5ae88db..d96ce5704 100644 --- a/src/structures/Role.js +++ b/src/structures/Role.js @@ -232,12 +232,13 @@ class Role extends Base { * Returns `channel.permissionsFor(role)`. Returns permissions for a role in a guild channel, * taking into account permission overwrites. * @param {GuildChannel|Snowflake} channel The guild channel to use as context + * @param {boolean} [checkAdmin=true] Whether having `ADMINISTRATOR` will return all permissions * @returns {Readonly} */ - permissionsIn(channel) { + permissionsIn(channel, checkAdmin = true) { channel = this.guild.channels.resolve(channel); if (!channel) throw new Error('GUILD_CHANNEL_RESOLVE'); - return channel.rolePermissions(this); + return channel.rolePermissions(this, checkAdmin); } /** diff --git a/src/structures/ThreadChannel.js b/src/structures/ThreadChannel.js index dc8be9a29..70c2b5949 100644 --- a/src/structures/ThreadChannel.js +++ b/src/structures/ThreadChannel.js @@ -227,10 +227,11 @@ class ThreadChannel extends Channel { * Gets the overall set of permissions for a member or role in this thread's parent channel, taking overwrites into * account. * @param {GuildMemberResolvable|RoleResolvable} memberOrRole The member or role to obtain the overall permissions for + * @param {boolean} [checkAdmin=true] Whether having `ADMINISTRATOR` will return all permissions * @returns {?Readonly} */ - permissionsFor(memberOrRole) { - return this.parent?.permissionsFor(memberOrRole) ?? null; + permissionsFor(memberOrRole, checkAdmin) { + return this.parent?.permissionsFor(memberOrRole, checkAdmin) ?? null; } /** diff --git a/typings/index.d.ts b/typings/index.d.ts index d2bb8759b..e53b001a9 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -883,8 +883,8 @@ export class GuildBan extends Base { export abstract class GuildChannel extends Channel { public constructor(guild: Guild, data?: RawGuildChannelData, client?: Client, immediatePatch?: boolean); - private memberPermissions(member: GuildMember): Readonly; - private rolePermissions(role: Role): Readonly; + private memberPermissions(member: GuildMember, checkAdmin: boolean): Readonly; + private rolePermissions(role: Role, checkAdmin: boolean): Readonly; public readonly calculatedPosition: number; public readonly deletable: boolean; @@ -906,8 +906,11 @@ export abstract class GuildChannel extends Channel { public edit(data: ChannelData, reason?: string): Promise; public equals(channel: GuildChannel): boolean; public lockPermissions(): Promise; - public permissionsFor(memberOrRole: GuildMember | Role): Readonly; - public permissionsFor(memberOrRole: GuildMemberResolvable | RoleResolvable): Readonly | null; + public permissionsFor(memberOrRole: GuildMember | Role, checkAdmin?: boolean): Readonly; + public permissionsFor( + memberOrRole: GuildMemberResolvable | RoleResolvable, + checkAdmin?: boolean, + ): Readonly | null; public setName(name: string, reason?: string): Promise; public setParent(channel: CategoryChannelResolvable | null, options?: SetParentOptions): Promise; public setPosition(position: number, options?: SetChannelPositionOptions): Promise; @@ -1725,7 +1728,7 @@ export class Role extends Base { public edit(data: RoleData, reason?: string): Promise; public equals(role: Role): boolean; public iconURL(options?: StaticImageURLOptions): string | null; - public permissionsIn(channel: GuildChannel | Snowflake): Readonly; + public permissionsIn(channel: GuildChannel | Snowflake, checkAdmin?: boolean): Readonly; public setColor(color: ColorResolvable, reason?: string): Promise; public setHoist(hoist?: boolean, reason?: string): Promise; public setMentionable(mentionable?: boolean, reason?: string): Promise; @@ -2004,8 +2007,11 @@ export class ThreadChannel extends TextBasedChannel(Channel) { public edit(data: ThreadEditData, reason?: string): Promise; public join(): Promise; public leave(): Promise; - public permissionsFor(memberOrRole: GuildMember | Role): Readonly; - public permissionsFor(memberOrRole: GuildMemberResolvable | RoleResolvable): Readonly | null; + public permissionsFor(memberOrRole: GuildMember | Role, checkAdmin?: boolean): Readonly; + public permissionsFor( + memberOrRole: GuildMemberResolvable | RoleResolvable, + checkAdmin?: boolean, + ): Readonly | null; public fetchOwner(options?: BaseFetchOptions): Promise; public fetchStarterMessage(options?: BaseFetchOptions): Promise; public setArchived(archived?: boolean, reason?: string): Promise;