From 5197757c9075a7a98b374ccf2a797005b53bfb12 Mon Sep 17 00:00:00 2001 From: Mark Dumay <61946753+markdumay@users.noreply.github.com> Date: Mon, 13 Jul 2026 11:43:35 +0200 Subject: [PATCH 1/3] fix(csp): allow gethinode.com to embed the demo site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The showcase pages on gethinode.com embed demo.gethinode.com in a live preview iframe, but the demo refused to render: it inherited the theme default `frame-ancestors 'self'`, so the browser blocked the cross-origin frame. - Add exampleSite/config/production/params.toml, overriding frame-ancestors for the demo deployment only. The theme default stays 'self', so downstream Hinode sites are unaffected. - Generate the production headers from the exampleSite rather than the main site. Netlify deploys exampleSite/public, so its config is the correct source; the previous netlify.toml was missing the exampleSite CSP entries (cookieyes) and the localized 404 redirects. - Regenerate netlify.toml. Note that this alone does not restore the preview: gethinode.com must also list the demo in its own CSP frame-src directive. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) --- exampleSite/config/production/params.toml | 10 ++++++++ netlify.toml | 30 +++++++++++++++++++---- package.json | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 exampleSite/config/production/params.toml diff --git a/exampleSite/config/production/params.toml b/exampleSite/config/production/params.toml new file mode 100644 index 000000000..ff9eb0621 --- /dev/null +++ b/exampleSite/config/production/params.toml @@ -0,0 +1,10 @@ +# Production-specific parameters for exampleSite + +[modules.hinode.csp] + # The exampleSite is deployed as demo.gethinode.com and is embedded as a live + # preview by the showcase pages on gethinode.com. Without this, the inherited + # theme default (frame-ancestors 'self') makes the browser refuse the iframe. + frame-ancestors = [ + "'self'", + "gethinode.com" + ] diff --git a/netlify.toml b/netlify.toml index 77d481f42..ed5bf29ad 100644 --- a/netlify.toml +++ b/netlify.toml @@ -36,18 +36,18 @@ Access-Control-Allow-Origin = '*' Content-Security-Policy = """ base-uri 'self'; \ - connect-src 'self' *.analytics.google.com *.google.com *.google-analytics.com *.googletagmanager.com; \ + connect-src 'self' *.cookieyes.com cdn-cookieyes.com *.analytics.google.com *.google.com *.google-analytics.com *.googletagmanager.com; \ default-src 'none'; \ font-src 'self' fonts.gstatic.com data:; \ form-action 'self'; \ - frame-ancestors 'self'; \ + frame-ancestors 'self' gethinode.com; \ frame-src *.googletagmanager.com player.cloudinary.com www.youtube-nocookie.com www.youtube.com player.vimeo.com; \ - img-src 'self' *.google-analytics.com *.googletagmanager.com googletagmanager.com ssl.gstatic.com www.gstatic.com data: *.imgix.net *.imagekit.io *.cloudinary.com i.ytimg.com tile.openstreetmap.org i.vimeocdn.com; \ + img-src 'self' cdn-cookieyes.com *.google-analytics.com *.googletagmanager.com googletagmanager.com ssl.gstatic.com www.gstatic.com data: *.imgix.net *.imagekit.io *.cloudinary.com i.ytimg.com tile.openstreetmap.org i.vimeocdn.com; \ manifest-src 'self'; \ media-src 'self'; \ object-src 'none'; \ - script-src 'self' *.google-analytics.com *.googletagmanager.com *.analytics.google.com googletagmanager.com tagmanager.google.com player.vimeo.com; \ - style-src 'self' googletagmanager.com tagmanager.google.com fonts.googleapis.com www.youtube.com 'unsafe-inline'; \ + script-src 'self' cdn-cookieyes.com *.google-analytics.com *.googletagmanager.com *.analytics.google.com googletagmanager.com tagmanager.google.com player.vimeo.com; \ + style-src 'self' 'unsafe-inline' googletagmanager.com tagmanager.google.com fonts.googleapis.com www.youtube.com; \ """ Permissions-Policy = 'geolocation=(), midi=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(), payment=() ' Referrer-Policy = 'strict-origin' @@ -56,3 +56,23 @@ X-XSS-Protection = '1; mode=block' cache-control = 'max-age=0, no-cache, no-store, must-revalidate ' +[[redirects]] + from = '/fr/*' + status = 404 + to = '/fr/404.html' + +[[redirects]] + from = '/nl/*' + status = 404 + to = '/nl/404.html' + +[[redirects]] + from = '/en/*' + status = 404 + to = '/en/404.html' + +[[redirects]] + from = '/*' + status = 404 + to = '/en/404.html' + diff --git a/package.json b/package.json index 763de5109..4b4b7702c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "build:debug": "hugo -e debug --debug", "build:headers": "pnpm build:headers:dev && pnpm build:headers:prod", "build:headers:dev": "hugo --renderSegments headers -d prebuild-headers-dev -e development && cpy prebuild-headers-dev/server.toml config/_default/ --flat", - "build:headers:prod": "hugo --renderSegments headers -d prebuild-headers-prod -e production && cpy prebuild-headers-prod/netlify.toml ./ --flat", + "build:headers:prod": "hugo -s exampleSite --renderSegments headers -d prebuild-headers-prod -e production && cpy exampleSite/prebuild-headers-prod/netlify.toml ./ --flat", "build:example:headers": "hugo -s exampleSite --renderSegments headers -d prebuild && cpy exampleSite/prebuild/netlify.toml ./ --flat && cpy exampleSite/prebuild/server.toml exampleSite/config/_default/ --flat", "build:preview": "pnpm build -D -F", "clean:public": "rimraf public exampleSite/public", From e57fef67234c1b6db6141b4d1b20965bd66996ae Mon Sep 17 00:00:00 2001 From: Mark Dumay <61946753+markdumay@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:04:49 +0200 Subject: [PATCH 2/3] fix(csp): render the preview blocks on the demo site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The block reference from mod-docs, published at demo.gethinode.com/docs/blocks/preview, previews a Wikipedia article and an OpenStreetMap map. Neither host was listed in the demo's own CSP frame-src directive, so the browser blocked both iframes and the page showed two empty boxes. - Add the two hosts to frame-src, under the docs module so they union with the theme's own sources rather than replacing them. - Upgrade mod-blocks to v2.0.3, which fixes the preview component's embedding detection. The same page previews google.com on purpose, to demonstrate a site that refuses to be framed; it sends X-Frame-Options: SAMEORIGIN, and before v2.0.3 that was rendered as a live iframe, so the "blocked" example was itself an empty box rather than the intended screenshot fallback. - Regenerate netlify.toml. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) --- exampleSite/config/production/params.toml | 10 ++++++++++ exampleSite/go.mod | 2 +- exampleSite/go.sum | 2 ++ netlify.toml | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/exampleSite/config/production/params.toml b/exampleSite/config/production/params.toml index ff9eb0621..882e8ce46 100644 --- a/exampleSite/config/production/params.toml +++ b/exampleSite/config/production/params.toml @@ -8,3 +8,13 @@ "'self'", "gethinode.com" ] + +[modules.docs.csp] + # The block reference from mod-docs demonstrates the preview block by embedding a + # Wikipedia article and an OpenStreetMap map, which the browser refuses without + # these sources. The page also previews google.com on purpose, to show a site that + # refuses to be framed; that one falls back to a screenshot and needs no source. + frame-src = [ + "*.wikipedia.org", + "www.openstreetmap.org" + ] diff --git a/exampleSite/go.mod b/exampleSite/go.mod index ce71e822d..3974e087f 100644 --- a/exampleSite/go.mod +++ b/exampleSite/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/FortAwesome/Font-Awesome v0.0.0-20260625220317-70fb2dd154b6 // indirect github.com/cloudcannon/bookshop/hugo/v3 v3.18.5 // indirect - github.com/gethinode/mod-blocks/v2 v2.0.1 // indirect + github.com/gethinode/mod-blocks/v2 v2.0.3 // indirect github.com/gethinode/mod-bootstrap-icons/v2 v2.0.0 // indirect github.com/gethinode/mod-cookieyes/v2 v2.2.6 // indirect github.com/gethinode/mod-docs v1.14.1 // indirect diff --git a/exampleSite/go.sum b/exampleSite/go.sum index 6dfd78b8a..37d2aa436 100644 --- a/exampleSite/go.sum +++ b/exampleSite/go.sum @@ -4,6 +4,8 @@ github.com/cloudcannon/bookshop/hugo/v3 v3.18.5 h1:AKWzUQpWcBSbJgHQ/5cfPQtGX40bn github.com/cloudcannon/bookshop/hugo/v3 v3.18.5/go.mod h1:s7mIonDhtsLcn10ZKuVXyqd6BDHI8vT1WQhZw8rPfY8= github.com/gethinode/mod-blocks/v2 v2.0.1 h1:BoHDy2PqZfSQ5kolAjnem2gWOarxVCRzaJZ6owM0oCs= github.com/gethinode/mod-blocks/v2 v2.0.1/go.mod h1:yhZH/AHvPlr1IkYu9GRmhvsLBlyvwpO0T8DvnKUITDw= +github.com/gethinode/mod-blocks/v2 v2.0.3 h1:9jsVov1cJsQhUALVz/E+spSezAf8YGyGnd873VsRM4w= +github.com/gethinode/mod-blocks/v2 v2.0.3/go.mod h1:bqogsRCwVHZlsLN/XZmBC25UmralIvYwmRkAcj3601Q= github.com/gethinode/mod-bootstrap-icons/v2 v2.0.0 h1:ryXa25d/9mXVcPXhOwMtxtAtFkR0M1EPSIuU0xRRDec= github.com/gethinode/mod-bootstrap-icons/v2 v2.0.0/go.mod h1:0DKJp0goqI0vwOIVa8/yd3tAE0XdUypu1QRoz9K+094= github.com/gethinode/mod-cookieyes/v2 v2.2.6 h1:/DQm8OYpms0On8wuosQER47TplVu/3z7MZHwbBKXCAg= diff --git a/netlify.toml b/netlify.toml index ed5bf29ad..9f16bf5ee 100644 --- a/netlify.toml +++ b/netlify.toml @@ -41,7 +41,7 @@ font-src 'self' fonts.gstatic.com data:; \ form-action 'self'; \ frame-ancestors 'self' gethinode.com; \ - frame-src *.googletagmanager.com player.cloudinary.com www.youtube-nocookie.com www.youtube.com player.vimeo.com; \ + frame-src *.wikipedia.org www.openstreetmap.org *.googletagmanager.com player.cloudinary.com www.youtube-nocookie.com www.youtube.com player.vimeo.com; \ img-src 'self' cdn-cookieyes.com *.google-analytics.com *.googletagmanager.com googletagmanager.com ssl.gstatic.com www.gstatic.com data: *.imgix.net *.imagekit.io *.cloudinary.com i.ytimg.com tile.openstreetmap.org i.vimeocdn.com; \ manifest-src 'self'; \ media-src 'self'; \ From c7df3897b2b638c161b2fbe3d811d7e16f3cbb78 Mon Sep 17 00:00:00 2001 From: Mark Dumay <61946753+markdumay@users.noreply.github.com> Date: Mon, 13 Jul 2026 13:28:06 +0200 Subject: [PATCH 3/3] build(deps): inherit the preview CSP sources from mod-docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mod-docs v1.15.0 declares the frame-src sources its preview block reference needs, so the demo no longer has to hand-maintain them. Drop the site-level entries and upgrade the modules: - mod-docs v1.14.1 => v1.15.0, which declares *.wikipedia.org and www.openstreetmap.org. - mod-blocks v2.0.3 => v2.1.0, whose preview component now also checks a URL against the frame-src the site itself publishes, and falls back to the screenshot when it is not covered. The generated netlify.toml is unchanged: the two sources are now inherited rather than declared locally, so the published policy is identical. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.8 (1M context) --- exampleSite/config/production/params.toml | 10 ---------- exampleSite/go.mod | 4 ++-- exampleSite/go.sum | 4 ++++ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/exampleSite/config/production/params.toml b/exampleSite/config/production/params.toml index 882e8ce46..ff9eb0621 100644 --- a/exampleSite/config/production/params.toml +++ b/exampleSite/config/production/params.toml @@ -8,13 +8,3 @@ "'self'", "gethinode.com" ] - -[modules.docs.csp] - # The block reference from mod-docs demonstrates the preview block by embedding a - # Wikipedia article and an OpenStreetMap map, which the browser refuses without - # these sources. The page also previews google.com on purpose, to show a site that - # refuses to be framed; that one falls back to a screenshot and needs no source. - frame-src = [ - "*.wikipedia.org", - "www.openstreetmap.org" - ] diff --git a/exampleSite/go.mod b/exampleSite/go.mod index 3974e087f..7893c5186 100644 --- a/exampleSite/go.mod +++ b/exampleSite/go.mod @@ -5,10 +5,10 @@ go 1.19 require ( github.com/FortAwesome/Font-Awesome v0.0.0-20260625220317-70fb2dd154b6 // indirect github.com/cloudcannon/bookshop/hugo/v3 v3.18.5 // indirect - github.com/gethinode/mod-blocks/v2 v2.0.3 // indirect + github.com/gethinode/mod-blocks/v2 v2.1.0 // indirect github.com/gethinode/mod-bootstrap-icons/v2 v2.0.0 // indirect github.com/gethinode/mod-cookieyes/v2 v2.2.6 // indirect - github.com/gethinode/mod-docs v1.14.1 // indirect + github.com/gethinode/mod-docs v1.15.0 // indirect github.com/gethinode/mod-fontawesome/v6 v6.0.0 // indirect github.com/gethinode/mod-utils/v6 v6.4.0 // indirect github.com/twbs/icons v1.13.1 // indirect diff --git a/exampleSite/go.sum b/exampleSite/go.sum index 37d2aa436..f10a96f0f 100644 --- a/exampleSite/go.sum +++ b/exampleSite/go.sum @@ -6,12 +6,16 @@ github.com/gethinode/mod-blocks/v2 v2.0.1 h1:BoHDy2PqZfSQ5kolAjnem2gWOarxVCRzaJZ github.com/gethinode/mod-blocks/v2 v2.0.1/go.mod h1:yhZH/AHvPlr1IkYu9GRmhvsLBlyvwpO0T8DvnKUITDw= github.com/gethinode/mod-blocks/v2 v2.0.3 h1:9jsVov1cJsQhUALVz/E+spSezAf8YGyGnd873VsRM4w= github.com/gethinode/mod-blocks/v2 v2.0.3/go.mod h1:bqogsRCwVHZlsLN/XZmBC25UmralIvYwmRkAcj3601Q= +github.com/gethinode/mod-blocks/v2 v2.1.0 h1:bW+3p3XpOBk2RtJkWkHvHTo4ovUmQWm1h82VkJx3G90= +github.com/gethinode/mod-blocks/v2 v2.1.0/go.mod h1:bqogsRCwVHZlsLN/XZmBC25UmralIvYwmRkAcj3601Q= github.com/gethinode/mod-bootstrap-icons/v2 v2.0.0 h1:ryXa25d/9mXVcPXhOwMtxtAtFkR0M1EPSIuU0xRRDec= github.com/gethinode/mod-bootstrap-icons/v2 v2.0.0/go.mod h1:0DKJp0goqI0vwOIVa8/yd3tAE0XdUypu1QRoz9K+094= github.com/gethinode/mod-cookieyes/v2 v2.2.6 h1:/DQm8OYpms0On8wuosQER47TplVu/3z7MZHwbBKXCAg= github.com/gethinode/mod-cookieyes/v2 v2.2.6/go.mod h1:tULb7D7CoTycGUyL7ryqHJKaX11XuL2SN+XwP7/DI0Y= github.com/gethinode/mod-docs v1.14.1 h1:+G8IjMi/krhAzvOlB5ODnfQCp6b5ixWyU3D7f/8vdRg= github.com/gethinode/mod-docs v1.14.1/go.mod h1:ru1w0fHqFocjDIMV0dm40OwhBw5k4UncCS8iO/1S5kI= +github.com/gethinode/mod-docs v1.15.0 h1:A/iJ2S2v8Le0u8gdOfpLoss8mDaaJI+gtMNXiws7SyE= +github.com/gethinode/mod-docs v1.15.0/go.mod h1:ru1w0fHqFocjDIMV0dm40OwhBw5k4UncCS8iO/1S5kI= github.com/gethinode/mod-fontawesome/v6 v6.0.0 h1:PrfiMfVEAM5Lpnkp+sXOtOdRSOe3l56z+ngrPcACzlA= github.com/gethinode/mod-fontawesome/v6 v6.0.0/go.mod h1:ayMslv2xpC5cjxUVTkIlFBbOd1LM5ezIr0OSOr6q8Gk= github.com/gethinode/mod-utils/v6 v6.4.0 h1:l49KrawKE/7c6XE00wXQ9T5/kuTfiETerBz6OWn3SJc=