mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-10 05:20:28 +00:00
150 lines
5.9 KiB
Go
150 lines
5.9 KiB
Go
// Copyright 2024 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package markup
|
|
|
|
import (
|
|
"html/template"
|
|
"io"
|
|
"net/url"
|
|
"regexp"
|
|
|
|
"gitea.dev/modules/setting"
|
|
|
|
"github.com/microcosm-cc/bluemonday"
|
|
)
|
|
|
|
func (st *Sanitizer) createDefaultPolicy() *bluemonday.Policy {
|
|
policy := bluemonday.UGCPolicy()
|
|
|
|
// NOTICE: DO NOT add special "class" regexp rules here anymore, use RenderInternal.SafeAttr instead
|
|
|
|
// General safe SVG attributes
|
|
policy.AllowAttrs("viewBox", "width", "height", "aria-hidden", "data-attr-class").OnElements("svg")
|
|
policy.AllowAttrs("fill-rule", "d").OnElements("path")
|
|
|
|
// Checkboxes
|
|
policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
|
|
policy.AllowAttrs("checked", "disabled", "data-source-position").OnElements("input")
|
|
|
|
// Chroma always uses 1-2 letters for style names, we could tolerate it at the moment
|
|
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^\w{0,2}$`)).OnElements("span")
|
|
|
|
// Line numbers on codepreview
|
|
policy.AllowAttrs("data-line-number").OnElements("span")
|
|
|
|
// Custom URL-Schemes
|
|
if len(setting.Markdown.CustomURLSchemes) > 0 {
|
|
policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
|
|
} else {
|
|
policy.AllowURLSchemesMatching(st.allowAllRegex)
|
|
|
|
// Even if every scheme is allowed, these three are blocked for security reasons
|
|
disallowScheme := func(*url.URL) bool {
|
|
return false
|
|
}
|
|
policy.AllowURLSchemeWithCustomPolicy("javascript", disallowScheme)
|
|
policy.AllowURLSchemeWithCustomPolicy("vbscript", disallowScheme)
|
|
policy.AllowURLSchemeWithCustomPolicy("data", disallowScheme)
|
|
}
|
|
|
|
// Allow classes for org mode list item status.
|
|
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(unchecked|checked|indeterminate)$`)).OnElements("li")
|
|
|
|
// Allow 'color' and 'background-color' properties for the style attribute on text elements.
|
|
policy.AllowStyles("color", "background-color").OnElements("div", "span", "p", "tr", "th", "td")
|
|
|
|
policy.AllowAttrs("src", "autoplay", "controls").OnElements("video")
|
|
|
|
// Native support of "<picture><source media=... srcset=...><img src=...></picture>"
|
|
// ATTENTION: it only works with "auto" theme, because "media" query doesn't work with the theme chosen by end user manually.
|
|
// For example: browser's color scheme is "dark", but end user chooses "light" theme. Maybe it needs JS to help to make it work.
|
|
policy.AllowAttrs("media", "srcset").OnElements("source")
|
|
|
|
policy.AllowAttrs("loading").OnElements("img")
|
|
|
|
// MathML Core (https://www.w3.org/TR/mathml-core/)
|
|
mathMLElements := []string{
|
|
"math",
|
|
// token elements
|
|
"mi", "mn", "mo", "mtext", "mspace", "ms",
|
|
// layout elements
|
|
"mrow", "mfrac", "msqrt", "mroot", "mstyle", "merror", "mpadded", "mphantom",
|
|
// scripting elements
|
|
"msub", "msup", "msubsup", "munder", "mover", "munderover", "mmultiscripts", "mprescripts", "none",
|
|
// tabular elements
|
|
"mtable", "mtr", "mtd",
|
|
// semantic annotations
|
|
"semantics", "annotation", "annotation-xml",
|
|
}
|
|
policy.AllowAttrs("display", "alttext").OnElements("math")
|
|
policy.AllowAttrs(
|
|
// global presentation attributes
|
|
"dir", "displaystyle", "mathbackground", "mathcolor", "mathsize", "mathvariant", "scriptlevel",
|
|
// operator attributes
|
|
"accent", "accentunder", "fence", "form", "largeop", "lspace", "maxsize", "minsize", "movablelimits", "rspace", "separator", "stretchy", "symmetric",
|
|
// space and padding attributes
|
|
"depth", "height", "voffset", "width",
|
|
// fraction attribute
|
|
"linethickness",
|
|
// table attributes
|
|
"columnalign", "columnlines", "columnspacing", "frame", "framespacing", "rowalign", "rowlines", "rowspacing",
|
|
// cell attributes
|
|
"columnspan",
|
|
// annotation attribute
|
|
"encoding",
|
|
).OnElements(mathMLElements...)
|
|
|
|
// Allow generally safe attributes (reference: https://github.com/jch/html-pipeline)
|
|
generalSafeAttrs := []string{
|
|
"abbr", "accept", "accept-charset",
|
|
"accesskey", "action", "align", "alt",
|
|
"aria-describedby", "aria-hidden", "aria-label", "aria-labelledby",
|
|
"axis", "border", "cellpadding", "cellspacing", "char",
|
|
"charoff", "charset", "checked",
|
|
"clear", "cols", "colspan", "color",
|
|
"compact", "coords", "datetime", "dir",
|
|
"disabled", "enctype", "for", "frame",
|
|
"headers", "height", "hreflang",
|
|
"hspace", "ismap", "label", "lang",
|
|
"maxlength", "media", "method",
|
|
"multiple", "name", "nohref", "noshade",
|
|
"nowrap", "open", "prompt", "readonly", "rel", "rev",
|
|
"rows", "rowspan", "rules", "scope",
|
|
"selected", "shape", "size", "span",
|
|
"start", "summary", "tabindex", "target",
|
|
"title", "type", "usemap", "valign", "value",
|
|
"vspace", "width", "itemprop", "itemscope", "itemtype",
|
|
"data-markdown-generated-content", "data-attr-class",
|
|
}
|
|
generalSafeElements := []string{
|
|
"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "center", "i", "strong", "em", "a", "pre", "code", "img", "tt",
|
|
"div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label",
|
|
"dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary",
|
|
"details", "caption", "figure", "figcaption",
|
|
"abbr", "bdo", "cite", "dfn", "mark", "small", "span", "time", "video", "wbr",
|
|
"picture", "source",
|
|
}
|
|
// FIXME: Need to handle longdesc in img but there is no easy way to do it
|
|
policy.AllowAttrs(generalSafeAttrs...).OnElements(generalSafeElements...)
|
|
|
|
// Custom keyword markup
|
|
defaultSanitizer.addSanitizerRules(policy, setting.ExternalSanitizerRules)
|
|
|
|
return policy
|
|
}
|
|
|
|
// Sanitize use default sanitizer policy to sanitize a string
|
|
func Sanitize(s string) template.HTML {
|
|
return template.HTML(GetDefaultSanitizer().defaultPolicy.Sanitize(s))
|
|
}
|
|
|
|
// SanitizeReader sanitizes a Reader
|
|
func SanitizeReader(r io.Reader, renderer string, w io.Writer) error {
|
|
policy, exist := GetDefaultSanitizer().rendererPolicies[renderer]
|
|
if !exist {
|
|
policy = GetDefaultSanitizer().defaultPolicy
|
|
}
|
|
return policy.SanitizeReaderToWriter(r, w)
|
|
}
|