Add helper for permission calculations

This commit is contained in:
Cadence Ember 2024-03-06 17:37:16 +13:00
parent 2fb68900c7
commit bf3d219716
4 changed files with 50 additions and 6 deletions

View File

@ -12,7 +12,7 @@ const utils = sync.require("../../m2d/converters/utils")
* @typedef ReactionRemoveRequest
* @prop {string} eventID
* @prop {string | null} mxid
* @prop {BigInt} [hash]
* @prop {bigint} [hash]
*/
/**

View File

@ -115,8 +115,7 @@ module.exports = {
if (!member) return
if (!("permission_overwrites" in channel)) continue
const permissions = dUtils.getPermissions(member.roles, guild.roles, client.user.id, channel.permission_overwrites)
const wants = BigInt(1 << 10) | BigInt(1 << 16) // VIEW_CHANNEL + READ_MESSAGE_HISTORY
if ((permissions & wants) !== wants) continue // We don't have permission to look back in this channel
if (!dUtils.hasAllPermissions(permissions, ["ViewChannel", "ReadMessageHistory"])) continue // We don't have permission to look back in this channel
/** More recent messages come first. */
// console.log(`[check missed messages] in ${channel.id} (${guild.name} / ${channel.name}) because its last message ${channel.last_message_id} is not in the database`)
@ -164,8 +163,7 @@ module.exports = {
// Permissions check
const permissions = dUtils.getPermissions(member.roles, guild.roles, client.user.id, channel.permission_overwrites)
const wants = BigInt(1 << 10) | BigInt(1 << 16) // VIEW_CHANNEL + READ_MESSAGE_HISTORY
if ((permissions & wants) !== wants) continue // We don't have permission to look up the pins in this channel
if (!dUtils.hasAllPermissions(permissions, ["ViewChannel", "ReadMessageHistory"])) continue // We don't have permission to look up the pins in this channel
const row = select("channel_room", ["room_id", "last_bridged_pin_timestamp"], {channel_id: channel.id}).get()
if (!row) continue // Only care about already bridged channels

View File

@ -137,7 +137,7 @@ const commands = [{
// Check CREATE_INSTANT_INVITE permission
assert(message.member)
const guildPermissions = utils.getPermissions(message.member.roles, guild.roles)
if (!(guildPermissions & BigInt(1))) {
if (!(guildPermissions & DiscordTypes.PermissionFlagsBits.CreateInstantInvite)) {
return discord.snow.channel.createMessage(channel.id, {
...ctx,
content: "You don't have permission to invite people to this Discord server."

View File

@ -1,6 +1,7 @@
// @ts-check
const DiscordTypes = require("discord-api-types/v10")
const assert = require("assert").strict
const EPOCH = 1420070400000
@ -49,6 +50,48 @@ function getPermissions(userRoles, guildRoles, userID, channelOverwrites) {
return allowed
}
/**
* Note: You can only provide one permission bit to permissionToCheckFor. To check multiple permissions, call `hasAllPermissions` or `hasSomePermissions`.
* It is designed like this to avoid developer error with bit manipulations.
*
* @param {bigint} resolvedPermissions
* @param {bigint} permissionToCheckFor
* @returns {boolean} whether the user has the requested permission
* @example
* const permissions = getPermissions(userRoles, guildRoles, userID, channelOverwrites)
* hasPermission(permissions, DiscordTypes.PermissionFlagsBits.ViewChannel)
*/
function hasPermission(resolvedPermissions, permissionToCheckFor) {
// Make sure permissionToCheckFor has exactly one permission in it
assert.equal(permissionToCheckFor.toString(2).match(/1/g), 1)
// Do the actual calculation
return (resolvedPermissions & permissionToCheckFor) === permissionToCheckFor
}
/**
* @param {bigint} resolvedPermissions
* @param {(keyof DiscordTypes.PermissionFlagsBits)[]} permissionsToCheckFor
* @returns {boolean} whether the user has any of the requested permissions
* @example
* const permissions = getPermissions(userRoles, guildRoles, userID, channelOverwrites)
* hasSomePermissions(permissions, ["ViewChannel", "ReadMessageHistory"])
*/
function hasSomePermissions(resolvedPermissions, permissionsToCheckFor) {
return permissionsToCheckFor.some(x => hasPermission(resolvedPermissions, DiscordTypes.PermissionFlagsBits[x]))
}
/**
* @param {bigint} resolvedPermissions
* @param {(keyof DiscordTypes.PermissionFlagsBits)[]} permissionsToCheckFor
* @returns {boolean} whether the user has all of the requested permissions
* @example
* const permissions = getPermissions(userRoles, guildRoles, userID, channelOverwrites)
* hasAllPermissions(permissions, ["ViewChannel", "ReadMessageHistory"])
*/
function hasAllPermissions(resolvedPermissions, permissionsToCheckFor) {
return permissionsToCheckFor.every(x => hasPermission(resolvedPermissions, DiscordTypes.PermissionFlagsBits[x]))
}
/**
* Command interaction responses have a webhook_id for some reason, but still have real author info of a real bot user in the server.
* @param {DiscordTypes.APIMessage} message
@ -69,6 +112,9 @@ function timestampToSnowflakeInexact(timestamp) {
}
module.exports.getPermissions = getPermissions
module.exports.hasPermission = hasPermission
module.exports.hasSomePermissions = hasSomePermissions
module.exports.hasAllPermissions = hasAllPermissions
module.exports.isWebhookMessage = isWebhookMessage
module.exports.snowflakeToTimestampExact = snowflakeToTimestampExact
module.exports.timestampToSnowflakeInexact = timestampToSnowflakeInexact