Spaces:
Runtime error
Runtime error
| """ | |
| Authentication Module | |
| User authentication, password hashing, and session management | |
| """ | |
| import hashlib | |
| import secrets | |
| import re | |
| from datetime import datetime, timedelta | |
| def hash_password(password): | |
| """ | |
| Hash password using SHA-256 with salt | |
| Args: | |
| password (str): Plain text password | |
| Returns: | |
| str: Hashed password (salt + hash) | |
| """ | |
| # Generate random salt | |
| salt = secrets.token_hex(16) | |
| # Hash password with salt | |
| password_hash = hashlib.sha256((salt + password).encode()).hexdigest() | |
| # Return salt + hash (separated by $) | |
| return f"{salt}${password_hash}" | |
| def verify_password(password, stored_hash): | |
| """ | |
| Verify password against stored hash | |
| Args: | |
| password (str): Plain text password to verify | |
| stored_hash (str): Stored hash (salt$hash format) | |
| Returns: | |
| bool: True if password matches, False otherwise | |
| """ | |
| try: | |
| # Split salt and hash | |
| salt, hash_value = stored_hash.split('$') | |
| # Hash the input password with the same salt | |
| test_hash = hashlib.sha256((salt + password).encode()).hexdigest() | |
| # Compare | |
| return test_hash == hash_value | |
| except Exception: | |
| return False | |
| def validate_email(email): | |
| """ | |
| Validate email format | |
| Args: | |
| email (str): Email address | |
| Returns: | |
| tuple: (valid: bool, message: str) | |
| """ | |
| # Basic email regex pattern | |
| pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' | |
| if not email: | |
| return (False, 'Email is required') | |
| if not re.match(pattern, email): | |
| return (False, 'Invalid email format') | |
| if len(email) > 255: | |
| return (False, 'Email too long (max 255 characters)') | |
| return (True, 'Valid email') | |
| def validate_username(username): | |
| """ | |
| Validate username | |
| Args: | |
| username (str): Username | |
| Returns: | |
| tuple: (valid: bool, message: str) | |
| """ | |
| if not username: | |
| return (False, 'Username is required') | |
| if len(username) < 3: | |
| return (False, 'Username must be at least 3 characters') | |
| if len(username) > 50: | |
| return (False, 'Username too long (max 50 characters)') | |
| # Allow alphanumeric, underscore, hyphen | |
| if not re.match(r'^[a-zA-Z0-9_-]+$', username): | |
| return (False, 'Username can only contain letters, numbers, underscore, and hyphen') | |
| return (True, 'Valid username') | |
| def validate_password(password, retype_password=None): | |
| """ | |
| Validate password strength | |
| Args: | |
| password (str): Password | |
| retype_password (str, optional): Password confirmation | |
| Returns: | |
| tuple: (valid: bool, message: str) | |
| """ | |
| if not password: | |
| return (False, 'Password is required') | |
| if len(password) < 6: | |
| return (False, 'Password must be at least 6 characters') | |
| if len(password) > 128: | |
| return (False, 'Password too long (max 128 characters)') | |
| # Check if passwords match (if retype provided) | |
| if retype_password is not None and password != retype_password: | |
| return (False, 'Passwords do not match') | |
| # Optional: Add more strength checks | |
| # if not any(c.isupper() for c in password): | |
| # return (False, 'Password must contain at least one uppercase letter') | |
| # if not any(c.isdigit() for c in password): | |
| # return (False, 'Password must contain at least one number') | |
| return (True, 'Valid password') | |
| def generate_session_token(): | |
| """ | |
| Generate secure session token | |
| Returns: | |
| str: Random session token | |
| """ | |
| return secrets.token_urlsafe(32) | |
| def validate_registration(username, email, password, retype_password): | |
| """ | |
| Validate registration form data | |
| Args: | |
| username (str): Username | |
| email (str): Email | |
| password (str): Password | |
| retype_password (str): Password confirmation | |
| Returns: | |
| tuple: (valid: bool, errors: dict) | |
| """ | |
| errors = {} | |
| # Validate username | |
| valid, msg = validate_username(username) | |
| if not valid: | |
| errors['username'] = msg | |
| # Validate email | |
| valid, msg = validate_email(email) | |
| if not valid: | |
| errors['email'] = msg | |
| # Validate password | |
| valid, msg = validate_password(password, retype_password) | |
| if not valid: | |
| errors['password'] = msg | |
| return (len(errors) == 0, errors) | |
| def validate_login(identifier, password): | |
| """ | |
| Validate login form data | |
| Args: | |
| identifier (str): Username or email | |
| password (str): Password | |
| Returns: | |
| tuple: (valid: bool, errors: dict) | |
| """ | |
| errors = {} | |
| if not identifier: | |
| errors['identifier'] = 'Username or email is required' | |
| if not password: | |
| errors['password'] = 'Password is required' | |
| return (len(errors) == 0, errors) | |
| def is_email(identifier): | |
| """ | |
| Check if identifier is an email | |
| Args: | |
| identifier (str): Username or email | |
| Returns: | |
| bool: True if email, False if username | |
| """ | |
| return '@' in identifier | |
| if __name__ == "__main__": | |
| # Test password hashing | |
| password = "test123" | |
| hashed = hash_password(password) | |
| print(f"Password: {password}") | |
| print(f"Hashed: {hashed}") | |
| print(f"Verification: {verify_password(password, hashed)}") | |
| print(f"Wrong password: {verify_password('wrong', hashed)}") | |
| # Test validation | |
| print("\nValidation Tests:") | |
| print(validate_username("user123")) | |
| print(validate_email("test@example.com")) | |
| print(validate_password("password", "password")) | |
| print(validate_password("short", "short")) | |