This commit is contained in:
2026-01-08 01:00:26 +10:30
commit 211854ca0a
70 changed files with 5241 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
"""Middleware package."""
from app.middleware.request_id import RequestIDMiddleware
from app.middleware.security_headers import SecurityHeadersMiddleware
from app.middleware.cors import setup_cors
__all__ = ["RequestIDMiddleware", "SecurityHeadersMiddleware", "setup_cors"]
+29
View File
@@ -0,0 +1,29 @@
"""CORS middleware configuration."""
from flask import request
def setup_cors(app, cors):
"""
Configure CORS for the application.
Args:
app: Flask application instance
cors: Flask-CORS instance
"""
# CORS is already initialized in extensions.py
# This function provides additional configuration if needed
@app.after_request
def after_request_cors(response):
"""Add additional CORS headers if needed."""
origin = request.headers.get("Origin")
cors_origins = app.config.get("CORS_ORIGINS", [])
# Allow all origins in development if CORS_ORIGINS is "*"
if cors_origins == "*" or origin in cors_origins:
response.headers["Access-Control-Allow-Origin"] = origin if cors_origins != "*" else "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization, X-Request-ID"
response.headers["Access-Control-Max-Age"] = "3600"
return response
+38
View File
@@ -0,0 +1,38 @@
"""Request ID middleware for request tracing."""
import uuid
from flask import g, request
class RequestIDMiddleware:
"""Middleware to add unique request ID to each request."""
def __init__(self, app=None):
"""Initialize middleware."""
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
"""Initialize with Flask app."""
app.before_request(self.before_request)
app.after_request(self.after_request)
@staticmethod
def before_request():
"""Generate or extract request ID before request processing."""
# Check if request already has an ID from client
request_id = request.headers.get("X-Request-ID")
# Generate new ID if not provided
if not request_id:
request_id = str(uuid.uuid4())
# Store in Flask g object for access throughout request
g.request_id = request_id
@staticmethod
def after_request(response):
"""Add request ID to response headers."""
if hasattr(g, "request_id"):
response.headers["X-Request-ID"] = g.request_id
return response
+54
View File
@@ -0,0 +1,54 @@
"""Security headers middleware."""
from flask import request
class SecurityHeadersMiddleware:
"""Middleware to add security headers to responses."""
def __init__(self, app=None):
"""Initialize middleware."""
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
"""Initialize with Flask app."""
app.after_request(self.add_security_headers)
@staticmethod
def add_security_headers(response):
"""Add security headers to response."""
# Prevent MIME type sniffing
response.headers["X-Content-Type-Options"] = "nosniff"
# Enable XSS protection
response.headers["X-XSS-Protection"] = "1; mode=block"
# Prevent clickjacking
response.headers["X-Frame-Options"] = "DENY"
# Strict Transport Security (HSTS)
if request.is_secure:
response.headers["Strict-Transport-Security"] = (
"max-age=31536000; includeSubDomains"
)
# Content Security Policy
response.headers["Content-Security-Policy"] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline'; "
"style-src 'self' 'unsafe-inline'; "
"img-src 'self' data: https:; "
"font-src 'self' data:; "
"connect-src 'self'"
)
# Referrer Policy
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
# Permissions Policy
response.headers["Permissions-Policy"] = (
"geolocation=(), microphone=(), camera=()"
)
return response