tpl/tplimpl: Escape Markdown attributes in render hooks and shortcodes
This commit is contained in:
parent
b8c15f245b
commit
54398f8d57
7 changed files with 74 additions and 68 deletions
|
@ -90,7 +90,7 @@ baseURL="https://example.org"
|
||||||
[markup.goldmark]
|
[markup.goldmark]
|
||||||
[markup.goldmark.renderer]
|
[markup.goldmark.renderer]
|
||||||
unsafe = true
|
unsafe = true
|
||||||
|
|
||||||
`)
|
`)
|
||||||
|
|
||||||
b.WithTemplates("index.html", `
|
b.WithTemplates("index.html", `
|
||||||
|
@ -223,16 +223,16 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
|
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
|
||||||
-- layouts/_default/single.html --
|
-- layouts/_default/single.html --
|
||||||
{{ .Title }}|{{ .Content }}|$
|
{{ .Title }}|{{ .Content }}|$
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
t.Run("Default multilingual", func(t *testing.T) {
|
t.Run("Default multilingual", func(t *testing.T) {
|
||||||
b := Test(t, files)
|
b := Test(t, files)
|
||||||
|
|
||||||
b.AssertFileContent("public/nn/p1/index.html",
|
b.AssertFileContent("public/nn/p1/index.html",
|
||||||
"p1|<p><a href=\"/nn/p2/\">P2</a\n></p>", "<img alt=\"Pixel\" src=\"/nn/p1/pixel.nn.png\">")
|
"p1|<p><a href=\"/nn/p2/\">P2</a\n></p>", "<img src=\"/nn/p1/pixel.nn.png\" alt=\"Pixel\">")
|
||||||
b.AssertFileContent("public/en/p1/index.html",
|
b.AssertFileContent("public/en/p1/index.html",
|
||||||
"p1 en|<p><a href=\"/en/p2/\">P2</a\n></p>", "<img alt=\"Pixel\" src=\"/nn/p1/pixel.nn.png\">")
|
"p1 en|<p><a href=\"/en/p2/\">P2</a\n></p>", "<img src=\"/nn/p1/pixel.nn.png\" alt=\"Pixel\">")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Disabled", func(t *testing.T) {
|
t.Run("Disabled", func(t *testing.T) {
|
||||||
|
@ -279,7 +279,7 @@ Image: 
|
||||||
if enabled {
|
if enabled {
|
||||||
b.AssertFileContent("public/index.html",
|
b.AssertFileContent("public/index.html",
|
||||||
"Link: <a href=\"/destination-%22%3C%3E\" title=\"title-"<>&\">text-"<>&</a>",
|
"Link: <a href=\"/destination-%22%3C%3E\" title=\"title-"<>&\">text-"<>&</a>",
|
||||||
"img alt=\"alt-"<>&\" src=\"/destination-%22%3C%3E\" title=\"title-"<>&\">",
|
"img src=\"/destination-%22%3C%3E\" alt=\"alt-"<>&\" title=\"title-"<>&\">",
|
||||||
"><script>",
|
"><script>",
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -89,6 +89,12 @@ title = true
|
||||||
| Codecademy Hoodie | False | 42.99 |
|
| Codecademy Hoodie | False | 42.99 |
|
||||||
{.foo}
|
{.foo}
|
||||||
|
|
||||||
|
## Table 2
|
||||||
|
|
||||||
|
a|b
|
||||||
|
---|---
|
||||||
|
1|2
|
||||||
|
{id="\"><script>alert()</script>"}
|
||||||
|
|
||||||
-- layouts/_default/single.html --
|
-- layouts/_default/single.html --
|
||||||
Summary: {{ .Summary }}
|
Summary: {{ .Summary }}
|
||||||
|
@ -97,7 +103,8 @@ Content: {{ .Content }}
|
||||||
`
|
`
|
||||||
b := hugolib.Test(t, files)
|
b := hugolib.Test(t, files)
|
||||||
|
|
||||||
b.AssertFileContent("public/p1/index.html", "<table class=\"foo\">")
|
b.AssertFileContent("public/p1/index.html", `<table class="foo">`)
|
||||||
|
b.AssertFileContent("public/p1/index.html", `<table id=""><script>alert()</script>">`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue 12811.
|
// Issue 12811.
|
||||||
|
@ -166,14 +173,8 @@ title: "Home"
|
||||||
| Codecademy Tee | False | 19.99 |
|
| Codecademy Tee | False | 19.99 |
|
||||||
| Codecademy Hoodie | False | 42.99 |
|
| Codecademy Hoodie | False | 42.99 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- layouts/index.xml --
|
-- layouts/index.xml --
|
||||||
Content: {{ .Content }}
|
Content: {{ .Content }}
|
||||||
|
|
||||||
|
|
||||||
`
|
`
|
||||||
b := hugolib.Test(t, files)
|
b := hugolib.Test(t, files)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{- $u := urls.Parse .Destination -}}
|
{{- $u := urls.Parse .Destination -}}
|
||||||
{{- $src := $u.String -}}
|
{{- $src := $u.String -}}
|
||||||
{{- if not $u.IsAbs -}}
|
{{- if not $u.IsAbs -}}
|
||||||
{{- $path := strings.TrimPrefix "./" $u.Path }}
|
{{- $path := strings.TrimPrefix "./" $u.Path -}}
|
||||||
{{- with or (.PageInner.Resources.Get $path) (resources.Get $path) -}}
|
{{- with or (.PageInner.Resources.Get $path) (resources.Get $path) -}}
|
||||||
{{- $src = .RelPermalink -}}
|
{{- $src = .RelPermalink -}}
|
||||||
{{- with $u.RawQuery -}}
|
{{- with $u.RawQuery -}}
|
||||||
|
@ -12,11 +12,12 @@
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $attributes := merge .Attributes (dict "alt" .Text "src" $src "title" (.Title | transform.HTMLEscape)) -}}
|
<img src="{{ $src }}" alt="{{ .Text }}"
|
||||||
<img
|
{{- with .Title }} title="{{ . }}" {{- end -}}
|
||||||
{{- range $k, $v := $attributes -}}
|
{{- range $k, $v := .Attributes -}}
|
||||||
{{- if $v -}}
|
{{- if $v -}}
|
||||||
{{- printf " %s=%q" $k $v | safeHTMLAttr -}}
|
{{- printf " %s=%q" $k ($v | transform.HTMLEscape) | safeHTMLAttr -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}>
|
{{- end -}}
|
||||||
|
>
|
||||||
{{- /**/ -}}
|
{{- /**/ -}}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
{{- $u := urls.Parse .Destination -}}
|
{{- $u := urls.Parse .Destination -}}
|
||||||
{{- $href := $u.String -}}
|
{{- $href := $u.String -}}
|
||||||
{{- if strings.HasPrefix $u.String "#" }}
|
{{- if strings.HasPrefix $u.String "#" -}}
|
||||||
{{- $href = printf "%s#%s" .PageInner.RelPermalink $u.Fragment }}
|
{{- $href = printf "%s#%s" .PageInner.RelPermalink $u.Fragment -}}
|
||||||
{{- else if not $u.IsAbs -}}
|
{{- else if and $href (not $u.IsAbs) -}}
|
||||||
{{- $path := strings.TrimPrefix "./" $u.Path }}
|
{{- $path := strings.TrimPrefix "./" $u.Path -}}
|
||||||
{{- with or
|
{{- with or
|
||||||
($.PageInner.GetPage $path)
|
($.PageInner.GetPage $path)
|
||||||
($.PageInner.Resources.Get $path)
|
($.PageInner.Resources.Get $path)
|
||||||
|
@ -18,12 +18,5 @@
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $attributes := dict "href" $href "title" (.Title | transform.HTMLEscape) -}}
|
<a href="{{ $href }}" {{- with .Title }} title="{{ . }}" {{- end }}>{{ .Text }}</a>
|
||||||
<a
|
|
||||||
{{- range $k, $v := $attributes -}}
|
|
||||||
{{- if $v -}}
|
|
||||||
{{- printf " %s=%q" $k $v | safeHTMLAttr -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
>{{ .Text }}</a>
|
|
||||||
{{- /**/ -}}
|
{{- /**/ -}}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<table
|
<table
|
||||||
{{- range $k, $v := .Attributes }}
|
{{- range $k, $v := .Attributes }}
|
||||||
{{- if $v }}
|
{{- if $v }}
|
||||||
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
|
{{- printf " %s=%q" $k ($v | transform.HTMLEscape) | safeHTMLAttr }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}>
|
{{- end }}>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -26,7 +26,7 @@ Renders an embedded YouTube video.
|
||||||
{{- if not $pc.Disable }}
|
{{- if not $pc.Disable }}
|
||||||
{{- with $id := or (.Get "id") (.Get 0) }}
|
{{- with $id := or (.Get "id") (.Get 0) }}
|
||||||
|
|
||||||
{{/* Set defaults. */}}
|
{{- /* Set defaults. */}}
|
||||||
{{- $allowFullScreen := "allowfullscreen" }}
|
{{- $allowFullScreen := "allowfullscreen" }}
|
||||||
{{- $autoplay := 0 }}
|
{{- $autoplay := 0 }}
|
||||||
{{- $class := "" }}
|
{{- $class := "" }}
|
||||||
|
@ -70,23 +70,8 @@ Renders an embedded YouTube video.
|
||||||
{{- $start := or ($.Get "start") $start }}
|
{{- $start := or ($.Get "start") $start }}
|
||||||
{{- $title := or ($.Get "title") $title }}
|
{{- $title := or ($.Get "title") $title }}
|
||||||
|
|
||||||
{{- /* Determine host. */}}
|
|
||||||
{{- $host := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" }}
|
|
||||||
|
|
||||||
{{- /* Set styles. */}}
|
|
||||||
{{- $divStyle := "position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;" }}
|
|
||||||
{{- $iframeStyle := "position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" }}
|
|
||||||
{{- if $class }}
|
|
||||||
{{- $iframeStyle = "" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- /* Set class or style of wrapping div element. */}}
|
|
||||||
{{- $divClassOrStyle := printf "style=%q" $divStyle }}
|
|
||||||
{{- with $class }}
|
|
||||||
{{- $divClassOrStyle = printf "class=%q" $class }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- /* Define src attribute. */}}
|
{{- /* Define src attribute. */}}
|
||||||
|
{{- $host := cond $pc.PrivacyEnhanced "www.youtube-nocookie.com" "www.youtube.com" }}
|
||||||
{{- $src := printf "https://%s/embed/%s" $host $id }}
|
{{- $src := printf "https://%s/embed/%s" $host $id }}
|
||||||
{{- $params := dict
|
{{- $params := dict
|
||||||
"autoplay" $autoplay
|
"autoplay" $autoplay
|
||||||
|
@ -108,25 +93,33 @@ Renders an embedded YouTube video.
|
||||||
{{- $src = printf "%s?%s" $src . }}
|
{{- $src = printf "%s?%s" $src . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- /* Set div attributes. */}}
|
||||||
|
{{- $divStyle := "position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;" }}
|
||||||
|
{{- if $class }}
|
||||||
|
{{- $divStyle = "" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{- /* Set iframe attributes. */}}
|
{{- /* Set iframe attributes. */}}
|
||||||
{{- $iframeAttributes := dict
|
{{- $iframeStyle := "position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" }}
|
||||||
"allow" "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
{{- if $class }}
|
||||||
"allowfullscreen" $allowFullScreen
|
{{- $iframeStyle = "" }}
|
||||||
"loading" $loading
|
{{- end }}
|
||||||
"referrerpolicy" "strict-origin-when-cross-origin"
|
{{- $allow := "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" }}
|
||||||
"src" $src
|
{{- $referrerpolicy := "strict-origin-when-cross-origin" }}
|
||||||
"style" $iframeStyle
|
|
||||||
"title" $title
|
|
||||||
}}
|
|
||||||
|
|
||||||
{{- /* Render. */}}
|
{{- /* Render. */}}
|
||||||
<div {{ $divClassOrStyle | safeHTMLAttr }}>
|
<div
|
||||||
|
{{- with $class }} class="{{ . }}" {{- end }}
|
||||||
|
{{- with $divStyle }} style="{{ . | safeCSS }}" {{- end -}}
|
||||||
|
>
|
||||||
<iframe
|
<iframe
|
||||||
{{- range $k, $v := $iframeAttributes }}
|
{{- with $allow }} allow="{{ . }}" {{- end }}
|
||||||
{{- if $v }}
|
{{- with $allowFullScreen }} allowfullscreen="{{ . }}" {{- end }}
|
||||||
{{- printf " %s=%q" $k $v | safeHTMLAttr }}
|
{{- with $loading }} loading="{{ . }}" {{- end }}
|
||||||
{{- end }}
|
{{- with $referrerpolicy }} referrerpolicy="{{ . }}" {{- end }}
|
||||||
{{- end }}
|
{{- with $src }} src="{{ . }}" {{- end }}
|
||||||
|
{{- with $iframeStyle}} style="{{ . | safeCSS }}" {{- end }}
|
||||||
|
{{- with $title }} title="{{ . }}" {{- end -}}
|
||||||
></iframe>
|
></iframe>
|
||||||
</div>
|
</div>
|
||||||
{{- else }}
|
{{- else }}
|
||||||
|
|
|
@ -91,6 +91,9 @@ title: s1/p3
|
||||||
[430](p2/)
|
[430](p2/)
|
||||||
[440](/s1/p2/)
|
[440](/s1/p2/)
|
||||||
[450](../s1/p2/)
|
[450](../s1/p2/)
|
||||||
|
|
||||||
|
// empty
|
||||||
|
[]()
|
||||||
`
|
`
|
||||||
|
|
||||||
b := hugolib.Test(t, files)
|
b := hugolib.Test(t, files)
|
||||||
|
@ -122,6 +125,8 @@ title: s1/p3
|
||||||
`<a href="/s1/p2/">430</a>`,
|
`<a href="/s1/p2/">430</a>`,
|
||||||
`<a href="/s1/p2/">440</a>`,
|
`<a href="/s1/p2/">440</a>`,
|
||||||
`<a href="/s1/p2/">450</a>`,
|
`<a href="/s1/p2/">450</a>`,
|
||||||
|
|
||||||
|
`<a href=""></a>`,
|
||||||
)
|
)
|
||||||
|
|
||||||
b.AssertFileContent("public/s1/p2/index.html",
|
b.AssertFileContent("public/s1/p2/index.html",
|
||||||
|
@ -148,10 +153,17 @@ block = false
|
||||||
[markup.goldmark.renderHooks.image]
|
[markup.goldmark.renderHooks.image]
|
||||||
enableDefault = true
|
enableDefault = true
|
||||||
-- content/p1/index.md --
|
-- content/p1/index.md --
|
||||||
|
![]()
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
{.foo #bar}
|
{.foo #bar}
|
||||||
|
|
||||||
|

|
||||||
|
{id="\"><script>alert()</script>"}
|
||||||
-- content/p1/pixel.png --
|
-- content/p1/pixel.png --
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
|
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
|
||||||
-- layouts/_default/single.html --
|
-- layouts/_default/single.html --
|
||||||
|
@ -160,15 +172,21 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
|
||||||
|
|
||||||
b := hugolib.Test(t, files)
|
b := hugolib.Test(t, files)
|
||||||
b.AssertFileContent("public/p1/index.html",
|
b.AssertFileContent("public/p1/index.html",
|
||||||
`<img alt="alt1" src="/dir/p1/pixel.png">`,
|
`<img src="" alt="">`,
|
||||||
`<img alt="alt2" src="/dir/p1/pixel.png?a=b&c=d#fragment">`,
|
`<img src="/dir/p1/pixel.png" alt="alt1">`,
|
||||||
|
`<img src="/dir/p1/pixel.png" alt="alt2-&<>’" title="&<>'">`,
|
||||||
|
`<img src="/dir/p1/pixel.png?a=b&c=d#fragment" alt="alt3">`,
|
||||||
|
`<img src="/dir/p1/pixel.png" alt="alt4">`,
|
||||||
)
|
)
|
||||||
|
|
||||||
files = strings.Replace(files, "block = false", "block = true", -1)
|
files = strings.Replace(files, "block = false", "block = true", -1)
|
||||||
|
|
||||||
b = hugolib.Test(t, files)
|
b = hugolib.Test(t, files)
|
||||||
b.AssertFileContent("public/p1/index.html",
|
b.AssertFileContent("public/p1/index.html",
|
||||||
`<img alt="alt1" src="/dir/p1/pixel.png">`,
|
`<img src="" alt="">`,
|
||||||
`<img alt="alt2" class="foo" id="bar" src="/dir/p1/pixel.png?a=b&c=d#fragment">`,
|
`<img src="/dir/p1/pixel.png" alt="alt1">`,
|
||||||
|
`<img src="/dir/p1/pixel.png" alt="alt2-&<>’" title="&<>'">`,
|
||||||
|
`<img src="/dir/p1/pixel.png?a=b&c=d#fragment" alt="alt3" class="foo" id="bar">`,
|
||||||
|
`<img src="/dir/p1/pixel.png" alt="alt4" id=""><script>alert()</script>">`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue