- Updated .env.example to clarify behavior when ALLOW_UNAUTHENTICATED is true. - Modified README.md to reflect changes in access key requirements and warnings. - Enhanced app_state.py to log warnings when running without access key. - Adjusted CSRF checks in middleware.py to enforce stricter origin validation. - Updated overall_config.py to provide clearer descriptions for configuration options. - Enforced HTTPS for image URLs in validators.py. - Added logging for SOCKS5 upstream proxy resolving to private IPs in upstream_client.py. - Improved test coverage for access control and CSRF checks in test_contract.py. - Fixed potential issues with image URL handling in frontend components.
58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
import re
|
|
import secrets
|
|
from pathlib import Path
|
|
|
|
from fastapi.responses import HTMLResponse
|
|
|
|
|
|
def build_content_security_policy(script_nonce: str | None = None) -> str:
|
|
script_sources = ["'self'"]
|
|
script_elem_sources = ["'self'"]
|
|
if script_nonce:
|
|
nonce_source = f"'nonce-{script_nonce}'"
|
|
script_sources.append(nonce_source)
|
|
script_elem_sources.append(nonce_source)
|
|
|
|
return "; ".join(
|
|
[
|
|
"default-src 'self'",
|
|
"base-uri 'self'",
|
|
"object-src 'none'",
|
|
"frame-ancestors 'none'",
|
|
"form-action 'self'",
|
|
f"script-src {' '.join(script_sources)}",
|
|
f"script-src-elem {' '.join(script_elem_sources)}",
|
|
"script-src-attr 'none'",
|
|
"style-src 'self'",
|
|
"style-src-attr 'unsafe-inline'",
|
|
"img-src 'self' data: blob:",
|
|
"font-src 'self' data:",
|
|
"connect-src 'self'",
|
|
]
|
|
)
|
|
|
|
|
|
CONTENT_SECURITY_POLICY = build_content_security_policy()
|
|
SCRIPT_TAG_RE = re.compile(r"<script(?P<attrs>[^>]*)>", re.IGNORECASE)
|
|
|
|
|
|
def add_script_nonce(html: str, nonce: str) -> str:
|
|
def replace_script_tag(match: re.Match[str]) -> str:
|
|
attrs = match.group("attrs")
|
|
if re.search(r"\snonce\s*=", attrs, flags=re.IGNORECASE):
|
|
return match.group(0)
|
|
return f'<script nonce="{nonce}"{attrs}>'
|
|
|
|
return SCRIPT_TAG_RE.sub(replace_script_tag, html)
|
|
|
|
|
|
def frontend_index_response(index_path: Path) -> HTMLResponse:
|
|
nonce = secrets.token_urlsafe(16)
|
|
html = add_script_nonce(index_path.read_text(encoding="utf-8"), nonce)
|
|
response = HTMLResponse(html)
|
|
response.headers["Content-Security-Policy"] = build_content_security_policy(
|
|
script_nonce=nonce
|
|
)
|
|
response.headers["Cache-Control"] = "no-cache"
|
|
return response
|