mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-18 00:33:59 +00:00
feat(bots/discord): blacklist and whitelist for filters
This commit is contained in:
@@ -37,11 +37,19 @@ export default {
|
|||||||
checkExpiredEvery: 3600,
|
checkExpiredEvery: 3600,
|
||||||
},
|
},
|
||||||
messageScan: {
|
messageScan: {
|
||||||
|
scanBots: false,
|
||||||
|
scanOutsideGuilds: false,
|
||||||
filter: {
|
filter: {
|
||||||
channels: ['CHANNEL_ID_HERE'],
|
whitelist: {
|
||||||
roles: ['ROLE_ID_HERE'],
|
channels: ['CHANNEL_ID_HERE'],
|
||||||
users: ['USER_ID_HERE'],
|
roles: ['ROLE_ID_HERE'],
|
||||||
whitelist: false,
|
users: ['USER_ID_HERE'],
|
||||||
|
},
|
||||||
|
blacklist: {
|
||||||
|
channels: ['CHANNEL_ID_HERE'],
|
||||||
|
roles: ['ROLE_ID_HERE'],
|
||||||
|
users: ['USER_ID_HERE'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
humanCorrections: {
|
humanCorrections: {
|
||||||
falsePositiveLabel: 'false_positive',
|
falsePositiveLabel: 'false_positive',
|
||||||
@@ -55,6 +63,18 @@ export default {
|
|||||||
allowedAttachmentMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
allowedAttachmentMimeTypes: ['image/jpeg', 'image/png', 'image/webp'],
|
||||||
responses: [
|
responses: [
|
||||||
{
|
{
|
||||||
|
filterOverride: {
|
||||||
|
whitelist: {
|
||||||
|
channels: ['CHANNEL_ID_HERE'],
|
||||||
|
roles: ['ROLE_ID_HERE'],
|
||||||
|
users: ['USER_ID_HERE'],
|
||||||
|
},
|
||||||
|
blacklist: {
|
||||||
|
channels: ['CHANNEL_ID_HERE'],
|
||||||
|
roles: ['ROLE_ID_HERE'],
|
||||||
|
users: ['USER_ID_HERE'],
|
||||||
|
},
|
||||||
|
},
|
||||||
triggers: {
|
triggers: {
|
||||||
text: [/^regexp?$/, { label: 'label', threshold: 0.85 }],
|
text: [/^regexp?$/, { label: 'label', threshold: 0.85 }],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ export type Config = {
|
|||||||
guilds: Record<string, Record<string, RolePresetConfig>>
|
guilds: Record<string, Record<string, RolePresetConfig>>
|
||||||
}
|
}
|
||||||
messageScan?: {
|
messageScan?: {
|
||||||
|
scanBots?: boolean
|
||||||
|
scanOutsideGuilds?: boolean
|
||||||
allowedAttachmentMimeTypes: string[]
|
allowedAttachmentMimeTypes: string[]
|
||||||
filter: {
|
filter?: {
|
||||||
roles?: string[]
|
whitelist?: Filter
|
||||||
users?: string[]
|
blacklist?: Filter
|
||||||
channels?: string[]
|
|
||||||
whitelist: boolean
|
|
||||||
}
|
}
|
||||||
humanCorrections: {
|
humanCorrections: {
|
||||||
falsePositiveLabel: string
|
falsePositiveLabel: string
|
||||||
@@ -73,4 +73,10 @@ export type ConfigMessageScanResponseLabelConfig = {
|
|||||||
threshold: number
|
threshold: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Filter = {
|
||||||
|
roles?: string[]
|
||||||
|
users?: string[]
|
||||||
|
channels?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
export type ConfigMessageScanResponseMessage = BaseMessageOptions
|
export type ConfigMessageScanResponseMessage = BaseMessageOptions
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, readdirSync } from 'fs'
|
|||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { Client as APIClient } from '@revanced/bot-api'
|
import { Client as APIClient } from '@revanced/bot-api'
|
||||||
import { createLogger } from '@revanced/bot-shared'
|
import { createLogger } from '@revanced/bot-shared'
|
||||||
import { ActivityType, Client as DiscordClient, Partials } from 'discord.js'
|
import { Client as DiscordClient, Partials } from 'discord.js'
|
||||||
import { drizzle } from 'drizzle-orm/bun-sqlite'
|
import { drizzle } from 'drizzle-orm/bun-sqlite'
|
||||||
|
|
||||||
// Export config first, as commands require them
|
// Export config first, as commands require them
|
||||||
@@ -13,7 +13,7 @@ export { config }
|
|||||||
import * as commands from './commands'
|
import * as commands from './commands'
|
||||||
import * as schemas from './database/schemas'
|
import * as schemas from './database/schemas'
|
||||||
|
|
||||||
import type { Command } from './commands/types'
|
import type Command from './classes/Command'
|
||||||
|
|
||||||
export const logger = createLogger({
|
export const logger = createLogger({
|
||||||
level: config.logLevel === 'none' ? Number.MAX_SAFE_INTEGER : config.logLevel,
|
level: config.logLevel === 'none' ? Number.MAX_SAFE_INTEGER : config.logLevel,
|
||||||
@@ -27,7 +27,7 @@ export const api = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
isStopping: false,
|
intentionallyDisconnecting: false,
|
||||||
disconnectCount: 0,
|
disconnectCount: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,16 +80,8 @@ export const discord = {
|
|||||||
repliedUser: true,
|
repliedUser: true,
|
||||||
},
|
},
|
||||||
partials: [Partials.Message, Partials.Reaction],
|
partials: [Partials.Message, Partials.Reaction],
|
||||||
presence: {
|
|
||||||
activities: [
|
|
||||||
{
|
|
||||||
type: ActivityType.Watching,
|
|
||||||
name: 'cat videos',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
commands: Object.fromEntries(Object.values<Command>(commands).map(cmd => [cmd.data.name, cmd])) as Record<
|
commands: Object.fromEntries(Object.values<Command>(commands).map(cmd => [cmd.name, cmd])) as Record<
|
||||||
string,
|
string,
|
||||||
Command
|
Command
|
||||||
>,
|
>,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { on, withContext } from '$utils/api/events'
|
|||||||
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
|
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
|
||||||
|
|
||||||
withContext(on, 'disconnect', ({ api, config, logger }, reason, msg) => {
|
withContext(on, 'disconnect', ({ api, config, logger }, reason, msg) => {
|
||||||
if (reason === DisconnectReason.PlannedDisconnect && api.isStopping) return
|
if (reason === DisconnectReason.PlannedDisconnect && api.intentionallyDisconnecting) return
|
||||||
|
|
||||||
const ws = api.client.ws
|
const ws = api.client.ws
|
||||||
if (!ws.disconnected) ws.disconnect()
|
if (!ws.disconnected) ws.disconnect()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { MessageScanLabeledResponseReactions } from '$/constants'
|
import { MessageScanLabeledResponseReactions } from '$/constants'
|
||||||
import { responses } from '$/database/schemas'
|
import { responses } from '$/database/schemas'
|
||||||
import { getResponseFromText, shouldScanMessage } from '$/utils/discord/messageScan'
|
import { getResponseFromText, messageMatchesFilter } from '$/utils/discord/messageScan'
|
||||||
import { createMessageScanResponseEmbed } from '$utils/discord/embeds'
|
import { createMessageScanResponseEmbed } from '$utils/discord/embeds'
|
||||||
import { on, withContext } from '$utils/discord/events'
|
import { on, withContext } from '$utils/discord/events'
|
||||||
|
|
||||||
@@ -13,8 +13,11 @@ withContext(on, 'messageCreate', async (context, msg) => {
|
|||||||
} = context
|
} = context
|
||||||
|
|
||||||
if (!config || !config.responses) return
|
if (!config || !config.responses) return
|
||||||
|
if (msg.author.bot && !config.scanBots)
|
||||||
|
if (!msg.inGuild() && !config.scanOutsideGuilds) return
|
||||||
|
if (msg.inGuild() && msg.member?.partial) await msg.member.fetch()
|
||||||
|
|
||||||
const filteredResponses = config.responses.filter(x => shouldScanMessage(msg, x.filterOverride ?? config.filter))
|
const filteredResponses = config.responses.filter(x => messageMatchesFilter(msg, x.filterOverride ?? config.filter))
|
||||||
if (!filteredResponses.length) return
|
if (!filteredResponses.length) return
|
||||||
|
|
||||||
if (msg.content.length) {
|
if (msg.content.length) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
if (reactionMessage.author.id !== reaction.client.user!.id) return
|
if (reactionMessage.author.id !== reaction.client.user!.id) return
|
||||||
if (!PossibleReactions.includes(reaction.emoji.name!)) return
|
if (!PossibleReactions.includes(reaction.emoji.name!)) return
|
||||||
|
|
||||||
if (!isAdmin(reactionMessage.member || reactionMessage.author, config.admin)) {
|
if (!isAdmin(reactionMessage.member || reactionMessage.author)) {
|
||||||
// User is in guild, and config has member requirements
|
// User is in guild, and config has member requirements
|
||||||
if (
|
if (
|
||||||
reactionMessage.inGuild() &&
|
reactionMessage.inGuild() &&
|
||||||
|
|||||||
@@ -113,24 +113,18 @@ export const getResponseFromText = async (
|
|||||||
return responseConfig
|
return responseConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
export const shouldScanMessage = (
|
export const messageMatchesFilter = (
|
||||||
message: Message,
|
message: Message,
|
||||||
filter: NonNullable<Config['messageScan']>['filter'],
|
filter: NonNullable<Config['messageScan']>['filter'],
|
||||||
): message is Message<true> => {
|
) => {
|
||||||
if (message.author.bot) return false
|
|
||||||
if (!message.guild) return false
|
|
||||||
if (!filter) return true
|
if (!filter) return true
|
||||||
|
|
||||||
const filters = [
|
const memberRoles = new Set(message.member?.roles.cache.keys())
|
||||||
filter.users?.includes(message.author.id),
|
const blFilter = filter.blacklist
|
||||||
message.member?.roles.cache.some(x => filter.roles?.includes(x.id)),
|
|
||||||
filter.channels?.includes(message.channel.id),
|
|
||||||
]
|
|
||||||
|
|
||||||
if (filter.whitelist && filters.every(x => !x)) return false
|
// If matches blacklist, will return false
|
||||||
if (!filter.whitelist && filters.some(x => x)) return false
|
// Any other case, will return true
|
||||||
|
return !(blFilter && (blFilter.channels?.includes(message.channelId) || blFilter.roles?.some(role => memberRoles.has(role)) || blFilter.users?.includes(message.author.id)))
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleUserResponseCorrection = async (
|
export const handleUserResponseCorrection = async (
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { GuildMember, type User } from 'discord.js'
|
import { GuildMember, type User } from 'discord.js'
|
||||||
import type { Config } from 'config.schema'
|
import config from '../../../config'
|
||||||
|
|
||||||
export const isAdmin = (userOrMember: User | GuildMember, adminConfig: Config['admin']) => {
|
export const isAdmin = (userOrMember: User | GuildMember) => {
|
||||||
return adminConfig?.users?.includes(userOrMember.id) || (userOrMember instanceof GuildMember && isMemberAdmin(userOrMember, adminConfig))
|
return config.admin?.users?.includes(userOrMember.id) || (userOrMember instanceof GuildMember && isMemberAdmin(userOrMember))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isMemberAdmin = (member: GuildMember, adminConfig: Config['admin']) => {
|
export const isMemberAdmin = (member: GuildMember) => {
|
||||||
const roles = new Set(member.roles.cache.keys())
|
const roles = new Set(member.roles.cache.keys())
|
||||||
return Boolean(adminConfig?.roles?.[member.guild.id]?.some(role => roles.has(role)))
|
return Boolean(config?.admin?.roles?.[member.guild.id]?.some(role => roles.has(role)))
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user