{# Create a namespace to hold the accumulated CSP parts #} {% set ns = namespace(csp_parts=[]) %} {# List of directives to build dynamically (except img-src) #} {% set directives = [ 'default-src', 'connect-src', 'frame-ancestors', 'frame-src', 'script-src', 'style-src', 'font-src' ] %} {# Build each directive line #} {% for directive in directives %} {# Always start with 'self' #} {% set tokens = ["'self'"] %} {# Add any unsafe flags for this directive #} {% for flag in applications | get_csp_flags(application_id, directive) %} {% set tokens = tokens + [flag] %} {% endfor %} {# If Matomo is enabled, allow its script and connect endpoints #} {% if applications | is_feature_enabled('matomo', application_id) and directive in ['script-src', 'connect-src'] %} {% set tokens = tokens + [web_protocol ~ '://' ~ domains.matomo] %} {% endif %} {# Append any extra whitelist URLs for this directive #} {% for url in applications | get_csp_whitelist(application_id, directive) %} {% set tokens = tokens + [url] %} {% endfor %} {# Store the completed directive line in the namespace #} {% set ns.csp_parts = ns.csp_parts + [directive ~ ' ' ~ (tokens | join(' ')) ~ ';'] %} {% endfor %} {# Add the (static) img-src directive #} {% set ns.csp_parts = ns.csp_parts + ['img-src * data: blob:;'] %} {# Emit the final header and hide any upstream header #} add_header Content-Security-Policy "{{ ns.csp_parts | join(' ') }}" always; proxy_hide_header Content-Security-Policy;