diff --git a/modules/templates/helper.go b/modules/templates/helper.go index d2fe6a28c..8e891bdc2 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -9,6 +9,7 @@ import ( "html" "html/template" "net/url" + "slices" "strings" "time" @@ -34,7 +35,8 @@ func NewFuncMap() 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. "Eval": Eval, - "Safe": Safe, + "SafeHTML": SafeHTML, + "HTMLFormat": HTMLFormat, "Escape": Escape, "QueryEscape": url.QueryEscape, "JSEscape": JSEscapeSafe, @@ -180,8 +182,25 @@ func NewFuncMap() template.FuncMap { } } -// Safe render raw as HTML -func Safe(s any) template.HTML { +func HTMLFormat(s string, rawArgs ...any) template.HTML { + args := slices.Clone(rawArgs) + for i, v := range args { + switch v := v.(type) { + case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML: + // for most basic types (including template.HTML which is safe), just do nothing and use it + case string: + args[i] = template.HTMLEscapeString(v) + case fmt.Stringer: + args[i] = template.HTMLEscapeString(v.String()) + default: + args[i] = template.HTMLEscapeString(fmt.Sprint(v)) + } + } + return template.HTML(fmt.Sprintf(s, args...)) +} + +// SafeHTML render raw as HTML +func SafeHTML(s any) template.HTML { switch v := s.(type) { case string: return template.HTML(v) diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index 739a92f34..8f5d633d4 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -4,6 +4,7 @@ package templates import ( + "html/template" "testing" "github.com/stretchr/testify/assert" @@ -56,3 +57,7 @@ func TestSubjectBodySeparator(t *testing.T) { func TestJSEscapeSafe(t *testing.T) { assert.EqualValues(t, `\u0026\u003C\u003E\'\"`, JSEscapeSafe(`&<>'"`)) } + +func TestHTMLFormat(t *testing.T) { + assert.Equal(t, template.HTML("< < 1"), HTMLFormat("%s %s %d", "<", template.HTML("<"), 1)) +} diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 04f76748d..cf860dab2 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -88,7 +88,7 @@ {{ctx.Locale.Tr "packages.settings.delete"}}
- {{ctx.Locale.Tr "packages.settings.delete.notice" (``|Safe) (``|Safe)}} + {{ctx.Locale.Tr "packages.settings.delete.notice" (``|SafeHTML) (``|SafeHTML)}}
{{template "base/modal_actions_confirm" .}} diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index c7a6ec7e4..e11247aed 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -101,7 +101,7 @@

{{ctx.Locale.Tr "repo.settings.delete_desc"}}

- {{ctx.Locale.Tr "repo.settings.delete_notices_2" (``|Safe)}}
+ {{ctx.Locale.Tr "repo.settings.delete_notices_2" (``|SafeHTML)}}
{{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}}
{{template "base/modal_actions_confirm" .}} diff --git a/templates/admin/stacktrace.tmpl b/templates/admin/stacktrace.tmpl index aa5e810cd..42944615c 100644 --- a/templates/admin/stacktrace.tmpl +++ b/templates/admin/stacktrace.tmpl @@ -39,7 +39,7 @@ {{ctx.Locale.Tr "admin.monitor.process.cancel"}}
-

{{ctx.Locale.Tr "admin.monitor.process.cancel_notices" (``|Safe)}}

+

{{ctx.Locale.Tr "admin.monitor.process.cancel_notices" (``|SafeHTML)}}

{{ctx.Locale.Tr "admin.monitor.process.cancel_desc"}}

{{template "base/modal_actions_confirm" .}} diff --git a/templates/mail/issue/assigned.tmpl b/templates/mail/issue/assigned.tmpl index e80bd2fc3..5720319ee 100644 --- a/templates/mail/issue/assigned.tmpl +++ b/templates/mail/issue/assigned.tmpl @@ -8,14 +8,14 @@ {{.Subject}} -{{$repo_url := printf "%s" (Escape .Issue.Repo.HTMLURL) (Escape .Issue.Repo.FullName)}} -{{$link := printf "#%d" (Escape .Link) .Issue.Index}} +{{$repo_url := HTMLFormat "%s" .Issue.Repo.HTMLURL .Issue.Repo.FullName}} +{{$link := HTMLFormat "#%d" .Link .Issue.Index}}

{{if .IsPull}} - {{.locale.Tr "mail.issue_assigned.pull" .Doer.Name ($link|Safe) ($repo_url|Safe)}} + {{.locale.Tr "mail.issue_assigned.pull" .Doer.Name $link $repo_url}} {{else}} - {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name ($link|Safe) ($repo_url|Safe)}} + {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name $link $repo_url}} {{end}}

-

{{ctx.Locale.Tr "org.members.leave.detail" (``|Safe)}}

+

{{ctx.Locale.Tr "org.members.leave.detail" (``|SafeHTML)}}

{{template "base/modal_actions_confirm" .}} @@ -82,7 +82,7 @@ {{ctx.Locale.Tr "org.members.remove"}}
-

