diff --git a/bundle/bannedWords b/bundle/bannedWords
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/bundle/bannedWords
diff --git a/bundle/src/Server.ts b/bundle/src/Server.ts
index 9cef9ed1..df29266d 100644
--- a/bundle/src/Server.ts
+++ b/bundle/src/Server.ts
@@ -7,7 +7,7 @@ import * as Gateway from "@fosscord/gateway";
import { CDNServer } from "@fosscord/cdn";
import express from "express";
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 Tracing from "@sentry/tracing";
@@ -35,6 +35,7 @@ process.on('SIGTERM', () => {
async function main() {
await initDatabase();
await Config.init();
+ await BannedWords.init();
// only set endpointPublic, if not already set
await Config.set({
cdn: {
diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts
index a6798a7c..387181df 100644
--- a/util/src/entities/Member.ts
+++ b/util/src/entities/Member.ts
@@ -1,6 +1,5 @@
import { PublicUser, User } from "./User";
import { Message } from "./Message";
-import { BaseClass } from "./BaseClass";
import {
Column,
Entity,
@@ -13,7 +12,7 @@ import {
RelationId,
} from "typeorm";
import { Guild } from "./Guild";
-import { Config, emitEvent } from "../util";
+import { Config, emitEvent, BannedWords, FieldErrors } from "../util";
import {
GuildCreateEvent,
GuildDeleteEvent,
@@ -21,6 +20,7 @@ import {
GuildMemberRemoveEvent,
GuildMemberUpdateEvent,
MessageCreateEvent,
+
} from "../interfaces";
import { HTTPError } from "lambert-server";
import { Role } from "./Role";
@@ -73,6 +73,11 @@ export class Member extends BaseClassWithoutId {
@Column({ nullable: true })
nick?: string;
+ setNick(val: string) {
+ if (BannedWords.find(val)) throw FieldErrors({ nick: { message: "Bad nickname", code: "INVALID_NICKNAME" } });
+ this.nick = val;
+ }
+
@JoinTable({
name: "member_roles",
joinColumn: { name: "index", referencedColumnName: "index" },
@@ -244,7 +249,7 @@ export class Member extends BaseClassWithoutId {
where: {
id: guild_id,
},
- relations: [ ...PublicGuildRelations, "system_channel" ],
+ relations: [...PublicGuildRelations, "system_channel"],
});
if (await Member.count({ id: user.id, guild: { id: guild_id } }))
diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts
index 38242152..78888e17 100644
--- a/util/src/entities/Message.ts
+++ b/util/src/entities/Message.ts
@@ -8,7 +8,6 @@ import {
Column,
CreateDateColumn,
Entity,
- FindConditions,
Index,
JoinColumn,
JoinTable,
@@ -16,14 +15,14 @@ import {
ManyToOne,
OneToMany,
RelationId,
- RemoveOptions,
- UpdateDateColumn,
} from "typeorm";
import { BaseClass } from "./BaseClass";
import { Guild } from "./Guild";
import { Webhook } from "./Webhook";
import { Sticker } from "./Sticker";
import { Attachment } from "./Attachment";
+import { BannedWords } from "../util";
+import { HTTPError } from "lambert-server";
export enum MessageType {
DEFAULT = 0,
@@ -117,6 +116,11 @@ export class Message extends BaseClass {
@Column({ nullable: true, type: process.env.PRODUCTION ? "longtext" : undefined })
content?: string;
+ setContent(val: string) {
+ if (BannedWords.find(val)) throw new HTTPError("Message was blocked by automatic moderation", 200000);
+ this.content = val;
+ }
+
@Column()
@CreateDateColumn()
timestamp: Date;
diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts
index cac2784a..230d6d82 100644
--- a/util/src/entities/User.ts
+++ b/util/src/entities/User.ts
@@ -3,9 +3,8 @@ import { BaseClass } from "./BaseClass";
import { BitField } from "../util/BitField";
import { Relationship } from "./Relationship";
import { ConnectedAccount } from "./ConnectedAccount";
-import { Config, FieldErrors, Snowflake, trimSpecial } from "..";
+import { Config, FieldErrors, Snowflake, trimSpecial, BannedWords } from "..";
import { Member, Session } from ".";
-import { Note } from "./Note";
export enum PublicUserEnum {
username,
@@ -49,7 +48,7 @@ export const PrivateUserProjection = [
// Private user data that should never get sent to the client
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> {
locale: string;
@@ -60,6 +59,11 @@ export class User extends BaseClass {
@Column()
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()
discriminator: string; // opaque string: 4 digits on discord.com
@@ -90,7 +94,7 @@ export class User extends BaseClass {
@Column()
premium: boolean; // if user bought individual premium
-
+
@Column()
premium_type: number; // individual premium level
@@ -105,7 +109,7 @@ export class User extends BaseClass {
@Column({ select: false })
nsfw_allowed: boolean; // if the user can do age-restricted actions (NSFW channels/guilds/commands)
-
+
@Column({ select: false })
mfa_enabled: boolean; // if multi factor authentication is enabled
@@ -176,7 +180,7 @@ export class User extends BaseClass {
@Column({ type: "simple-json", select: false })
settings: UserSettings;
-
+
// workaround to prevent fossord-unaware clients from deleting settings not used by them
@Column({ type: "simple-json", select: false })
extended_settings: string;
@@ -202,7 +206,7 @@ export class User extends BaseClass {
private static async generateDiscriminator(username: string): Promise<string | undefined> {
if (Config.get().register.incrementingDiscriminators) {
// discriminator will be incrementally generated
-
+
// First we need to figure out the currently highest discrimnator for the given username and then increment it
const users = await User.find({ where: { username }, select: ["discriminator"] });
const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator)));
@@ -299,7 +303,7 @@ export class User extends BaseClass {
setImmediate(async () => {
if (Config.get().guild.autoJoin.enabled) {
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;
enable_tts_command: boolean;
explicit_content_filter: number;
- friend_source_flags: { all: boolean };
+ friend_source_flags: { all: boolean; };
gateway_connected: boolean;
gif_auto_play: boolean;
// every top guild is displayed as a "folder"
diff --git a/util/src/entities/index.ts b/util/src/entities/index.ts
index c439a4b7..49793810 100644
--- a/util/src/entities/index.ts
+++ b/util/src/entities/index.ts
@@ -29,4 +29,4 @@ export * from "./VoiceState";
export * from "./Webhook";
export * from "./ClientRelease";
export * from "./BackupCodes";
-export * from "./Note";
+export * from "./Note";
\ No newline at end of file
diff --git a/util/src/util/BannedWords.ts b/util/src/util/BannedWords.ts
new file mode 100644
index 00000000..891a5980
--- /dev/null
+++ b/util/src/util/BannedWords.ts
@@ -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);
+ }
+};
\ No newline at end of file
diff --git a/util/src/util/index.ts b/util/src/util/index.ts
index f7a273cb..b2bd6489 100644
--- a/util/src/util/index.ts
+++ b/util/src/util/index.ts
@@ -19,4 +19,5 @@ export * from "./Snowflake";
export * from "./String";
export * from "./Array";
export * from "./TraverseDirectory";
-export * from "./InvisibleCharacters";
\ No newline at end of file
+export * from "./InvisibleCharacters";
+export * from "./BannedWords";
\ No newline at end of file
|