Compare commits

...

4 commits

Author SHA1 Message Date
Bjørn Erik Pedersen 509ab08c1b markup/goldmark: Fix data race in the hugocontext wrapper
The window for this to happen is very small, but it has been reported by Go's race detector (-race flag) in a tests once.
2024-04-22 19:10:15 +02:00
Bjørn Erik Pedersen 2d75f539e1
Delete .hugo_build.lock
Added to Git by accident.
2024-04-22 16:57:48 +02:00
Bjørn Erik Pedersen 15a4b9b337 tpl: Escape .Title in built-in image and link render hooks
Co-authored-by: Joe Mooring <joe@mooring.com>
2024-04-22 16:54:24 +02:00
Joe Mooring 10a8448eee tpl/tplimpl: Improve embedded templates
- Do not call the YouTube oEmbed API
- Do not include the Hugo version in RSS feeds

Closes #12396
2024-04-22 15:57:37 +02:00
8 changed files with 60 additions and 24 deletions

View file

@ -14,6 +14,7 @@
package hugolib
import (
"fmt"
"strings"
"testing"
)
@ -241,3 +242,52 @@ iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAA
"p1|<p><a href=\"p2\">P2</a>", "<img src=\"pixel.png\" alt=\"Pixel\">")
})
}
func TestRenderHooksDefaultEscape(t *testing.T) {
files := `
-- hugo.toml --
[markup.goldmark.renderHooks]
[markup.goldmark.renderHooks.image]
enableDefault = ENABLE
[markup.goldmark.renderHooks.link]
enableDefault = ENABLE
[markup.goldmark.parser]
wrapStandAloneImageWithinParagraph = false
[markup.goldmark.parser.attribute]
block = true
title = true
-- content/_index.md --
---
title: "Home"
---
Link: [text-"<>&](/destination-"<> 'title-"<>&')
Image: ![alt-"<>&](/destination-"<> 'title-"<>&')
{class="><script>alert()</script>" id="baz"}
-- layouts/index.html --
{{ .Content }}
`
for _, enabled := range []bool{true, false} {
enabled := enabled
t.Run(fmt.Sprint(enabled), func(t *testing.T) {
t.Parallel()
b := Test(t, strings.ReplaceAll(files, "ENABLE", fmt.Sprint(enabled)))
// The escaping is slightly different between the two.
if enabled {
b.AssertFileContent("public/index.html",
"Link: <a href=\"/destination-%22%3C%3E\" title=\"title-&#34;&lt;&gt;&amp;\">text-&quot;&lt;&gt;&amp;</a>",
"img alt=\"alt-&quot;&lt;&gt;&amp;\" src=\"/destination-%22%3C%3E\" title=\"title-&#34;&lt;&gt;&amp;\">",
"&gt;&lt;script&gt;",
)
} else {
b.AssertFileContent("public/index.html",
"Link: <a href=\"/destination-%22%3C%3E\" title=\"title-&quot;&lt;&gt;&amp;\">text-&quot;&lt;&gt;&amp;</a>",
"Image: <img src=\"/destination-%22%3C%3E\" alt=\"alt-&quot;&lt;&gt;&amp;\" title=\"title-&quot;&lt;&gt;&amp;\">",
)
}
})
}
}

View file

@ -175,7 +175,7 @@ func (pco *pageContentOutput) RenderShortcodes(ctx context.Context) (template.HT
// This content will be parsed and rendered by Goldmark.
// Wrap it in a special Hugo markup to assign the correct Page from
// the stack.
c = hugocontext.Wrap(c, pco.po.p.pid)
return template.HTML(hugocontext.Wrap(c, pco.po.p.pid)), nil
}
return helpers.BytesToHTML(c), nil

View file

@ -34,7 +34,7 @@ func New() goldmark.Extender {
// Wrap wraps the given byte slice in a Hugo context that used to determine the correct Page
// in .RenderShortcodes.
func Wrap(b []byte, pid uint64) []byte {
func Wrap(b []byte, pid uint64) string {
buf := bufferpool.GetBuffer()
defer bufferpool.PutBuffer(buf)
buf.Write(prefix)
@ -45,7 +45,7 @@ func Wrap(b []byte, pid uint64) []byte {
buf.Write(b)
buf.Write(prefix)
buf.Write(closingDelimAndNewline)
return buf.Bytes()
return buf.String()
}
var kindHugoContext = ast.NewNodeKind("HugoContext")

View file

@ -24,7 +24,7 @@ func TestWrap(t *testing.T) {
b := []byte("test")
c.Assert(string(Wrap(b, 42)), qt.Equals, "{{__hugo_ctx pid=42}}\ntest{{__hugo_ctx/}}\n")
c.Assert(Wrap(b, 42), qt.Equals, "{{__hugo_ctx pid=42}}\ntest{{__hugo_ctx/}}\n")
}
func BenchmarkWrap(b *testing.B) {

View file

@ -5,7 +5,7 @@
{{- $src = .RelPermalink -}}
{{- end -}}
{{- end -}}
{{- $attributes := merge .Attributes (dict "alt" .Text "src" $src "title" .Title) -}}
{{- $attributes := merge .Attributes (dict "alt" .Text "src" $src "title" (.Title | transform.HTMLEscape)) -}}
<img
{{- range $k, $v := $attributes -}}
{{- if $v -}}

View file

@ -17,7 +17,7 @@
{{- end -}}
{{- end -}}
{{- end -}}
{{- $attributes := dict "href" $href "title" .Title -}}
{{- $attributes := dict "href" $href "title" (.Title | transform.HTMLEscape) -}}
<a
{{- range $k, $v := $attributes -}}
{{- if $v -}}

View file

@ -48,7 +48,7 @@
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} on {{ end }}{{ .Site.Title }}{{ end }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{ . }} {{ end }}{{ end }}on {{ .Site.Title }}</description>
<generator>Hugo {{ hugo.Version }}</generator>
<generator>Hugo</generator>
<language>{{ site.Language.LanguageCode }}</language>{{ with $authorEmail }}
<managingEditor>{{.}}{{ with $authorName }} ({{ . }}){{ end }}</managingEditor>{{ end }}{{ with $authorEmail }}
<webMaster>{{ . }}{{ with $authorName }} ({{ . }}){{ end }}</webMaster>{{ end }}{{ with .Site.Copyright }}

View file

@ -8,10 +8,10 @@ Renders an embedded YouTube video.
@param {int} [end] The time, measured in seconds from the start of the video, when the player should stop playing the video.
@param {string} [id] The video id. Optional if the id is provided as first positional argument.
@param {string} [loading=eager] The loading attribute of the iframe element.
@param {bool} [loop=false] Whether to indefinitely repeat the video.
@param {bool} [loop=false] Whether to indefinitely repeat the video. Ignores the start and end arguments after the first play.
@param {bool} [mute=false] Whether to mute the video. Always true when autoplay is true.
@param {int} [start] The time, measured in seconds from the start of the video, when the player should start playing the video.
@param {string} [title] The title attribute of the iframe element. Defaults to the title returned by YouTube oEmbed API.
@param {string} [title] The title attribute of the iframe element. Defaults to "YouTube video".
@returns {template.HTML}
@ -26,20 +26,6 @@ Renders an embedded YouTube video.
{{- if not $pc.Disable }}
{{- with $id := or (.Get "id") (.Get 0) }}
{{- /* Get data from the YouTube oEmbed API. */}}
{{- $q := querify "url" (printf "https://www.youtube.com/watch?v=%s" $id) "format" "json" }}
{{- $url := printf "https://www.youtube.com/oembed?%s" $q }}
{{- $data := dict }}
{{- with resources.GetRemote $url }}
{{- with .Err }}
{{- erroridf $remoteErrID "The %q shortcode was unable to get remote resource %q. %s. See %s" $.Name $url . $.Position }}
{{- else }}
{{- $data = .Content | transform.Unmarshal }}
{{- end }}
{{- else }}
{{- erroridf $remoteErrID "The %q shortcode was unable to get remote resource %q. See %s" $.Name $url $.Position }}
{{- end }}
{{/* Set defaults. */}}
{{- $allowFullScreen := "allowfullscreen" }}
{{- $autoplay := 0 }}
@ -50,7 +36,7 @@ Renders an embedded YouTube video.
{{- $loop := 0 }}
{{- $mute := 0 }}
{{- $start := 0 }}
{{- $title := $data.title }}
{{- $title := "YouTube video" }}
{{- /* Get arguments. */}}
{{- if in (slice "false" false 0) ($.Get "allowFullScreen") }}