package classes import ( "bytes" "fmt" "regexp" "strings" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer/html" ) var ( markdownEngine = goldmark.New( goldmark.WithExtensions(extension.Footnote, extension.Table), goldmark.WithParserOptions(parser.WithAttribute()), // Winter's Markdown::parse passes raw HTML through, so imported HTML // bodies round-trip unchanged (D-03, PHP parity); rejectUnsafe gates // the rendered result on every write path. goldmark.WithRendererOptions(html.WithUnsafe()), ) markdownUnsafeTag = regexp.MustCompile(`(?i)<(?:script|iframe|object|embed)\b`) markdownEventHandler = regexp.MustCompile(`(?i)\son[a-z]+\s*=`) markdownDangerousURL = regexp.MustCompile(`(?i)(?:javascript|vbscript|data):`) ) // FormatHTML converts journal post markdown to stored HTML using goldmark // footnote, table, and attribute extensions. Raw HTML in the source passes // through unchanged; the result then goes through the same rejectUnsafe gate // as cabana.RenderMarkdown. It does not call cabana.RenderMarkdown, whose // admin preview stays without unsafe HTML. func FormatHTML(src string) (string, error) { var buf bytes.Buffer if err := markdownEngine.Convert([]byte(strings.TrimSpace(src)), &buf); err != nil { return "", fmt.Errorf("journal: markdown: %w", err) } out := buf.String() if err := rejectUnsafe(out); err != nil { return "", err } return out, nil } // CheckHTML applies the FormatHTML safety gate to HTML that is stored as is, // such as category content. It refuses raw script, iframe, object and embed // tags, event handler attributes and javascript, vbscript or data URL schemes. func CheckHTML(doc string) error { return rejectUnsafe(doc) } func rejectUnsafe(doc string) error { if markdownUnsafeTag.MatchString(doc) { return fmt.Errorf("journal: rendered HTML contains raw unsafe tags") } if markdownEventHandler.MatchString(doc) { return fmt.Errorf("journal: rendered HTML contains event handlers") } if markdownDangerousURL.MatchString(doc) { return fmt.Errorf("journal: rendered HTML contains a dangerous URL scheme") } return nil }