forked from gitea/gitea
Rename Str2html to SanitizeHTML and clarify its behavior (#29516)
Str2html was abused a lot. So use a proper name for it: SanitizeHTML And add some tests to show its behavior.
This commit is contained in:
parent
cb52b17f92
commit
fb42972c05
|
@ -224,7 +224,7 @@ Please check [Gitea's logs](administration/logging-config.md) for error messages
|
||||||
{{if not (eq .Body "")}}
|
{{if not (eq .Body "")}}
|
||||||
<h3>Message content</h3>
|
<h3>Message content</h3>
|
||||||
<hr>
|
<hr>
|
||||||
{{.Body | Str2html}}
|
{{.Body | SanitizeHTML}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -260,19 +260,19 @@ The template system contains several functions that can be used to further proce
|
||||||
the messages. Here's a list of some of them:
|
the messages. Here's a list of some of them:
|
||||||
|
|
||||||
| Name | Parameters | Available | Usage |
|
| Name | Parameters | Available | Usage |
|
||||||
| ---------------- | ----------- | --------- | --------------------------------------------------------------------------- |
|
| ---------------- | ----------- | --------- |-----------------------------------------------------------------------------|
|
||||||
| `AppUrl` | - | Any | Gitea's URL |
|
| `AppUrl` | - | Any | Gitea's URL |
|
||||||
| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" |
|
| `AppName` | - | Any | Set from `app.ini`, usually "Gitea" |
|
||||||
| `AppDomain` | - | Any | Gitea's host name |
|
| `AppDomain` | - | Any | Gitea's host name |
|
||||||
| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed |
|
| `EllipsisString` | string, int | Any | Truncates a string to the specified length; adds ellipsis as needed |
|
||||||
| `Str2html` | string | Body only | Sanitizes text by removing any HTML tags from it. |
|
| `SanitizeHTML` | string | Body only | Sanitizes text by removing any dangerous HTML tags from it. |
|
||||||
| `SafeHTML` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. |
|
| `SafeHTML` | string | Body only | Takes the input as HTML; can be used for `.ReviewComments.RenderedContent`. |
|
||||||
|
|
||||||
These are _functions_, not metadata, so they have to be used:
|
These are _functions_, not metadata, so they have to be used:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
Like this: {{Str2html "Escape<my>text"}}
|
Like this: {{SanitizeHTML "Escape<my>text"}}
|
||||||
Or this: {{"Escape<my>text" | Str2html}}
|
Or this: {{"Escape<my>text" | SanitizeHTML}}
|
||||||
Or this: {{AppUrl}}
|
Or this: {{AppUrl}}
|
||||||
But not like this: {{.AppUrl}}
|
But not like this: {{.AppUrl}}
|
||||||
```
|
```
|
||||||
|
|
|
@ -207,7 +207,7 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/
|
||||||
{{if not (eq .Body "")}}
|
{{if not (eq .Body "")}}
|
||||||
<h3>消息内容:</h3>
|
<h3>消息内容:</h3>
|
||||||
<hr>
|
<hr>
|
||||||
{{.Body | Str2html}}
|
{{.Body | SanitizeHTML}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -242,20 +242,20 @@ _主题_ 和 _邮件正文_ 由 [Golang的模板引擎](https://go.dev/pkg/text/
|
||||||
|
|
||||||
模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:
|
模板系统包含一些函数,可用于进一步处理和格式化消息。以下是其中一些函数的列表:
|
||||||
|
|
||||||
| 函数名 | 参数 | 可用于 | 用法 |
|
| 函数名 | 参数 | 可用于 | 用法 |
|
||||||
|------------------| ----------- | ------------ | --------------------------------------------------------------------------------- |
|
|------------------| ----------- | ------------ |---------------------------------------------------------|
|
||||||
| `AppUrl` | - | 任何地方 | Gitea 的 URL |
|
| `AppUrl` | - | 任何地方 | Gitea 的 URL |
|
||||||
| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" |
|
| `AppName` | - | 任何地方 | 从 `app.ini` 中设置,通常为 "Gitea" |
|
||||||
| `AppDomain` | - | 任何地方 | Gitea 的主机名 |
|
| `AppDomain` | - | 任何地方 | Gitea 的主机名 |
|
||||||
| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 |
|
| `EllipsisString` | string, int | 任何地方 | 将字符串截断为指定长度;根据需要添加省略号 |
|
||||||
| `Str2html` | string | 仅正文部分 | 通过删除其中的 HTML 标签对文本进行清理 |
|
| `SanitizeHTML` | string | 仅正文部分 | 通过删除其中的危险 HTML 标签对文本进行清理 |
|
||||||
| `SafeHTML` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于 `.ReviewComments.RenderedContent` 等字段 |
|
| `SafeHTML` | string | 仅正文部分 | 将输入作为 HTML 处理;可用于 `.ReviewComments.RenderedContent` 等字段 |
|
||||||
|
|
||||||
这些都是 _函数_,而不是元数据,因此必须按以下方式使用:
|
这些都是 _函数_,而不是元数据,因此必须按以下方式使用:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
像这样使用: {{Str2html "Escape<my>text"}}
|
像这样使用: {{SanitizeHTML "Escape<my>text"}}
|
||||||
或者这样使用: {{"Escape<my>text" | Str2html}}
|
或者这样使用: {{"Escape<my>text" | SanitizeHTML}}
|
||||||
或者这样使用: {{AppUrl}}
|
或者这样使用: {{AppUrl}}
|
||||||
但不要像这样使用: {{.AppUrl}}
|
但不要像这样使用: {{.AppUrl}}
|
||||||
```
|
```
|
||||||
|
|
|
@ -33,16 +33,16 @@ func NewFuncMap() template.FuncMap {
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// html/template related functions
|
// html/template related functions
|
||||||
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
|
||||||
"Eval": Eval,
|
"Eval": Eval,
|
||||||
"SafeHTML": SafeHTML,
|
"SafeHTML": SafeHTML,
|
||||||
"HTMLFormat": HTMLFormat,
|
"HTMLFormat": HTMLFormat,
|
||||||
"HTMLEscape": HTMLEscape,
|
"HTMLEscape": HTMLEscape,
|
||||||
"QueryEscape": url.QueryEscape,
|
"QueryEscape": url.QueryEscape,
|
||||||
"JSEscape": JSEscapeSafe,
|
"JSEscape": JSEscapeSafe,
|
||||||
"Str2html": Str2html, // TODO: rename it to SanitizeHTML
|
"SanitizeHTML": SanitizeHTML,
|
||||||
"URLJoin": util.URLJoin,
|
"URLJoin": util.URLJoin,
|
||||||
"DotEscape": DotEscape,
|
"DotEscape": DotEscape,
|
||||||
|
|
||||||
"PathEscape": url.PathEscape,
|
"PathEscape": url.PathEscape,
|
||||||
"PathEscapeSegments": util.PathEscapeSegments,
|
"PathEscapeSegments": util.PathEscapeSegments,
|
||||||
|
@ -207,8 +207,8 @@ func SafeHTML(s any) template.HTML {
|
||||||
panic(fmt.Sprintf("unexpected type %T", s))
|
panic(fmt.Sprintf("unexpected type %T", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Str2html sanitizes the input by pre-defined markdown rules
|
// SanitizeHTML sanitizes the input by pre-defined markdown rules
|
||||||
func Str2html(s any) template.HTML {
|
func SanitizeHTML(s any) template.HTML {
|
||||||
switch v := s.(type) {
|
switch v := s.(type) {
|
||||||
case string:
|
case string:
|
||||||
return template.HTML(markup.Sanitize(v))
|
return template.HTML(markup.Sanitize(v))
|
||||||
|
|
|
@ -61,3 +61,8 @@ func TestJSEscapeSafe(t *testing.T) {
|
||||||
func TestHTMLFormat(t *testing.T) {
|
func TestHTMLFormat(t *testing.T) {
|
||||||
assert.Equal(t, template.HTML("<a>< < 1</a>"), HTMLFormat("<a>%s %s %d</a>", "<", template.HTML("<"), 1))
|
assert.Equal(t, template.HTML("<a>< < 1</a>"), HTMLFormat("<a>%s %s %d</a>", "<", template.HTML("<"), 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(template.HTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`)))
|
||||||
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func renderMarkdown(ctx *context.Context, act *activities_model.Action, content
|
||||||
}
|
}
|
||||||
markdown, err := markdown.RenderString(markdownCtx, content)
|
markdown, err := markdown.RenderString(markdownCtx, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return templates.Str2html(content) // old code did so: use Str2html to render in tmpl
|
return templates.SanitizeHTML(content) // old code did so: use SanitizeHTML to render in tmpl
|
||||||
}
|
}
|
||||||
return markdown
|
return markdown
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(content) == 0 {
|
if len(content) == 0 {
|
||||||
content = templates.Str2html(desc)
|
content = templates.SanitizeHTML(desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
items = append(items, &feeds.Item{
|
items = append(items, &feeds.Item{
|
||||||
|
|
|
@ -105,7 +105,7 @@ func Projects(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, project := range projects {
|
for _, project := range projects {
|
||||||
project.RenderedContent = templates.Str2html(project.Description) // FIXME: is it right? why not render?
|
project.RenderedContent = templates.SanitizeHTML(project.Description) // FIXME: is it right? why not render?
|
||||||
}
|
}
|
||||||
|
|
||||||
err = shared_user.LoadHeaderCount(ctx)
|
err = shared_user.LoadHeaderCount(ctx)
|
||||||
|
@ -396,7 +396,7 @@ func ViewProject(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
project.RenderedContent = templates.Str2html(project.Description) // FIXME: is it right? why not render?
|
project.RenderedContent = templates.SanitizeHTML(project.Description) // FIXME: is it right? why not render?
|
||||||
ctx.Data["LinkedPRs"] = linkedPrsMap
|
ctx.Data["LinkedPRs"] = linkedPrsMap
|
||||||
ctx.Data["PageIsViewProjects"] = true
|
ctx.Data["PageIsViewProjects"] = true
|
||||||
ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
|
ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
|
||||||
|
|
|
@ -1761,7 +1761,7 @@ func ViewIssue(ctx *context.Context) {
|
||||||
// so "|" is used as delimeter to mark the new format
|
// so "|" is used as delimeter to mark the new format
|
||||||
if comment.Content[0] != '|' {
|
if comment.Content[0] != '|' {
|
||||||
// handle old time comments that have formatted text stored
|
// handle old time comments that have formatted text stored
|
||||||
comment.RenderedContent = templates.Str2html(comment.Content)
|
comment.RenderedContent = templates.SanitizeHTML(comment.Content)
|
||||||
comment.Content = ""
|
comment.Content = ""
|
||||||
} else {
|
} else {
|
||||||
// else it's just a duration in seconds to pass on to the frontend
|
// else it's just a duration in seconds to pass on to the frontend
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
{{if .Flash.ErrorMsg}}
|
{{if .Flash.ErrorMsg}}
|
||||||
<div class="ui negative message flash-message flash-error">
|
<div class="ui negative message flash-message flash-error">
|
||||||
<p>{{.Flash.ErrorMsg | Str2html}}</p>
|
<p>{{.Flash.ErrorMsg | SanitizeHTML}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Flash.SuccessMsg}}
|
{{if .Flash.SuccessMsg}}
|
||||||
<div class="ui positive message flash-message flash-success">
|
<div class="ui positive message flash-message flash-success">
|
||||||
<p>{{.Flash.SuccessMsg | Str2html}}</p>
|
<p>{{.Flash.SuccessMsg | SanitizeHTML}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Flash.InfoMsg}}
|
{{if .Flash.InfoMsg}}
|
||||||
<div class="ui info message flash-message flash-info">
|
<div class="ui info message flash-message flash-info">
|
||||||
<p>{{.Flash.InfoMsg | Str2html}}</p>
|
<p>{{.Flash.InfoMsg | SanitizeHTML}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Flash.WarningMsg}}
|
{{if .Flash.WarningMsg}}
|
||||||
<div class="ui warning message flash-message flash-warning">
|
<div class="ui warning message flash-message flash-warning">
|
||||||
<p>{{.Flash.WarningMsg | Str2html}}</p>
|
<p>{{.Flash.WarningMsg | SanitizeHTML}}</p>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
<details>
|
<details>
|
||||||
<summary>{{.Summary}}</summary>
|
<summary>{{.Summary}}</summary>
|
||||||
<code>
|
<code>
|
||||||
{{.Details | Str2html}}
|
{{.Details | SanitizeHTML}}
|
||||||
</code>
|
</code>
|
||||||
</details>
|
</details>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
{{.locale.Tr "mail.issue.action.new" .Doer.Name .Issue.Index}}
|
{{.locale.Tr "mail.issue.action.new" .Doer.Name .Issue.Index}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.Body | Str2html}}
|
{{.Body | SanitizeHTML}}
|
||||||
{{end -}}
|
{{end -}}
|
||||||
{{- range .ReviewComments}}
|
{{- range .ReviewComments}}
|
||||||
<hr>
|
<hr>
|
||||||
|
|
|
@ -276,7 +276,7 @@
|
||||||
<span class="text grey" id="note-authored-time">{{TimeSince .NoteCommit.Author.When ctx.Locale}}</span>
|
<span class="text grey" id="note-authored-time">{{TimeSince .NoteCommit.Author.When ctx.Locale}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached info segment git-notes">
|
<div class="ui bottom attached info segment git-notes">
|
||||||
<pre class="commit-body">{{.NoteRendered | Str2html}}</pre>
|
<pre class="commit-body">{{.NoteRendered | SanitizeHTML}}</pre>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{template "repo/diff/box" .}}
|
{{template "repo/diff/box" .}}
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
</span>
|
</span>
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
{{svg "octicon-git-commit"}}
|
{{svg "octicon-git-commit"}}
|
||||||
<span class="text grey muted-links">{{.Content | Str2html}}</span>
|
<span class="text grey muted-links">{{.Content | SanitizeHTML}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else if eq .Type 7}}
|
{{else if eq .Type 7}}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<div class="ui list">
|
<div class="ui list">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
{{.Description | Str2html}}
|
{{.Description | SanitizeHTML}}
|
||||||
</div>
|
</div>
|
||||||
{{range .Webhooks}}
|
{{range .Webhooks}}
|
||||||
<div class="item truncated-item-container">
|
<div class="item truncated-item-container">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics.
|
{{/* This page should only depend the minimal template functions/variables, to avoid triggering new panics.
|
||||||
* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, ThemeName, Str2html
|
* base template functions: AppName, AssetUrlPrefix, AssetVersion, AppSubUrl, ThemeName, SanitizeHTML
|
||||||
* ctx.Locale
|
* ctx.Locale
|
||||||
* .Flash
|
* .Flash
|
||||||
* .ErrorMsg
|
* .ErrorMsg
|
||||||
|
|
Loading…
Reference in New Issue