wip
This commit is contained in:
parent
f7f28b35ec
commit
eedc354160
6 changed files with 56 additions and 6 deletions
|
@ -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
|
||||
|
|
16
app/core/csrf_utils.py
Normal file
16
app/core/csrf_utils.py
Normal file
|
@ -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)
|
|
@ -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"]
|
||||
)
|
||||
|
|
|
@ -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"])
|
||||
|
|
4
app/templates/dashboard/any_form_template.html
Normal file
4
app/templates/dashboard/any_form_template.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<form method="POST" action="...">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<!-- Form fields -->
|
||||
</form>
|
|
@ -25,6 +25,7 @@
|
|||
<link rel="stylesheet" href="{{ url_for('static', filename='css/theme.css') }}">
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="{{ url_for('static', filename='img/favicon.png') }}">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
{% block styles %}{% endblock %}
|
||||
<script>
|
||||
// Check for saved theme preference or respect OS preference
|
||||
|
@ -602,6 +603,18 @@
|
|||
to { opacity: 0; }
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
// Add CSRF token to all AJAX requests
|
||||
$(document).ready(function () {
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr, settings) {
|
||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", $('meta[name="csrf-token"]').attr('content'));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue