Even tighter CSP
Will this fix it? Remove inline script and style from demo Okay I'm dumb Ugh
This commit is contained in:
@ -162,13 +162,17 @@ show_backlinks = true
|
||||
# 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.
|
||||
csp = [
|
||||
{ directive = "font-src", domains = ["'self'", "data:"] },
|
||||
{ directive = "font-src", domains = ["'self'"] },
|
||||
{ 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 = "style-src", domains = ["'self'", "'unsafe-inline'"] },
|
||||
{ directive = "frame-src", domains = ["https://player.vimeo.com", "https://www.youtube-nocookie.com", "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
|
||||
# debug_layout = true
|
||||
|
40
content/demo/demo.css
Normal file
40
content/demo/demo.css
Normal 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
91
content/demo/demo.js
Normal 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();
|
@ -1,6 +1,8 @@
|
||||
+++
|
||||
title = "Demo Page"
|
||||
[extra]
|
||||
styles = ["demo/demo.css"]
|
||||
scripts = ["demo/demo.js"]
|
||||
katex = true
|
||||
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."
|
||||
@ -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 />
|
||||
<label for="contrast-color-dark">Dark theme</label>
|
||||
</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 -->
|
||||
|
8
static/katex-init.js
Normal file
8
static/katex-init.js
Normal file
@ -0,0 +1,8 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{ left: "$$", right: "$$", display: true },
|
||||
{ left: "$", right: "$", display: false },
|
||||
],
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
{#- Based on https://github.com/welpo/tabi/blob/7b00ed1d9dca5c529d2816c5b6679bfe600d63fc/templates/partials/content_security_policy.html -#}
|
||||
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'
|
||||
<meta http-equiv="content-security-policy"
|
||||
content="default-src 'none';
|
||||
{%- if config.extra.csp -%}
|
||||
|
||||
{#- Initialise a base script-src directive -#}
|
||||
@ -39,9 +39,7 @@ content="default-src 'self'
|
||||
{#- Handle directives that are not connect-src -#}
|
||||
{{ domain.directive }} {{ domain.domains | join(sep=' ') -}}
|
||||
|
||||
{%- if not loop.last -%}
|
||||
;
|
||||
{%- endif -%}
|
||||
{%- if not loop.last -%};{%- endif -%}
|
||||
{%- endfor -%}
|
||||
|
||||
{#- Insert the generated connect-src -#}
|
||||
@ -50,4 +48,4 @@ content="default-src 'self'
|
||||
{#- Insert the generated script-src -#}
|
||||
{{ ";" ~ script_src }}
|
||||
|
||||
{%- endif -%}">
|
||||
{%- endif -%}" />
|
||||
|
@ -78,17 +78,7 @@
|
||||
{%- endif %}
|
||||
|
||||
{%- if page.extra.katex or section.extra.katex or config.extra.katex %}
|
||||
{%- set scripts = scripts | concat(with=["katex.min.js", "auto-render.min.js"]) %}
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{ left: "$$", right: "$$", display: true },
|
||||
{ left: "$", right: "$", display: false },
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{%- set scripts = scripts | concat(with=["katex.min.js", "auto-render.min.js", "katex-init.js"]) %}
|
||||
{%- endif %}
|
||||
|
||||
{%- if config.build_search_index %}
|
||||
|
Reference in New Issue
Block a user