diff --git a/Dockerfile b/Dockerfile index 4117b9e..2365998 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,10 @@ RUN pip install --upgrade pip && \ # Copy the rest of the application COPY . . +# Create the instance directory for SQLite +RUN mkdir -p instance && \ + chmod 777 instance + # Create a non-root user to run the app RUN useradd -m appuser && \ chown -R appuser:appuser /app @@ -27,7 +31,9 @@ USER appuser # Set environment variables ENV PYTHONDONTWRITEBYTECODE=1 \ - PYTHONUNBUFFERED=1 + PYTHONUNBUFFERED=1 \ + SECRET_KEY="" \ + FLASK_APP=wsgi.py # Run gunicorn -CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "wsgi:app"] +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--timeout", "120", "--workers", "4", "wsgi:app"] diff --git a/app/__init__.py b/app/__init__.py index 6456156..9cbfd5f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,6 +1,7 @@ -from flask import Flask, g, redirect, url_for, render_template +from flask import Flask, g, redirect, url_for, render_template, session import datetime import os +import secrets def create_app(config_name="development"): @@ -14,6 +15,10 @@ def create_app(config_name="development"): else: app.config.from_object("config.DevelopmentConfig") + # Ensure SECRET_KEY is set + if not app.config.get('SECRET_KEY'): + app.config['SECRET_KEY'] = secrets.token_hex(32) + # Initialize extensions from app.core.extensions import db, migrate, login_manager, bcrypt, limiter, csrf @@ -44,7 +49,7 @@ def create_app(config_name="development"): # Register the markdown filter directly app.jinja_env.filters['markdown'] = markdown_filter - # Create database tables without seeding any data + # Create database tables with app.app_context(): try: db.create_all() @@ -78,6 +83,11 @@ def create_app(config_name="development"): app.register_blueprint(static_bp) + # Add session handling + @app.before_request + def make_session_permanent(): + session.permanent = True + # Add error handlers @app.errorhandler(404) def page_not_found(e): diff --git a/compose.yml b/compose.yml index 8441da6..444892f 100644 --- a/compose.yml +++ b/compose.yml @@ -12,4 +12,5 @@ services: - ./instance:/app/instance # Persist SQLite database environment: - FLASK_ENV=${FLASK_ENV:-production} + - SECRET_KEY=${SECRET_KEY:-} # Will be generated if empty restart: unless-stopped diff --git a/config.py b/config.py index 924b427..8542d80 100644 --- a/config.py +++ b/config.py @@ -1,13 +1,19 @@ import os +import secrets class Config: """Base config.""" - SECRET_KEY = os.environ.get("SECRET_KEY", "dev-key-placeholder") + SECRET_KEY = os.environ.get('SECRET_KEY') or secrets.token_hex(32) + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///instance/app.db' SQLALCHEMY_TRACK_MODIFICATIONS = False WTF_CSRF_ENABLED = True - SESSION_COOKIE_SECURE = False # Set to True in production with HTTPS + WTF_CSRF_SECRET_KEY = os.environ.get('CSRF_SECRET_KEY') or secrets.token_hex(32) + SESSION_TYPE = 'filesystem' + SESSION_PERMANENT = False + PERMANENT_SESSION_LIFETIME = 3600 # 1 hour + REMEMBER_COOKIE_DURATION = 2592000 # 30 days class DevelopmentConfig(Config): diff --git a/wsgi.py b/wsgi.py index e4ee86e..7c48ac6 100644 --- a/wsgi.py +++ b/wsgi.py @@ -2,6 +2,10 @@ import os import secrets from app import create_app +# Generate a secret key if not provided +if not os.environ.get("SECRET_KEY"): + os.environ["SECRET_KEY"] = secrets.token_hex(32) + # Get Flask environment flask_env = os.environ.get("FLASK_ENV", "production")