chore: format

This commit is contained in:
Timothy J. Baek 2024-09-19 03:24:39 +02:00
parent f448341211
commit 1053863175

View File

@ -5,12 +5,14 @@ from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.base import BaseHTTPMiddleware
from typing import Dict from typing import Dict
class SecurityHeadersMiddleware(BaseHTTPMiddleware): class SecurityHeadersMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next): async def dispatch(self, request: Request, call_next):
response = await call_next(request) response = await call_next(request)
response.headers.update(set_security_headers()) response.headers.update(set_security_headers())
return response return response
def set_security_headers() -> Dict[str, str]: def set_security_headers() -> Dict[str, str]:
""" """
Sets security headers based on environment variables. Sets security headers based on environment variables.
@ -34,13 +36,13 @@ def set_security_headers() -> Dict[str, str]:
""" """
options = {} options = {}
header_setters = { header_setters = {
'CACHE_CONTROL': set_cache_control, "CACHE_CONTROL": set_cache_control,
'HSTS': set_hsts, "HSTS": set_hsts,
'REFERRER_POLICY': set_referrer, "REFERRER_POLICY": set_referrer,
'XCONTENT_TYPE': set_xcontent_type, "XCONTENT_TYPE": set_xcontent_type,
'XDOWNLOAD_OPTIONS': set_xdownload_options, "XDOWNLOAD_OPTIONS": set_xdownload_options,
'XFRAME_OPTIONS': set_xframe, "XFRAME_OPTIONS": set_xframe,
'XPERMITTED_CROSS_DOMAIN_POLICIES': set_xpermitted_cross_domain_policies, "XPERMITTED_CROSS_DOMAIN_POLICIES": set_xpermitted_cross_domain_policies,
} }
for env_var, setter in header_setters.items(): for env_var, setter in header_setters.items():
@ -52,69 +54,62 @@ def set_security_headers() -> Dict[str, str]:
return options return options
# Set HTTP Strict Transport Security(HSTS) response header # Set HTTP Strict Transport Security(HSTS) response header
def set_hsts(value: str): def set_hsts(value: str):
pattern = r'^max-age=(\d+)(;includeSubDomains)?(;preload)?$' pattern = r"^max-age=(\d+)(;includeSubDomains)?(;preload)?$"
match = re.match(pattern, value, re.IGNORECASE) match = re.match(pattern, value, re.IGNORECASE)
if not match: if not match:
return 'max-age=31536000;includeSubDomains' return "max-age=31536000;includeSubDomains"
return { return {"Strict-Transport-Security": value}
'Strict-Transport-Security': value
}
# Set X-Frame-Options response header # Set X-Frame-Options response header
def set_xframe(value: str): def set_xframe(value: str):
pattern = r'^(DENY|SAMEORIGIN)$' pattern = r"^(DENY|SAMEORIGIN)$"
match = re.match(pattern, value, re.IGNORECASE) match = re.match(pattern, value, re.IGNORECASE)
if not match: if not match:
value = 'DENY' value = "DENY"
return { return {"X-Frame-Options": value}
"X-Frame-Options": value
}
# Set Referrer-Policy response header # Set Referrer-Policy response header
def set_referrer(value: str): def set_referrer(value: str):
pattern = r'^(no-referrer|no-referrer-when-downgrade|origin|origin-when-cross-origin|same-origin|strict-origin|strict-origin-when-cross-origin|unsafe-url)$' pattern = r"^(no-referrer|no-referrer-when-downgrade|origin|origin-when-cross-origin|same-origin|strict-origin|strict-origin-when-cross-origin|unsafe-url)$"
match = re.match(pattern, value, re.IGNORECASE) match = re.match(pattern, value, re.IGNORECASE)
if not match: if not match:
value = 'no-referrer' value = "no-referrer"
return { return {"Referrer-Policy": value}
'Referrer-Policy': value
}
# Set Cache-Control response header # Set Cache-Control response header
def set_cache_control(value: str): def set_cache_control(value: str):
pattern = r'^(public|private|no-cache|no-store|must-revalidate|proxy-revalidate|max-age=\d+|s-maxage=\d+|no-transform|immutable)(,\s*(public|private|no-cache|no-store|must-revalidate|proxy-revalidate|max-age=\d+|s-maxage=\d+|no-transform|immutable))*$' pattern = r"^(public|private|no-cache|no-store|must-revalidate|proxy-revalidate|max-age=\d+|s-maxage=\d+|no-transform|immutable)(,\s*(public|private|no-cache|no-store|must-revalidate|proxy-revalidate|max-age=\d+|s-maxage=\d+|no-transform|immutable))*$"
match = re.match(pattern, value, re.IGNORECASE) match = re.match(pattern, value, re.IGNORECASE)
if not match: if not match:
value = 'no-store, max-age=0' value = "no-store, max-age=0"
return {"Cache-Control": value}
return {
'Cache-Control': value
}
# Set X-Download-Options response header # Set X-Download-Options response header
def set_xdownload_options(value: str): def set_xdownload_options(value: str):
if value != 'noopen': if value != "noopen":
value = 'noopen' value = "noopen"
return { return {"X-Download-Options": value}
'X-Download-Options': value
}
# Set X-Content-Type-Options response header # Set X-Content-Type-Options response header
def set_xcontent_type(value: str): def set_xcontent_type(value: str):
if value != 'nosniff': if value != "nosniff":
value = 'nosniff' value = "nosniff"
return { return {"X-Content-Type-Options": value}
'X-Content-Type-Options': value
}
# Set X-Permitted-Cross-Domain-Policies response header # Set X-Permitted-Cross-Domain-Policies response header
def set_xpermitted_cross_domain_policies(value: str): def set_xpermitted_cross_domain_policies(value: str):
pattern = r'^(none|master-only|by-content-type|by-ftp-filename)$' pattern = r"^(none|master-only|by-content-type|by-ftp-filename)$"
match = re.match(pattern, value, re.IGNORECASE) match = re.match(pattern, value, re.IGNORECASE)
if not match: if not match:
value = 'none' value = "none"
return { return {"X-Permitted-Cross-Domain-Policies": value}
'X-Permitted-Cross-Domain-Policies': value
}