Even tighter CSP

Will this fix it?

Remove inline script and style from demo

Okay I'm dumb

Ugh
This commit is contained in:
daudix
2024-10-18 18:28:31 +03:00
parent 26b12aadf6
commit bc9a13d630
7 changed files with 152 additions and 156 deletions

View File

@ -162,13 +162,17 @@ show_backlinks = true
# Keep in mind that although this can potentially increase security, # Keep in mind that although this can potentially increase security,
# it can break some stuff, in which case you will need to set custom policy. # it can break some stuff, in which case you will need to set custom policy.
csp = [ csp = [
{ directive = "font-src", domains = ["'self'", "data:"] }, { directive = "font-src", domains = ["'self'"] },
{ directive = "img-src", domains = ["'self'", "https:", "data:"] }, { directive = "img-src", domains = ["'self'", "https:", "data:"] },
{ directive = "media-src", domains = ["'self'", "https:", "data:"] }, { directive = "media-src", domains = ["'self'", "https:"] },
{ directive = "script-src", domains = ["'self'"] }, { directive = "script-src", domains = ["'self'"] },
{ directive = "style-src", domains = ["'self'", "'unsafe-inline'"] }, { directive = "style-src", domains = ["'self'", "'unsafe-inline'"] },
{ directive = "frame-src", domains = ["https://player.vimeo.com", "https://www.youtube-nocookie.com", "https://toot.community"] }, { directive = "frame-src", domains = ["https://player.vimeo.com", "https://www.youtube-nocookie.com", "https://toot.community"] },
{ directive = "connect-src", domains = ["https://toot.community"] }, { directive = "connect-src", domains = ["https://toot.community"] },
{ directive = "frame-ancestors", domains = ["'none'"] },
{ directive = "base-uri", domains = ["'none'"] },
{ directive = "form-action", domains = ["'none'"] },
{ directive = "require-trusted-types-for", domains = ["'script'"] },
] ]
# Display outlines around all elements for debugging purposes # Display outlines around all elements for debugging purposes
# debug_layout = true # debug_layout = true

40
content/demo/demo.css Normal file
View File

@ -0,0 +1,40 @@
#color-picker-container {
-webkit-backdrop-filter: var(--blur);
position: fixed;
transform: translateX(calc(-100% + 1rem));
z-index: 1;
backdrop-filter: var(--blur);
transition: var(--transition);
inset-block-end: 1rem;
inset-inline-start: 0;
box-shadow: var(--edge-highlight), var(--shadow-glass);
border-start-end-radius: var(--rounded-corner);
border-end-end-radius: var(--rounded-corner);
background-color: var(--nav-bg);
padding: 0.5rem;
}
#color-picker-container:hover {
transform: none;
}
#color-picker-container label {
margin-inline-end: 0.25rem;
color: var(--fg-muted-4);
font-weight: bold;
}
:root[dir*="rtl"] #color-picker-container {
transform: translateX(calc(100% - 1rem));
}
:root[dir*="rtl"] #color-picker-container:hover {
transform: none;
}
#color-picker-light,
#color-picker-dark,
#contrast-color-light,
#contrast-color-dark {
margin-inline-end: 0.25rem;
}

91
content/demo/demo.js Normal file
View File

@ -0,0 +1,91 @@
const colorPickerLight = document.querySelector("#color-picker-light");
const colorPickerDark = document.querySelector("#color-picker-dark");
const contrastCheckboxLight = document.querySelector("#contrast-color-light");
const contrastCheckboxDark = document.querySelector("#contrast-color-dark");
let accentColorLight = colorPickerLight.value;
let accentColorDark = colorPickerDark.value;
colorPickerLight.addEventListener("input", updateAccentColorLight);
colorPickerDark.addEventListener("input", updateAccentColorDark);
contrastCheckboxLight.addEventListener("change", updateStyles);
contrastCheckboxDark.addEventListener("change", updateStyles);
function updateAccentColorLight() {
accentColorLight = colorPickerLight.value;
updateStyles();
}
function updateAccentColorDark() {
accentColorDark = colorPickerDark.value;
updateStyles();
}
function updateStyles() {
const contrastColorLight = contrastCheckboxLight.checked;
const contrastColorDark = contrastCheckboxDark.checked;
let styleElement = document.getElementById("dynamic-styles");
if (!styleElement) {
styleElement = document.createElement("style");
styleElement.id = "dynamic-styles";
document.head.appendChild(styleElement);
}
let styles = `
:root {
--accent-color: ${accentColorLight};
}
[data-theme="dark"] {
--accent-color: ${accentColorDark};
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--accent-color: ${accentColorDark};
}
}
`;
if (contrastColorLight) {
styles += `
:root {
--contrast-color: rgb(0 0 0 / 0.8);
}
`;
} else {
styles += `
:root {
--contrast-color: #fff;
}
`;
}
if (contrastColorDark) {
styles += `
[data-theme="dark"] {
--contrast-color: rgb(0 0 0 / 0.8);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--contrast-color: rgb(0 0 0 / 0.8);
}
}
`;
} else {
styles += `
[data-theme="dark"] {
--contrast-color: #fff;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--contrast-color: #fff;
}
}
`;
}
styleElement.textContent = styles;
}
updateStyles();

View File

