From c5a4c07b892128f36ec4638bfd44e5404437e066 Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Sun, 15 Nov 2015 14:30:57 -0600 Subject: [PATCH] Add SafeJS template function This commit adds a SafeJS template function. Tests and documentation are included. Fixes #1579 --- docs/content/templates/functions.md | 15 +++++++++++++ tpl/template_funcs.go | 7 +++++- tpl/template_funcs_test.go | 35 +++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/docs/content/templates/functions.md b/docs/content/templates/functions.md index fc6c361e6..503702290 100644 --- a/docs/content/templates/functions.md +++ b/docs/content/templates/functions.md @@ -456,6 +456,21 @@ Example: Given `style = "color: red;"` defined in the front matter of your `.md` Note: "ZgotmplZ" is a special value that indicates that unsafe content reached a CSS or URL context. +### safeJS + +Declares the provided string as a known "safe" Javascript string so Go +html/templates will not escape it. "Safe" means the string encapsulates a known +safe EcmaScript5 Expression, for example, `(x + y * z())`. Template authors +are responsible for ensuring that typed expressions do not break the intended +precedence and that there is no statement/expression ambiguity as when passing +an expression like `{ foo:bar() }\n['foo']()`, which is both a valid Expression +and a valid Program with a very different meaning. + +Example: Given `hash = "619c16f"` defined in the front matter of your `.md` file: + +* `` ⇒ `` (Good!) +* `` ⇒ `` (Bad!) + ### singularize Singularize the given word with a set of common English singularization rules. diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go index 8b5b71a2c..283bcc829 100644 --- a/tpl/template_funcs.go +++ b/tpl/template_funcs.go @@ -14,7 +14,6 @@ package tpl import ( - "bitbucket.org/pkg/inflect" "bytes" "encoding/base64" "errors" @@ -28,6 +27,8 @@ import ( "strings" "time" + "bitbucket.org/pkg/inflect" + "github.com/spf13/cast" "github.com/spf13/hugo/helpers" jww "github.com/spf13/jwalterweatherman" @@ -1192,6 +1193,9 @@ func SafeURL(text string) template.URL { func SafeHTML(a string) template.HTML { return template.HTML(a) } +// SafeJS returns the given string as a template.JS type from html/template. +func SafeJS(a string) template.JS { return template.JS(a) } + func doArithmetic(a, b interface{}, op rune) (interface{}, error) { av := reflect.ValueOf(a) bv := reflect.ValueOf(b) @@ -1393,6 +1397,7 @@ func init() { "echoParam": ReturnWhenSet, "safeHTML": SafeHTML, "safeCSS": SafeCSS, + "safeJS": SafeJS, "safeURL": SafeURL, "absURL": func(a string) template.HTML { return template.HTML(helpers.AbsURL(a)) }, "relURL": func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) }, diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go index 9683e4595..99acfa475 100644 --- a/tpl/template_funcs_test.go +++ b/tpl/template_funcs_test.go @@ -1580,6 +1580,41 @@ func TestSafeCSS(t *testing.T) { } } +func TestSafeJS(t *testing.T) { + for i, this := range []struct { + str string + tmplStr string + expectWithoutEscape string + expectWithEscape string + }{ + {`619c16f`, ``, ``, ``}, + } { + tmpl, err := template.New("test").Parse(this.tmplStr) + if err != nil { + t.Errorf("[%d] unable to create new html template %q: %s", i, this.tmplStr, err) + continue + } + + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, this.str) + if err != nil { + t.Errorf("[%d] execute template with a raw string value returns unexpected error: %s", i, err) + } + if buf.String() != this.expectWithoutEscape { + t.Errorf("[%d] execute template with a raw string value, got %v but expected %v", i, buf.String(), this.expectWithoutEscape) + } + + buf.Reset() + err = tmpl.Execute(buf, SafeJS(this.str)) + if err != nil { + t.Errorf("[%d] execute template with an escaped string value by SafeJS returns unexpected error: %s", i, err) + } + if buf.String() != this.expectWithEscape { + t.Errorf("[%d] execute template with an escaped string value by SafeJS, got %v but expected %v", i, buf.String(), this.expectWithEscape) + } + } +} + func TestSafeURL(t *testing.T) { for i, this := range []struct { str string