escape Text input, rename Raw to UnsafeRaw

This commit is contained in:
maddalax 2024-09-28 20:45:27 -05:00
parent 4d95e21316
commit 2d333a6e0a
5 changed files with 23 additions and 13 deletions

View file

@ -5,7 +5,6 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/maddalax/htmgo/framework/h" "github.com/maddalax/htmgo/framework/h"
"github.com/maddalax/htmgo/framework/hx" "github.com/maddalax/htmgo/framework/hx"
"github.com/microcosm-cc/bluemonday"
"todolist/ent" "todolist/ent"
"todolist/internal/tasks" "todolist/internal/tasks"
) )
@ -18,8 +17,6 @@ const (
TabComplete Tab = "Complete" TabComplete Tab = "Complete"
) )
var policy = bluemonday.UGCPolicy()
func getActiveTab(ctx *h.RequestContext) Tab { func getActiveTab(ctx *h.RequestContext) Tab {
if tab := h.GetQueryParam(ctx, "tab"); tab != "" { if tab := h.GetQueryParam(ctx, "tab"); tab != "" {
return tab return tab
@ -185,7 +182,7 @@ func CompleteIcon(task *ent.Task) *h.Element {
"border-green-500": task.CompletedAt != nil, "border-green-500": task.CompletedAt != nil,
"border-slate-400": task.CompletedAt == nil, "border-slate-400": task.CompletedAt == nil,
}), }),
h.If(task.CompletedAt != nil, h.Raw(` h.If(task.CompletedAt != nil, h.UnsafeRaw(`
<svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <svg class="w-6 h-6 text-green-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"></path> <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"></path>
</svg> </svg>
@ -290,7 +287,6 @@ func ClearCompleted(ctx *h.RequestContext) *h.Partial {
func Create(ctx *h.RequestContext) *h.Partial { func Create(ctx *h.RequestContext) *h.Partial {
name := ctx.FormValue("name") name := ctx.FormValue("name")
name = policy.Sanitize(name)
if name == "" { if name == "" {
return h.NewPartial(h.Div(h.Text("name is required"))) return h.NewPartial(h.Div(h.Text("name is required")))

View file

@ -87,7 +87,7 @@ func TestRender(t *testing.T) {
func TestRawContent(t *testing.T) { func TestRawContent(t *testing.T) {
t.Parallel() t.Parallel()
str := "<div>hello, world</div>" str := "<div>hello, world</div>"
raw := Raw(str) raw := UnsafeRaw(str)
assert.Equal(t, str, Render(raw)) assert.Equal(t, str, Render(raw))
} }
@ -526,6 +526,13 @@ func TestBackgroundCleaner(t *testing.T) {
assert.Equal(t, 0, len(node.byKeyCache)) assert.Equal(t, 0, len(node.byKeyCache))
} }
func TestEscapeHtml(t *testing.T) {
t.Parallel()
assert.Equal(t, "&lt;script&gt;alert(1)&lt;/script&gt;", Render(Text("<script>alert(1)</script>")))
assert.Equal(t, "<p >&lt;script&gt;alert(1)&lt;/script&gt;</p>", Render(Pf("<script>alert(1)</script>")))
}
func BenchmarkCacheByKey(b *testing.B) { func BenchmarkCacheByKey(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
page := CachedPerKeyT(time.Second*3, func(userId string) (any, GetElementFunc) { page := CachedPerKeyT(time.Second*3, func(userId string) (any, GetElementFunc) {

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/maddalax/htmgo/framework/hx" "github.com/maddalax/htmgo/framework/hx"
"golang.org/x/net/html" "golang.org/x/net/html"
"html/template"
"strings" "strings"
) )
@ -167,7 +168,7 @@ func (a *AttributeR) Render(context *RenderContext) {
} }
func (t *TextContent) 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) { func (r *RawContent) Render(context *RenderContext) {

View file

@ -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) return NewRawContent(text)
} }
@ -135,12 +137,16 @@ func MultiLineQuotes(text string) string {
return "`" + text + "`" return "`" + text + "`"
} }
func RawF(text string, args any) *RawContent { // UnsafeRawF is a helper function to create a raw content with the given text
return Raw(fmt.Sprintf(text, args)) // 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 { // UnsafeRawScript is a helper function to create a script tag with the given text
return Raw("<script>" + text + "</script>") // The text is not escaped, do not use this function with user input
func UnsafeRawScript(text string) *RawContent {
return UnsafeRaw("<script>" + text + "</script>")
} }
func Pre(children ...Ren) *Element { func Pre(children ...Ren) *Element {

View file

@ -23,7 +23,7 @@ func MarkdownContent(ctx *h.RequestContext, path string, id string) *h.Element {
h.If(id != "", h.Id(id)), h.If(id != "", h.Id(id)),
h.Div( 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.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)),
), ),
) )
} }