mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-18 05:20:50 +00:00
Refactor flash message and remove SanitizeHTML template func (#37179)
1. Fix the "flash message" layout problem for different cases * I am sure most of the users should have ever seen the ugly center-aligned error message with multiple lines. 2. Fix inconsistent "Details" flash message EOL handling, sometimes `\n`, sometimes `<br>` * Now, always use "\n" and use `<pre>` to render 3. Remove SanitizeHTML template func because it is not useful and can be easily abused. * But it is still kept for mail templates, for example: https://github.com/go-gitea/gitea/issues/36049 4. Clarify PostProcessCommitMessage's behavior and add FIXME comment By the way: cleaned up some devtest pages, move embedded style block to CSS file
This commit is contained in:
@@ -6,6 +6,7 @@ package markup
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"regexp"
|
||||
"slices"
|
||||
@@ -149,9 +150,9 @@ func PostProcessDefault(ctx *RenderContext, input io.Reader, output io.Writer) e
|
||||
return postProcess(ctx, procs, input, output)
|
||||
}
|
||||
|
||||
// PostProcessCommitMessage will use the same logic as PostProcess, but will disable
|
||||
// the shortLinkProcessor.
|
||||
func PostProcessCommitMessage(ctx *RenderContext, content string) (string, error) {
|
||||
// PostProcessCommitMessage will use the same logic as PostProcess, but will disable the shortLinkProcessor.
|
||||
// FIXME: this function and its family have a very strange design: it takes HTML as input and output, processes the "escaped" content.
|
||||
func PostProcessCommitMessage(ctx *RenderContext, content template.HTML) (template.HTML, error) {
|
||||
procs := []processor{
|
||||
fullIssuePatternProcessor,
|
||||
comparePatternProcessor,
|
||||
@@ -165,7 +166,8 @@ func PostProcessCommitMessage(ctx *RenderContext, content string) (string, error
|
||||
emojiProcessor,
|
||||
emojiShortCodeProcessor,
|
||||
}
|
||||
return postProcessString(ctx, procs, content)
|
||||
s, err := postProcessString(ctx, procs, string(content))
|
||||
return template.HTML(s), err
|
||||
}
|
||||
|
||||
var emojiProcessors = []processor{
|
||||
|
||||
@@ -32,13 +32,12 @@ func newFuncMapWebPage() template.FuncMap {
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// html/template related functions
|
||||
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
||||
"Iif": iif,
|
||||
"Eval": evalTokens,
|
||||
"HTMLFormat": htmlFormat,
|
||||
"QueryEscape": queryEscape,
|
||||
"QueryBuild": QueryBuild,
|
||||
"SanitizeHTML": SanitizeHTML,
|
||||
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
||||
"Iif": iif,
|
||||
"Eval": evalTokens,
|
||||
"HTMLFormat": htmlFormat,
|
||||
"QueryEscape": queryEscape,
|
||||
"QueryBuild": QueryBuild,
|
||||
|
||||
"PathEscape": url.PathEscape,
|
||||
"PathEscapeSegments": util.PathEscapeSegments,
|
||||
@@ -146,9 +145,8 @@ func newFuncMapWebPage() template.FuncMap {
|
||||
}
|
||||
}
|
||||
|
||||
// SanitizeHTML sanitizes the input by default sanitization rules.
|
||||
func SanitizeHTML(s string) template.HTML {
|
||||
return markup.Sanitize(s)
|
||||
func sanitizeHTML(msg string) template.HTML {
|
||||
return markup.Sanitize(msg)
|
||||
}
|
||||
|
||||
func htmlFormat(s any, args ...any) template.HTML {
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestSubjectBodySeparator(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSanitizeHTML(t *testing.T) {
|
||||
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`))
|
||||
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), sanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`))
|
||||
}
|
||||
|
||||
func TestTemplateIif(t *testing.T) {
|
||||
|
||||
@@ -65,13 +65,16 @@ func mailBodyFuncMap() template.FuncMap {
|
||||
"NIL": func() any { return nil },
|
||||
|
||||
// html/template related functions
|
||||
"dict": dict,
|
||||
"Iif": iif,
|
||||
"Eval": evalTokens,
|
||||
"HTMLFormat": htmlFormat,
|
||||
"QueryEscape": queryEscape,
|
||||
"QueryBuild": QueryBuild,
|
||||
"SanitizeHTML": SanitizeHTML,
|
||||
"dict": dict,
|
||||
"Iif": iif,
|
||||
"Eval": evalTokens,
|
||||
"HTMLFormat": htmlFormat,
|
||||
"QueryEscape": queryEscape,
|
||||
"QueryBuild": QueryBuild,
|
||||
|
||||
// deprecated, use "HTMLFormat" instead, but some user custom mail templates still use it
|
||||
// see: https://github.com/go-gitea/gitea/issues/36049
|
||||
"SanitizeHTML": sanitizeHTML,
|
||||
|
||||
"PathEscape": url.PathEscape,
|
||||
"PathEscapeSegments": util.PathEscapeSegments,
|
||||
|
||||
@@ -40,7 +40,7 @@ func NewRenderUtils(ctx reqctx.RequestContext) *RenderUtils {
|
||||
|
||||
// RenderCommitMessage renders commit message with XSS-safe and special links.
|
||||
func (ut *RenderUtils) RenderCommitMessage(msg string, repo *repo.Repository) template.HTML {
|
||||
cleanMsg := template.HTMLEscapeString(msg)
|
||||
cleanMsg := template.HTML(template.HTMLEscapeString(msg))
|
||||
// we can safely assume that it will not return any error, since there shouldn't be any special HTML.
|
||||
// "repo" can be nil when rendering commit messages for deleted repositories in a user's dashboard feed.
|
||||
fullMessage, err := markup.PostProcessCommitMessage(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), cleanMsg)
|
||||
@@ -48,7 +48,7 @@ func (ut *RenderUtils) RenderCommitMessage(msg string, repo *repo.Repository) te
|
||||
log.Error("PostProcessCommitMessage: %v", err)
|
||||
return ""
|
||||
}
|
||||
msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
|
||||
msgLines := strings.Split(strings.TrimSpace(string(fullMessage)), "\n")
|
||||
if len(msgLines) == 0 {
|
||||
return ""
|
||||
}
|
||||
@@ -91,12 +91,14 @@ func (ut *RenderUtils) RenderCommitBody(msg string, repo *repo.Repository) templ
|
||||
return ""
|
||||
}
|
||||
|
||||
renderedMessage, err := markup.PostProcessCommitMessage(renderhelper.NewRenderContextRepoComment(ut.ctx, repo), template.HTMLEscapeString(msgLine))
|
||||
rctx := renderhelper.NewRenderContextRepoComment(ut.ctx, repo)
|
||||
htmlContent := template.HTML(template.HTMLEscapeString(msgLine))
|
||||
renderedMessage, err := markup.PostProcessCommitMessage(rctx, htmlContent)
|
||||
if err != nil {
|
||||
log.Error("PostProcessCommitMessage: %v", err)
|
||||
return ""
|
||||
}
|
||||
return template.HTML(renderedMessage)
|
||||
return renderedMessage
|
||||
}
|
||||
|
||||
// Match text that is between back ticks.
|
||||
@@ -279,6 +281,35 @@ func (ut *RenderUtils) RenderThemeItem(info *webtheme.ThemeMetaInfo, iconSize in
|
||||
return htmlutil.HTMLFormat(`<div class="theme-menu-item" data-tooltip-content="%s">%s %s %s</div>`, info.GetDescription(), icon, info.DisplayName, extraIcon)
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderFlashMessage(typ, msg string) template.HTML {
|
||||
msg = strings.TrimSpace(msg)
|
||||
if msg == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
cls := typ
|
||||
// legacy logic: "negative" for error, "positive" for success
|
||||
switch cls {
|
||||
case "error":
|
||||
cls = "negative"
|
||||
case "success":
|
||||
cls = "positive"
|
||||
}
|
||||
|
||||
var msgContent template.HTML
|
||||
if strings.Contains(msg, "</pre>") || strings.Contains(msg, "</details>") || strings.Contains(msg, "</ul>") || strings.Contains(msg, "</div>") {
|
||||
// If the message contains some known "block" elements, no need to do more alignment or line-break processing, just sanitize it directly.
|
||||
msgContent = sanitizeHTML(msg)
|
||||
} else if !strings.Contains(msg, "\n") {
|
||||
// If the message is a single line, center-align it by wrapping it
|
||||
msgContent = htmlutil.HTMLFormat(`<div class="tw-text-center">%s</div>`, sanitizeHTML(msg))
|
||||
} else {
|
||||
// For a multi-line message, preserve line breaks, and left-align it.
|
||||
msgContent = htmlutil.HTMLFormat(`%s`, sanitizeHTML(strings.ReplaceAll(msg, "\n", "<br>")))
|
||||
}
|
||||
return htmlutil.HTMLFormat(`<div class="ui %s message flash-message flash-%s">%s</div>`, cls, typ, msgContent)
|
||||
}
|
||||
|
||||
func (ut *RenderUtils) RenderUnicodeEscapeToggleButton(escapeStatus *charset.EscapeStatus) template.HTML {
|
||||
if escapeStatus == nil || !escapeStatus.Escaped {
|
||||
return ""
|
||||
|
||||
Reference in New Issue
Block a user