fix perms checks

This commit is contained in:
Erik 2022-07-28 10:45:24 +03:00
parent 2581d91481
commit 79f09fe03c
Signed by untrusted user: Navy.gif
GPG Key ID: 811EC0CD80E7E5FB
14 changed files with 110 additions and 56 deletions

View File

@ -22,10 +22,10 @@ class AuditLogObserver extends Observer {
} }
async guildBanAdd({ guild, user, guildWrapper: wrapper }) { async guildBanAdd({ user, guildWrapper: wrapper }) {
const settings = await wrapper.settings(); const settings = await wrapper.settings();
if (!settings.moderation.channel || !settings.moderation.infractions.includes('BAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier. if (!settings.moderation.channel || !settings.moderation.infractions.includes('BAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
const audit = await this._fetchFirstEntry(guild, user, 'MemberBanAdd'); const audit = await this._fetchFirstEntry(wrapper, user, 'MemberBanAdd');
if (!audit) return undefined; if (!audit) return undefined;
new Infraction(this.client, { new Infraction(this.client, {
type: 'BAN', type: 'BAN',
@ -37,10 +37,10 @@ class AuditLogObserver extends Observer {
}).handle(); }).handle();
} }
async guildBanRemove({ guild, user, guildWrapper: wrapper }) { async guildBanRemove({ user, guildWrapper: wrapper }) {
const settings = await wrapper.settings(); const settings = await wrapper.settings();
if (!settings.moderation.channel || !settings.moderation.infractions.includes('UNBAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier. if (!settings.moderation.channel || !settings.moderation.infractions.includes('UNBAN')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
const audit = await this._fetchFirstEntry(guild, user, 'MemberBanRemove'); const audit = await this._fetchFirstEntry(wrapper, user, 'MemberBanRemove');
if (!audit) return undefined; if (!audit) return undefined;
new Infraction(this.client, { new Infraction(this.client, {
type: 'UNBAN', type: 'UNBAN',
@ -56,7 +56,7 @@ class AuditLogObserver extends Observer {
const { guildWrapper: wrapper } = member; const { guildWrapper: wrapper } = member;
const settings = await wrapper.settings(); const settings = await wrapper.settings();
if (!settings.moderation.channel || !settings.moderation.infractions.includes('KICK')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier. if (!settings.moderation.channel || !settings.moderation.infractions.includes('KICK')) return undefined; //This is checked by the infraction handling, but it may save resources if checked earlier.
const audit = await this._fetchFirstEntry(member.guild, member.user, 'MemberKick'); const audit = await this._fetchFirstEntry(wrapper, member.user, 'MemberKick');
if (!audit) return undefined; if (!audit) return undefined;
new Infraction(this.client, { new Infraction(this.client, {
type: 'KICK', type: 'KICK',
@ -123,7 +123,7 @@ class AuditLogObserver extends Observer {
const mutedRole = settings.mute.role; const mutedRole = settings.mute.role;
if (!mutedRole) return undefined; if (!mutedRole) return undefined;
const audit = await this._fetchFirstEntry(newMember.guild, newMember.user, 'MemberRoleUpdate'); const audit = await this._fetchFirstEntry(wrapper, newMember.user, 'MemberRoleUpdate');
if (!audit) return undefined; if (!audit) return undefined;
let type = null; let type = null;
@ -148,7 +148,8 @@ class AuditLogObserver extends Observer {
} }
async _fetchFirstEntry(guild, user, type, subtype = null) { async _fetchFirstEntry(guild, user, type, subtype = null) {
if (!guild.members.me.permissions.has('ViewAuditLog')) return null; const me = await guild.resolveMember(this.client.user);
if (!me.permissions.has('ViewAuditLog')) return null;
type = AuditLogEvent[type]; type = AuditLogEvent[type];
const audit = await guild.fetchAuditLogs({ limit: 1, type }); const audit = await guild.fetchAuditLogs({ limit: 1, type });
if (audit.entries.size === 0) return null; if (audit.entries.size === 0) return null;

View File

@ -133,7 +133,7 @@ module.exports = class AutoModeration extends Observer {
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return; if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages'); const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
if (missing.length) { if (missing.length) {
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'word', permissions: missing }); this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'word', permissions: missing });
return; return;
@ -432,7 +432,7 @@ module.exports = class AutoModeration extends Observer {
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return; if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages'); const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
if (missing.length) { if (missing.length) {
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'link', permissions: missing }); this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'link', permissions: missing });
return; return;
@ -454,9 +454,10 @@ module.exports = class AutoModeration extends Observer {
let log = `${guild.name} Link filter debug:`; let log = `${guild.name} Link filter debug:`;
for (const match of matches) { for (const match of matches) {
const { domain } = match.match(this.regex.linkReg).groups; let { domain } = match.match(this.regex.linkReg).groups;
domain = domain.toLowerCase();
// Invites are filtered separately // Invites are filtered separately
if (domain.toLowerCase() === 'discord.gg') continue; if (domain === 'discord.gg') continue;
log += `\nMatched link ${match}: `; log += `\nMatched link ${match}: `;
const predicate = (dom) => { const predicate = (dom) => {
@ -550,13 +551,13 @@ module.exports = class AutoModeration extends Observer {
const member = message.member || await guild.members.fetch(author.id).catch(() => null); const member = message.member || await guild.members.fetch(author.id).catch(() => null);
const settings = await wrapper.settings(); const settings = await wrapper.settings();
const { invitefilter: setting } = settings; const { invitefilter: setting } = settings;
const { bypass, ignore, actions, silent, enabled, whitelist } = setting; const { bypass, ignore, actions, silent, enabled, whitelist = [] } = setting;
if (!enabled) return; if (!enabled) return;
const roles = member?.roles.cache.map((r) => r.id) || []; const roles = member?.roles.cache.map((r) => r.id) || [];
if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return; if (roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages'); const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
if (missing.length) { if (missing.length) {
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'invite', permissions: missing }); this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'invite', permissions: missing });
return; return;
@ -613,7 +614,7 @@ module.exports = class AutoModeration extends Observer {
if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return; if (!enabled || roles.some((r) => bypass.includes(r)) || ignore.includes(channel.id)) return;
const missing = channel.permissionsFor(guild.members.me).missing('ManageMessages'); const missing = channel.permissionsFor(this.client.user).missing('ManageMessages');
if (missing.length) { if (missing.length) {
this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'mention', permissions: missing }); this.client.emit('filterMissingPermissions', { channel, guild: wrapper, filter: 'mention', permissions: missing });
return; return;

View File

@ -1,5 +1,5 @@
/* eslint-disable no-labels */ /* eslint-disable no-labels */
const { WebhookClient, AttachmentBuilder } = require('discord.js'); const { WebhookClient, AttachmentBuilder, AuditLogEvent } = require('discord.js');
const { stripIndents } = require('common-tags'); const { stripIndents } = require('common-tags');
const moment = require('moment'); const moment = require('moment');
const { inspect } = require('util'); const { inspect } = require('util');
@ -103,22 +103,23 @@ class GuildLogger extends Observer {
const hook = await guild.getWebhook('messages'); const hook = await guild.getWebhook('messages');
if (!hook) { if (!hook) {
this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`); // this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
return this.client.emit('logError', { guild, logger: 'threadLogger', reason: 'MSGLOG_NO_HOOK' }); return this.client.emit('logError', { guild, logger: 'threadLogger', reason: 'MSGLOG_NO_HOOK' });
} }
let actor = null; let actor = null;
const auditLogPerm = guild.members.me.permissions.has('ViewAuditLog'); const me = await this.client.resolver.resolveMember(this.client.user, null, guild);
const auditLogPerm = me.permissions.has('ViewAuditLog');
if (type === 'CREATE') actor = owner; if (type === 'CREATE') actor = owner;
else if (type === 'DELETE' && auditLogPerm) { else if (type === 'DELETE' && auditLogPerm) {
const auditLogs = await guild.fetchAuditLogs({ type: 'THREAD_DELETE', limit: 1 }); const auditLogs = await guild.fetchAuditLogs({ type: AuditLogEvent.ThreadDelete, limit: 1 });
const log = auditLogs.entries.first(); const log = auditLogs.entries.first();
if (log) { if (log) {
if (thread.id !== log.target.id) return; if (thread.id !== log.target.id) return;
actor = log.executor; actor = log.executor;
} }
} else if (['ARCHIVE', 'UNARCHIVE'].includes(type) && auditLogPerm) { } else if (['ARCHIVE', 'UNARCHIVE'].includes(type) && auditLogPerm) {
const auditLogs = await guild.fetchAuditLogs({ type: 'THREAD_UPDATE', limit: 1 }); const auditLogs = await guild.fetchAuditLogs({ type: AuditLogEvent.ThreadUpdate, limit: 1 });
const log = auditLogs.entries.first(); const log = auditLogs.entries.first();
if (log) { if (log) {
if (thread.id !== log.target.id) return; if (thread.id !== log.target.id) return;
@ -178,7 +179,7 @@ class GuildLogger extends Observer {
const hook = await wrapper.getWebhook('messages'); const hook = await wrapper.getWebhook('messages');
if (!hook) { if (!hook) {
this.logger.debug(`Missing messageLog hook in ${wrapper.name} (${wrapper.id})`); // this.logger.debug(`Missing messageLog hook in ${wrapper.name} (${wrapper.id})`);
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' }); return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
} }
@ -340,13 +341,13 @@ class GuildLogger extends Observer {
const { ignore, bypass } = chatlogs; const { ignore, bypass } = chatlogs;
if (ignore.includes(channel.id)) return; if (ignore.includes(channel.id)) return;
const missing = logChannel.permissionsFor(guild.members.me).missing(['ViewChannel', 'EmbedLinks', 'SendMessages', 'ManageWebhooks']); const missing = logChannel.permissionsFor(this.client.user).missing(['ViewChannel', 'EmbedLinks', 'SendMessages', 'ManageWebhooks']);
if (missing.length) if (missing.length)
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } }); return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_PERMS', params: { missing: missing.join(', ') } });
const hook = await wrapper.getWebhook('messages'); const hook = await wrapper.getWebhook('messages');
if (!hook) { if (!hook) {
this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`); // this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' }); return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
} }
@ -364,6 +365,7 @@ class GuildLogger extends Observer {
content = Util.escapeMarkdown(content); content = Util.escapeMarkdown(content);
if (author.bot) continue; if (author.bot) continue;
// TODO: Apparently the cache for this doesn't work properly and the bot hits rate limits occasionally, make own cache at some point
if (!member || member.partial) member = await guild.members.fetch(message.author.id).catch(() => { if (!member || member.partial) member = await guild.members.fetch(message.author.id).catch(() => {
return false; return false;
}); });
@ -533,7 +535,7 @@ class GuildLogger extends Observer {
const hook = await wrapper.getWebhook('messages'); const hook = await wrapper.getWebhook('messages');
if (!hook) { if (!hook) {
this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`); // this.logger.debug(`Missing messageLog hook in ${guild.name} (${guild.id})`);
return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' }); return this.client.emit('logError', { guild: wrapper, logger: 'messageLogger', reason: 'MSGLOG_NO_HOOK' });
} }
@ -710,7 +712,7 @@ class GuildLogger extends Observer {
async memberLeave(member) { async memberLeave(member) {
const { guild, guildWrapper: wrapper } = member; const { guildWrapper: wrapper } = member;
const settings = await wrapper.settings(); const settings = await wrapper.settings();
const setting = settings.members; const setting = settings.members;
if (!setting.channel || !setting.enabled) return; if (!setting.channel || !setting.enabled) return;
@ -732,7 +734,7 @@ class GuildLogger extends Observer {
if (oldMember.nickname === newMember.nickname) return; if (oldMember.nickname === newMember.nickname) return;
const { guild, user, guildWrapper: wrapper } = oldMember; const { user, guildWrapper: wrapper } = oldMember;
const settings = await wrapper.settings(); const settings = await wrapper.settings();
const setting = settings.nicknames; const setting = settings.nicknames;
if (!setting.channel || !setting.enabled) return; if (!setting.channel || !setting.enabled) return;

View File

@ -0,0 +1,31 @@
const { Observer } = require("../../interfaces");
class Metrics extends Observer {
constructor(client) {
super(client, {
name: 'metrics',
priority: 10,
disabled: false
});
this.hooks = [
['apiRequest', this.request.bind(this)],
['apiResponse', this.response.bind(this)]
];
this.cache = {};
}
async request(request) {
// console.log(request);
}
async response(request, response) {
// console.log(response, await response.json(), response.status);
}
}
module.exports = Metrics;

View File

@ -51,7 +51,8 @@ class UtilityHook extends Observer {
const { guildWrapper: guild } = member; const { guildWrapper: guild } = member;
const settings = await guild.settings(); const settings = await guild.settings();
const setting = settings.mute; const setting = settings.mute;
if (!guild.members.me.permissions.has('ManageRoles')) return; const me = await guild.resolveMember(this.client.user);
if (!me.permissions.has('ManageRoles')) return;
const infraction = await this.client.storageManager.mongodb.infractions.findOne({ const infraction = await this.client.storageManager.mongodb.infractions.findOne({
duration: { $gt: 0 }, duration: { $gt: 0 },
@ -79,7 +80,7 @@ class UtilityHook extends Observer {
if (managed) { if (managed) {
await member.roles.add(setting.role, 'automute upon rejoin, type 1'); await member.roles.add(setting.role, 'automute upon rejoin, type 1');
await member.roles.remove(remove, 'removing excess roles for type 1 mute'); await member.roles.remove(remove, 'removing excess roles for type 1 mute');
} else await member.roles.set(setting.role, 'automute upon join, type 1'); } else await member.roles.set([role], 'automute upon join, type 1');
} else if (infraction.data.muteType === 2) { } else if (infraction.data.muteType === 2) {
@ -100,7 +101,8 @@ class UtilityHook extends Observer {
const settings = await guild.settings(); const settings = await guild.settings();
const setting = settings.stickyrole; const setting = settings.stickyrole;
if (!setting.roles.length || guild.premium < 1) return; if (!setting.roles.length || guild.premium < 1) return;
if (!guild.members.me.permissions.has('ManageRoles')) return; const me = await guild.resolveMember(this.client.user);
if (!me.permissions.has('ManageRoles')) return;
const data = await this.client.storageManager.mongodb.role_cache.findOne({ guild: guild.id, member: member.id }); const data = await this.client.storageManager.mongodb.role_cache.findOne({ guild: guild.id, member: member.id });
if (!data) return; if (!data) return;
@ -115,7 +117,8 @@ class UtilityHook extends Observer {
const settings = await guild.settings(); const settings = await guild.settings();
const setting = settings.autorole; const setting = settings.autorole;
if (!setting.enabled) return; if (!setting.enabled) return;
if (!guild.members.me.permissions.has('ManageRoles')) return; const me = await guild.resolveMember(this.client.user);
if (!me.permissions.has('ManageRoles')) return;
const _roles = await guild.resolveRoles(setting.roles); const _roles = await guild.resolveRoles(setting.roles);
const roles = _roles.map((r) => r.id); const roles = _roles.map((r) => r.id);
@ -153,7 +156,8 @@ class UtilityHook extends Observer {
const { guild } = invite; const { guild } = invite;
if (!guild) return; if (!guild) return;
if (!guild.members.me.permissions.has('ManageGuild')) return; const me = await this.client.resolver.resolveMember(this.client.user, null, guild);
if (!me.permissions.has('ManageGuild')) return;
if (!guild.invites) guild.invites = await guild.fetchInvites(); if (!guild.invites) guild.invites = await guild.fetchInvites();
guild.invites.set(invite.code, invite); guild.invites.set(invite.code, invite);
@ -163,7 +167,8 @@ class UtilityHook extends Observer {
const { guild } = invite; const { guild } = invite;
if (!guild) return; if (!guild) return;
if (!guild.members.me.permissions.has('ManageGuild')) return; const me = await this.client.resolver.resolveMember(this.client.user, null, guild);
if (!me.permissions.has('ManageGuild')) return;
if (!guild.invites) guild.invites = await guild.fetchInvites(); if (!guild.invites) guild.invites = await guild.fetchInvites();
guild.invites.delete(invite.code); guild.invites.delete(invite.code);
@ -203,7 +208,8 @@ class UtilityHook extends Observer {
!selfrole.channel || selfrole.channel !== channel.id || !selfrole.channel || selfrole.channel !== channel.id ||
!selfrole.roles.length) return; !selfrole.roles.length) return;
const missing = guild.members.me.permissions.missing(['ManageRoles']); const me = await guild.resolveMember(this.client.user);
const missing = me.permissions.missing(['ManageRoles']);
if (missing.length) if (missing.length)
return this.client.emit('utilityError', { guild, utility: 'selfrole', reason: 'UTILITY_SELFROLE_PERMS', params: { missing: missing.join(', ') } }); return this.client.emit('utilityError', { guild, utility: 'selfrole', reason: 'UTILITY_SELFROLE_PERMS', params: { missing: missing.join(', ') } });

View File

@ -53,7 +53,8 @@ class AddroleInfraction extends Infraction {
const { grantable } = await this.guild.settings(); const { grantable } = await this.guild.settings();
let filtered = []; let filtered = [];
const { highest: clientHighest } = this.guild.members.me.roles; const me = await this.guild.resolveMember(this.client.user);
const { highest: clientHighest } = me.roles;
filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0); filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0);
if (filtered.length === 0) { if (filtered.length === 0) {
return super._fail('C_ADDROLE_ROLEHIERARCHYBOT'); return super._fail('C_ADDROLE_ROLEHIERARCHYBOT');

View File

@ -140,7 +140,7 @@ class LockdownInfraction extends Infraction {
async verify() { async verify() {
const perms = this.target.permissionsFor(this.guild.members.me); const perms = this.target.permissionsFor(this.client.user);
if(perms.missing('ManageRoles').length) return this._fail('INFRACTION_LOCKDOWN_MISSING_PERMS'); if(perms.missing('ManageRoles').length) return this._fail('INFRACTION_LOCKDOWN_MISSING_PERMS');
return super._verify(); return super._verify();

View File

@ -48,6 +48,8 @@ class MuteInfraction extends Infraction {
role = await this.client.resolver.resolveRole(setting.role, true, this.guild); role = await this.client.resolver.resolveRole(setting.role, true, this.guild);
} }
const me = await this.guild.resolveMember(this.client.user);
let removed = []; let removed = [];
switch (setting.type) { switch (setting.type) {
case 0: case 0:
@ -60,12 +62,12 @@ class MuteInfraction extends Infraction {
break; break;
case 1: case 1:
removed = this.member.roles.cache.filter((r) => !r.managed && removed = this.member.roles.cache.filter((r) => !r.managed &&
r.comparePositionTo(this.guild.members.me.roles.highest) < 0 && r.comparePositionTo(me.roles.highest) < 0 &&
r.id !== this.guild.id); r.id !== this.guild.id);
try { try {
await this.member.roles.set([ await this.member.roles.set([
...this.member.roles.cache.filter((r) => r.managed || ...this.member.roles.cache.filter((r) => r.managed ||
r.comparePositionTo(this.guild.members.me.roles.highest) >= 0 || r.comparePositionTo(me.roles.highest) >= 0 ||
r.id === this.guild.id).values(), r.id === this.guild.id).values(),
role role
], this._reason); ], this._reason);
@ -76,11 +78,11 @@ class MuteInfraction extends Infraction {
break; break;
case 2: case 2:
removed = this.member.roles.cache.filter((r) => !r.managed && removed = this.member.roles.cache.filter((r) => !r.managed &&
r.comparePositionTo(this.guild.members.me.roles.highest) < 0 && r.comparePositionTo(me.roles.highest) < 0 &&
r.id !== this.guild.id); r.id !== this.guild.id);
try { try {
await this.member.roles.set(this.member.roles.cache.filter((r) => r.managed || await this.member.roles.set(this.member.roles.cache.filter((r) => r.managed ||
r.comparePositionTo(this.guild.members.me.roles.highest) >= 0 || r.comparePositionTo(me.roles.highest) >= 0 ||
r.id === this.guild.id), this._reason); r.id === this.guild.id), this._reason);
} catch (error) { } catch (error) {
this.client.logger.error(`Mute infraction failed to calculate removeable roles, might want to check this out.\n${error.stack || error}`); this.client.logger.error(`Mute infraction failed to calculate removeable roles, might want to check this out.\n${error.stack || error}`);
@ -96,6 +98,8 @@ class MuteInfraction extends Infraction {
} }
} }
if (this.member.voice.channel) await this.member.voice.disconnect(this._reason);
this.data = { this.data = {
removedRoles: removed.map((r) => r.id), removedRoles: removed.map((r) => r.id),
muteType: setting.type, muteType: setting.type,
@ -107,7 +111,7 @@ class MuteInfraction extends Infraction {
if (callback) { if (callback) {
this.data.removedRoles = [...new Set([...this.data.removedRoles, ...callback.infraction.data.removedRoles])]; this.data.removedRoles = [...new Set([...this.data.removedRoles, ...callback.infraction.data.removedRoles])];
this.client.moderationManager.removeCallback(callback.infraction); this.client.moderationManager.removeCallback(callback.infraction, true);
} }
// if(callbacks.size > 0) callbacks.map((c) => this.client.moderationManager._removeExpiration(c)); // if(callbacks.size > 0) callbacks.map((c) => this.client.moderationManager._removeExpiration(c));
@ -134,10 +138,12 @@ class MuteInfraction extends Infraction {
return this._fail('COMMAND_MUTE_INVALIDMUTEROLE', true); return this._fail('COMMAND_MUTE_INVALIDMUTEROLE', true);
} }
} }
const me = await this.guild.resolveMember(this.client.user);
if (settings.mute.type === 3) { if (settings.mute.type === 3) {
if (this.guild.members.me.permissions.missing('ModerateMembers').length) return this._fail('COMMAND_MUTE_MISSING_MODERATE_PERM', true); if (me.permissions.missing('ModerateMembers').length) return this._fail('COMMAND_MUTE_MISSING_MODERATE_PERM', true);
if (me.roles.highest.position <= this.member.roles.highest.position) return this._fail('COMMAND_MUTE_HIERARCHY_ERROR');
// if (!this.duration && !settings.mute.default) // if (!this.duration && !settings.mute.default)
} else if (this.guild.members.me.permissions.missing('ManageRoles').length) return this._fail('COMMAND_MUTE_MISSING_MANAGEROLE_PERM'); } else if (me.permissions.missing('ManageRoles').length) return this._fail('COMMAND_MUTE_MISSING_MANAGEROLE_PERM');
return super._verify(); return super._verify();

View File

@ -82,7 +82,8 @@ class NicknameInfraction extends Infraction {
async verify() { async verify() {
const { highest } = this.member.roles; const { highest } = this.member.roles;
if (highest.comparePositionTo(this.guild.members.me.roles.highest) > 0 || !this.guild.members.me.permissions.has('ManageNicknames')) { const me = await this.guild.resolveMember(this.client.user);
if (highest.comparePositionTo(me.roles.highest) > 0 || !me.permissions.has('ManageNicknames')) {
return this._fail('C_NICKNAME_MISSINGPERMISSIONS'); return this._fail('C_NICKNAME_MISSINGPERMISSIONS');
} }

View File

@ -53,7 +53,8 @@ class RemoveroleInfraction extends Infraction {
const { grantable } = await this.guild.settings(); const { grantable } = await this.guild.settings();
let filtered = []; let filtered = [];
const { highest: clientHighest } = this.guild.members.me.roles; const me = await this.guild.resolveMember(this.client.user);
const { highest: clientHighest } = me.roles;
filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0); filtered = this.data.roles.filter((r) => r.comparePositionTo(clientHighest) < 0);
if (filtered.length === 0) { if (filtered.length === 0) {
return super._fail('C_REMOVEROLE_ROLEHIERARCHYBOT'); return super._fail('C_REMOVEROLE_ROLEHIERARCHYBOT');

View File

@ -39,7 +39,7 @@ class UnbanInfraction extends Infraction {
const callbacks = this.client.moderationManager.callbacks.filter((c) => c.infraction.type === 'BAN' const callbacks = this.client.moderationManager.callbacks.filter((c) => c.infraction.type === 'BAN'
&& c.infraction.target === this.target.id); && c.infraction.target === this.target.id);
if (callbacks.size > 0) callbacks.map((c) => this.client.moderationManager.removeCallback(c.infraction)); if (callbacks.size > 0) callbacks.map((c) => this.client.moderationManager.removeCallback(c.infraction, true));
await this.handle(); await this.handle();
return this._succeed(); return this._succeed();

View File

@ -95,7 +95,7 @@ class UnlockdownInfraction extends Infraction {
async verify() { async verify() {
const perms = this.target.permissionsFor(this.guild.members.me); const perms = this.target.permissionsFor(this.client.user);
if (perms.missing('ManageRoles').length) return this._fail('INFRACTION_LOCKDOWN_MISSING_PERMS'); if (perms.missing('ManageRoles').length) return this._fail('INFRACTION_LOCKDOWN_MISSING_PERMS');
return super._verify(); return super._verify();

View File

@ -321,7 +321,9 @@ module.exports = class FilterUtility {
matched: true, matched: true,
_matcher: _word, _matcher: _word,
matcher: `fuzzy [\`${_word}\`, \`${sim}\`, \`${threshold}\`]`, matcher: `fuzzy [\`${_word}\`, \`${sim}\`, \`${threshold}\`]`,
type: 'fuzzy' type: 'fuzzy',
_threshold: threshold,
_sim: sim
}; };
} }

View File

@ -206,7 +206,7 @@ class SettingsMigrator {
stickyrole: result.stickyrole ? { ...result.stickyrole, enabled: Boolean(result.stickyrole.roles.length) } : undefined, stickyrole: result.stickyrole ? { ...result.stickyrole, enabled: Boolean(result.stickyrole.roles.length) } : undefined,
welcomer: result.welcomer, welcomer: result.welcomer,
commands: { disabled: result.disabledCommands, custom: {} }, commands: { disabled: result.disabledCommands, custom: {} },
prefix: result.prefix textcommands: { prefix: result.prefix, enabled: false }
}; };
return settings; return settings;
} }
@ -287,14 +287,15 @@ class SettingsMigrator {
}; };
if (linkfilter) settings.linkfilter = { if (linkfilter) settings.linkfilter = {
enabled: result.linkfilter?.enabled || false, enabled: linkfilter.enabled || false,
silent: result.linkfilter?.silent || false, silent: linkfilter.silent || false,
ignore: result.linkfilter?.channels || [], ignore: linkfilter.channels || [],
bypass: result.linkfilter?.roles || [], bypass: linkfilter.roles || [],
actions: [], actions: [],
whitelist: result.linkfilter?.whitelist === true ? result.linkfilter.filter : [], whitelist: linkfilter.whitelist === true ? linkfilter.filter : [],
blacklist: result.linkfilter?.whitelist === false ? result.linkfilter.filter : [], blacklist: linkfilter.whitelist === false ? linkfilter.filter : [],
greylist: [] greylist: [],
whitelistMode: linkfilter.whitelist || false
}; };
if (ignore) settings.ignore = { if (ignore) settings.ignore = {
@ -334,7 +335,7 @@ class SettingsMigrator {
}; };
if (autorole) settings.autorole = autorole; if (autorole) settings.autorole = autorole;
if (prefix) settings.prefix = prefix; if (prefix) settings.textcommands = { prefix, enabled: false };
if (welcomer) { if (welcomer) {
settings.welcomer.enabled = welcomer.enabled; settings.welcomer.enabled = welcomer.enabled;
settings.welcomer.message = welcomer.message || null; settings.welcomer.message = welcomer.message || null;
@ -398,7 +399,8 @@ class SettingsMigrator {
silent: false, silent: false,
bypass: result.invitefilter.roles, bypass: result.invitefilter.roles,
enabled: result.invitefilter.enabled, enabled: result.invitefilter.enabled,
actions: [] actions: [],
whitelist: []
}; };
const channels = Object.entries(invitefilter.channels || {}); const channels = Object.entries(invitefilter.channels || {});
for (const [id, value] of channels) { for (const [id, value] of channels) {