|
- // Copyright (c) 2014, David Kitchen <david@buro9.com>
- //
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are met:
- //
- // * Redistributions of source code must retain the above copyright notice, this
- // list of conditions and the following disclaimer.
- //
- // * Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // * Neither the name of the organisation (Microcosm) nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- // 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
-
- import (
- "regexp"
- )
-
- // StrictPolicy returns an empty policy, which will effectively strip all HTML
- // elements and their attributes from a document.
- func StrictPolicy() *Policy {
- return NewPolicy()
- }
-
- // StripTagsPolicy is DEPRECATED. Use StrictPolicy instead.
- func StripTagsPolicy() *Policy {
- return StrictPolicy()
- }
-
- // UGCPolicy returns a policy aimed at user generated content that is a result
- // of HTML WYSIWYG tools and Markdown conversions.
- //
- // This is expected to be a fairly rich document where as much markup as
- // possible should be retained. Markdown permits raw HTML so we are basically
- // providing a policy to sanitise HTML5 documents safely but with the
- // least intrusion on the formatting expectations of the user.
- func UGCPolicy() *Policy {
-
- p := NewPolicy()
-
- ///////////////////////
- // Global attributes //
- ///////////////////////
-
- // "class" is not permitted as we are not allowing users to style their own
- // content
-
- p.AllowStandardAttributes()
-
- //////////////////////////////
- // Global URL format policy //
- //////////////////////////////
-
- p.AllowStandardURLs()
-
- ////////////////////////////////
- // Declarations and structure //
- ////////////////////////////////
-
- // "xml" "xslt" "DOCTYPE" "html" "head" are not permitted as we are
- // expecting user generated content to be a fragment of HTML and not a full
- // document.
-
- //////////////////////////
- // Sectioning root tags //
- //////////////////////////
-
- // "article" and "aside" are permitted and takes no attributes
- p.AllowElements("article", "aside")
-
- // "body" is not permitted as we are expecting user generated content to be a fragment
- // of HTML and not a full document.
-
- // "details" is permitted, including the "open" attribute which can either
- // be blank or the value "open".
- p.AllowAttrs(
- "open",
- ).Matching(regexp.MustCompile(`(?i)^(|open)$`)).OnElements("details")
-
- // "fieldset" is not permitted as we are not allowing forms to be created.
-
- // "figure" is permitted and takes no attributes
- p.AllowElements("figure")
-
- // "nav" is not permitted as it is assumed that the site (and not the user)
- // has defined navigation elements
-
- // "section" is permitted and takes no attributes
- p.AllowElements("section")
-
- // "summary" is permitted and takes no attributes
- p.AllowElements("summary")
-
- //////////////////////////
- // Headings and footers //
- //////////////////////////
-
- // "footer" is not permitted as we expect user content to be a fragment and
- // not structural to this extent
-
- // "h1" through "h6" are permitted and take no attributes
- p.AllowElements("h1", "h2", "h3", "h4", "h5", "h6")
-
- // "header" is not permitted as we expect user content to be a fragment and
- // not structural to this extent
-
- // "hgroup" is permitted and takes no attributes
- p.AllowElements("hgroup")
-
- /////////////////////////////////////
- // Content grouping and separating //
- /////////////////////////////////////
-
- // "blockquote" is permitted, including the "cite" attribute which must be
- // a standard URL.
- p.AllowAttrs("cite").OnElements("blockquote")
-
- // "br" "div" "hr" "p" "span" "wbr" are permitted and take no attributes
- p.AllowElements("br", "div", "hr", "p", "span", "wbr")
-
- ///////////
- // Links //
- ///////////
-
- // "a" is permitted
- p.AllowAttrs("href").OnElements("a")
-
- // "area" is permitted along with the attributes that map image maps work
- p.AllowAttrs("name").Matching(
- regexp.MustCompile(`^([\p{L}\p{N}_-]+)$`),
- ).OnElements("map")
- p.AllowAttrs("alt").Matching(Paragraph).OnElements("area")
- p.AllowAttrs("coords").Matching(
- regexp.MustCompile(`^([0-9]+,)+[0-9]+$`),
- ).OnElements("area")
- p.AllowAttrs("href").OnElements("area")
- p.AllowAttrs("rel").Matching(SpaceSeparatedTokens).OnElements("area")
- p.AllowAttrs("shape").Matching(
- regexp.MustCompile(`(?i)^(default|circle|rect|poly)$`),
- ).OnElements("area")
- p.AllowAttrs("usemap").Matching(
- regexp.MustCompile(`(?i)^#[\p{L}\p{N}_-]+$`),
- ).OnElements("img")
-
- // "link" is not permitted
-
- /////////////////////
- // Phrase elements //
- /////////////////////
-
- // The following are all inline phrasing elements
- p.AllowElements("abbr", "acronym", "cite", "code", "dfn", "em",
- "figcaption", "mark", "s", "samp", "strong", "sub", "sup", "var")
-
- // "q" is permitted and "cite" is a URL and handled by URL policies
- p.AllowAttrs("cite").OnElements("q")
-
- // "time" is permitted
- p.AllowAttrs("datetime").Matching(ISO8601).OnElements("time")
-
- ////////////////////
- // Style elements //
- ////////////////////
-
- // block and inline elements that impart no semantic meaning but style the
- // document
- p.AllowElements("b", "i", "pre", "small", "strike", "tt", "u")
-
- // "style" is not permitted as we are not yet sanitising CSS and it is an
- // XSS attack vector
-
- //////////////////////
- // HTML5 Formatting //
- //////////////////////
-
- // "bdi" "bdo" are permitted
- p.AllowAttrs("dir").Matching(Direction).OnElements("bdi", "bdo")
-
- // "rp" "rt" "ruby" are permitted
- p.AllowElements("rp", "rt", "ruby")
-
- ///////////////////////////
- // HTML5 Change tracking //
- ///////////////////////////
-
- // "del" "ins" are permitted
- p.AllowAttrs("cite").Matching(Paragraph).OnElements("del", "ins")
- p.AllowAttrs("datetime").Matching(ISO8601).OnElements("del", "ins")
-
- ///////////
- // Lists //
- ///////////
-
- p.AllowLists()
-
- ////////////
- // Tables //
- ////////////
-
- p.AllowTables()
-
- ///////////
- // Forms //
- ///////////
-
- // By and large, forms are not permitted. However there are some form
- // elements that can be used to present data, and we do permit those
- //
- // "button" "fieldset" "input" "keygen" "label" "output" "select" "datalist"
- // "textarea" "optgroup" "option" are all not permitted
-
- // "meter" is permitted
- p.AllowAttrs(
- "value",
- "min",
- "max",
- "low",
- "high",
- "optimum",
- ).Matching(Number).OnElements("meter")
-
- // "progress" is permitted
- p.AllowAttrs("value", "max").Matching(Number).OnElements("progress")
-
- //////////////////////
- // Embedded content //
- //////////////////////
-
- // Vast majority not permitted
- // "audio" "canvas" "embed" "iframe" "object" "param" "source" "svg" "track"
- // "video" are all not permitted
-
- p.AllowImages()
-
- return p
- }
|