@ -1,6 +1,8 @@
+++ +++
title = "Demo Page" title = "Demo Page"
[extra] [extra]
styles = ["demo/demo.css"]
scripts = ["demo/demo.js"]
katex = true katex = true
archive = "This page is in fact not archived. It is only here to demonstrate the archival statement." archive = "This page is in fact not archived. It is only here to demonstrate the archival statement."
trigger = "This page contains blackjack and hookers, and bad jokes such as this one." trigger = "This page contains blackjack and hookers, and bad jokes such as this one."
@ -678,141 +680,4 @@ You know, <span class="spoiler solid">Duckquill is a pretty dumb name.</span> I
<input id="contrast-color-dark" class="switch" type="checkbox" checked /> <input id="contrast-color-dark" class="switch" type="checkbox" checked />
<label for="contrast-color-dark">Dark theme</label> <label for="contrast-color-dark">Dark theme</label>
</div> </div>
<style>
#color-picker-container {
-webkit-backdrop-filter: var(--blur);
position: fixed;
transform: translateX(calc(-100% + 1rem));
z-index: 1;
backdrop-filter: var(--blur);
transition: var(--transition);
inset-block-end: 1rem;
inset-inline-start: 0;
box-shadow: var(--edge-highlight), var(--shadow-glass);
border-start-end-radius: var(--rounded-corner);
border-end-end-radius: var(--rounded-corner);
background-color: var(--nav-bg);
padding: 0.5rem;
}
#color-picker-container:hover {
transform: none;
}
#color-picker-container label {
margin-inline-end: 0.25rem;
color: var(--fg-muted-4);
font-weight: bold;
}
:root[dir*="rtl"] #color-picker-container {
transform: translateX(calc(100% - 1rem));
}
:root[dir*="rtl"] #color-picker-container:hover {
transform: none;
}
#color-picker-light,
#color-picker-dark,
#contrast-color-light,
#contrast-color-dark {
margin-inline-end: 0.25rem;
}
</style>
<script type="text/javascript">
const colorPickerLight = document.querySelector("#color-picker-light");
const colorPickerDark = document.querySelector("#color-picker-dark");
const contrastCheckboxLight = document.querySelector("#contrast-color-light");
const contrastCheckboxDark = document.querySelector("#contrast-color-dark");
let accentColorLight = colorPickerLight.value;
let accentColorDark = colorPickerDark.value;
colorPickerLight.addEventListener("input", updateAccentColorLight);
colorPickerDark.addEventListener("input", updateAccentColorDark);
contrastCheckboxLight.addEventListener("change", updateStyles);
contrastCheckboxDark.addEventListener("change", updateStyles);
function updateAccentColorLight() {
accentColorLight = colorPickerLight.value;
updateStyles();
}
function updateAccentColorDark() {
accentColorDark = colorPickerDark.value;
updateStyles();
}
function updateStyles() {
const contrastColorLight = contrastCheckboxLight.checked;
const contrastColorDark = contrastCheckboxDark.checked;
let styleElement = document.getElementById("dynamic-styles");
if (!styleElement) {
styleElement = document.createElement("style");
styleElement.id = "dynamic-styles";
document.head.appendChild(styleElement);
}
let styles = `
:root {
--accent-color: ${accentColorLight};
}
[data-theme="dark"] {
--accent-color: ${accentColorDark};
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--accent-color: ${accentColorDark};
}
}
`;
if (contrastColorLight) {
styles += `
:root {
--contrast-color: rgb(0 0 0 / 0.8);
}
`;
} else {
styles += `
:root {
--contrast-color: #fff;
}
`;
}
if (contrastColorDark) {
styles += `
[data-theme="dark"] {
--contrast-color: rgb(0 0 0 / 0.8);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--contrast-color: rgb(0 0 0 / 0.8);
}
}
`;
} else {
styles += `
[data-theme="dark"] {
--contrast-color: #fff;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--contrast-color: #fff;
}
}
`;
}
styleElement.textContent = styles;
}
updateStyles();
</script>
<!-- End --> <!-- End -->

8
static/katex-init.js Normal file
View File

@ -0,0 +1,8 @@
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
],
});
});

View File

@ -1,7 +1,7 @@
{#- Based on https://github.com/welpo/tabi/blob/7b00ed1d9dca5c529d2816c5b6679bfe600d63fc/templates/partials/content_security_policy.html -#} {#- Based on https://github.com/welpo/tabi/blob/7b00ed1d9dca5c529d2816c5b6679bfe600d63fc/templates/partials/content_security_policy.html -#}
<meta http-equiv="Content-Security-Policy" <meta http-equiv="content-security-policy"
content="default-src 'self' content="default-src 'none';
{%- if config.extra.csp -%} {%- if config.extra.csp -%}
{#- Initialise a base script-src directive -#} {#- Initialise a base script-src directive -#}
@ -39,9 +39,7 @@ content="default-src 'self'
{#- Handle directives that are not connect-src -#} {#- Handle directives that are not connect-src -#}
{{ domain.directive }} {{ domain.domains | join(sep=' ') -}} {{ domain.directive }} {{ domain.domains | join(sep=' ') -}}
{%- if not loop.last -%} {%- if not loop.last -%};{%- endif -%}
;
{%- endif -%}
{%- endfor -%} {%- endfor -%}
{#- Insert the generated connect-src -#} {#- Insert the generated connect-src -#}
@ -50,4 +48,4 @@ content="default-src 'self'
{#- Insert the generated script-src -#} {#- Insert the generated script-src -#}
{{ ";" ~ script_src }} {{ ";" ~ script_src }}
{%- endif -%}"> {%- endif -%}" />

View File

@ -78,17 +78,7 @@
{%- endif %} {%- endif %}
{%- if page.extra.katex or section.extra.katex or config.extra.katex %} {%- if page.extra.katex or section.extra.katex or config.extra.katex %}
{%- set scripts = scripts | concat(with=["katex.min.js", "auto-render.min.js"]) %} {%- set scripts = scripts | concat(with=["katex.min.js", "auto-render.min.js", "katex-init.js"]) %}
<script>
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
],
});
});
</script>
{%- endif %} {%- endif %}
{%- if config.build_search_index %} {%- if config.build_search_index %}