Skip to content

Commit

Permalink
Better support for linkable elements that aren't by default safe
Browse files Browse the repository at this point in the history
  • Loading branch information
buro9 committed Jun 12, 2021
1 parent aea9941 commit cb61469
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 6 deletions.
18 changes: 12 additions & 6 deletions sanitize.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ func (p *Policy) sanitizeAttrs(
tmpAttrs := []html.Attribute{}
for _, htmlAttr := range cleanAttrs {
switch elementName {
case "a", "area", "link":
case "a", "area", "base", "link":
if htmlAttr.Key == "href" {
if u, ok := p.validURL(htmlAttr.Val); ok {
htmlAttr.Val = u
Expand All @@ -546,7 +546,7 @@ func (p *Policy) sanitizeAttrs(
break
}
tmpAttrs = append(tmpAttrs, htmlAttr)
case "blockquote", "q":
case "blockquote", "del", "ins", "q":
if htmlAttr.Key == "cite" {
if u, ok := p.validURL(htmlAttr.Val); ok {
htmlAttr.Val = u
Expand All @@ -555,7 +555,7 @@ func (p *Policy) sanitizeAttrs(
break
}
tmpAttrs = append(tmpAttrs, htmlAttr)
case "img", "script":
case "audio", "embed", "iframe", "img", "script", "source", "track", "video":
if htmlAttr.Key == "src" {
if u, ok := p.validURL(htmlAttr.Val); ok {
htmlAttr.Val = u
Expand All @@ -580,7 +580,7 @@ func (p *Policy) sanitizeAttrs(

// Add rel="nofollow" if a "href" exists
switch elementName {
case "a", "area", "link":
case "a", "area", "base", "link":
var hrefFound bool
var externalLink bool
for _, htmlAttr := range cleanAttrs {
Expand Down Expand Up @@ -870,7 +870,6 @@ func (p *Policy) validURL(rawurl string) (string, bool) {
urlPolicy, ok := p.allowURLSchemes[u.Scheme]
if !ok {
return "", false

}

if urlPolicy == nil || urlPolicy(u) == true {
Expand All @@ -894,7 +893,14 @@ func (p *Policy) validURL(rawurl string) (string, bool) {

func linkable(elementName string) bool {
switch elementName {
case "a", "area", "blockquote", "img", "link", "script":
case "a", "area", "base", "link":
// elements that allow .href
return true
case "blockquote", "del", "ins", "q":
// elements that allow .cite
return true
case "audio", "embed", "iframe", "img", "input", "script", "track", "video":
// elements that allow .src
return true
default:
return false
Expand Down
83 changes: 83 additions & 0 deletions sanitize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,89 @@ func TestDataUri(t *testing.T) {
}
}

func TestGlobalURLPatternsViaCustomPolicy(t *testing.T) {

p := UGCPolicy()
// youtube embeds
p.AllowElements("iframe")
p.AllowAttrs("width", "height", "frameborder").Matching(Integer).OnElements("iframe")
p.AllowAttrs("allow").Matching(regexp.MustCompile(`^(([\p{L}\p{N}_-]+)(; )?)+$`)).OnElements("iframe")
p.AllowAttrs("allowfullscreen").OnElements("iframe")
p.AllowAttrs("src").OnElements("iframe")
// These clobber... so you only get one and it applies to URLs everywhere
p.AllowURLSchemeWithCustomPolicy("mailto", func(url *url.URL) (allowUrl bool) { return false })
p.AllowURLSchemeWithCustomPolicy("http", func(url *url.URL) (allowUrl bool) { return false })
p.AllowURLSchemeWithCustomPolicy(
"https",
func(url *url.URL) bool {
// Allow YouTube
if url.Host == `www.youtube.com` {
return true
}
return false
},
)

tests := []test{
{
in: `<iframe width="560" height="315" src="https://www.youtube.com/embed/lJIrF4YjHfQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`,
expected: `<iframe width="560" height="315" src="https://www.youtube.com/embed/lJIrF4YjHfQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>`,
},
{
in: `<iframe width="560" height="315" src="htt://www.vimeo.com/embed/lJIrF4YjHfQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`,
expected: `<iframe width="560" height="315" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>`,
},
}

for ii, test := range tests {
out := p.Sanitize(test.in)
if out != test.expected {
t.Errorf(
"test %d failed;\ninput : %s\noutput : %s\nexpected: %s",
ii,
test.in,
out,
test.expected,
)
}
}
}

func TestELementURLPatternsMatching(t *testing.T) {

p := UGCPolicy()
// youtube embeds
p.AllowElements("iframe")
p.AllowAttrs("width", "height", "frameborder").Matching(Integer).OnElements("iframe")
p.AllowAttrs("allow").Matching(regexp.MustCompile(`^(([\p{L}\p{N}_-]+)(; )?)+$`)).OnElements("iframe")
p.AllowAttrs("allowfullscreen").OnElements("iframe")
p.AllowAttrs("src").Matching(regexp.MustCompile(`^https://www.youtube.com/.*$`)).OnElements("iframe")

tests := []test{
{
in: `<iframe width="560" height="315" src="https://www.youtube.com/embed/lJIrF4YjHfQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`,
expected: `<iframe width="560" height="315" src="https://www.youtube.com/embed/lJIrF4YjHfQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>`,
},
{
in: `<iframe width="560" height="315" src="htt://www.vimeo.com/embed/lJIrF4YjHfQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`,
expected: `<iframe width="560" height="315" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>`,
},
}

for ii, test := range tests {
out := p.Sanitize(test.in)
if out != test.expected {
t.Errorf(
"test %d failed;\ninput : %s\noutput : %s\nexpected: %s",
ii,
test.in,
out,
test.expected,
)
}
}
}

func TestAntiSamy(t *testing.T) {

standardUrls := regexp.MustCompile(`(?i)^https?|mailto`)
Expand Down

0 comments on commit cb61469

Please sign in to comment.