Improve permission utils, make them bigint-aware

This commit is contained in:
Dragory 2020-08-07 00:39:52 +03:00
parent a404c7a97f
commit 8af64a6944
No known key found for this signature in database
GPG key ID: 5F387BA66DF8AAC1
11 changed files with 97 additions and 34 deletions

View file

@ -21,7 +21,7 @@ export const InitReactionRolesCmd = reactionRolesCmd({
},
async run({ message: msg, args, pluginData }) {
if (!canReadChannel(args.message.channel, msg.member.id)) {
if (!canReadChannel(args.message.channel, msg.member)) {
sendErrorMessage(pluginData, msg.channel, "Unknown message");
return;
}

View file

@ -30,7 +30,7 @@ export const ContextCmd = utilityCmd({
const channel = args.channel || args.message.channel;
const messageId = args.messageId || args.message.messageId;
if (!canReadChannel(channel, msg.member.id)) {
if (!canReadChannel(channel, msg.member)) {
sendErrorMessage(pluginData, msg.channel, "Message context not found");
return;
}

View file

@ -61,7 +61,7 @@ export const InfoCmd = utilityCmd({
// 4. Message
const messageTarget = await resolveMessageTarget(pluginData, value);
if (messageTarget) {
if (canReadChannel(messageTarget.channel, message.author.id)) {
if (canReadChannel(messageTarget.channel, message.member)) {
const embed = await getMessageInfoEmbed(pluginData, messageTarget.channel.id, messageTarget.messageId);
if (embed) {
message.channel.createMessage({ embed });

View file

@ -15,7 +15,7 @@ export const MessageInfoCmd = utilityCmd({
},
async run({ message, args, pluginData }) {
if (!canReadChannel(args.message.channel, message.author.id)) {
if (!canReadChannel(args.message.channel, message.member)) {
sendErrorMessage(pluginData, message.channel, "Unknown message");
return;
}

View file

@ -4,7 +4,6 @@ import { errorMessage } from "../../../utils";
import { getBaseUrl, sendErrorMessage } from "../../../pluginUtils";
import moment from "moment-timezone";
import { Constants, TextChannel } from "eris";
import { hasChannelPermissions } from "../../../utils/hasChannelPermissions";
import { canReadChannel } from "../../../utils/canReadChannel";
export const SourceCmd = utilityCmd({
@ -18,7 +17,7 @@ export const SourceCmd = utilityCmd({
},
async run({ message: cmdMessage, args, pluginData }) {
if (!canReadChannel(args.message.channel, cmdMessage.member.id)) {
if (!canReadChannel(args.message.channel, cmdMessage.member)) {
sendErrorMessage(pluginData, cmdMessage.channel, "Unknown message");
return;
}

View file

@ -1,10 +1,7 @@
import { Constants, GuildChannel } from "eris";
import { hasChannelPermissions } from "./hasChannelPermissions";
import { Constants, GuildChannel, Member } from "eris";
import { memberHasChannelPermissions } from "./memberHasChannelPermissions";
import { readChannelPermissions } from "./readChannelPermissions";
export function canReadChannel(channel: GuildChannel, memberId: string) {
const channelPermissions = channel.permissionsOf(memberId);
return hasChannelPermissions(channelPermissions, [
Constants.Permissions.readMessages,
Constants.Permissions.readMessageHistory,
]);
export function canReadChannel(channel: GuildChannel, member: Member) {
return memberHasChannelPermissions(member, channel, readChannelPermissions);
}

View file

@ -1,17 +0,0 @@
import { Constants, Permission } from "eris";
export function hasChannelPermissions(channelPermissions: Permission, permissions: number | number[]) {
if (Boolean(channelPermissions.allow & Constants.Permissions.administrator)) {
return true;
}
if (!Array.isArray(permissions)) {
permissions = [permissions];
}
for (const permission of permissions) {
if (!(channelPermissions.allow & permission)) return false;
}
return true;
}

View file

@ -0,0 +1,16 @@
import { Constants, Permission } from "eris";
/**
* @param resolvedPermissions A Permission object from e.g. GuildChannel#permissionsOf() or Member#permission
* @param requiredPermissions Bitmask of required permissions
*/
export function hasDiscordPermissions(resolvedPermissions: Permission, requiredPermissions: number | bigint) {
const allowedPermissions = BigInt(resolvedPermissions.allow);
const nRequiredPermissions = BigInt(requiredPermissions);
if (Boolean(allowedPermissions & BigInt(Constants.Permissions.administrator))) {
return true;
}
return Boolean(allowedPermissions & nRequiredPermissions);
}

View file

@ -1,8 +1,15 @@
import { Constants, GuildChannel, Member, Permission } from "eris";
import { PluginData } from "knub";
import { hasChannelPermissions } from "./hasChannelPermissions";
import { hasDiscordPermissions } from "./hasDiscordPermissions";
export function memberHasChannelPermissions(member: Member, channel: GuildChannel, permissions: number | number[]) {
/**
* @param requiredPermissions Bitmask of required permissions
*/
export function memberHasChannelPermissions(
member: Member,
channel: GuildChannel,
requiredPermissions: number | bigint,
) {
const memberChannelPermissions = channel.permissionsOf(member.id);
return hasChannelPermissions(memberChannelPermissions, permissions);
return hasDiscordPermissions(memberChannelPermissions, requiredPermissions);
}

View file

@ -0,0 +1,7 @@
import { Constants } from "eris";
/**
* Bitmask of permissions required to read messages in a channel
*/
export const readChannelPermissions =
BigInt(Constants.Permissions.readMessages) | BigInt(Constants.Permissions.readMessageHistory);

View file

@ -0,0 +1,54 @@
import { Constants, Permission } from "eris";
import { PluginData } from "knub";
import { hasDiscordPermissions } from "./hasDiscordPermissions";
import { LogsPlugin } from "../plugins/Logs/LogsPlugin";
import { LogType } from "../data/LogType";
const defaultErrorText = `Missing permissions.`;
const camelCaseToTitleCase = str =>
str
.replace(/([a-z])([A-Z])/g, "$1 $2")
.split(" ")
.map(w => w[0].toUpperCase() + w.slice(1))
.join(" ");
const permissionNumberToName: Map<bigint, string> = new Map();
for (const key in Constants.Permissions) {
permissionNumberToName.set(BigInt(Constants.Permissions[key]), camelCaseToTitleCase(key));
}
/**
*
* @param resolvedPermissions A Permission object from e.g. GuildChannel#permissionsOf() or Member#permission
* @param requiredPermissions Bitmask of required permissions
* @param errorText Custom error text
*/
export function verifyPermissions(
pluginData: PluginData<any>,
resolvedPermissions: Permission,
requiredPermissions: number | bigint,
errorText?: string,
) {
const nRequiredPermissions = BigInt(requiredPermissions);
if (!hasDiscordPermissions(resolvedPermissions, nRequiredPermissions)) {
const requiredPermissionNames = [];
for (const [permissionNumber, permissionName] of permissionNumberToName.entries()) {
if (nRequiredPermissions & permissionNumber) {
requiredPermissionNames.push(permissionName);
}
}
const logs = pluginData.getPlugin(LogsPlugin);
logs.log(LogType.BOT_ALERT, {
body: `${errorText ||
defaultErrorText} Please ensure I have the following permissions: **${requiredPermissionNames.join(
"**, **",
)}**`.trim(),
});
return false;
}
return true;
}