This is a comment on CSP nonce, posted by WikiAdmin at 07/06/2026 08:48

View source for Comment 10

**Understood. This is a real constraint due to the template pull system.**

Here's the cleanest practical compromise without breaking templates or introducing ugly hacks:

==== Final Recommended Approach ====

**1. Keep ##$this->db->csp_nonce## for template compatibility** (as it was), but manage it properly from ##Http##.

**2. Add proper internal properties + getters on ##Http##.**

==== Code ====

===== In ##Http## class: =====

%%(hl php)
private ?string $csp_nonce_raw = null;
    private ?string $csp_nonce_attr = null;

    // Auto-generate nonce if '{nonce}' is present
    if (str_contains($csp_header, '{nonce}'))
    {
        if ($this->should_use_csp_nonce())
        {
            $nonce                    = $this->generate_csp_nonce();
            $this->csp_nonce_raw      = $nonce;
            $this->csp_nonce_attr     = ' nonce="' . $nonce . '"';
            $this->db->csp_nonce      = $this->csp_nonce_attr;   // keep for templates
            $csp_header               = str_replace("{nonce}", $nonce, $csp_header);
        }
        else
        {
            $this->csp_nonce_raw      = '';
            $this->csp_nonce_attr     = '';
            $this->db->csp_nonce      = '';

            // Cached page: fallback policy without strict-dynamic + nonce
            $csp_header = str_replace(
                ["'strict-dynamic'", "'nonce-{nonce}'"],
                ['', ''],
                $csp_header
            );
        }
    }
%%

===== Add these methods to ##Http##: =====

%%(hl php)
public function should_use_csp_nonce()
    {
        if (!$this->db->csp)
        {
            return false;
        }

        return isset($this->sess->user_profile) || $this->no_cache;
    }

    public function get_csp_nonce_attr()
    {
        return $this->csp_nonce_attr ?? '';
    }
%%

===== In ##Wacko## class (##apply_csp_nonce##): =====

%%(hl php)
// helper to apply nonce retroactively
    private function apply_csp_nonce(string $html): string
    {
        $nonce_attr = $this->http->get_csp_nonce_attr();

        if (empty($nonce_attr) || !str_contains($html, '<script'))
        {
            return $html;
        }

        // Simple regex to inject nonce into <script> tags that don't have one yet
        return preg_replace_callback(
            '#<script\b(?![^>]*nonce=)([^>]*?)>#i',
            function ($matches) use ($nonce_attr) {
                return '<script' . $matches[1] . $nonce_attr . '>';
            },
            $html
        );
    }
%%

----

==== Why this is the best balance ====
  - ##$this->db->csp_nonce## is still set exactly as before → **no template breakage**, no undefined key warnings.
  - Internal code (##apply_csp_nonce##, future code) uses the clean ##$this->http->get_csp_nonce_attr()##.
  - No real duplication — the attribute is computed once and assigned to both places.
  - Future refactoring (Wacko 7) can remove the ##$db->csp_nonce## assignment more easily.

This is not pretty, but it is the least disruptive and safest path given the template constraints.

Would you like me to give you the full ##http_security_headers()## method with this integrated?