I'm loading a text file that has newlines in it, and pass it to html/templates
.
Substituting the \n
with <br>
in the loaded string, they are escaped by the template to html <br>
and displayed in the browser, instead of causing a line return.
How can I change this behavior without switching to text/templates
(which doesn't have XSS protection)?
The accepted answer can easily be turned into a custom template function:
func replaceNewline(s string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>", -1))
}
Add it with func (*Template) Funcs
Example
package main
import (
"html/template"
"os"
"strings"
)
const page = `<!DOCTYPE html>
<html>
<body>
<p>{{. | replaceNewline}}</p>
</body>
</html>`
const text = `first line
<script>dangerous</script>
last line`
func main() {
t := template.Must(template.New("page").Funcs(template.FuncMap{
"replaceNewline": func(s string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>", -1))
},
}).Parse(page))
t.Execute(os.Stdout, text)
}
Output
<!DOCTYPE html>
<html>
<body>
<p>first line<br><script>dangerous</script><br>last line</p>
</body>
</html>
Go Playground
It seems you could run template.HTMLEscape() on your text first to sanitize it, then do the \n to
substitution that you trust, then use that as pre-escaped and trusted template data.
Update: Expanding on Kocka's example, this is what I had in mind:
package main
import (
"html/template"
"os"
"strings"
)
const page = `<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>{{.}}</p>
</body>
</html>`
const text = `first line
<script>dangerous</script>
last line`
func main() {
t := template.Must(template.New("page").Parse(page))
safe := template.HTMLEscapeString(text)
safe = strings.Replace(safe, "\n", "<br>", -1)
t.Execute(os.Stdout, template.HTML(safe)) // template.HTML encapsulates a known safe HTML document fragment.
}
http://play.golang.org/p/JiH0uD5Zh2
Output is
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>first line<br><script>dangerous</script><br>last line</p>
</body>
</html>
And text rendered in the browser is
first line
<script>dangerous</script>
last line
Not sure where you're substituting \n
for <br>
but if it's in go, you can cast the string as template.HTML
so it's not escaped.
See: http://golang.org/pkg/html/template/#HTML
If it's in a template, there should be a pipeline available, {{. | html}}
You can do it like this:
package main
import (
"html/template"
"os"
)
const page = `<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>{{.}}</p>
</body>
</html>`
func main() {
t := template.Must(template.New("page").Parse(page))
t.Execute(os.Stdout, template.HTML("<br>"))
}
Try it out!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With