diff --git a/app/__init__.py b/app/__init__.py index 9cbfd5f..07e98e0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -20,13 +20,14 @@ def create_app(config_name="development"): app.config['SECRET_KEY'] = secrets.token_hex(32) # Initialize extensions - from app.core.extensions import db, migrate, login_manager, bcrypt, limiter, csrf + from app.core.extensions import db, migrate, login_manager, bcrypt, limiter + from app.core.csrf_utils import init_csrf db.init_app(app) migrate.init_app(app, db) login_manager.init_app(app) bcrypt.init_app(app) - csrf.init_app(app) + init_csrf(app) limiter.init_app(app) # Initialize login manager @@ -101,4 +102,21 @@ def create_app(config_name="development"): def forbidden(e): return render_template("errors/403.html", title="Forbidden"), 403 + # Session configuration + app.config['SESSION_TYPE'] = 'filesystem' + app.config['SESSION_FILE_DIR'] = os.path.join(os.getcwd(), 'instance/sessions') + app.config['SESSION_PERMANENT'] = True + app.config['PERMANENT_SESSION_LIFETIME'] = 3600 # 1 hour in seconds + + # Ensure the sessions directory exists + os.makedirs(app.config['SESSION_FILE_DIR'], exist_ok=True) + + # Debug CSRF issues + @app.after_request + def after_request(response): + if app.debug: # Only in development + print(f"Session contains CSRF token: {'csrf_token' in session}") + print(f"CSRF header name: {app.config.get('WTF_CSRF_HEADERS')}") + return response + return app diff --git a/app/core/csrf_utils.py b/app/core/csrf_utils.py new file mode 100644 index 0000000..edc12b7 --- /dev/null +++ b/app/core/csrf_utils.py @@ -0,0 +1,16 @@ +from flask_wtf.csrf import CSRFProtect + +# Single global instance of CSRFProtect +csrf = CSRFProtect() + +def init_csrf(app): + """Initialize CSRF protection with proper configuration""" + # Ensure cookies work in Docker environment + app.config['WTF_CSRF_ENABLED'] = True + app.config['WTF_CSRF_TIME_LIMIT'] = 3600 # 1 hour + app.config['SESSION_COOKIE_SECURE'] = False # Set to True if using HTTPS + app.config['SESSION_COOKIE_HTTPONLY'] = True + app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' + + # Initialize CSRF protection + csrf.init_app(app) \ No newline at end of file diff --git a/app/core/extensions.py b/app/core/extensions.py index 47773bf..d825b3d 100644 --- a/app/core/extensions.py +++ b/app/core/extensions.py @@ -4,7 +4,7 @@ from flask_login import LoginManager from flask_bcrypt import Bcrypt from flask_limiter import Limiter from flask_limiter.util import get_remote_address -from flask_wtf.csrf import CSRFProtect +from app.core.csrf_utils import csrf # Import from centralized location # Initialize extensions db = SQLAlchemy() @@ -15,7 +15,7 @@ login_manager.login_message = "Please log in to access this page." login_manager.login_message_category = "info" bcrypt = Bcrypt() -csrf = CSRFProtect() +# csrf is now imported from csrf_utils, not defined here limiter = Limiter( key_func=get_remote_address, default_limits=["200 per day", "50 per hour"] ) diff --git a/app/routes/auth.py b/app/routes/auth.py index 6fab0a8..1f6d3fb 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -4,10 +4,9 @@ from werkzeug.security import generate_password_hash, check_password_hash from app.core.extensions import db from app.core.auth import User import re -from flask_wtf.csrf import CSRFProtect +from app.core.csrf_utils import csrf # Import from centralized location bp = Blueprint("auth", __name__, url_prefix="/auth") -csrf = CSRFProtect() @bp.route("/login", methods=["GET", "POST"]) diff --git a/app/templates/dashboard/any_form_template.html b/app/templates/dashboard/any_form_template.html new file mode 100644 index 0000000..68671ac --- /dev/null +++ b/app/templates/dashboard/any_form_template.html @@ -0,0 +1,4 @@ +
+ + +
\ No newline at end of file diff --git a/app/templates/layout.html b/app/templates/layout.html index 495b688..4fcb611 100644 --- a/app/templates/layout.html +++ b/app/templates/layout.html @@ -25,6 +25,7 @@ + {% block styles %}{% endblock %} + {% block scripts %}{% endblock %}