Advanced registration validation: email domain check, username blacklist, MX verification
This commit is contained in:
156
ospabhost/frontend/src/utils/usernameBlacklist.ts
Normal file
156
ospabhost/frontend/src/utils/usernameBlacklist.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Username blacklist validation
|
||||
* Prevents registration with profanity and reserved words
|
||||
*/
|
||||
|
||||
// Profanity and inappropriate words (Russian)
|
||||
const RUSSIAN_BLACKLIST = [
|
||||
'хуй', 'хуя', 'хуи', 'хуе', 'хую', 'xyй', 'xуй', 'хyй', 'xyи', 'xуи', 'хyи',
|
||||
'пизд', 'пизда', 'пиздец', 'пизды', 'пизде', 'пиздой', 'piзд', 'пiзд',
|
||||
'ебал', 'ебать', 'ебет', 'ебут', 'ебал', 'ебала', 'ебало', 'еба',
|
||||
'бля', 'блять', 'блядь', 'бляд', 'блять', 'блят', 'блядина', 'блядский',
|
||||
'сука', 'суки', 'суку', 'сукой', 'cyка', 'cука', 'сyка',
|
||||
'гандон', 'гондон', 'пидор', 'пидар', 'педик', 'пидр', 'пидарас',
|
||||
'уебок', 'уебан', 'дебил', 'мудак', 'долбоеб', 'еблан',
|
||||
'залупа', 'жопа', 'срака', 'говно', 'дерьмо', 'срать',
|
||||
'манда', 'мандавошка', 'влагалище',
|
||||
];
|
||||
|
||||
// Profanity and inappropriate words (English)
|
||||
const ENGLISH_BLACKLIST = [
|
||||
'fuck', 'fucked', 'fucker', 'fucking', 'fucks', 'fuk', 'fck', 'f**k',
|
||||
'shit', 'shits', 'shitty', 'shitter', 'sh1t', 'sht',
|
||||
'bitch', 'bitches', 'bitching', 'b1tch', 'btch',
|
||||
'ass', 'asshole', 'arsehole', 'arse', 'a55', 'a55hole',
|
||||
'dick', 'dicks', 'dickhead', 'd1ck', 'dik',
|
||||
'cock', 'cocks', 'c0ck', 'cok',
|
||||
'cunt', 'cunts', 'c**t', 'cnt',
|
||||
'pussy', 'pussies', 'puss',
|
||||
'whore', 'slut', 'sluts', 'slutty',
|
||||
'bastard', 'bastards', 'wanker', 'tosser',
|
||||
'nigger', 'nigga', 'negro', 'n1gger', 'n1gga',
|
||||
'faggot', 'fag', 'fags', 'fagot', 'f4ggot',
|
||||
'retard', 'retarded', 'tard',
|
||||
'rape', 'raping', 'rapist',
|
||||
'nazi', 'hitler', 'heil',
|
||||
];
|
||||
|
||||
// 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',
|
||||
];
|
||||
|
||||
// Common number patterns to avoid (like test123, user1, etc)
|
||||
const GENERIC_PATTERNS = [
|
||||
/^user\d+$/i,
|
||||
/^test\d*$/i,
|
||||
/^admin\d+$/i,
|
||||
/^\d+$/, // Only numbers
|
||||
];
|
||||
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user