diff --git a/server/src/config.ts b/server/src/config.ts index f298310f1..4616e2389 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -226,6 +226,11 @@ export interface ConfigType { * Limits the number of teams that can be created by any one IP address. */ readonly maxTeams?: number + + /** + * If a player's username matches one of the regexes in this array, it will be replaced with the default username. + */ + readonly usernameFilters?: RegExp[] } /** diff --git a/server/src/game.ts b/server/src/game.ts index 28bdb9740..64c9fafe4 100644 --- a/server/src/game.ts +++ b/server/src/game.ts @@ -46,9 +46,8 @@ import { PluginManager } from "./pluginManager"; import { Team } from "./team"; import { Grid } from "./utils/grid"; import { IDAllocator } from "./utils/idAllocator"; -import { Logger, removeFrom } from "./utils/misc"; +import { cleanUsername, Logger, removeFrom } from "./utils/misc"; import { createServer, forbidden, getIP } from "./utils/serverHelpers"; -import { cleanUsername } from "./utils/usernameFilter"; /* eslint-disable diff --git a/server/src/server.ts b/server/src/server.ts index a102e6224..9647d2cd4 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -16,7 +16,7 @@ import { findGame, games, newGame } from "./gameManager"; import { CustomTeam, CustomTeamPlayer, type CustomTeamPlayerContainer } from "./team"; import { Logger } from "./utils/misc"; import { cors, createServer, forbidden, getIP, textDecoder } from "./utils/serverHelpers"; -import { cleanUsername } from "./utils/usernameFilter"; +import { cleanUsername } from "./utils/misc"; export interface Punishment { readonly id: string diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index 1f4103cf7..3c0b3cf61 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -4,6 +4,8 @@ import { NullString, type ObjectDefinition, type ReferenceTo } from "@common/uti import { weightedRandom } from "@common/utils/random"; import { LootTiers, type WeightedItem } from "../data/lootTables"; +import { Config } from "../config"; +import { GameConstants } from "@common/constants"; export const Logger = { log(...message: string[]): void { @@ -23,6 +25,17 @@ function internalLog(...message: string[]): void { ); } +export function cleanUsername(name?: string | null): string { + return ( + !name?.length + || name.length > 16 + || Config.protection?.usernameFilters?.some(regex => regex.test(name)) + || /[^\x20-\x7E]/g.test(name) // extended ASCII chars + ) + ? GameConstants.player.defaultName + : name; +} + export class LootItem { constructor( public readonly idString: ReferenceTo, diff --git a/server/src/utils/usernameFilter.ts b/server/src/utils/usernameFilter.ts deleted file mode 100644 index 9d20dbd5e..000000000 --- a/server/src/utils/usernameFilter.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { GameConstants } from "@common/constants"; -import { Config } from "../config"; - -const badWordRegexes: RegExp[] = [ - /n[i1l!|\\/(){}[\]]+[g693]+[e3]*[ra@]*/i, // N word - /f[a@4]+[g9]+[s$5z2]+[ao0]+[t+]*/i, // F slur - /n[a@4]+z[i1]+[s$5z2]*/i, // Nazi references - /a[d]+[o0]+[/|l1]+[f]+(\s|\W|_)*h[/|!i1]+[t]+[/|!l1]+[e3]+[r]+/i, // Hitler - /(?=.*k[i1]+[l1]+[l1]*)(?=.*j[e3]+[w]+[s$5z2]*)/i // Antisemitist stuff - // FIXME too broad, matches "rap" - // sounds like that * at the end should be a + then - /// (?=.*m[o0]+[l1]+[e3]+[s$5z2]+[t+]*)|(?=.*r[a@4]+[p]+[e3]*)/i // Molest and rape -]; - -export function cleanUsername(name?: string | null): string { - return ( - !name?.length - || name.length > 16 - || (!Config.disableUsernameFilter && badWordRegexes.some(regex => regex.test(name))) - - || /[^\x20-\x7E]/g.test(name) // extended ASCII chars - ) - ? GameConstants.player.defaultName - : name; -}