Primitive banned words blocking
This commit is contained in:
parent
4d23c4836d
commit
b504edae92
0
bundle/bannedWords
Normal file
0
bundle/bannedWords
Normal 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: {
|
||||||
|
@ -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 } }))
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -90,7 +94,7 @@ export class User extends BaseClass {
|
|||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
premium: boolean; // if user bought individual premium
|
premium: boolean; // if user bought individual premium
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
premium_type: number; // individual premium level
|
premium_type: number; // individual premium level
|
||||||
|
|
||||||
@ -105,7 +109,7 @@ export class User extends BaseClass {
|
|||||||
|
|
||||||
@Column({ select: false })
|
@Column({ select: false })
|
||||||
nsfw_allowed: boolean; // if the user can do age-restricted actions (NSFW channels/guilds/commands)
|
nsfw_allowed: boolean; // if the user can do age-restricted actions (NSFW channels/guilds/commands)
|
||||||
|
|
||||||
@Column({ select: false })
|
@Column({ select: false })
|
||||||
mfa_enabled: boolean; // if multi factor authentication is enabled
|
mfa_enabled: boolean; // if multi factor authentication is enabled
|
||||||
|
|
||||||
@ -176,7 +180,7 @@ export class User extends BaseClass {
|
|||||||
|
|
||||||
@Column({ type: "simple-json", select: false })
|
@Column({ type: "simple-json", select: false })
|
||||||
settings: UserSettings;
|
settings: UserSettings;
|
||||||
|
|
||||||
// workaround to prevent fossord-unaware clients from deleting settings not used by them
|
// workaround to prevent fossord-unaware clients from deleting settings not used by them
|
||||||
@Column({ type: "simple-json", select: false })
|
@Column({ type: "simple-json", select: false })
|
||||||
extended_settings: string;
|
extended_settings: string;
|
||||||
@ -202,7 +206,7 @@ export class User extends BaseClass {
|
|||||||
private static async generateDiscriminator(username: string): Promise<string | undefined> {
|
private static async generateDiscriminator(username: string): Promise<string | undefined> {
|
||||||
if (Config.get().register.incrementingDiscriminators) {
|
if (Config.get().register.incrementingDiscriminators) {
|
||||||
// discriminator will be incrementally generated
|
// discriminator will be incrementally generated
|
||||||
|
|
||||||
// First we need to figure out the currently highest discrimnator for the given username and then increment it
|
// 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 users = await User.find({ where: { username }, select: ["discriminator"] });
|
||||||
const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator)));
|
const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator)));
|
||||||
@ -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"
|
||||||
|
@ -29,4 +29,4 @@ export * from "./VoiceState";
|
|||||||
export * from "./Webhook";
|
export * from "./Webhook";
|
||||||
export * from "./ClientRelease";
|
export * from "./ClientRelease";
|
||||||
export * from "./BackupCodes";
|
export * from "./BackupCodes";
|
||||||
export * from "./Note";
|
export * from "./Note";
|
23
util/src/util/BannedWords.ts
Normal file
23
util/src/util/BannedWords.ts
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
@ -19,4 +19,5 @@ export * from "./Snowflake";
|
|||||||
export * from "./String";
|
export * from "./String";
|
||||||
export * from "./Array";
|
export * from "./Array";
|
||||||
export * from "./TraverseDirectory";
|
export * from "./TraverseDirectory";
|
||||||
export * from "./InvisibleCharacters";
|
export * from "./InvisibleCharacters";
|
||||||
|
export * from "./BannedWords";
|
Loading…
x
Reference in New Issue
Block a user