diff --git a/main.go b/main.go index 3954fbf..c618205 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,62 @@ import ( "golang.org/x/net/html" ) +// sanitizeHTML filters the input, allowing only and tags with "style" and "onload" attributes. +func sanitizeHTML(input string) string { + doc, err := html.Parse(strings.NewReader(input)) + if err != nil { + return "" + } + + var buf bytes.Buffer + processNode(&buf, doc) + str := buf.String() + cleaned := strings.ReplaceAll(str, "onreadystatechange", "") + + return cleaned +} + +// processNode recursively processes nodes, allowing only specific elements and attributes. +func processNode(buf *bytes.Buffer, n *html.Node) { + if n.Type == html.ElementNode { + if n.Data != "img" && n.Data != "a" { + // Skip non-allowed tags but still process children + for c := n.FirstChild; c != nil; c = c.NextSibling { + processNode(buf, c) + } + return + } + + // Start tag + buf.WriteString("<" + n.Data) + + // Filter attributes + for _, attr := range n.Attr { + if attr.Key == "onerror" || attr.Key == "src" || attr.Key == "href" { + buf.WriteString(fmt.Sprintf(` %s="%s"`, attr.Key, attr.Val)) + } + } + + buf.WriteString(">") + + // Process child nodes (for which can have text) + for c := n.FirstChild; c != nil; c = c.NextSibling { + processNode(buf, c) + } + + // Close tag + buf.WriteString("") + } else if n.Type == html.TextNode { + // Preserve text inside tags + buf.WriteString(n.Data) + } + + // Process other children + for c := n.FirstChild; c != nil; c = c.NextSibling { + processNode(buf, c) + } +} + type User struct { ID int Name string @@ -117,62 +173,6 @@ func getHeros(username string) []string { return heros } -// sanitizeHTML filters the input, allowing only and tags with "style" and "onload" attributes. -func sanitizeHTML(input string) string { - doc, err := html.Parse(strings.NewReader(input)) - if err != nil { - return "" - } - - var buf bytes.Buffer - processNode(&buf, doc) - str := buf.String() - cleaned := strings.ReplaceAll(str, "onreadystatechange", "") - - return cleaned -} - -// processNode recursively processes nodes, allowing only specific elements and attributes. -func processNode(buf *bytes.Buffer, n *html.Node) { - if n.Type == html.ElementNode { - if n.Data != "img" && n.Data != "a" { - // Skip non-allowed tags but still process children - for c := n.FirstChild; c != nil; c = c.NextSibling { - processNode(buf, c) - } - return - } - - // Start tag - buf.WriteString("<" + n.Data) - - // Filter attributes - for _, attr := range n.Attr { - if attr.Key == "onerror" || attr.Key == "src" || attr.Key == "href" { - buf.WriteString(fmt.Sprintf(` %s="%s"`, attr.Key, attr.Val)) - } - } - - buf.WriteString(">") - - // Process child nodes (for which can have text) - for c := n.FirstChild; c != nil; c = c.NextSibling { - processNode(buf, c) - } - - // Close tag - buf.WriteString("") - } else if n.Type == html.TextNode { - // Preserve text inside tags - buf.WriteString(n.Data) - } - - // Process other children - for c := n.FirstChild; c != nil; c = c.NextSibling { - processNode(buf, c) - } -} - func addPost(w http.ResponseWriter, r *http.Request) { user := getUser(r) if user == nil {