Add to html button in markdown type="button" (#10520)

This is for preventing that a markdown button is recognized as button for submission in a html form.

Buttons can't be stripped from the markdown due to: https://codeberg.org/forgejo/forgejo/pulls/7670#issuecomment-4086608

There is no issue with buttons if they always have `type="button"`, so this should be fine.

This is a "follow-up" to !7670.

Fixes #7656

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10520
Reviewed-by: Otto <otto@codeberg.org>
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Co-committed-by: Beowulf <beowulf@beocode.eu>
This commit is contained in:
Beowulf 2025-12-21 05:21:27 +01:00 committed by Gusted
parent e04ae29d0d
commit d436de90b1
5 changed files with 97 additions and 1 deletions

View file

@ -1,4 +1,5 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package markdown
@ -87,6 +88,8 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
if scope, found := ctx.Metas["scope"]; found {
v.Name = fmt.Appendf(v.Name, "-%s", scope)
}
case *ast.RawHTML:
g.transformRawHTML(ctx, v, reader)
}
return ast.WalkContinue, nil
})

View file

@ -1,4 +1,5 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package markdown_test
@ -125,6 +126,32 @@ func TestRender_Images(t *testing.T) {
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
}
func TestRender_Buttons(t *testing.T) {
setting.AppURL = AppURL
test := func(input, expected string) {
buffer, err := markdown.RenderString(&markup.RenderContext{
Ctx: git.DefaultContext,
Links: markup.Links{
Base: FullURL,
},
}, input)
require.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer)))
}
test(
"<button>Test</button>",
`<p><button type="button">Test</button></p>`)
test(
`<button class="toggle-escape-button btn interact-bg">Test</button>`,
`<p><button type="button" class="toggle-escape-button btn interact-bg">Test</button></p>`)
test(
`<button type="submit" class="toggle-escape-button btn interact-bg">Test</button>`,
`<p><button type="button" class="toggle-escape-button btn interact-bg">Test</button></p>`)
}
func testAnswers(baseURLContent, baseURLImages string) []string {
return []string{
`<p>Wiki! Enjoy :)</p>

View file

@ -0,0 +1,28 @@
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package markdown
import (
"strings"
"forgejo.org/modules/markup"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/text"
)
func (g *ASTTransformer) addTypeToButton(v *ast.RawHTML, segment string) {
segment = strings.TrimPrefix(segment, "<button")
newTag := ast.NewString([]byte(`<button type="button"` + segment))
newTag.SetCode(true)
v.Parent().ReplaceChild(v.Parent(), v, newTag)
}
func (g *ASTTransformer) transformRawHTML(_ *markup.RenderContext, v *ast.RawHTML, reader text.Reader) {
segment := string(v.Segments.Value(reader.Source()))
if strings.HasPrefix(segment, "<button") {
g.addTypeToButton(v, segment)
}
}

View file

@ -1,5 +1,6 @@
// Copyright 2017 The Gitea Authors. All rights reserved.
// Copyright 2017 The Gogs Authors. All rights reserved.
// Copyright 2017 The Gitea Authors. All rights reserved.
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package markup
@ -78,6 +79,9 @@ func createDefaultPolicy() *bluemonday.Policy {
policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input")
// Buttons
policy.AllowAttrs("type").Matching(regexp.MustCompile(`^button$`)).OnElements("button")
// Custom URL-Schemes
if len(setting.Markdown.CustomURLSchemes) > 0 {
policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)