Primitive banned words blocking

This commit is contained in:
Madeline 2022-09-11 23:19:55 +10:00
parent 4d23c4836d
commit b504edae92
8 changed files with 56 additions and 18 deletions

0
bundle/bannedWords Normal file
View File

View File

@ -7,7 +7,7 @@ import * as Gateway from "@fosscord/gateway";
import { CDNServer } from "@fosscord/cdn"; import { CDNServer } from "@fosscord/cdn";
import express from "express"; import express from "express";
import { green, bold, yellow } from "picocolors"; import { green, bold, yellow } from "picocolors";
import { Config, initDatabase } from "@fosscord/util"; import { Config, initDatabase, BannedWords } from "@fosscord/util";
import * as Sentry from "@sentry/node"; import * as Sentry from "@sentry/node";
import * as Tracing from "@sentry/tracing"; import * as Tracing from "@sentry/tracing";
@ -35,6 +35,7 @@ process.on('SIGTERM', () => {
async function main() { async function main() {
await initDatabase(); await initDatabase();
await Config.init(); await Config.init();
await BannedWords.init();
// only set endpointPublic, if not already set // only set endpointPublic, if not already set
await Config.set({ await Config.set({
cdn: { cdn: {

View File

@ -1,6 +1,5 @@
import { PublicUser, User } from "./User"; import { PublicUser, User } from "./User";
import { Message } from "./Message"; import { Message } from "./Message";
import { BaseClass } from "./BaseClass";
import { import {
Column, Column,
Entity, Entity,
@ -13,7 +12,7 @@ import {
RelationId, RelationId,
} from "typeorm"; } from "typeorm";
import { Guild } from "./Guild"; import { Guild } from "./Guild";
import { Config, emitEvent } from "../util"; import { Config, emitEvent, BannedWords, FieldErrors } from "../util";
import { import {
GuildCreateEvent, GuildCreateEvent,
GuildDeleteEvent, GuildDeleteEvent,
@ -21,6 +20,7 @@ import {
GuildMemberRemoveEvent, GuildMemberRemoveEvent,
GuildMemberUpdateEvent, GuildMemberUpdateEvent,
MessageCreateEvent, MessageCreateEvent,
} from "../interfaces"; } from "../interfaces";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { Role } from "./Role"; import { Role } from "./Role";
@ -73,6 +73,11 @@ export class Member extends BaseClassWithoutId {
@Column({ nullable: true }) @Column({ nullable: true })
nick?: string; nick?: string;
setNick(val: string) {
if (BannedWords.find(val)) throw FieldErrors({ nick: { message: "Bad nickname", code: "INVALID_NICKNAME" } });
this.nick = val;
}
@JoinTable({ @JoinTable({
name: "member_roles", name: "member_roles",
joinColumn: { name: "index", referencedColumnName: "index" }, joinColumn: { name: "index", referencedColumnName: "index" },
@ -244,7 +249,7 @@ export class Member extends BaseClassWithoutId {
where: { where: {
id: guild_id, id: guild_id,
}, },
relations: [ ...PublicGuildRelations, "system_channel" ], relations: [...PublicGuildRelations, "system_channel"],
}); });
if (await Member.count({ id: user.id, guild: { id: guild_id } })) if (await Member.count({ id: user.id, guild: { id: guild_id } }))

View File

@ -8,7 +8,6 @@ import {
Column, Column,
CreateDateColumn, CreateDateColumn,
Entity, Entity,
FindConditions,
Index, Index,
JoinColumn, JoinColumn,
JoinTable, JoinTable,
@ -16,14 +15,14 @@ import {
ManyToOne, ManyToOne,
OneToMany, OneToMany,
RelationId, RelationId,
RemoveOptions,
UpdateDateColumn,
} from "typeorm"; } from "typeorm";
import { BaseClass } from "./BaseClass"; import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild"; import { Guild } from "./Guild";
import { Webhook } from "./Webhook"; import { Webhook } from "./Webhook";
import { Sticker } from "./Sticker"; import { Sticker } from "./Sticker";
import { Attachment } from "./Attachment"; import { Attachment } from "./Attachment";
import { BannedWords } from "../util";
import { HTTPError } from "lambert-server";
export enum MessageType { export enum MessageType {
DEFAULT = 0, DEFAULT = 0,
@ -117,6 +116,11 @@ export class Message extends BaseClass {
@Column({ nullable: true, type: process.env.PRODUCTION ? "longtext" : undefined }) @Column({ nullable: true, type: process.env.PRODUCTION ? "longtext" : undefined })
content?: string; content?: string;
setContent(val: string) {
if (BannedWords.find(val)) throw new HTTPError("Message was blocked by automatic moderation", 200000);
this.content = val;
}
@Column() @Column()
@CreateDateColumn() @CreateDateColumn()
timestamp: Date; timestamp: Date;

View File

@ -3,9 +3,8 @@ import { BaseClass } from "./BaseClass";
import { BitField } from "../util/BitField"; import { BitField } from "../util/BitField";
import { Relationship } from "./Relationship"; import { Relationship } from "./Relationship";
import { ConnectedAccount } from "./ConnectedAccount"; import { ConnectedAccount } from "./ConnectedAccount";
import { Config, FieldErrors, Snowflake, trimSpecial } from ".."; import { Config, FieldErrors, Snowflake, trimSpecial, BannedWords } from "..";
import { Member, Session } from "."; import { Member, Session } from ".";
import { Note } from "./Note";
export enum PublicUserEnum { export enum PublicUserEnum {
username, username,
@ -49,7 +48,7 @@ export const PrivateUserProjection = [
// Private user data that should never get sent to the client // Private user data that should never get sent to the client
export type PublicUser = Pick<User, PublicUserKeys>; export type PublicUser = Pick<User, PublicUserKeys>;
export interface UserPublic extends Pick<User, PublicUserKeys> {} export interface UserPublic extends Pick<User, PublicUserKeys> { }
export interface UserPrivate extends Pick<User, PrivateUserKeys> { export interface UserPrivate extends Pick<User, PrivateUserKeys> {
locale: string; locale: string;
@ -60,6 +59,11 @@ export class User extends BaseClass {
@Column() @Column()
username: string; // username max length 32, min 2 (should be configurable) username: string; // username max length 32, min 2 (should be configurable)
setUsername(val: string) {
if (BannedWords.find(val)) throw FieldErrors({ username: { message: "Bad username", code: "INVALID_USERNAME" } });
this.username = val;
}
@Column() @Column()
discriminator: string; // opaque string: 4 digits on discord.com discriminator: string; // opaque string: 4 digits on discord.com
@ -299,7 +303,7 @@ export class User extends BaseClass {
setImmediate(async () => { setImmediate(async () => {
if (Config.get().guild.autoJoin.enabled) { if (Config.get().guild.autoJoin.enabled) {
for (const guild of Config.get().guild.autoJoin.guilds || []) { for (const guild of Config.get().guild.autoJoin.guilds || []) {
await Member.addToGuild(user.id, guild).catch((e) => {}); await Member.addToGuild(user.id, guild).catch((e) => { });
} }
} }
}); });
@ -366,7 +370,7 @@ export interface UserSettings {
disable_games_tab: boolean; disable_games_tab: boolean;
enable_tts_command: boolean; enable_tts_command: boolean;
explicit_content_filter: number; explicit_content_filter: number;
friend_source_flags: { all: boolean }; friend_source_flags: { all: boolean; };
gateway_connected: boolean; gateway_connected: boolean;
gif_auto_play: boolean; gif_auto_play: boolean;
// every top guild is displayed as a "folder" // every top guild is displayed as a "folder"

View File

@ -0,0 +1,23 @@
import fs from "fs/promises";
import path from "path";
var words: string[];
export const BannedWords = {
init: async function init() {
if (words) return words;
const file = (await fs.readFile(path.join(process.cwd(), "bannedWords"))).toString();
if (!file) {
words = [];
return [];
}
words = file.trim().split("\n");
return words;
},
get: () => words,
find: (val: string) => {
return words.some(x => val.indexOf(x) != -1);
}
};

View File

@ -20,3 +20,4 @@ export * from "./String";
export * from "./Array"; export * from "./Array";
export * from "./TraverseDirectory"; export * from "./TraverseDirectory";
export * from "./InvisibleCharacters"; export * from "./InvisibleCharacters";
export * from "./BannedWords";