diff options
author | 6543 <6543@obermui.de> | 2021-07-04 04:06:10 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-04 04:06:10 +0200 |
commit | fae07cbc8fece383c88ed7b13474a94133c4accf (patch) | |
tree | 65e3279dc5655d22302c9b79c48ecd3d1a06ffcd /vendor/github.com/microcosm-cc | |
parent | 65ae46bc20f60534ba2590a106a6c86aaa1ecae0 (diff) | |
download | gitea-fae07cbc8fece383c88ed7b13474a94133c4accf.tar.gz gitea-fae07cbc8fece383c88ed7b13474a94133c4accf.zip |
Update Vendor (#16325)
* Add Dependencie Update Script
* update gitea.com/lunny/levelqueue
* update github.com/PuerkitoBio/goquery
* update github.com/alecthomas/chroma
* update github.com/blevesearch/bleve/v2
* update github.com/caddyserver/certmagic
* update github.com/go-enry/go-enry/v2
* update github.com/go-redis/redis/v8
* update github.com/hashicorp/golang-lru
* update github.com/klauspost/compress
* update github.com/markbates/goth
* update github.com/mholt/archiver/v3
* update github.com/microcosm-cc/bluemonday
* update github.com/minio/minio-go/v7
* update github.com/olivere/elastic/v7
* update github.com/xanzy/go-gitlab
* update github.com/yuin/goldmark
Diffstat (limited to 'vendor/github.com/microcosm-cc')
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/Makefile | 2 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/README.md | 29 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/css/handlers.go (renamed from vendor/github.com/microcosm-cc/bluemonday/handlers.go) | 4 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/doc.go | 14 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/go.mod | 2 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/go.sum | 3 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/helpers.go | 2 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/policy.go | 133 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/sanitize.go | 296 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_go1.12.go | 10 | ||||
-rw-r--r-- | vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_ltgo1.12.go | 14 |
11 files changed, 327 insertions, 182 deletions
diff --git a/vendor/github.com/microcosm-cc/bluemonday/Makefile b/vendor/github.com/microcosm-cc/bluemonday/Makefile index b15dc74f37..b5903a2e86 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/Makefile +++ b/vendor/github.com/microcosm-cc/bluemonday/Makefile @@ -25,7 +25,7 @@ build: @go build vet: - @go vet *.go + @go vet lint: @golint *.go diff --git a/vendor/github.com/microcosm-cc/bluemonday/README.md b/vendor/github.com/microcosm-cc/bluemonday/README.md index cd2766f6b2..6a34473efa 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/README.md +++ b/vendor/github.com/microcosm-cc/bluemonday/README.md @@ -2,7 +2,7 @@ bluemonday is a HTML sanitizer implemented in Go. It is fast and highly configurable. -bluemonday takes untrusted user generated content as an input, and will return HTML that has been sanitised against a whitelist of approved HTML elements and attributes so that you can safely include the content in your web page. +bluemonday takes untrusted user generated content as an input, and will return HTML that has been sanitised against an allowlist of approved HTML elements and attributes so that you can safely include the content in your web page. If you accept user generated content, and your server uses Go, you **need** bluemonday. @@ -50,15 +50,15 @@ bluemonday is heavily inspired by both the [OWASP Java HTML Sanitizer](https://c ## Technical Summary -Whitelist based, you need to either build a policy describing the HTML elements and attributes to permit (and the `regexp` patterns of attributes), or use one of the supplied policies representing good defaults. +Allowlist based, you need to either build a policy describing the HTML elements and attributes to permit (and the `regexp` patterns of attributes), or use one of the supplied policies representing good defaults. -The policy containing the whitelist is applied using a fast non-validating, forward only, token-based parser implemented in the [Go net/html library](https://godoc.org/golang.org/x/net/html) by the core Go team. +The policy containing the allowlist is applied using a fast non-validating, forward only, token-based parser implemented in the [Go net/html library](https://godoc.org/golang.org/x/net/html) by the core Go team. -We expect to be supplied with well-formatted HTML (closing elements for every applicable open element, nested correctly) and so we do not focus on repairing badly nested or incomplete HTML. We focus on simply ensuring that whatever elements do exist are described in the policy whitelist and that attributes and links are safe for use on your web page. [GIGO](http://en.wikipedia.org/wiki/Garbage_in,_garbage_out) does apply and if you feed it bad HTML bluemonday is not tasked with figuring out how to make it good again. +We expect to be supplied with well-formatted HTML (closing elements for every applicable open element, nested correctly) and so we do not focus on repairing badly nested or incomplete HTML. We focus on simply ensuring that whatever elements do exist are described in the policy allowlist and that attributes and links are safe for use on your web page. [GIGO](http://en.wikipedia.org/wiki/Garbage_in,_garbage_out) does apply and if you feed it bad HTML bluemonday is not tasked with figuring out how to make it good again. ### Supported Go Versions -bluemonday is tested against Go 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11, 1.12, and tip. +bluemonday is tested on all versions since Go 1.2 including tip. We do not support Go 1.0 as we depend on `golang.org/x/net/html` which includes a reference to `io.ErrNoProgress` which did not exist in Go 1.0. @@ -146,8 +146,8 @@ func main() { We ship two default policies: -1. `bluemonday.StrictPolicy()` which can be thought of as equivalent to stripping all HTML elements and their attributes as it has nothing on its whitelist. An example usage scenario would be blog post titles where HTML tags are not expected at all and if they are then the elements *and* the content of the elements should be stripped. This is a *very* strict policy. -2. `bluemonday.UGCPolicy()` which allows a broad selection of HTML elements and attributes that are safe for user generated content. Note that this policy does *not* whitelist iframes, object, embed, styles, script, etc. An example usage scenario would be blog post bodies where a variety of formatting is expected along with the potential for TABLEs and IMGs. +1. `bluemonday.StrictPolicy()` which can be thought of as equivalent to stripping all HTML elements and their attributes as it has nothing on its allowlist. An example usage scenario would be blog post titles where HTML tags are not expected at all and if they are then the elements *and* the content of the elements should be stripped. This is a *very* strict policy. +2. `bluemonday.UGCPolicy()` which allows a broad selection of HTML elements and attributes that are safe for user generated content. Note that this policy does *not* allow iframes, object, embed, styles, script, etc. An example usage scenario would be blog post bodies where a variety of formatting is expected along with the potential for TABLEs and IMGs. ## Policy Building @@ -220,7 +220,7 @@ p.AllowElements("fieldset", "select", "option") ### Inline CSS -Although it's possible to handle inline CSS using `AllowAttrs` with a `Matching` rule, writing a single monolithic regular expression to safely process all inline CSS which you wish to allow is not a trivial task. Instead of attempting to do so, you can whitelist the `style` attribute on whichever element(s) you desire and use style policies to control and sanitize inline styles. +Although it's possible to handle inline CSS using `AllowAttrs` with a `Matching` rule, writing a single monolithic regular expression to safely process all inline CSS which you wish to allow is not a trivial task. Instead of attempting to do so, you can allow the `style` attribute on whichever element(s) you desire and use style policies to control and sanitize inline styles. It is suggested that you use `Matching` (with a suitable regular expression) `MatchingEnum`, or `MatchingHandler` to ensure each style matches your needs, @@ -241,7 +241,7 @@ p.AllowAttrs("style").OnElements("span", "p") p.AllowStyles("text-decoration").MatchingEnum("underline", "line-through", "none").OnElements("span") ``` -Or you can specify elements based on a regex patterm match: +Or you can specify elements based on a regex pattern match: ```go p.AllowAttrs("style").OnElementsMatching(regex.MustCompile(`^my-element-`)) // Allow the 'text-decoration' property to be set to 'underline', 'line-through' or 'none' @@ -254,6 +254,7 @@ validate the values for a given property. The string parameter has been converted to lowercase and unicode code points have been converted. ```go myHandler := func(value string) bool{ + // Validate your input here return true } p.AllowAttrs("style").OnElements("span", "p") @@ -279,12 +280,12 @@ We provide some additional global options for safely working with links. p.RequireParseableURLs(true) ``` -If you have enabled parseable URLs then the following option will `AllowRelativeURLs`. By default this is disabled (bluemonday is a whitelist tool... you need to explicitly tell us to permit things) and when disabled it will prevent all local and scheme relative URLs (i.e. `href="localpage.html"`, `href="../home.html"` and even `href="//www.google.com"` are relative): +If you have enabled parseable URLs then the following option will `AllowRelativeURLs`. By default this is disabled (bluemonday is an allowlist tool... you need to explicitly tell us to permit things) and when disabled it will prevent all local and scheme relative URLs (i.e. `href="localpage.html"`, `href="../home.html"` and even `href="//www.google.com"` are relative): ```go p.AllowRelativeURLs(true) ``` -If you have enabled parseable URLs then you can whitelist the schemes (commonly called protocol when thinking of `http` and `https`) that are permitted. Bear in mind that allowing relative URLs in the above option will allow for a blank scheme: +If you have enabled parseable URLs then you can allow the schemes (commonly called protocol when thinking of `http` and `https`) that are permitted. Bear in mind that allowing relative URLs in the above option will allow for a blank scheme: ```go p.AllowURLSchemes("mailto", "http", "https") ``` @@ -302,7 +303,7 @@ p.RequireNoReferrerOnLinks(true) ``` -We provide a convenience method that applies all of the above, but you will still need to whitelist the linkable elements for the URL rules to be applied to: +We provide a convenience method that applies all of the above, but you will still need to allow the linkable elements for the URL rules to be applied to: ```go p.AllowStandardURLs() p.AllowAttrs("cite").OnElements("blockquote", "q") @@ -372,11 +373,11 @@ p.AllowAttrs( ) ``` -Both examples exhibit the same issue, they declare attributes but do not then specify whether they are whitelisted globally or only on specific elements (and which elements). Attributes belong to one or more elements, and the policy needs to declare this. +Both examples exhibit the same issue, they declare attributes but do not then specify whether they are allowed globally or only on specific elements (and which elements). Attributes belong to one or more elements, and the policy needs to declare this. ## Limitations -We are not yet including any tools to help whitelist and sanitize CSS. Which means that unless you wish to do the heavy lifting in a single regular expression (inadvisable), **you should not allow the "style" attribute anywhere**. +We are not yet including any tools to help allow and sanitize CSS. Which means that unless you wish to do the heavy lifting in a single regular expression (inadvisable), **you should not allow the "style" attribute anywhere**. It is not the job of bluemonday to fix your bad HTML, it is merely the job of bluemonday to prevent malicious HTML getting through. If you have mismatched HTML elements, or non-conforming nesting of elements, those will remain. But if you have well-structured HTML bluemonday will not break it. diff --git a/vendor/github.com/microcosm-cc/bluemonday/handlers.go b/vendor/github.com/microcosm-cc/bluemonday/css/handlers.go index 9753d6e952..200a6729a2 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/handlers.go +++ b/vendor/github.com/microcosm-cc/bluemonday/css/handlers.go @@ -27,7 +27,7 @@ // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -package bluemonday +package css import ( "regexp" @@ -329,7 +329,7 @@ func splitValues(value string) []string { return values } -func getDefaultHandler(attr string) func(string) bool { +func GetDefaultHandler(attr string) func(string) bool { if defaultStyleHandlers[attr] != nil { return defaultStyleHandlers[attr] diff --git a/vendor/github.com/microcosm-cc/bluemonday/doc.go b/vendor/github.com/microcosm-cc/bluemonday/doc.go index 71dab60898..ba2d775ac9 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/doc.go +++ b/vendor/github.com/microcosm-cc/bluemonday/doc.go @@ -28,10 +28,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* -Package bluemonday provides a way of describing a whitelist of HTML elements +Package bluemonday provides a way of describing an allowlist of HTML elements and attributes as a policy, and for that policy to be applied to untrusted strings from users that may contain markup. All elements and attributes not on -the whitelist will be stripped. +the allowlist will be stripped. The default bluemonday.UGCPolicy().Sanitize() turns this: @@ -84,21 +84,21 @@ bluemonday is heavily inspired by both the OWASP Java HTML Sanitizer We ship two default policies, one is bluemonday.StrictPolicy() and can be thought of as equivalent to stripping all HTML elements and their attributes as -it has nothing on its whitelist. +it has nothing on its allowlist. The other is bluemonday.UGCPolicy() and allows a broad selection of HTML elements and attributes that are safe for user generated content. Note that -this policy does not whitelist iframes, object, embed, styles, script, etc. +this policy does not allow iframes, object, embed, styles, script, etc. The essence of building a policy is to determine which HTML elements and attributes are considered safe for your scenario. OWASP provide an XSS prevention cheat sheet ( https://www.google.com/search?q=xss+prevention+cheat+sheet ) to help explain the risks, but essentially: - 1. Avoid whitelisting anything other than plain HTML elements - 2. Avoid whitelisting `script`, `style`, `iframe`, `object`, `embed`, `base` + 1. Avoid allowing anything other than plain HTML elements + 2. Avoid allowing `script`, `style`, `iframe`, `object`, `embed`, `base` elements - 3. Avoid whitelisting anything other than plain HTML elements with simple + 3. Avoid allowing anything other than plain HTML elements with simple values that you can match to a regexp */ package bluemonday diff --git a/vendor/github.com/microcosm-cc/bluemonday/go.mod b/vendor/github.com/microcosm-cc/bluemonday/go.mod index edbd585f26..02cf2eac30 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/go.mod +++ b/vendor/github.com/microcosm-cc/bluemonday/go.mod @@ -5,5 +5,5 @@ go 1.16 require ( github.com/aymerick/douceur v0.2.0 github.com/gorilla/css v1.0.0 // indirect - golang.org/x/net v0.0.0-20210421230115-4e50805a0758 + golang.org/x/net v0.0.0-20210610132358-84b48f89b13b ) diff --git a/vendor/github.com/microcosm-cc/bluemonday/go.sum b/vendor/github.com/microcosm-cc/bluemonday/go.sum index e195d4eafd..930d271e36 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/go.sum +++ b/vendor/github.com/microcosm-cc/bluemonday/go.sum @@ -4,8 +4,11 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= golang.org/x/net v0.0.0-20210421230115-4e50805a0758 h1:aEpZnXcAmXkd6AvLb2OPt+EN1Zu/8Ne3pCqPjja5PXY= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b h1:k+E048sYJHyVnsr1GDrRZWQ32D2C7lWs9JRc0bel53A= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/vendor/github.com/microcosm-cc/bluemonday/helpers.go b/vendor/github.com/microcosm-cc/bluemonday/helpers.go index 089fe9db90..776a4a6cd4 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/helpers.go +++ b/vendor/github.com/microcosm-cc/bluemonday/helpers.go @@ -141,7 +141,7 @@ func (p *Policy) AllowStandardURLs() { } // AllowStandardAttributes will enable "id", "title" and the language specific -// attributes "dir" and "lang" on all elements that are whitelisted +// attributes "dir" and "lang" on all elements that are allowed func (p *Policy) AllowStandardAttributes() { // "dir" "lang" are permitted as both language attributes affect charsets // and direction of text. diff --git a/vendor/github.com/microcosm-cc/bluemonday/policy.go b/vendor/github.com/microcosm-cc/bluemonday/policy.go index 9c7e662fc2..602a203798 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/policy.go +++ b/vendor/github.com/microcosm-cc/bluemonday/policy.go @@ -35,9 +35,11 @@ import ( "net/url" "regexp" "strings" + + "github.com/microcosm-cc/bluemonday/css" ) -// Policy encapsulates the whitelist of HTML elements and attributes that will +// Policy encapsulates the allowlist of HTML elements and attributes that will // be applied to the sanitised HTML. // // You should use bluemonday.NewPolicy() to create a blank policy as the @@ -86,28 +88,31 @@ type Policy struct { // When true, allow data attributes. allowDataAttributes bool - // map[htmlElementName]map[htmlAttributeName]attrPolicy - elsAndAttrs map[string]map[string]attrPolicy + // When true, allow comments. + allowComments bool + + // map[htmlElementName]map[htmlAttributeName][]attrPolicy + elsAndAttrs map[string]map[string][]attrPolicy // elsMatchingAndAttrs stores regex based element matches along with attributes - elsMatchingAndAttrs map[*regexp.Regexp]map[string]attrPolicy + elsMatchingAndAttrs map[*regexp.Regexp]map[string][]attrPolicy - // map[htmlAttributeName]attrPolicy - globalAttrs map[string]attrPolicy + // map[htmlAttributeName][]attrPolicy + globalAttrs map[string][]attrPolicy - // map[htmlElementName]map[cssPropertyName]stylePolicy - elsAndStyles map[string]map[string]stylePolicy + // map[htmlElementName]map[cssPropertyName][]stylePolicy + elsAndStyles map[string]map[string][]stylePolicy - // map[regex]map[cssPropertyName]stylePolicy - elsMatchingAndStyles map[*regexp.Regexp]map[string]stylePolicy + // map[regex]map[cssPropertyName][]stylePolicy + elsMatchingAndStyles map[*regexp.Regexp]map[string][]stylePolicy - // map[cssPropertyName]stylePolicy - globalStyles map[string]stylePolicy + // map[cssPropertyName][]stylePolicy + globalStyles map[string][]stylePolicy // If urlPolicy is nil, all URLs with matching schema are allowed. // Otherwise, only the URLs with matching schema and urlPolicy(url) // returning true are allowed. - allowURLSchemes map[string]urlPolicy + allowURLSchemes map[string][]urlPolicy // If an element has had all attributes removed as a result of a policy // being applied, then the element would be removed from the output. @@ -174,22 +179,22 @@ type urlPolicy func(url *url.URL) (allowUrl bool) // init initializes the maps if this has not been done already func (p *Policy) init() { if !p.initialized { - p.elsAndAttrs = make(map[string]map[string]attrPolicy) - p.elsMatchingAndAttrs = make(map[*regexp.Regexp]map[string]attrPolicy) - p.globalAttrs = make(map[string]attrPolicy) - p.elsAndStyles = make(map[string]map[string]stylePolicy) - p.elsMatchingAndStyles = make(map[*regexp.Regexp]map[string]stylePolicy) - p.globalStyles = make(map[string]stylePolicy) - p.allowURLSchemes = make(map[string]urlPolicy) + p.elsAndAttrs = make(map[string]map[string][]attrPolicy) + p.elsMatchingAndAttrs = make(map[*regexp.Regexp]map[string][]attrPolicy) + p.globalAttrs = make(map[string][]attrPolicy) + p.elsAndStyles = make(map[string]map[string][]stylePolicy) + p.elsMatchingAndStyles = make(map[*regexp.Regexp]map[string][]stylePolicy) + p.globalStyles = make(map[string][]stylePolicy) + p.allowURLSchemes = make(map[string][]urlPolicy) p.setOfElementsAllowedWithoutAttrs = make(map[string]struct{}) p.setOfElementsToSkipContent = make(map[string]struct{}) p.initialized = true } } -// NewPolicy returns a blank policy with nothing whitelisted or permitted. This +// NewPolicy returns a blank policy with nothing allowed or permitted. This // is the recommended way to start building a policy and you should now use -// AllowAttrs() and/or AllowElements() to construct the whitelist of HTML +// AllowAttrs() and/or AllowElements() to construct the allowlist of HTML // elements and attributes. func NewPolicy() *Policy { @@ -203,7 +208,7 @@ func NewPolicy() *Policy { // AllowAttrs takes a range of HTML attribute names and returns an // attribute policy builder that allows you to specify the pattern and scope of -// the whitelisted attribute. +// the allowed attribute. // // The attribute policy is only added to the core policy when either Globally() // or OnElements(...) are called. @@ -223,7 +228,7 @@ func (p *Policy) AllowAttrs(attrNames ...string) *attrPolicyBuilder { return &abp } -// AllowDataAttributes whitelists all data attributes. We can't specify the name +// AllowDataAttributes permits all data attributes. We can't specify the name // of each attribute exactly as they are customized. // // NOTE: These values are not sanitized and applications that evaluate or process @@ -238,6 +243,22 @@ func (p *Policy) AllowDataAttributes() { p.allowDataAttributes = true } +// AllowComments allows comments. +// +// Please note that only one type of comment will be allowed by this, this is the +// the standard HTML comment <!-- --> which includes the use of that to permit +// conditionals as per https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/ms537512(v=vs.85)?redirectedfrom=MSDN +// +// What is not permitted are CDATA XML comments, as the x/net/html package we depend +// on does not handle this fully and we are not choosing to take on that work: +// https://pkg.go.dev/golang.org/x/net/html#Tokenizer.AllowCDATA . If the x/net/html +// package changes this then these will be considered, otherwise if you AllowComments +// but provide a CDATA comment, then as per the documentation in x/net/html this will +// be treated as a plain HTML comment. +func (p *Policy) AllowComments() { + p.allowComments = true +} + // AllowNoAttrs says that attributes on element are optional. // // The attribute policy is only added to the core policy when OnElements(...) @@ -265,8 +286,7 @@ func (abp *attrPolicyBuilder) AllowNoAttrs() *attrPolicyBuilder { } // Matching allows a regular expression to be applied to a nascent attribute -// policy, and returns the attribute policy. Calling this more than once will -// replace the existing regexp. +// policy, and returns the attribute policy. func (abp *attrPolicyBuilder) Matching(regex *regexp.Regexp) *attrPolicyBuilder { abp.regexp = regex @@ -284,7 +304,7 @@ func (abp *attrPolicyBuilder) OnElements(elements ...string) *Policy { for _, attr := range abp.attrNames { if _, ok := abp.p.elsAndAttrs[element]; !ok { - abp.p.elsAndAttrs[element] = make(map[string]attrPolicy) + abp.p.elsAndAttrs[element] = make(map[string][]attrPolicy) } ap := attrPolicy{} @@ -292,14 +312,14 @@ func (abp *attrPolicyBuilder) OnElements(elements ...string) *Policy { ap.regexp = abp.regexp } - abp.p.elsAndAttrs[element][attr] = ap + abp.p.elsAndAttrs[element][attr] = append(abp.p.elsAndAttrs[element][attr], ap) } if abp.allowEmpty { abp.p.setOfElementsAllowedWithoutAttrs[element] = struct{}{} if _, ok := abp.p.elsAndAttrs[element]; !ok { - abp.p.elsAndAttrs[element] = make(map[string]attrPolicy) + abp.p.elsAndAttrs[element] = make(map[string][]attrPolicy) } } } @@ -312,19 +332,19 @@ func (abp *attrPolicyBuilder) OnElements(elements ...string) *Policy { func (abp *attrPolicyBuilder) OnElementsMatching(regex *regexp.Regexp) *Policy { for _, attr := range abp.attrNames { if _, ok := abp.p.elsMatchingAndAttrs[regex]; !ok { - abp.p.elsMatchingAndAttrs[regex] = make(map[string]attrPolicy) + abp.p.elsMatchingAndAttrs[regex] = make(map[string][]attrPolicy) } ap := attrPolicy{} if abp.regexp != nil { ap.regexp = abp.regexp } - abp.p.elsMatchingAndAttrs[regex][attr] = ap + abp.p.elsMatchingAndAttrs[regex][attr] = append(abp.p.elsMatchingAndAttrs[regex][attr], ap) } if abp.allowEmpty { abp.p.setOfElementsMatchingAllowedWithoutAttrs = append(abp.p.setOfElementsMatchingAllowedWithoutAttrs, regex) if _, ok := abp.p.elsMatchingAndAttrs[regex]; !ok { - abp.p.elsMatchingAndAttrs[regex] = make(map[string]attrPolicy) + abp.p.elsMatchingAndAttrs[regex] = make(map[string][]attrPolicy) } } @@ -337,7 +357,7 @@ func (abp *attrPolicyBuilder) Globally() *Policy { for _, attr := range abp.attrNames { if _, ok := abp.p.globalAttrs[attr]; !ok { - abp.p.globalAttrs[attr] = attrPolicy{} + abp.p.globalAttrs[attr] = []attrPolicy{} } ap := attrPolicy{} @@ -345,7 +365,7 @@ func (abp *attrPolicyBuilder) Globally() *Policy { ap.regexp = abp.regexp } - abp.p.globalAttrs[attr] = ap + abp.p.globalAttrs[attr] = append(abp.p.globalAttrs[attr], ap) } return abp.p @@ -353,7 +373,7 @@ func (abp *attrPolicyBuilder) Globally() *Policy { // AllowStyles takes a range of CSS property names and returns a // style policy builder that allows you to specify the pattern and scope of -// the whitelisted property. +// the allowed property. // // The style policy is only added to the core policy when either Globally() // or OnElements(...) are called. @@ -373,8 +393,7 @@ func (p *Policy) AllowStyles(propertyNames ...string) *stylePolicyBuilder { } // Matching allows a regular expression to be applied to a nascent style -// policy, and returns the style policy. Calling this more than once will -// replace the existing regexp. +// policy, and returns the style policy. func (spb *stylePolicyBuilder) Matching(regex *regexp.Regexp) *stylePolicyBuilder { spb.regexp = regex @@ -383,8 +402,7 @@ func (spb *stylePolicyBuilder) Matching(regex *regexp.Regexp) *stylePolicyBuilde } // MatchingEnum allows a list of allowed values to be applied to a nascent style -// policy, and returns the style policy. Calling this more than once will -// replace the existing list of allowed values. +// policy, and returns the style policy. func (spb *stylePolicyBuilder) MatchingEnum(enum ...string) *stylePolicyBuilder { spb.enum = enum @@ -393,8 +411,7 @@ func (spb *stylePolicyBuilder) MatchingEnum(enum ...string) *stylePolicyBuilder } // MatchingHandler allows a handler to be applied to a nascent style -// policy, and returns the style policy. Calling this more than once will -// replace the existing handler. +// policy, and returns the style policy. func (spb *stylePolicyBuilder) MatchingHandler(handler func(string) bool) *stylePolicyBuilder { spb.handler = handler @@ -412,7 +429,7 @@ func (spb *stylePolicyBuilder) OnElements(elements ...string) *Policy { for _, attr := range spb.propertyNames { if _, ok := spb.p.elsAndStyles[element]; !ok { - spb.p.elsAndStyles[element] = make(map[string]stylePolicy) + spb.p.elsAndStyles[element] = make(map[string][]stylePolicy) } sp := stylePolicy{} @@ -423,9 +440,9 @@ func (spb *stylePolicyBuilder) OnElements(elements ...string) *Policy { } else if spb.regexp != nil { sp.regexp = spb.regexp } else { - sp.handler = getDefaultHandler(attr) + sp.handler = css.GetDefaultHandler(attr) } - spb.p.elsAndStyles[element][attr] = sp + spb.p.elsAndStyles[element][attr] = append(spb.p.elsAndStyles[element][attr], sp) } } @@ -439,7 +456,7 @@ func (spb *stylePolicyBuilder) OnElementsMatching(regex *regexp.Regexp) *Policy for _, attr := range spb.propertyNames { if _, ok := spb.p.elsMatchingAndStyles[regex]; !ok { - spb.p.elsMatchingAndStyles[regex] = make(map[string]stylePolicy) + spb.p.elsMatchingAndStyles[regex] = make(map[string][]stylePolicy) } sp := stylePolicy{} @@ -450,9 +467,9 @@ func (spb *stylePolicyBuilder) OnElementsMatching(regex *regexp.Regexp) *Policy } else if spb.regexp != nil { sp.regexp = spb.regexp } else { - sp.handler = getDefaultHandler(attr) + sp.handler = css.GetDefaultHandler(attr) } - spb.p.elsMatchingAndStyles[regex][attr] = sp + spb.p.elsMatchingAndStyles[regex][attr] = append(spb.p.elsMatchingAndStyles[regex][attr], sp) } return spb.p @@ -464,7 +481,7 @@ func (spb *stylePolicyBuilder) Globally() *Policy { for _, attr := range spb.propertyNames { if _, ok := spb.p.globalStyles[attr]; !ok { - spb.p.globalStyles[attr] = stylePolicy{} + spb.p.globalStyles[attr] = []stylePolicy{} } // Use only one strategy for validating styles, fallback to default @@ -476,15 +493,15 @@ func (spb *stylePolicyBuilder) Globally() *Policy { } else if spb.regexp != nil { sp.regexp = spb.regexp } else { - sp.handler = getDefaultHandler(attr) + sp.handler = css.GetDefaultHandler(attr) } - spb.p.globalStyles[attr] = sp + spb.p.globalStyles[attr] = append(spb.p.globalStyles[attr], sp) } return spb.p } -// AllowElements will append HTML elements to the whitelist without applying an +// AllowElements will append HTML elements to the allowlist without applying an // attribute policy to those elements (the elements are permitted // sans-attributes) func (p *Policy) AllowElements(names ...string) *Policy { @@ -494,17 +511,19 @@ func (p *Policy) AllowElements(names ...string) *Policy { element = strings.ToLower(element) if _, ok := p.elsAndAttrs[element]; !ok { - p.elsAndAttrs[element] = make(map[string]attrPolicy) + p.elsAndAttrs[element] = make(map[string][]attrPolicy) } } return p } +// AllowElementsMatching will append HTML elements to the allowlist if they +// match a regexp. func (p *Policy) AllowElementsMatching(regex *regexp.Regexp) *Policy { p.init() if _, ok := p.elsMatchingAndAttrs[regex]; !ok { - p.elsMatchingAndAttrs[regex] = make(map[string]attrPolicy) + p.elsMatchingAndAttrs[regex] = make(map[string][]attrPolicy) } return p } @@ -611,7 +630,7 @@ func (p *Policy) AllowRelativeURLs(require bool) *Policy { return p } -// AllowURLSchemes will append URL schemes to the whitelist +// AllowURLSchemes will append URL schemes to the allowlist // Example: p.AllowURLSchemes("mailto", "http", "https") func (p *Policy) AllowURLSchemes(schemes ...string) *Policy { p.init() @@ -629,7 +648,7 @@ func (p *Policy) AllowURLSchemes(schemes ...string) *Policy { } // AllowURLSchemeWithCustomPolicy will append URL schemes with -// a custom URL policy to the whitelist. +// a custom URL policy to the allowlist. // Only the URLs with matching schema and urlPolicy(url) // returning true will be allowed. func (p *Policy) AllowURLSchemeWithCustomPolicy( @@ -643,13 +662,13 @@ func (p *Policy) AllowURLSchemeWithCustomPolicy( scheme = strings.ToLower(scheme) - p.allowURLSchemes[scheme] = urlPolicy + p.allowURLSchemes[scheme] = append(p.allowURLSchemes[scheme], urlPolicy) return p } // AddSpaceWhenStrippingTag states whether to add a single space " " when -// removing tags that are not whitelisted by the policy. +// removing tags that are not allowed by the policy. // // This is useful if you expect to strip tags in dense markup and may lose the // value of whitespace. diff --git a/vendor/github.com/microcosm-cc/bluemonday/sanitize.go b/vendor/github.com/microcosm-cc/bluemonday/sanitize.go index b462f0990a..9bb87a6879 100644 --- a/vendor/github.com/microcosm-cc/bluemonday/sanitize.go +++ b/vendor/github.com/microcosm-cc/bluemonday/sanitize.go @@ -31,6 +31,7 @@ package bluemonday import ( "bytes" + "fmt" "io" "net/url" "regexp" @@ -47,10 +48,11 @@ var ( dataAttributeXMLPrefix = regexp.MustCompile("^xml.+") dataAttributeInvalidChars = regexp.MustCompile("[A-Z;]+") cssUnicodeChar = regexp.MustCompile(`\\[0-9a-f]{1,6} ?`) + dataURIbase64Prefix = regexp.MustCompile(`^data:[^,]*;base64,`) ) // Sanitize takes a string that contains a HTML fragment or document and applies -// the given policy whitelist. +// the given policy allowlist. // // It returns a HTML string that has been sanitized by the policy or an empty // string if an error has occurred (most likely as a consequence of extremely @@ -60,11 +62,11 @@ func (p *Policy) Sanitize(s string) string { return s } - return p.sanitize(strings.NewReader(s)).String() + return p.sanitizeWithBuff(strings.NewReader(s)).String() } // SanitizeBytes takes a []byte that contains a HTML fragment or document and applies -// the given policy whitelist. +// the given policy allowlist. // // It returns a []byte containing the HTML that has been sanitized by the policy // or an empty []byte if an error has occurred (most likely as a consequence of @@ -74,26 +76,32 @@ func (p *Policy) SanitizeBytes(b []byte) []byte { return b } - return p.sanitize(bytes.NewReader(b)).Bytes() + return p.sanitizeWithBuff(bytes.NewReader(b)).Bytes() } // SanitizeReader takes an io.Reader that contains a HTML fragment or document -// and applies the given policy whitelist. +// and applies the given policy allowlist. // // It returns a bytes.Buffer containing the HTML that has been sanitized by the // policy. Errors during sanitization will merely return an empty result. func (p *Policy) SanitizeReader(r io.Reader) *bytes.Buffer { - return p.sanitize(r) + return p.sanitizeWithBuff(r) +} + +// SanitizeReaderToWriter takes an io.Reader that contains a HTML fragment or document +// and applies the given policy allowlist and writes to the provided writer returning +// an error if there is one. +func (p *Policy) SanitizeReaderToWriter(r io.Reader, w io.Writer) error { + return p.sanitize(r, w) } const escapedURLChars = "'<>\"\r" -func escapeUrlComponent(val string) string { - w := bytes.NewBufferString("") +func escapeUrlComponent(w stringWriterWriter, val string) error { i := strings.IndexAny(val, escapedURLChars) for i != -1 { if _, err := w.WriteString(val[:i]); err != nil { - return w.String() + return err } var esc string switch val[i] { @@ -114,12 +122,12 @@ func escapeUrlComponent(val string) string { } val = val[i+1:] if _, err := w.WriteString(esc); err != nil { - return w.String() + return err } i = strings.IndexAny(val, escapedURLChars) } - w.WriteString(val) - return w.String() + _, err := w.WriteString(val) + return err } // Query represents a query @@ -205,15 +213,16 @@ func sanitizedURL(val string) (string, error) { return u.String(), nil } -func (p *Policy) writeLinkableBuf(buff *bytes.Buffer, token *html.Token) { +func (p *Policy) writeLinkableBuf(buff stringWriterWriter, token *html.Token) (int, error) { // do not escape multiple query parameters - tokenBuff := bytes.NewBufferString("") - tokenBuff.WriteString("<") + tokenBuff := bytes.NewBuffer(make([]byte, 0, 1024)) // This should stay on the stack unless it gets too big + + tokenBuff.WriteByte('<') tokenBuff.WriteString(token.Data) for _, attr := range token.Attr { tokenBuff.WriteByte(' ') tokenBuff.WriteString(attr.Key) - tokenBuff.WriteString(`="`) + tokenBuff.Write([]byte{'=', '"'}) switch attr.Key { case "href", "src": u, ok := p.validURL(attr.Val) @@ -238,12 +247,27 @@ func (p *Policy) writeLinkableBuf(buff *bytes.Buffer, token *html.Token) { tokenBuff.WriteString("/") } tokenBuff.WriteString(">") - buff.WriteString(tokenBuff.String()) + return buff.Write(tokenBuff.Bytes()) } // Performs the actual sanitization process. -func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { +func (p *Policy) sanitizeWithBuff(r io.Reader) *bytes.Buffer { + var buff bytes.Buffer + if err := p.sanitize(r, &buff); err != nil { + return &bytes.Buffer{} + } + return &buff +} + +type asStringWriter struct { + io.Writer +} +func (a *asStringWriter) WriteString(s string) (int, error) { + return a.Write([]byte(s)) +} + +func (p *Policy) sanitize(r io.Reader, w io.Writer) error { // It is possible that the developer has created the policy via: // p := bluemonday.Policy{} // rather than: @@ -252,8 +276,12 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { // would initiliaze the maps, then we need to do that. p.init() + buff, ok := w.(stringWriterWriter) + if !ok { + buff = &asStringWriter{w} + } + var ( - buff bytes.Buffer skipElementContent bool skippingElementsCount int64 skipClosingTag bool @@ -267,11 +295,11 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { err := tokenizer.Err() if err == io.EOF { // End of input means end of processing - return &buff + return nil } // Raw tokenizer error - return &bytes.Buffer{} + return err } token := tokenizer.Token() @@ -289,6 +317,10 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { case html.CommentToken: // Comments are ignored by default + if p.allowComments { + // But if allowed then write the comment out as-is + buff.WriteString(token.String()) + } case html.StartTagToken: @@ -303,7 +335,9 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { skippingElementsCount++ } if p.addSpaces { - buff.WriteString(" ") + if _, err := buff.WriteString(" "); err != nil { + return err + } } break } @@ -318,7 +352,9 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { skipClosingTag = true closingTagToSkipStack = append(closingTagToSkipStack, token.Data) if p.addSpaces { - buff.WriteString(" ") + if _, err := buff.WriteString(" "); err != nil { + return err + } } break } @@ -327,9 +363,13 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { if !skipElementContent { // do not escape multiple query parameters if linkable(token.Data) { - p.writeLinkableBuf(&buff, &token) + if _, err := p.writeLinkableBuf(buff, &token); err != nil { + return err + } } else { - buff.WriteString(token.String()) + if _, err := buff.WriteString(token.String()); err != nil { + return err + } } } @@ -345,7 +385,9 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { skipClosingTag = false } if p.addSpaces { - buff.WriteString(" ") + if _, err := buff.WriteString(" "); err != nil { + return err + } } break } @@ -366,14 +408,18 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { } if !match { if p.addSpaces { - buff.WriteString(" ") + if _, err := buff.WriteString(" "); err != nil { + return err + } } break } } if !skipElementContent { - buff.WriteString(token.String()) + if _, err := buff.WriteString(token.String()); err != nil { + return err + } } case html.SelfClosingTagToken: @@ -383,7 +429,9 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { aa, matched := p.matchRegex(token.Data) if !matched { if p.addSpaces && !matched { - buff.WriteString(" ") + if _, err := buff.WriteString(" "); err != nil { + return err + } } break } @@ -396,16 +444,22 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { if len(token.Attr) == 0 && !p.allowNoAttrs(token.Data) { if p.addSpaces { - buff.WriteString(" ") + if _, err := buff.WriteString(" "); err != nil { + return err + } break } } if !skipElementContent { // do not escape multiple query parameters if linkable(token.Data) { - p.writeLinkableBuf(&buff, &token) + if _, err := p.writeLinkableBuf(buff, &token); err != nil { + return err + } } else { - buff.WriteString(token.String()) + if _, err := buff.WriteString(token.String()); err != nil { + return err + } } } @@ -416,20 +470,26 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { case `script`: // not encouraged, but if a policy allows JavaScript we // should not HTML escape it as that would break the output - buff.WriteString(token.Data) - case `style`: + if _, err := buff.WriteString(token.Data); err != nil { + return err + } + case "style": // not encouraged, but if a policy allows CSS styles we // should not HTML escape it as that would break the output - buff.WriteString(token.Data) + if _, err := buff.WriteString(token.Data); err != nil { + return err + } default: // HTML escape the text - buff.WriteString(token.String()) + if _, err := buff.WriteString(token.String()); err != nil { + return err + } } } default: // A token that didn't exist in the html package when we wrote this - return &bytes.Buffer{} + return fmt.Errorf("unknown token: %v", token) } } } @@ -440,7 +500,7 @@ func (p *Policy) sanitize(r io.Reader) *bytes.Buffer { func (p *Policy) sanitizeAttrs( elementName string, attrs []html.Attribute, - aps map[string]attrPolicy, + aps map[string][]attrPolicy, ) []html.Attribute { if len(attrs) == 0 { @@ -465,8 +525,9 @@ func (p *Policy) sanitizeAttrs( } // Builds a new attribute slice based on the whether the attribute has been - // whitelisted explicitly or globally. + // allowed explicitly or globally. cleanAttrs := []html.Attribute{} +attrsLoop: for _, htmlAttr := range attrs { if p.allowDataAttributes { // If we see a data attribute, let it through. @@ -489,27 +550,30 @@ func (p *Policy) sanitizeAttrs( } // Is there an element specific attribute policy that applies? - if ap, ok := aps[htmlAttr.Key]; ok { - if ap.regexp != nil { - if ap.regexp.MatchString(htmlAttr.Val) { + if apl, ok := aps[htmlAttr.Key]; ok { + for _, ap := range apl { + if ap.regexp != nil { + if ap.regexp.MatchString(htmlAttr.Val) { + cleanAttrs = append(cleanAttrs, htmlAttr) + continue attrsLoop + } + } else { cleanAttrs = append(cleanAttrs, htmlAttr) - continue + continue attrsLoop } - } else { - cleanAttrs = append(cleanAttrs, htmlAttr) - continue } } // Is there a global attribute policy that applies? - if ap, ok := p.globalAttrs[htmlAttr.Key]; ok { - - if ap.regexp != nil { - if ap.regexp.MatchString(htmlAttr.Val) { + if apl, ok := p.globalAttrs[htmlAttr.Key]; ok { + for _, ap := range apl { + if ap.regexp != nil { + if ap.regexp.MatchString(htmlAttr.Val) { + cleanAttrs = append(cleanAttrs, htmlAttr) + } + } else { cleanAttrs = append(cleanAttrs, htmlAttr) } - } else { - cleanAttrs = append(cleanAttrs, htmlAttr) } } } @@ -533,7 +597,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 @@ -542,7 +606,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 @@ -551,7 +615,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 @@ -576,7 +640,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 { @@ -753,14 +817,14 @@ func (p *Policy) sanitizeAttrs( func (p *Policy) sanitizeStyles(attr html.Attribute, elementName string) html.Attribute { sps := p.elsAndStyles[elementName] if len(sps) == 0 { - sps = map[string]stylePolicy{} + sps = map[string][]stylePolicy{} // check for any matching elements, if we don't already have a policy found // if multiple matches are found they will be overwritten, it's best // to not have overlapping matchers for regex, policies := range p.elsMatchingAndStyles { if regex.MatchString(elementName) { for k, v := range policies { - sps[k] = v + sps[k] = append(sps[k], v...) } } } @@ -778,46 +842,51 @@ func (p *Policy) sanitizeStyles(attr html.Attribute, elementName string) html.At clean := []string{} prefixes := []string{"-webkit-", "-moz-", "-ms-", "-o-", "mso-", "-xv-", "-atsc-", "-wap-", "-khtml-", "prince-", "-ah-", "-hp-", "-ro-", "-rim-", "-tc-"} +decLoop: for _, dec := range decs { - addedProperty := false tempProperty := strings.ToLower(dec.Property) tempValue := removeUnicode(strings.ToLower(dec.Value)) for _, i := range prefixes { tempProperty = strings.TrimPrefix(tempProperty, i) } - if sp, ok := sps[tempProperty]; ok { - if sp.handler != nil { - if sp.handler(tempValue) { - clean = append(clean, dec.Property+": "+dec.Value) - addedProperty = true - } - } else if len(sp.enum) > 0 { - if stringInSlice(tempValue, sp.enum) { - clean = append(clean, dec.Property+": "+dec.Value) - addedProperty = true - } - } else if sp.regexp != nil { - if sp.regexp.MatchString(tempValue) { - clean = append(clean, dec.Property+": "+dec.Value) - addedProperty = true + if spl, ok := sps[tempProperty]; ok { + for _, sp := range spl { + if sp.handler != nil { + if sp.handler(tempValue) { + clean = append(clean, dec.Property+": "+dec.Value) + continue decLoop + } + } else if len(sp.enum) > 0 { + if stringInSlice(tempValue, sp.enum) { + clean = append(clean, dec.Property+": "+dec.Value) + continue decLoop + } + } else if sp.regexp != nil { + if sp.regexp.MatchString(tempValue) { + clean = append(clean, dec.Property+": "+dec.Value) + continue decLoop + } } - continue } } - if sp, ok := p.globalStyles[tempProperty]; ok && !addedProperty { - if sp.handler != nil { - if sp.handler(tempValue) { - clean = append(clean, dec.Property+": "+dec.Value) - } - } else if len(sp.enum) > 0 { - if stringInSlice(tempValue, sp.enum) { - clean = append(clean, dec.Property+": "+dec.Value) - } - } else if sp.regexp != nil { - if sp.regexp.MatchString(tempValue) { - clean = append(clean, dec.Property+": "+dec.Value) + if spl, ok := p.globalStyles[tempProperty]; ok { + for _, sp := range spl { + if sp.handler != nil { + if sp.handler(tempValue) { + clean = append(clean, dec.Property+": "+dec.Value) + continue decLoop + } + } else if len(sp.enum) > 0 { + if stringInSlice(tempValue, sp.enum) { + clean = append(clean, dec.Property+": "+dec.Value) + continue decLoop + } + } else if sp.regexp != nil { + if sp.regexp.MatchString(tempValue) { + clean = append(clean, dec.Property+": "+dec.Value) + continue decLoop + } } - continue } } } @@ -848,11 +917,28 @@ func (p *Policy) validURL(rawurl string) (string, bool) { rawurl = strings.TrimSpace(rawurl) // URLs cannot contain whitespace, unless it is a data-uri - if (strings.Contains(rawurl, " ") || + if strings.Contains(rawurl, " ") || strings.Contains(rawurl, "\t") || - strings.Contains(rawurl, "\n")) && - !strings.HasPrefix(rawurl, `data:`) { - return "", false + strings.Contains(rawurl, "\n") { + if !strings.HasPrefix(rawurl, `data:`) { + return "", false + } + + // Remove \r and \n from base64 encoded data to pass url.Parse. + matched := dataURIbase64Prefix.FindString(rawurl) + if matched != "" { + rawurl = matched + strings.Replace( + strings.Replace( + rawurl[len(matched):], + "\r", + "", + -1, + ), + "\n", + "", + -1, + ) + } } // URLs are valid if they parse @@ -863,16 +949,21 @@ func (p *Policy) validURL(rawurl string) (string, bool) { if u.Scheme != "" { - urlPolicy, ok := p.allowURLSchemes[u.Scheme] + urlPolicies, ok := p.allowURLSchemes[u.Scheme] if !ok { return "", false - } - if urlPolicy == nil || urlPolicy(u) == true { + if len(urlPolicies) == 0 { return u.String(), true } + for _, urlPolicy := range urlPolicies { + if urlPolicy(u) == true { + return u.String(), true + } + } + return "", false } @@ -890,7 +981,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 @@ -957,14 +1055,14 @@ func removeUnicode(value string) string { return substitutedValue } -func (p *Policy) matchRegex(elementName string) (map[string]attrPolicy, bool) { - aps := make(map[string]attrPolicy, 0) +func (p *Policy) matchRegex(elementName string) (map[string][]attrPolicy, bool) { + aps := make(map[string][]attrPolicy, 0) matched := false for regex, attrs := range p.elsMatchingAndAttrs { if regex.MatchString(elementName) { matched = true for k, v := range attrs { - aps[k] = v + aps[k] = append(aps[k], v...) } } } diff --git a/vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_go1.12.go b/vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_go1.12.go new file mode 100644 index 0000000000..afa011e02a --- /dev/null +++ b/vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_go1.12.go @@ -0,0 +1,10 @@ +// +build go1.12 + +package bluemonday + +import "io" + +type stringWriterWriter interface { + io.Writer + io.StringWriter +} diff --git a/vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_ltgo1.12.go b/vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_ltgo1.12.go new file mode 100644 index 0000000000..9bc6747982 --- /dev/null +++ b/vendor/github.com/microcosm-cc/bluemonday/stringwriterwriter_ltgo1.12.go @@ -0,0 +1,14 @@ +// +build go1.1,!go1.12 + +package bluemonday + +import "io" + +type stringWriterWriter interface { + io.Writer + StringWriter +} + +type StringWriter interface { + WriteString(s string) (n int, err error) +} |