mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-03-16 14:11:50 +00:00
212 lines
6.1 KiB
TypeScript
212 lines
6.1 KiB
TypeScript
import { Plugin, decorators as d } from "knub";
|
|
import { Invite, Message } from "eris";
|
|
import url from "url";
|
|
import tlds from "tlds";
|
|
import escapeStringRegexp from "escape-string-regexp";
|
|
import { GuildLogs } from "../data/GuildLogs";
|
|
import { LogType } from "../data/LogType";
|
|
import { stripObjectToScalars } from "../utils";
|
|
|
|
const urlRegex = /(\S+\.\S+)/g;
|
|
const protocolRegex = /^[a-z]+:\/\//;
|
|
|
|
const getInviteCodesInString = (str: string): string[] => {
|
|
const inviteCodeRegex = /(?:discord.gg|discordapp.com\/invite)\/([a-z0-9]+)/gi;
|
|
const inviteCodes = [];
|
|
let match;
|
|
|
|
// tslint:disable-next-line
|
|
while ((match = inviteCodeRegex.exec(str)) !== null) {
|
|
inviteCodes.push(match[1]);
|
|
}
|
|
|
|
return inviteCodes;
|
|
};
|
|
|
|
const getUrlsInString = (str: string): url.URL[] => {
|
|
const matches = str.match(urlRegex) || [];
|
|
return matches.reduce((urls, match) => {
|
|
if (!protocolRegex.test(match)) {
|
|
match = `https://${match}`;
|
|
}
|
|
|
|
let matchUrl: url.URL;
|
|
try {
|
|
matchUrl = new url.URL(match);
|
|
} catch (e) {
|
|
return urls;
|
|
}
|
|
|
|
const hostnameParts = matchUrl.hostname.split(".");
|
|
const tld = hostnameParts[hostnameParts.length - 1];
|
|
if (tlds.includes(tld)) {
|
|
urls.push(matchUrl);
|
|
}
|
|
|
|
return urls;
|
|
}, []);
|
|
};
|
|
|
|
export class CensorPlugin extends Plugin {
|
|
protected serverLogs: GuildLogs;
|
|
|
|
getDefaultOptions() {
|
|
return {
|
|
config: {
|
|
filter_invites: false,
|
|
invite_guild_whitelist: null,
|
|
invite_guild_blacklist: null,
|
|
invite_code_whitelist: null,
|
|
invite_code_blacklist: null,
|
|
|
|
filter_domains: false,
|
|
domain_whitelist: null,
|
|
domain_blacklist: null,
|
|
|
|
blocked_tokens: null,
|
|
blocked_words: null,
|
|
blocked_regex: null
|
|
},
|
|
|
|
overrides: [
|
|
{
|
|
level: ">=50",
|
|
config: {
|
|
filter_invites: false,
|
|
filter_domains: false,
|
|
blocked_tokens: null,
|
|
blocked_words: null,
|
|
blocked_regex: null
|
|
}
|
|
}
|
|
]
|
|
};
|
|
}
|
|
|
|
onLoad() {
|
|
this.serverLogs = new GuildLogs(this.guildId);
|
|
}
|
|
|
|
async censorMessage(msg: Message, reason: string) {
|
|
this.serverLogs.ignoreLog(LogType.MESSAGE_DELETE, msg.id);
|
|
|
|
try {
|
|
await msg.delete("Censored");
|
|
} catch (e) {
|
|
return;
|
|
}
|
|
|
|
this.serverLogs.log(LogType.CENSOR, {
|
|
member: stripObjectToScalars(msg.member, ["user"]),
|
|
channel: stripObjectToScalars(msg.channel),
|
|
reason,
|
|
messageText: msg.cleanContent
|
|
});
|
|
}
|
|
|
|
async applyFiltersToMsg(msg: Message) {
|
|
if (msg.author.bot) return;
|
|
if (msg.type !== 0) return;
|
|
if (!msg.content) return;
|
|
|
|
// Filter invites
|
|
if (this.configValueForMsg(msg, "filter_invites")) {
|
|
const inviteGuildWhitelist: string[] = this.configValueForMsg(msg, "invite_guild_whitelist");
|
|
const inviteGuildBlacklist: string[] = this.configValueForMsg(msg, "invite_guild_blacklist");
|
|
const inviteCodeWhitelist: string[] = this.configValueForMsg(msg, "invite_code_whitelist");
|
|
const inviteCodeBlacklist: string[] = this.configValueForMsg(msg, "invite_code_blacklist");
|
|
|
|
const inviteCodes = getInviteCodesInString(msg.content);
|
|
|
|
const invites: Invite[] = await Promise.all(
|
|
inviteCodes.map(code => this.bot.getInvite(code))
|
|
);
|
|
|
|
for (const invite of invites) {
|
|
if (inviteGuildWhitelist && !inviteGuildWhitelist.includes(invite.guild.id)) {
|
|
this.censorMessage(
|
|
msg,
|
|
`invite guild (**${invite.guild.name}** \`${invite.guild.id}\`) not found in whitelist`
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (inviteGuildBlacklist && inviteGuildBlacklist.includes(invite.guild.id)) {
|
|
this.censorMessage(
|
|
msg,
|
|
`invite guild (**${invite.guild.name}** \`${invite.guild.id}\`) found in blacklist`
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (inviteCodeWhitelist && !inviteCodeWhitelist.includes(invite.code)) {
|
|
this.censorMessage(msg, `invite code (\`${invite.code}\`) not found in whitelist`);
|
|
return;
|
|
}
|
|
|
|
if (inviteCodeBlacklist && inviteCodeBlacklist.includes(invite.code)) {
|
|
this.censorMessage(msg, `invite code (\`${invite.code}\`) found in blacklist`);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Filter domains
|
|
if (this.configValueForMsg(msg, "filter_domains")) {
|
|
const domainWhitelist: string[] = this.configValueForMsg(msg, "domain_whitelist");
|
|
const domainBlacklist: string[] = this.configValueForMsg(msg, "domain_blacklist");
|
|
|
|
const urls = getUrlsInString(msg.content);
|
|
for (const thisUrl of urls) {
|
|
if (domainWhitelist && !domainWhitelist.includes(thisUrl.hostname)) {
|
|
this.censorMessage(msg, `domain (\`${thisUrl.hostname}\`) not found in whitelist`);
|
|
return;
|
|
}
|
|
|
|
if (domainBlacklist && domainBlacklist.includes(thisUrl.hostname)) {
|
|
this.censorMessage(msg, `domain (\`${thisUrl.hostname}\`) found in blacklist`);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Filter tokens
|
|
const blockedTokens = this.configValueForMsg(msg, "blocked_tokens") || [];
|
|
for (const token of blockedTokens) {
|
|
if (msg.content.includes(token)) {
|
|
this.censorMessage(msg, `blocked token (\`${token}\`) found`);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Filter words
|
|
const blockedWords = this.configValueForMsg(msg, "blocked_words") || [];
|
|
for (const word of blockedWords) {
|
|
const regex = new RegExp(`\\b${escapeStringRegexp(word)}\\b`, "i");
|
|
if (regex.test(msg.content)) {
|
|
this.censorMessage(msg, `blocked word (\`${word}\`) found`);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Filter regex
|
|
const blockedRegex = this.configValueForMsg(msg, "blocked_regex") || [];
|
|
for (const regexStr of blockedRegex) {
|
|
const regex = new RegExp(regexStr);
|
|
if (regex.test(msg.content)) {
|
|
this.censorMessage(msg, `blocked regex (\`${regexStr}\`) found`);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
@d.event("messageCreate")
|
|
async onMessageCreate(msg: Message) {
|
|
this.applyFiltersToMsg(msg);
|
|
}
|
|
|
|
@d.event("messageUpdate")
|
|
async onMessageUpdate(msg: Message) {
|
|
this.applyFiltersToMsg(msg);
|
|
}
|
|
}
|