{{ctx.Locale.Tr "org.members.remove.detail" (``|Safe) (``|Safe)}}

+

{{ctx.Locale.Tr "org.members.remove.detail" (``|SafeHTML) (``|SafeHTML)}}

{{template "base/modal_actions_confirm" .}} diff --git a/templates/org/team/members.tmpl b/templates/org/team/members.tmpl index dd4ece143..adaf83ae1 100644 --- a/templates/org/team/members.tmpl +++ b/templates/org/team/members.tmpl @@ -81,7 +81,7 @@ {{ctx.Locale.Tr "org.members.remove"}}
-

{{ctx.Locale.Tr "org.members.remove.detail" (``|Safe) (``|Safe)}}

+

{{ctx.Locale.Tr "org.members.remove.detail" (``|SafeHTML) (``|SafeHTML)}}

{{template "base/modal_actions_confirm" .}} diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 37550ab71..509c6382d 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -88,7 +88,7 @@ {{ctx.Locale.Tr "org.teams.leave"}}
-

{{ctx.Locale.Tr "org.teams.leave.detail" (``|Safe)}}

+

{{ctx.Locale.Tr "org.teams.leave.detail" (``|SafeHTML)}}

{{template "base/modal_actions_confirm" .}} diff --git a/templates/org/team/teams.tmpl b/templates/org/team/teams.tmpl index b518d7d9d..53c909ee9 100644 --- a/templates/org/team/teams.tmpl +++ b/templates/org/team/teams.tmpl @@ -49,7 +49,7 @@ {{ctx.Locale.Tr "org.teams.leave"}}
-

{{ctx.Locale.Tr "org.teams.leave.detail" (``|Safe)}}

+

{{ctx.Locale.Tr "org.teams.leave.detail" (``|SafeHTML)}}

