From 7264c44fd799ac36d1d46018d35bee8d994a817f Mon Sep 17 00:00:00 2001 From: denkfabrik-li <274324701+denkfabrik-li@users.noreply.github.com> Date: Sat, 29 Aug 2026 00:14:23 +0200 Subject: [PATCH] Serve the interface font from the installation, not from a font CDN app.blade.php is the root template for all three interfaces, and it opened with two lines pointing at a third party: Every visitor to /login, /register, /forgot-password, /s/{token} and every public listing page therefore made a request to a host the operator did not choose and could not switch off, before they had done anything at all -- handing it their IP address, their user agent, and through Origin the hostname of the installation they were visiting. On the signed-out pages that is a visitor who has agreed to nothing, and an operator who often has told their own users that this server is where their files live. There was no self-hosted copy in the repository, no setting, no mention in INSTALL.md, DOCKER.md or SECURITY.md, and no SRI on the tag. The font now ships with the application, through @fontsource/instrument-sans -- the same font, the same three weights the URL asked for, from a versioned dependency rather than binaries pasted into the repository. Vite fingerprints and emits them like any other asset. Cost, measured on this build: twelve files, 192 KB on disk. A browser fetches only woff2 and only the subsets it needs, which is 73 KB for all six woff2 files together and typically 41 KB (latin, three weights) for a page in English. Against that, every page load loses a DNS lookup, a TLS handshake and a round trip to another origin, so signed-out pages get faster rather than slower. This is a privacy change rather than a vulnerability fix, and worth saying plainly: the share token does not leak this way. Referrer-Policy: strict-origin-when-cross-origin is set in both nginx configs and in the INSTALL.md snippet, so the path never travelled in the Referer. What travelled was the visit itself. Not changed: public/.htaccess still sets no security headers at all, so an Apache installation has no Referrer-Policy. That is a real gap and a separate change. Verified: `npm run build` succeeds and emits the faces; no reference to the CDN survives anywhere in public/build; `tsc --noEmit` and prettier are clean. No test asserts on the font, before or after. --- package-lock.json | 10 ++++++++++ package.json | 1 + resources/css/app.css | 16 ++++++++++++++++ resources/views/app.blade.php | 3 --- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 143aa2e0..6d2b9211 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@fontsource/instrument-sans": "^5.3.0", "@headlessui/react": "^2.2.0", "@inertiajs/react": "^2.0.0", "@radix-ui/react-avatar": "^1.1.3", @@ -1160,6 +1161,15 @@ "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", "license": "MIT" }, + "node_modules/@fontsource/instrument-sans": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/instrument-sans/-/instrument-sans-5.3.0.tgz", + "integrity": "sha512-QwXc4hb/px3XvSPS2CPAOgey8nyrQFxgxrmXQQ+pN+P51hKdAcchxpg8rSbjANFfPu6VKXhDqkVDucXMZ9CM5g==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@headlessui/react": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.0.tgz", diff --git a/package.json b/package.json index e70008ae..bcc5171b 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@fontsource/instrument-sans": "^5.3.0", "@headlessui/react": "^2.2.0", "@inertiajs/react": "^2.0.0", "@radix-ui/react-avatar": "^1.1.3", diff --git a/resources/css/app.css b/resources/css/app.css index 006a8bbd..935bacc7 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,5 +1,21 @@ @import 'tailwindcss'; +/* + * Instrument Sans, served by this installation rather than by a font CDN. + * + * The three weights the design uses, which is what the stylesheet this + * replaces asked for. Every visitor to /login, /register, /forgot-password + * and every public share link used to make a request to a third party + * before they had done anything, handing it their IP, their user agent and + * the hostname of the installation they were visiting — on the signed-out + * pages, where the visitor has not agreed to anything and the operator + * never chose the recipient. Bundling it makes those pages talk only to + * the server they were asked for. + */ +@import '@fontsource/instrument-sans/400.css'; +@import '@fontsource/instrument-sans/500.css'; +@import '@fontsource/instrument-sans/600.css'; + @plugin 'tailwindcss-animate'; @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; diff --git a/resources/views/app.blade.php b/resources/views/app.blade.php index a54dcc9b..5a3fd2e6 100644 --- a/resources/views/app.blade.php +++ b/resources/views/app.blade.php @@ -33,9 +33,6 @@ - - - @routes @viteReactRefresh @php