From 2d333a6e0a49758c6957d5a61fe0908c2e6586f2 Mon Sep 17 00:00:00 2001 From: maddalax Date: Sat, 28 Sep 2024 20:45:27 -0500 Subject: [PATCH] escape Text input, rename Raw to UnsafeRaw --- examples/todo-list/partials/task/task.go | 6 +----- framework/h/render_test.go | 9 ++++++++- framework/h/renderer.go | 3 ++- framework/h/tag.go | 16 +++++++++++----- htmgo-site/pages/markdown.go | 2 +- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/examples/todo-list/partials/task/task.go b/examples/todo-list/partials/task/task.go index 123a707..fd55827 100644 --- a/examples/todo-list/partials/task/task.go +++ b/examples/todo-list/partials/task/task.go @@ -5,7 +5,6 @@ import ( "github.com/google/uuid" "github.com/maddalax/htmgo/framework/h" "github.com/maddalax/htmgo/framework/hx" - "github.com/microcosm-cc/bluemonday" "todolist/ent" "todolist/internal/tasks" ) @@ -18,8 +17,6 @@ const ( TabComplete Tab = "Complete" ) -var policy = bluemonday.UGCPolicy() - func getActiveTab(ctx *h.RequestContext) Tab { if tab := h.GetQueryParam(ctx, "tab"); tab != "" { return tab @@ -185,7 +182,7 @@ func CompleteIcon(task *ent.Task) *h.Element { "border-green-500": task.CompletedAt != nil, "border-slate-400": task.CompletedAt == nil, }), - h.If(task.CompletedAt != nil, h.Raw(` + h.If(task.CompletedAt != nil, h.UnsafeRaw(` @@ -290,7 +287,6 @@ func ClearCompleted(ctx *h.RequestContext) *h.Partial { func Create(ctx *h.RequestContext) *h.Partial { name := ctx.FormValue("name") - name = policy.Sanitize(name) if name == "" { return h.NewPartial(h.Div(h.Text("name is required"))) diff --git a/framework/h/render_test.go b/framework/h/render_test.go index 06555a6..3d5792f 100644 --- a/framework/h/render_test.go +++ b/framework/h/render_test.go @@ -87,7 +87,7 @@ func TestRender(t *testing.T) { func TestRawContent(t *testing.T) { t.Parallel() str := "
hello, world
" - raw := Raw(str) + raw := UnsafeRaw(str) assert.Equal(t, str, Render(raw)) } @@ -526,6 +526,13 @@ func TestBackgroundCleaner(t *testing.T) { assert.Equal(t, 0, len(node.byKeyCache)) } +func TestEscapeHtml(t *testing.T) { + t.Parallel() + assert.Equal(t, "<script>alert(1)</script>", Render(Text(""))) + assert.Equal(t, "

<script>alert(1)</script>

", Render(Pf(""))) + +} + func BenchmarkCacheByKey(b *testing.B) { b.ReportAllocs() page := CachedPerKeyT(time.Second*3, func(userId string) (any, GetElementFunc) { diff --git a/framework/h/renderer.go b/framework/h/renderer.go index f29c4db..3122da1 100644 --- a/framework/h/renderer.go +++ b/framework/h/renderer.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/maddalax/htmgo/framework/hx" "golang.org/x/net/html" + "html/template" "strings" ) @@ -167,7 +168,7 @@ func (a *AttributeR) Render(context *RenderContext) { } func (t *TextContent) Render(context *RenderContext) { - context.builder.WriteString(t.Content) + context.builder.WriteString(template.HTMLEscapeString(t.Content)) } func (r *RawContent) Render(context *RenderContext) { diff --git a/framework/h/tag.go b/framework/h/tag.go index 9fde493..76e6e85 100644 --- a/framework/h/tag.go +++ b/framework/h/tag.go @@ -123,7 +123,9 @@ func Script(url string) *Element { } } -func Raw(text string) *RawContent { +// UnsafeRaw is a helper function to create a raw content with the given text +// The text is not escaped, do not use this function with user input +func UnsafeRaw(text string) *RawContent { return NewRawContent(text) } @@ -135,12 +137,16 @@ func MultiLineQuotes(text string) string { return "`" + text + "`" } -func RawF(text string, args any) *RawContent { - return Raw(fmt.Sprintf(text, args)) +// UnsafeRawF is a helper function to create a raw content with the given text +// The text is not escaped, do not use this function with user input +func UnsafeRawF(text string, args any) *RawContent { + return UnsafeRaw(fmt.Sprintf(text, args)) } -func RawScript(text string) *RawContent { - return Raw("") +// UnsafeRawScript is a helper function to create a script tag with the given text +// The text is not escaped, do not use this function with user input +func UnsafeRawScript(text string) *RawContent { + return UnsafeRaw("") } func Pre(children ...Ren) *Element { diff --git a/htmgo-site/pages/markdown.go b/htmgo-site/pages/markdown.go index 247b128..7239048 100644 --- a/htmgo-site/pages/markdown.go +++ b/htmgo-site/pages/markdown.go @@ -23,7 +23,7 @@ func MarkdownContent(ctx *h.RequestContext, path string, id string) *h.Element { h.If(id != "", h.Id(id)), h.Div( h.Class("w-full flex flex-col prose max-w-[95vw] md:max-w-3xl prose-code:text-black prose-p:my-1 prose:p-0 prose-li:m-0 prose-ul:m-0 prose-ol:m-0"), - h.Raw(renderer.RenderFile(path, embeddedMd)), + h.UnsafeRaw(renderer.RenderFile(path, embeddedMd)), ), ) }