mirror of
https://github.com/chenasraf/venom.git
synced 2026-05-17 17:28:08 +00:00
feat: improve whitelist
This commit is contained in:
@@ -9,15 +9,7 @@ import {
|
||||
setMuted,
|
||||
} from '@/core/megahal'
|
||||
import { CHAT_TRIGGERS, DEFAULT_COMMAND_PREFIX } from '@/env'
|
||||
import {
|
||||
blacklistChannel,
|
||||
blacklistGuild,
|
||||
isBlacklisted,
|
||||
isWhitelisted,
|
||||
whitelistChannel,
|
||||
whitelistGuild,
|
||||
} from '@/lib/blacklist'
|
||||
import { setSetting } from '@/lib/settings'
|
||||
import { isWhitelisted, manipulateWhitelist } from '@/lib/blacklist'
|
||||
|
||||
export default command({
|
||||
command: 'chat',
|
||||
@@ -33,6 +25,7 @@ export default command({
|
||||
`\`${DEFAULT_COMMAND_PREFIX}chat save\` - backs up the brain immediately`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}chat size\` - shows the current brain size`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}chat <anything else>\` - chat with Venom and immediately get a reply.`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}chat whitelist <add|remove> <guild|channel>\` - update whitelist for guild/channel.`,
|
||||
`\`${CHAT_TRIGGERS[1]}hi!\` - You can also just prefix it with one of the chat prefixes to chat more naturally: \`${CHAT_TRIGGERS.join('`, `')}\`, `,
|
||||
],
|
||||
execute: async (message, args) => {
|
||||
@@ -43,43 +36,11 @@ export default command({
|
||||
const [sub] = args
|
||||
switch (sub.toLowerCase()) {
|
||||
case 'whitelist': {
|
||||
const guild = message.guild!
|
||||
const channel = message.channel!
|
||||
const type = args[1]?.trim().toLowerCase()
|
||||
if (!type || !['guild', 'channel'].includes(type)) {
|
||||
return message.reply(
|
||||
'You need to provide a type to whitelist, either "guild" or "channel"',
|
||||
)
|
||||
}
|
||||
if (type === 'guild') {
|
||||
await whitelistGuild('chat', guild)
|
||||
logger.info(`Whitelisted guild ${guild.id}`)
|
||||
message.reply(`Guild ${guild.toString()} whitelisted`)
|
||||
} else {
|
||||
logger.info(`Whitelisting channel ${channel.id} in guild ${guild.id}`)
|
||||
await whitelistChannel('chat', guild, channel)
|
||||
message.reply(`Channel ${channel.toString()} on ${guild.toString()} whitelisted`)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'blacklist': {
|
||||
const guild = message.guild!
|
||||
const channel = message.channel!
|
||||
const type = args[1]?.trim().toLowerCase()
|
||||
if (!type || !['guild', 'channel'].includes(type)) {
|
||||
return message.reply(
|
||||
'You need to provide a type to blacklist, either "guild" or "channel"',
|
||||
)
|
||||
}
|
||||
if (type === 'guild') {
|
||||
await blacklistGuild('chat', guild)
|
||||
logger.info(`Blacklisted guild ${guild.id}`)
|
||||
message.reply(`Guild ${guild.toString()} blacklisted`)
|
||||
} else {
|
||||
logger.info(`Blacklisting channel ${channel.id} in guild ${guild.id}`)
|
||||
await blacklistChannel('chat', guild, channel)
|
||||
message.reply(`Channel ${channel.toString()} on ${guild.toString()} blacklisted`)
|
||||
}
|
||||
const action = args[1]?.trim().toLowerCase() as 'add' | 'remove' | undefined
|
||||
const type = args[2]?.trim().toLowerCase() as 'guild' | 'channel' | undefined
|
||||
message.reply(
|
||||
await manipulateWhitelist('commands', action, type, message.guild!, message.channel),
|
||||
)
|
||||
break
|
||||
}
|
||||
case 'mute':
|
||||
|
||||
@@ -2,6 +2,7 @@ import Discord from 'discord.js'
|
||||
import { command, commands } from '@/core/commands'
|
||||
import { DEFAULT_COMMAND_PREFIX } from '@/env'
|
||||
import { logger } from '@/core/logger'
|
||||
import { isWhitelisted } from '@/lib/blacklist'
|
||||
|
||||
interface HelpMessage {
|
||||
command: string
|
||||
@@ -13,17 +14,21 @@ export default command({
|
||||
aliases: ['h'],
|
||||
description: 'Lists available commands and their usage.',
|
||||
examples: ['`!help`', '`!help ping`', '`!help chat`'],
|
||||
global: true,
|
||||
async execute(message, args) {
|
||||
const whitelisted = await isWhitelisted('commands', message.guild!, message.channel)
|
||||
let output = ''
|
||||
const data: HelpMessage[] = []
|
||||
const name = args[0]
|
||||
|
||||
const commandList = Object.values(commands()).filter((c) =>
|
||||
name
|
||||
const commandList = Object.values(commands()).filter((c) => {
|
||||
const nameMatches = name
|
||||
? c.command.toLowerCase() === name.toLowerCase() ||
|
||||
c.aliases.some((a) => a.toLowerCase() === name.toLowerCase())
|
||||
: true,
|
||||
)
|
||||
c.aliases.some((a) => a.toLowerCase() === name.toLowerCase())
|
||||
: true
|
||||
const isGlobal = c.global ?? false
|
||||
return [nameMatches, whitelisted || isGlobal].every(Boolean)
|
||||
})
|
||||
|
||||
for (const cmd of commandList) {
|
||||
let description = `\`${DEFAULT_COMMAND_PREFIX}${cmd.command}\``
|
||||
|
||||
@@ -25,7 +25,7 @@ export default command({
|
||||
description: 'Manage quotes',
|
||||
examples: [
|
||||
`\`${DEFAULT_COMMAND_PREFIX}quote\` - Get a random quote`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}quote <id>\` - Get a specific quote`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}quote #<id>\` - Get a specific quote`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}quote search <query>\` - Search for a quote`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}quote count\` - See how many quotes have been stored so far!`,
|
||||
`\`${DEFAULT_COMMAND_PREFIX}quote add @author <quote>\` - Add a new quote (@author can be a user mention, a plain nickname, or left out)`,
|
||||
@@ -158,24 +158,22 @@ async function addNewQuote(message: Discord.Message, args: string[]): Promise<vo
|
||||
`Are you serious? This is the best quote ever${differentAuthor ? `, ${authorName}` : ''}!`,
|
||||
'OH. MY. GOD. Perfection.',
|
||||
'I am putting this on my wall. This is a quote I will hold dear to me always.',
|
||||
`Is that real? Woah! Hey,${
|
||||
differentAuthor ? ` ${authorName},` : ''
|
||||
`Is that real? Woah! Hey,${differentAuthor ? ` ${authorName},` : ''
|
||||
} did you ever consider writing a book?! This will sell for millions.`,
|
||||
clean(
|
||||
`Okay, this is spooky. I definitely dreamt of ${!hasAuthor ? 'a person' : differentAuthor ? authorName : 'you'} ` +
|
||||
`saying exactly that this week. ${!hasAuthor ? 'Is someone' : differentAuthor ? `Is ${authorName}` : 'Are you'} prying into my subconscious?`,
|
||||
`saying exactly that this week. ${!hasAuthor ? 'Is someone' : differentAuthor ? `Is ${authorName}` : 'Are you'} prying into my subconscious?`,
|
||||
),
|
||||
'Consider me floored. If there was an award for amazing quotes, it would be named after this exact one.',
|
||||
'Why did no one say this earlier? It HAS to be said!',
|
||||
"I can't believe you withold that quote from me until now. It's way too good to just remain unshared!",
|
||||
'I have a pretty large memory capacity for a bot, and I gotta say, I scanned all my other quotes, this one is definitely on the top 10.',
|
||||
clean(`Oh, I am DEFINITELY saving this. One day someone will interview me about
|
||||
${
|
||||
!hasAuthor ? 'The best quote I can recall,' : differentAuthor ? authorName + ', ' : 'you,'
|
||||
} and I will refer to this moment precisely.`),
|
||||
${!hasAuthor ? 'The best quote I can recall,' : differentAuthor ? authorName + ', ' : 'you,'
|
||||
} and I will refer to this moment precisely.`),
|
||||
clean(
|
||||
`You're not serious. Are you serious? You can't be serious. It's impossible there's **this** good a quote ` +
|
||||
`just floating around
|
||||
`just floating around
|
||||
out there. It's probably fictional. Yeah.`,
|
||||
),
|
||||
]
|
||||
|
||||
18
src/commands/whitelist.command.ts
Normal file
18
src/commands/whitelist.command.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { command } from '@/core/commands'
|
||||
import { manipulateWhitelist } from '@/lib/blacklist'
|
||||
|
||||
export default command({
|
||||
command: 'whitelist',
|
||||
aliases: ['wl'],
|
||||
description: 'Whitelist a channel or guild for commands.',
|
||||
examples: ['`!whitelist add channel`', '`!whitelist add guild`'],
|
||||
global: true,
|
||||
adminOnly: true,
|
||||
async execute(message, args) {
|
||||
const action = args[0]?.trim().toLowerCase() as 'add' | 'remove' | undefined
|
||||
const type = args[1]?.trim().toLowerCase() as 'guild' | 'channel' | undefined
|
||||
return message.reply(
|
||||
await manipulateWhitelist('commands', action, type, message.guild!, message.channel),
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -5,10 +5,19 @@ import { COMMAND_TRIGGERS } from '@/env'
|
||||
import { logger } from './logger'
|
||||
|
||||
export interface Command {
|
||||
/** Command name */
|
||||
command: string
|
||||
/** Command aliases */
|
||||
aliases: string[]
|
||||
/** Command description - shown in help */
|
||||
description: string
|
||||
/** Command examples - shown in help */
|
||||
examples: string[]
|
||||
/** Global commands are available on non-whitelisted channels (default: false) */
|
||||
global?: boolean
|
||||
/** Admin-only commands are only available to whitelisted users/permissions/roles (default: false) */
|
||||
adminOnly?: boolean
|
||||
/** Function that executes the command */
|
||||
execute(_message: Message, _args: string[]): void
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,10 @@ export function isMuted() {
|
||||
|
||||
export async function trainMegahal(message: Discord.Message, replyChance: number) {
|
||||
const whitelisted = await isWhitelisted('chat', message.guild!, message.channel)
|
||||
if (!whitelisted) return
|
||||
if (!whitelisted) {
|
||||
logger.debug('Not whitelisted, ignoring message:', JSON.stringify(message.content))
|
||||
return
|
||||
}
|
||||
|
||||
const key = msgCountKey(message)
|
||||
msgCount[key]! += 1
|
||||
|
||||
@@ -3,10 +3,13 @@ import { CHAT_TRIGGERS, COMMAND_TRIGGERS } from '@/env'
|
||||
import { parseArguments, parseCommand } from '@/core/commands'
|
||||
import { logger } from '@/core/logger'
|
||||
import { CHATTER_REPLY_CHANCE, trainMegahal } from '@/core/megahal'
|
||||
import { isWhitelisted } from '@/lib/blacklist'
|
||||
import { isAdministrator } from '@/utils/discord_utils'
|
||||
|
||||
export async function handleMessage(message: Discord.Message) {
|
||||
// ignore bot/own messages
|
||||
if (message.author.bot) return
|
||||
const whitelisted = await isWhitelisted('commands', message.guild!, message.channel)
|
||||
|
||||
logger.debug(
|
||||
'Message received:',
|
||||
@@ -30,6 +33,22 @@ export async function handleMessage(message: Discord.Message) {
|
||||
}
|
||||
const command = parseCommand(message.content)
|
||||
const [cmdName, ...args] = parseArguments(message.content)
|
||||
if (!whitelisted && !command?.global) {
|
||||
logger.debug(
|
||||
'Command received in non-whitelisted channel/guild:',
|
||||
message.channel.id,
|
||||
'guild:',
|
||||
message.guild!.id,
|
||||
)
|
||||
return
|
||||
}
|
||||
if (command?.adminOnly) {
|
||||
const isAdmin = await isAdministrator(message.member!)
|
||||
if (!isAdmin) {
|
||||
logger.debug('Non-administrator tried to use admin command:', message.author.id)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (command) {
|
||||
command.execute(message, args)
|
||||
} else {
|
||||
|
||||
@@ -17,26 +17,45 @@ export async function isWhitelisted(
|
||||
return channelValue ?? guildValue
|
||||
}
|
||||
|
||||
export async function whitelistChannel(
|
||||
export async function whitelist(prefix: string, guild: Discord.Guild, channel?: Discord.Channel) {
|
||||
const key = channel
|
||||
? `${prefix}.whitelist.${guild.id}.${channel.id}`
|
||||
: `${prefix}.whitelist.${guild.id}`
|
||||
return setSetting(key, true)
|
||||
}
|
||||
|
||||
export async function blacklist(prefix: string, guild: Discord.Guild, channel?: Discord.Channel) {
|
||||
const key = channel
|
||||
? `${prefix}.whitelist.${guild.id}.${channel.id}`
|
||||
: `${prefix}.whitelist.${guild.id}`
|
||||
return setSetting(key, false)
|
||||
}
|
||||
|
||||
export async function manipulateWhitelist(
|
||||
prefix: string,
|
||||
guild: Discord.Guild,
|
||||
channel: Discord.Channel,
|
||||
) {
|
||||
return setSetting(`${prefix}.whitelist.${guild.id}.${channel.id}`, true)
|
||||
}
|
||||
action: 'add' | 'remove' | undefined,
|
||||
type: 'guild' | 'channel' | undefined,
|
||||
gulid: Discord.Guild,
|
||||
channel?: Discord.Channel,
|
||||
): Promise<string> {
|
||||
if (!action || !['add', 'remove'].includes(action)) {
|
||||
return 'You need to provide an action to whitelist, either "add" or "remove"'
|
||||
}
|
||||
if (!type || !['guild', 'channel'].includes(type)) {
|
||||
return 'You need to provide a type to whitelist, either "guild" or "channel"'
|
||||
}
|
||||
|
||||
export async function whitelistGuild(prefix: string, guild: Discord.Guild) {
|
||||
return setSetting(`${prefix}.whitelist.${guild.id}`, true)
|
||||
}
|
||||
const actionMap = {
|
||||
add: whitelist,
|
||||
remove: blacklist,
|
||||
} as const
|
||||
|
||||
export async function blacklistChannel(
|
||||
prefix: string,
|
||||
guild: Discord.Guild,
|
||||
channel: Discord.Channel,
|
||||
) {
|
||||
return setSetting(`${prefix}.whitelist.${guild.id}.${channel.id}`, false)
|
||||
}
|
||||
|
||||
export async function blacklistGuild(prefix: string, guild: Discord.Guild) {
|
||||
return setSetting(`${prefix}.whitelist.${guild.id}`, false)
|
||||
if (type === 'guild') {
|
||||
actionMap[action](prefix, gulid)
|
||||
return `Guild ${gulid.toString()} ${action === 'add' ? 'whitelisted' : 'blacklisted'} for ${prefix}`
|
||||
} else {
|
||||
if (!channel) return 'You need to provide a channel to whitelist'
|
||||
actionMap[action](prefix, gulid, channel)
|
||||
return `Channel ${channel.toString()} on ${gulid.toString()} ${action === 'add' ? 'whitelisted' : 'blacklisted'} for ${prefix}`
|
||||
}
|
||||
}
|
||||
|
||||
6
src/utils/discord_utils.ts
Normal file
6
src/utils/discord_utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import Discord, { PermissionsBitField } from 'discord.js'
|
||||
|
||||
export async function isAdministrator(member: Discord.GuildMember): Promise<boolean> {
|
||||
// TODO check role permissions
|
||||
return member.permissions.has(PermissionsBitField.Flags.ManageGuild)
|
||||
}
|
||||
Reference in New Issue
Block a user