Please look over - not for production
diff --git a/src/reflex/scanners.ts b/src/reflex/scanners.ts
index 450a4af..f00e82c 100644
--- a/src/reflex/scanners.ts
+++ b/src/reflex/scanners.ts
@@ -8,6 +8,9 @@
import * as nsfwjs from 'nsfwjs';
import * as clamscan from 'clamscan'
import * as tf from "@tensorflow/tfjs-node";
+import EmojiEmbed from "../utils/generateEmojiEmbed.js";
+import getEmojiByName from "../utils/getEmojiByName.js";
+import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
interface NSFWSchema {
nsfw: boolean;
@@ -164,7 +167,8 @@
}
}
-export function TestString(string: string, soft: string[], strict: string[]): object | null {
+export function TestString(string: string, soft: string[], strict: string[], enabled?: boolean): {word: string, type: string} | null {
+ if (!enabled) return null;
for (const word of strict) {
if (string.toLowerCase().includes(word)) {
return { word: word, type: "strict" };
@@ -173,7 +177,7 @@
for (const word of soft) {
for (const word2 of string.match(/[a-z]+/gi) ?? []) {
if (word2 === word) {
- return { word: word, type: "strict" };
+ return { word: word, type: "soft" };
}
}
}
@@ -188,3 +192,76 @@
});
return text;
}
+
+export async function doMemberChecks(member: Discord.GuildMember, guild: Discord.Guild): Promise<void> {
+ if (member.user.bot) return;
+ const guildData = await client.database.guilds.read(guild.id);
+ if (!guildData.logging.staff.channel) return;
+ const [ loose, strict ] = [guildData.filters.wordFilter.words.loose, guildData.filters.wordFilter.words.strict];
+ // Does the username contain filtered words
+ const usernameCheck = TestString(member.user.username, loose, strict, guildData.filters.wordFilter.enabled);
+ // Does the nickname contain filtered words
+ const nicknameCheck = TestString(member.nickname ?? "", loose, strict, guildData.filters.wordFilter.enabled);
+ // Does the profile picture contain filtered words
+ const avatarTextCheck = TestString(await TestImage(member.user.displayAvatarURL({ forceStatic: true })) ?? "", loose, strict, guildData.filters.wordFilter.enabled);
+ // Is the profile picture NSFW
+ const avatarCheck = guildData.filters.images.NSFW && await NSFWCheck(member.user.displayAvatarURL({ forceStatic: true }));
+ // Does the username contain an invite
+ const inviteCheck = guildData.filters.invite.enabled && member.user.username.match(/discord\.gg\/[a-zA-Z0-9]+/gi) !== null;
+ // Does the nickname contain an invite
+ const nicknameInviteCheck = guildData.filters.invite.enabled && member.nickname?.match(/discord\.gg\/[a-zA-Z0-9]+/gi) !== null;
+
+ if (usernameCheck !== null || nicknameCheck !== null || avatarCheck || inviteCheck || nicknameInviteCheck || avatarTextCheck !== null) {
+ const infractions = [];
+ if (usernameCheck !== null) {
+ infractions.push(`Username contains a ${usernameCheck.type}ly filtered word (${usernameCheck.word})`);
+ } if (nicknameCheck !== null) {
+ infractions.push(`Nickname contains a ${nicknameCheck.type}ly filtered word (${nicknameCheck.word})`);
+ } if (avatarCheck) {
+ infractions.push("Profile picture is NSFW");
+ } if (inviteCheck) {
+ infractions.push("Username contains an invite");
+ } if (nicknameInviteCheck) {
+ infractions.push("Nickname contains an invite");
+ } if (avatarTextCheck !== null) {
+ infractions.push(`Profile picture contains a ${avatarTextCheck.type}ly filtered word: ${avatarTextCheck.word}`);
+ }
+ if (infractions.length === 0) return;
+ // This is bad - Warn in the staff notifications channel
+ const filter = getEmojiByName("ICONS.FILTER");
+ const channel = guild.channels.cache.get(guildData.logging.staff.channel) as Discord.TextChannel;
+ const embed = new EmojiEmbed()
+ .setTitle("Member Flagged")
+ .setEmoji("ICONS.FLAGS.RED")
+ .setStatus("Danger")
+ .setDescription(`**Member:** ${member.user.username} (<@${member.user.id}>)\n\n` +
+ infractions.map((element) => `${filter} ${element}`).join("\n")
+ )
+ await channel.send({
+ embeds: [embed],
+ components: [new ActionRowBuilder<ButtonBuilder>().addComponents(...[
+ new ButtonBuilder()
+ .setCustomId(`mod:warn:${member.user.id}`)
+ .setLabel("Warn")
+ .setStyle(ButtonStyle.Primary),
+ new ButtonBuilder()
+ .setCustomId(`mod:mute:${member.user.id}`)
+ .setLabel("Mute")
+ .setStyle(ButtonStyle.Primary),
+ new ButtonBuilder()
+ .setCustomId(`mod:kick:${member.user.id}`)
+ .setLabel("Kick")
+ .setStyle(ButtonStyle.Danger),
+ new ButtonBuilder()
+ .setCustomId(`mod:ban:${member.user.id}`)
+ .setLabel("Ban")
+ .setStyle(ButtonStyle.Danger),
+ ].concat((usernameCheck !== null || nicknameCheck !== null || avatarTextCheck !== null) ? [
+ new ButtonBuilder()
+ .setCustomId(`mod:nickname:${member.user.id}`)
+ .setLabel("Change Name")
+ .setStyle(ButtonStyle.Primary)
+ ] : []))]
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/reflex/statsChannelUpdate.ts b/src/reflex/statsChannelUpdate.ts
index 6c601f7..e3c7a2a 100644
--- a/src/reflex/statsChannelUpdate.ts
+++ b/src/reflex/statsChannelUpdate.ts
@@ -1,7 +1,6 @@
import { getCommandMentionByName } from "../utils/getCommandDataByName.js";
import type { Guild, User } from "discord.js";
-import type { NucleusClient } from "../utils/client.js";
-import type { GuildMember } from "discord.js";
+import client from "../utils/client.js";
import convertCurlyBracketString from "../utils/convertCurlyBracketString.js";
import singleNotify from "../utils/singleNotify.js";
@@ -10,10 +9,8 @@
name: string;
}
-export async function callback(client: NucleusClient, member?: GuildMember, guild?: Guild, user?: User) {
- if (!member && !guild) return;
- guild = await client.guilds.fetch(member ? member.guild.id : guild!.id);
- user = user ?? member!.user;
+export async function callback(user: User, guild: Guild) {
+ guild = await client.guilds.fetch(guild.id);
const config = await client.database.guilds.read(guild.id);
Object.entries(config.stats).forEach(async ([channel, props]) => {
if ((props as PropSchema).enabled) {
@@ -22,16 +19,16 @@
string = await convertCurlyBracketString(string, user!.id, user!.username, guild!.name, guild!.members);
let fetchedChannel;
try {
- fetchedChannel = await guild!.channels.fetch(channel);
+ fetchedChannel = await guild.channels.fetch(channel);
} catch (e) {
fetchedChannel = null;
}
if (!fetchedChannel) {
const deleted = config.stats[channel];
- await client.database.guilds.write(guild!.id, null, `stats.${channel}`);
+ await client.database.guilds.write(guild.id, null, `stats.${channel}`);
return singleNotify(
"statsChannelDeleted",
- guild!.id,
+ guild.id,
`One or more of your stats channels have been deleted. You can use ${getCommandMentionByName(
"settings/stats"
)}.\n` + `The channels name was: ${deleted!.name}`,
diff --git a/src/reflex/welcome.ts b/src/reflex/welcome.ts
index 5597b81..8e471c6 100644
--- a/src/reflex/welcome.ts
+++ b/src/reflex/welcome.ts
@@ -1,12 +1,11 @@
import { getCommandMentionByName } from "./../utils/getCommandDataByName.js";
-import type { NucleusClient } from "../utils/client.js";
import convertCurlyBracketString from "../utils/convertCurlyBracketString.js";
import client from "../utils/client.js";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";
import { GuildChannel, GuildMember, BaseGuildTextChannel } from "discord.js";
import singleNotify from "../utils/singleNotify.js";
-export async function callback(_client: NucleusClient, member: GuildMember) {
+export async function callback(member: GuildMember) {
if (member.user.bot) return;
const config = await client.database.guilds.read(member.guild.id);
if (!config.welcome.enabled) return;