Spaces:
Sleeping
Sleeping
| """ | |
| Security utilities for API key management and validation. | |
| This module provides secure handling of sensitive configuration data. | |
| """ | |
| import hashlib | |
| import os | |
| import secrets | |
| from typing import Optional, Dict, Any | |
| from dataclasses import dataclass | |
| from datetime import datetime | |
| from enum import Enum | |
| class ErrorType(Enum): | |
| """Types of errors that can occur in the system.""" | |
| VALIDATION_ERROR = "validation_error" | |
| AUTHENTICATION_ERROR = "authentication_error" | |
| AUTHORIZATION_ERROR = "authorization_error" | |
| RATE_LIMIT_ERROR = "rate_limit_error" | |
| API_ERROR = "api_error" | |
| NETWORK_ERROR = "network_error" | |
| TIMEOUT_ERROR = "timeout_error" | |
| UNKNOWN_ERROR = "unknown_error" | |
| class ErrorResponse: | |
| """Standardized error response for API operations.""" | |
| error_type: ErrorType | |
| error_code: str | |
| message: str | |
| details: Optional[str] = None | |
| timestamp: datetime = None | |
| request_id: Optional[str] = None | |
| def __post_init__(self): | |
| if self.timestamp is None: | |
| self.timestamp = datetime.now() | |
| def __iter__(self): | |
| """Prevent unpacking by raising a clear error message.""" | |
| raise TypeError( | |
| "ErrorResponse object cannot be unpacked. " | |
| "Access attributes directly: error_response.error_type, error_response.error_code, etc." | |
| ) | |
| def to_dict(self) -> Dict[str, Any]: | |
| """Convert ErrorResponse to dictionary for easy access.""" | |
| return { | |
| "error_type": self.error_type.value if hasattr(self.error_type, 'value') else str(self.error_type), | |
| "error_code": self.error_code, | |
| "message": self.message, | |
| "details": self.details, | |
| "timestamp": self.timestamp, | |
| "request_id": self.request_id | |
| } | |
| class SecurityUtils: | |
| """Security utilities for API key management.""" | |
| def mask_api_key(api_key: str, visible_chars: int = 4) -> str: | |
| """ | |
| Mask an API key for safe logging. | |
| Args: | |
| api_key: The API key to mask | |
| visible_chars: Number of characters to show at the end | |
| Returns: | |
| Masked API key string | |
| """ | |
| if not api_key or len(api_key) < visible_chars: | |
| return "***" | |
| masked_length = len(api_key) - visible_chars | |
| return "*" * masked_length + api_key[-visible_chars:] | |
| def generate_secret_key(length: int = 32) -> str: | |
| """ | |
| Generate a cryptographically secure secret key. | |
| Args: | |
| length: Length of the secret key | |
| Returns: | |
| Random secret key | |
| """ | |
| return secrets.token_urlsafe(length) | |
| def hash_api_key(api_key: str) -> str: | |
| """ | |
| Create a hash of an API key for identification purposes. | |
| Args: | |
| api_key: The API key to hash | |
| Returns: | |
| SHA-256 hash of the API key | |
| """ | |
| return hashlib.sha256(api_key.encode()).hexdigest()[:16] | |
| def validate_api_key_format(api_key: str, expected_prefix: Optional[str] = None) -> bool: | |
| """ | |
| Validate API key format. | |
| Args: | |
| api_key: The API key to validate | |
| expected_prefix: Expected prefix (e.g., "sk-", "pk-") | |
| Returns: | |
| True if valid, False otherwise | |
| """ | |
| if not api_key or len(api_key) < 10: | |
| return False | |
| if expected_prefix and not api_key.startswith(expected_prefix): | |
| return False | |
| return True | |
| def check_environment_security() -> dict: | |
| """ | |
| Check environment security settings. | |
| Returns: | |
| Dictionary with security status | |
| """ | |
| security_status = { | |
| "env_file_exists": os.path.exists(".env"), | |
| "env_file_permissions": None, | |
| "home_directory_secure": True, | |
| "temp_directory_secure": True, | |
| "recommendations": [] | |
| } | |
| # Check .env file permissions | |
| if security_status["env_file_exists"]: | |
| try: | |
| stat_info = os.stat(".env") | |
| permissions = oct(stat_info.st_mode)[-3:] | |
| security_status["env_file_permissions"] = permissions | |
| # Check if file is world-readable (security risk) | |
| if int(permissions[2]) > 4: # Others can read | |
| security_status["recommendations"].append( | |
| "⚠️ .env file is world-readable. Run: chmod 600 .env" | |
| ) | |
| except OSError: | |
| security_status["env_file_permissions"] = "unknown" | |
| # Check if running in secure environment | |
| if os.path.expanduser("~") == "/root": | |
| security_status["recommendations"].append( | |
| "⚠️ Running as root user. Consider using a non-root user." | |
| ) | |
| # Check for common security issues | |
| if not security_status["env_file_exists"]: | |
| security_status["recommendations"].append( | |
| "❌ .env file not found. Create one from env.example" | |
| ) | |
| return security_status | |
| def secure_log_api_key(api_key: str, key_name: str = "API_KEY") -> str: | |
| """ | |
| Create a secure log message for API keys. | |
| Args: | |
| api_key: The API key | |
| key_name: Name of the key for logging | |
| Returns: | |
| Safe log message | |
| """ | |
| if not api_key: | |
| return f"{key_name}: Not configured" | |
| masked_key = SecurityUtils.mask_api_key(api_key) | |
| key_hash = SecurityUtils.hash_api_key(api_key) | |
| return f"{key_name}: {masked_key} (hash: {key_hash})" | |
| # Example usage | |
| if __name__ == "__main__": | |
| # Test security utilities | |
| test_key = "sk-1234567890abcdef1234567890abcdef" | |
| print("🔒 Security Utilities Test:") | |
| print(f"Original key: {test_key}") | |
| print(f"Masked key: {SecurityUtils.mask_api_key(test_key)}") | |
| print(f"Key hash: {SecurityUtils.hash_api_key(test_key)}") | |
| print(f"Valid format: {SecurityUtils.validate_api_key_format(test_key, 'sk-')}") | |
| print(f"Secure log: {secure_log_api_key(test_key, 'ANTHROPIC_API_KEY')}") | |
| print("\n🛡️ Environment Security Check:") | |
| security_status = SecurityUtils.check_environment_security() | |
| print(f"Environment file exists: {security_status['env_file_exists']}") | |
| print(f"File permissions: {security_status['env_file_permissions']}") | |
| if security_status['recommendations']: | |
| print("\n📋 Security Recommendations:") | |
| for rec in security_status['recommendations']: | |
| print(f" {rec}") | |
| else: | |
| print("✅ No security issues detected!") | |