mirror of
https://github.com/discourse/discourse.git
synced 2024-12-08 11:43:39 +08:00
b1f74ab59e
The strict-dynamic CSP directive is supported in all our target browsers, and makes for a much simpler configuration. Instead of allowlisting paths, we use a per-request nonce to authorize `<script>` tags, and then those scripts are allowed to load additional scripts (or add additional inline scripts) without restriction. This becomes especially useful when admins want to add external scripts like Google Tag Manager, or advertising scripts, which then go on to load a ton of other scripts. All script tags introduced via themes will automatically have the nonce attribute applied, so it should be zero-effort for theme developers. Plugins *may* need some changes if they are inserting their own script tags. This commit introduces a strict-dynamic-based CSP behind an experimental `content_security_policy_strict_dynamic` site setting.
254 lines
6.7 KiB
Plaintext
254 lines
6.7 KiB
Plaintext
<%- unless customization_disabled? %>
|
|
<section id="d-splash">
|
|
<template class="splash-svg-template">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
version="1.1"
|
|
>
|
|
<style>
|
|
:root {
|
|
--animation-state: paused;
|
|
}
|
|
|
|
/* user picked a theme where the "regular" scheme is dark */
|
|
<%- if dark_color_scheme? %>
|
|
:root {
|
|
--primary: #<%= ColorScheme.hex_for_name("primary", scheme_id) %>;
|
|
--secondary: #<%= ColorScheme.hex_for_name("secondary", scheme_id) %>;
|
|
--tertiary: #<%= ColorScheme.hex_for_name("tertiary", scheme_id) %>;
|
|
--quaternary: #<%= ColorScheme.hex_for_name("quaternary", scheme_id) %>;
|
|
--highlight: #<%= ColorScheme.hex_for_name("highlight", scheme_id) %>;
|
|
--success: #<%= ColorScheme.hex_for_name("success", scheme_id) %>;
|
|
}
|
|
<%- else %>
|
|
/* user picked a theme a light scheme and also enabled a dark scheme */
|
|
|
|
/* deal with light scheme first */
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
--primary: #<%= ColorScheme.hex_for_name("primary", scheme_id) %>;
|
|
--secondary: #<%= ColorScheme.hex_for_name("secondary", scheme_id) %>;
|
|
--tertiary: #<%= ColorScheme.hex_for_name("tertiary", scheme_id) %>;
|
|
--quaternary: #<%= ColorScheme.hex_for_name("quaternary", scheme_id) %>;
|
|
--highlight: #<%= ColorScheme.hex_for_name("highlight", scheme_id) %>;
|
|
--success: #<%= ColorScheme.hex_for_name("success", scheme_id) %>;
|
|
}
|
|
}
|
|
|
|
/* then deal with dark scheme */
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--primary: #<%= ColorScheme.hex_for_name("primary", dark_scheme_id) %>;
|
|
--secondary: #<%= ColorScheme.hex_for_name("secondary", dark_scheme_id) %>;
|
|
--tertiary: #<%= ColorScheme.hex_for_name("tertiary", dark_scheme_id) %>;
|
|
--quaternary: #<%= ColorScheme.hex_for_name("quaternary", dark_scheme_id) %>;
|
|
--highlight: #<%= ColorScheme.hex_for_name("highlight", dark_scheme_id) %>;
|
|
--success: #<%= ColorScheme.hex_for_name("success", dark_scheme_id) %>;
|
|
}
|
|
}
|
|
<%- end %>
|
|
|
|
/* these styles need to live here because the SVG has a different scope */
|
|
.dots {
|
|
animation-name: loader;
|
|
animation-timing-function: ease-in-out;
|
|
animation-duration: 3s;
|
|
animation-iteration-count: infinite;
|
|
animation-play-state: var(--animation-state);
|
|
stroke: #fff;
|
|
stroke-width: 0.5px;
|
|
transform-origin: center;
|
|
opacity: 0;
|
|
r: max(1vw, 11px);
|
|
cy: 50%;
|
|
filter: saturate(2) opacity(0.85);
|
|
}
|
|
|
|
.dots:first-child {
|
|
fill: var(--quaternary);
|
|
}
|
|
|
|
.dots:nth-child(2) {
|
|
fill: var(--quaternary);
|
|
animation-delay: 0.15s;
|
|
}
|
|
|
|
.dots:nth-child(3) {
|
|
fill: var(--highlight);
|
|
animation-delay: 0.3s;
|
|
}
|
|
|
|
.dots:nth-child(4) {
|
|
fill: var(--tertiary);
|
|
animation-delay: 0.45s;
|
|
}
|
|
|
|
.dots:nth-child(5) {
|
|
fill: var(--tertiary);
|
|
animation-delay: 0.6s;
|
|
}
|
|
|
|
@keyframes loader {
|
|
0% {
|
|
opacity: 0;
|
|
transform: scale(1);
|
|
}
|
|
45% {
|
|
opacity: 1;
|
|
transform: scale(0.7);
|
|
}
|
|
65% {
|
|
opacity: 1;
|
|
transform: scale(0.7);
|
|
}
|
|
100% {
|
|
opacity: 0;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<g class="container">
|
|
<circle class="dots" cx="30vw" />
|
|
<circle class="dots" cx="40vw" />
|
|
<circle class="dots" cx="50vw" />
|
|
<circle class="dots" cx="60vw" />
|
|
<circle class="dots" cx="70vw" />
|
|
</g>
|
|
</svg>
|
|
</template>
|
|
|
|
<style>
|
|
html {
|
|
overflow-y: hidden !important;
|
|
}
|
|
|
|
/* user picked a theme where the "regular" scheme is dark */
|
|
<%- if dark_color_scheme? %>
|
|
html {
|
|
background-color: #<%= ColorScheme.hex_for_name("secondary", scheme_id) %>;
|
|
}
|
|
|
|
#d-splash .preloader-text-wrapper {
|
|
color: #<%= ColorScheme.hex_for_name("primary", scheme_id) %>;
|
|
}
|
|
<%- else %>
|
|
/* user picked a theme a light scheme and also enabled a dark scheme */
|
|
|
|
/* deal with light scheme first */
|
|
@media (prefers-color-scheme: light) {
|
|
html {
|
|
background-color: #<%= ColorScheme.hex_for_name("secondary", scheme_id) %>;
|
|
}
|
|
|
|
#d-splash .preloader-text-wrapper {
|
|
color: #<%= ColorScheme.hex_for_name("primary", scheme_id) %>;
|
|
}
|
|
}
|
|
|
|
/* then deal with dark scheme */
|
|
@media (prefers-color-scheme: dark) {
|
|
html {
|
|
background-color: #<%= ColorScheme.hex_for_name("secondary", dark_scheme_id) %>;
|
|
}
|
|
|
|
#d-splash .preloader-text-wrapper {
|
|
color: #<%= ColorScheme.hex_for_name("primary", dark_scheme_id) %>;
|
|
}
|
|
}
|
|
<%- end %>
|
|
|
|
#d-splash {
|
|
display: grid;
|
|
place-items: center;
|
|
backface-visibility: hidden;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
z-index: 1001;
|
|
--animation-state: paused;
|
|
}
|
|
|
|
#d-splash .preloader-image {
|
|
max-width: 100%;
|
|
height: 100vh;
|
|
}
|
|
|
|
#d-splash .preloader-text-wrapper {
|
|
position: absolute;
|
|
opacity: 0;
|
|
animation: fade-in 0.5s ease-in-out;
|
|
animation-delay: 1s;
|
|
animation-fill-mode: forwards;
|
|
animation-play-state: var(--animation-state);
|
|
margin-bottom: -4em;
|
|
}
|
|
|
|
#d-splash .preloader-text:after {
|
|
animation: loading-text 3s infinite;
|
|
content: "";
|
|
position: absolute;
|
|
margin: 0 0.1em;
|
|
left: 100%;
|
|
}
|
|
|
|
.rtl #d-splash .preloader-text:after {
|
|
left: 0;
|
|
right: 100%;
|
|
}
|
|
|
|
@keyframes fade-in {
|
|
0% {
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes loading-text {
|
|
0% {
|
|
content: "";
|
|
}
|
|
25% {
|
|
content: ".";
|
|
}
|
|
50% {
|
|
content: "..";
|
|
}
|
|
75% {
|
|
content: "...";
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<img
|
|
class="preloader-image"
|
|
src="data:image/svg;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
|
alt="<%=SiteSetting.title%>"
|
|
/>
|
|
|
|
<div class="preloader-text-wrapper">
|
|
<div class="preloader-text"><%= I18n.t("js.preloader_text") %></div>
|
|
</div>
|
|
|
|
<noscript>
|
|
<style>
|
|
html {
|
|
overflow-y: revert !important;
|
|
}
|
|
|
|
#d-splash {
|
|
display: none;
|
|
}
|
|
</style>
|
|
</noscript>
|
|
|
|
<script nonce="<%= csp_nonce_placeholder %>">
|
|
<%= SplashScreenHelper.raw_js %>
|
|
</script>
|
|
</section>
|
|
<%- end %>
|