diff --git a/src/handlers/channel.ts b/src/handlers/channel.ts index 4545155e8..fedba0bd1 100644 --- a/src/handlers/channel.ts +++ b/src/handlers/channel.ts @@ -13,7 +13,7 @@ import { MessageContent, } from "../types/channel.ts"; import { Errors } from "../types/errors.ts"; -import { RawOverwrite } from "../types/guild.ts"; +import { PermissionOverwrite } from "../types/guild.ts"; import { MessageCreateOptions } from "../types/message.ts"; import { Permissions } from "../types/permission.ts"; import { endpoints } from "../utils/constants.ts"; @@ -23,7 +23,7 @@ import { botHasChannelPermissions } from "../utils/permissions.ts"; export function channelOverwriteHasPermission( guildID: string, id: string, - overwrites: RawOverwrite[], + overwrites: PermissionOverwrite[], permissions: Permissions[], ) { const overwrite = overwrites.find((perm) => perm.id === id) || @@ -31,8 +31,10 @@ export function channelOverwriteHasPermission( return permissions.every((perm) => { if (overwrite) { - if (BigInt(overwrite.deny) & BigInt(perm)) return false; - if (BigInt(overwrite.allow) & BigInt(perm)) return true; + const allowBits = calculateBits(overwrite.allow); + const denyBits = calculateBits(overwrite.deny); + if (BigInt(denyBits) & BigInt(perm)) return false; + if (BigInt(allowBits) & BigInt(perm)) return true; } return false; }); diff --git a/src/handlers/guild.ts b/src/handlers/guild.ts index bb96903fd..ebcdb7e6e 100644 --- a/src/handlers/guild.ts +++ b/src/handlers/guild.ts @@ -116,7 +116,7 @@ export async function createGuildChannel( (await RequestManager.post(endpoints.GUILD_CHANNELS(guild.id), { ...options, name, - permission_overwrites: options?.permission_overwrites?.map((perm) => ({ + permission_overwrites: options?.permissionOverwrites?.map((perm) => ({ ...perm, allow: perm.allow.reduce( diff --git a/src/structures/channel.ts b/src/structures/channel.ts index acc29ebb4..b36662d2b 100644 --- a/src/structures/channel.ts +++ b/src/structures/channel.ts @@ -1,5 +1,6 @@ import { cacheHandlers } from "../controllers/cache.ts"; import { ChannelCreatePayload } from "../types/channel.ts"; +import { PermissionOverwrite } from "../types/guild.ts"; import { Unpromise } from "../types/misc.ts"; import { calculatePermissions } from "../utils/permissions.ts"; @@ -14,6 +15,7 @@ export async function createChannel( rate_limit_per_user: rateLimitPerUser, parent_id: parentID, last_pin_timestamp: lastPinTimestamp, + permission_overwrites, ...rest } = data; @@ -32,13 +34,14 @@ export async function createChannel( /** The last time when a message was pinned in this channel */ lastPinTimestamp, /** The permission overwrites for this channel */ - permissions: data.permission_overwrites - ? data.permission_overwrites.map((perm) => ({ - ...perm, - allow: calculatePermissions(BigInt(perm.allow)), - deny: calculatePermissions(BigInt(perm.deny)), - })) - : [], + permissionOverwrites: + (data.permission_overwrites + ? data.permission_overwrites.map((perm) => ({ + ...perm, + allow: calculatePermissions(BigInt(perm.allow)), + deny: calculatePermissions(BigInt(perm.deny)), + })) + : []) as PermissionOverwrite[], /** Whether this channel is nsfw or not */ nsfw: data.nsfw || false, /** The mention of the channel */ diff --git a/src/types/guild.ts b/src/types/guild.ts index 905bee298..5addee40d 100644 --- a/src/types/guild.ts +++ b/src/types/guild.ts @@ -474,6 +474,12 @@ export interface RawOverwrite { deny: number; } +export interface PermissionOverwrite + extends Omit { + allow: Permission[]; + deny: Permission[]; +} + export interface ChannelCreateOptions { /** The type of the channel */ type?: ChannelTypes; @@ -488,7 +494,7 @@ export interface ChannelCreateOptions { /** The sorting position of the channel */ position?: number; /** The channel's permission overwrites */ - permission_overwrites?: Overwrite[]; + permissionOverwrites?: Overwrite[]; /** The id of the parent category for the channel */ parent_id?: string; /** Whether the channel is nsfw */ diff --git a/src/utils/permissions.ts b/src/utils/permissions.ts index 1623c6451..c466a48b8 100644 --- a/src/utils/permissions.ts +++ b/src/utils/permissions.ts @@ -2,7 +2,7 @@ import { cacheHandlers } from "../controllers/cache.ts"; import { botID } from "../module/client.ts"; import { Guild } from "../structures/guild.ts"; import { Role } from "../structures/role.ts"; -import { RawOverwrite } from "../types/guild.ts"; +import { PermissionOverwrite } from "../types/guild.ts"; import { Permission, Permissions } from "../types/permission.ts"; /** Checks if the member has this permission. If the member is an owner or has admin perms it will always be true. */ @@ -105,11 +105,11 @@ export async function hasChannelPermissions( const member = guild.members.get(memberID); if (!member) return false; - let memberOverwrite: RawOverwrite | undefined; - let everyoneOverwrite: RawOverwrite | undefined; - let rolesOverwrites: RawOverwrite[] = []; + let memberOverwrite: PermissionOverwrite | undefined; + let everyoneOverwrite: PermissionOverwrite | undefined; + let rolesOverwrites: PermissionOverwrite[] = []; - for (const overwrite of channel.permission_overwrites || []) { + for (const overwrite of channel.permissionOverwrites || []) { // If the overwrite on this channel is specific to this member if (overwrite.id === memberID) memberOverwrite = overwrite; // If it is the everyone role overwrite @@ -122,13 +122,16 @@ export async function hasChannelPermissions( // Member perms override everything so we must check them first if (memberOverwrite) { + const allowBits = calculateBits(memberOverwrite.allow); + const denyBits = calculateBits(memberOverwrite.deny); for (const perm of permissions) { // One of the necessary permissions is denied. Since this is main permission we can cancel if its denied. - if (BigInt(memberOverwrite.deny) & BigInt(perm)) return false; + if (BigInt(denyBits) & BigInt(perm)) return false; // Already allowed perm if (allowedPermissions.has(perm)) continue; + // This perm is allowed so we save it - if (BigInt(memberOverwrite.allow) & BigInt(perm)) { + if (BigInt(allowBits) & BigInt(perm)) { allowedPermissions.add(perm); } } @@ -140,17 +143,19 @@ export async function hasChannelPermissions( if (allowedPermissions.has(perm)) continue; for (const overwrite of rolesOverwrites) { + const allowBits = calculateBits(overwrite.allow); // This perm is allowed so we save it - if (BigInt(overwrite.allow) & BigInt(perm)) { + if (BigInt(allowBits) & BigInt(perm)) { allowedPermissions.add(perm); break; } + const denyBits = calculateBits(overwrite.deny); // If this role denies it we need to save and check if another role allows it, allows > deny - if (BigInt(overwrite.deny) & BigInt(perm)) { + if (BigInt(denyBits) & BigInt(perm)) { // This role denies his perm, but before denying we need to check all other roles if any allow as allow > deny const isAllowed = rolesOverwrites.some((o) => - BigInt(o.allow) & BigInt(perm) + BigInt(calculateBits(o.allow)) & BigInt(perm) ); if (isAllowed) continue; // This permission is in fact denied. Since Roles overrule everything below here we can cancel ou here @@ -160,13 +165,15 @@ export async function hasChannelPermissions( } if (everyoneOverwrite) { + const allowBits = calculateBits(everyoneOverwrite.allow); + const denyBits = calculateBits(everyoneOverwrite.deny); for (const perm of permissions) { // Already allowed perm if (allowedPermissions.has(perm)) continue; // One of the necessary permissions is denied. Since everyone overwrite overrides role perms we can cancel here - if (BigInt(everyoneOverwrite.deny) & BigInt(perm)) return false; + if (BigInt(denyBits) & BigInt(perm)) return false; // This perm is allowed so we save it - if (BigInt(everyoneOverwrite.allow) & BigInt(perm)) { + if (BigInt(allowBits) & BigInt(perm)) { allowedPermissions.add(perm); } } diff --git a/tests/mod.test.ts b/tests/mod.test.ts index 263519312..498ae37ad 100644 --- a/tests/mod.test.ts +++ b/tests/mod.test.ts @@ -168,18 +168,18 @@ Deno.test({ const channel = cache.channels.get(data.channelID); if (!channel) throw "Channel not found"; - if (!channel.permission_overwrites) throw "Channel overwrites not found."; + if (!channel.permissionOverwrites) throw "Channel overwrites not found."; const hasPerm = channelOverwriteHasPermission( data.guildID, data.roleID, - channel.permission_overwrites, + channel.permissionOverwrites, [Permissions.VIEW_CHANNEL, Permissions.SEND_MESSAGES], ); const missingPerm = channelOverwriteHasPermission( data.guildID, data.roleID, - channel.permission_overwrites, + channel.permissionOverwrites, [Permissions.USE_EXTERNAL_EMOJIS], );