diff options
author | IRONM00N <64110067+IRONM00N@users.noreply.github.com> | 2022-09-05 17:36:42 -0400 |
---|---|---|
committer | IRONM00N <64110067+IRONM00N@users.noreply.github.com> | 2022-09-05 17:36:42 -0400 |
commit | 048f99752550c6e03d1990a03cad78f3ac7d73aa (patch) | |
tree | c238ac29b1b526e86bcbc4989036df981c860187 /lib/extensions | |
parent | 6f8a4d13a490eda7a195d14833c83810f7b5a789 (diff) | |
download | tanzanite-048f99752550c6e03d1990a03cad78f3ac7d73aa.tar.gz tanzanite-048f99752550c6e03d1990a03cad78f3ac7d73aa.tar.bz2 tanzanite-048f99752550c6e03d1990a03cad78f3ac7d73aa.zip |
revamp command permissions, fix permission exploit for some command when used in forum channels, use enums more
Diffstat (limited to 'lib/extensions')
-rw-r--r-- | lib/extensions/discord-akairo/BotArgumentTypeCaster.ts | 2 | ||||
-rw-r--r-- | lib/extensions/discord-akairo/BotCommand.ts | 92 | ||||
-rw-r--r-- | lib/extensions/discord-akairo/BotCommandHandler.ts | 107 | ||||
-rw-r--r-- | lib/extensions/discord-akairo/BotInhibitor.ts | 33 | ||||
-rw-r--r-- | lib/extensions/discord-akairo/BotListener.ts | 50 | ||||
-rw-r--r-- | lib/extensions/discord-akairo/BotListenerHandler.ts | 16 | ||||
-rw-r--r-- | lib/extensions/discord-akairo/TanzaniteClient.ts | 21 | ||||
-rw-r--r-- | lib/extensions/discord.js/BotClientEvents.ts | 31 | ||||
-rw-r--r-- | lib/extensions/discord.js/ExtendedGuild.ts | 21 | ||||
-rw-r--r-- | lib/extensions/discord.js/ExtendedGuildMember.ts | 69 |
10 files changed, 314 insertions, 128 deletions
diff --git a/lib/extensions/discord-akairo/BotArgumentTypeCaster.ts b/lib/extensions/discord-akairo/BotArgumentTypeCaster.ts index 5f4f32f..d7943fc 100644 --- a/lib/extensions/discord-akairo/BotArgumentTypeCaster.ts +++ b/lib/extensions/discord-akairo/BotArgumentTypeCaster.ts @@ -1,3 +1,3 @@ -import { type CommandMessage } from '#lib'; +import type { CommandMessage } from '#lib'; export type BotArgumentTypeCaster<R = unknown> = (message: CommandMessage, phrase: string) => R; diff --git a/lib/extensions/discord-akairo/BotCommand.ts b/lib/extensions/discord-akairo/BotCommand.ts index abd945e..11a8bad 100644 --- a/lib/extensions/discord-akairo/BotCommand.ts +++ b/lib/extensions/discord-akairo/BotCommand.ts @@ -1,17 +1,16 @@ import { type DiscordEmojiInfo, type RoleWithDuration } from '#args'; -import { - type BotArgumentTypeCaster, - type BotCommandHandler, - type BotInhibitor, - type BotListener, - type BotTask, - type ParsedDuration, - type TanzaniteClient +import type { + BotArgumentTypeCaster, + BotCommandHandler, + BotInhibitor, + BotListener, + BotTask, + ParsedDuration, + TanzaniteClient } from '#lib'; import { - ArgumentMatch, Command, - CommandUtil, + CommandArguments, type AkairoApplicationCommandAutocompleteOption, type AkairoApplicationCommandChannelOptionData, type AkairoApplicationCommandChoicesData, @@ -20,26 +19,25 @@ import { type AkairoApplicationCommandOptionData, type AkairoApplicationCommandSubCommandData, type AkairoApplicationCommandSubGroupData, + type ArgumentMatch, type ArgumentOptions, type ArgumentType, type ArgumentTypeCaster, type BaseArgumentType, type CommandOptions, + type CommandUtil, type ContextMenuCommand, - type MissingPermissionSupplier, type SlashOption, type SlashResolveType } from 'discord-akairo'; import { - Message, PermissionsBitField, - User, type ApplicationCommandOptionChoiceData, - // eslint-disable-next-line @typescript-eslint/no-unused-vars type ApplicationCommandOptionType, - type PermissionResolvable, + type Message, type PermissionsString, - type Snowflake + type Snowflake, + type User } from 'discord.js'; import _ from 'lodash'; import { SlashMessage } from './SlashMessage.js'; @@ -219,6 +217,7 @@ export type CustomMissingPermissionSupplier = (message: CommandMessage | SlashMe interface ExtendedCommandOptions { /** * Whether the command is hidden from the help command. + * @default false */ hidden?: boolean; @@ -244,11 +243,13 @@ interface ExtendedCommandOptions { /** * A fake command, completely hidden from the help command. + * @default false */ pseudo?: boolean; /** * Allow this command to be run in channels that are blacklisted. + * @default false */ bypassChannelBlacklist?: boolean; @@ -261,6 +262,24 @@ interface ExtendedCommandOptions { * Extra information about the command, displayed in the help command. */ note?: string; + + /** + * Whether to check for channel overrides when considering client permissions. + * @default false + */ + clientCheckChannel?: boolean; + + /** + * Whether to check for channel overrides when considering user permissions. + * @default false + */ + userCheckChannel?: boolean; + + /** + * **Text Command Only**: Don't check if the user has send permissions in the channel. + * @default false + */ + skipSendCheck?: boolean; } export interface BaseBotCommandOptions @@ -281,12 +300,12 @@ export interface BaseBotCommandOptions /** * Permissions required by the client to run this command. */ - clientPermissions: bigint | bigint[] | CustomMissingPermissionSupplier; + clientPermissions: PermissionsString[]; /** * Permissions required by the user to run this command. */ - userPermissions: bigint | bigint[] | CustomMissingPermissionSupplier; + userPermissions: PermissionsString[]; /** * Whether the argument is only accessible to the owners. @@ -364,6 +383,8 @@ export abstract class BotCommand extends Command { public declare client: TanzaniteClient; public declare handler: BotCommandHandler; public declare description: string; + public declare userPermissions: PermissionsString[]; + public declare clientPermissions: PermissionsString[]; /** * Show how to use the command. @@ -411,7 +432,7 @@ export abstract class BotCommand extends Command { public bypassChannelBlacklist: boolean; /** - * Info about the arguments for the help command. + * Information about the arguments for the help command. */ public argsInfo?: ArgsInfo[]; @@ -420,6 +441,24 @@ export abstract class BotCommand extends Command { */ public note?: string; + /** + * Whether to check for channel overrides when considering client permissions. + * @default true + */ + public clientCheckChannel: boolean; + + /** + * Whether to check for channel overrides when considering user permissions. + * @default true + */ + public userCheckChannel: boolean; + + /** + * **Text Command Only**: Don't check if the user has send permissions in the channel. + * @default false + */ + public skipSendCheck: boolean; + public constructor(id: string, options: CustomCommandOptions) { const options_ = options as BaseBotCommandOptions; @@ -490,7 +529,7 @@ export abstract class BotCommand extends Command { if (newTextArgs.length > 0) newOptions.args = newTextArgs; if (newSlashArgs.length > 0) newOptions.slashOptions = options_.slashOptions ?? newSlashArgs; } else if (key === 'clientPermissions' || key === 'userPermissions') { - newOptions[key] = options_[key] as PermissionResolvable | PermissionResolvable[] | MissingPermissionSupplier; + newOptions[key] = options_[key]; } else { newOptions[key] = options_[key]; } @@ -543,12 +582,15 @@ export abstract class BotCommand extends Command { this.examples = options_.examples; this.options = options_; this.parsedOptions = newOptions; - this.hidden = !!options_.hidden; + this.hidden = options_.hidden ?? false; this.restrictedChannels = options_.restrictedChannels; this.restrictedGuilds = options_.restrictedGuilds; - this.pseudo = !!options_.pseudo; - this.bypassChannelBlacklist = !!options_.bypassChannelBlacklist; + this.pseudo = options_.pseudo ?? false; + this.bypassChannelBlacklist = options_.bypassChannelBlacklist ?? false; this.note = options_.note; + this.clientCheckChannel = options_.clientCheckChannel ?? false; + this.userCheckChannel = options_.userCheckChannel ?? false; + this.skipSendCheck = options_.skipSendCheck ?? false; } /** @@ -556,13 +598,13 @@ export abstract class BotCommand extends Command { * @param message - Message that triggered the command. * @param args - Evaluated arguments. */ - public abstract override exec(message: CommandMessage, args: any): any; + public abstract override exec(message: CommandMessage, args: CommandArguments): any; /** * Executes the command. * @param message - Message that triggered the command. * @param args - Evaluated arguments. */ - public abstract override exec(message: CommandMessage | SlashMessage, args: any): any; + public abstract override exec(message: CommandMessage | SlashMessage, args: CommandArguments): any; } type SlashOptionKeys = diff --git a/lib/extensions/discord-akairo/BotCommandHandler.ts b/lib/extensions/discord-akairo/BotCommandHandler.ts index 8a4fe60..71d9ad4 100644 --- a/lib/extensions/discord-akairo/BotCommandHandler.ts +++ b/lib/extensions/discord-akairo/BotCommandHandler.ts @@ -1,6 +1,7 @@ -import { type BotCommand, type CommandMessage, type SlashMessage } from '#lib'; -import { CommandHandler, type Category, type CommandHandlerEvents, type CommandHandlerOptions } from 'discord-akairo'; -import { type Collection, type Message, type PermissionsString } from 'discord.js'; +import type { BotCommand, CommandMessage, SlashMessage } from '#lib'; +import { CommandHandler, CommandHandlerEvents, type Category, type CommandHandlerOptions } from 'discord-akairo'; +import { GuildMember, PermissionResolvable, type Collection, type Message, type PermissionsString } from 'discord.js'; +import { CommandHandlerEvent } from '../../utils/Constants.js'; export type CustomCommandHandlerOptions = CommandHandlerOptions; @@ -18,20 +19,116 @@ export interface BotCommandHandlerEvents extends CommandHandlerEvents { load: [command: BotCommand, isReload: boolean]; messageBlocked: [message: /* no util */ Message | CommandMessage | SlashMessage, reason: string]; messageInvalid: [message: CommandMessage]; - missingPermissions: [message: CommandMessage, command: BotCommand, type: 'client' | 'user', missing: PermissionsString[]]; + missingPermissions: [ + message: CommandMessage, + command: BotCommand, + type: 'client' | 'user', + // fix: this is jank + missing: (PermissionsString | '[[UnsupportedChannel]]')[] + ]; remove: [command: BotCommand]; slashBlocked: [message: SlashMessage, command: BotCommand, reason: string]; slashError: [error: Error, message: SlashMessage, command: BotCommand]; slashFinished: [message: SlashMessage, command: BotCommand, args: any, returnValue: any]; - slashMissingPermissions: [message: SlashMessage, command: BotCommand, type: 'client' | 'user', missing: PermissionsString[]]; + slashMissingPermissions: [ + message: SlashMessage, + command: BotCommand, + type: 'client' | 'user', + // fix: this is jank + missing: (PermissionsString | '[[UnsupportedChannel]]')[] + ]; slashStarted: [message: SlashMessage, command: BotCommand, args: any]; } export class BotCommandHandler extends CommandHandler { public declare modules: Collection<string, BotCommand>; public declare categories: Collection<string, Category<string, BotCommand>>; + + //! this is a simplified version of the original + public override async runPermissionChecks( + message: Message | SlashMessage, + command: BotCommand, + slash: boolean = false + ): Promise<boolean> { + const event = slash ? CommandHandlerEvent.SlashMissingPermissions : CommandHandlerEvent.MissingPermissions; + + const appSlashPerms = slash ? (message as SlashMessage).interaction.appPermissions : null; + const userSlashPerms = slash ? (message as SlashMessage).interaction.memberPermissions : null; + + console.dir(message); + console.dir(appSlashPerms); + console.dir(userSlashPerms); + console.dir(event); + console.dir(command); + + const noPerms = message.channel == null || (message.channel.isThread() && message.channel.parent == null); + + if (message.inGuild()) { + if (noPerms && command.clientCheckChannel && appSlashPerms == null) { + this.emit(event, message, command, 'client', ['[[UnsupportedChannel]]']); + return true; + } + if (message.channel?.isDMBased()) return false; + + const missing = command.clientCheckChannel + ? (appSlashPerms ?? message.channel?.permissionsFor(message.guild.members.me!))?.missing(command.clientPermissions) + : message.guild?.members.me?.permissions.missing(command.clientPermissions); + + if (missing?.length) { + this.emit(event, message, command, 'client', missing); + return true; + } + } + + if (command.userPermissions) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const ignorer = command.ignorePermissions || this.ignorePermissions; + const isIgnored = Array.isArray(ignorer) + ? ignorer.includes(message.author.id) + : typeof ignorer === 'function' + ? ignorer(message, command) + : message.author.id === ignorer; + + if (!isIgnored) { + if (message.inGuild()) { + if (noPerms && command.userCheckChannel && userSlashPerms == null) { + this.emit(event, message, command, 'user', ['[[UnsupportedChannel]]']); + return true; + } + if (message.channel?.isDMBased()) return false; + + const missing = command.userCheckChannel + ? (userSlashPerms ?? message.channel?.permissionsFor(message.author))?.missing(command.userPermissions) + : message.member?.permissions.missing(command.userPermissions); + + if (missing?.length) { + this.emit(event, message, command, 'user', missing); + return true; + } + } + } + } + + return false; + } } export interface BotCommandHandler extends CommandHandler { findCommand(name: string): BotCommand; } + +export function permissionCheck( + message: CommandMessage | SlashMessage, + check: GuildMember, + perms: PermissionResolvable, + useChannel: boolean +): boolean { + if (message.inGuild()) { + if (!message.channel || message.channel.isDMBased()) return true; + + const missing = useChannel ? message.channel.permissionsFor(check)?.missing(perms) : check.permissions.missing(perms); + + if (missing?.length) return false; + } + return true; +} diff --git a/lib/extensions/discord-akairo/BotInhibitor.ts b/lib/extensions/discord-akairo/BotInhibitor.ts index d134eab..8892b8b 100644 --- a/lib/extensions/discord-akairo/BotInhibitor.ts +++ b/lib/extensions/discord-akairo/BotInhibitor.ts @@ -1,8 +1,12 @@ -import { type BotCommand, type CommandMessage, type SlashMessage } from '#lib'; -import { Inhibitor } from 'discord-akairo'; +import type { BotCommand, CommandMessage, InhibitorReason, InhibitorType, SlashMessage } from '#lib'; +import { Inhibitor, InhibitorOptions } from 'discord-akairo'; import { Message } from 'discord.js'; export abstract class BotInhibitor extends Inhibitor { + public constructor(id: InhibitorReason, options?: BotInhibitorOptions) { + super(id, options); + } + /** * Checks if message should be blocked. * A return value of true will block the message. @@ -16,3 +20,28 @@ export abstract class BotInhibitor extends Inhibitor { public abstract override exec(message: CommandMessage, command: BotCommand): any; public abstract override exec(message: CommandMessage | SlashMessage, command: BotCommand): any; } + +/** + * Options to use for inhibitor execution behavior. + */ +export interface BotInhibitorOptions extends InhibitorOptions { + /** + * Reason emitted when command or message is blocked. + * @default "" + */ + reason: InhibitorReason; + + /** + * - {@link InhibitorType.All} run on all messages + * - {@link InhibitorType.Pre} run on messages not blocked by the built-in inhibitors + * - {@link InhibitorType.Post} run on messages that are commands + */ + type: InhibitorType; + + /** + * Priority for the inhibitor for when more than one inhibitors block a message. + * The inhibitor with the highest priority is the one that is used for the block reason. + * @default 0 + */ + priority?: number; +} diff --git a/lib/extensions/discord-akairo/BotListener.ts b/lib/extensions/discord-akairo/BotListener.ts index f4bfd6c..4f760e2 100644 --- a/lib/extensions/discord-akairo/BotListener.ts +++ b/lib/extensions/discord-akairo/BotListener.ts @@ -1,3 +1,49 @@ -import { Listener } from 'discord-akairo'; +import { Listener, type ListenerOptions } from 'discord-akairo'; -export abstract class BotListener extends Listener {} +export abstract class BotListener extends Listener { + public constructor(id: string, options: BotListenerOptions) { + super(id, options); + } +} + +/** + * Options to use for listener execution behavior. + */ +export interface BotListenerOptions extends ListenerOptions { + /** + * The event emitter, either a key from `ListenerHandler#emitters` or an EventEmitter. + */ + emitter: Emitter; + + /** + * Event name to listen to. + */ + event: string; + + /** + * Type of listener, either 'on' or 'once'. + * @default "on" + */ + type?: ListenerType; +} + +export const enum Emitter { + Client = 'client', + CommandHandler = 'commandHandler', + InhibitorHandler = 'inhibitorHandler', + ListenerHandler = 'listenerHandler', + TaskHandler = 'taskHandler', + ContextMenuCommandHandler = 'contextMenuCommandHandler', + Process = 'process', + Stdin = 'stdin', + Gateway = 'gateway', + Rest = 'rest', + Ws = 'ws' +} + +export const enum ListenerType { + On = 'on', + Once = 'once', + PrependListener = 'prependListener', + PrependOnceListener = 'prependOnceListener' +} diff --git a/lib/extensions/discord-akairo/BotListenerHandler.ts b/lib/extensions/discord-akairo/BotListenerHandler.ts index 9b3b525..bc14a53 100644 --- a/lib/extensions/discord-akairo/BotListenerHandler.ts +++ b/lib/extensions/discord-akairo/BotListenerHandler.ts @@ -1,3 +1,19 @@ import { ListenerHandler } from 'discord-akairo'; +import type readline from 'readline'; +import { TanzaniteClient } from './TanzaniteClient.js'; export class BotListenerHandler extends ListenerHandler {} + +export interface Emitters { + client: TanzaniteClient; + commandHandler: TanzaniteClient['commandHandler']; + inhibitorHandler: TanzaniteClient['inhibitorHandler']; + listenerHandler: TanzaniteClient['listenerHandler']; + taskHandler: TanzaniteClient['taskHandler']; + contextMenuCommandHandler: TanzaniteClient['contextMenuCommandHandler']; + process: NodeJS.Process; + stdin: readline.Interface; + gateway: TanzaniteClient['ws']; + rest: TanzaniteClient['rest']; + ws: TanzaniteClient['ws']; +} diff --git a/lib/extensions/discord-akairo/TanzaniteClient.ts b/lib/extensions/discord-akairo/TanzaniteClient.ts index fe34b58..ac09aea 100644 --- a/lib/extensions/discord-akairo/TanzaniteClient.ts +++ b/lib/extensions/discord-akairo/TanzaniteClient.ts @@ -11,7 +11,6 @@ import { snowflake } from '#args'; import type { Config } from '#config'; -import { BotClientEvents, emojis, formatError, inspect, updateEveryCache } from '#lib'; import { patch, type PatchedElements } from '@notenoughupdates/events-intercept'; import * as Sentry from '@sentry/node'; import { @@ -62,14 +61,18 @@ import { } from '../../models/index.js'; import { AllowedMentions } from '../../utils/AllowedMentions.js'; import { BotClientUtils } from '../../utils/BotClientUtils.js'; +import { emojis } from '../../utils/Constants.js'; import { Logger } from '../../utils/Logger.js'; +import { updateEveryCache } from '../../utils/UpdateCache.js'; +import { formatError, inspect } from '../../utils/Utils.js'; +import { BotClientEvents } from '../discord.js/BotClientEvents.js'; import { ExtendedGuild } from '../discord.js/ExtendedGuild.js'; import { ExtendedGuildMember } from '../discord.js/ExtendedGuildMember.js'; import { ExtendedMessage } from '../discord.js/ExtendedMessage.js'; import { ExtendedUser } from '../discord.js/ExtendedUser.js'; import { BotCommandHandler } from './BotCommandHandler.js'; import { BotInhibitorHandler } from './BotInhibitorHandler.js'; -import { BotListenerHandler } from './BotListenerHandler.js'; +import { BotListenerHandler, Emitters } from './BotListenerHandler.js'; import { BotTaskHandler } from './BotTaskHandler.js'; declare module 'discord.js' { @@ -578,17 +581,3 @@ export interface BotStats { */ slashCommandsUsed: bigint; } - -export interface Emitters { - client: TanzaniteClient; - commandHandler: TanzaniteClient['commandHandler']; - inhibitorHandler: TanzaniteClient['inhibitorHandler']; - listenerHandler: TanzaniteClient['listenerHandler']; - taskHandler: TanzaniteClient['taskHandler']; - contextMenuCommandHandler: TanzaniteClient['contextMenuCommandHandler']; - process: NodeJS.Process; - stdin: readline.Interface; - gateway: TanzaniteClient['ws']; - rest: TanzaniteClient['rest']; - ws: TanzaniteClient['ws']; -} diff --git a/lib/extensions/discord.js/BotClientEvents.ts b/lib/extensions/discord.js/BotClientEvents.ts index 284ea32..941a6d8 100644 --- a/lib/extensions/discord.js/BotClientEvents.ts +++ b/lib/extensions/discord.js/BotClientEvents.ts @@ -1,4 +1,3 @@ -import type { BanResponse, CommandMessage, Guild as GuildDB, GuildSettings } from '#lib'; import type { AkairoClientEvents } from 'discord-akairo'; import type { ButtonInteraction, @@ -13,32 +12,10 @@ import type { Snowflake, User } from 'discord.js'; - -export enum TanzaniteEvent { - Ban = 'customBan', - Block = 'customBlock', - Kick = 'customKick', - Mute = 'customMute', - PunishRoleAdd = 'punishRoleAdd', - PunishRoleRemove = 'punishRoleRemove', - Purge = 'customPurge', - RemoveTimeout = 'customRemoveTimeout', - Timeout = 'customTimeout', - Unban = 'customUnban', - Unblock = 'customUnblock', - Unmute = 'customUnmute', - UpdateModlog = 'updateModlog', - UpdateSettings = 'updateSettings', - Warn = 'customWarn', - LevelUpdate = 'levelUpdate', - Lockdown = 'lockdown', - Unlockdown = 'unlockdown', - MassBan = 'massBan', - MassEvidence = 'massEvidence', - Button = 'button', - SelectMenu = 'selectMenu', - ModalSubmit = 'modal' -} +import { Guild as GuildDB, GuildSettings } from '../../models/index.js'; +import { TanzaniteEvent } from '../../utils/Constants.js'; +import { CommandMessage } from '../discord-akairo/BotCommand.js'; +import { BanResponse } from './ExtendedGuildMember.js'; export interface BotClientEvents extends AkairoClientEvents { [TanzaniteEvent.Ban]: [ diff --git a/lib/extensions/discord.js/ExtendedGuild.ts b/lib/extensions/discord.js/ExtendedGuild.ts index 67de5cf..6b69206 100644 --- a/lib/extensions/discord.js/ExtendedGuild.ts +++ b/lib/extensions/discord.js/ExtendedGuild.ts @@ -1,19 +1,7 @@ -import { - AllowedMentions, - banResponse, - colors, - dmResponse, - emojis, - permissionsResponse, - punishmentEntryRemove, - TanzaniteClient, - type BanResponse, - type GuildFeatures, - type GuildLogType, - type GuildModel -} from '#lib'; import * as Moderation from '#lib/common/Moderation.js'; -import { Guild as GuildDB, ModLogType } from '#lib/models/index.js'; +import { Guild as GuildDB, GuildFeatures, GuildLogType, GuildModel, ModLogType } from '#lib/models/index.js'; +import { AllowedMentions } from '#lib/utils/AllowedMentions.js'; +import { colors, emojis, TanzaniteEvent } from '#lib/utils/Constants.js'; import { addOrRemoveFromArray } from '#lib/utils/Utils.js'; import assert from 'assert/strict'; import { @@ -43,7 +31,8 @@ import { type WebhookMessageOptions } from 'discord.js'; import _ from 'lodash'; -import { TanzaniteEvent } from './BotClientEvents.js'; +import { TanzaniteClient } from '../discord-akairo/TanzaniteClient.js'; +import { banResponse, BanResponse, dmResponse, permissionsResponse, punishmentEntryRemove } from './ExtendedGuildMember.js'; declare module 'discord.js' { export interface BaseGuild { diff --git a/lib/extensions/discord.js/ExtendedGuildMember.ts b/lib/extensions/discord.js/ExtendedGuildMember.ts index 172f6df..043cc1d 100644 --- a/lib/extensions/discord.js/ExtendedGuildMember.ts +++ b/lib/extensions/discord.js/ExtendedGuildMember.ts @@ -1,15 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { - formatError, - Moderation, - ModLogType, - TanzaniteClient, - Time, - type BotClientEvents, - type PunishmentTypeDM, - type ValueOf -} from '#lib'; -import { ChannelType, GuildMember, PermissionFlagsBits, @@ -17,7 +7,18 @@ import { type GuildTextBasedChannel, type Role } from 'discord.js'; -import { TanzaniteEvent } from './BotClientEvents.js'; +import { + checkMutePermissions, + createModLogEntry, + createPunishmentEntry, + punishDM, + PunishmentTypeDM, + removePunishmentEntry +} from '../../common/Moderation.js'; +import { ModLogType } from '../../models/index.js'; +import { TanzaniteEvent, Time } from '../../utils/Constants.js'; +import { formatError, ValueOf } from '../../utils/Utils.js'; +import { TanzaniteClient } from '../discord-akairo/TanzaniteClient.js'; /* eslint-enable @typescript-eslint/no-unused-vars */ declare module 'discord.js' { @@ -140,7 +141,7 @@ export class ExtendedGuildMember extends GuildMember { modlog?: string, sendFooter = true ): Promise<boolean> { - return Moderation.punishDM({ + return punishDM({ client: this.client, modlog, guild: this.guild, @@ -166,7 +167,7 @@ export class ExtendedGuildMember extends GuildMember { const ret = await (async (): Promise<{ result: WarnResponse; caseNum: number | null }> => { // add modlog entry - const result = await Moderation.createModLogEntry( + const result = await createModLogEntry( { client: this.client, type: ModLogType.WARN, @@ -214,7 +215,7 @@ export class ExtendedGuildMember extends GuildMember { const ret = await (async () => { if (options.addToModlog || options.duration) { - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: options.duration ? ModLogType.TEMP_PUNISHMENT_ROLE : ModLogType.PERM_PUNISHMENT_ROLE, guild: this.guild, @@ -230,7 +231,7 @@ export class ExtendedGuildMember extends GuildMember { caseID = modlog.id; if (options.addToModlog || options.duration) { - const punishmentEntrySuccess = await Moderation.createPunishmentEntry({ + const punishmentEntrySuccess = await createPunishmentEntry({ client: this.client, type: 'role', user: this, @@ -287,7 +288,7 @@ export class ExtendedGuildMember extends GuildMember { const ret = await (async () => { if (options.addToModlog) { - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: ModLogType.REMOVE_PUNISHMENT_ROLE, guild: this.guild, @@ -301,7 +302,7 @@ export class ExtendedGuildMember extends GuildMember { if (!modlog) return removeRoleResponse.MODLOG_ERROR; caseID = modlog.id; - const punishmentEntrySuccess = await Moderation.removePunishmentEntry({ + const punishmentEntrySuccess = await removePunishmentEntry({ client: this.client, type: 'role', user: this, @@ -370,7 +371,7 @@ export class ExtendedGuildMember extends GuildMember { */ public override async customMute(options: CustomTimedPunishmentOptions): Promise<MuteResponse> { // checks - const checks = await Moderation.checkMutePermissions(this.guild); + const checks = await checkMutePermissions(this.guild); if (checks !== true) return checks; const muteRoleID = (await this.guild.getSetting('muteRole'))!; @@ -393,7 +394,7 @@ export class ExtendedGuildMember extends GuildMember { if (!muteSuccess) return muteResponse.ACTION_ERROR; // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: options.duration ? ModLogType.TEMP_MUTE : ModLogType.PERM_MUTE, user: this, @@ -409,7 +410,7 @@ export class ExtendedGuildMember extends GuildMember { caseID = modlog.id; // add punishment entry so they can be unmuted later - const punishmentEntrySuccess = await Moderation.createPunishmentEntry({ + const punishmentEntrySuccess = await createPunishmentEntry({ client: this.client, type: 'mute', user: this, @@ -456,7 +457,7 @@ export class ExtendedGuildMember extends GuildMember { */ public override async customUnmute(options: CustomPunishmentOptions): Promise<UnmuteResponse> { // checks - const checks = await Moderation.checkMutePermissions(this.guild); + const checks = await checkMutePermissions(this.guild); if (checks !== true) return checks; const muteRoleID = (await this.guild.getSetting('muteRole'))!; @@ -478,7 +479,7 @@ export class ExtendedGuildMember extends GuildMember { if (!muteSuccess) return unmuteResponse.ACTION_ERROR; // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: ModLogType.UNMUTE, user: this, @@ -493,7 +494,7 @@ export class ExtendedGuildMember extends GuildMember { caseID = modlog.id; // remove mute entry - const removePunishmentEntrySuccess = await Moderation.removePunishmentEntry({ + const removePunishmentEntrySuccess = await removePunishmentEntry({ client: this.client, type: 'mute', user: this, @@ -548,7 +549,7 @@ export class ExtendedGuildMember extends GuildMember { if (!moderator) return kickResponse.CANNOT_RESOLVE_USER; const ret = await (async () => { // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: ModLogType.KICK, user: this, @@ -613,7 +614,7 @@ export class ExtendedGuildMember extends GuildMember { const ret = await (async () => { // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN, user: this, @@ -641,7 +642,7 @@ export class ExtendedGuildMember extends GuildMember { if (!banSuccess) return banResponse.ACTION_ERROR; // add punishment entry so they can be unbanned later - const punishmentEntrySuccess = await Moderation.createPunishmentEntry({ + const punishmentEntrySuccess = await createPunishmentEntry({ client: this.client, type: 'ban', user: this, @@ -699,7 +700,7 @@ export class ExtendedGuildMember extends GuildMember { if (!blockSuccess) return blockResponse.ACTION_ERROR; // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: options.duration ? ModLogType.TEMP_CHANNEL_BLOCK : ModLogType.PERM_CHANNEL_BLOCK, user: this, @@ -713,7 +714,7 @@ export class ExtendedGuildMember extends GuildMember { caseID = modlog.id; // add punishment entry so they can be unblocked later - const punishmentEntrySuccess = await Moderation.createPunishmentEntry({ + const punishmentEntrySuccess = await createPunishmentEntry({ client: this.client, type: 'block', user: this, @@ -727,7 +728,7 @@ export class ExtendedGuildMember extends GuildMember { // dm user const dmSuccess = options.silent ? null - : await Moderation.punishDM({ + : await punishDM({ client: this.client, punishment: 'blocked', reason: options.reason ?? undefined, @@ -793,7 +794,7 @@ export class ExtendedGuildMember extends GuildMember { if (!blockSuccess) return unblockResponse.ACTION_ERROR; // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: ModLogType.CHANNEL_UNBLOCK, user: this, @@ -807,7 +808,7 @@ export class ExtendedGuildMember extends GuildMember { caseID = modlog.id; // remove punishment entry - const punishmentEntrySuccess = await Moderation.removePunishmentEntry({ + const punishmentEntrySuccess = await removePunishmentEntry({ client: this.client, type: 'block', user: this, @@ -819,7 +820,7 @@ export class ExtendedGuildMember extends GuildMember { // dm user const dmSuccess = options.silent ? null - : await Moderation.punishDM({ + : await punishDM({ client: this.client, punishment: 'unblocked', reason: options.reason ?? undefined, @@ -880,7 +881,7 @@ export class ExtendedGuildMember extends GuildMember { if (!timeoutSuccess) return timeoutResponse.ACTION_ERROR; // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: ModLogType.TIMEOUT, user: this, @@ -942,7 +943,7 @@ export class ExtendedGuildMember extends GuildMember { if (!timeoutSuccess) return removeTimeoutResponse.ACTION_ERROR; // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ + const { log: modlog } = await createModLogEntry({ client: this.client, type: ModLogType.REMOVE_TIMEOUT, user: this, |