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:
		
							parent
							
								
									8ad2697611
								
							
						
					
					
						commit
						cea8ea5ae6
					
				| 
						 | 
					@ -92,6 +92,32 @@ func getIssueFullPattern() *regexp.Regexp {
 | 
				
			||||||
	return issueFullPattern
 | 
						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
 | 
					// IsSameDomain checks if given url string has the same hostname as current Gitea instance
 | 
				
			||||||
func IsSameDomain(s string) bool {
 | 
					func IsSameDomain(s string) bool {
 | 
				
			||||||
	if strings.HasPrefix(s, "/") {
 | 
						if strings.HasPrefix(s, "/") {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,6 +89,11 @@ func TestRender_links(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Text that should be turned into URL
 | 
						// Text that should be turned into URL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defaultCustom := setting.Markdown.CustomURLSchemes
 | 
				
			||||||
 | 
						setting.Markdown.CustomURLSchemes = []string{"ftp", "magnet"}
 | 
				
			||||||
 | 
						ReplaceSanitizer()
 | 
				
			||||||
 | 
						CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	test(
 | 
						test(
 | 
				
			||||||
		"https://www.example.com",
 | 
							"https://www.example.com",
 | 
				
			||||||
		`<p><a href="https://www.example.com" rel="nofollow">https://www.example.com</a></p>`)
 | 
							`<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(
 | 
						test(
 | 
				
			||||||
		"https://username:password@gitea.com",
 | 
							"https://username:password@gitea.com",
 | 
				
			||||||
		`<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`)
 | 
							`<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 that should *not* be turned into URL
 | 
				
			||||||
	test(
 | 
						test(
 | 
				
			||||||
| 
						 | 
					@ -154,6 +165,14 @@ func TestRender_links(t *testing.T) {
 | 
				
			||||||
	test(
 | 
						test(
 | 
				
			||||||
		"www",
 | 
							"www",
 | 
				
			||||||
		`<p>www</p>`)
 | 
							`<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) {
 | 
					func TestRender_email(t *testing.T) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,12 +9,16 @@ import (
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Init initialize regexps for markdown parsing
 | 
					// Init initialize regexps for markdown parsing
 | 
				
			||||||
func Init() {
 | 
					func Init() {
 | 
				
			||||||
	getIssueFullPattern()
 | 
						getIssueFullPattern()
 | 
				
			||||||
	NewSanitizer()
 | 
						NewSanitizer()
 | 
				
			||||||
 | 
						if len(setting.Markdown.CustomURLSchemes) > 0 {
 | 
				
			||||||
 | 
							CustomLinkURLSchemes(setting.Markdown.CustomURLSchemes)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// since setting maybe changed extensions, this will reload all parser extensions mapping
 | 
						// since setting maybe changed extensions, this will reload all parser extensions mapping
 | 
				
			||||||
	extParsers = make(map[string]Parser)
 | 
						extParsers = make(map[string]Parser)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,13 @@ var sanitizer = &Sanitizer{}
 | 
				
			||||||
// entire application lifecycle.
 | 
					// entire application lifecycle.
 | 
				
			||||||
func NewSanitizer() {
 | 
					func NewSanitizer() {
 | 
				
			||||||
	sanitizer.init.Do(func() {
 | 
						sanitizer.init.Do(func() {
 | 
				
			||||||
 | 
							ReplaceSanitizer()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReplaceSanitizer replaces the current sanitizer to account for changes in settings
 | 
				
			||||||
 | 
					func ReplaceSanitizer() {
 | 
				
			||||||
 | 
						sanitizer = &Sanitizer{}
 | 
				
			||||||
	sanitizer.policy = bluemonday.UGCPolicy()
 | 
						sanitizer.policy = bluemonday.UGCPolicy()
 | 
				
			||||||
	// We only want to allow HighlightJS specific classes for code blocks
 | 
						// We only want to allow HighlightJS specific classes for code blocks
 | 
				
			||||||
	sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code")
 | 
						sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^language-\w+$`)).OnElements("code")
 | 
				
			||||||
| 
						 | 
					@ -41,7 +48,6 @@ func NewSanitizer() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Allow keyword markup
 | 
						// Allow keyword markup
 | 
				
			||||||
	sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span")
 | 
						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.
 | 
					// Sanitize takes a string that contains a HTML fragment or document and applies policy whitelist.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue