Skip to content

Commit da9c3a4

Browse files
jvoisinfguillot
authored andcommitted
feat(js): tighten the trusted types policy
- Implement a better/simpler polyfill for web browsers that don't supported trusted types yet - Use two separate policies: one to create HTML, another to create/use script urls - Instead of having the policy live in the top-level scope, they're now declared at the lowest possible scope, right before they're used, making them inaccessible outside of it. This puts their usage completely out of reach of an attacker unable to gain some control outside of those two (small) scopes, and thus removes the need to tighten the policies. - Remove the now-unused tt.js file This has been tested on Firefox (doesn't support trusted types) and on Chromium (does support trusted types).
1 parent 8e1d0bb commit da9c3a4

File tree

4 files changed

+15
-18
lines changed

4 files changed

+15
-18
lines changed

internal/template/templates/common/layout.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
{{ if .user }}
3131
{{ $cspNonce := nonce }}
32-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; {{ if .user.ExternalFontHosts }}font-src {{ .user.ExternalFontHosts }}; {{ end }}style-src 'self'{{ if .user.Stylesheet }}{{ if .user.ExternalFontHosts }} {{ .user.ExternalFontHosts }}{{ end }} 'nonce-{{ $cspNonce }}'{{ end }}{{ if .user.CustomJS }}; script-src 'self' 'nonce-{{ $cspNonce }}'{{ end }}; require-trusted-types-for 'script'; trusted-types ttpolicy;">
32+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; {{ if .user.ExternalFontHosts }}font-src {{ .user.ExternalFontHosts }}; {{ end }}style-src 'self'{{ if .user.Stylesheet }}{{ if .user.ExternalFontHosts }} {{ .user.ExternalFontHosts }}{{ end }} 'nonce-{{ $cspNonce }}'{{ end }}{{ if .user.CustomJS }}; script-src 'self' 'nonce-{{ $cspNonce }}'{{ end }}; require-trusted-types-for 'script'; trusted-types html url;">
3333

3434
{{ if .user.Stylesheet -}}
3535
<style nonce="{{ $cspNonce }}">{{ .user.Stylesheet | safeCSS }}</style>
@@ -39,7 +39,7 @@
3939
<script type="module" nonce="{{ $cspNonce }}">{{ .user.CustomJS | safeJS }}</script>
4040
{{ end -}}
4141
{{ else -}}
42-
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; require-trusted-types-for 'script'; trusted-types ttpolicy;">
42+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; require-trusted-types-for 'script'; trusted-types html url;">
4343
{{ end -}}
4444

4545
<script src="{{ route "javascript" "name" "app" "checksum" .app_js_checksum }}" type="module"></script>

internal/ui/static/js/app.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22
const TOP = 9999;
33
const BOTTOM = -9999;
44

5+
// Simple Polyfill for browsers that don't support Trusted Types
6+
// See https://caniuse.com/?search=trusted%20types
7+
if (!window.trustedTypes || !trustedTypes.createPolicy) {
8+
window.trustedTypes = {
9+
createPolicy: (name, policy) => ({
10+
createScriptURL: src => src,
11+
createHTML: html => html,
12+
})
13+
};
14+
}
15+
516
/**
617
* Send a POST request to the specified URL with the given body.
718
*
@@ -746,6 +757,7 @@ function handleFetchOriginalContentAction() {
746757

747758
response.json().then((data) => {
748759
if (data.content && data.reading_time) {
760+
const ttpolicy = trustedTypes.createPolicy('html', {createHTML: html => html});
749761
document.querySelector(".entry-content").innerHTML = ttpolicy.createHTML(data.content);
750762
const entryReadingtimeElement = document.querySelector(".entry-reading-time");
751763
if (entryReadingtimeElement) {
@@ -1081,6 +1093,7 @@ function initializeServiceWorker() {
10811093
if ("serviceWorker" in navigator) {
10821094
const serviceWorkerURL = document.body.dataset.serviceWorkerUrl;
10831095
if (serviceWorkerURL) {
1096+
const ttpolicy = trustedTypes.createPolicy('url', {createScriptURL: src => src});
10841097
navigator.serviceWorker.register(ttpolicy.createScriptURL(serviceWorkerURL), {
10851098
type: "module"
10861099
}).catch((error) => {

internal/ui/static/js/tt.js

Lines changed: 0 additions & 15 deletions
This file was deleted.

internal/ui/static/static.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ func GenerateStylesheetsBundles() error {
121121
func GenerateJavascriptBundles(webauthnEnabled bool) error {
122122
var bundles = map[string][]string{
123123
"app": {
124-
"js/tt.js", // has to be first
125124
"js/touch_handler.js",
126125
"js/keyboard_handler.js",
127126
"js/modal_handler.js",

0 commit comments

Comments
 (0)