summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules/markup/html.go26
-rw-r--r--modules/markup/html_test.go19
-rw-r--r--modules/markup/markup.go4
-rw-r--r--modules/markup/sanitizer.go28
4 files changed, 66 insertions, 11 deletions
diff --git a/modules/markup/html.go b/modules/markup/html.go
index fc823b1f30..1ff7a41cbb 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -92,6 +92,32 @@ func getIssueFullPattern() *regexp.Regexp {
return issueFullPattern
}
+// CustomLinkURLSchemes allows for additional schemes to be detected when parsing links within text
+func CustomLinkURLSchemes(schemes []string) {
+ schemes = append(schemes, "http", "https")
+ withAuth := make([]string, 0, len(schemes))
+ validScheme := regexp.MustCompile(`^[a-z]+$`)
+ for _, s := range schemes {
+ if !validScheme.MatchString(s) {
+ continue
+ }
+ without := false
+ for _, sna := range xurls.SchemesNoAuthority {
+ if s == sna {
+ without = true
+ break
+ }
+ }
+ if without {
+ s += ":"
+ } else {
+ s += "://"
+ }
+ withAuth = append(withAuth, s)
+ }
+ linkRegex, _ = xurls.StrictMatchingScheme(strings.Join(withAuth, "|"))
+}
+
// IsSameDomain checks if given url string has the same hostname as current Gitea instance
func IsSameDomain(s string) bool {
if strings.HasPrefix(s, "/") {
diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go
index 66e56f71a7..91ef320b40 100644
--- a/modules/markup/html_test.go
+++ b/modules/markup/html_test.go
@@ -89,6 +89,11 @@ func TestRender_links(t *testing.T) {
}
// Text that should be turned into URL
+ defaultCustom := setting.Markdown.CustomURLSchemes
+ setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"}
+ ReplaceSanitizer()
+ CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
+
test(
"https://www.example.com",
`<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`)
@@ -131,6 +136,12 @@ func TestRender_links(t *testing.T) {
test(
"https://username:password@gitea.com",
`<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`)
+ test(
+ "ftp://gitea.com/file.txt",
+ `<p><a href="ftp://gitea.com/file.txt" rel="nofollow">ftp://gitea.com/file.txt</a></p>`)
+ test(
+ "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&dn=download",
+ `<p><a href="magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&amp;dn=download</a></p>`)
// Test that should *not* be turned into URL
test(
@@ -154,6 +165,14 @@ func TestRender_links(t *testing.T) {
test(
"www",
`<p>www</p>`)
+ test(
+ "ftps://gitea.com",
+ `<p>ftps://gitea.com</p>`)
+
+ // Restore previous settings
+ setting.Markdown.CustomURLSchemes = defaultCustom
+ ReplaceSanitizer()
+ CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
}
func TestRender_email(t *testing.T) {
diff --git a/modules/markup/markup.go b/modules/markup/markup.go
index dc43b533c0..008b21ab97 100644
--- a/modules/markup/markup.go
+++ b/modules/markup/markup.go
@@ -9,12 +9,16 @@ import (
"strings"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
)
// Init initialize regexps for markdown parsing
func Init() {
getIssueFullPattern()
NewSanitizer()
+ if len(setting.Markdown.CustomURLSchemes) > 0 {
+ CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
+ }
// since setting maybe changed extensions, this will reload all parser extensions mapping
extParsers = make(map[string]Parser)
diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go
index fd6f90b2ab..f873e8105e 100644
--- a/modules/markup/sanitizer.go
+++ b/modules/markup/sanitizer.go
@@ -28,20 +28,26 @@ var sanitizer = &Sanitizer{}
// entire application lifecycle.
func NewSanitizer() {
sanitizer.init.Do(func() {
- sanitizer.policy = bluemonday.UGCPolicy()
- // We only want to allow HighlightJS specific classes for code blocks
- sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code")
+ ReplaceSanitizer()
+ })
+}
- // Checkboxes
- sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
- sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input")
+// ReplaceSanitizer replaces the current sanitizer to account for changes in settings
+func ReplaceSanitizer() {
+ sanitizer = &Sanitizer{}
+ sanitizer.policy = bluemonday.UGCPolicy()
+ // We only want to allow HighlightJS specific classes for code blocks
+ sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code")
- // Custom URL-Schemes
- sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
+ // Checkboxes
+ sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
+ sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input")
- // Allow keyword markup
- sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span")
- })
+ // Custom URL-Schemes
+ sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
+
+ // Allow keyword markup
+ sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span")
}
// Sanitize takes a string that contains a HTML fragment or document and applies policy whitelist.