Die HoneyBar braucht kein 'unsafe-inline' mehr

Ihre Stile hingen als <style> im Shadow DOM, und Markup faellt unter die
CSP der Gastgeber-App: Jede fremde App musste deshalb style-src
'unsafe-inline' erlauben, sonst stand die HoneyBar schwarz auf schwarz da.

Jetzt kommen sie als konstruiertes Stylesheet ueber die CSSOM herein, die
keine CSP kennt. Damit braucht die App gar keine style-src-Erlaubnis mehr
-- auch keine fuer die HoneyOS-Domain, was der geplante Weg ueber eine
zweite Datei und <link> gekostet haette, samt zweiter Anfrage.

Der Strich zum Wiederausklappen hat seinen eigenen Shadow-Root und geht
denselben Weg. Der Rueckfall fuer alte Browser laeuft nach innerHTML,
sonst raeumt das Markup ihn gleich wieder weg.

Gemessen an einer nachgebauten App mit style-src 'self': Leiste bernstein,
32 px, Strich mit Verlauf, keine CSP-Meldung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-11 13:50:06 +02:00
1 parent 8ca16aec84
commit 3b47003492
4 files changed
+97 -33

No files matched your search

+46 -14
View File
@@ -105,10 +105,37 @@
*/
const WAPPEN = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 12" shape-rendering="crispEdges" aria-hidden="true"><rect x="4" y="0" width="2" height="1" fill="#f5f2e7"/><rect x="9" y="0" width="2" height="1" fill="#f5f2e7"/><rect x="2" y="1" width="5" height="1" fill="#f5f2e7"/><rect x="8" y="1" width="5" height="1" fill="#f5f2e7"/><rect x="2" y="2" width="11" height="1" fill="#f5f2e7"/><rect x="14" y="2" width="1" height="1" fill="#3b2412"/><rect x="3" y="3" width="9" height="1" fill="#f5f2e7"/><rect x="13" y="3" width="2" height="1" fill="#3b2412"/><rect x="3" y="4" width="11" height="1" fill="#ffd060"/><rect x="2" y="5" width="2" height="1" fill="#f2b33d"/><rect x="4" y="5" width="2" height="1" fill="#5c3a1c"/><rect x="6" y="5" width="2" height="1" fill="#f2b33d"/><rect x="8" y="5" width="2" height="1" fill="#5c3a1c"/><rect x="10" y="5" width="5" height="1" fill="#f2b33d"/><rect x="1" y="6" width="3" height="1" fill="#f2b33d"/><rect x="4" y="6" width="2" height="1" fill="#5c3a1c"/><rect x="6" y="6" width="2" height="1" fill="#f2b33d"/><rect x="8" y="6" width="2" height="1" fill="#5c3a1c"/><rect x="10" y="6" width="2" height="1" fill="#f2b33d"/><rect x="12" y="6" width="1" height="1" fill="#181410"/><rect x="13" y="6" width="1" height="1" fill="#63c7c0"/><rect x="14" y="6" width="1" height="1" fill="#f2b33d"/><rect x="0" y="7" width="1" height="1" fill="#5c3a1c"/><rect x="1" y="7" width="3" height="1" fill="#f2b33d"/><rect x="4" y="7" width="2" height="1" fill="#5c3a1c"/><rect x="6" y="7" width="2" height="1" fill="#f2b33d"/><rect x="8" y="7" width="2" height="1" fill="#5c3a1c"/><rect x="10" y="7" width="2" height="1" fill="#f2b33d"/><rect x="12" y="7" width="2" height="1" fill="#181410"/><rect x="14" y="7" width="1" height="1" fill="#f2b33d"/><rect x="1" y="8" width="3" height="1" fill="#f2b33d"/><rect x="4" y="8" width="2" height="1" fill="#5c3a1c"/><rect x="6" y="8" width="2" height="1" fill="#f2b33d"/><rect x="8" y="8" width="2" height="1" fill="#5c3a1c"/><rect x="10" y="8" width="5" height="1" fill="#f2b33d"/><rect x="2" y="9" width="1" height="1" fill="#d2952a"/><rect x="3" y="9" width="2" height="1" fill="#462b14"/><rect x="5" y="9" width="2" height="1" fill="#d2952a"/><rect x="7" y="9" width="2" height="1" fill="#462b14"/><rect x="9" y="9" width="6" height="1" fill="#d2952a"/><rect x="3" y="10" width="2" height="1" fill="#181410"/><rect x="7" y="10" width="2" height="1" fill="#181410"/><rect x="11" y="10" width="2" height="1" fill="#181410"/><rect x="3" y="11" width="2" height="1" fill="#181410"/><rect x="7" y="11" width="2" height="1" fill="#181410"/><rect x="11" y="11" width="2" height="1" fill="#181410"/></svg>';
/* ── Stile ohne CSP-Ausnahme ──────────────────────────────────────────────
* Die Stile kommen als konstruiertes Stylesheet in den Shadow-Root, nicht
* als style-Element. Der Unterschied ist nicht Geschmack, sondern der
* ganze Punkt: Ein style-Element ist Markup und faellt damit unter die CSP der
* fremden App — die musste deshalb bis hierher style-src 'unsafe-inline'
* erlauben, sonst stand die HoneyBar schwarz auf schwarz da. Ueber die
* CSSOM gesetzte Stile fallen nicht darunter. So braucht die Gastgeber-App
* fuer die HoneyBar gar keine style-src-Erlaubnis mehr, und es bleibt
* trotzdem bei einer Datei ohne zweite Anfrage.
*
* Der Rueckfall ist fuer Browser ohne konstruierbare Stylesheets (vor
* Safari 16.4, Firefox 101): Dort steht es wie bisher, also nicht
* schlechter — nur eben weiter mit 'unsafe-inline'.
*/
function stileAnlegen(wurzel, css) {
try {
const blatt = new CSSStyleSheet();
blatt.replaceSync(css);
wurzel.adoptedStyleSheets = [blatt];
return;
} catch {
/* alter Browser: unten der Weg ueber das Markup */
}
const el = document.createElement("style");
el.textContent = css;
wurzel.appendChild(el);
}
const root = host.attachShadow({ mode: "open" });
root.innerHTML = `
<style>
const STIL = `
:host, * { box-sizing: border-box; }
/* Dieselben Röhren wie auf dem Schreibtisch. Welche gilt, sagt der
Server; bis seine Antwort da ist, leuchtet Bernstein. */
@@ -253,8 +280,9 @@
Logo links, das App-Menue am Pfeil rechts. */
.menu.sys { left: 6px; right: auto; }
@media (max-width: 560px) { .clock { display: none; } }
</style>
`;
root.innerHTML = `
<div class="bar">
<button class="home" id="home" title="HoneyOS-Menü" aria-haspopup="true" aria-expanded="false"><span class="hex">${WAPPEN}</span> HONEY<b>OS</b></button>
<nav class="apps" id="apps"></nav>
@@ -277,6 +305,8 @@
<div class="drawer" id="menuApps"></div>
</div>`;
stileAnlegen(root, STIL);
/* ── Aussehen ─────────────────────────────────────────────────────────────
* Dieselben drei Röhren wie in style.css. Sie hier zu wiederholen ist die
* bewusste Entscheidung: die HoneyBar soll ohne zweite Datei auskommen, damit
@@ -520,17 +550,19 @@
// auch wenn in HoneyOS Grün eingestellt war. Er gehört zur HoneyBar, also
// trägt er dieselbe Röhre.
const t = ROEHREN[(settings && settings.phosphor) || "amber"] || ROEHREN.amber;
r.innerHTML = `
<style>
.strich {
height: 3px;
background: linear-gradient(90deg, ${t.dim}, ${t.p} 50%, ${t.dim});
opacity: .55;
transition: opacity .15s, height .15s;
}
:host(:hover) .strich { opacity: 1; height: 3px; }
</style>
<div class="strich"></div>`;
// Auch hier ueber die CSSOM statt als style-Element: Der Strich hat seinen
// eigenen Shadow-Root und waere sonst das einzige Stueck geblieben, das
// unter einer strengen CSP unsichtbar bleibt.
r.innerHTML = `<div class="strich"></div>`;
stileAnlegen(r, `
.strich {
height: 3px;
background: linear-gradient(90deg, ${t.dim}, ${t.p} 50%, ${t.dim});
opacity: .55;
transition: opacity .15s, height .15s;
}
:host(:hover) .strich { opacity: 1; height: 3px; }
`);
nub.addEventListener("click", () => {
forget();