Spaces:
Sleeping
Sleeping
| """ | |
| Configuration settings for Chatty application | |
| Handles different environments (development, production, testing) | |
| """ | |
| import os | |
| import secrets | |
| from datetime import timedelta | |
| from dotenv import load_dotenv | |
| # Load environment variables from .env file | |
| load_dotenv() | |
| class Config: | |
| """Base configuration class""" | |
| # Security Configuration | |
| SECRET_KEY = os.environ.get('SECRET_KEY') or secrets.token_hex(32) | |
| # MongoDB Configuration | |
| MONGODB_URL = os.environ.get('MONGODB_URL') or os.environ.get('MONGODB_URI') | |
| MONGODB_DATABASE = os.environ.get('MONGODB_DATABASE', 'Atlas') | |
| # Session Configuration | |
| PERMANENT_SESSION_LIFETIME = timedelta(hours=int(os.environ.get('SESSION_LIFETIME_HOURS', 24))) | |
| SESSION_COOKIE_SECURE = os.environ.get('SESSION_COOKIE_SECURE', 'False').lower() == 'true' | |
| SESSION_COOKIE_HTTPONLY = True | |
| SESSION_COOKIE_SAMESITE = 'Lax' | |
| # CSRF Configuration | |
| WTF_CSRF_TIME_LIMIT = int(os.environ.get('CSRF_TIME_LIMIT', 3600)) # 1 hour | |
| WTF_CSRF_SSL_STRICT = os.environ.get('WTF_CSRF_SSL_STRICT', 'False').lower() == 'true' | |
| WTF_CSRF_ENABLED = os.environ.get('WTF_CSRF_ENABLED', 'True').lower() == 'true' | |
| # Additional CSRF settings for proxy environments (like Hugging Face Spaces) | |
| WTF_CSRF_CHECK_DEFAULT = os.environ.get('WTF_CSRF_CHECK_DEFAULT', 'True').lower() == 'true' | |
| # Rate Limiting Configuration | |
| MAX_LOGIN_ATTEMPTS = int(os.environ.get('MAX_LOGIN_ATTEMPTS', 5)) | |
| RATE_LIMIT_WINDOW = int(os.environ.get('RATE_LIMIT_WINDOW', 900)) # 15 minutes | |
| # Anonymous User Configuration | |
| ANONYMOUS_ENABLED = os.environ.get('ANONYMOUS_ENABLED', 'True').lower() == 'true' | |
| ANONYMOUS_RATE_LIMIT = int(os.environ.get('ANONYMOUS_RATE_LIMIT', 20)) # messages per hour | |
| ANONYMOUS_RATE_LIMIT_WINDOW = int(os.environ.get('ANONYMOUS_RATE_LIMIT_WINDOW', 3600)) # 1 hour | |
| ANONYMOUS_SESSION_TIMEOUT = int(os.environ.get('ANONYMOUS_SESSION_TIMEOUT', 3600)) # 1 hour | |
| ANONYMOUS_MAX_MESSAGE_LENGTH = int(os.environ.get('ANONYMOUS_MAX_MESSAGE_LENGTH', 2000)) # characters | |
| # API Configuration | |
| API_URL = os.environ.get('API_URL', 'https://findEthics-Atlas.hf.space/chat') | |
| API_TIMEOUT = int(os.environ.get('API_TIMEOUT', 30)) | |
| # Logging Configuration | |
| LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') | |
| LOG_FILE = os.environ.get('LOG_FILE') | |
| # Application Configuration | |
| DEBUG = False | |
| TESTING = False | |
| def validate_config(): | |
| """Validate required configuration values""" | |
| errors = [] | |
| if not Config.MONGODB_URL: | |
| errors.append("MONGODB_URL environment variable is required") | |
| if not Config.SECRET_KEY or Config.SECRET_KEY == 'dev-secret-key-change-in-production': | |
| errors.append("SECRET_KEY environment variable must be set to a secure random value") | |
| if len(Config.SECRET_KEY) < 32: | |
| errors.append("SECRET_KEY should be at least 32 characters long") | |
| return errors | |
| class DevelopmentConfig(Config): | |
| """Development configuration""" | |
| DEBUG = True | |
| SESSION_COOKIE_SECURE = False | |
| WTF_CSRF_SSL_STRICT = False | |
| WTF_CSRF_ENABLED = False # Disable CSRF for testing | |
| LOG_LEVEL = 'DEBUG' | |
| class ProductionConfig(Config): | |
| """Production configuration""" | |
| DEBUG = False | |
| # Hugging Face Spaces compatibility | |
| # HF Spaces runs behind a proxy, so we need to be more flexible with CSRF/session settings | |
| SESSION_COOKIE_SECURE = os.environ.get('SESSION_COOKIE_SECURE', 'False').lower() == 'true' | |
| WTF_CSRF_SSL_STRICT = os.environ.get('WTF_CSRF_SSL_STRICT', 'False').lower() == 'true' | |
| # Override with production-specific values | |
| MAX_LOGIN_ATTEMPTS = int(os.environ.get('MAX_LOGIN_ATTEMPTS', 3)) # Stricter in production | |
| RATE_LIMIT_WINDOW = int(os.environ.get('RATE_LIMIT_WINDOW', 1800)) # 30 minutes | |
| def validate_config(): | |
| """Additional production-specific validation""" | |
| errors = Config.validate_config() | |
| # Production-specific checks | |
| if not os.environ.get('SECRET_KEY'): | |
| errors.append("SECRET_KEY environment variable must be explicitly set in production") | |
| # Relaxed validation for Hugging Face Spaces compatibility | |
| # SESSION_COOKIE_SECURE and WTF_CSRF_SSL_STRICT are now optional in production | |
| if ProductionConfig.DEBUG: | |
| errors.append("DEBUG must be False in production") | |
| return errors | |
| class HuggingFaceConfig(Config): | |
| """Hugging Face Spaces specific configuration | |
| Security Note: | |
| CSRF protection is disabled for Hugging Face Spaces due to: | |
| 1. HF Spaces runs applications in iframes which breaks CSRF token validation | |
| 2. Cross-origin restrictions prevent proper CSRF token exchange | |
| 3. HF Spaces provides its own security layer at the platform level | |
| Trade-offs: | |
| - Reduced protection against CSRF attacks | |
| - Mitigated by: HF Spaces platform security, rate limiting, and authentication requirements | |
| """ | |
| DEBUG = False | |
| # Hugging Face Spaces runs in iframes with complex proxy setup | |
| # Sessions and CSRF are problematic in this environment | |
| SESSION_COOKIE_SECURE = False | |
| WTF_CSRF_SSL_STRICT = False | |
| WTF_CSRF_ENABLED = False # Disable CSRF for HF Spaces due to iframe issues | |
| # Very permissive session settings for iframe compatibility | |
| SESSION_COOKIE_SAMESITE = None # Most permissive setting | |
| SESSION_COOKIE_HTTPONLY = False # Allow JavaScript access | |
| SESSION_COOKIE_DOMAIN = None # Don't restrict domain | |
| SESSION_COOKIE_PATH = '/' # Ensure cookies work across all paths | |
| # Extend session lifetime to help with iframe issues | |
| PERMANENT_SESSION_LIFETIME = timedelta(hours=int(os.environ.get('SESSION_LIFETIME_HOURS', 48))) | |
| # Production-level security for other settings | |
| MAX_LOGIN_ATTEMPTS = int(os.environ.get('MAX_LOGIN_ATTEMPTS', 3)) | |
| RATE_LIMIT_WINDOW = int(os.environ.get('RATE_LIMIT_WINDOW', 1800)) | |
| def validate_config(): | |
| """Validation for Hugging Face Spaces""" | |
| errors = Config.validate_config() | |
| if not os.environ.get('SECRET_KEY'): | |
| errors.append("SECRET_KEY environment variable must be explicitly set") | |
| return errors | |
| class TestingConfig(Config): | |
| """Testing configuration""" | |
| TESTING = True | |
| DEBUG = True | |
| SESSION_COOKIE_SECURE = False | |
| WTF_CSRF_ENABLED = False # Disable CSRF for testing | |
| MONGODB_DATABASE = os.environ.get('TEST_MONGODB_DATABASE', 'Atlas_test') | |
| # Configuration mapping | |
| config = { | |
| 'development': DevelopmentConfig, | |
| 'production': ProductionConfig, | |
| 'huggingface': HuggingFaceConfig, | |
| 'testing': TestingConfig, | |
| 'default': DevelopmentConfig | |
| } | |
| def get_config(config_name=None): | |
| """Get configuration class based on environment""" | |
| if config_name is None: | |
| config_name = os.environ.get('FLASK_ENV', 'development') | |
| return config.get(config_name, config['default']) | |
| def validate_environment(): | |
| """Validate the current environment configuration""" | |
| config_name = os.environ.get('FLASK_ENV', 'development') | |
| config_class = get_config(config_name) | |
| errors = config_class.validate_config() | |
| if errors: | |
| print(f"Configuration errors for {config_name} environment:") | |
| for error in errors: | |
| print(f" - {error}") | |
| return False | |
| print(f"✓ Configuration validation passed for {config_name} environment") | |
| return True | |
| if __name__ == "__main__": | |
| # Validate configuration when run directly | |
| validate_environment() |