package controller import ( "bytes" "strings" "golang.org/x/net/html" ) // Artwork scripts run only inside an opaque-origin sandbox. CSP blocks network // access; navigation, forms, and embedded documents are removed here. func sanitizeDetectionHTML(source string) string { root, err := html.Parse(strings.NewReader(source)) if err != nil { return "" } var walk func(*html.Node) walk = func(n *html.Node) { for child := n.FirstChild; child != nil; { next := child.NextSibling switch strings.ToLower(child.Data) { case "iframe", "frame", "frameset", "object", "embed", "base", "meta", "link", "form", "input", "textarea", "select", "audio", "video", "source", "foreignobject": if child.Type == html.ElementNode { n.RemoveChild(child) child = next continue } } if child.Type == html.ElementNode { attrs := child.Attr[:0] for _, attr := range child.Attr { name := strings.ToLower(attr.Key) value := strings.TrimSpace(attr.Val) if strings.HasPrefix(name, "on") { continue } switch name { case "href": if !strings.HasPrefix(value, "#") { continue } case "src": if child.Data != "img" || !(strings.HasPrefix(value, "data:image/png;") || strings.HasPrefix(value, "data:image/jpeg;") || strings.HasPrefix(value, "data:image/webp;")) { continue } case "srcset", "srcdoc", "action", "formaction", "ping", "target", "download", "http-equiv": continue } attrs = append(attrs, attr) } child.Attr = attrs } walk(child) child = next } } walk(root) var out bytes.Buffer if html.Render(&out, root) != nil { return "" } return out.String() }