mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Support inline rendering of CUSTOM_URL_SCHEMES (#8496)
* Support inline rendering of CUSTOM_URL_SCHEMES * Fix lint * Add tests * Fix lint
This commit is contained in:
		@@ -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, "/") {
 | 
			
		||||
 
 | 
			
		||||
@@ -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&dn=download" rel="nofollow">magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcadabcde&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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,13 @@ var sanitizer = &Sanitizer{}
 | 
			
		||||
// entire application lifecycle.
 | 
			
		||||
func NewSanitizer() {
 | 
			
		||||
	sanitizer.init.Do(func() {
 | 
			
		||||
		ReplaceSanitizer()
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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")
 | 
			
		||||
@@ -41,7 +48,6 @@ func NewSanitizer() {
 | 
			
		||||
 | 
			
		||||
	// 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.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user