Commit 3eb41fbe authored by Mike Samuel's avatar Mike Samuel

exp/template/html: render templates unusable when escaping fails

This moots a caveat in the proposed package documentation by
rendering useless any template that could not be escaped.

From https://golang.org/cl/4969078/
> If EscapeSet returns an error, do not Execute the set; it is not
> safe against injection.
r: [but isn't the returned set nil? i guess you don't overwrite the
r: original if there's a problem, but i think you're in your rights to
r: do so]

R=r
CC=golang-dev
https://golang.org/cl/5020043
parent 5c303259
......@@ -19,7 +19,6 @@ that will be passed to Execute.
If successful, set will now be injection-safe. Otherwise, the returned set will
be nil and an error, described below, will explain the problem.
If an error is returned, do not use the original set; it is insecure.
The template names do not need to include helper templates but should include
all names x used thus:
......
......@@ -28,10 +28,10 @@ func Escape(t *template.Template) (*template.Template, os.Error) {
// EscapeSet rewrites the template set to guarantee that the output of any of
// the named templates is properly escaped.
// Names should include the names of all templates that might be called but
// need not include helper templates only called by top-level templates.
// If nil is returned, then the templates have been modified. Otherwise no
// changes were made.
// Names should include the names of all templates that might be Executed but
// need not include helper templates.
// If no error is returned, then the named templates have been modified.
// Otherwise the named templates have been rendered unusable.
func EscapeSet(s *template.Set, names ...string) (*template.Set, os.Error) {
if len(names) == 0 {
// TODO: Maybe add a method to Set to enumerate template names
......@@ -48,11 +48,20 @@ func EscapeSet(s *template.Set, names ...string) (*template.Set, os.Error) {
}
for _, name := range names {
c, _ := e.escapeTree(context{}, name, 0)
var err os.Error
if c.errStr != "" {
return nil, fmt.Errorf("%s:%d: %s", name, c.errLine, c.errStr)
err = fmt.Errorf("%s:%d: %s", name, c.errLine, c.errStr)
} else if c.state != stateText {
err = fmt.Errorf("%s ends in a non-text context: %v", name, c)
}
if c.state != stateText {
return nil, fmt.Errorf("%s ends in a non-text context: %v", name, c)
if err != nil {
// Prevent execution of unsafe templates.
for _, name := range names {
if t := s.Template(name); t != nil {
t.Tree = nil
}
}
return nil, err
}
}
e.commit()
......
......@@ -1148,3 +1148,32 @@ func TestEnsurePipelineContains(t *testing.T) {
}
}
}
func expectExecuteFailure(t *testing.T, b *bytes.Buffer) {
if x := recover(); x != nil {
if b.Len() != 0 {
t.Errorf("output on buffer: %q", b.String())
}
} else {
t.Errorf("unescaped template executed")
}
}
func TestEscapeErrorsNotIgnorable(t *testing.T) {
var b bytes.Buffer
tmpl := template.Must(template.New("dangerous").Parse("<a"))
Escape(tmpl)
defer expectExecuteFailure(t, &b)
tmpl.Execute(&b, nil)
}
func TestEscapeSetErrorsNotIgnorable(t *testing.T) {
s, err := (&template.Set{}).Parse(`{{define "t"}}<a{{end}}`)
if err != nil {
t.Error("failed to parse set: %q", err)
}
EscapeSet(s, "t")
var b bytes.Buffer
defer expectExecuteFailure(t, &b)
s.Execute(&b, "t", nil)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment