mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
fix(web): Resolve font display errors and config API CSRF issues (#152)
* fix(web): Resolve font display and config API error handling issues - Fix font catalog display error where path.startsWith fails (path is object, not string) - Update save_main_config to use error_response() helper - Improve save_raw_main_config error handling consistency - Add proper error codes and traceback details to API responses * fix(web): Prevent fontCatalog redeclaration error on HTMX reload - Use window object to store global font variables - Check if script has already loaded before declaring variables - Update both window properties and local references on assignment - Fixes 'Identifier fontCatalog has already been declared' error * fix(web): Wrap fonts script in IIFE to prevent all redeclaration errors - Wrap entire script in IIFE that only runs once - Check if script already loaded before declaring variables/functions - Expose initializeFontsTab to window for re-initialization - Prevents 'Identifier has already been declared' errors on HTMX reload * fix(web): Exempt config save API endpoints from CSRF protection - Exempt save_raw_main_config, save_raw_secrets_config, and save_main_config from CSRF - These endpoints are called via fetch from JavaScript and don't include CSRF tokens - Fixes 500 error when saving config via raw JSON editor * fix(web): Exempt system action endpoint from CSRF protection - Exempt execute_system_action from CSRF - Fixes 500 error when using system action buttons (restart display, restart Pi, etc.) - These endpoints are called via HTMX and don't include CSRF tokens * fix(web): Exempt all API v3 endpoints from CSRF protection - Add before_request handler to exempt all api_v3.* endpoints - All API endpoints are programmatic (HTMX/fetch) and don't include CSRF tokens - Prevents future CSRF errors on any API endpoint - Cleaner than exempting individual endpoints * refactor(web): Remove CSRF protection for local-only application - CSRF is designed for internet-facing apps to prevent cross-site attacks - For local-only Raspberry Pi app, threat model is different - All endpoints were exempted anyway, so it wasn't protecting anything - Forms use HTMX without CSRF tokens - If exposing to internet later, can re-enable with proper token implementation * fix(web): Fix font path double-prefixing in font catalog display - Only prefix with 'assets/fonts/' if path is a bare filename - If path starts with '/' (absolute) or 'assets/' (already prefixed), use as-is - Fixes double-prefixing when get_fonts_catalog returns relative paths like 'assets/fonts/press_start.ttf' * fix(web): Remove fontsTabInitialized guard to allow re-initialization on HTMX reload - Remove fontsTabInitialized check that prevented re-initialization on HTMX content swap - The window._fontsScriptLoaded guard is sufficient to prevent function redeclaration - Allow initializeFontsTab() to run on each HTMX swap to attach listeners to new DOM elements - Fixes fonts UI breaking after HTMX reload (buttons, upload dropzone, etc. not working) --------- Co-authored-by: Chuck <chuck@example.com>
This commit is contained in:
@@ -26,30 +26,14 @@ app = Flask(__name__)
|
||||
app.secret_key = os.urandom(24)
|
||||
config_manager = ConfigManager()
|
||||
|
||||
# Initialize CSRF protection (optional for local-only, but recommended for defense-in-depth)
|
||||
try:
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
csrf = CSRFProtect(app)
|
||||
# Exempt SSE streams from CSRF (read-only)
|
||||
from functools import wraps
|
||||
from flask import request
|
||||
|
||||
def csrf_exempt(f):
|
||||
"""Decorator to exempt a route from CSRF protection."""
|
||||
f.csrf_exempt = True
|
||||
return f
|
||||
|
||||
# Mark SSE streams as exempt
|
||||
@app.before_request
|
||||
def check_csrf_exempt():
|
||||
"""Check if route should be exempt from CSRF."""
|
||||
if request.endpoint and 'stream' in request.endpoint:
|
||||
# SSE streams are read-only, exempt from CSRF
|
||||
pass
|
||||
except ImportError:
|
||||
# flask-wtf not installed, CSRF protection disabled
|
||||
csrf = None
|
||||
pass
|
||||
# CSRF protection disabled for local-only application
|
||||
# CSRF is designed for internet-facing web apps to prevent cross-site request forgery.
|
||||
# For a local-only Raspberry Pi application, the threat model is different:
|
||||
# - If an attacker has network access to perform CSRF, they have other attack vectors
|
||||
# - All API endpoints are programmatic (HTMX/fetch) and don't include CSRF tokens
|
||||
# - Forms use HTMX which doesn't automatically include CSRF tokens
|
||||
# If you need CSRF protection (e.g., exposing to internet), properly implement CSRF tokens in HTMX forms
|
||||
csrf = None
|
||||
|
||||
# Initialize rate limiting (prevent accidental abuse, not security)
|
||||
try:
|
||||
@@ -543,6 +527,7 @@ if csrf:
|
||||
csrf.exempt(stream_stats)
|
||||
csrf.exempt(stream_display)
|
||||
csrf.exempt(stream_logs)
|
||||
# Note: api_v3 blueprint is exempted above after registration
|
||||
|
||||
if limiter:
|
||||
limiter.limit("20 per minute")(stream_stats)
|
||||
|
||||
Reference in New Issue
Block a user