{{template "base/modal_actions_confirm" .}} diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index fbfaa1941..115ee9295 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -88,7 +88,7 @@ {{.CsrfTokenHtml}}
@@ -113,7 +113,7 @@
diff --git a/templates/repo/editor/cherry_pick.tmpl b/templates/repo/editor/cherry_pick.tmpl index b65c3a303..f9c9eef5a 100644 --- a/templates/repo/editor/cherry_pick.tmpl +++ b/templates/repo/editor/cherry_pick.tmpl @@ -11,11 +11,11 @@
@@ -599,19 +599,19 @@ {{$oldProjectDisplayHtml := "Unknown Project"}} {{if .OldProject}} {{$trKey := printf "projects.type-%d.display_name" .OldProject.Type}} - {{$oldProjectDisplayHtml = printf `%s` (ctx.Locale.Tr $trKey | Escape) (.OldProject.Title | Escape)}} + {{$oldProjectDisplayHtml = HTMLFormat `%s` (ctx.Locale.Tr $trKey) .OldProject.Title}} {{end}} {{$newProjectDisplayHtml := "Unknown Project"}} {{if .Project}} {{$trKey := printf "projects.type-%d.display_name" .Project.Type}} - {{$newProjectDisplayHtml = printf `%s` (ctx.Locale.Tr $trKey | Escape) (.Project.Title | Escape)}} + {{$newProjectDisplayHtml = HTMLFormat `%s` (ctx.Locale.Tr $trKey) .Project.Title}} {{end}} {{if and (gt .OldProjectID 0) (gt .ProjectID 0)}} - {{ctx.Locale.Tr "repo.issues.change_project_at" ($oldProjectDisplayHtml|Safe) ($newProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.change_project_at" $oldProjectDisplayHtml $newProjectDisplayHtml $createdStr}} {{else if gt .OldProjectID 0}} - {{ctx.Locale.Tr "repo.issues.remove_project_at" ($oldProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.remove_project_at" $oldProjectDisplayHtml $createdStr}} {{else if gt .ProjectID 0}} - {{ctx.Locale.Tr "repo.issues.add_project_at" ($newProjectDisplayHtml|Safe) $createdStr}} + {{ctx.Locale.Tr "repo.issues.add_project_at" $newProjectDisplayHtml $createdStr}} {{end}}
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 13d49b61b..371c9db6f 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -39,7 +39,7 @@ {{ctx.Locale.Tr "repo.pulls.merged_success"}}
diff --git a/templates/repo/issue/view_title.tmpl b/templates/repo/issue/view_title.tmpl index c6c86124a..d6c814645 100644 --- a/templates/repo/issue/view_title.tmpl +++ b/templates/repo/issue/view_title.tmpl @@ -43,33 +43,33 @@ {{end}}
{{if .Issue.IsPull}} - {{$headHref := .HeadTarget|Escape}} + {{$headHref := .HeadTarget}} {{if .HeadBranchLink}} - {{$headHref = printf `%s` (.HeadBranchLink | Escape) $headHref}} + {{$headHref = HTMLFormat `%s` .HeadBranchLink $headHref}} {{end}} {{if not .MadeUsingAGit}} - {{$headHref = printf `%s ` $headHref (ctx.Locale.Tr "copy_branch") (.HeadTarget | Escape) (svg "octicon-copy" 14)}} + {{$headHref = HTMLFormat `%s ` $headHref (ctx.Locale.Tr "copy_branch") .HeadTarget (svg "octicon-copy" 14)}} {{end}} {{$baseHref := .BaseTarget|Escape}} {{if .BaseBranchLink}} - {{$baseHref = printf `%s` (.BaseBranchLink | Escape) $baseHref}} + {{$baseHref = HTMLFormat `%s` .BaseBranchLink $baseHref}} {{end}} {{if .Issue.PullRequest.HasMerged}} {{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix ctx.Locale}} {{if .Issue.OriginalAuthor}} {{.Issue.OriginalAuthor}} - {{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}} + {{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr}} {{else}} {{.Issue.PullRequest.Merger.GetDisplayName}} - {{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe) $mergedStr}} + {{ctx.Locale.Tr "repo.pulls.merged_title_desc" .NumCommits $headHref $baseHref $mergedStr}} {{end}} {{else}} {{if .Issue.OriginalAuthor}} - {{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}} + {{.Issue.OriginalAuthor}} {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}} {{else}} {{.Issue.Poster.GetDisplayName}} - {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits ($headHref|Safe) ($baseHref|Safe)}} + {{ctx.Locale.Tr "repo.pulls.title_desc" .NumCommits $headHref $baseHref}} {{end}} {{if .MadeUsingAGit}} diff --git a/templates/repo/migrate/migrate.tmpl b/templates/repo/migrate/migrate.tmpl index c686f0b83..d1abb1537 100644 --- a/templates/repo/migrate/migrate.tmpl +++ b/templates/repo/migrate/migrate.tmpl @@ -20,7 +20,7 @@ {{.Title}}
- {{(printf "repo.migrate.%s.description" .Name) | ctx.Locale.Tr}} + {{ctx.Locale.Tr (printf "repo.migrate.%s.description" .Name)}}
diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index 0aeb2af17..7f1d07e46 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -15,9 +15,9 @@ {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
{{if .IsMarkup}} - {{if .FileContent}}{{.FileContent | Safe}}{{end}} + {{if .FileContent}}{{.FileContent | SafeHTML}}{{end}} {{else if .IsPlainText}} -
{{if .FileContent}}{{.FileContent | Safe}}{{end}}
+
{{if .FileContent}}{{.FileContent | SafeHTML}}{{end}}
{{else if not .IsTextFile}}
{{if .IsImageFile}} diff --git a/templates/repo/settings/webhook/settings.tmpl b/templates/repo/settings/webhook/settings.tmpl index 8e2387067..6836e695e 100644 --- a/templates/repo/settings/webhook/settings.tmpl +++ b/templates/repo/settings/webhook/settings.tmpl @@ -263,7 +263,7 @@ {{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}} - {{ctx.Locale.Tr "repo.settings.authorization_header_desc" ("Bearer token123456, Basic YWxhZGRpbjpvcGVuc2VzYW1l" | Safe)}} + {{ctx.Locale.Tr "repo.settings.authorization_header_desc" ("Bearer token123456, Basic YWxhZGRpbjpvcGVuc2VzYW1l" | SafeHTML)}} {{end}}
diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index 5b296dc2a..f3b6be97c 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -67,13 +67,13 @@
{{if .sidebarTocContent}} {{end}}
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}} - {{.content | Safe}} + {{.content | SafeHTML}}
{{if .sidebarPresent}} @@ -82,7 +82,7 @@ {{svg "octicon-pencil"}} {{end}} {{template "repo/unicode_escape_prompt" dict "EscapeStatus" .sidebarEscapeStatus "root" $}} - {{.sidebarContent | Safe}} + {{.sidebarContent | SafeHTML}}
{{end}} @@ -94,7 +94,7 @@ {{svg "octicon-pencil"}} {{end}} {{template "repo/unicode_escape_prompt" dict "footerEscapeStatus" .sidebarEscapeStatus "root" $}} - {{.footerContent | Safe}} + {{.footerContent | SafeHTML}}
{{end}}
diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index e7eb6c818..7ce9a4b70 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -75,7 +75,7 @@ {{ctx.Locale.Tr "settings.select_permissions"}}

- {{ctx.Locale.Tr "settings.access_token_desc" (printf `href="/api/swagger" target="_blank"`) (printf `href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`) | Str2html}} + {{ctx.Locale.Tr "settings.access_token_desc" (`href="/api/swagger" target="_blank"`|SafeHTML) (`href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`|SafeHTML)}}

-

{{ctx.Locale.Tr "org.members.leave.detail" (``|Safe)}}

+

{{ctx.Locale.Tr "org.members.leave.detail" (``|SafeHTML)}}

{{template "base/modal_actions_confirm" .}}