feat(breakwater): Markdown renderer and HTML sanitizer with the forum policy (D-17)
- modules/breakwater exports Render(markdown) and Purify(html): goldmark GFM in its default safe mode (raw HTML stripped, unsafe links dropped), then a named bluemonday policy built from NewPolicy, not the UGC preset - the policy is the PHP golem15/forum HTMLPurifier config 1:1: the fixed element list, a[href|rel|target], http/https/mailto only, rel=nofollow on every link, target=_blank plus noopener on fully-qualified links - tests cover the PHP ForumMarkdownRenderTest corpus, links per scheme, blank input, the Purify allow-list and concurrent use; testable examples feed the docs page snippets - module README, root module table row, introduction.md Utilities row and docs/services/markdown.md (which gate serves user content vs admin fields) - go.mod and go.sum unchanged: bluemonday v1.0.27 and goldmark v1.8.6 were already pinned
This commit is contained in:
25
modules/breakwater/example_test.go
Normal file
25
modules/breakwater/example_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package breakwater_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/breakwater"
|
||||
)
|
||||
|
||||
func ExampleRender() {
|
||||
// A forum post: store the rendered HTML on write and serve it as is.
|
||||
post := "See [the docs](https://example.com/docs) and <b onclick=\"x()\">this</b>.\n\n<script>alert(1)</script>"
|
||||
html := breakwater.Render(post)
|
||||
fmt.Println(html)
|
||||
// Output:
|
||||
// <p>See <a href="https://example.com/docs" rel="nofollow noopener" target="_blank">the docs</a> and this.</p>
|
||||
}
|
||||
|
||||
func ExamplePurify() {
|
||||
// Content stored as HTML: the same allow-list, no Markdown pass.
|
||||
stored := `<p onclick="x()">Hi <b>there</b><img src="a.jpg"></p><a href="tel:+48">call</a>`
|
||||
clean := breakwater.Purify(stored)
|
||||
fmt.Println(clean)
|
||||
// Output:
|
||||
// <p>Hi <b>there</b></p>call
|
||||
}
|
||||
Reference in New Issue
Block a user