import os import secrets from flask import Flask from flask_sqlalchemy import SQLAlchemy from dotenv import load_dotenv # Load environment variables load_dotenv() # Initialize SQLAlchemy db = SQLAlchemy() # Get or generate a stable SECRET_KEY def get_secret_key(): # Check for an existing key file key_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../instance/secret_key') # If running in production with Docker, store in a more appropriate location if os.environ.get('FLASK_ENV') == 'production': key_file = '/data/secret_key' try: # Try to read existing key if os.path.exists(key_file): with open(key_file, 'rb') as f: key = f.read() if key: return key except: pass # Generate a new key key = secrets.token_hex(32).encode() # Try to save it for future use try: os.makedirs(os.path.dirname(key_file), exist_ok=True) with open(key_file, 'wb') as f: f.write(key) except: # If we can't save it, just use it for this session pass return key def create_app(): app = Flask(__name__, instance_relative_config=True) # Determine if we're in production is_production = os.environ.get('FLASK_ENV') == 'production' # Configure the app app.config.from_mapping( SECRET_KEY=os.environ.get('SECRET_KEY', get_secret_key()), SQLALCHEMY_DATABASE_URI=f"sqlite:///{os.path.join(app.instance_path, 'game_tracker.sqlite')}", SQLALCHEMY_TRACK_MODIFICATIONS=False, # Session configuration for secure cookies SESSION_COOKIE_SECURE=is_production, # Only send cookies over HTTPS in production SESSION_COOKIE_HTTPONLY=True, # Prevent JavaScript access to cookies SESSION_COOKIE_SAMESITE='Lax', # Prevent CSRF attacks PERMANENT_SESSION_LIFETIME=86400, # 24 hours ) # If behind a proxy (like Nginx), trust the proxy headers app.config['PREFERRED_URL_SCHEME'] = 'https' if is_production else 'http' # Ensure the instance folder exists try: os.makedirs(app.instance_path) except OSError: pass # Initialize database with app db.init_app(app) # Import and register blueprints from .routes import main_bp app.register_blueprint(main_bp) # Set up session persistence for production if is_production: from flask_session import Session app.config['SESSION_TYPE'] = 'filesystem' app.config['SESSION_FILE_DIR'] = '/data/flask_session' app.config['SESSION_PERMANENT'] = True Session(app) # Create database tables with app.app_context(): db.create_all() return app