""" Konfigurationsklassen für die MYP Flask-Anwendung. Definiert verschiedene Konfigurationen für Development, Production und Testing. """ import os from datetime import timedelta import secrets class Config: """Basis-Konfigurationsklasse mit gemeinsamen Einstellungen.""" SECRET_KEY = os.environ.get('SECRET_KEY') or secrets.token_hex(32) DATABASE = os.environ.get('DATABASE_PATH', 'instance/myp.db') # Session-Konfiguration SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Lax' PERMANENT_SESSION_LIFETIME = timedelta(days=7) # Job-Konfiguration JOB_CHECK_INTERVAL = int(os.environ.get('JOB_CHECK_INTERVAL', '60')) # Sekunden # Tapo-Konfiguration TAPO_USERNAME = os.environ.get('TAPO_USERNAME') TAPO_PASSWORD = os.environ.get('TAPO_PASSWORD') # Logging-Konfiguration LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') LOG_MAX_BYTES = int(os.environ.get('LOG_MAX_BYTES', '10485760')) # 10MB LOG_BACKUP_COUNT = int(os.environ.get('LOG_BACKUP_COUNT', '10')) # Drucker-Konfiguration PRINTERS = os.environ.get('PRINTERS', '{}') # JSON-Konfiguration parsen @property def PRINTERS_DICT(self): """Parse PRINTERS configuration as JSON""" import json printers_str = self.PRINTERS if isinstance(printers_str, dict): return printers_str try: return json.loads(printers_str) if printers_str else {} except (json.JSONDecodeError, TypeError): return {} # API-Konfiguration API_KEY = os.environ.get('API_KEY') # Rate Limiting RATE_LIMIT_ENABLED = True MAX_REQUESTS_PER_MINUTE = int(os.environ.get('MAX_REQUESTS_PER_MINUTE', '100')) RATE_LIMIT_WINDOW_MINUTES = int(os.environ.get('RATE_LIMIT_WINDOW_MINUTES', '15')) # Security SECURITY_ENABLED = True MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB @staticmethod def init_app(app): """Initialisierung der Anwendung mit der Konfiguration.""" pass class DevelopmentConfig(Config): """Konfiguration für die Entwicklungsumgebung.""" DEBUG = True TESTING = False # Session-Cookies in Development weniger strikt SESSION_COOKIE_SECURE = False # Kürzere Job-Check-Intervalle für schnellere Entwicklung JOB_CHECK_INTERVAL = int(os.environ.get('JOB_CHECK_INTERVAL', '30')) # Weniger strikte Sicherheit in Development SECURITY_ENABLED = False RATE_LIMIT_ENABLED = False @staticmethod def init_app(app): Config.init_app(app) # Development-spezifische Initialisierung import logging logging.basicConfig(level=logging.DEBUG) class ProductionConfig(Config): """Konfiguration für die Produktionsumgebung.""" DEBUG = False TESTING = False # Sichere Session-Cookies in Production SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'Strict' # Strengere Sicherheitseinstellungen WTF_CSRF_ENABLED = True WTF_CSRF_TIME_LIMIT = None # Längere Job-Check-Intervalle für bessere Performance JOB_CHECK_INTERVAL = int(os.environ.get('JOB_CHECK_INTERVAL', '60')) # Produktions-Sicherheit SECURITY_ENABLED = True RATE_LIMIT_ENABLED = True MAX_REQUESTS_PER_MINUTE = int(os.environ.get('MAX_REQUESTS_PER_MINUTE', '60')) # HTTPS-Enforcement (wenn verfügbar) FORCE_HTTPS = os.environ.get('FORCE_HTTPS', 'False').lower() == 'true' @staticmethod def init_app(app): Config.init_app(app) # Production-spezifische Initialisierung import logging from logging.handlers import RotatingFileHandler, SysLogHandler # Datei-Logging if not os.path.exists('logs'): os.mkdir('logs') # Prüfe ob Datei-Logging deaktiviert ist (für Tests) if app.config.get('DISABLE_FILE_LOGGING', False): app.logger.info('Datei-Logging deaktiviert (Test-Modus)') return # Windows-kompatibles Logging import platform if platform.system() == 'Windows': # Windows: Verwende TimedRotatingFileHandler statt RotatingFileHandler from logging.handlers import TimedRotatingFileHandler file_handler = TimedRotatingFileHandler( 'logs/myp.log', when='midnight', interval=1, backupCount=Config.LOG_BACKUP_COUNT ) error_handler = TimedRotatingFileHandler( 'logs/myp-errors.log', when='midnight', interval=1, backupCount=Config.LOG_BACKUP_COUNT ) security_handler = TimedRotatingFileHandler( 'logs/security.log', when='midnight', interval=1, backupCount=Config.LOG_BACKUP_COUNT ) else: # Linux/Unix: Verwende RotatingFileHandler file_handler = RotatingFileHandler( 'logs/myp.log', maxBytes=Config.LOG_MAX_BYTES, backupCount=Config.LOG_BACKUP_COUNT ) error_handler = RotatingFileHandler( 'logs/myp-errors.log', maxBytes=Config.LOG_MAX_BYTES, backupCount=Config.LOG_BACKUP_COUNT ) security_handler = RotatingFileHandler( 'logs/security.log', maxBytes=Config.LOG_MAX_BYTES, backupCount=Config.LOG_BACKUP_COUNT ) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]' )) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) error_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]' )) error_handler.setLevel(logging.ERROR) app.logger.addHandler(error_handler) security_handler.setFormatter(logging.Formatter( '%(asctime)s SECURITY %(levelname)s: %(message)s [%(name)s]' )) security_handler.setLevel(logging.WARNING) # Security-Logger security_logger = logging.getLogger('security') security_logger.addHandler(security_handler) security_logger.setLevel(logging.WARNING) app.logger.setLevel(logging.INFO) app.logger.info('MYP Backend starting in production mode') # Sicherheits-Middleware registrieren (optional) if app.config.get('SECURITY_ENABLED', True): try: from security import security_middleware security_middleware.init_app(app) except ImportError: app.logger.warning('Security module not found, skipping security middleware') class TestingConfig(Config): """Konfiguration für Tests""" TESTING = True DEBUG = True WTF_CSRF_ENABLED = False DATABASE_PATH = ':memory:' # In-Memory-Datenbank für Tests # Deaktiviere Datei-Logging für Tests (Windows-Kompatibilität) DISABLE_FILE_LOGGING = True @staticmethod def init_app(app): """Initialisierung für Test-Umgebung""" # Nur Console-Logging für Tests import logging app.logger.setLevel(logging.WARNING) # Reduziere Log-Level für Tests # Konfigurationsmapping config = { 'development': DevelopmentConfig, 'production': ProductionConfig, 'testing': TestingConfig, 'default': DevelopmentConfig }