mirror of
https://github.com/miniflux/v2.git
synced 2025-09-15 18:57:04 +00:00
Merge 65b86b1bcc
into 87e65f800e
This commit is contained in:
commit
ef564b39c9
3 changed files with 51 additions and 11 deletions
|
@ -33,6 +33,7 @@ type funcMap struct {
|
||||||
func (f *funcMap) Map() template.FuncMap {
|
func (f *funcMap) Map() template.FuncMap {
|
||||||
return template.FuncMap{
|
return template.FuncMap{
|
||||||
"contains": strings.Contains,
|
"contains": strings.Contains,
|
||||||
|
"csp": csp,
|
||||||
"startsWith": strings.HasPrefix,
|
"startsWith": strings.HasPrefix,
|
||||||
"formatFileSize": formatFileSize,
|
"formatFileSize": formatFileSize,
|
||||||
"dict": dict,
|
"dict": dict,
|
||||||
|
@ -116,6 +117,42 @@ func (f *funcMap) Map() template.FuncMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func csp(user *model.User, nonce string) string {
|
||||||
|
order := [...]string{"default-src", "img-src", "media-src", "frame-src", "style-src", "script-src", "font-src", "require-trusted-types-for", "trusted-types"}
|
||||||
|
policies := map[string]string{
|
||||||
|
"default-src": "'none'",
|
||||||
|
"img-src": "* data:",
|
||||||
|
"media-src": "*",
|
||||||
|
"frame-src": "*",
|
||||||
|
"style-src": "'nonce-" + nonce + "'",
|
||||||
|
"script-src": "'nonce-" + nonce + "' 'strict-dynamic'",
|
||||||
|
"require-trusted-types-for": "'script'",
|
||||||
|
"trusted-types": "html url",
|
||||||
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
if user.ExternalFontHosts != "" {
|
||||||
|
policies["font-src"] = user.ExternalFontHosts
|
||||||
|
if user.Stylesheet != "" {
|
||||||
|
policies["style-src"] += " " + user.ExternalFontHosts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var policy strings.Builder
|
||||||
|
// This is needed to always have the same order.
|
||||||
|
for _, key := range order {
|
||||||
|
if value, ok := policies[key]; ok {
|
||||||
|
policy.WriteString(key)
|
||||||
|
policy.WriteString(" ")
|
||||||
|
policy.WriteString(value)
|
||||||
|
policy.WriteString("; ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<meta http-equiv="Content-Security-Policy" content="` + policy.String() + `">`
|
||||||
|
}
|
||||||
|
|
||||||
func dict(values ...any) (map[string]any, error) {
|
func dict(values ...any) (map[string]any, error) {
|
||||||
if len(values)%2 != 0 {
|
if len(values)%2 != 0 {
|
||||||
return nil, fmt.Errorf("dict expects an even number of arguments")
|
return nil, fmt.Errorf("dict expects an even number of arguments")
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
|
"miniflux.app/v2/internal/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDict(t *testing.T) {
|
func TestDict(t *testing.T) {
|
||||||
|
@ -159,3 +160,11 @@ func TestFormatFileSize(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCSP(t *testing.T) {
|
||||||
|
want := `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src * data:; media-src *; frame-src *; style-src 'nonce-1234'; script-src 'nonce-1234' 'strict-dynamic'; font-src test.com; require-trusted-types-for 'script'; trusted-types html url; ">`
|
||||||
|
got := csp(&model.User{ExternalFontHosts: "test.com"}, "1234")
|
||||||
|
if got != want {
|
||||||
|
t.Errorf(`Unexpected result, got %q instead of %q`, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,24 +25,18 @@
|
||||||
<link rel="apple-touch-icon" sizes="167x167" href="{{ route "appIcon" "filename" "icon-167.png" }}">
|
<link rel="apple-touch-icon" sizes="167x167" href="{{ route "appIcon" "filename" "icon-167.png" }}">
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ route "appIcon" "filename" "icon-180.png" }}">
|
<link rel="apple-touch-icon" sizes="180x180" href="{{ route "appIcon" "filename" "icon-180.png" }}">
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="{{ route "stylesheet" "name" .theme "checksum" .theme_checksum }}">
|
|
||||||
|
|
||||||
{{ if .user }}
|
|
||||||
{{ $cspNonce := nonce }}
|
{{ $cspNonce := nonce }}
|
||||||
<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;">
|
{{ csp .user $cspNonce | safeHTML }}
|
||||||
|
<link rel="stylesheet" nonce="{{ $cspNonce }}" type="text/css" href="{{ route "stylesheet" "name" .theme "checksum" .theme_checksum }}">
|
||||||
|
<script nonce="{{ $cspNonce }}" src="{{ route "javascript" "name" "app" "checksum" .app_js_checksum }}" type="module"></script>
|
||||||
|
{{ if .user -}}
|
||||||
{{ if .user.Stylesheet -}}
|
{{ if .user.Stylesheet -}}
|
||||||
<style nonce="{{ $cspNonce }}">{{ .user.Stylesheet | safeCSS }}</style>
|
<style nonce="{{ $cspNonce }}">{{ .user.Stylesheet | safeCSS }}</style>
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
|
||||||
{{ if .user.CustomJS -}}
|
{{ if .user.CustomJS -}}
|
||||||
<script type="module" nonce="{{ $cspNonce }}">{{ .user.CustomJS | safeJS }}</script>
|
<script type="module" nonce="{{ $cspNonce }}">{{ .user.CustomJS | safeJS }}</script>
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ else -}}
|
|
||||||
<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;">
|
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
|
||||||
<script src="{{ route "javascript" "name" "app" "checksum" .app_js_checksum }}" type="module"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
data-service-worker-url="{{ route "javascript" "name" "service-worker" "checksum" .sw_js_checksum }}"
|
data-service-worker-url="{{ route "javascript" "name" "service-worker" "checksum" .sw_js_checksum }}"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue