import { RegExpMatcher, englishDataset, englishRecommendedTransformers, } from "obscenity"; import { translateText } from "../../client/Utils"; import { simpleHash } from "../Util"; const matcher = new RegExpMatcher({ ...englishDataset.build(), ...englishRecommendedTransformers, }); export const MIN_USERNAME_LENGTH = 3; export const MAX_USERNAME_LENGTH = 27; const validPattern = /^[a-zA-Z0-9_\[\] πŸˆπŸ€ΓΌΓœ]+$/u; const shadowNames = [ "NicePeopleOnly", "BeKindPlz", "LearningManners", "StayClassy", "BeNicer", "NeedHugs", "MakeFriends", ]; export function fixProfaneUsername(username: string): string { if (isProfaneUsername(username)) { return shadowNames[simpleHash(username) % shadowNames.length]; } return username; } export function isProfaneUsername(username: string): boolean { return matcher.hasMatch(username) || username.toLowerCase().includes("nig"); } export function validateUsername(username: string): { isValid: boolean; error?: string; } { if (typeof username !== "string") { return { isValid: false, error: translateText("username.not_string") }; } if (username.length < MIN_USERNAME_LENGTH) { return { isValid: false, error: translateText("username.too_short", { min: MIN_USERNAME_LENGTH, }), }; } if (username.length > MAX_USERNAME_LENGTH) { return { isValid: false, error: translateText("username.too_long", { max: MAX_USERNAME_LENGTH, }), }; } if (!validPattern.test(username)) { return { isValid: false, error: translateText("username.invalid_chars", { max: MAX_USERNAME_LENGTH, }), }; } // All checks passed return { isValid: true }; } export function sanitizeUsername(str: string): string { const sanitized = str .replace(/[^a-zA-Z0-9_\[\] πŸˆπŸ€]/gu, "") .slice(0, MAX_USERNAME_LENGTH); return sanitized.padEnd(MIN_USERNAME_LENGTH, "x"); }