diff --git a/CHANGELOG.md b/CHANGELOG.md index 4687833..6aed3de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to `ichava/icon-browser` follow [Keep a Changelog](https://k ## [Unreleased] +### Fixed + +- **The browser page works under a host's nonce-based CSP.** A host that sends its own policy with a per-request nonce (`script-src 'self' 'nonce-…'`, as ichava.com does) hands that nonce to Vite; the page now puts it on the loader's ` @@ -58,7 +65,10 @@ @if(! $viteDev) - + {{-- No ?v= on the entry: its page chunks import it back as `./inertia-app.js`, and a module + URL with a query is a different module. Two copies of the entry meant two Inertia + contexts, so every page threw "usePage must be used within the Inertia component". --}} + @endif diff --git a/src/Support/PageNonce.php b/src/Support/PageNonce.php new file mode 100644 index 0000000..dfc036d --- /dev/null +++ b/src/Support/PageNonce.php @@ -0,0 +1,49 @@ +vite->cspNonce(); + + if (is_string($host) && $host !== '') { + return $host; + } + + if (config('ichava.icon-browser.security.csp.mode', 'strict') === 'nonce') { + return $this->nonce->value(); + } + + return null; + } + + /** ` nonce="…"`, ready to put after a tag name, or '' when the page has no nonce. */ + public function attribute(): string + { + $value = $this->value(); + + return $value === null ? '' : ' nonce="' . e($value) . '"'; + } +} diff --git a/src/View/Components/Prepaint.php b/src/View/Components/Prepaint.php index 5774d3e..0da7535 100644 --- a/src/View/Components/Prepaint.php +++ b/src/View/Components/Prepaint.php @@ -6,7 +6,7 @@ use Illuminate\View\Component; use Illuminate\Support\HtmlString; -use Simtabi\Laranail\Ichava\Support\SecurityNonce; +use Simtabi\Laranail\Ichava\IconBrowser\Support\PageNonce; /** * Inline react-icon-browser's static loader, so something paints on the first HTML parse @@ -22,7 +22,7 @@ */ final class Prepaint extends Component { - public function __construct(private readonly SecurityNonce $nonce) {} + public function __construct(private readonly PageNonce $nonce) {} public static function path(): string { @@ -33,8 +33,9 @@ public function render(): HtmlString { $html = is_file(self::path()) ? (string) file_get_contents(self::path()) : ''; - if ($html !== '' && config('ichava.icon-browser.security.csp.mode', 'strict') === 'nonce') { - $attribute = $this->nonce->attribute(); + $attribute = $this->nonce->attribute(); + + if ($html !== '' && $attribute !== '') { $html = str_replace(['