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