From b4a0790aa4cc84216907076182b50dd7bdfc000b Mon Sep 17 00:00:00 2001 From: Debatty-Tom <145542891+Debatty-Tom@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:27:09 +0200 Subject: [PATCH 1/4] Added csp option on default script tag --- config/cookieconsent.php | 13 +++++++++++++ src/CookiesManager.php | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/config/cookieconsent.php b/config/cookieconsent.php index d22ea2a..56d644d 100644 --- a/config/cookieconsent.php +++ b/config/cookieconsent.php @@ -55,6 +55,19 @@ 'policy' => null, + /* + |-------------------------------------------------------------------------- + | CSP configuration + |-------------------------------------------------------------------------- + | + | Most cookie notices display a link to a dedicated page explaining + | the extended cookies usage policy. If your application has such a page + | you can add its route name here. + | + */ + + 'csp_enable' => env('CSP_ENABLE', false), + /* Google Analytics configuration |-------------------------------------------------------------------------- | diff --git a/src/CookiesManager.php b/src/CookiesManager.php index 58b387c..940f275 100644 --- a/src/CookiesManager.php +++ b/src/CookiesManager.php @@ -4,6 +4,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Cookie as CookieFacade; +use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Cookie as CookieComponent; class CookiesManager @@ -198,11 +199,28 @@ protected function getConsentedScripts(bool $withDefault): string protected function getDefaultScriptTag(): string { + $csp_enable = config('cookieconsent.csp_enable', false); + + if ($csp_enable) { + return ''; + } + return ''; + + } + + protected function generateCspNonce(): string + { + return Str::random(32); } /** From 6efe10dc4788901383775f71cd37b3be65f66d74 Mon Sep 17 00:00:00 2001 From: Debatty-Tom <145542891+Debatty-Tom@users.noreply.github.com> Date: Wed, 8 Oct 2025 16:33:29 +0200 Subject: [PATCH 2/4] Refactor return script and add some complexity to the nonce --- src/CookiesManager.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/CookiesManager.php b/src/CookiesManager.php index 940f275..73e1e71 100644 --- a/src/CookiesManager.php +++ b/src/CookiesManager.php @@ -201,26 +201,17 @@ protected function getDefaultScriptTag(): string { $csp_enable = config('cookieconsent.csp_enable', false); - if ($csp_enable) { - return ''; - } - return ''; - } protected function generateCspNonce(): string { - return Str::random(32); + return bin2hex(random_bytes(16)); } /** From c902ac4d3de469307b815c58336116c66936f65e Mon Sep 17 00:00:00 2001 From: Debatty-Tom <145542891+Debatty-Tom@users.noreply.github.com> Date: Mon, 20 Oct 2025 16:30:29 +0200 Subject: [PATCH 3/4] fix using csp nonce by passing it from the view to the default script tag and added explanations in the readme --- README.md | 23 +++++++++++++++++++++++ config/cookieconsent.php | 13 ------------- src/CookiesManager.php | 27 ++++++++++----------------- src/ServiceProvider.php | 3 +-- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 76d1423..3774d80 100644 --- a/README.md +++ b/README.md @@ -439,6 +439,29 @@ $factors['years'] = [365, 'dayz']; More information on CarbonInterval's gotchas in [Constantin's blog post on chasingcode.dev](https://chasingcode.dev/blog/carbon-php-practical-examples/). +### Content Security Policy + +This package supports CSP nonces for secure script loading. Pass your nonce to the @cookieconsentscripts directive: + +```blade +{{-- Basic usage with nonce --}} +@cookieconsentscripts($yourNonce) + +{{-- Example with Spatie Laravel CSP --}} +@cookieconsentscripts(app('csp-nonce')) + +{{-- Without CSP --}} +@cookieconsentscripts +``` + +How It Works + +When you provide a nonce, it's added to the script tag: + +```html + +``` + ### Let your users change their mind Users should be able to change their consent settings at any time. No worries, with this package it is quite simple to achieve: generate a button that will reset the user's cookies and show the consent modal again. diff --git a/config/cookieconsent.php b/config/cookieconsent.php index 56d644d..d22ea2a 100644 --- a/config/cookieconsent.php +++ b/config/cookieconsent.php @@ -55,19 +55,6 @@ 'policy' => null, - /* - |-------------------------------------------------------------------------- - | CSP configuration - |-------------------------------------------------------------------------- - | - | Most cookie notices display a link to a dedicated page explaining - | the extended cookies usage policy. If your application has such a page - | you can add its route name here. - | - */ - - 'csp_enable' => env('CSP_ENABLE', false), - /* Google Analytics configuration |-------------------------------------------------------------------------- | diff --git a/src/CookiesManager.php b/src/CookiesManager.php index 73e1e71..e38ca6f 100644 --- a/src/CookiesManager.php +++ b/src/CookiesManager.php @@ -168,11 +168,11 @@ protected function makeConsentCookie(): CookieComponent /** * Output all the scripts for current consent state. */ - public function renderScripts(bool $withDefault = true): string + public function renderScripts(bool $withDefault = true, ?string $nonce = null): string { $output = $this->shouldDisplayNotice() - ? $this->getNoticeScripts($withDefault) - : $this->getConsentedScripts($withDefault); + ? $this->getNoticeScripts($withDefault, $nonce) + : $this->getConsentedScripts($withDefault, $nonce); if(strlen($output)) { $output = '' . $output; @@ -181,14 +181,14 @@ public function renderScripts(bool $withDefault = true): string return $output; } - public function getNoticeScripts(bool $withDefault): string + public function getNoticeScripts(bool $withDefault, ?string $nonce = null): string { - return $withDefault ? $this->getDefaultScriptTag() : ''; + return $withDefault ? $this->getDefaultScriptTag($nonce) : ''; } - protected function getConsentedScripts(bool $withDefault): string + protected function getConsentedScripts(bool $withDefault, ?string $nonce = null): string { - $output = $this->getNoticeScripts($withDefault); + $output = $this->getNoticeScripts($withDefault, $nonce); foreach ($this->getConsentResponse()->getResponseScripts() ?? [] as $tag) { $output .= $tag; @@ -197,23 +197,16 @@ protected function getConsentedScripts(bool $withDefault): string return $output; } - protected function getDefaultScriptTag(): string + protected function getDefaultScriptTag(?string $nonce = null): string { - $csp_enable = config('cookieconsent.csp_enable', false); - return ''; } - protected function generateCspNonce(): string - { - return bin2hex(random_bytes(16)); - } - /** * Output the consent alert/modal for current consent state. */ diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index c8fd666..5c68730 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -64,9 +64,8 @@ public function boot() protected function registerBladeDirectives() { Blade::directive('cookieconsentscripts', function (string $expression) { - return ''; + return ''; }); - Blade::directive('cookieconsentview', function (string $expression) { return ''; }); From 2fbc9dfd31b99a2ea13c0ae3bcdf6578e514edc5 Mon Sep 17 00:00:00 2001 From: Debatty-Tom <145542891+Debatty-Tom@users.noreply.github.com> Date: Tue, 21 Oct 2025 16:08:26 +0200 Subject: [PATCH 4/4] Removed unused import --- src/CookiesManager.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CookiesManager.php b/src/CookiesManager.php index e38ca6f..c0b3c0f 100644 --- a/src/CookiesManager.php +++ b/src/CookiesManager.php @@ -4,7 +4,6 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Cookie as CookieFacade; -use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\Cookie as CookieComponent; class CookiesManager