aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIRONM00N <64110067+IRONM00N@users.noreply.github.com>2022-02-16 17:40:02 -0500
committerIRONM00N <64110067+IRONM00N@users.noreply.github.com>2022-02-16 17:40:02 -0500
commit43428f8a747f1b3e6b2a3418173910ce3ff1866c (patch)
treed1e7892fbd9d5f5881e9f34d3053a9fceb796c1d /src
parentb04c2b02c012baba9bbf2b8f3fb1a08c7796d38e (diff)
downloadtanzanite-43428f8a747f1b3e6b2a3418173910ce3ff1866c.tar.gz
tanzanite-43428f8a747f1b3e6b2a3418173910ce3ff1866c.tar.bz2
tanzanite-43428f8a747f1b3e6b2a3418173910ce3ff1866c.zip
feat: start testing perspectiveApi, and fix checkScamMentions
Diffstat (limited to 'src')
-rw-r--r--src/config/example-options.ts3
-rw-r--r--src/lib/common/AutoMod.ts163
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts8
-rw-r--r--src/lib/models/instance/Guild.ts17
-rw-r--r--src/lib/utils/Config.ts1
5 files changed, 133 insertions, 59 deletions
diff --git a/src/config/example-options.ts b/src/config/example-options.ts
index 338428e..1b384c4 100644
--- a/src/config/example-options.ts
+++ b/src/config/example-options.ts
@@ -9,7 +9,8 @@ export default new Config({
wolframAlphaAppId: '[APP_ID]',
imgurClientId: '[CLIENT_ID]',
imgurClientSecret: '[CLIENT_SECRET]',
- sentryDsn: 'SENTRY_DSN'
+ sentryDsn: 'SENTRY_DSN',
+ perspectiveApiKey: '[PERSPECTIVE_API_KEY]'
},
environment: 'development',
owners: [
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts
index 784085d..fc5532b 100644
--- a/src/lib/common/AutoMod.ts
+++ b/src/lib/common/AutoMod.ts
@@ -1,14 +1,7 @@
import { banResponse, Moderation, type BushButtonInteraction, type BushMessage } from '#lib';
-import {
- ActionRow,
- ButtonComponent,
- ButtonStyle,
- ChannelType,
- Embed,
- GuildMember,
- PermissionFlagsBits,
- type TextChannel
-} from 'discord.js';
+import assert from 'assert';
+import chalk from 'chalk';
+import { ActionRow, ButtonComponent, ButtonStyle, Embed, GuildMember, PermissionFlagsBits, type TextChannel } from 'discord.js';
/**
* Handles auto moderation functionality.
@@ -33,59 +26,77 @@ export class AutoMod {
void this.handle();
}
+ private get isImmune() {
+ if (!this.message.inGuild()) return false;
+ assert(this.message.member);
+
+ if (this.message.author.isOwner()) return true;
+ if (this.message.guild.ownerId === this.message.author.id) return true;
+ if (this.message.member.permissions.has('Administrator')) return true;
+
+ return false;
+ }
+
/**
* Handles the auto moderation
*/
private async handle() {
- if (this.message.channel.type === ChannelType.DM || !this.message.guild) return;
+ if (!this.message.inGuild()) return;
if (!(await this.message.guild.hasFeature('automod'))) return;
if (this.message.author.bot) return;
- if (this.message.author.isOwner()) return;
-
- const badLinksArray = util.getShared('badLinks');
- const badLinksSecretArray = util.getShared('badLinksSecret');
- const badWordsRaw = util.getShared('badWords');
-
- const customAutomodPhrases = (await this.message.guild.getSetting('autoModPhases')) ?? [];
- const uniqueLinks = [...new Set([...badLinksArray, ...badLinksSecretArray])];
-
- const badLinks: BadWordDetails[] = uniqueLinks.map((link) => ({
- match: link,
- severity: Severity.PERM_MUTE,
- ignoreSpaces: false,
- ignoreCapitalization: true,
- reason: 'malicious link',
- regex: false
- }));
-
- const parsedBadWords = Object.values(badWordsRaw).flat();
- const result = [
- ...this.checkWords(customAutomodPhrases),
- ...this.checkWords((await this.message.guild.hasFeature('excludeDefaultAutomod')) ? [] : parsedBadWords),
- ...this.checkWords((await this.message.guild.hasFeature('excludeAutomodScamLinks')) ? [] : badLinks)
- ];
-
- if (result.length === 0) return;
-
- const highestOffence = result.sort((a, b) => b.severity - a.severity)[0];
+ traditional: {
+ if (this.isImmune) break traditional;
+ const badLinksArray = util.getShared('badLinks');
+ const badLinksSecretArray = util.getShared('badLinksSecret');
+ const badWordsRaw = util.getShared('badWords');
+
+ const customAutomodPhrases = (await this.message.guild.getSetting('autoModPhases')) ?? [];
+ const uniqueLinks = [...new Set([...badLinksArray, ...badLinksSecretArray])];
+
+ const badLinks: BadWordDetails[] = uniqueLinks.map((link) => ({
+ match: link,
+ severity: Severity.PERM_MUTE,
+ ignoreSpaces: false,
+ ignoreCapitalization: true,
+ reason: 'malicious link',
+ regex: false
+ }));
+
+ const parsedBadWords = Object.values(badWordsRaw).flat();
+
+ const result = [
+ ...this.checkWords(customAutomodPhrases),
+ ...this.checkWords((await this.message.guild.hasFeature('excludeDefaultAutomod')) ? [] : parsedBadWords),
+ ...this.checkWords((await this.message.guild.hasFeature('excludeAutomodScamLinks')) ? [] : badLinks)
+ ];
+
+ if (result.length === 0) break traditional;
+
+ const highestOffence = result.sort((a, b) => b.severity - a.severity)[0];
+
+ if (highestOffence.severity === undefined || highestOffence.severity === null) {
+ void this.message.guild.sendLogChannel('error', {
+ embeds: [
+ {
+ title: 'AutoMod Error',
+ description: `Unable to find severity information for ${util.format.inlineCode(highestOffence.match)}`,
+ color: util.colors.error
+ }
+ ]
+ });
+ } else {
+ const color = this.punish(highestOffence);
+ void this.log(highestOffence, color, result);
+ }
+ }
- if (highestOffence.severity === undefined || highestOffence.severity === null) {
- void this.message.guild.sendLogChannel('error', {
- embeds: [
- {
- title: 'AutoMod Error',
- description: `Unable to find severity information for ${util.format.inlineCode(highestOffence.match)}`,
- color: util.colors.error
- }
- ]
- });
- } else {
- const color = this.punish(highestOffence);
- void this.log(highestOffence, color, result);
+ other: {
+ if (this.isImmune) break other;
+ if (!this.punished && (await this.message.guild.hasFeature('delScamMentions'))) void this.checkScamMentions();
}
- if (!this.punished && (await this.message.guild.hasFeature('delScamMentions'))) void this.checkScamMentions();
+ if (!this.punished && (await this.message.guild.hasFeature('perspectiveApi'))) void this.checkPerspectiveApi();
}
/**
@@ -166,6 +177,52 @@ export class AutoMod {
}
}
+ private async checkPerspectiveApi() {
+ if (!client.config.isDevelopment) return;
+
+ if (!this.message.content) return;
+ client.perspective.comments.analyze(
+ {
+ key: client.config.credentials.perspectiveApiKey,
+ resource: {
+ comment: {
+ text: this.message.content
+ },
+ requestedAttributes: {
+ TOXICITY: {},
+ SEVERE_TOXICITY: {},
+ IDENTITY_ATTACK: {},
+ INSULT: {},
+ PROFANITY: {},
+ THREAT: {},
+ SEXUALLY_EXPLICIT: {},
+ FLIRTATION: {}
+ }
+ }
+ },
+ (err: any, response: any) => {
+ if (err) return console.log(err?.message);
+
+ const normalize = (val: number, min: number, max: number) => (val - min) / (max - min);
+
+ const color = (val: number) => {
+ if (val >= 0.5) {
+ const x = 194 - Math.round(normalize(val, 0.5, 1) * 194);
+ return chalk.rgb(194, x, 0)(val);
+ } else {
+ const x = Math.round(normalize(val, 0, 0.5) * 194);
+ return chalk.rgb(x, 194, 0)(val);
+ }
+ };
+
+ console.log(chalk.cyan(this.message.content));
+ Object.entries(response.data.attributeScores)
+ .sort(([a], [b]) => a.localeCompare(b))
+ .forEach(([key, value]: any[]) => console.log(chalk.white(key), color(value.summaryScore.value)));
+ }
+ );
+ }
+
/**
* Format a string according to the word options
* @param string The string to format
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index 904ab51..43ae139 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -41,6 +41,7 @@ import {
type WebhookEditMessageOptions
} from 'discord.js';
import EventEmitter from 'events';
+import { google } from 'googleapis';
import path from 'path';
import readline from 'readline';
import type { Options as SequelizeOptions, Sequelize as SequelizeType } from 'sequelize';
@@ -191,6 +192,11 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
public highlightManager = new HighlightManager();
/**
+ * The perspective api
+ */
+ public perspective: any;
+
+ /**
* @param config The configuration for the bot.
*/
public constructor(config: Config) {
@@ -335,6 +341,8 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
process.exit(2);
}
+ this.perspective = await google.discoverAPI<any>('https://commentanalyzer.googleapis.com/$discovery/rest?version=v1alpha1');
+
this.commandHandler.useInhibitorHandler(this.inhibitorHandler);
this.commandHandler.useListenerHandler(this.listenerHandler);
this.commandHandler.useTaskHandler(this.taskHandler);
diff --git a/src/lib/models/instance/Guild.ts b/src/lib/models/instance/Guild.ts
index 4d7f208..cdf3552 100644
--- a/src/lib/models/instance/Guild.ts
+++ b/src/lib/models/instance/Guild.ts
@@ -342,11 +342,12 @@ export const guildFeaturesObj = asGuildFeature({
default: false
},
// todo implement a better auto thread system
- // autoThread: {
- // name: 'Auto Thread',
- // description: 'Creates a new thread for messages in configured channels.',
- // default: false
- // },
+ autoThread: {
+ name: 'Auto Thread',
+ description: 'Creates a new thread for messages in configured channels.',
+ default: false,
+ notConfigurable: true
+ },
blacklistedFile: {
name: 'Blacklisted File',
description: 'Automatically deletes malicious files.',
@@ -392,6 +393,12 @@ export const guildFeaturesObj = asGuildFeature({
description: 'Allow users to appeal their punishments and send the appeal to the configured channel.',
default: false,
notConfigurable: true
+ },
+ perspectiveApi: {
+ name: 'Perspective API',
+ description: 'Use the Perspective API to detect toxicity.',
+ default: false,
+ notConfigurable: true
}
});
diff --git a/src/lib/utils/Config.ts b/src/lib/utils/Config.ts
index bc31964..ce5ec06 100644
--- a/src/lib/utils/Config.ts
+++ b/src/lib/utils/Config.ts
@@ -62,6 +62,7 @@ interface Credentials {
imgurClientId: string;
imgurClientSecret: string;
sentryDsn: string;
+ perspectiveApiKey: string;
}
type Environment = 'production' | 'beta' | 'development';