Skip to content

Instantly share code, notes, and snippets.

@KosayJabre
Created January 27, 2025 01:03
Show Gist options
  • Save KosayJabre/61cae43bab664f317fdf7ff43d31dc10 to your computer and use it in GitHub Desktop.
Save KosayJabre/61cae43bab664f317fdf7ff43d31dc10 to your computer and use it in GitHub Desktop.
Basic username validation. Checks for profanity, emails, and other basic rules.
import re
from better_profanity import profanity
from pydantic import BaseModel
from email_validator import validate_email, EmailNotValidError
MINIMUM_USERNAME_LENGTH = 3
MAXIMUM_USERNAME_LENGTH = 24
ALLOWED_CHARACTERS_REGEX = re.compile(r"^[\x20-\x7E]+$") # Only allow visible/printable ASCII characters
RESERVED_WORDS = ["admin", "administrator", "staff", "support", "root"]
class UsernameValidationResult(BaseModel):
is_valid: bool
reason: str | None = None
def validate_username(username: str) -> UsernameValidationResult:
if len(username) < MINIMUM_USERNAME_LENGTH:
return UsernameValidationResult(is_valid=False, reason=f"Username is too short. It must be at least {MINIMUM_USERNAME_LENGTH} characters.")
if len(username) > MAXIMUM_USERNAME_LENGTH:
return UsernameValidationResult(is_valid=False, reason=f"Username is too long. It must be at most {MAXIMUM_USERNAME_LENGTH} characters.")
if username.strip() != username:
return UsernameValidationResult(is_valid=False, reason=f"Username cannot start or end with whitespace.")
if not ALLOWED_CHARACTERS_REGEX.match(username):
return UsernameValidationResult(
is_valid=False, reason=f"Username contains invalid characters. Only alphanumeric characters, underscores, and hyphens are allowed."
)
if username.isdigit():
return UsernameValidationResult(is_valid=False, reason=f"Username cannot be number-only.")
if username.lower() in RESERVED_WORDS:
return UsernameValidationResult(is_valid=False, reason=f"Username is reserved.")
if profanity.contains_profanity(username):
return UsernameValidationResult(is_valid=False, reason=f"Username might contain profanity.")
try:
validate_email(username, check_deliverability=False) # check_deliverability=False makes it not require internet
return UsernameValidationResult(is_valid=False, reason=f"Username cannot be an email address.")
except EmailNotValidError as e:
pass # Username is not an email address
return UsernameValidationResult(is_valid=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment