Files
ospab.host/ospabhost/frontend/src/utils/usernameBlacklist.ts

245 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Username blacklist validation
* Prevents registration with profanity and reserved words
*/
// Profanity and inappropriate words (Russian)
const RUSSIAN_BLACKLIST = [
// Мат - основные слова
'хуй', 'хуя', 'хуи', 'хуе', 'хую', 'хуем', 'хуев', 'хуйня', 'хуёвый', 'хуёво',
'xyй', 'xуй', 'хyй', 'xyи', 'xуи', 'хyи', 'хyйня', 'хyево',
'пизд', 'пизда', 'пиздец', 'пизды', 'пизде', 'пиздой', 'пиздюк', 'пиздёж',
'piзд', 'пiзд', 'пiзда', 'пизд0ц',
'ебал', 'ебать', 'ебет', 'ебут', 'ебал', 'ебала', 'ебало', 'еба', 'ебаный', 'ебанутый',
'ебош', 'ебло', 'ебля', 'выебон', 'заебал', 'заебись', 'наебал', 'поебать',
'бля', 'блять', 'блядь', 'бляд', 'блять', 'блят', 'блядина', 'блядский', 'блядство',
'бл@дь', 'бл@ть', 'блять', 'бл*дь',
'сука', 'суки', 'суку', 'сукой', 'сучка', 'сучара', 'cyка', 'cука', 'са', 'сyka',
'gандон', 'гандон', 'гондон', 'презерватив',
'пидор', 'пидар', 'педик', 'пидр', 'пидарас', 'пидрила', 'пидорас', 'педофил',
'пeдик', 'пидop', 'п1дор', 'пiдор',
'уебок', 'уебан', 'уебище', 'ублюдок', 'выродок',
'дебил', 'дебилоид', 'даун', 'долбоеб', 'еблан', 'ебланище',
'мудак', 'мудило', 'мудачье', 'мудачина', 'мудила', 'мудозвон',
'залупа', 'залупить', 'жопа', 'жопный', 'срака', 'сракотан',
'говно', 'говнюк', 'говноед', 'дерьмо', 'срать', 'высрал', 'обосрал',
'манда', 'мандавошка', 'влагалище', 'пилотка',
'шлюха', 'шалава', 'потаскуха', 'проститутка', 'блудница',
'гнида', 'падла', 'сволочь', 'мразь', 'тварь', 'скотина',
'чмо', 'чмошник', 'лох', 'лохматый', 'лошара', 'даун',
// Национальные оскорбления
'хохол', 'хохлы', 'хохлятина', 'хохляндия', 'укроп', 'укропы',
'москаль', 'москали', 'кацап', 'кацапы', 'кацапня',
'жид', 'жиды', 'жидовка', 'жидовня', 'жидяра', 'жидовский',
'еврей', 'еврейка', 'евреи', 'еврейский', 'жидовский', 'иудей',
'чурка', 'чурбан', 'чучмек', 'чучело', 'узбек', 'хачик', 'хач',
'азер', 'азиат', 'узкоглазый', 'косоглазый', 'раскосый',
'ниггер', 'негр', 'черножопый', ернож0пый', 'черномазый',
'пиндос', 'пиндосы', 'пиндосия', 'америкос', 'пендос',
// Нацистская тематика
'гитлер', 'гитлеровец', 'гиммлер', 'геббельс', 'геринг',
'нацист', 'нацисты', 'нацизм', 'наци', 'фашист', 'фашисты', 'фашизм',
'свастика', 'хайль', 'зиг', 'хайль', 'третийрейх', 'рейх',
'эсэс', 'сс', 'нсдап', 'вермахт',
'холокост', 'освенцим', 'концлагерь',
'ариец', 'арийцы', 'арийский', 'арийская',
// Экстремистские коды
'1488', '88', '14', 'авб', 'акб', 'ддт',
];
// Profanity and inappropriate words (English)
const ENGLISH_BLACKLIST = [
// Basic profanity
'fuck', 'fucked', 'fucker', 'fucking', 'fucks', 'fuk', 'fck', 'f**k', 'fock', 'fuk', 'phuck',
'motherfucker', 'motherfuck', 'mofo', 'mf',
'shit', 'shits', 'shitty', 'shitter', 'sh1t', 'sht', 'shite', 'bullshit', 'horseshit',
'bitch', 'bitches', 'bitching', 'b1tch', 'btch', 'biatch', 'beyotch',
'ass', 'asshole', 'arsehole', 'arse', 'a55', 'a55hole', 'asses', 'arsewipe',
'dick', 'dicks', 'dickhead', 'd1ck', 'dik', 'dickwad', 'dickface',
'cock', 'cocks', 'c0ck', 'cok', 'cocksucker', 'cocksuck',
'cunt', 'cunts', 'c**t', 'cnt', 'kunt',
'pussy', 'pussies', 'puss', 'pussycat',
'whore', 'slut', 'sluts', 'slutty', 'hoe', 'ho', 'tramp', 'prostitute',
'bastard', 'bastards', 'wanker', 'tosser', 'bellend', 'knobhead',
'damn', 'damned', 'goddamn', 'dammit', 'damnit',
'piss', 'pissed', 'pissing', 'pisser',
'twat', 'wank', 'bollocks', 'bugger',
// Racial slurs
'nigger', 'nigga', 'niggaz', 'niger', 'negro', 'n1gger', 'n1gga', 'nig', 'nigg',
'coon', 'jigaboo', 'spook', 'darkie', 'darky',
'chink', 'chinky', 'gook', 'zipperhead',
'spic', 'beaner', 'wetback', 'greaser',
'kike', 'yid', 'heeb', 'hymie', 'sheeny',
'towelhead', 'raghead', 'sandnigger', 'camel', 'muzzie',
'cracker', 'honky', 'whitey', 'paleface',
'paki', 'curry', 'dothead',
'abo', 'boong', 'coon',
// Homophobic slurs
'faggot', 'fag', 'fags', 'fagot', 'f4ggot', 'fagget', 'fagg0t',
'queer', 'dyke', 'homo', 'poof', 'fairy', 'fudgepacker',
'tranny', 'shemale', 'heshe',
// Mental health slurs
'retard', 'retarded', 'tard', 'retart', 'r3tard',
'mongoloid', 'mongo', 'downie', 'spastic', 'spaz',
'psycho', 'nutjob', 'lunatic', 'mental',
// Sexual content
'rape', 'raping', 'rapist', 'molest', 'pedophile', 'pedo',
'porn', 'porno', 'xxx', 'sex', 'anal', 'blowjob', 'handjob',
'masturbate', 'orgasm', 'cumshot', 'jizz', 'sperm',
// Nazi/Extremist terms
'nazi', 'nazy', 'n4zi', 'nаzi',
'hitler', 'adolf', 'fuhrer', 'fuehrer', 'gitler',
'heil', 'sieg', 'swastika', 'hakenkreuz',
'ss', 'gestapo', 'wehrmacht', 'nsdap',
'holocaust', 'auschwitz', 'konzentrationslager',
'aryan', 'kkk', 'klan', 'klux',
'skinhead', 'whitepower', 'whitesupremacy',
// Extremist codes
'1488', '14/88', '1488', 'fourteeneightyfour',
'acab', 'antifa', 'blm',
// Violence
'kill', 'murder', 'genocide', 'terrorist', 'bomb', 'shoot',
];
// Reserved system usernames
const RESERVED_NAMES = [
'admin', 'administrator', 'root', 'system', 'support',
'moderator', 'mod', 'operator', 'staff', 'team',
'official', 'help', 'info', 'contact', 'service',
'user', 'username', 'test', 'demo', 'guest',
'null', 'undefined', 'unknown', 'anonymous', 'anon',
'ospab', 'ospabhost', 'hosting', 'server',
'api', 'backup', 'cdn', 'database', 'email',
'ftp', 'mail', 'mysql', 'news', 'payment',
'postmaster', 'security', 'webmaster', 'www',
// Nazi leaders
'hitler', 'adolf', 'goebbels', 'himmler', 'goering', 'mengele',
'eichmann', 'bormann', 'hess', 'speer', 'heydrich',
// Extremist figures
'breivik', 'tarrant', 'roof', 'mcveigh',
];
// Common number patterns to avoid (like test123, user1, etc)
const GENERIC_PATTERNS = [
/^user\d+$/i,
/^test\d*$/i,
/^admin\d+$/i,
/^\d+$/, // Only numbers
// Extremist numeric codes
/1488/,
/88$/, // HH = Heil Hitler
/^88/,
/14$/,
/^14/,
// Nazi combinations
/(hitler|adolf|nazi|fuhrer).*(88|1488|14)/i,
/(88|1488|14).*(hitler|adolf|nazi|fuhrer)/i,
// Anti-semitic patterns
/(jew|jude|kike).*(kill|death|die|hate|burn)/i,
/(kill|death|die|hate|burn).*(jew|jude|kike)/i,
// Violence patterns
/(kill|murder|shoot).*(all|every)/i,
];
// Combine all blacklists
const COMBINED_BLACKLIST = new Set([
...RUSSIAN_BLACKLIST,
...ENGLISH_BLACKLIST,
...RESERVED_NAMES,
]);
export type UsernameValidationResult = {
isValid: boolean;
error?: string;
};
/**
* Check if username contains blacklisted words
*/
function containsBlacklistedWord(username: string): boolean {
const lower = username.toLowerCase();
// Check exact matches
if (COMBINED_BLACKLIST.has(lower)) {
return true;
}
// Check if username contains any blacklisted word
for (const word of COMBINED_BLACKLIST) {
if (lower.includes(word)) {
return true;
}
}
// Check generic patterns
for (const pattern of GENERIC_PATTERNS) {
if (pattern.test(username)) {
return true;
}
}
return false;
}
/**
* Validate username
*/
export function validateUsername(
username: string,
locale: 'ru' | 'en' = 'ru'
): UsernameValidationResult {
const trimmed = username.trim();
// Check length
if (trimmed.length < 3) {
return {
isValid: false,
error: locale === 'en'
? 'Username must be at least 3 characters long'
: 'Имя пользователя должно быть не менее 3 символов',
};
}
if (trimmed.length > 20) {
return {
isValid: false,
error: locale === 'en'
? 'Username must be no more than 20 characters'
: 'Имя пользователя должно быть не более 20 символов',
};
}
// Check format (alphanumeric, underscore, hyphen)
if (!/^[a-zA-Z0-9_-]+$/.test(trimmed)) {
return {
isValid: false,
error: locale === 'en'
? 'Username can only contain letters, numbers, underscore and hyphen'
: 'Имя пользователя может содержать только буквы, цифры, подчёркивание и дефис',
};
}
// Check blacklist
if (containsBlacklistedWord(trimmed)) {
return {
isValid: false,
error: locale === 'en'
? 'This username is not allowed. Please choose another one.'
: 'Это имя пользователя недопустимо. Пожалуйста, выберите другое.',
};
}
return { isValid: true };
}
/**
* Get username validation error message
*/
export function getUsernameError(
username: string,
locale: 'ru' | 'en' = 'ru'
): string | null {
const result = validateUsername(username, locale);
return result.error || null;
}