diff options
| author | Taras Madan <tarasmadan@google.com> | 2025-01-22 16:07:17 +0100 |
|---|---|---|
| committer | Taras Madan <tarasmadan@google.com> | 2025-01-23 10:42:36 +0000 |
| commit | 7b4377ad9d8a7205416df8d6217ef2b010f89481 (patch) | |
| tree | e6fec4fd12ff807a16d847923f501075bf71d16c /vendor/github.com/google/safehtml | |
| parent | 475a4c203afb8b7d3af51c4fd32bb170ff32a45e (diff) | |
vendor: delete
Diffstat (limited to 'vendor/github.com/google/safehtml')
32 files changed, 0 insertions, 5573 deletions
diff --git a/vendor/github.com/google/safehtml/CONTRIBUTING.md b/vendor/github.com/google/safehtml/CONTRIBUTING.md deleted file mode 100644 index 22b241cb7..000000000 --- a/vendor/github.com/google/safehtml/CONTRIBUTING.md +++ /dev/null @@ -1,29 +0,0 @@ -# How to Contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement (CLA). You (or your employer) retain the copyright to your -contribution; this simply gives us permission to use and redistribute your -contributions as part of the project. Head over to -<https://cla.developers.google.com/> to see your current agreements on file or -to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult -[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more -information on using pull requests. - -## Community Guidelines - -This project follows -[Google's Open Source Community Guidelines](https://opensource.google/conduct/). diff --git a/vendor/github.com/google/safehtml/LICENSE b/vendor/github.com/google/safehtml/LICENSE deleted file mode 100644 index dec93b16e..000000000 --- a/vendor/github.com/google/safehtml/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2017 The Go Authors. 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 Google LLC 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 -OWNER 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.
\ No newline at end of file diff --git a/vendor/github.com/google/safehtml/README.md b/vendor/github.com/google/safehtml/README.md deleted file mode 100644 index d3c9676d1..000000000 --- a/vendor/github.com/google/safehtml/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Safe HTML for Go - -`safehtml` provides immutable string-like types that wrap web types such as -HTML, JavaScript and CSS. These wrappers are safe by construction against XSS -and similar web vulnerabilities, and they can only be interpolated in safe ways. -You can read more about our approach to web security in our -[whitepaper](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/42934.pdf), -or this [OWASP talk](https://www.youtube.com/watch?v=ccfEu-Jj0as). - -Additional subpackages provide APIs for managing exceptions to the -safety rules, and a template engine with a syntax and interface that closely -matches [`html/template`](https://golang.org/pkg/html/template/). You can refer -to the [godoc](https://pkg.go.dev/github.com/google/safehtml?tab=doc) -for each (sub)package for the API documentation and code examples. -More end-to-end demos are available in `example_test.go`. - -This is not an officially supported Google product. diff --git a/vendor/github.com/google/safehtml/doc.go b/vendor/github.com/google/safehtml/doc.go deleted file mode 100644 index 4c5c1bf78..000000000 --- a/vendor/github.com/google/safehtml/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Package safehtml provides immutable string-like types which represent values that -// are guaranteed to be safe, by construction or by escaping or sanitization, to use -// in various HTML contexts and with various DOM APIs. -// -package safehtml diff --git a/vendor/github.com/google/safehtml/html.go b/vendor/github.com/google/safehtml/html.go deleted file mode 100644 index 27c0f337d..000000000 --- a/vendor/github.com/google/safehtml/html.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "bytes" - "html" - "unicode" - - "golang.org/x/text/unicode/rangetable" -) - -// An HTML is an immutable string-like type that is safe to use in HTML -// contexts in DOM APIs and HTML documents. -// -// HTML guarantees that its value as a string will not cause untrusted script -// execution when evaluated as HTML in a browser. -// -// Values of this type are guaranteed to be safe to use in HTML contexts, -// such as assignment to the innerHTML DOM property, or interpolation into an -// HTML template in HTML PC_DATA context, in the sense that the use will not -// result in a Cross-site Scripting (XSS) vulnerability. -type HTML struct { - // We declare an HTML not as a string but as a struct wrapping a string - // to prevent construction of HTML values through string conversion. - str string -} - -// HTMLer is implemented by any value that has an HTML method, which defines the -// safe HTML format for that value. -type HTMLer interface { - HTML() HTML -} - -// HTMLEscaped returns an HTML whose value is text, with the characters [&<>"'] escaped. -// -// text is coerced to interchange valid, so the resulting HTML contains only -// valid UTF-8 characters which are legal in HTML and XML. -// -func HTMLEscaped(text string) HTML { - return HTML{escapeAndCoerceToInterchangeValid(text)} -} - -// HTMLConcat returns an HTML which contains, in order, the string representations -// of the given htmls. -func HTMLConcat(htmls ...HTML) HTML { - var b bytes.Buffer - for _, html := range htmls { - b.WriteString(html.String()) - } - return HTML{b.String()} -} - -// String returns the string form of the HTML. -func (h HTML) String() string { - return h.str -} - -// escapeAndCoerceToInterchangeValid coerces the string to interchange-valid -// UTF-8 and then HTML-escapes it. -func escapeAndCoerceToInterchangeValid(str string) string { - return html.EscapeString(coerceToUTF8InterchangeValid(str)) -} - -// coerceToUTF8InterchangeValid coerces a string to interchange-valid UTF-8. -// Illegal UTF-8 bytes are replaced with the Unicode replacement character -// ('\uFFFD'). C0 and C1 control codes (other than CR LF HT FF) and -// non-characters are also replaced with the Unicode replacement character. -func coerceToUTF8InterchangeValid(s string) string { - // TODO: Replace this entire function with stdlib function if https://golang.org/issue/25805 gets addressed. - runes := make([]rune, 0, len(s)) - // If s contains any invalid UTF-8 byte sequences, range will have rune - // contain the Unicode replacement character and there's no need to call - // utf8.ValidRune. I.e. iteration over the string implements - // CoerceToStructurallyValid() from C++/Java. - // See https://blog.golang.org/strings. - for _, rune := range s { - if unicode.Is(controlAndNonCharacter, rune) { - runes = append(runes, unicode.ReplacementChar) - } else { - runes = append(runes, rune) - } - } - return string(runes) -} - -// controlAndNonCharacters contains the non-interchange-valid codepoints. -// -// See http://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream -// -// safehtml functions do a lot of lookups on these tables, so merging them is probably -// worth it to avoid comparing against both tables each time. -var controlAndNonCharacter = rangetable.Merge(unicode.Noncharacter_Code_Point, controlChar) - -// controlChar contains Unicode control characters disallowed in interchange -// valid UTF-8. This table is slightly different from unicode.Cc: -// - Disallows null. -// - Allows LF, CR, HT, and FF. -// -// unicode.C is mentioned in unicode.IsControl; it contains "special" characters -// which includes at least control characters, surrogate code points, and -// formatting codepoints (e.g. word joiner). We don't need to exclude all of -// those. In particular, surrogates are handled by the for loop converting -// invalid UTF-8 byte sequences to the Unicode replacement character. -var controlChar = &unicode.RangeTable{ - R16: []unicode.Range16{ - {0x0000, 0x0008, 1}, - {0x000B, 0x000B, 1}, - {0x000E, 0x001F, 1}, - {0x007F, 0x009F, 1}, - }, - LatinOffset: 4, -} diff --git a/vendor/github.com/google/safehtml/identifier.go b/vendor/github.com/google/safehtml/identifier.go deleted file mode 100644 index ffad26423..000000000 --- a/vendor/github.com/google/safehtml/identifier.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "fmt" - "regexp" -) - -// A Identifier is an immutable string-like type that is safe to use in HTML -// contexts as an identifier for HTML elements. For example, it is unsafe to -// insert an untrusted string into a -// -// <img name="..."></img> -// -// context since the string may be controlled by an attacker who can assign it -// a value that masks existing DOM properties (i.e. DOM Clobbering). An -// attacker may also be able to force legitimate Javascript code, which uses -// document.getElementsByName(...) to read DOM elements, to refer to this -// element. This may lead to unintended side effects, particularly if that -// element contains attacker-controlled data. It is, however, safe to use an -// Identifier in this context since its value is known to be partially or fully -// under application control. -// -// In order to ensure that an attacker cannot influence the Identifier value, -// an Identifier can only be instantiated from a compile-time constant string -// literal prefix. -// -// Note that Identifier is Go-specific and therefore does not have a Proto form -// for cross-language use. -type Identifier struct { - // We declare a Identifier not as a string but as a struct wrapping a string - // to prevent construction of Identifier values through string conversion. - str string -} - -// To minimize the risk of parsing errors, Identifier values must start with an -// alphabetical rune, and comprise of only alphanumeric, '-', and '_' runes. - -// startsWithAlphabetPattern matches strings that start with an alphabetical rune. -var startsWithAlphabetPattern = regexp.MustCompile(`^[a-zA-Z]`) - -// onlyAlphanumericsOrHyphenPattern matches strings that only contain alphanumeric, -// '-' and '_' runes. -var onlyAlphanumericsOrHyphenPattern = regexp.MustCompile(`^[-_a-zA-Z0-9]*$`) - -// IdentifierFromConstant constructs an Identifier with its underlying identifier -// set to the given string value, which must be an untyped string constant. It -// panics if value does not start with an alphabetic rune or contains any -// non-alphanumeric runes other than '-' and '_'. -func IdentifierFromConstant(value stringConstant) Identifier { - if !startsWithAlphabetPattern.MatchString(string(value)) || - !onlyAlphanumericsOrHyphenPattern.MatchString(string(value)) { - panic(fmt.Sprintf("invalid identifier %q", string(value))) - } - return Identifier{string(value)} -} - -// IdentifierFromConstantPrefix constructs an Identifier with its underlying string -// set to the string formed by joining prefix, which must be an untyped string -// constant, and value with a hyphen. It panics if prefix or value contain any -// non-alphanumeric runes other than '-' and '_', or if prefix does not start with -// an alphabetic rune. -func IdentifierFromConstantPrefix(prefix stringConstant, value string) Identifier { - prefixString := string(prefix) - if !startsWithAlphabetPattern.MatchString(string(prefix)) || - !onlyAlphanumericsOrHyphenPattern.MatchString(string(prefix)) { - panic(fmt.Sprintf("invalid prefix %q", string(prefix))) - } - if !onlyAlphanumericsOrHyphenPattern.MatchString(value) { - panic(fmt.Sprintf("value %q contains non-alphanumeric runes", value)) - } - return Identifier{prefixString + "-" + value} -} - -// String returns the string form of the Identifier. -func (i Identifier) String() string { - return i.str -} diff --git a/vendor/github.com/google/safehtml/init.go b/vendor/github.com/google/safehtml/init.go deleted file mode 100644 index d37547d72..000000000 --- a/vendor/github.com/google/safehtml/init.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "github.com/google/safehtml/internal/raw" -) - -// stringConstant is an unexported string type. Users of this package cannot -// create values of this type except by passing an untyped string constant to -// functions which expect a stringConstant. This type should only be used in -// function and method parameters. -type stringConstant string - -// The following functions are used by package uncheckedconversions -// (via package raw) to create safe HTML types from plain strings. - -func htmlRaw(s string) HTML { - return HTML{s} -} - -func scriptRaw(s string) Script { - return Script{s} -} - -func style(s string) Style { - return Style{s} -} - -func styleSheetRaw(s string) StyleSheet { - return StyleSheet{s} -} - -func urlRaw(s string) URL { - return URL{s} -} - -func trustedResourceURLRaw(s string) TrustedResourceURL { - return TrustedResourceURL{s} -} - -func identifierRaw(s string) Identifier { - return Identifier{s} -} - -func init() { - raw.HTML = htmlRaw - raw.Script = scriptRaw - raw.Style = style - raw.StyleSheet = styleSheetRaw - raw.URL = urlRaw - raw.TrustedResourceURL = trustedResourceURLRaw - raw.Identifier = identifierRaw -} diff --git a/vendor/github.com/google/safehtml/internal/raw/raw.go b/vendor/github.com/google/safehtml/internal/raw/raw.go deleted file mode 100644 index 3bedb6a6d..000000000 --- a/vendor/github.com/google/safehtml/internal/raw/raw.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Package raw provides a coordination point for package safehtml, package -// uncheckedconversions, package legacyconversions, and package testconversions. -// raw must only be imported by these four packages. -package raw - -// HTML is the raw constructor for a safehtml.HTML. -var HTML interface{} - -// Script is the raw constructor for a safehtml.Script. -var Script interface{} - -// Style is the raw constructor for a safehtml.Style. -var Style interface{} - -// StyleSheet is the raw constructor for a safehtml.StyleSheet. -var StyleSheet interface{} - -// URL is the raw constructor for a safehtml.URL. -var URL interface{} - -// TrustedResourceURL is the raw constructor for a safehtml.TrustedResourceURL. -var TrustedResourceURL interface{} - -// Identifier is the raw constructor for a safehtml.Identifier. -var Identifier interface{} diff --git a/vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go b/vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go deleted file mode 100644 index dd8e7fe36..000000000 --- a/vendor/github.com/google/safehtml/internal/safehtmlutil/safehtmlutil.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Package safehtmlutil contains functions shared by package safehtml and safehtml/template. -package safehtmlutil - -import ( - "bytes" - "fmt" - "reflect" - "regexp" -) - -// IsSafeTrustedResourceURLPrefix returns whether the given prefix is safe to use as a -// TrustedResourceURL prefix. -// -// TrustedResourceURL prefixes must start with one of the following: -// * `https://<origin>/` -// * `//<origin>/` -// * `/<pathStart>` -// * `about:blank#` -// -// `<origin>` must contain only alphanumerics, '.', ':', '[', ']', or '-'. -// These restrictions do not enforce a well-formed domain name, so '.' and '1.2' are valid. -// -// `<pathStart>` is any character except `/` and `\`. Based on -// https://url.spec.whatwg.org/commit-snapshots/56b74ce7cca8883eab62e9a12666e2fac665d03d/#url-parsing, -// an initial / which is not followed by another / or \ will end up in the "path state" and from there -// it can only go to the "fragment state" and "query state". -func IsSafeTrustedResourceURLPrefix(prefix string) bool { - return safeTrustedResourceURLPrefixPattern.MatchString(prefix) -} - -var safeTrustedResourceURLPrefixPattern = regexp.MustCompile(`(?i)^(?:` + - `(?:https:)?//[0-9a-z.:\[\]-]+/|` + - `/[^/\\]|` + - `about:blank#)`) - -// URLContainsDoubleDotSegment returns whether the given URL or URL substring -// contains the double dot-segment ".." (RFC3986 3.3) in its percent-encoded or -// unencoded form. -func URLContainsDoubleDotSegment(url string) bool { - return urlDoubleDotSegmentPattern.MatchString(url) -} - -var urlDoubleDotSegmentPattern = regexp.MustCompile(`(?i)(?:\.|%2e)(?:\.|%2e)`) - -// QueryEscapeURL produces an output that can be embedded in a URL query. -// The output can be embedded in an HTML attribute without further escaping. -func QueryEscapeURL(args ...interface{}) string { - return urlProcessor(false, Stringify(args...)) -} - -// NormalizeURL normalizes URL content so it can be embedded in a quote-delimited -// string or parenthesis delimited url(...). -// The normalizer does not encode all HTML specials. Specifically, it does not -// encode '&' so correct embedding in an HTML attribute requires escaping of -// '&' to '&'. -func NormalizeURL(args ...interface{}) string { - return urlProcessor(true, Stringify(args...)) -} - -// urlProcessor normalizes (when norm is true) or escapes its input to produce -// a valid hierarchical or opaque URL part. -func urlProcessor(norm bool, s string) string { - var b bytes.Buffer - written := 0 - // The byte loop below assumes that all URLs use UTF-8 as the - // content-encoding. This is similar to the URI to IRI encoding scheme - // defined in section 3.1 of RFC 3987, and behaves the same as the - // EcmaScript builtin encodeURIComponent. - // It should not cause any misencoding of URLs in pages with - // Content-type: text/html;charset=UTF-8. - for i, n := 0, len(s); i < n; i++ { - c := s[i] - switch c { - // Single quote and parens are sub-delims in RFC 3986, but we - // escape them so the output can be embedded in single - // quoted attributes and unquoted CSS url(...) constructs. - // Single quotes are reserved in URLs, but are only used in - // the obsolete "mark" rule in an appendix in RFC 3986 - // so can be safely encoded. - case '!', '#', '$', '&', '*', '+', ',', '/', ':', ';', '=', '?', '@', '[', ']': - if norm { - continue - } - // Unreserved according to RFC 3986 sec 2.3 - // "For consistency, percent-encoded octets in the ranges of - // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), - // period (%2E), underscore (%5F), or tilde (%7E) should not be - // created by URI producers - case '-', '.', '_', '~': - continue - case '%': - // When normalizing do not re-encode valid escapes. - if norm && i+2 < len(s) && isHex(s[i+1]) && isHex(s[i+2]) { - continue - } - default: - // Unreserved according to RFC 3986 sec 2.3 - if 'a' <= c && c <= 'z' { - continue - } - if 'A' <= c && c <= 'Z' { - continue - } - if '0' <= c && c <= '9' { - continue - } - } - b.WriteString(s[written:i]) - fmt.Fprintf(&b, "%%%02x", c) - written = i + 1 - } - if written == 0 { - return s - } - b.WriteString(s[written:]) - return b.String() -} - -// isHex reports whether the given character is a hex digit. -func isHex(c byte) bool { - return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' -} - -// Stringify converts its arguments to a string. It is equivalent to -// fmt.Sprint(args...), except that it deferences all pointers. -func Stringify(args ...interface{}) string { - // Optimization for simple common case of a single string argument. - if len(args) == 1 { - if s, ok := args[0].(string); ok { - return s - } - } - for i, arg := range args { - args[i] = indirectToStringerOrError(arg) - } - return fmt.Sprint(args...) -} - -var ( - errorType = reflect.TypeOf((*error)(nil)).Elem() - fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() -) - -// indirectToStringerOrError dereferences a as many times -// as necessary to reach the base type, an implementation of fmt.Stringer, -// or an implementation of error, and returns a value of that type. It returns -// nil if a is nil. -func indirectToStringerOrError(a interface{}) interface{} { - if a == nil { - return nil - } - v := reflect.ValueOf(a) - for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - return v.Interface() -} - -// Indirect returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil). -func Indirect(a interface{}) interface{} { - if a == nil { - return nil - } - if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr { - // Avoid creating a reflect.Value if it's not a pointer. - return a - } - v := reflect.ValueOf(a) - for v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - return v.Interface() -} diff --git a/vendor/github.com/google/safehtml/internal/template/raw/raw.go b/vendor/github.com/google/safehtml/internal/template/raw/raw.go deleted file mode 100644 index b69599bd2..000000000 --- a/vendor/github.com/google/safehtml/internal/template/raw/raw.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Package raw provides a coordination point for package safehtml/template and -// package safehtml/template/uncheckedconversions. raw must be imported only by -// these two packages. -package raw - -// TrustedSource is the raw constructor for a template.TrustedSource. -var TrustedSource interface{} - -// TrustedTemplate is the raw constructor for a template.TrustedTemplate. -var TrustedTemplate interface{} diff --git a/vendor/github.com/google/safehtml/script.go b/vendor/github.com/google/safehtml/script.go deleted file mode 100644 index c9e0fd298..000000000 --- a/vendor/github.com/google/safehtml/script.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "encoding/json" - "fmt" - "regexp" -) - -// A Script is an immutable string-like type which represents JavaScript -// code and guarantees that its value, as a string, will not cause execution -// of unconstrained attacker controlled code (cross-site scripting) when -// evaluated as JavaScript in a browser. -// -// Script's string representation can safely be interpolated as the -// content of a script element within HTML, and can safely be passed to DOM -// properties and functions which expect JavaScript. In these cases, the Script -// string should not be escaped. Script's string representation can also be safely -// used as the value for on* attribute handlers in HTML, though the Script string -// must be escaped before such use. -// -// Note that the Script might contain text that is attacker-controlled but -// that text should have been interpolated with appropriate escaping, -// sanitization and/or validation into the right location in the script, such -// that it is highly constrained in its effect (for example, it had to match a -// set of allowed words). -// -// In order to ensure that an attacker cannot influence the Script -// value, a Script can only be instantiated from compile-time -// constant string literals or security-reviewed unchecked conversions, -// but never from arbitrary string values potentially representing untrusted -// user input. -type Script struct { - // We declare a Script not as a string but as a struct wrapping a string - // to prevent construction of Script values through string conversion. - str string -} - -// ScriptFromConstant constructs a Script with its underlying script set -// to the given script, which must be an untyped string constant. -// -// No runtime validation or sanitization is performed on script; being under -// application control, it is simply assumed to comply with the Script -// contract. -func ScriptFromConstant(script stringConstant) Script { - return Script{string(script)} -} - -// ScriptFromDataAndConstant constructs a Script of the form -// -// var name = data; script -// -// where name is the supplied variable name, data is the supplied data value -// encoded as JSON using encoding/json.Marshal, and script is the supplied -// JavaScript statement or sequence of statements. The supplied name and script -// must both be untyped string constants. It returns an error if name is not a -// valid Javascript identifier or JSON encoding fails. -// -// No runtime validation or sanitization is performed on script; being under -// application control, it is simply assumed to comply with the Script -// contract. -func ScriptFromDataAndConstant(name stringConstant, data interface{}, script stringConstant) (Script, error) { - if !jsIdentifierPattern.MatchString(string(name)) { - return Script{}, fmt.Errorf("variable name %q is an invalid Javascript identifier", string(name)) - } - json, err := json.Marshal(data) - if err != nil { - return Script{}, err - } - return Script{fmt.Sprintf("var %s = %s;\n%s", name, json, string(script))}, nil -} - -// jsIdentifierPattern matches strings that are valid Javascript identifiers. -// -// This pattern accepts only a subset of valid identifiers defined in -// https://tc39.github.io/ecma262/#sec-names-and-keywords. In particular, -// it does not match identifiers that contain non-ASCII letters, Unicode -// escape sequences, and the Unicode format-control characters -// \u200C (zero-width non-joiner) and \u200D (zero-width joiner). -var jsIdentifierPattern = regexp.MustCompile(`^[$_a-zA-Z][$_a-zA-Z0-9]+$`) - -// String returns the string form of the Script. -func (s Script) String() string { - return s.str -} diff --git a/vendor/github.com/google/safehtml/style.go b/vendor/github.com/google/safehtml/style.go deleted file mode 100644 index c11ac9d96..000000000 --- a/vendor/github.com/google/safehtml/style.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "bytes" - "fmt" - "regexp" - "strings" -) - -// A Style is an immutable string-like type which represents a sequence of CSS -// declarations (property_name1: property_value1; property_name2: property_value2; ...) -// and guarantees that its value will not cause untrusted script execution -// (cross-site scripting) when evaluated as CSS in a browser. -// -// Style's string representation can safely be: -// * Interpolated as the content of a quoted HTML style attribute. However, the -// Style string must be HTML-attribute-escaped before interpolation. -// * Interpolated as the content of a {}-wrapped block within a StyleSheet. -// '<' runes in the Style string must be CSS-escaped before interpolation. -// The Style string is also guaranteed not to be able to introduce new -// properties or elide existing ones. -// * Interpolated as the content of a {}-wrapped block within an HTML <style> -// element. '<' runes in the Style string must be CSS-escaped before interpolation. -// * Assigned to the style property of a DOM node. The Style string should not -// be escaped before being assigned to the property. -// -// In addition, values of this type are composable, that is, for any two Style -// values |style1| and |style2|, style1.style() + style2.style() is itself a -// value that satisfies the Style type constraint. -type Style struct { - // We declare a Style not as a string but as a struct wrapping a string - // to prevent construction of Style values through string conversion. - str string -} - -// StyleFromConstant constructs a Style with its underlying style set to the -// given style, which must be an untyped string constant, and panics if the -// style string does not pass basic syntax checks. -// -// Users of this function must ensure themselves that the style: -// * Does not contain unsafe CSS. -// * Does not contain literal angle brackets. Otherwise, it could be unsafe to -// place a Style into the contents of a <style> element where it can't be -// HTML escaped (see http://www.w3.org/International/questions/qa-escapes). -// For example, if the Style containing -// "font: 'foo <style/><script>evil</script>'" was interpolated within a -// <style> tag, it would then break out of the style context into HTML. -// * Does not end in a property value or property name context. -// For example, a value of "background:url(\"" or "font-" does not satisfy -// the Style type contract. This rule is enforced to ensure composability: -// concatenating two incomplete strings that themselves do not contain unsafe -// CSS can result in an overall string that does. For example, if -// "javascript:evil())\"" is appended to "background:url(\"", the resulting -// string may result in the execution of a malicious script. -// -// The style may, however, contain literal single or double quotes (for example, -// in the "content" property). Therefore, the entire style string must be -// escaped when used in a style attribute. -// -// The following example values comply with Style's type contract: -// width: 1em; -// height:1em; -// width: 1em;height: 1em; -// background:url('http://url'); -// -// In addition, the empty string is safe for use in a style attribute. -// -// The following example values do NOT comply with this type's contract: -// background: red --- missing a trailing semi-colon -// background: --- missing a value and a trailing semi-colon -// 1em --- missing an attribute name, which provides context -// for the value -// -// See also http://www.w3.org/TR/css3-syntax/. -func StyleFromConstant(style stringConstant) Style { - // TODO: implement UTF-8 interchange-validity checks and blocking of newlines - // (including Unicode ones) and other whitespace characters (\t, \f) for Style and other safe types - // in this package. - if strings.ContainsAny(string(style), "<>") { - panic(fmt.Sprintf("style string %q contains angle brackets", style)) - } - if !strings.HasSuffix(string(style), ";") { - panic(fmt.Sprintf("style string %q must end with ';'", style)) - } - if !strings.Contains(string(style), ":") { - panic(fmt.Sprintf("style string %q must contain at least one ':' to specify a property-value pair", style)) - } - return Style{string(style)} -} - -// String returns the string form of the Style. -func (s Style) String() string { - return s.str -} - -// StyleProperties contains property values for CSS properties whose names are -// the hyphen-separated form of the field names. These values will be validated -// by StyleFromProperties before being included in a Style. -// -// For example, BackgroundPosition contains the value for the -// "background-position" property, and Display contains the value for the "display" -// property. -// -type StyleProperties struct { - // BackgroundImageURLs contains URL values for the background-image property. - // These values val_1, val_2, ..., val_n will be passed through URLSanitized and CSS-escaped in - // StyleFromProperties, then interpolated into to a comma-separated list of CSS URLs of the form - // url("val_1"), url("val_2"), ..., url("val_n") - // See https://www.w3.org/TR/CSS2/syndata.html#value-def-uri and https://drafts.csswg.org/css-backgrounds-3/#layering. - BackgroundImageURLs []string - // FontFamily values are used, comma-separated, as the font-family property. - // * Names starting with a Latin alphabet runes and containing only Latin alphabets and hyphens will be included unquoted. - // * Names enclosed in double quote literals (e.g. `"21st Century"`) will be CSS-escaped without the outermost quotes, - // then included within double quotes. - // * All other names will be CSS-escaped, and included within double quotes. - // See https://drafts.csswg.org/css-fonts-3/#font-family-prop. - FontFamily []string - // Display must consist of only ASCII alphabetic or '-' runes. - // Non-conforming values will be replaced by InnocuousPropertyValue in - // StyleFromProperties. - Display string - // The following values can only contain allowed runes, that is, alphanumerics, - // space, tab, and the set [+-.!#%_/*]. In addition, comment markers "//", "/*", - // and "*/" are disallowed. Non-conforming values will be replaced by - // InnocuousPropertyValue in StyleFromProperties. - BackgroundColor string - BackgroundPosition string - BackgroundRepeat string - BackgroundSize string - Color string - Height string - Width string - Left string - Right string - Top string - Bottom string - FontWeight string - Padding string - // Note: this property might allow clickjacking, but the risk is limited without - // the ability to set the position property to "absolute" or "fixed". - ZIndex string -} - -// identifierPattern matches a subset of valid <ident-token> values defined in -// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram. This pattern matches all generic family name -// keywords defined in https://drafts.csswg.org/css-fonts-3/#family-name-value. -var identifierPattern = regexp.MustCompile(`^[a-zA-Z][-a-zA-Z]+$`) - -// StyleFromProperties constructs a Style containining properties whose values -// are set in properties. The contents of the returned Style will be of the form -// property_1:val_1;property2:val_2; ... ;property_n:val_n; -// This syntax is defined in https://www.w3.org/TR/css-style-attr/. -// -// All property values are validated and, if necessary, modified to ensure that their -// inclusion in a HTML style attribute does not result in untrusted script execution, -// the addition of new properties, or the removal of existing properties. Please refer -// to the StyleProperties documentation for validation rules. -// -// The constructed Style is guaranteed to fulfill its type contract, but is not -// guaranteed to be semantically valid CSS. -func StyleFromProperties(properties StyleProperties) Style { - // TODO: if this boilerplate code grows large, consider generating property names from Field names using reflection. - var buf bytes.Buffer - if len(properties.BackgroundImageURLs) > 0 { - buf.WriteString("background-image:") - for i, url := range properties.BackgroundImageURLs { - if i > 0 { - buf.WriteString(", ") - } - fmt.Fprintf(&buf, "url(\"%s\")", cssEscapeString(URLSanitized(url).String())) - } - buf.WriteString(";") - } - if len(properties.FontFamily) > 0 { - buf.WriteString("font-family:") - for i, name := range properties.FontFamily { - if i > 0 { - buf.WriteString(", ") - } - if identifierPattern.MatchString(name) { - buf.WriteString(name) - continue - } - unescaped := name - if len(name) >= 3 && strings.HasPrefix(name, `"`) && strings.HasSuffix(name, `"`) { - unescaped = name[1 : len(name)-1] - } - fmt.Fprintf(&buf, `"%s"`, cssEscapeString(unescaped)) - } - buf.WriteByte(';') - } - if properties.Display != "" { - fmt.Fprintf(&buf, "display:%s;", filter(properties.Display, safeEnumPropertyValuePattern)) - } - if properties.BackgroundColor != "" { - fmt.Fprintf(&buf, "background-color:%s;", filter(properties.BackgroundColor, safeRegularPropertyValuePattern)) - } - if properties.BackgroundPosition != "" { - fmt.Fprintf(&buf, "background-position:%s;", filter(properties.BackgroundPosition, safeRegularPropertyValuePattern)) - } - if properties.BackgroundRepeat != "" { - fmt.Fprintf(&buf, "background-repeat:%s;", filter(properties.BackgroundRepeat, safeRegularPropertyValuePattern)) - } - if properties.BackgroundSize != "" { - fmt.Fprintf(&buf, "background-size:%s;", filter(properties.BackgroundSize, safeRegularPropertyValuePattern)) - } - if properties.Color != "" { - fmt.Fprintf(&buf, "color:%s;", filter(properties.Color, safeRegularPropertyValuePattern)) - } - if properties.Height != "" { - fmt.Fprintf(&buf, "height:%s;", filter(properties.Height, safeRegularPropertyValuePattern)) - } - if properties.Width != "" { - fmt.Fprintf(&buf, "width:%s;", filter(properties.Width, safeRegularPropertyValuePattern)) - } - if properties.Left != "" { - fmt.Fprintf(&buf, "left:%s;", filter(properties.Left, safeRegularPropertyValuePattern)) - } - if properties.Right != "" { - fmt.Fprintf(&buf, "right:%s;", filter(properties.Right, safeRegularPropertyValuePattern)) - } - if properties.Top != "" { - fmt.Fprintf(&buf, "top:%s;", filter(properties.Top, safeRegularPropertyValuePattern)) - } - if properties.Bottom != "" { - fmt.Fprintf(&buf, "bottom:%s;", filter(properties.Bottom, safeRegularPropertyValuePattern)) - } - if properties.FontWeight != "" { - fmt.Fprintf(&buf, "font-weight:%s;", filter(properties.FontWeight, safeRegularPropertyValuePattern)) - } - if properties.Padding != "" { - fmt.Fprintf(&buf, "padding:%s;", filter(properties.Padding, safeRegularPropertyValuePattern)) - } - if properties.ZIndex != "" { - fmt.Fprintf(&buf, "z-index:%s;", filter(properties.ZIndex, safeRegularPropertyValuePattern)) - } - - return Style{buf.String()} -} - -// InnocuousPropertyValue is an innocuous property generated by filter when its input unsafe. -const InnocuousPropertyValue = "zGoSafezInvalidPropertyValue" - -// safeRegularPropertyValuePattern matches strings that are safe to use as property values. -// Specifically, it matches string where every '*' or '/' is followed by end-of-text or a safe rune -// (i.e. alphanumberics or runes in the set [+-.!#%_ \t]). This regex ensures that the following -// are disallowed: -// * "/*" and "*/", which are CSS comment markers. -// * "//", even though this is not a comment marker in the CSS specification. Disallowing -// this string minimizes the chance that browser peculiarities or parsing bugs will allow -// sanitization to be bypassed. -// * '(' and ')', which can be used to call functions. -// * ',', since it can be used to inject extra values into a property. -// * Runes which could be matched on CSS error recovery of a previously malformed token, such as '@' -// and ':'. See http://www.w3.org/TR/css3-syntax/#error-handling. -var safeRegularPropertyValuePattern = regexp.MustCompile(`^(?:[*/]?(?:[0-9a-zA-Z+-.!#%_ \t]|$))*$`) - -// safeEnumPropertyValuePattern matches strings that are safe to use as enumerated property values. -// Specifically, it matches strings that contain only alphabetic and '-' runes. -var safeEnumPropertyValuePattern = regexp.MustCompile(`^[a-zA-Z-]*$`) - -// filter returns value if it matches pattern. Otherwise, it returns InnocuousPropertyValue. -func filter(value string, pattern *regexp.Regexp) string { - if !pattern.MatchString(value) { - return InnocuousPropertyValue - } - return value -} - -// cssEscapeString escapes s so that it is safe to put between "" to form a CSS <string-token>. -// See syntax at https://www.w3.org/TR/css-syntax-3/#string-token-diagram. -// -// On top of the escape sequences required in <string-token>, this function also escapes -// control runes to minimize the risk of these runes triggering browser-specific bugs. -func cssEscapeString(s string) string { - var b bytes.Buffer - b.Grow(len(s)) - // TODO: consider optmizations (e.g. ranging over bytes, batching writes of contiguous sequences of unescaped runes) if - // performance becomes an issue. - for _, c := range s { - switch { - case c == '\u0000': - // Replace the NULL byte according to https://www.w3.org/TR/css-syntax-3/#input-preprocessing. - // We take this extra precaution in case the user agent fails to handle NULL properly. - b.WriteString("\uFFFD") - case c == '<', // Prevents breaking out of a style element with `</style>`. Escape this in case the Style user forgets to. - c == '"', c == '\\', // Must be CSS-escaped in <string-token>. U+000A line feed is handled in the next case. - c <= '\u001F', c == '\u007F', // C0 control codes - c >= '\u0080' && c <= '\u009F', // C1 control codes - c == '\u2028', c == '\u2029': // Unicode newline characters - // See CSS escape sequence syntax at https://www.w3.org/TR/css-syntax-3/#escape-diagram. - fmt.Fprintf(&b, "\\%06X", c) - default: - b.WriteRune(c) - } - } - return b.String() -} diff --git a/vendor/github.com/google/safehtml/stylesheet.go b/vendor/github.com/google/safehtml/stylesheet.go deleted file mode 100644 index 17de8a517..000000000 --- a/vendor/github.com/google/safehtml/stylesheet.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "container/list" - "fmt" - "regexp" - "strings" -) - -// A StyleSheet is an immutable string-like type which represents a CSS -// style sheet and guarantees that its value, as a string, will not cause -// untrusted script execution (cross-site scripting) when evaluated as CSS -// in a browser. -// -// StyleSheet's string representation can safely be interpolated as the -// content of a style element within HTML. The StyleSheet string should -// not be escaped before interpolation. -type StyleSheet struct { - // We declare a StyleSheet not as a string but as a struct wrapping a string - // to prevent construction of StyleSheet values through string conversion. - str string -} - -// StyleSheetFromConstant constructs a StyleSheet with the -// underlying stylesheet set to the given styleSheet, which must be an untyped string -// constant. -// -// No runtime validation or sanitization is performed on script; being under -// application control, it is simply assumed to comply with the StyleSheet -// contract. -func StyleSheetFromConstant(styleSheet stringConstant) StyleSheet { - return StyleSheet{string(styleSheet)} -} - -// CSSRule constructs a StyleSheet containng a CSS rule of the form: -// selector{style} -// It returns an error if selector contains disallowed characters or unbalanced -// brackets. -// -// The constructed StyleSheet value is guaranteed to fulfill its type contract, -// but is not guaranteed to be semantically valid CSS. -func CSSRule(selector string, style Style) (StyleSheet, error) { - if strings.ContainsRune(selector, '<') { - return StyleSheet{}, fmt.Errorf("selector %q contains '<'", selector) - } - selectorWithoutStrings := cssStringPattern.ReplaceAllString(selector, "") - if matches := invalidCSSSelectorRune.FindStringSubmatch(selectorWithoutStrings); matches != nil { - return StyleSheet{}, fmt.Errorf("selector %q contains %q, which is disallowed outside of CSS strings", selector, matches[0]) - } - if !hasBalancedBrackets(selectorWithoutStrings) { - return StyleSheet{}, fmt.Errorf("selector %q contains unbalanced () or [] brackets", selector) - } - return StyleSheet{fmt.Sprintf("%s{%s}", selector, style.String())}, nil -} - -var ( - // cssStringPattern matches a single- or double-quoted CSS string. - cssStringPattern = regexp.MustCompile( - `"([^"\r\n\f\\]|\\[\s\S])*"|` + // Double-quoted string literal - `'([^'\r\n\f\\]|\\[\s\S])*'`) // Single-quoted string literal - - // invalidCSSSelectorRune matches a rune that is not allowed in a CSS3 - // selector that does not contain string literals. - // See https://w3.org/TR/css3-selectors/#selectors. - invalidCSSSelectorRune = regexp.MustCompile(`[^-_a-zA-Z0-9#.:* ,>+~[\]()=^$|]`) -) - -// hasBalancedBrackets returns whether s has balanced () and [] brackets. -func hasBalancedBrackets(s string) bool { - stack := list.New() - for i := 0; i < len(s); i++ { - c := s[i] - if expected, ok := matchingBrackets[c]; ok { - e := stack.Back() - if e == nil { - return false - } - // Skip success check for this type assertion since it is trivial to - // see that only bytes are pushed onto this stack. - if v := e.Value.(byte); v != expected { - return false - } - stack.Remove(e) - continue - } - for _, openBracket := range matchingBrackets { - if c == openBracket { - stack.PushBack(c) - break - } - } - } - return stack.Len() == 0 -} - -// matchingBrackets[x] is the opening bracket that matches closing bracket x. -var matchingBrackets = map[byte]byte{ - ')': '(', - ']': '[', -} - -// String returns the string form of the StyleSheet. -func (s StyleSheet) String() string { - return s.str -} diff --git a/vendor/github.com/google/safehtml/template/context.go b/vendor/github.com/google/safehtml/template/context.go deleted file mode 100644 index dd7886dc6..000000000 --- a/vendor/github.com/google/safehtml/template/context.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "strings" -) - -// context describes the state an HTML parser must be in when it reaches the -// portion of HTML produced by evaluating a particular template node. -// -// The zero value of type Context is the start context for a template that -// produces an HTML fragment as defined at -// http://www.w3.org/TR/html5/syntax.html#the-end -// where the context element is null. -type context struct { - state state - delim delim - element element - attr attr - err *Error - // scriptType is the lowercase value of the "type" attribute inside the current "script" - // element (see https://dev.w3.org/html5/spec-preview/the-script-element.html#attr-script-type). - // This field will be empty if the parser is currently not in a script element, - // the type attribute has not already been parsed in the current element, or if the - // value of the type attribute cannot be determined at parse time. - scriptType string - // linkRel is the value of the "rel" attribute inside the current "link" - // element (see https://html.spec.whatwg.org/multipage/semantics.html#attr-link-rel). - // This value has been normalized to lowercase with exactly one space between tokens - // and exactly one space at start and end, so that a lookup of any token foo can - // be performed by searching for the substring " foo ". - // This field will be empty if the parser is currently not in a link element, - // the rel attribute has not already been parsed in the current element, or if the - // value of the rel attribute cannot be determined at parse time. - linkRel string -} - -// eq returns whether Context c is equal to Context d. -func (c context) eq(d context) bool { - return c.state == d.state && - c.delim == d.delim && - c.element.eq(d.element) && - c.attr.eq(d.attr) && - c.err == d.err && - c.scriptType == d.scriptType && - c.linkRel == d.linkRel -} - -// state describes a high-level HTML parser state. -// -// It bounds the top of the element stack, and by extension the HTML insertion -// mode, but also contains state that does not correspond to anything in the -// HTML5 parsing algorithm because a single token production in the HTML -// grammar may contain embedded actions in a template. For instance, the quoted -// HTML attribute produced by -// <div title="Hello {{.World}}"> -// is a single token in HTML's grammar but in a template spans several nodes. -type state uint8 - -//go:generate stringer -type state - -const ( - // stateText is parsed character data. An HTML parser is in - // this state when its parse position is outside an HTML tag, - // directive, comment, and special element body. - stateText state = iota - // stateSpecialElementBody occurs inside a specal HTML element body. - stateSpecialElementBody - // stateTag occurs before an HTML attribute or the end of a tag. - stateTag - // stateAttrName occurs inside an attribute name. - // It occurs between the ^'s in ` ^name^ = value`. - stateAttrName - // stateAfterName occurs after an attr name has ended but before any - // equals sign. It occurs between the ^'s in ` name^ ^= value`. - stateAfterName - // stateBeforeValue occurs after the equals sign but before the value. - // It occurs between the ^'s in ` name =^ ^value`. - stateBeforeValue - // stateHTMLCmt occurs inside an <!-- HTML comment -->. - stateHTMLCmt - // stateAttr occurs inside an HTML attribute whose content is text. - stateAttr - // stateError is an infectious error state outside any valid - // HTML/CSS/JS construct. - stateError -) - -// isComment reports whether a state contains content meant for template -// authors & maintainers, not for end-users or machines. -func isComment(s state) bool { - switch s { - case stateHTMLCmt: - return true - } - return false -} - -// isInTag reports whether s occurs solely inside an HTML tag. -func isInTag(s state) bool { - switch s { - case stateTag, stateAttrName, stateAfterName, stateBeforeValue, stateAttr: - return true - } - return false -} - -// delim is the delimiter that will end the current HTML attribute. -type delim uint8 - -//go:generate stringer -type delim - -const ( - // delimNone occurs outside any attribute. - delimNone delim = iota - // delimDoubleQuote occurs when a double quote (") closes the attribute. - delimDoubleQuote - // delimSingleQuote occurs when a single quote (') closes the attribute. - delimSingleQuote - // delimSpaceOrTagEnd occurs when a space or right angle bracket (>) - // closes the attribute. - delimSpaceOrTagEnd -) - -type element struct { - // name is the lowercase name of the element. If context joining has occurred, name - // will be arbitrarily assigned the element name from one of the joined contexts. - name string - // names contains all possible names the element could assume because of context joining. - // For example, after joining the contexts in the "if" and "else" branches of - // {{if .C}}<img{{else}}<audio{{end}} src="/some/path">`, - // names will contain "img" and "audio". - // names can also contain empty strings, which represent joined contexts with no element name. - // names will be empty if no context joining occurred. - names []string -} - -// eq reports whether a and b have the same name. All other fields are ignored. -func (e element) eq(d element) bool { - return e.name == d.name -} - -// String returns the string representation of the element. -func (e element) String() string { - return "element" + strings.Title(e.name) -} - -// attr represents the attribute that the parser is in, that is, -// starting from stateAttrName until stateTag/stateText (exclusive). -type attr struct { - // name is the lowercase name of the attribute. If context joining has occurred, name - // will be arbitrarily assigned the attribute name from one of the joined contexts. - name string - // value is the value of the attribute. If context joining has occurred, value - // will be arbitrarily assigned the attribute value from one of the joined contexts. - // If there are multiple actions in the attribute value, value will contain the - // concatenation of all values seen so far. For example, in - // <a name="foo{{.X}}bar{{.Y}}"> - // value is "foo" at "{{.X}}" and "foobar" at "{{.Y}}". - value string - // ambiguousValue indicates whether value contains an ambiguous value due to context-joining. - ambiguousValue bool - // names contains all possible names the attribute could assume because of context joining. - // For example, after joining the contexts in the "if" and "else" branches of - // <a {{if .C}}title{{else}}name{{end}}="foo"> - // names will contain "title" and "name". - // names can also contain empty strings, which represent joined contexts with no attribute name. - // names will be empty if no context joining occurred. - names []string -} - -// eq reports whether a and b have the same name. All other fields are ignored. -func (a attr) eq(b attr) bool { - return a.name == b.name -} - -// String returns the string representation of the attr. -func (a attr) String() string { - return "attr" + strings.Title(a.name) -} diff --git a/vendor/github.com/google/safehtml/template/delim_string.go b/vendor/github.com/google/safehtml/template/delim_string.go deleted file mode 100644 index 0ef2c2510..000000000 --- a/vendor/github.com/google/safehtml/template/delim_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by "stringer -type Delim"; DO NOT EDIT - -package template - -import "fmt" - -const _Delim_name = "DelimNoneDelimDoubleQuoteDelimSingleQuoteDelimSpaceOrTagEnd" - -var _Delim_index = [...]uint8{0, 9, 25, 41, 59} - -func (i delim) String() string { - if i >= delim(len(_Delim_index)-1) { - return fmt.Sprintf("delim(%d)", i) - } - return _Delim_name[_Delim_index[i]:_Delim_index[i+1]] -} diff --git a/vendor/github.com/google/safehtml/template/doc.go b/vendor/github.com/google/safehtml/template/doc.go deleted file mode 100644 index fab552b25..000000000 --- a/vendor/github.com/google/safehtml/template/doc.go +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -/* -Package template (safehtml/template) implements data-driven templates for -generating HTML output safe against code injection. It provides an interface -similar to that of package html/template, but produces HTML output that is more -secure. Therefore, it should be used instead of html/template to render HTML. - -The documentation here focuses on the security features of the package. For -information about how to program the templates themselves, see the -documentation for text/template. - - -Basic usage - -This package provides an API almost identical to that of text/template and -html/template to parse and execute HTML templates safely. - - tmpl := template.Must(template.New("name").Parse(`<div>Hello {{.}}</div>`)) - err := tmpl.Execute(out, data) - -If successful, out will contain code-injection-safe HTML. Otherwise, err's -string representation will describe the error that occurred. - -Elements of data might be modified at run time before being included in out, or -rejected completely if such a conversion is not possible. Pass values of -appropriate types from package safehtml to ensure that they are included in the -template's HTML output in their expected form. More details are provided below -in "Contextual autosanitization" and "Sanitization contexts". - - -Security improvements - -safehtml/template produces HTML more resistant to code injection than -html/template because it: - * Allows values of types only from package safehtml to bypass run-time - sanitization. These types represent values that are known---by construction - or by run-time sanitization---to be safe for use in various HTML contexts - without being processed by certain sanitization functions. - * Does not attempt to escape CSS or JavaScript. Instead of attempting to - parse and escape these complex languages, safehtml/template allows values - of only the appropriate types from package safehtml (e.g. safehtml.Style, - safehtml.Script) to be used in these contexts, since they are already - guaranteed to be safe. - * Emits an error if user data is interpolated in unsafe contexts, such as - within disallowed elements or unquoted attribute values. - * Only loads templates from trusted sources. This ensures that the contents - of the template are always under programmer control. More details are - provided below in "Trusted template sources". - * Differentiates between URLs that load code and those that do not. URLs in - the former category must be supplied to the template as values of type - safehtml.TrustedResourceURL, whose type contract promises that the URL - identifies a trustworthy resource. URLs in the latter category can be - sanitized at run time. - - -Threat model - -safehtml/template assumes that programmers are trustworthy. Therefore, data -fully under programmer control, such as string literals, are considered safe. -The types from package safehtml are designed around this same assumption, so -their type contracts are trusted by this package. - -safehtml/template considers all other data values untrustworthy and -conservatively assumes that such values could result in a code-injection -vulnerability if included verbatim in HTML. - - -Trusted template sources - -safehtml/template loads templates only from trusted sources. Therefore, template -text, file paths, and file patterns passed to Parse* functions and methods must -be entirely under programmer control. - -This constraint is enforced by using unexported string types for the parameters -of Parse* functions and methods, such as trustedFilePattern for ParseGlob. -The only values that may be assigned to these types (and thus provided as -arguments) are untyped string constants such as string literals, which are -always under programmer control. - - -Contextual autosanitization - -Code injection vulnerabilities, such as cross-site scripting (XSS), occur when -untrusted data values are embedded in a HTML document. For example, - - import "text/template" - ... - var t = template.Must(template.New("foo").Parse(`<a href="{{ .X }}">{{ .Y }}</a>`)) - func renderHTML(x, y string) string { - var out bytes.Buffer - err := t.Execute(&out, struct{ X, Y string }{x, y}) - // Error checking elided - return out.String() - } - -If x and y originate from user-provided data, an attacker who controls these -strings could arrange for them to contain the following values: - - x = "javascript:evil()" - y = "</a><script>alert('pwned')</script><a>" - -which will cause renderHTML to return the following unsafe HTML: - - <a href="javascript:evil()"></a><script>alert('pwned')</script><a></a> - -To prevent such vulnerabilities, untrusted data must be sanitized before being -included in HTML. A sanitization function takes untrusted data and returns a -string that will not create a code-injection vulnerability in the destination -context. The function might return the input unchanged if it deems it safe, -escape special runes in the input's string representation to prevent them from -triggering undesired state changes in the HTML parser, or entirely replace the -input by an innocuous string (also known as "filtering"). If none of these -conversions are possible, the sanitization function aborts template processing. - -safehtml/template contextually autosanitizes untrusted data by adding -appropriate sanitization functions to template actions to ensure that the -action output is safe to include in the HTML context in which the action -appears. For example, in - - import "safehtml/template" - ... - var t = template.Must(template.New("foo").Parse(`<a href="{{ .X }}">{{ .Y }}</a>`)) - func renderHTML(x, y string) string { - var out bytes.Buffer - err := t.Execute(&out, struct{ X, Y string }{x, y}) - // Error checking elided - return out.String() - } - -the contextual autosanitizer rewrites the template to - - <a href="{{ .X | _sanitizeTrustedResourceURLOrURL | _sanitizeHTML }}">{{ .Y | _sanitizeHTML }}</a> - -so that the template produces the following safe, sanitized HTML output (split -across multiple lines for clarity): - - <a href="about:invalid#zGoSafez"> - </a><script>alert('pwned')</script><a> - </a> - -Similar template systems such as html/template, Soy, and Angular, refer to this -functionality as "contextual autoescaping". safehtml/template uses the term -"autosanitization" instead of "autoescaping" since "sanitization" broadly -captures the operations of escaping and filtering. - - -Sanitization contexts - -The types of sanitization functions inserted into an action depend on the -action's sanitization context, which is determined by its surrounding text. -The following table describes these sanitization contexts. - - +--------------------+----------------------------------+------------------------------+-----------------------+ - | Context | Examples | Safe types | Run-time sanitizer | - |--------------------+----------------------------------+------------------------------+-----------------------+ - | HTMLContent | Hello {{.}} | safehtml.HTML | safehtml.HTMLEscaped | - | | <title>{{.}}</title> | | | - +--------------------------------------------------------------------------------------------------------------+ - | HTMLValOnly | <iframe srcdoc="{{.}}"></iframe> | safehtml.HTML* | N/A | - +--------------------------------------------------------------------------------------------------------------+ - | URL | <q cite="{{.}}">Cite</q> | safehtml.URL | safehtml.URLSanitized | - +--------------------------------------------------------------------------------------------------------------+ - | URL or | <a href="{{.}}">Link</a> | safehtml.URL | safehtml.URLSanitized | - | TrustedResourceURL | | safehtml.TrustedResourceURL | | - +--------------------------------------------------------------------------------------------------------------+ - | TrustedResourceURL | <script src="{{.}}"></script> | safehtml.TrustedResourceURL† | N/A | - +--------------------------------------------------------------------------------------------------------------+ - | Script | <script>{{.}}</script> | safehtml.Script* | N/A | - +--------------------------------------------------------------------------------------------------------------+ - | Style | <p style="{{.}}">Paragraph</p> | safehtml.Style* | N/A | - +--------------------------------------------------------------------------------------------------------------+ - | Stylesheet | <style>{{.}}</style> | safehtml.StyleSheet* | N/A | - +--------------------------------------------------------------------------------------------------------------+ - | Identifier | <h1 id="{{.}}">Hello</h1> | safehtml.Identifier* | N/A | - +--------------------------------------------------------------------------------------------------------------+ - | Enumerated value | <a target="{{.}}">Link</a> | Allowed string values | N/A | - | | | ("_self" or "_blank" for | | - | | | the given example) | | - +--------------------------------------------------------------------------------------------------------------+ - | None | <h1 class="{{.}}">Hello</h1> | N/A (any type allowed) | N/A (any type | - | | | | allowed) | - +--------------------+----------------------------------+------------------------------+-----------------------+ - *: Values only of this type are allowed in this context. Other values will trigger a run-time error. - †: If the action is a prefix of the attribute value, values only of this type are allowed. - Otherwise, values of any type are allowed. See "Substitutions in URLs" for more details. - -For each context, the function named in "Run-time sanitizer" is called to -sanitize the output of the action. However, if the action outputs a value of -any of the types listed in "Safe types", the run-time sanitizer is not called. -For example, in - - <title>{{ .X }}</title> - -if X is a string value, a HTML sanitizer that calls safehtml.HTMLEscaped will be -added to the action to sanitize X. - - // _sanitizeHTML calls safehtml.HTMLEscaped. - <title>{{ .X | _sanitizeHTML }}</title> - -However, if X is a safehtml.HTML value, _sanitizeHTML will not change its -value, since safehtml.HTML values are already safe to use in HTML contexts. -Therefore, the string contents of X will bypass context-specific -sanitization (in this case, HTML escaping) and appear unchanged in the -template's HTML output. Note that in attribute value contexts, HTML escaping -will always take place, whether or not context-specific sanitization is -performed. More details can be found at the end of this section. - -In certain contexts, the autosanitizer allows values only of that context's -"Safe types". Any other values will trigger an error and abort template -processing. For example, the template - - <style>{{ .X }}</style> - -triggers a run-time error if X is not a safehtml.StyleSheet. Otherwise, the -string form of X will appear unchanged in the output. The only exception to -this behavior is in TrustedResourceURL sanitization contexts, where actions may -output data of any type if the action occurs after a safe attribute value prefix. -More details can be found below in "Substitutions in URLs". - - -Unconditional sanitization - -In attribute value contexts, action outputs are always HTML-escaped after -context-specific sanitization to ensure that the attribute values cannot change -change the structure of the surrounding HTML tag. In URL or TrustedResourceURL -sanitization contexts, action outputs are additionally URL-normalized to reduce -the likelihood of downstream URL-parsing bugs. For example, the template - - <a href="{{ .X }}">Link</a> - <p id="{{ .Y }}">Text</p> - -is rewritten by the autosanitizer into - - // _sanitizeHTML calls safehtml.HTMLEscaped. - <a href="{{ .X | _sanitizeTrustedResourceURLOrURL | _normalizeURL | _sanitizeHTML }}">Link</a> - <p id="{{ .Y | _sanitizeIdentifier | _sanitizeHTML }}">Text</p> - -Even if X is a safehtml.URL or safehtml.TrustedResourceURL value, which -remains unchanged after _sanitizeTrustedResourceURLOrURL, X will still be -URL-normalized and HTML-escaped. Likewise, Y will still be HTML-escaped even if -its string form is left unchanged by _sanitizeIdentifier. - - -Substitutions in URLs - -Values of any type may be substituted into attribute values in URL and -TrustedResourceURL sanitization contexts only if the action is preceded by a -safe URL prefix. For example, in - - <q cite="http://www.foo.com/{{ .PathComponent }}">foo</q> - -Since "http://www.foo.com/" is a safe URL prefix, PathComponent can safely be -interpolated into this URL sanitization context after URL normalization. -Similarly, in - - <script src="https://www.bar.com/{{ .PathComponent }}"></script> - -Since "https://www.bar.com/" is a safe TrustedResourceURL prefix, PathComponent -can safely be interpolated into this TrustedResourceURL sanitization context -after URL escaping. Substitutions after a safe TrustedResourceURL prefix are -escaped instead of normalized to prevent the injection of any new URL -components, including additional path components. URL escaping also takes place -in URL sanitization contexts where the substitutions occur in the query or -fragment part of the URL, such as in: - - <a href="/foo?q={{ .Query }}&hl={{ .LangCode }}">Link</a> - -A URL prefix is considered safe in a URL sanitization context if it does -not end in an incomplete HTML character reference (e.g. https) or incomplete -percent-encoding character triplet (e.g. /fo%6), does not contain whitespace or control -characters, and one of the following is true: - * The prefix has a safe scheme (i.e. http, https, mailto, or ftp). - * The prefix has the data scheme with base64 encoding and an allowed audio, image, - or video MIME type (e.g. data:img/jpeg;base64, data:video/mp4;base64). - * The prefix has no scheme at all, and cannot be interpreted as a scheme prefix (e.g. /path). - -A URL prefix is considered safe in a TrustedResourceURL sanitization context if it does -not end in an incomplete HTML character reference (e.g. https) or incomplete -percent-encoding character triplet (e.g. /fo%6), does not contain white space or control -characters, and one of the following is true: - * The prefix has the https scheme and contains a domain name (e.g. https://www.foo.com). - * The prefix is scheme-relative and contains a domain name (e.g. //www.foo.com/). - * The prefix is path-absolute and contains a path (e.g. /path). - * The prefix is "about:blank". -*/ -package template diff --git a/vendor/github.com/google/safehtml/template/error.go b/vendor/github.com/google/safehtml/template/error.go deleted file mode 100644 index fe7821433..000000000 --- a/vendor/github.com/google/safehtml/template/error.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "fmt" - "text/template/parse" -) - -// Error describes a problem encountered during template Escaping. -type Error struct { - // ErrorCode describes the kind of error. - ErrorCode ErrorCode - // Node is the node that caused the problem, if known. - // If not nil, it overrides Name and Line. - Node parse.Node - // Name is the name of the template in which the error was encountered. - Name string - // Line is the line number of the error in the template source or 0. - Line int - // Description is a human-readable description of the problem. - Description string -} - -// ErrorCode is a code for a kind of error. -type ErrorCode int - -// We define codes for each error that manifests while escaping templates, but -// escaped templates may also fail at runtime. -// -// Output: "ZgotmplZ" -// Example: -// <img src="{{.X}}"> -// where {{.X}} evaluates to `javascript:...` -// Discussion: -// "ZgotmplZ" is a special value that indicates that unsafe content reached a -// CSS or URL context at runtime. The output of the example will be -// <img src="#ZgotmplZ"> -// If the data comes from a trusted source, use content types to exempt it -// from filtering: URL(`javascript:...`). -const ( - // OK indicates the lack of an error. - OK ErrorCode = iota - - // ErrAmbigContext: "... appears in an ambiguous context within a URL" - // Example: - // <a href=" - // {{if .C}} - // /path/ - // {{else}} - // /search?q= - // {{end}} - // {{.X}} - // "> - // Discussion: - // {{.X}} is in an ambiguous URL context since, depending on {{.C}}, - // it may be either a URL suffix or a query parameter. - // Moving {{.X}} into the condition removes the ambiguity: - // <a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}"> - ErrAmbigContext - - // ErrBadHTML: "expected space, attr name, or end of tag, but got ...", - // "... in unquoted attr", "... in attribute name" - // Example: - // <a href = /search?q=foo> - // <href=foo> - // <form na<e=...> - // <option selected< - // Discussion: - // This is often due to a typo in an HTML element, but some runes - // are banned in tag names, attribute names, and unquoted attribute - // values because they can tickle parser ambiguities. - // Quoting all attributes is the best policy. - ErrBadHTML - - // ErrBranchEnd: "{{if}} branches end in different contexts" - // Example: - // {{if .C}}<a href="{{end}}{{.X}} - // Discussion: - // Package html/template statically examines each path through an - // {{if}}, {{range}}, or {{with}} to escape any following pipelines. - // The example is ambiguous since {{.X}} might be an HTML text node, - // or a URL prefix in an HTML attribute. The context of {{.X}} is - // used to figure out how to escape it, but that context depends on - // the run-time value of {{.C}} which is not statically known. - // - // The problem is usually something like missing quotes or angle - // brackets, or can be avoided by refactoring to put the two contexts - // into different branches of an if, range or with. If the problem - // is in a {{range}} over a collection that should never be empty, - // adding a dummy {{else}} can help. - ErrBranchEnd - - // ErrEndContext: "... ends in a non-text context: ..." - // Examples: - // <div - // <div title="no close quote> - // <script>f() - // Discussion: - // Executed templates should produce a DocumentFragment of HTML. - // Templates that end without closing tags will trigger this error. - // Templates that should not be used in an HTML context or that - // produce incomplete Fragments should not be executed directly. - // - // {{define "main"}} <script>{{template "helper"}}</script> {{end}} - // {{define "helper"}} document.write(' <div title=" ') {{end}} - // - // "helper" does not produce a valid document fragment, so should - // not be Executed directly. - ErrEndContext - - // ErrNoSuchTemplate: "no such template ..." - // Examples: - // {{define "main"}}<div {{template "attrs"}}>{{end}} - // {{define "attrs"}}href="{{.URL}}"{{end}} - // Discussion: - // Package html/template looks through template calls to compute the - // context. - // Here the {{.URL}} in "attrs" must be treated as a URL when called - // from "main", but you will get this error if "attrs" is not defined - // when "main" is parsed. - ErrNoSuchTemplate - - // ErrOutputContext: "cannot compute output context for template ..." - // Examples: - // {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}} - // Discussion: - // A recursive template does not end in the same context in which it - // starts, and a reliable output context cannot be computed. - // Look for typos in the named template. - // If the template should not be called in the named start context, - // look for calls to that template in unexpected contexts. - // Maybe refactor recursive templates to not be recursive. - ErrOutputContext - - // ErrPartialCharset: "unfinished JS regexp charset in ..." - // Example: - // <script>var pattern = /foo[{{.Chars}}]/</script> - // Discussion: - // Package html/template does not support interpolation into regular - // expression literal character sets. - ErrPartialCharset - - // ErrPartialEscape: "unfinished escape sequence in ..." - // Example: - // <script>alert("\{{.X}}")</script> - // Discussion: - // Package html/template does not support actions following a - // backslash. - // This is usually an error and there are better solutions; for - // example - // <script>alert("{{.X}}")</script> - // should work, and if {{.X}} is a partial escape sequence such as - // "xA0", mark the whole sequence as safe content: JSStr(`\xA0`) - ErrPartialEscape - - // ErrRangeLoopReentry: "on range loop re-entry: ..." - // Example: - // <script>var x = [{{range .}}'{{.}},{{end}}]</script> - // Discussion: - // If an iteration through a range would cause it to end in a - // different context than an earlier pass, there is no single context. - // In the example, there is missing a quote, so it is not clear - // whether {{.}} is meant to be inside a JS string or in a JS value - // context. The second iteration would produce something like - // - // <script>var x = ['firstValue,'secondValue]</script> - ErrRangeLoopReentry - - // ErrSlashAmbig: '/' could start a division or regexp. - // Example: - // <script> - // {{if .C}}var x = 1{{end}} - // /-{{.N}}/i.test(x) ? doThis : doThat(); - // </script> - // Discussion: - // The example above could produce `var x = 1/-2/i.test(s)...` - // in which the first '/' is a mathematical division operator or it - // could produce `/-2/i.test(s)` in which the first '/' starts a - // regexp literal. - // Look for missing semicolons inside branches, and maybe add - // parentheses to make it clear which interpretation you intend. - ErrSlashAmbig - - // ErrPredefinedEscaper: "predefined escaper ... disallowed in template" - // Example: - // <div class={{. | html}}>Hello<div> - // Discussion: - // Package html/template already contextually escapes all pipelines to - // produce HTML output safe against code injection. Manually escaping - // pipeline output using the predefined escapers "html" or "urlquery" is - // unnecessary, and may affect the correctness or safety of the escaped - // pipeline output in Go 1.8 and earlier. - // - // In most cases, such as the given example, this error can be resolved by - // simply removing the predefined escaper from the pipeline and letting the - // contextual autoescaper handle the escaping of the pipeline. In other - // instances, where the predefined escaper occurs in the middle of a - // pipeline where subsequent commands expect escaped input, e.g. - // {{.X | html | makeALink}} - // where makeALink does - // return `<a href="`+input+`">link</a>` - // consider refactoring the surrounding template to make use of the - // contextual autoescaper, i.e. - // <a href="{{.X}}">link</a> - // - // To ease migration to Go 1.9 and beyond, "html" and "urlquery" will - // continue to be allowed as the last command in a pipeline. However, if the - // pipeline occurs in an unquoted attribute value context, "html" is - // disallowed. Avoid using "html" and "urlquery" entirely in new templates. - ErrPredefinedEscaper - - // ErrEscapeAction: "cannot escape action ..." - // Discussion: - // Error returned while escaping an action using EscaperForContext. - // Refer to error message for more details. - // TODO: remove this error type and replace it with more informative sanitization errors. - ErrEscapeAction - - // ErrCSPCompatibility: `"javascript:" URI disallowed for CSP compatibility`, - // "inline event handler ... is disallowed for CSP compatibility - // Examples: - // <span onclick="doThings();">A thing.</span> - // <a href="javascript:linkClicked()">foo</a> - // Discussion: - // Inline event handlers (onclick="...", onerror="...") and - // <a href="javascript:..."> links can be used to run scripts, - // so an attacker who finds an XSS bug could inject such HTML - // and execute malicious JavaScript. These patterns must be - // refactored into safer alternatives for compatibility with - // Content Security Policy (CSP). - // - // For example, the following HTML that contains an inline event handler: - // <script> function doThings() { ... } </script> - // <span onclick="doThings();">A thing.</span> - // can be refactored into: - // <span id="things">A thing.</span> - // <script nonce="${nonce}"> - // document.addEventListener('DOMContentLoaded', function () { - // document.getElementById('things') - // .addEventListener('click', function doThings() { ... }); - // }); - // </script> - // - // Likewise, the following HTML containng a javascript: URI: - // <a href="javascript:linkClicked()">foo</a> - // can be refactored into: - // <a id="foo">foo</a> - // <script nonce="${nonce}"> - // document.addEventListener('DOMContentLoaded', function () { - // document.getElementById('foo') - // .addEventListener('click', linkClicked); - // }); - // </script> - ErrCSPCompatibility - // All JS templates inside script literals have to be balanced; otherwise a concatenation such as - // <script>alert(`x{{.data}}`</script> can contain XSS if data contains user-controlled escaped strings (e.g. as JSON). - ErrUnbalancedJsTemplate -) - -func (e *Error) Error() string { - switch { - case e.Node != nil: - loc, _ := (*parse.Tree)(nil).ErrorContext(e.Node) - return fmt.Sprintf("html/template:%s: %s", loc, e.Description) - case e.Line != 0: - return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description) - case e.Name != "": - return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description) - } - return "html/template: " + e.Description -} - -// errorf creates an error given a format string f and args. -// The template Name still needs to be supplied. -func errorf(k ErrorCode, node parse.Node, line int, f string, args ...interface{}) *Error { - return &Error{k, node, "", line, fmt.Sprintf(f, args...)} -} diff --git a/vendor/github.com/google/safehtml/template/escape.go b/vendor/github.com/google/safehtml/template/escape.go deleted file mode 100644 index 8a9d53dd5..000000000 --- a/vendor/github.com/google/safehtml/template/escape.go +++ /dev/null @@ -1,884 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "bytes" - "fmt" - "html" - "reflect" - "strings" - "text/template" - "text/template/parse" -) - -// TODO: remove all unused escaping logic inherited from html/template. -// TODO: replace "escape" with "sanitize" in file names and contents to maintain consistency with safehtml/template docs. - -// escapeTemplate rewrites the named template, which must be -// associated with t, to guarantee that the output of any of the named -// templates is properly escaped. If no error is returned, then the named templates have -// been modified. Otherwise the named templates have been rendered -// unusable. -func escapeTemplate(tmpl *Template, node parse.Node, name string) error { - c, _ := tmpl.esc.escapeTree(context{}, node, name, 0) - var err error - if c.err != nil { - err, c.err.Name = c.err, name - } else if c.state != stateText { - err = &Error{ErrEndContext, nil, name, 0, fmt.Sprintf("ends in a non-text context: %+v", c)} - } - if err != nil { - // Prevent execution of unsafe templates. - if t := tmpl.set[name]; t != nil { - t.escapeErr = err - t.text.Tree = nil - t.Tree = nil - } - return err - } - tmpl.esc.commit() - if t := tmpl.set[name]; t != nil { - t.escapeErr = errEscapeOK - t.Tree = t.text.Tree - } - return nil -} - -// evalArgs formats the list of arguments into a string. It is equivalent to -// fmt.Sprint(args...), except that it deferences all pointers. -func evalArgs(args ...interface{}) string { - // Optimization for simple common case of a single string argument. - if len(args) == 1 { - if s, ok := args[0].(string); ok { - return s - } - } - for i, arg := range args { - args[i] = indirectToStringerOrError(arg) - } - return fmt.Sprint(args...) -} - -// escaper collects type inferences about templates and changes needed to make -// templates injection safe. -type escaper struct { - // ns is the nameSpace that this escaper is associated with. - ns *nameSpace - // output[templateName] is the output context for a templateName that - // has been mangled to include its input context. - output map[string]context - // derived[c.mangle(name)] maps to a template derived from the template - // named name templateName for the start context c. - derived map[string]*template.Template - // called[templateName] is a set of called mangled template names. - called map[string]bool - // xxxNodeEdits are the accumulated edits to apply during commit. - // Such edits are not applied immediately in case a template set - // executes a given template in different escaping contexts. - actionNodeEdits map[*parse.ActionNode][]string - templateNodeEdits map[*parse.TemplateNode]string - textNodeEdits map[*parse.TextNode][]byte -} - -// makeEscaper creates a blank escaper for the given set. -func makeEscaper(n *nameSpace) escaper { - return escaper{ - n, - map[string]context{}, - map[string]*template.Template{}, - map[string]bool{}, - map[*parse.ActionNode][]string{}, - map[*parse.TemplateNode]string{}, - map[*parse.TextNode][]byte{}, - } -} - -// escape escapes a template node. -func (e *escaper) escape(c context, n parse.Node) context { - switch n := n.(type) { - case *parse.ActionNode: - return e.escapeAction(c, n) - case *parse.IfNode: - return e.escapeBranch(c, &n.BranchNode, "if") - case *parse.ListNode: - return e.escapeList(c, n) - case *parse.RangeNode: - return e.escapeBranch(c, &n.BranchNode, "range") - case *parse.TemplateNode: - return e.escapeTemplate(c, n) - case *parse.TextNode: - return e.escapeText(c, n) - case *parse.WithNode: - return e.escapeBranch(c, &n.BranchNode, "with") - } - panic("escaping " + n.String() + " is unimplemented") -} - -// escapeAction escapes an action template node. -func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { - if len(n.Pipe.Decl) != 0 { - // A local variable assignment, not an interpolation. - return c - } - c = nudge(c) - // Check for disallowed use of predefined escapers in the pipeline. - for pos, idNode := range n.Pipe.Cmds { - node, ok := idNode.Args[0].(*parse.IdentifierNode) - if !ok { - // A predefined escaper "esc" will never be found as an identifier in a - // Chain or Field node, since: - // - "esc.x ..." is invalid, since predefined escapers return strings, and - // strings do not have methods, keys or fields. - // - "... .esc" is invalid, since predefined escapers are global functions, - // not methods or fields of any types. - // Therefore, it is safe to ignore these two node types. - continue - } - ident := node.Ident - if _, ok := predefinedEscapers[ident]; ok { - if pos < len(n.Pipe.Cmds)-1 || - c.state == stateAttr && c.delim == delimSpaceOrTagEnd && ident == "html" { - return context{ - state: stateError, - err: errorf(ErrPredefinedEscaper, n, n.Line, "predefined escaper %q disallowed in template", ident), - } - } - } - } - switch c.state { - case stateError: - return c - case stateAttrName, stateTag: - c.state = stateAttrName - } - // TODO: integrate sanitizerForContext into escapeAction. - s, err := sanitizerForContext(c) - if err != nil { - return context{ - state: stateError, - // TODO: return sanitization-specific errors. - err: errorf(ErrEscapeAction, n, n.Line, "cannot escape action %v: %s", n, err), - } - } - e.editActionNode(n, s) - return c -} - -// ensurePipelineContains ensures that the pipeline ends with the commands with -// the identifiers in s in order. If the pipeline ends with a predefined escaper -// (i.e. "html" or "urlquery"), merge it with the identifiers in s.c -func ensurePipelineContains(p *parse.PipeNode, s []string) { - if len(s) == 0 { - // Do not rewrite pipeline if we have no escapers to insert. - return - } - // Precondition: p.Cmds contains at most one predefined escaper and the - // escaper will be present at p.Cmds[len(p.Cmds)-1]. This precondition is - // always true because of the checks in escapeAction. - pipelineLen := len(p.Cmds) - if pipelineLen > 0 { - lastCmd := p.Cmds[pipelineLen-1] - if idNode, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok { - if esc := idNode.Ident; predefinedEscapers[esc] { - // Pipeline ends with a predefined escaper. - if len(p.Cmds) == 1 && len(lastCmd.Args) > 1 { - // Special case: pipeline is of the form {{ esc arg1 arg2 ... argN }}, - // where esc is the predefined escaper, and arg1...argN are its arguments. - // Convert this into the equivalent form - // {{ _eval_args_ arg1 arg2 ... argN | esc }}, so that esc can be easily - // merged with the escapers in s. - lastCmd.Args[0] = parse.NewIdentifier(evalArgsFuncName).SetTree(nil).SetPos(lastCmd.Args[0].Position()) - p.Cmds = append(p.Cmds, newIdentCmd(esc, p.Position())) - pipelineLen++ - } - // If any of the commands in s that we are about to insert is equivalent - // to the predefined escaper, use the predefined escaper instead. - dup := false - for i, escaper := range s { - if escFnsEq(esc, escaper) { - s[i] = idNode.Ident - dup = true - } - } - if dup { - // The predefined escaper will already be inserted along with the - // escapers in s, so do not copy it to the rewritten pipeline. - pipelineLen-- - } - } - } - } - // Rewrite the pipeline, creating the escapers in s at the end of the pipeline. - newCmds := make([]*parse.CommandNode, pipelineLen, pipelineLen+len(s)) - copy(newCmds, p.Cmds) - for _, name := range s { - newCmds = append(newCmds, newIdentCmd(name, p.Position())) - } - p.Cmds = newCmds -} - -// predefinedEscapers contains template predefined escapers that are equivalent -// to some contextual escapers. Keep in sync with equivEscapers. -var predefinedEscapers = map[string]bool{ - "html": true, - "urlquery": true, -} - -// equivEscapers matches contextual escapers to equivalent predefined -// template escapers. -var equivEscapers = map[string]string{ - // The following pairs of HTML escapers provide equivalent security - // guarantees, since they all escape '\000', '\'', '"', '&', '<', and '>'. - sanitizeHTMLFuncName: "html", - sanitizeRCDATAFuncName: "html", - // These two URL escapers produce URLs safe for embedding in a URL query by - // percent-encoding all the reserved characters specified in RFC 3986 Section - // 2.2 - queryEscapeURLFuncName: "urlquery", - // The normalizer function is not actually equivalent to urlquery; urlquery is - // stricter as it escapes reserved characters (e.g. '#'), while the normalizer - // function does not. It is therefore only safe to replace the normalizer with - // with urlquery (this happens in ensurePipelineContains), but not the other - // way around. We keep this entry around to preserve the behavior of templates - // written before Go 1.9, which might depend on this substitution taking place. - normalizeURLFuncName: "urlquery", -} - -// escFnsEq reports whether the two escaping functions are equivalent. -func escFnsEq(a, b string) bool { - return normalizeEscFn(a) == normalizeEscFn(b) -} - -// normalizeEscFn(a) is equal to normalizeEscFn(b) for any pair of names of -// escaper functions a and b that are equivalent. -func normalizeEscFn(e string) string { - if norm := equivEscapers[e]; norm != "" { - return norm - } - return e -} - -// newIdentCmd produces a command containing a single identifier node. -func newIdentCmd(identifier string, pos parse.Pos) *parse.CommandNode { - return &parse.CommandNode{ - NodeType: parse.NodeCommand, - Args: []parse.Node{parse.NewIdentifier(identifier).SetTree(nil).SetPos(pos)}, // TODO: SetTree. - Pos: pos, - } -} - -// nudge returns the context that would result from following empty string -// transitions from the input context. -// For example, parsing: -// `<a href=` -// will end in context{stateBeforeValue, AttrURL}, but parsing one extra rune: -// `<a href=x` -// will end in context{stateURL, delimSpaceOrTagEnd, ...}. -// There are two transitions that happen when the 'x' is seen: -// (1) Transition from a before-value state to a start-of-value state without -// consuming any character. -// (2) Consume 'x' and transition past the first value character. -// In this case, nudging produces the context after (1) happens. -func nudge(c context) context { - switch c.state { - case stateTag: - // In `<foo {{.}}`, the action should emit an attribute. - c.state = stateAttrName - case stateBeforeValue: - // In `<foo bar={{.}}`, the action is an undelimited value. - c.state, c.delim = stateAttr, delimSpaceOrTagEnd - case stateAfterName: - // In `<foo bar {{.}}`, the action is an attribute name. - c.state = stateAttrName - } - return c -} - -// join joins the two contexts of a branch template node. The result is an -// error context if either of the input contexts are error contexts, or if the -// input contexts differ. -func join(a, b context, node parse.Node, nodeName string) context { - if a.state == stateError { - return a - } - if b.state == stateError { - return b - } - - // Accumulate the result of context-joining elements and attributes in a, since the - // contents of a are always returned. - a.element.names = joinNames(a.element.name, b.element.name, a.element.names, b.element.names) - a.attr.names = joinNames(a.attr.name, b.attr.name, a.attr.names, b.attr.names) - if a.attr.value != b.attr.value { - a.attr.ambiguousValue = true - } - - if a.eq(b) { - return a - } - - c := a - c.element.name = b.element.name - if c.eq(b) { - // The contexts differ only by their element names. The element names from the conditional - // branches that are accumulated in c.element.names will be checked during action sanitization - // to ensure that they do not lead to different sanitization contexts. - return c - } - - c = a - c.attr.name = b.attr.name - if c.eq(b) { - // The contexts differ only by their attribute name. The attribute names from the conditional - // branches that are accumulated in c.attr.names will be checked during action sanitization - // to ensure that they do not lead to different sanitization contexts. - return c - } - - // Allow a nudged context to join with an unnudged one. - // This means that - // <p title={{if .C}}{{.}}{{end}} - // ends in an unquoted value state even though the else branch - // ends in stateBeforeValue. - if c, d := nudge(a), nudge(b); !(c.eq(a) && d.eq(b)) { - if e := join(c, d, node, nodeName); e.state != stateError { - return e - } - } - - return context{ - state: stateError, - err: errorf(ErrBranchEnd, node, 0, "{{%s}} branches end in different contexts: %v, %v", nodeName, a, b), - } -} - -// joinNames returns the slice of all possible names that an element or attr could -// assume after context joining the element or attr containing aName and aNames with the -// element or attr containing bName and bNames. -func joinNames(aName, bName string, aNames, bNames []string) []string { - var ret []string - if aName != bName { - ret = append(ret, aName, bName) - } - aNamesSet := make(map[string]bool) - for _, name := range aNames { - aNamesSet[name] = true - } - for _, name := range bNames { - if !aNamesSet[name] { - ret = append(ret, name) - } - } - return ret -} - -// escapeBranch escapes a branch template node: "if", "range" and "with". -func (e *escaper) escapeBranch(c context, n *parse.BranchNode, nodeName string) context { - c0 := e.escapeList(c, n.List) - if nodeName == "range" && c0.state != stateError { - // The "true" branch of a "range" node can execute multiple times. - // We check that executing n.List once results in the same context - // as executing n.List twice. - c1, _ := e.escapeListConditionally(c0, n.List, nil) - c0 = join(c0, c1, n, nodeName) - if c0.state == stateError { - // Make clear that this is a problem on loop re-entry - // since developers tend to overlook that branch when - // debugging templates. - c0.err.Line = n.Line - c0.err.Description = "on range loop re-entry: " + c0.err.Description - return c0 - } - } - c1 := e.escapeList(c, n.ElseList) - return join(c0, c1, n, nodeName) -} - -// escapeList escapes a list template node. -func (e *escaper) escapeList(c context, n *parse.ListNode) context { - if n == nil { - return c - } - for _, m := range n.Nodes { - c = e.escape(c, m) - } - return c -} - -// escapeListConditionally escapes a list node but only preserves edits and -// inferences in e if the inferences and output context satisfy filter. -// It returns the best guess at an output context, and the result of the filter -// which is the same as whether e was updated. -func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) { - e1 := makeEscaper(e.ns) - // Make type inferences available to f. - for k, v := range e.output { - e1.output[k] = v - } - c = e1.escapeList(c, n) - ok := filter != nil && filter(&e1, c) - if ok { - // Copy inferences and edits from e1 back into e. - for k, v := range e1.output { - e.output[k] = v - } - for k, v := range e1.derived { - e.derived[k] = v - } - for k, v := range e1.called { - e.called[k] = v - } - for k, v := range e1.actionNodeEdits { - e.editActionNode(k, v) - } - for k, v := range e1.templateNodeEdits { - e.editTemplateNode(k, v) - } - for k, v := range e1.textNodeEdits { - e.editTextNode(k, v) - } - } - return c, ok -} - -// escapeTemplate escapes a {{template}} call node. -func (e *escaper) escapeTemplate(c context, n *parse.TemplateNode) context { - c, name := e.escapeTree(c, n, n.Name, n.Line) - if name != n.Name { - e.editTemplateNode(n, name) - } - return c -} - -// mangle produces an identifier that includes a suffix that distinguishes it -// from template names mangled with different contexts. -func mangle(c context, templateName string) string { - // The mangled name for the default context is the input templateName. - if c.state == stateText { - return templateName - } - s := templateName + "$htmltemplate_" + c.state.String() - if c.delim != 0 { - s += "_" + c.delim.String() - } - if c.attr.name != "" { - s += "_" + c.attr.String() - } - if c.element.name != "" { - s += "_" + c.element.String() - } - return s -} - -// escapeTree escapes the named template starting in the given context as -// necessary and returns its output context. -func (e *escaper) escapeTree(c context, node parse.Node, name string, line int) (context, string) { - // Mangle the template name with the input context to produce a reliable - // identifier. - dname := mangle(c, name) - e.called[dname] = true - if out, ok := e.output[dname]; ok { - // Already escaped. - return out, dname - } - t := e.template(name) - if t == nil { - // Two cases: The template exists but is empty, or has never been mentioned at - // all. Distinguish the cases in the error messages. - if e.ns.set[name] != nil { - return context{ - state: stateError, - err: errorf(ErrNoSuchTemplate, node, line, "%q is an incomplete or empty template", name), - }, dname - } - return context{ - state: stateError, - err: errorf(ErrNoSuchTemplate, node, line, "no such template %q", name), - }, dname - } - if dname != name { - // Use any template derived during an earlier call to escapeTemplate - // with different top level templates, or clone if necessary. - dt := e.template(dname) - if dt == nil { - dt = template.New(dname) - dt.Tree = t.Tree.Copy() - dt.Tree.Name = dname - e.derived[dname] = dt - } - t = dt - } - return e.computeOutCtx(c, t), dname -} - -// computeOutCtx takes a template and its start context and computes the output -// context while storing any inferences in e. -func (e *escaper) computeOutCtx(c context, t *template.Template) context { - // Propagate context over the body. - c1, ok := e.escapeTemplateBody(c, t) - if !ok { - // Look for a fixed point by assuming c1 as the output context. - if c2, ok2 := e.escapeTemplateBody(c1, t); ok2 { - c1, ok = c2, true - } - // Use c1 as the error context if neither assumption worked. - } - if !ok && c1.state != stateError { - return context{ - state: stateError, - err: errorf(ErrOutputContext, t.Tree.Root, 0, "cannot compute output context for template %s", t.Name()), - } - } - return c1 -} - -// escapeTemplateBody escapes the given template assuming the given output -// context, and returns the best guess at the output context and whether the -// assumption was correct. -func (e *escaper) escapeTemplateBody(c context, t *template.Template) (context, bool) { - filter := func(e1 *escaper, c1 context) bool { - if c1.state == stateError { - // Do not update the input escaper, e. - return false - } - if !e1.called[t.Name()] { - // If t is not recursively called, then c1 is an - // accurate output context. - return true - } - // c1 is accurate if it matches our assumed output context. - return c.eq(c1) - } - // We need to assume an output context so that recursive template calls - // take the fast path out of escapeTree instead of infinitely recursing. - // Naively assuming that the input context is the same as the output - // works >90% of the time. - e.output[t.Name()] = c - return e.escapeListConditionally(c, t.Tree.Root, filter) -} - -// delimEnds maps each delim to a string of characters that terminate it. -var delimEnds = [...]string{ - delimDoubleQuote: `"`, - delimSingleQuote: "'", - // Determined empirically by running the below in various browsers. - // var div = document.createElement("DIV"); - // for (var i = 0; i < 0x10000; ++i) { - // div.innerHTML = "<span title=x" + String.fromCharCode(i) + "-bar>"; - // if (div.getElementsByTagName("SPAN")[0].title.indexOf("bar") < 0) - // document.write("<p>U+" + i.toString(16)); - // } - delimSpaceOrTagEnd: " \t\n\f\r>", -} - -var doctypeBytes = []byte("<!DOCTYPE") - -// escapeText escapes a text template node. -func (e *escaper) escapeText(c context, n *parse.TextNode) context { - s, written, i, b := n.Text, 0, 0, new(bytes.Buffer) - if e.ns.cspCompatible && bytes.Contains(s, []byte("javascript:")) { - // This substring search is not perfect, but it is unlikely that this substring will - // exist in template text for any other reason than to specify a javascript URI. - return context{ - state: stateError, - err: errorf(ErrCSPCompatibility, n, 0, `"javascript:" URI disallowed for CSP compatibility`), - } - } - for i != len(s) { - if e.ns.cspCompatible && strings.HasPrefix(c.attr.name, "on") { - return context{ - state: stateError, - err: errorf(ErrCSPCompatibility, n, 0, "inline event handler %q is disallowed for CSP compatibility", c.attr.name), - } - } - c1, nread := contextAfterText(c, s[i:]) - i1 := i + nread - sc, err := sanitizationContextForElementContent(c.element.name) - if c.state == stateText || err == nil && sc == sanitizationContextRCDATA { - end := i1 - if c1.state != c.state { - for j := end - 1; j >= i; j-- { - if s[j] == '<' { - end = j - break - } - } - } - for j := i; j < end; j++ { - if s[j] == '<' && !bytes.HasPrefix(bytes.ToUpper(s[j:]), doctypeBytes) { - b.Write(s[written:j]) - b.WriteString("<") - written = j + 1 - } - } - } else if isComment(c.state) && c.delim == delimNone { - written = i1 - } - if c.state == stateSpecialElementBody && c.element.name == "script" { - if err := isJsTemplateBalanced(bytes.NewBuffer(s)); err != nil { - return context{ - state: stateError, - err: errorf(ErrUnbalancedJsTemplate, n, 0, "Mixing template systems can cause security vulnerabilites. Therefore, there can be no safehtml/template insertion points or actions inside an ES6 template, and all ES6 templates must be closed: %v", err.Error()), - } - } - } - - if c.state != c1.state && isComment(c1.state) && c1.delim == delimNone { - // Preserve the portion between written and the comment start. - cs := i1 - 2 - if c1.state == stateHTMLCmt { - // "<!--" instead of "/*" or "//" - cs -= 2 - } - b.Write(s[written:cs]) - written = i1 - } - if i == i1 && c.state == c1.state { - panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:])) - } - c, i = c1, i1 - } - - if written != 0 && c.state != stateError { - if !isComment(c.state) || c.delim != delimNone { - b.Write(n.Text[written:]) - } - e.editTextNode(n, b.Bytes()) - } - return c -} - -// contextAfterText starts in context c, consumes some tokens from the front of -// s, then returns the context after those tokens and the unprocessed suffix. -func contextAfterText(c context, s []byte) (context, int) { - if c.delim == delimNone { - c1, i := tSpecialTagEnd(c, s) - if i == 0 { - // A special end tag (`</script>`) has been seen and - // all content preceding it has been consumed. - return c1, 0 - } - // Consider all content up to any end tag. - return transitionFunc[c.state](c, s[:i]) - } - - // We are at the beginning of an attribute value. - - i := bytes.IndexAny(s, delimEnds[c.delim]) - if i == -1 { - i = len(s) - } - if c.delim == delimSpaceOrTagEnd { - // http://www.w3.org/TR/html5/syntax.html#attribute-value-(unquoted)-state - // lists the runes below as error characters. - // Error out because HTML parsers may differ on whether - // "<a id= onclick=f(" ends inside id's or onclick's value, - // "<a class=`foo " ends inside a value, - // "<a style=font:'Arial'" needs open-quote fixup. - // IE treats '`' as a quotation character. - if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 { - return context{ - state: stateError, - err: errorf(ErrBadHTML, nil, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]), - }, len(s) - } - } - if i == len(s) { - c.attr.value += string(s) - // Remain inside the attribute. - // Decode the value so non-HTML rules can easily handle - // <button onclick="alert("Hi!")"> - // without having to entity decode token boundaries. - for u := []byte(html.UnescapeString(string(s))); len(u) != 0; { - c1, i1 := transitionFunc[c.state](c, u) - c, u = c1, u[i1:] - } - return c, len(s) - } - - // On exiting an attribute, we discard all state information - // except the state, element, scriptType, and linkRel. - ret := context{ - state: stateTag, - element: c.element, - scriptType: c.scriptType, - linkRel: c.linkRel, - } - // Save the script element's type attribute value if we are parsing it for the first time. - if c.state == stateAttr && c.element.name == "script" && c.attr.name == "type" { - ret.scriptType = strings.ToLower(string(s[:i])) - } - // Save the link element's rel attribute value if we are parsing it for the first time. - if c.state == stateAttr && c.element.name == "link" && c.attr.name == "rel" { - ret.linkRel = " " + strings.Join(strings.Fields(strings.TrimSpace(strings.ToLower(string(s[:i])))), " ") + " " - } - if c.delim != delimSpaceOrTagEnd { - // Consume any quote. - i++ - } - return ret, i -} - -// editActionNode records a change to an action pipeline for later commit. -func (e *escaper) editActionNode(n *parse.ActionNode, cmds []string) { - if _, ok := e.actionNodeEdits[n]; ok { - panic(fmt.Sprintf("node %s shared between templates", n)) - } - e.actionNodeEdits[n] = cmds -} - -// editTemplateNode records a change to a {{template}} callee for later commit. -func (e *escaper) editTemplateNode(n *parse.TemplateNode, callee string) { - if _, ok := e.templateNodeEdits[n]; ok { - panic(fmt.Sprintf("node %s shared between templates", n)) - } - e.templateNodeEdits[n] = callee -} - -// editTextNode records a change to a text node for later commit. -func (e *escaper) editTextNode(n *parse.TextNode, text []byte) { - if _, ok := e.textNodeEdits[n]; ok { - panic(fmt.Sprintf("node %s shared between templates", n)) - } - e.textNodeEdits[n] = text -} - -// commit applies changes to actions and template calls needed to contextually -// autoescape content and adds any derived templates to the set. -func (e *escaper) commit() { - for name := range e.output { - e.template(name).Funcs(funcs) - } - // Any template from the name space associated with this escaper can be used - // to add derived templates to the underlying text/template name space. - tmpl := e.arbitraryTemplate() - for _, t := range e.derived { - if _, err := tmpl.text.AddParseTree(t.Name(), t.Tree); err != nil { - panic("error adding derived template") - } - } - for n, s := range e.actionNodeEdits { - ensurePipelineContains(n.Pipe, s) - } - for n, name := range e.templateNodeEdits { - n.Name = name - } - for n, s := range e.textNodeEdits { - n.Text = s - } - // Reset state that is specific to this commit so that the same changes are - // not re-applied to the template on subsequent calls to commit. - e.called = make(map[string]bool) - e.actionNodeEdits = make(map[*parse.ActionNode][]string) - e.templateNodeEdits = make(map[*parse.TemplateNode]string) - e.textNodeEdits = make(map[*parse.TextNode][]byte) -} - -// template returns the named template given a mangled template name. -func (e *escaper) template(name string) *template.Template { - // Any template from the name space associated with this escaper can be used - // to look up templates in the underlying text/template name space. - t := e.arbitraryTemplate().text.Lookup(name) - if t == nil { - t = e.derived[name] - } - return t -} - -// arbitraryTemplate returns an arbitrary template from the name space -// associated with e and panics if no templates are found. -func (e *escaper) arbitraryTemplate() *Template { - for _, t := range e.ns.set { - return t - } - panic("no templates in name space") -} - -var ( - errorType = reflect.TypeOf((*error)(nil)).Elem() - fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() -) - -// indirectToStringerOrError returns the value, after dereferencing as many times -// as necessary to reach the base type (or nil) or an implementation of fmt.Stringer -// or error, -func indirectToStringerOrError(a interface{}) interface{} { - if a == nil { - return nil - } - v := reflect.ValueOf(a) - for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() { - v = v.Elem() - } - return v.Interface() -} - -var ( - jsTemplateSeparator = []byte("`") - jsTemplateExprStart = []byte("${") - jsTemplateExprEnd = []byte("}") -) - -// Determine if a string has unbalanced (open) JS templates. -func isJsTemplateBalanced(s *bytes.Buffer) error { - for { - index := bytes.Index(s.Bytes(), jsTemplateSeparator) - if index == -1 { - return nil - } - s.Next(index + 1) - err := consumeJsTemplate(s) - if err != nil { - return err - } - } -} - -// s is a JS template string (without the opening `); this function consumes s up to -// the matching closing `. -func consumeJsTemplate(s *bytes.Buffer) error { - for { - templateEnd := bytes.Index(s.Bytes(), jsTemplateSeparator) - exprStart := bytes.Index(s.Bytes(), jsTemplateExprStart) - if templateEnd == -1 { - return fmt.Errorf("Missing closing ` in JS template") - } - if exprStart != -1 && exprStart < templateEnd { - err := consumeJsTemplateExpr(s) - if err != nil { - return err - } - return consumeJsTemplate(s) - } else { - // The template expression occurs after this template, e.g. "`foo``bar${test}`". - s.Next(templateEnd + 1) - return nil - } - } -} - -// s is a Js Template expression (starting with "${"). This function consumes up to and including the matching closing "}". -func consumeJsTemplateExpr(s *bytes.Buffer) error { - for { - exprEnd := bytes.Index(s.Bytes(), jsTemplateExprEnd) - if exprEnd == -1 { - // Template expression isn't closed - return fmt.Errorf("Missing closing } in JS template") - } - nestedTemplateStart := bytes.Index(s.Bytes(), jsTemplateSeparator) - if nestedTemplateStart != -1 && nestedTemplateStart < exprEnd { - s.Next(nestedTemplateStart + 1) - err := consumeJsTemplate(s) - if err != nil { - return err - } - return consumeJsTemplateExpr(s) - } else { - s.Next(exprEnd + 1) - return nil - } - } -} diff --git a/vendor/github.com/google/safehtml/template/init.go b/vendor/github.com/google/safehtml/template/init.go deleted file mode 100644 index c9fa2de1d..000000000 --- a/vendor/github.com/google/safehtml/template/init.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package template - -import ( - "github.com/google/safehtml/internal/template/raw" -) - -// The following functions are used by package uncheckedconversions -// (via package raw) to create TrustedSource and TrustedTemplate values -// from plain strings. - -func trustedSourceRaw(s string) TrustedSource { - return TrustedSource{s} -} - -func trustedTemplateRaw(s string) TrustedTemplate { - return TrustedTemplate{s} -} - -func init() { - raw.TrustedSource = trustedSourceRaw - raw.TrustedTemplate = trustedTemplateRaw -} diff --git a/vendor/github.com/google/safehtml/template/sanitize.go b/vendor/github.com/google/safehtml/template/sanitize.go deleted file mode 100644 index c75e345e1..000000000 --- a/vendor/github.com/google/safehtml/template/sanitize.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "fmt" - "regexp" - "strings" -) - -// sanitizerForContext returns an ordered list of function names that will be called to -// sanitize data values found in the HTML context defined by c. -func sanitizerForContext(c context) ([]string, error) { - switch c.state { - case stateTag, stateAttrName, stateAfterName: - return nil, fmt.Errorf("actions must not affect element or attribute names") - case stateHTMLCmt: - return []string{sanitizeHTMLCommentFuncName}, nil - } - if len(c.element.names) == 0 && c.element.name == "" && c.state == stateText { - // Not in an HTML element. - return []string{sanitizeHTMLFuncName}, nil - } - if c.attr.name != "" || len(c.attr.names) > 0 { - // We are in an attribute value context. - if c.delim != delimDoubleQuote && c.delim != delimSingleQuote { - // TODO: consider disallowing single-quoted or unquoted attribute values completely, even in hardcoded template text. - return nil, fmt.Errorf("unquoted attribute values disallowed") - } - return sanitizersForAttributeValue(c) - } - // Otherwise, we are in an element content context. - elementContentSanitizer, err := sanitizerForElementContent(c) - return appendIfNotEmpty([]string{}, elementContentSanitizer), err -} - -// appendIfNotEmpty appends the given strings that are non-empty to the given slice. -func appendIfNotEmpty(slice []string, strings ...string) []string { - for _, s := range strings { - if s != "" { - slice = append(slice, s) - } - } - return slice -} - -// sanitizersForAttributeValue returns a list of names of functions that will be -// called in order to sanitize data values found the HTML attribtue value context c. -func sanitizersForAttributeValue(c context) ([]string, error) { - // Ensure that all combinations of element and attribute names for this context results - // in the same attribute value sanitization context. - var elems, attrs []string - if len(c.element.names) == 0 { - elems = []string{c.element.name} - } else { - elems = c.element.names - } - if len(c.attr.names) == 0 { - attrs = []string{c.attr.name} - } else { - attrs = c.attr.names - } - var sc0 sanitizationContext - var elem0, attr0 string - for i, elem := range elems { - for j, attr := range attrs { - sc, err := sanitizationContextForAttrVal(elem, attr, c.linkRel) - if err != nil { - if len(elems) == 1 && len(attrs) == 1 { - return nil, err - } - return nil, fmt.Errorf(`conditional branch with {element=%q, attribute=%q} results in sanitization error: %s`, elem, attr, err) - } - if i == 0 && j == 0 { - sc0, elem0, attr0 = sc, elem, attr - continue - } - if sc != sc0 { - return nil, fmt.Errorf( - `conditional branches end in different attribute value sanitization contexts: {element=%q, attribute=%q} has sanitization context %q, {element=%q, attribute=%q} has sanitization context %q`, - elem0, attr0, sc0, elem, attr, sc) - } - } - } - if sc0.isEnum() && c.attr.value != "" { - return nil, fmt.Errorf("partial substitutions are disallowed in the %q attribute value context of a %q element", c.attr.name, c.element.name) - } - if sc0 == sanitizationContextStyle && c.attr.value != "" { - if err := validateDoesNotEndsWithCharRefPrefix(c.attr.value); err != nil { - return nil, fmt.Errorf("action cannot be interpolated into the %q attribute value of this %q element: %s", c.attr.name, c.element.name, err) - } - } - // ret is a stack of sanitizer names that will be built in reverse. - var ret []string - // All attribute values must be HTML-escaped at run time by sanitizeHTML to eliminate - // any HTML markup that can cause the HTML parser to transition out of the attribute value state. - // These attribute values will later be HTML-unescaped by the HTML parser in the browser. - ret = append(ret, sanitizeHTMLFuncName) - sanitizer := sc0.sanitizerName() - if !sc0.isURLorTrustedResourceURL() { - return reverse(appendIfNotEmpty(ret, sanitizer)), nil - } - urlAttrValPrefix := c.attr.value - if urlAttrValPrefix == "" { - // Attribute value prefixes in URL or TrustedResourceURL sanitization contexts - // must sanitized and normalized. - return reverse(appendIfNotEmpty(ret, normalizeURLFuncName, sanitizer)), nil - } - // Action occurs after a URL or TrustedResourceURL prefix. - if c.attr.ambiguousValue { - return nil, fmt.Errorf("actions must not occur after an ambiguous URL prefix in the %q attribute value context of a %q element", c.attr.name, c.element.name) - } - validator, ok := urlPrefixValidators[sc0] - if !ok { - return nil, fmt.Errorf("cannot validate attribute value prefix %q in the %q sanitization context", c.attr.value, sc0) - } - if err := validator(c.attr.value); err != nil { - return nil, fmt.Errorf("action cannot be interpolated into the %q URL attribute value of this %q element: %s", c.attr.name, c.element.name, err) - } - switch { - case sc0 == sanitizationContextTrustedResourceURL: - // Untrusted data that occurs anywhere after TrustedResourceURL prefix must be query-escaped - // to prevent the injection of any new path segments or URL components. Moreover, they must - // not contain any ".." dot-segments. - ret = append(ret, queryEscapeURLFuncName, validateTrustedResourceURLSubstitutionFuncName) - case strings.ContainsAny(urlAttrValPrefix, "#?"): - // For URLs, we only escape in the query or fragment part to prevent the injection of new query - // parameters or fragments. - ret = append(ret, queryEscapeURLFuncName) - default: - ret = append(ret, normalizeURLFuncName) - } - return reverse(ret), nil -} - -// reverse reverses s and returns it. -func reverse(s []string) []string { - for head, tail := 0, len(s)-1; head < tail; head, tail = head+1, tail-1 { - s[head], s[tail] = s[tail], s[head] - } - return s -} - -// sanitizationContextForAttrVal returns the sanitization context for attr when it -// appears within element. -func sanitizationContextForAttrVal(element, attr, linkRel string) (sanitizationContext, error) { - if element == "link" && attr == "href" { - // Special case: safehtml.URL values are allowed in a link element's href attribute if that element's - // rel attribute possesses certain values. - relVals := strings.Fields(linkRel) - for _, val := range relVals { - if urlLinkRelVals[val] { - return sanitizationContextTrustedResourceURLOrURL, nil - } - } - } - if dataAttributeNamePattern.MatchString(attr) { - // Special case: data-* attributes are specified by HTML5 to hold custom data private to - // the page or application; they should not be interpreted by browsers. Therefore, no - // sanitization is required for these attribute values. - return sanitizationContextNone, nil - } - if sc, ok := elementSpecificAttrValSanitizationContext[attr][element]; ok { - return sc, nil - } - sc, isAllowedAttr := globalAttrValSanitizationContext[attr] - _, isAllowedElement := elementContentSanitizationContext[element] - if isAllowedAttr && (isAllowedElement || allowedVoidElements[element]) { - // Only sanitize attributes that appear in elements whose semantics are known. - // Thes attributes might have different semantics in other standard or custom - // elements that our sanitization policy does not handle correctly. - return sc, nil - } - return 0, fmt.Errorf("actions must not occur in the %q attribute value context of a %q element", attr, element) -} - -// dataAttributeNamePattern matches valid data attribute names. -// This pattern is conservative and matches only a subset of the valid names defined in -// https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes -var dataAttributeNamePattern = regexp.MustCompile(`^data-[a-z_][-a-z0-9_]*$`) - -// endsWithCharRefPrefixPattern matches strings that end in an incomplete -// HTML character reference. -// -// See https://html.spec.whatwg.org/multipage/syntax.html#character-references. -var endsWithCharRefPrefixPattern = regexp.MustCompile( - `&(?:[[:alpha:]][[:alnum:]]*|#(?:[xX][[:xdigit:]]*|[[:digit:]]*))?$`) - -// validateDoesNotEndsWithCharRefPrefix returns an error only if the given prefix ends -// with an incomplete HTML character reference. -func validateDoesNotEndsWithCharRefPrefix(prefix string) error { - if endsWithCharRefPrefixPattern.MatchString(prefix) { - return fmt.Errorf(`prefix %q ends with an incomplete HTML character reference; did you mean "&" instead of "&"?`, prefix) - } - return nil -} - -// sanitizerForElementContent returns the name of the function that will be called -// to sanitize data values found in the HTML element content context c. -func sanitizerForElementContent(c context) (string, error) { - // Ensure that all other possible element names for this context result in the same - // element content sanitization context. - var elems []string - if len(c.element.names) == 0 { - elems = []string{c.element.name} - } else { - elems = c.element.names - } - var sc0 sanitizationContext - var elem0 string - for i, elem := range elems { - var sc sanitizationContext - var err error - if elem == "" { - // Special case: an empty element name represents a context outside of a HTML element. - sc = sanitizationContextHTML - } else { - sc, err = sanitizationContextForElementContent(elem) - } - if err != nil { - if len(elems) == 1 { - return "", err - } - return "", fmt.Errorf(`conditional branch with element %q results in sanitization error: %s`, elem, err) - } - if i == 0 { - sc0, elem0 = sc, elem - continue - } - if sc != sc0 { - return "", - fmt.Errorf(`conditional branches end in different element content sanitization contexts: element %q has sanitization context %q, element %q has sanitization context %q`, - elem0, sc0, elem, sc) - } - } - return sc0.sanitizerName(), nil -} - -// sanitizationContextForElementContent returns the element content sanitization context for the given element. -func sanitizationContextForElementContent(element string) (sanitizationContext, error) { - sc, ok := elementContentSanitizationContext[element] - if !ok { - return 0, fmt.Errorf("actions must not occur in the element content context of a %q element", element) - } - return sc, nil -} - -// sanitizeHTMLComment returns the empty string regardless of input. -// Comment content does not correspond to any parsed structure or -// human-readable content, so the simplest and most secure policy is to drop -// content interpolated into comments. -// This approach is equally valid whether or not static comment content is -// removed from the template. -func sanitizeHTMLComment(_ ...interface{}) string { - return "" -} diff --git a/vendor/github.com/google/safehtml/template/sanitizers.go b/vendor/github.com/google/safehtml/template/sanitizers.go deleted file mode 100644 index 782e931b8..000000000 --- a/vendor/github.com/google/safehtml/template/sanitizers.go +++ /dev/null @@ -1,599 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package template - -import ( - "fmt" - "text/template" - - "github.com/google/safehtml/internal/safehtmlutil" - "github.com/google/safehtml" -) - -// sanitizationContext determines what type of sanitization to perform -// on a template action. -type sanitizationContext uint8 - -const ( - _ = iota - sanitizationContextAsyncEnum - sanitizationContextDirEnum - sanitizationContextHTML - sanitizationContextHTMLValOnly - sanitizationContextIdentifier - sanitizationContextLoadingEnum - sanitizationContextNone - sanitizationContextRCDATA - sanitizationContextScript - sanitizationContextStyle - sanitizationContextStyleSheet - sanitizationContextTargetEnum - sanitizationContextTrustedResourceURL - sanitizationContextTrustedResourceURLOrURL - sanitizationContextURL - sanitizationContextURLSet -) - -// String returns the string representation of sanitizationContext s. -func (s sanitizationContext) String() string { - if int(s) >= len(sanitizationContextInfo) { - return fmt.Sprintf("invalid sanitization context %d", s) - } - return sanitizationContextInfo[s].name -} - -// sanitizerName returns the name of the sanitizer to call in sanitizationContext s. -// It returns an empty string if no sanitization is required in s. -func (s sanitizationContext) sanitizerName() string { - if int(s) >= len(sanitizationContextInfo) { - return fmt.Sprintf("invalid sanitization context %d", s) - } - return sanitizationContextInfo[s].sanitizerName -} - -// isEnum reports reports whether s is a sanitization context for enumerated values. -func (s sanitizationContext) isEnum() bool { - return s == sanitizationContextAsyncEnum || s == sanitizationContextDirEnum || s == sanitizationContextLoadingEnum || s == sanitizationContextTargetEnum -} - -// isURLorTrustedResourceURL reports reports whether s is a sanitization context for URL or TrustedResourceURL values. -func (s sanitizationContext) isURLorTrustedResourceURL() bool { - return s == sanitizationContextTrustedResourceURL || s == sanitizationContextTrustedResourceURLOrURL || s == sanitizationContextURL -} - -// sanitizationContextInfo[x] contains the name for sanitization context x and the -// name of the sanitizer to call in that context. -// If sanitizationContextInfo[x].sanitizerName is empty, then no sanitizer needs -// to be called in x. -var sanitizationContextInfo = [...]struct { - name, sanitizerName string -}{ - sanitizationContextAsyncEnum: {"AsyncEnum", sanitizeAsyncEnumFuncName}, - sanitizationContextDirEnum: {"DirEnum", sanitizeDirEnumFuncName}, - sanitizationContextHTML: {"HTML", sanitizeHTMLFuncName}, - sanitizationContextHTMLValOnly: {"HTMLValOnly", sanitizeHTMLValOnlyFuncName}, - sanitizationContextIdentifier: {"Identifier", sanitizeIdentifierFuncName}, - sanitizationContextLoadingEnum: {"LoadingEnum", sanitizeLoadingEnumFuncName}, - sanitizationContextNone: {"None", ""}, - sanitizationContextRCDATA: {"RCDATA", sanitizeRCDATAFuncName}, - sanitizationContextScript: {"Script", sanitizeScriptFuncName}, - sanitizationContextStyle: {"Style", sanitizeStyleFuncName}, - sanitizationContextStyleSheet: {"StyleSheet", sanitizeStyleSheetFuncName}, - sanitizationContextTargetEnum: {"TargetEnum", sanitizeTargetEnumFuncName}, - sanitizationContextTrustedResourceURL: {"TrustedResourceURL", sanitizeTrustedResourceURLFuncName}, - sanitizationContextTrustedResourceURLOrURL: {"TrustedResourceURLOrURL", sanitizeTrustedResourceURLOrURLFuncName}, - sanitizationContextURL: {"URL", sanitizeURLFuncName}, - sanitizationContextURLSet: {"URLSet", sanitizeURLSetFuncName}, -} - -var funcs = template.FuncMap{ - queryEscapeURLFuncName: safehtmlutil.QueryEscapeURL, - normalizeURLFuncName: safehtmlutil.NormalizeURL, - validateTrustedResourceURLSubstitutionFuncName: validateTrustedResourceURLSubstitution, - evalArgsFuncName: evalArgs, - sanitizeHTMLCommentFuncName: sanitizeHTMLComment, - sanitizeAsyncEnumFuncName: sanitizeAsyncEnum, - sanitizeDirEnumFuncName: sanitizeDirEnum, - sanitizeHTMLFuncName: sanitizeHTML, - sanitizeHTMLValOnlyFuncName: sanitizeHTMLValOnly, - sanitizeIdentifierFuncName: sanitizeIdentifier, - sanitizeLoadingEnumFuncName: sanitizeLoadingEnum, - sanitizeRCDATAFuncName: sanitizeRCDATA, - sanitizeScriptFuncName: sanitizeScript, - sanitizeStyleFuncName: sanitizeStyle, - sanitizeStyleSheetFuncName: sanitizeStyleSheet, - sanitizeTargetEnumFuncName: sanitizeTargetEnum, - sanitizeTrustedResourceURLFuncName: sanitizeTrustedResourceURL, - sanitizeTrustedResourceURLOrURLFuncName: sanitizeTrustedResourceURLOrURL, - sanitizeURLFuncName: sanitizeURL, - sanitizeURLSetFuncName: sanitizeURLSet, -} - -const ( - queryEscapeURLFuncName = "_queryEscapeURL" - normalizeURLFuncName = "_normalizeURL" - validateTrustedResourceURLSubstitutionFuncName = "_validateTrustedResourceURLSubstitution" - evalArgsFuncName = "_evalArgs" - sanitizeHTMLCommentFuncName = "_sanitizeHTMLComment" - sanitizeAsyncEnumFuncName = "_sanitizeAsyncEnum" - sanitizeDirEnumFuncName = "_sanitizeDirEnum" - sanitizeHTMLFuncName = "_sanitizeHTML" - sanitizeHTMLValOnlyFuncName = "_sanitizeHTMLValOnly" - sanitizeIdentifierFuncName = "_sanitizeIdentifier" - sanitizeLoadingEnumFuncName = "_sanitizeLoadingEnum" - sanitizeRCDATAFuncName = "_sanitizeRCDATA" - sanitizeScriptFuncName = "_sanitizeScript" - sanitizeStyleFuncName = "_sanitizeStyle" - sanitizeStyleSheetFuncName = "_sanitizeStyleSheet" - sanitizeTargetEnumFuncName = "_sanitizeTargetEnum" - sanitizeTrustedResourceURLFuncName = "_sanitizeTrustedResourceURL" - sanitizeTrustedResourceURLOrURLFuncName = "_sanitizeTrustedResourceURLOrURL" - sanitizeURLFuncName = "_sanitizeURL" - sanitizeURLSetFuncName = "_sanitizeURLSet" -) - -// urlLinkRelVals contains values for a link element's rel attribute that indicate that the same link -// element's href attribute may contain a safehtml.URL value. -var urlLinkRelVals = map[string]bool{ - "alternate": true, - "author": true, - "bookmark": true, - "canonical": true, - "cite": true, - "dns-prefetch": true, - "help": true, - "icon": true, - "license": true, - "next": true, - "preconnect": true, - "prefetch": true, - "preload": true, - "prerender": true, - "prev": true, - "search": true, - "subresource": true, -} - -// elementSpecificAttrValSanitizationContext[x][y] is the sanitization context for -// attribute x when it appears within element y. -var elementSpecificAttrValSanitizationContext = map[string]map[string]sanitizationContext{ - "accept": { - "input": sanitizationContextNone, - }, - "action": { - "form": sanitizationContextURL, - }, - "defer": { - "script": sanitizationContextNone, - }, - "formaction": { - "button": sanitizationContextURL, - "input": sanitizationContextURL, - }, - "formmethod": { - "button": sanitizationContextNone, - "input": sanitizationContextNone, - }, - "href": { - "a": sanitizationContextTrustedResourceURLOrURL, - "area": sanitizationContextTrustedResourceURLOrURL, - }, - "method": { - "form": sanitizationContextNone, - }, - "pattern": { - "input": sanitizationContextNone, - }, - "readonly": { - "input": sanitizationContextNone, - "textarea": sanitizationContextNone, - }, - "src": { - "audio": sanitizationContextTrustedResourceURLOrURL, - "img": sanitizationContextTrustedResourceURLOrURL, - "input": sanitizationContextTrustedResourceURLOrURL, - "source": sanitizationContextTrustedResourceURLOrURL, - "video": sanitizationContextTrustedResourceURLOrURL, - }, - "srcdoc": { - "iframe": sanitizationContextHTMLValOnly, - }, -} - -// globalAttrValSanitizationContext[x] is the sanitization context for attribute x when -// it appears within any element not in the key set of elementSpecificAttrValSanitizationContext[x]. -var globalAttrValSanitizationContext = map[string]sanitizationContext{ - "align": sanitizationContextNone, - "alt": sanitizationContextNone, - "aria-activedescendant": sanitizationContextIdentifier, - "aria-atomic": sanitizationContextNone, - "aria-autocomplete": sanitizationContextNone, - "aria-busy": sanitizationContextNone, - "aria-checked": sanitizationContextNone, - "aria-controls": sanitizationContextIdentifier, - "aria-current": sanitizationContextNone, - "aria-disabled": sanitizationContextNone, - "aria-dropeffect": sanitizationContextNone, - "aria-expanded": sanitizationContextNone, - "aria-haspopup": sanitizationContextNone, - "aria-hidden": sanitizationContextNone, - "aria-invalid": sanitizationContextNone, - "aria-label": sanitizationContextNone, - "aria-labelledby": sanitizationContextIdentifier, - "aria-level": sanitizationContextNone, - "aria-live": sanitizationContextNone, - "aria-multiline": sanitizationContextNone, - "aria-multiselectable": sanitizationContextNone, - "aria-orientation": sanitizationContextNone, - "aria-owns": sanitizationContextIdentifier, - "aria-posinset": sanitizationContextNone, - "aria-pressed": sanitizationContextNone, - "aria-readonly": sanitizationContextNone, - "aria-relevant": sanitizationContextNone, - "aria-required": sanitizationContextNone, - "aria-selected": sanitizationContextNone, - "aria-setsize": sanitizationContextNone, - "aria-sort": sanitizationContextNone, - "aria-valuemax": sanitizationContextNone, - "aria-valuemin": sanitizationContextNone, - "aria-valuenow": sanitizationContextNone, - "aria-valuetext": sanitizationContextNone, - "async": sanitizationContextAsyncEnum, - "autocapitalize": sanitizationContextNone, - "autocomplete": sanitizationContextNone, - "autocorrect": sanitizationContextNone, - "autofocus": sanitizationContextNone, - "autoplay": sanitizationContextNone, - "bgcolor": sanitizationContextNone, - "border": sanitizationContextNone, - "cellpadding": sanitizationContextNone, - "cellspacing": sanitizationContextNone, - "checked": sanitizationContextNone, - "cite": sanitizationContextURL, - "class": sanitizationContextNone, - "color": sanitizationContextNone, - "cols": sanitizationContextNone, - "colspan": sanitizationContextNone, - "contenteditable": sanitizationContextNone, - "controls": sanitizationContextNone, - "datetime": sanitizationContextNone, - "dir": sanitizationContextDirEnum, - "disabled": sanitizationContextNone, - "download": sanitizationContextNone, - "draggable": sanitizationContextNone, - "enctype": sanitizationContextNone, - "face": sanitizationContextNone, - "for": sanitizationContextIdentifier, - "formenctype": sanitizationContextNone, - "frameborder": sanitizationContextNone, - "height": sanitizationContextNone, - "hidden": sanitizationContextNone, - "href": sanitizationContextTrustedResourceURL, - "hreflang": sanitizationContextNone, - "id": sanitizationContextIdentifier, - "ismap": sanitizationContextNone, - "itemid": sanitizationContextNone, - "itemprop": sanitizationContextNone, - "itemref": sanitizationContextNone, - "itemscope": sanitizationContextNone, - "itemtype": sanitizationContextNone, - "label": sanitizationContextNone, - "lang": sanitizationContextNone, - "list": sanitizationContextIdentifier, - "loading": sanitizationContextLoadingEnum, - "loop": sanitizationContextNone, - "max": sanitizationContextNone, - "maxlength": sanitizationContextNone, - "media": sanitizationContextNone, - "min": sanitizationContextNone, - "minlength": sanitizationContextNone, - "multiple": sanitizationContextNone, - "muted": sanitizationContextNone, - "name": sanitizationContextIdentifier, - "nonce": sanitizationContextNone, - "open": sanitizationContextNone, - "placeholder": sanitizationContextNone, - "poster": sanitizationContextURL, - "preload": sanitizationContextNone, - "rel": sanitizationContextNone, - "required": sanitizationContextNone, - "reversed": sanitizationContextNone, - "role": sanitizationContextNone, - "rows": sanitizationContextNone, - "rowspan": sanitizationContextNone, - "selected": sanitizationContextNone, - "shape": sanitizationContextNone, - "size": sanitizationContextNone, - "sizes": sanitizationContextNone, - "slot": sanitizationContextNone, - "span": sanitizationContextNone, - "spellcheck": sanitizationContextNone, - "src": sanitizationContextTrustedResourceURL, - "srcset": sanitizationContextURLSet, - "start": sanitizationContextNone, - "step": sanitizationContextNone, - "style": sanitizationContextStyle, - "summary": sanitizationContextNone, - "tabindex": sanitizationContextNone, - "target": sanitizationContextTargetEnum, - "title": sanitizationContextNone, - "translate": sanitizationContextNone, - "type": sanitizationContextNone, - "valign": sanitizationContextNone, - "value": sanitizationContextNone, - "width": sanitizationContextNone, - "wrap": sanitizationContextNone, -} - -// elementContentSanitizationContext maps element names to element content sanitization contexts. -var elementContentSanitizationContext = map[string]sanitizationContext{ - "a": sanitizationContextHTML, - "abbr": sanitizationContextHTML, - "address": sanitizationContextHTML, - "article": sanitizationContextHTML, - "aside": sanitizationContextHTML, - "audio": sanitizationContextHTML, - "b": sanitizationContextHTML, - "bdi": sanitizationContextHTML, - "bdo": sanitizationContextHTML, - "blockquote": sanitizationContextHTML, - "body": sanitizationContextHTML, - "button": sanitizationContextHTML, - "canvas": sanitizationContextHTML, - "caption": sanitizationContextHTML, - "center": sanitizationContextHTML, - "cite": sanitizationContextHTML, - "code": sanitizationContextHTML, - "colgroup": sanitizationContextHTML, - "command": sanitizationContextHTML, - "data": sanitizationContextHTML, - "datalist": sanitizationContextHTML, - "dd": sanitizationContextHTML, - "del": sanitizationContextHTML, - "details": sanitizationContextHTML, - "dfn": sanitizationContextHTML, - "dialog": sanitizationContextHTML, - "div": sanitizationContextHTML, - "dl": sanitizationContextHTML, - "dt": sanitizationContextHTML, - "em": sanitizationContextHTML, - "fieldset": sanitizationContextHTML, - "figcaption": sanitizationContextHTML, - "figure": sanitizationContextHTML, - "font": sanitizationContextHTML, - "footer": sanitizationContextHTML, - "form": sanitizationContextHTML, - "frame": sanitizationContextHTML, - "frameset": sanitizationContextHTML, - "h1": sanitizationContextHTML, - "h2": sanitizationContextHTML, - "h3": sanitizationContextHTML, - "h4": sanitizationContextHTML, - "h5": sanitizationContextHTML, - "h6": sanitizationContextHTML, - "head": sanitizationContextHTML, - "header": sanitizationContextHTML, - "html": sanitizationContextHTML, - "i": sanitizationContextHTML, - "iframe": sanitizationContextHTML, - "ins": sanitizationContextHTML, - "kbd": sanitizationContextHTML, - "label": sanitizationContextHTML, - "legend": sanitizationContextHTML, - "lh": sanitizationContextHTML, - "li": sanitizationContextHTML, - "main": sanitizationContextHTML, - "map": sanitizationContextHTML, - "mark": sanitizationContextHTML, - "menu": sanitizationContextHTML, - "meter": sanitizationContextHTML, - "nav": sanitizationContextHTML, - "noscript": sanitizationContextHTML, - "ol": sanitizationContextHTML, - "optgroup": sanitizationContextHTML, - "option": sanitizationContextHTML, - "output": sanitizationContextHTML, - "p": sanitizationContextHTML, - "picture": sanitizationContextHTML, - "pre": sanitizationContextHTML, - "progress": sanitizationContextHTML, - "q": sanitizationContextHTML, - "rb": sanitizationContextHTML, - "rp": sanitizationContextHTML, - "rt": sanitizationContextHTML, - "rtc": sanitizationContextHTML, - "ruby": sanitizationContextHTML, - "s": sanitizationContextHTML, - "samp": sanitizationContextHTML, - "script": sanitizationContextScript, - "section": sanitizationContextHTML, - "select": sanitizationContextHTML, - "slot": sanitizationContextHTML, - "small": sanitizationContextHTML, - "span": sanitizationContextHTML, - "strong": sanitizationContextHTML, - "style": sanitizationContextStyleSheet, - "sub": sanitizationContextHTML, - "summary": sanitizationContextHTML, - "sup": sanitizationContextHTML, - "table": sanitizationContextHTML, - "tbody": sanitizationContextHTML, - "td": sanitizationContextHTML, - "textarea": sanitizationContextRCDATA, - "tfoot": sanitizationContextHTML, - "th": sanitizationContextHTML, - "thead": sanitizationContextHTML, - "time": sanitizationContextHTML, - "title": sanitizationContextRCDATA, - "tr": sanitizationContextHTML, - "u": sanitizationContextHTML, - "ul": sanitizationContextHTML, - "var": sanitizationContextHTML, - "video": sanitizationContextHTML, -} - -// allowedVoidElements is a set of names of void elements actions may appear in. -var allowedVoidElements = map[string]bool{ - "area": true, - "br": true, - "col": true, - "hr": true, - "img": true, - "input": true, - "link": true, - "param": true, - "source": true, - "track": true, - "wbr": true, -} - -var sanitizeAsyncEnumValues = map[string]bool{ - "async": true, -} - -func sanitizeAsyncEnum(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - if sanitizeAsyncEnumValues[input] { - return input, nil - } - return "", fmt.Errorf(`expected one of the following strings: ["async"]`) -} - -var sanitizeDirEnumValues = map[string]bool{ - "auto": true, - "ltr": true, - "rtl": true, -} - -func sanitizeDirEnum(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - if sanitizeDirEnumValues[input] { - return input, nil - } - return "", fmt.Errorf(`expected one of the following strings: ["auto" "ltr" "rtl"]`) -} - -func sanitizeHTML(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.HTML); ok { - return safeTypeValue.String(), nil - } - } - input := safehtmlutil.Stringify(args...) - return safehtml.HTMLEscaped(input).String(), nil -} - -func sanitizeHTMLValOnly(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.HTML); ok { - return safeTypeValue.String(), nil - } - } - return "", fmt.Errorf(`expected a safehtml.HTML value`) -} - -func sanitizeIdentifier(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.Identifier); ok { - return safeTypeValue.String(), nil - } - } - return "", fmt.Errorf(`expected a safehtml.Identifier value`) -} - -var sanitizeLoadingEnumValues = map[string]bool{ - "eager": true, - "lazy": true, -} - -func sanitizeLoadingEnum(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - if sanitizeLoadingEnumValues[input] { - return input, nil - } - return "", fmt.Errorf(`expected one of the following strings: ["eager" "lazy"]`) -} - -func sanitizeRCDATA(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - return safehtml.HTMLEscaped(input).String(), nil -} - -func sanitizeScript(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.Script); ok { - return safeTypeValue.String(), nil - } - } - return "", fmt.Errorf(`expected a safehtml.Script value`) -} - -func sanitizeStyle(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.Style); ok { - return safeTypeValue.String(), nil - } - } - return "", fmt.Errorf(`expected a safehtml.Style value`) -} - -func sanitizeStyleSheet(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.StyleSheet); ok { - return safeTypeValue.String(), nil - } - } - return "", fmt.Errorf(`expected a safehtml.StyleSheet value`) -} - -var sanitizeTargetEnumValues = map[string]bool{ - "_blank": true, - "_self": true, -} - -func sanitizeTargetEnum(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - if sanitizeTargetEnumValues[input] { - return input, nil - } - return "", fmt.Errorf(`expected one of the following strings: ["_blank" "_self"]`) -} - -func sanitizeTrustedResourceURL(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.TrustedResourceURL); ok { - return safeTypeValue.String(), nil - } - } - return "", fmt.Errorf(`expected a safehtml.TrustedResourceURL value`) -} - -func sanitizeTrustedResourceURLOrURL(args ...interface{}) (string, error) { - if len(args) > 0 { - switch v := safehtmlutil.Indirect(args[0]).(type) { - case safehtml.TrustedResourceURL, safehtml.URL: - return safehtmlutil.Stringify(v), nil - } - } - input := safehtmlutil.Stringify(args...) - return safehtml.URLSanitized(input).String(), nil -} - -func sanitizeURL(args ...interface{}) (string, error) { - if len(args) > 0 { - if safeTypeValue, ok := safehtmlutil.Indirect(args[0]).(safehtml.URL); ok { - return safeTypeValue.String(), nil - } - } - input := safehtmlutil.Stringify(args...) - return safehtml.URLSanitized(input).String(), nil -} - -func sanitizeURLSet(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - return safehtml.URLSetSanitized(input).String(), nil -} diff --git a/vendor/github.com/google/safehtml/template/state_string.go b/vendor/github.com/google/safehtml/template/state_string.go deleted file mode 100644 index afbbf5a0d..000000000 --- a/vendor/github.com/google/safehtml/template/state_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// Code generated by "stringer -type State"; DO NOT EDIT - -package template - -import "fmt" - -const _State_name = "StateTextStateSpecialElementBodyStateTagStateAttrNameStateAfterNameStateBeforeValueStateHTMLCmtStateAttrStateError" - -var _State_index = [...]uint16{0, 9, 32, 40, 53, 67, 83, 95, 104, 114} - -func (i state) String() string { - if i >= state(len(_State_index)-1) { - return fmt.Sprintf("state(%d)", i) - } - return _State_name[_State_index[i]:_State_index[i+1]] -} diff --git a/vendor/github.com/google/safehtml/template/template.go b/vendor/github.com/google/safehtml/template/template.go deleted file mode 100644 index efd0ef610..000000000 --- a/vendor/github.com/google/safehtml/template/template.go +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "path/filepath" - "sync" - "text/template" - "text/template/parse" - - "log" - "github.com/google/safehtml" - "github.com/google/safehtml/uncheckedconversions" -) - -// Template is a specialized Template from "text/template" that produces a safe -// HTML document fragment. -type Template struct { - // Sticky error if escaping fails, or errEscapeOK if succeeded. - escapeErr error - // We could embed the text/template field, but it's safer not to because - // we need to keep our version of the name space and the underlying - // template's in sync. - text *template.Template - // The underlying template's parse tree, updated to be HTML-safe. - Tree *parse.Tree - *nameSpace // common to all associated templates -} - -// errEscapeOK is a sentinel value used to indicate valid escaping. -var errEscapeOK = fmt.Errorf("template escaped correctly") - -// nameSpace is the data structure shared by all templates in an association. -type nameSpace struct { - mu sync.Mutex - set map[string]*Template - escaped bool - // cspCompatible indicates whether inline event handlers and - // javascript: URIs are disallowed in templates in this namespace. - cspCompatible bool - esc escaper -} - -// Templates returns a slice of the templates associated with t, including t -// itself. -func (t *Template) Templates() []*Template { - ns := t.nameSpace - ns.mu.Lock() - defer ns.mu.Unlock() - // Return a slice so we don't expose the map. - m := make([]*Template, 0, len(ns.set)) - for _, v := range ns.set { - m = append(m, v) - } - return m -} - -// Option sets options for the template. Options are described by -// strings, either a simple string or "key=value". There can be at -// most one equals sign in an option string. If the option string -// is unrecognized or otherwise invalid, Option panics. -// -// Known options: -// -// missingkey: Control the behavior during execution if a map is -// indexed with a key that is not present in the map. -// "missingkey=default" or "missingkey=invalid" -// The default behavior: Do nothing and continue execution. -// If printed, the result of the index operation is the string -// "<no value>". -// "missingkey=zero" -// The operation returns the zero value for the map type's element. -// "missingkey=error" -// Execution stops immediately with an error. -// -func (t *Template) Option(opt ...string) *Template { - t.text.Option(opt...) - return t -} - -// checkCanParse checks whether it is OK to parse templates. -// If not, it returns an error. -func (t *Template) checkCanParse() error { - if t == nil { - return nil - } - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - if t.nameSpace.escaped { - return fmt.Errorf("html/template: cannot Parse after Execute") - } - return nil -} - -// escape escapes all associated templates. -func (t *Template) escape() error { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - t.nameSpace.escaped = true - if t.escapeErr == nil { - if t.Tree == nil { - return fmt.Errorf("template: %q is an incomplete or empty template", t.Name()) - } - if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil { - return err - } - } else if t.escapeErr != errEscapeOK { - return t.escapeErr - } - return nil -} - -// Execute applies a parsed template to the specified data object, -// writing the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel, although if parallel -// executions share a Writer the output may be interleaved. -func (t *Template) Execute(wr io.Writer, data interface{}) error { - if err := t.escape(); err != nil { - return err - } - return t.text.Execute(wr, data) -} - -// ExecuteToHTML applies a parsed template to the specified data object, -// returning the output as a safehtml.HTML value. -// A template may be executed safely in parallel. -func (t *Template) ExecuteToHTML(data interface{}) (safehtml.HTML, error) { - var buf bytes.Buffer - if err := t.Execute(&buf, data); err != nil { - return safehtml.HTML{}, err - } - return uncheckedconversions.HTMLFromStringKnownToSatisfyTypeContract(buf.String()), nil -} - -// MustParseAndExecuteToHTML is a helper that returns the safehtml.HTML value produced -// by parsing text as a template body and executing it with no data. Any errors -// encountered parsing or executing the template are fatal. This function is intended -// to produce safehtml.HTML values from static HTML snippets such as -// -// html := MustParseAndExecuteToHTML("<b>Important</b>") -// -// To guarantee that the template body is never controlled by an attacker, text -// must be an untyped string constant, which is always under programmer control. -func MustParseAndExecuteToHTML(text stringConstant) safehtml.HTML { - t, err := New("").Parse(text) - if err != nil { - log.Fatal(err) - } - html, err := t.ExecuteToHTML(nil) - if err != nil { - log.Fatal(err) - } - return html -} - -// ExecuteTemplate applies the template associated with t that has the given -// name to the specified data object and writes the output to wr. -// If an error occurs executing the template or writing its output, -// execution stops, but partial results may already have been written to -// the output writer. -// A template may be executed safely in parallel, although if parallel -// executions share a Writer the output may be interleaved. -func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { - tmpl, err := t.lookupAndEscapeTemplate(name) - if err != nil { - return err - } - return tmpl.text.Execute(wr, data) -} - -// ExecuteTemplateToHTML applies the template associated with t that has -// the given name to the specified data object and returns the output as -// a safehtml.HTML value. -// A template may be executed safely in parallel. -func (t *Template) ExecuteTemplateToHTML(name string, data interface{}) (safehtml.HTML, error) { - var buf bytes.Buffer - if err := t.ExecuteTemplate(&buf, name, data); err != nil { - return safehtml.HTML{}, err - } - return uncheckedconversions.HTMLFromStringKnownToSatisfyTypeContract(buf.String()), nil -} - -// lookupAndEscapeTemplate guarantees that the template with the given name -// is escaped, or returns an error if it cannot be. It returns the named -// template. -func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - t.nameSpace.escaped = true - tmpl = t.set[name] - if tmpl == nil { - return nil, fmt.Errorf("html/template: %q is undefined", name) - } - if tmpl.escapeErr != nil && tmpl.escapeErr != errEscapeOK { - return nil, tmpl.escapeErr - } - if tmpl.text.Tree == nil || tmpl.text.Root == nil { - return nil, fmt.Errorf("html/template: %q is an incomplete template", name) - } - if t.text.Lookup(name) == nil { - panic("html/template internal error: template escaping out of sync") - } - if tmpl.escapeErr == nil { - err = escapeTemplate(tmpl, tmpl.text.Root, name) - } - return tmpl, err -} - -// DefinedTemplates returns a string listing the defined templates, -// prefixed by the string "; defined templates are: ". If there are none, -// it returns the empty string. Used to generate an error message. -func (t *Template) DefinedTemplates() string { - return t.text.DefinedTemplates() -} - -// Parse parses text as a template body for t. -// Named template definitions ({{define ...}} or {{block ...}} statements) in text -// define additional templates associated with t and are removed from the -// definition of t itself. -// -// Templates can be redefined in successive calls to Parse, -// before the first use of Execute on t or any associated template. -// A template definition with a body containing only white space and comments -// is considered empty and will not replace an existing template's body. -// This allows using Parse to add new named template definitions without -// overwriting the main template body. -// -// To guarantee that the template body is never controlled by an attacker, text -// must be an untyped string constant, which is always under programmer control. -func (t *Template) Parse(text stringConstant) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - - ret, err := t.text.Parse(string(text)) - if err != nil { - return nil, err - } - - // In general, all the named templates might have changed underfoot. - // Regardless, some new ones may have been defined. - // The template.Template set has been updated; update ours. - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - for _, v := range ret.Templates() { - name := v.Name() - tmpl := t.set[name] - if tmpl == nil { - tmpl = t.new(name) - } - tmpl.text = v - tmpl.Tree = v.Tree - } - return t, nil -} - -// ParseFromTrustedTemplate parses tmpl as a template body for t. -// Named template definitions ({{define ...}} or {{block ...}} statements) in text -// define additional templates associated with t and are removed from the -// definition of t itself. -// -// Templates can be redefined in successive calls to ParseFromTrustedTemplate, -// before the first use of Execute on t or any associated template. -// A template definition with a body containing only white space and comments -// is considered empty and will not replace an existing template's body. -// This allows using ParseFromTrustedTemplate to add new named template definitions without -// overwriting the main template body. -// -// To guarantee that the template body is never controlled by an attacker, tmpl -// is a TrustedTemplate, which is always under programmer control. -func (t *Template) ParseFromTrustedTemplate(tmpl TrustedTemplate) (*Template, error) { - return t.Parse(stringConstant(tmpl.String())) -} - -// Clone returns a duplicate of the template, including all associated -// templates. The actual representation is not copied, but the name space of -// associated templates is, so further calls to Parse in the copy will add -// templates to the copy but not to the original. Clone can be used to prepare -// common templates and use them with variant definitions for other templates -// by adding the variants after the clone is made. -// -// It returns an error if t has already been executed. -func (t *Template) Clone() (*Template, error) { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - if t.escapeErr != nil { - return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) - } - textClone, err := t.text.Clone() - if err != nil { - return nil, err - } - ns := &nameSpace{set: make(map[string]*Template)} - ns.esc = makeEscaper(ns) - ret := &Template{ - nil, - textClone, - textClone.Tree, - ns, - } - ret.set[ret.Name()] = ret - for _, x := range textClone.Templates() { - name := x.Name() - src := t.set[name] - if src == nil || src.escapeErr != nil { - return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name()) - } - x.Tree = x.Tree.Copy() - ret.set[name] = &Template{ - nil, - x, - x.Tree, - ret.nameSpace, - } - } - // Return the template associated with the name of this template. - return ret.set[ret.Name()], nil -} - -// New allocates a new HTML template with the given name. -func New(name string) *Template { - ns := &nameSpace{set: make(map[string]*Template)} - ns.esc = makeEscaper(ns) - tmpl := &Template{ - nil, - template.New(name), - nil, - ns, - } - tmpl.set[name] = tmpl - return tmpl -} - -// New allocates a new HTML template associated with the given one -// and with the same delimiters. The association, which is transitive, -// allows one template to invoke another with a {{template}} action. -// -// If a template with the given name already exists, the new HTML template -// will replace it. The existing template will be reset and disassociated with -// t. -func (t *Template) New(name string) *Template { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - return t.new(name) -} - -// new is the implementation of New, without the lock. -func (t *Template) new(name string) *Template { - tmpl := &Template{ - nil, - t.text.New(name), - nil, - t.nameSpace, - } - if existing, ok := tmpl.set[name]; ok { - emptyTmpl := New(existing.Name()) - *existing = *emptyTmpl - } - tmpl.set[name] = tmpl - return tmpl -} - -// Name returns the name of the template. -func (t *Template) Name() string { - return t.text.Name() -} - -// FuncMap is the type of the map defining the mapping from names to -// functions. Each function must have either a single return value, or two -// return values of which the second has type error. In that case, if the -// second (error) argument evaluates to non-nil during execution, execution -// terminates and Execute returns that error. FuncMap has the same base type -// as FuncMap in "text/template", copied here so clients need not import -// "text/template". -type FuncMap map[string]interface{} - -// Funcs adds the elements of the argument map to the template's function map. -// It must be called before the template is parsed. -// It panics if a value in the map is not a function with appropriate return -// type. However, it is legal to overwrite elements of the map. The return -// value is the template, so calls can be chained. -func (t *Template) Funcs(funcMap FuncMap) *Template { - t.text.Funcs(template.FuncMap(funcMap)) - return t -} - -// CSPCompatible causes this template to check template text for -// Content Security Policy (CSP) compatibility. The template will return errors -// at execution time if inline event handler attribute names or javascript: -// URIs are found in template text. -// -// For example, the following templates will cause errors: -// <span onclick="doThings();">A thing.</span> // inline event handler "onclick" -// <a href="javascript:linkClicked()">foo</a> // javascript: URI present -func (t *Template) CSPCompatible() *Template { - t.nameSpace.mu.Lock() - t.nameSpace.cspCompatible = true - t.nameSpace.mu.Unlock() - return t -} - -// Delims sets the action delimiters to the specified strings, to be used in -// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template -// definitions will inherit the settings. An empty delimiter stands for the -// corresponding default: {{ or }}. -// The return value is the template, so calls can be chained. -func (t *Template) Delims(left, right string) *Template { - t.text.Delims(left, right) - return t -} - -// Lookup returns the template with the given name that is associated with t, -// or nil if there is no such template. -func (t *Template) Lookup(name string) *Template { - t.nameSpace.mu.Lock() - defer t.nameSpace.mu.Unlock() - return t.set[name] -} - -// Must is a helper that wraps a call to a function returning (*Template, error) -// and panics if the error is non-nil. It is intended for use in variable initializations -// such as -// var t = template.Must(template.New("name").Parse("html")) -func Must(t *Template, err error) *Template { - if err != nil { - panic(err) - } - return t -} - -// stringConstant is an unexported string type. Users of this package cannot -// create values of this type except by passing an untyped string constant to -// functions which expect a stringConstant. This type must be used only in -// function and method parameters. -type stringConstant string - -func stringConstantsToStrings(strs []stringConstant) []string { - ret := make([]string, 0, len(strs)) - for _, s := range strs { - ret = append(ret, string(s)) - } - return ret -} - -// ParseFiles creates a new Template and parses the template definitions from -// the named files. The returned template's name will have the (base) name and -// (parsed) contents of the first file. There must be at least one file. -// If an error occurs, parsing stops and the returned *Template is nil. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template -// named "foo", while "a/foo" is unavailable. -// -// To guarantee that filepaths, and thus template bodies, are never controlled by -// an attacker, filenames must be untyped string constants, which are always under -// programmer control. -func ParseFiles(filenames ...stringConstant) (*Template, error) { - return parseFiles(nil, readFileOS, stringConstantsToStrings(filenames)...) -} - -// ParseFilesFromTrustedSources creates a new Template and parses the template definitions from -// the named files. The returned template's name will have the (base) name and -// (parsed) contents of the first file. There must be at least one file. -// If an error occurs, parsing stops and the returned *Template is nil. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template -// named "foo", while "a/foo" is unavailable. -// -// To guarantee that filepaths, and thus template bodies, are never controlled by -// an attacker, filenames must be trusted sources, which are always under programmer -// or application control. -func ParseFilesFromTrustedSources(filenames ...TrustedSource) (*Template, error) { - return parseFiles(nil, readFileOS, trustedSourcesToStrings(filenames)...) -} - -// ParseFiles parses the named files and associates the resulting templates with -// t. If an error occurs, parsing stops and the returned template is nil; -// otherwise it is t. There must be at least one file. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// -// ParseFiles returns an error if t or any associated template has already been executed. -// -// To guarantee that filepaths, and thus template bodies, are never controlled by -// an attacker, filenames must be untyped string constants, which are always under -// programmer control. -func (t *Template) ParseFiles(filenames ...stringConstant) (*Template, error) { - return parseFiles(t, readFileOS, stringConstantsToStrings(filenames)...) -} - -// ParseFilesFromTrustedSources parses the named files and associates the resulting templates with -// t. If an error occurs, parsing stops and the returned template is nil; -// otherwise it is t. There must be at least one file. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// -// ParseFilesFromTrustedSources returns an error if t or any associated template has already been executed. -// -// To guarantee that filepaths, and thus template bodies, are never controlled by -// an attacker, filenames must be trusted sources, which are always under programmer -// or application control. -func (t *Template) ParseFilesFromTrustedSources(filenames ...TrustedSource) (*Template, error) { - return parseFiles(t, readFileOS, trustedSourcesToStrings(filenames)...) -} - -// parseFiles is the helper for the method and function. If the argument -// template is nil, it is created from the first file. -// readFile takes a filename and returns the file's basename and contents. -func parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - - if len(filenames) == 0 { - // Not really a problem, but be consistent. - return nil, fmt.Errorf("html/template: no files named in call to ParseFiles") - } - for _, filename := range filenames { - name, b, err := readFile(filename) - if err != nil { - return nil, err - } - s := stringConstant(b) - // First template becomes return value if not already defined, - // and we use that one for subsequent New calls to associate - // all the templates together. Also, if this file has the same name - // as t, this file becomes the contents of t, so - // t, err := New(name).Funcs(xxx).ParseFiles(name) - // works. Otherwise we create a new template associated with t. - var tmpl *Template - if t == nil { - t = New(name) - } - if name == t.Name() { - tmpl = t - } else { - tmpl = t.New(name) - } - _, err = tmpl.Parse(s) - if err != nil { - return nil, err - } - } - return t, nil -} - -// Copied with minor changes from -// https://go.googlesource.com/go/+/refs/tags/go1.17.1/src/text/template/helper.go. -func readFileOS(file string) (string, []byte, error) { - name := filepath.Base(file) - b, err := ioutil.ReadFile(file) - return name, b, err -} - -// ParseGlob creates a new Template and parses the template definitions from the -// files identified by the pattern, which must match at least one file. The -// returned template will have the (base) name and (parsed) contents of the -// first file matched by the pattern. ParseGlob is equivalent to calling -// ParseFiles with the list of files matched by the pattern. -// -// To guarantee that the pattern, and thus the template bodies, is never controlled by -// an attacker, pattern must be an untyped string constant, which is always under -// programmer control. -func ParseGlob(pattern stringConstant) (*Template, error) { - return parseGlob(nil, string(pattern)) -} - -// ParseGlobFromTrustedSource creates a new Template and parses the template definitions from the -// files identified by the pattern, which must match at least one file. The -// returned template will have the (base) name and (parsed) contents of the -// first file matched by the pattern. ParseGlobFromTrustedSource is equivalent to calling -// ParseFilesFromTrustedSources with the list of files matched by the pattern. -// -// To guarantee that the pattern, and thus the template bodies, is never controlled by -// an attacker, pattern must be a trusted source, which is always under programmer or -// application control. -func ParseGlobFromTrustedSource(pattern TrustedSource) (*Template, error) { - return parseGlob(nil, pattern.String()) -} - -// ParseGlob parses the template definitions in the files identified by the -// pattern and associates the resulting templates with t. The pattern is -// processed by filepath.Glob and must match at least one file. ParseGlob is -// equivalent to calling t.ParseFiles with the list of files matched by the -// pattern. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// -// ParseGlob returns an error if t or any associated template has already been executed. -// -// To guarantee that the pattern, and thus the template bodies, is never controlled by -// an attacker, pattern must be an untyped string constant, which is always under -// programmer control. -func (t *Template) ParseGlob(pattern stringConstant) (*Template, error) { - return parseGlob(t, string(pattern)) -} - -// ParseGlobFromTrustedSource parses the template definitions in the files identified by the -// pattern and associates the resulting templates with t. The pattern is -// processed by filepath.Glob and must match at least one file. ParseGlob is -// equivalent to calling t.ParseFiles with the list of files matched by the -// pattern. -// -// When parsing multiple files with the same name in different directories, -// the last one mentioned will be the one that results. -// -// ParseGlobFromTrustedSource returns an error if t or any associated template has already been executed. -// -// To guarantee that the pattern, and thus the template bodies, is never controlled by -// an attacker, pattern must be a trusted source, which is always under programmer or -// application control. -func (t *Template) ParseGlobFromTrustedSource(pattern TrustedSource) (*Template, error) { - return parseGlob(t, pattern.String()) -} - -// parseGlob is the implementation of the function and method ParseGlob. -func parseGlob(t *Template, pattern string) (*Template, error) { - if err := t.checkCanParse(); err != nil { - return nil, err - } - filenames, err := filepath.Glob(pattern) - if err != nil { - return nil, err - } - if len(filenames) == 0 { - return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern) - } - return parseFiles(t, readFileOS, filenames...) -} - -// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, -// and whether the value has a meaningful truth value. This is the definition of -// truth used by if and other such actions. -func IsTrue(val interface{}) (truth, ok bool) { - return template.IsTrue(val) -} diff --git a/vendor/github.com/google/safehtml/template/transition.go b/vendor/github.com/google/safehtml/template/transition.go deleted file mode 100644 index e0882e489..000000000 --- a/vendor/github.com/google/safehtml/template/transition.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "bytes" - "strings" -) - -// transitionFunc is the array of context transition functions for text nodes. -// A transition function takes a context and template text input, and returns -// the updated context and the number of bytes consumed from the front of the -// input. -var transitionFunc = [...]func(context, []byte) (context, int){ - stateText: tText, - stateSpecialElementBody: tSpecialTagEnd, - stateTag: tTag, - stateAttrName: tAttrName, - stateAfterName: tAfterName, - stateBeforeValue: tBeforeValue, - stateHTMLCmt: tHTMLCmt, - stateAttr: tAttr, - stateError: tError, -} - -var commentStart = []byte("<!--") -var commentEnd = []byte("-->") - -// tText is the context transition function for the text state. -func tText(c context, s []byte) (context, int) { - k := 0 - for { - i := k + bytes.IndexByte(s[k:], '<') - if i < k || i+1 == len(s) { - return c, len(s) - } else if i+4 <= len(s) && bytes.Equal(commentStart, s[i:i+4]) { - return context{state: stateHTMLCmt}, i + 4 - } - i++ - end := false - if s[i] == '/' { - if i+1 == len(s) { - return c, len(s) - } - end, i = true, i+1 - } - j, e := eatTagName(s, i) - if j != i { - // We've found an HTML tag. - ret := context{state: stateTag} - // Element name not needed if we are at the end of the element. - if !end { - ret.element = e - } - return ret, j - } - k = j - } -} - -// specialElements contains the names of elements whose bodies are treated -// differently by the parser and escaper from stateText. -var specialElements = map[string]bool{ - "script": true, - "style": true, - "textarea": true, - "title": true, -} - -// voidElements contains the names of all void elements. -// https://www.w3.org/TR/html5/syntax.html#void-elements -var voidElements = map[string]bool{ - "area": true, - "base": true, - "br": true, - "col": true, - "embed": true, - "hr": true, - "img": true, - "input": true, - "keygen": true, - "link": true, - "meta": true, - "param": true, - "source": true, - "track": true, - "wbr": true, -} - -// tTag is the context transition function for the tag state. -func tTag(c context, s []byte) (context, int) { - // Find the attribute name. - i := eatWhiteSpace(s, 0) - if i == len(s) { - return c, len(s) - } - if s[i] == '>' { - ret := context{ - state: stateText, - element: c.element, - scriptType: c.scriptType, - linkRel: c.linkRel, - } - if specialElements[c.element.name] { - ret.state = stateSpecialElementBody - } - if c.element.name != "" && voidElements[c.element.name] { - // Special case: end of start tag of a void element. - // Discard unnecessary state, since this element have no content. - ret.element = element{} - ret.scriptType = "" - ret.linkRel = "" - } - return ret, i + 1 - } - j, err := eatAttrName(s, i) - if err != nil { - return context{state: stateError, err: err}, len(s) - } - state := stateTag - if i == j { - return context{ - state: stateError, - err: errorf(ErrBadHTML, nil, 0, "expected space, attr name, or end of tag, but got %q", s[i:]), - }, len(s) - } - - if j == len(s) { - state = stateAttrName - } else { - state = stateAfterName - } - return context{ - state: state, - element: c.element, - attr: attr{name: strings.ToLower(string(s[i:j]))}, - linkRel: c.linkRel, - }, j -} - -// tAttrName is the context transition function for stateAttrName. -func tAttrName(c context, s []byte) (context, int) { - i, err := eatAttrName(s, 0) - if err != nil { - return context{state: stateError, err: err}, len(s) - } else if i != len(s) { - c.state = stateAfterName - } - return c, i -} - -// tAfterName is the context transition function for stateAfterName. -func tAfterName(c context, s []byte) (context, int) { - // Look for the start of the value. - i := eatWhiteSpace(s, 0) - if i == len(s) { - return c, len(s) - } else if s[i] != '=' { - // Occurs due to tag ending '>', and valueless attribute. - c.state = stateTag - return c, i - } - c.state = stateBeforeValue - // Consume the "=". - return c, i + 1 -} - -// tBeforeValue is the context transition function for stateBeforeValue. -func tBeforeValue(c context, s []byte) (context, int) { - i := eatWhiteSpace(s, 0) - if i == len(s) { - return c, len(s) - } - // Find the attribute delimiter. - // TODO: consider disallowing single-quoted or unquoted attribute values completely, even in hardcoded template text. - delim := delimSpaceOrTagEnd - switch s[i] { - case '\'': - delim, i = delimSingleQuote, i+1 - case '"': - delim, i = delimDoubleQuote, i+1 - } - c.state, c.delim = stateAttr, delim - return c, i -} - -// tHTMLCmt is the context transition function for stateHTMLCmt. -func tHTMLCmt(c context, s []byte) (context, int) { - if i := bytes.Index(s, commentEnd); i != -1 { - return context{}, i + 3 - } - return c, len(s) -} - -var ( - specialTagEndPrefix = []byte("</") - tagEndSeparators = []byte("> \t\n\f/") -) - -// tSpecialTagEnd is the context transition function for raw text, RCDATA -// script data, and stylesheet element states. -func tSpecialTagEnd(c context, s []byte) (context, int) { - if specialElements[c.element.name] { - if i := indexTagEnd(s, []byte(c.element.name)); i != -1 { - return context{}, i - } - } - return c, len(s) -} - -// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1 -func indexTagEnd(s []byte, tag []byte) int { - res := 0 - plen := len(specialTagEndPrefix) - for len(s) > 0 { - // Try to find the tag end prefix first - i := bytes.Index(s, specialTagEndPrefix) - if i == -1 { - return i - } - s = s[i+plen:] - // Try to match the actual tag if there is still space for it - if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) { - s = s[len(tag):] - // Check the tag is followed by a proper separator - if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 { - return res + i - } - res += len(tag) - } - res += i + plen - } - return -1 -} - -// tAttr is the context transition function for the attribute state. -func tAttr(c context, s []byte) (context, int) { - return c, len(s) -} - -// tError is the context transition function for the error state. -func tError(c context, s []byte) (context, int) { - return c, len(s) -} - -// eatAttrName returns the largest j such that s[i:j] is an attribute name. -// It returns an error if s[i:] does not look like it begins with an -// attribute name, such as encountering a quote mark without a preceding -// equals sign. -func eatAttrName(s []byte, i int) (int, *Error) { - for j := i; j < len(s); j++ { - switch s[j] { - case ' ', '\t', '\n', '\f', '\r', '=', '>': - return j, nil - case '\'', '"', '<': - // These result in a parse warning in HTML5 and are - // indicative of serious problems if seen in an attr - // name in a template. - return -1, errorf(ErrBadHTML, nil, 0, "%q in attribute name: %.32q", s[j:j+1], s) - default: - // No-op. - } - } - return len(s), nil -} - -// asciiAlpha reports whether c is an ASCII letter. -func asciiAlpha(c byte) bool { - return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' -} - -// asciiAlphaNum reports whether c is an ASCII letter or digit. -func asciiAlphaNum(c byte) bool { - return asciiAlpha(c) || '0' <= c && c <= '9' -} - -// eatTagName returns the largest j such that s[i:j] is a tag name and the tag name. -func eatTagName(s []byte, i int) (int, element) { - if i == len(s) || !asciiAlpha(s[i]) { - return i, element{} - } - j := i + 1 - for j < len(s) { - x := s[j] - if asciiAlphaNum(x) { - j++ - continue - } - // Allow "x-y" or "x:y" but not "x-", "-y", or "x--y". - if (x == ':' || x == '-') && j+1 < len(s) && asciiAlphaNum(s[j+1]) { - j += 2 - continue - } - break - } - return j, element{name: strings.ToLower(string(s[i:j]))} -} - -// eatWhiteSpace returns the largest j such that s[i:j] is white space. -func eatWhiteSpace(s []byte, i int) int { - for j := i; j < len(s); j++ { - switch s[j] { - case ' ', '\t', '\n', '\f', '\r': - // No-op. - default: - return j - } - } - return len(s) -} diff --git a/vendor/github.com/google/safehtml/template/trustedfs.go b/vendor/github.com/google/safehtml/template/trustedfs.go deleted file mode 100644 index 80db11824..000000000 --- a/vendor/github.com/google/safehtml/template/trustedfs.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2021 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -//go:build go1.16 -// +build go1.16 - -package template - -import ( - "embed" - "fmt" - "io/fs" - "os" - "path" -) - -// A TrustedFS is an immutable type referencing a filesystem (fs.FS) -// under application control. -// -// In order to ensure that an attacker cannot influence the TrustedFS value, a -// TrustedFS can be instantiated in only two ways. One way is from an embed.FS -// with TrustedFSFromEmbed. It is assumed that embedded filesystems are under -// the programmer's control. The other way is from a TrustedSource using -// TrustedFSFromTrustedSource, in which case the guarantees and caveats of -// TrustedSource apply. -type TrustedFS struct { - fsys fs.FS -} - -// TrustedFSFromEmbed constructs a TrustedFS from an embed.FS. -func TrustedFSFromEmbed(fsys embed.FS) TrustedFS { - return TrustedFS{fsys: fsys} -} - -// TrustedFSFromTrustedSource constructs a TrustedFS from the string in the -// TrustedSource, which should refer to a directory. -func TrustedFSFromTrustedSource(ts TrustedSource) TrustedFS { - return TrustedFS{fsys: os.DirFS(ts.src)} -} - -// Sub returns a TrustedFS at a subdirectory of the receiver. -// It works by calling fs.Sub on the receiver's fs.FS. -func (tf TrustedFS) Sub(dir TrustedSource) (TrustedFS, error) { - subfs, err := fs.Sub(tf.fsys, dir.String()) - return TrustedFS{fsys: subfs}, err -} - -// ParseFS is like ParseFiles or ParseGlob but reads from the TrustedFS -// instead of the host operating system's file system. -// It accepts a list of glob patterns. -// (Note that most file names serve as glob patterns matching only themselves.) -// -// The same behaviors listed for ParseFiles() apply to ParseFS too (e.g. using the base name -// of the file as the template name). -func ParseFS(tfs TrustedFS, patterns ...string) (*Template, error) { - return parseFS(nil, tfs.fsys, patterns) -} - -// ParseFS is like ParseFiles or ParseGlob but reads from the TrustedFS -// instead of the host operating system's file system. -// It accepts a list of glob patterns. -// (Note that most file names serve as glob patterns matching only themselves.) -// -// The same behaviors listed for ParseFiles() apply to ParseFS too (e.g. using the base name -// of the file as the template name). -func (t *Template) ParseFS(tfs TrustedFS, patterns ...string) (*Template, error) { - return parseFS(t, tfs.fsys, patterns) -} - -// Copied from -// https://go.googlesource.com/go/+/refs/tags/go1.17.1/src/text/template/helper.go. -func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) { - var filenames []string - for _, pattern := range patterns { - list, err := fs.Glob(fsys, pattern) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) - } - filenames = append(filenames, list...) - } - return parseFiles(t, readFileFS(fsys), filenames...) -} - -// Copied with minor changes from -// https://go.googlesource.com/go/+/refs/tags/go1.17.1/src/text/template/helper.go. -func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { - return func(file string) (string, []byte, error) { - name := path.Base(file) - b, err := fs.ReadFile(fsys, file) - return name, b, err - } -} diff --git a/vendor/github.com/google/safehtml/template/trustedsource.go b/vendor/github.com/google/safehtml/template/trustedsource.go deleted file mode 100644 index f64263948..000000000 --- a/vendor/github.com/google/safehtml/template/trustedsource.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package template - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "flag" -) - -// A TrustedSource is an immutable string-like type referencing -// trusted template files under application control. It can be passed to -// template-parsing functions and methods to safely load templates -// without the risk of untrusted template execution. -// -// In order to ensure that an attacker cannot influence the TrustedSource -// value, a TrustedSource can be instantiated only from untyped string -// constants, command-line flags, and other application-controlled strings, but -// never from arbitrary string values potentially representing untrusted user input. -// -// Note that TrustedSource's constructors cannot truly guarantee that the -// templates it references are not attacker-controlled; it can guarantee only that -// the path to the template itself is under application control. Users of these -// constructors must ensure themselves that TrustedSource never references -// attacker-controlled files or directories that contain such files. -type TrustedSource struct { - // We declare a TrustedSource not as a string but as a struct wrapping a string - // to prevent construction of TrustedSource values through string conversion. - src string -} - -// TrustedSourceFromConstant constructs a TrustedSource with its underlying -// src set to the given src, which must be an untyped string constant. -// -// No runtime validation or sanitization is performed on src; being under -// application control, it is simply assumed to comply with the TrustedSource type -// contract. -func TrustedSourceFromConstant(src stringConstant) TrustedSource { - return TrustedSource{string(src)} -} - -// TrustedSourceFromConstantDir constructs a TrustedSource calling path/filepath.Join on -// an application-controlled directory path, which must be an untyped string constant, -// a TrustedSource, and a dynamic filename. It returns an error if filename contains -// filepath or list separators, since this might cause the resulting path to reference a -// file outside of the given directory. -// -// dir or src may be empty if either of these path segments are not required. -func TrustedSourceFromConstantDir(dir stringConstant, src TrustedSource, filename string) (TrustedSource, error) { - if i := strings.IndexAny(filename, string([]rune{filepath.Separator, filepath.ListSeparator})); i != -1 { - return TrustedSource{}, fmt.Errorf("filename %q must not contain the separator %q", filename, filename[i]) - } - if filename == ".." { - return TrustedSource{}, fmt.Errorf("filename must not be the special name %q", filename) - } - return TrustedSource{filepath.Join(string(dir), src.String(), filename)}, nil -} - -// TrustedSourceJoin is a wrapper around path/filepath.Join that returns a -// TrustedSource formed by joining the given path elements into a single path, -// adding an OS-specific path separator if necessary. -func TrustedSourceJoin(elem ...TrustedSource) TrustedSource { - return TrustedSource{filepath.Join(trustedSourcesToStrings(elem)...)} -} - -// TrustedSourceFromFlag returns a TrustedSource containing the string -// representation of the retrieved value of the flag. -// -// In a server setting, flags are part of the application's deployment -// configuration and are hence considered application-controlled. -func TrustedSourceFromFlag(value flag.Value) TrustedSource { - return TrustedSource{fmt.Sprint(value.String())} -} - -// TrustedSourceFromEnvVar is a wrapper around os.Getenv that -// returns a TrustedSource containing the value of the environment variable -// named by the key. It returns the value, which will be empty if the variable -// is not present. To distinguish between an empty value and an unset value, -// use os.LookupEnv. -// -// In a server setting, environment variables are part of the application's -// deployment configuration and are hence considered application-controlled. -func TrustedSourceFromEnvVar(key stringConstant) TrustedSource { - return TrustedSource{os.Getenv(string(key))} -} - -// String returns the string form of the TrustedSource. -func (t TrustedSource) String() string { - return t.src -} - -func trustedSourcesToStrings(paths []TrustedSource) []string { - ret := make([]string, 0, len(paths)) - for _, p := range paths { - ret = append(ret, p.String()) - } - return ret -} diff --git a/vendor/github.com/google/safehtml/template/trustedtemplate.go b/vendor/github.com/google/safehtml/template/trustedtemplate.go deleted file mode 100644 index bd3b1b46a..000000000 --- a/vendor/github.com/google/safehtml/template/trustedtemplate.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package template - -// A TrustedTemplate is an immutable string-like type containing a -// safehtml/template template body. It can be safely loaded as template -// text without the risk of untrusted template execution. -// -// In order to ensure that an attacker cannot influence the TrustedTemplate -// value, a TrustedTemplate can be instantiated only from untyped string constants, -// and never from arbitrary string values potentially representing untrusted user input. -// -type TrustedTemplate struct { - // We declare a TrustedTemplate not as a string but as a struct wrapping a string - // to prevent construction of TrustedTemplate values through string conversion. - tmpl string -} - -// MakeTrustedTemplate constructs a TrustedTemplate with its underlying -// tmpl set to the given tmpl, which must be an untyped string constant. -// -// No runtime validation or sanitization is performed on tmpl; being under -// application control, it is simply assumed to comply with the TrustedTemplate type -// contract. -func MakeTrustedTemplate(tmpl stringConstant) TrustedTemplate { - return TrustedTemplate{string(tmpl)} -} - -// String returns the string form of the TrustedTemplate. -func (t TrustedTemplate) String() string { - return t.tmpl -} diff --git a/vendor/github.com/google/safehtml/template/url.go b/vendor/github.com/google/safehtml/template/url.go deleted file mode 100644 index f63475fcf..000000000 --- a/vendor/github.com/google/safehtml/template/url.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package template - -import ( - "fmt" - "html" - "regexp" - "strings" - - "github.com/google/safehtml/internal/safehtmlutil" - "github.com/google/safehtml" -) - -// urlPrefixValidators maps URL and TrustedResourceURL sanitization contexts to functions return an error -// if the given string is unsafe to use as a URL prefix in that sanitization context. -var urlPrefixValidators = map[sanitizationContext]func(string) error{ - sanitizationContextURL: validateURLPrefix, - sanitizationContextTrustedResourceURLOrURL: validateURLPrefix, - sanitizationContextTrustedResourceURL: validateTrustedResourceURLPrefix, -} - -// startsWithFullySpecifiedSchemePattern matches strings that have a fully-specified scheme component. -// See RFC 3986 Section 3. -var startsWithFullySpecifiedSchemePattern = regexp.MustCompile( - `^[[:alpha:]](?:[[:alnum:]]|[+.-])*:`) - -// validateURLPrefix validates if the given non-empty prefix is a safe safehtml.URL prefix. -// -// Prefixes are considered unsafe if they end in an incomplete HTML character reference -// or percent-encoding character triplet. -// -// If the prefix contains a fully-specified scheme component, it is considered safe only if -// it starts with an allowed scheme. See safehtml.URLSanitized for more details. -// -// Otherwise, the prefix is safe only if it contains '/', '?', or '#', since the presence of any -// of these runes ensures that this prefix, when combined with some arbitrary suffix, cannot be -// interpreted as a part of a scheme. -func validateURLPrefix(prefix string) error { - decoded, err := decodeURLPrefix(prefix) - if err != nil { - return err - } - switch { - case startsWithFullySpecifiedSchemePattern.MatchString(decoded): - if safehtml.URLSanitized(decoded).String() != decoded { - return fmt.Errorf("URL prefix %q contains an unsafe scheme", prefix) - } - case !strings.ContainsAny(decoded, "/?#"): - // If the URL prefix does not already have a ':' scheme delimiter, and does not contain - // '/', '?', or '#', any ':' following this prefix will be intepreted as a scheme - // delimiter, causing this URL prefix to be interpreted as being part of a scheme. - // e.g. `<a href="java{{ "script:" }}alert(1)>` - return fmt.Errorf("URL prefix %q is unsafe; it might be interpreted as part of a scheme", prefix) - } - return nil -} - -// validateTrustedResourceURLPrefix validates if the given non-empty prefix is a safe -// safehtml.TrustedResourceURL prefix. -// -// Prefixes are considered unsafe if they end in an incomplete HTML character reference -// or percent-encoding character triplet. -// -// See safehtmlutil.IsSafeTrustedResourceURLPrefix for details on how the prefix is validated. -func validateTrustedResourceURLPrefix(prefix string) error { - decoded, err := decodeURLPrefix(prefix) - if err != nil { - return err - } - if !safehtmlutil.IsSafeTrustedResourceURLPrefix(decoded) { - return fmt.Errorf("%q is a disallowed TrustedResourceURL prefix", prefix) - } - return nil -} - -// endsWithPercentEncodingPrefixPattern matches strings that end in an incomplete -// URL percent encoding triplet. -// -// See https://tools.ietf.org/html/rfc3986#section-2.1. -var endsWithPercentEncodingPrefixPattern = regexp.MustCompile( - `%[[:xdigit:]]?$`) - -// containsWhitespaceOrControlPattern matches strings that contain ASCII whitespace -// or control characters. -var containsWhitespaceOrControlPattern = regexp.MustCompile(`[[:space:]]|[[:cntrl:]]`) - -// decodeURLPrefix returns the given prefix after it has been HTML-unescaped. -// It returns an error if the prefix: -// * ends in an incomplete HTML character reference before HTML-unescaping, -// * ends in an incomplete percent-encoding character triplet after HTML-unescaping, or -// * contains whitespace before or after HTML-unescaping. -func decodeURLPrefix(prefix string) (string, error) { - if containsWhitespaceOrControlPattern.MatchString(prefix) { - return "", fmt.Errorf("URL prefix %q contains whitespace or control characters", prefix) - } - if err := validateDoesNotEndsWithCharRefPrefix(prefix); err != nil { - return "", fmt.Errorf("URL %s", err) - } - decoded := html.UnescapeString(prefix) - // Check again for whitespace that might have previously been masked by a HTML reference, - // such as in "javascript
". - if containsWhitespaceOrControlPattern.MatchString(decoded) { - return "", fmt.Errorf("URL prefix %q contains whitespace or control characters", prefix) - } - if endsWithPercentEncodingPrefixPattern.MatchString(decoded) { - return "", fmt.Errorf("URL prefix %q ends with an incomplete percent-encoding character triplet", prefix) - } - return decoded, nil -} - -func validateTrustedResourceURLSubstitution(args ...interface{}) (string, error) { - input := safehtmlutil.Stringify(args...) - if safehtmlutil.URLContainsDoubleDotSegment(input) { - // Reject substitutions containing the ".." dot-segment to prevent the final TrustedResourceURL from referencing - // a resource higher up in the path name hierarchy than the path specified in the prefix. - return "", fmt.Errorf(`cannot substitute %q after TrustedResourceURL prefix: ".." is disallowed`, input) - } - return input, nil -} diff --git a/vendor/github.com/google/safehtml/trustedresourceurl.go b/vendor/github.com/google/safehtml/trustedresourceurl.go deleted file mode 100644 index e31a2fd56..000000000 --- a/vendor/github.com/google/safehtml/trustedresourceurl.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "fmt" - "regexp" - "sort" - "strings" - - "flag" - "github.com/google/safehtml/internal/safehtmlutil" -) - -// A TrustedResourceURL is an immutable string-like type referencing the -// application’s own, trusted resources. It can be used to safely load scripts, -// CSS and other sensitive resources without the risk of untrusted code execution. -// For example, it is unsafe to insert a plain string in a -// -// <script src=“...”></script> -// -// context since the URL may originate from untrusted user input and the -// script it is pointing to may thus be controlled by an attacker. It is, -// however, safe to use a TrustedResourceURL since its value is known to never -// have left application control. -// -// In order to ensure that an attacker cannot influence the TrustedResourceURL -// value, a TrustedResourceURL can only be instantiated from compile-time -// constant string literals, command-line flags or a combination of the two, -// but never from arbitrary string values potentially representing untrusted user input. -// -// Additionally, TrustedResourceURLs can be serialized and passed along within -// the application via protocol buffers. It is the application’s responsibility -// to ensure that the protocol buffers originate from within the application -// itself and not from an external entity outside its trust domain. -// -// Note that TrustedResourceURLs can also use absolute paths (starting with '/') -// and relative paths. This allows the same binary to be used for different -// hosts without hard-coding the hostname in a string literal. -type TrustedResourceURL struct { - // We declare a TrustedResourceURL not as a string but as a struct wrapping a string - // to prevent construction of TrustedResourceURL values through string conversion. - str string -} - -// TrustedResourceURLWithParams constructs a new TrustedResourceURL with the -// given key-value pairs added as query parameters. -// -// Map entries with empty keys or values are ignored. The order of appended -// keys is guaranteed to be stable but may differ from the order in input. -func TrustedResourceURLWithParams(t TrustedResourceURL, params map[string]string) TrustedResourceURL { - url := t.str - var fragment string - if i := strings.IndexByte(url, '#'); i != -1 { - // The fragment identifier component will always appear at the end - // of the URL after the query segment. It is therefore safe to - // trim the fragment from the tail of the URL and re-append it after - // all query parameters have been added. - // See https://tools.ietf.org/html/rfc3986#appendix-A. - fragment = url[i:] - url = url[:i] - } - sep := "?" - if i := strings.IndexRune(url, '?'); i != -1 { - // The first "?" in a URL indicates the start of the query component. - // See https://tools.ietf.org/html/rfc3986#section-3.4 - if i == len(url)-1 { - sep = "" - } else { - sep = "&" - } - } - stringParams := make([]string, 0, len(params)) - for k, v := range params { - if k == "" || v == "" { - continue - } - stringParam := safehtmlutil.QueryEscapeURL(k) + "=" + safehtmlutil.QueryEscapeURL(v) - stringParams = append(stringParams, stringParam) - } - if len(stringParams) > 0 { - sort.Strings(stringParams) - url += sep + strings.Join(stringParams, "&") - } - return TrustedResourceURL{url + fragment} -} - -// TrustedResourceURLFromConstant constructs a TrustedResourceURL with its underlying -// URL set to the given url, which must be an untyped string constant. -// -// No runtime validation or sanitization is performed on url; being under -// application control, it is simply assumed to comply with the TrustedResourceURL type -// contract. -func TrustedResourceURLFromConstant(url stringConstant) TrustedResourceURL { - return TrustedResourceURL{string(url)} -} - -// TrustedResourceURLFormatFromConstant constructs a TrustedResourceURL from a -// format string, which must be an untyped string constant, and string arguments. -// -// Arguments are specified as a map of labels, which must contain only alphanumeric -// and '_' runes, to string values. Each `%{<label>}` marker in the format string is -// replaced by the string value identified by <label> after it has been URL-escaped. -// Arguments that do not match any label in the format string are ignored. -// -// The format string must have a prefix of one of the following forms: -// * `https://<origin>/` -// * `//<origin>/` -// * `/<pathStart>` -// * `about:blank#` -// -// `<origin>` must contain only alphanumerics, '.', ':', '[', ']', or '-', and -// `<pathStart>` is any character except `/` and `\`. -func TrustedResourceURLFormatFromConstant(format stringConstant, args map[string]string) (TrustedResourceURL, error) { - return trustedResourceURLFormat(string(format), args) -} - -// TrustedResourceURLFormatFromFlag is a variant of TrustedResourceURLFormatFromConstant -// that constructs a TrustedResourceURL from a format string, which is given as a flag.Value, -// and string arguments. -// -// See TrustedResourceURLFormatFromConstant for more details about format -// string markers and validation. -func TrustedResourceURLFormatFromFlag(format flag.Value, args map[string]string) (TrustedResourceURL, error) { - return trustedResourceURLFormat(fmt.Sprint(format.String()), args) -} - -func trustedResourceURLFormat(format string, args map[string]string) (TrustedResourceURL, error) { - if !safehtmlutil.IsSafeTrustedResourceURLPrefix(format) { - return TrustedResourceURL{}, fmt.Errorf("%q is a disallowed TrustedResourceURL format string", format) - } - var err error - ret := trustedResourceURLFormatMarkerPattern.ReplaceAllStringFunc(format, func(match string) string { - argName := match[len("%{") : len(match)-len("}")] - argVal, ok := args[argName] - if !ok { - if err == nil { - // Report an error for the first missing argument. - err = fmt.Errorf("expected argument named %q", argName) - } - return "" - } - if safehtmlutil.URLContainsDoubleDotSegment(argVal) { - // Reject values containing the ".." dot-segment to prevent the final TrustedResourceURL from referencing - // a resource higher up in the path name hierarchy than the path specified in the prefix. - err = fmt.Errorf(`argument %q with value %q must not contain ".."`, argName, argVal) - return "" - } - // QueryEscapeURL escapes some non-reserved characters in the path - // segment (e.g. '/' and '?') in order to prevent the injection of any new path - // segments or URL components. - return safehtmlutil.QueryEscapeURL(argVal) - }) - return TrustedResourceURL{ret}, err -} - -// trustedResourceURLFormatMarkerPattern matches markers in TrustedResourceURLFormat -// format strings. -var trustedResourceURLFormatMarkerPattern = regexp.MustCompile(`%{[[:word:]]+}`) - -// TrustedResourceURLFromFlag returns a TrustedResourceURL containing the string -// representation of the retrieved value of the flag. -// -// In a server setting, flags are part of the application's deployment -// configuration and are hence considered application-controlled. -func TrustedResourceURLFromFlag(value flag.Value) TrustedResourceURL { - return TrustedResourceURL{fmt.Sprint(value.String())} -} - -// String returns the string form of the TrustedResourceURL. -func (t TrustedResourceURL) String() string { - return t.str -} - -// TrustedResourceURLAppend URL-escapes a string and appends it to the TrustedResourceURL. -// -// This function can only be used if the TrustedResourceURL has a prefix of one of the following -// forms: -// * `https://<origin>/` -// * `//<origin>/` -// * `/<pathStart>` -// * `about:blank#` -// -// `<origin>` must contain only alphanumerics, '.', ':', '[', ']', or '-', and -// `<pathStart>` is any character except `/` and `\`. -func TrustedResourceURLAppend(t TrustedResourceURL, s string) (TrustedResourceURL, error) { - if !safehtmlutil.IsSafeTrustedResourceURLPrefix(t.str) { - return TrustedResourceURL{}, fmt.Errorf("cannot append to TrustedResourceURL %q because it has an unsafe prefix", t) - } - return TrustedResourceURL{t.str + safehtmlutil.QueryEscapeURL(s)}, nil -} diff --git a/vendor/github.com/google/safehtml/uncheckedconversions/uncheckedconversions.go b/vendor/github.com/google/safehtml/uncheckedconversions/uncheckedconversions.go deleted file mode 100644 index 1b753a52d..000000000 --- a/vendor/github.com/google/safehtml/uncheckedconversions/uncheckedconversions.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Package uncheckedconversions provides functions to create values of package -// safehtml types from plain strings. Use of these functions could potentially -// result in instances of safe HTML types that violate their type contracts, -// and hence result in security vulnerabilties. -// -// Avoid use of the functions in this file whenever possible; instead prefer to -// create instances of package safehtml types using inherently safe builders or -// template systems. -// -// Example appropriate uses include: -// * Wrapping the result of general-purpose or application-specific content -// sanitizer libraries. -// * Wrapping the result of rendering strictly contextually autoescaping -// templates (assuming the template's autoescaping implementation is indeed -// strict enough to support the type contract). -package uncheckedconversions - -import ( - "github.com/google/safehtml/internal/raw" - "github.com/google/safehtml" -) - -var html = raw.HTML.(func(string) safehtml.HTML) -var script = raw.Script.(func(string) safehtml.Script) -var style = raw.Style.(func(string) safehtml.Style) -var styleSheet = raw.StyleSheet.(func(string) safehtml.StyleSheet) -var url = raw.URL.(func(string) safehtml.URL) -var trustedResourceURL = raw.TrustedResourceURL.(func(string) safehtml.TrustedResourceURL) -var identifier = raw.Identifier.(func(string) safehtml.Identifier) - -// HTMLFromStringKnownToSatisfyTypeContract converts a string into a HTML. -// -func HTMLFromStringKnownToSatisfyTypeContract(s string) safehtml.HTML { - return html(s) -} - -// ScriptFromStringKnownToSatisfyTypeContract converts a string into a Script. -// -// Users of this function must ensure themselves that the string does not -// contain unsafe script. Note in particular that '<' is dangerous, even when -// inside JavaScript strings, and so should always be forbidden or JavaScript -// escaped in user controlled input. For example, if -// "</script><script>evil</script>" were interpolated inside a JavaScript -// string,it would break out of the context of the original script element and -// "evil" would execute. Also note that within an HTML script (raw text) -// element, HTML character references, such as "<" are not allowed. See -// http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements. -func ScriptFromStringKnownToSatisfyTypeContract(s string) safehtml.Script { - return script(s) -} - -// StyleFromStringKnownToSatisfyTypeContract converts a string into a Style. -// -// Users of thie function must ensure themselves that the string: -// * Does not contain unsafe CSS. -// * Does not contain literal angle brackets. Otherwise, it could be unsafe to -// place a Style into the contents of a <style> element where it can't be -// HTML escaped (see http://www.w3.org/International/questions/qa-escapes). -// For example, if the Style containing -// "font: 'foo <style/><script>evil</script>'" was interpolated within a -// <style> tag, it would then break out of the style context into HTML. -// * Does not end in a property value or property name context. -// For example, a value of "background:url(\"" or "font-" does not satisfy -// the Style type contract. This rule is enforced to ensure composability: -// concatenating two incomplete strings that themselves do not contain unsafe -// CSS can result in an overall string that does. For example, if -// "javascript:evil())\"" is appended to "background:url(\"", the resulting -// string may result in the execution of a malicious script. -// -// The string may, however, contain literal single or double quotes (for example, -// in the "content" property). Therefore, the entire style string must be -// escaped when used in a style attribute. -// -// The following example values comply with Style's type contract: -// width: 1em; -// height:1em; -// width: 1em;height: 1em; -// background:url('http://url'); -// -// In addition, the empty string is safe for use in a style attribute. -// -// The following example values do NOT comply with this type's contract: -// background: red --- missing a trailing semi-colon -// background: --- missing a value and a trailing semi-colon -// 1em --- missing an attribute name, which provides context -// for the value -// -// See also http://www.w3.org/TR/css3-syntax/. -func StyleFromStringKnownToSatisfyTypeContract(s string) safehtml.Style { - return style(s) -} - -// StyleSheetFromStringKnownToSatisfyTypeContract converts a string into a StyleSheet. -// -// Users of this function must ensure themselves that the string does not -// contain unsafe script. Note in particular that '<' is dangerous, even when -// inside CSS strings, and so should always be forbidden or CSS-escaped in -// user controlled input. For example, if -// "</style><script>evil</script>" were interpolated inside a CSS string, it -// would break out of the context of the original style element and "evil" would -// execute. Also note that within an HTML style (raw text) element, HTML -// character references, such as "<", are not allowed.See -// http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements -// (Similar considerations apply to the style element.) -func StyleSheetFromStringKnownToSatisfyTypeContract(s string) safehtml.StyleSheet { - return styleSheet(s) -} - -// URLFromStringKnownToSatisfyTypeContract converts a string into a URL. -// -func URLFromStringKnownToSatisfyTypeContract(s string) safehtml.URL { - return url(s) -} - -// TrustedResourceURLFromStringKnownToSatisfyTypeContract converts a string into a TrustedResourceURL. -// -func TrustedResourceURLFromStringKnownToSatisfyTypeContract(s string) safehtml.TrustedResourceURL { - return trustedResourceURL(s) -} - -// IdentifierFromStringKnownToSatisfyTypeContract converts a string into a Identifier. -// -func IdentifierFromStringKnownToSatisfyTypeContract(s string) safehtml.Identifier { - return identifier(s) -} diff --git a/vendor/github.com/google/safehtml/url.go b/vendor/github.com/google/safehtml/url.go deleted file mode 100644 index 6e772219c..000000000 --- a/vendor/github.com/google/safehtml/url.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "regexp" - "strings" -) - -// A URL is an immutable string-like type that is safe to use in URL contexts in -// DOM APIs and HTML documents. -// -// URL guarantees that its value as a string will not cause untrusted script execution -// when evaluated as a hyperlink URL in a browser. -// -// Values of this type are guaranteed to be safe to use in URL/hyperlink contexts, -// such as assignment to URL-valued DOM properties, in the sense that the use -// will not result in a Cross-site Scripting (XSS) vulnerability. Similarly, URLs can -// be interpolated into the URL context of an HTML template (e.g. inside a href attribute). -// However, appropriate HTML-escaping must still be applied. -// -// Note that this type's contract does not imply any guarantees regarding the resource -// the URL refers to. In particular, URLs are not safe to use in a context -// where the referred-to resource is interpreted as trusted code, e.g., as the src of -// a script tag. For safely loading trusted resources, use the TrustedResourceURL type. -type URL struct { - // We declare a URL not as a string but as a struct wrapping a string - // to prevent construction of URL values through string conversion. - str string -} - -// InnocuousURL is an innocuous URL generated by URLSanitized when passed an unsafe URL. -// -// about:invalid is registered in http://www.w3.org/TR/css3-values/#about-invalid, -// and "references a non-existent document with a generic error condition. It can be -// used when a URI is necessary, but the default value shouldn't be resolveable as any -// type of document." -// -// http://tools.ietf.org/html/rfc6694#section-2.1 permits about URLs to contain -// a fragment, which is not to be considered when determining if an about URL is -// well-known. -const InnocuousURL = "about:invalid#zGoSafez" - -// URLSanitized returns a URL whose value is url, validating that the input string matches -// a pattern of commonly used safe URLs. If url fails validation, this method returns a -// URL containing InnocuousURL. -// -// url may be a URL with the http, https, ftp or mailto scheme, or a relative URL, -// i.e. a URL without a scheme. Specifically, a relative URL may be scheme-relative, -// absolute-path-relative, or path-relative. See -// http://url.spec.whatwg.org/#concept-relative-url. -// -// url may also be a base64 data URL with an allowed audio, image or video MIME type. -// -// No attempt is made at validating that the URL percent-decodes to structurally valid or -// interchange-valid UTF-8 since the percent-decoded representation is unsafe to use in an -// HTML context regardless of UTF-8 validity. -func URLSanitized(url string) URL { - if !isSafeURL(url) { - return URL{InnocuousURL} - } - return URL{url} -} - -// safeURLPattern matches URLs that -// (a) Start with a scheme in an allowlist (http, https, mailto, ftp); or -// (b) Contain no scheme. To ensure that the URL cannot be interpreted as a -// disallowed scheme URL, ':' may only appear after one of the runes [/?#]. -// -// The origin (RFC 6454) in which a URL is loaded depends on -// its scheme. We assume that the scheme used by the current document is HTTPS, HTTP, or -// something equivalent. We allow relative URLs unless in a particularly sensitive context -// called a "TrustedResourceUrl" context. In a non-TrustedResourceURL context we allow absolute -// URLs whose scheme is on a white-list. -// -// The position of the first colon (':') character determines whether a URL is absolute or relative. -// Looking at the prefix leading up to the first colon allows us to identify relative and absolute URLs, -// extract the scheme, and minimize the risk of a user-agent concluding a URL specifies a scheme not in -// our allowlist. -// -// According to RFC 3986 Section 3, the normative interpretation of the canonicial WHATWG specification -// (https://url.spec.whatwg.org/#url-scheme-string), colons can appear in a URL in these locations: -// * A colon after a non-empty run of (ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )) ends a scheme. -// If the colon after the scheme is not followed by "//" then any subsequent colons are part -// of an opaque URI body. -// * Otherwise, a colon after a hash (#) must be in the fragment. -// * Otherwise, a colon after a (?) must be in the query. -// * Otherwise, a colon after a single solidus ("/") must be in the path. -// * Otherwise, a colon after a double solidus ("//") must be in the authority (before port). -// * Otherwise, a colon after a valid protocol must be in the opaque part of the URL. -var safeURLPattern = regexp.MustCompile(`^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))`) - -// dataURLPattern matches base-64 data URLs (RFC 2397), with the first capture group being the media type -// specification given as a MIME type. -// -// Note: this pattern does not match data URLs containig media type specifications with optional parameters, -// such as `data:text/javascript;charset=UTF-8;base64,...`. This is ok since this pattern only needs to -// match audio, image and video MIME types in its capture group. -var dataURLPattern = regexp.MustCompile(`^data:([^;,]*);base64,[a-z0-9+/]+=*$`) - -// safeMIMETypePattern matches MIME types that are safe to include in a data URL. -var safeMIMETypePattern = regexp.MustCompile(`^(?:audio/(?:3gpp2|3gpp|aac|midi|mp3|mp4|mpeg|oga|ogg|opus|x-m4a|x-matroska|x-wav|wav|webm)|image/(?:bmp|gif|jpeg|jpg|png|tiff|webp|x-icon)|video/(?:mpeg|mp4|ogg|webm|x-matroska))$`) - -// isSafeURL matches url to a subset of URLs that will not cause script execution if used in -// a URL context within a HTML document. Specifically, this method returns true if url: -// (a) Starts with a scheme in the default allowlist (http, https, mailto, ftp); or -// (b) Contains no scheme. To ensure that the URL cannot be interpreted as a -// disallowed scheme URL, the runes ':', and '&' may only appear -// after one of the runes [/?#]. -func isSafeURL(url string) bool { - // Ignore case. - url = strings.ToLower(url) - if safeURLPattern.MatchString(url) { - return true - } - submatches := dataURLPattern.FindStringSubmatch(url) - return len(submatches) == 2 && safeMIMETypePattern.MatchString(submatches[1]) -} - -// String returns the string form of the URL. -func (u URL) String() string { - return u.str -} diff --git a/vendor/github.com/google/safehtml/urlset.go b/vendor/github.com/google/safehtml/urlset.go deleted file mode 100644 index 8d74a7732..000000000 --- a/vendor/github.com/google/safehtml/urlset.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2017 The Go Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -package safehtml - -import ( - "bytes" - "strconv" -) - -// https://infra.spec.whatwg.org/#ascii-whitespace -// ASCII whitespace is U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE. -var asciiWhitespace [256]bool - -// Metacharacters that affect parsing of srcset values. -var srcsetMetachars [256]bool - -func init() { - asciiWhitespace['\t'] = true - asciiWhitespace[' '] = true - asciiWhitespace['\n'] = true - asciiWhitespace['\f'] = true - asciiWhitespace['\r'] = true - - srcsetMetachars['\t'] = true - srcsetMetachars[' '] = true - srcsetMetachars['\n'] = true - srcsetMetachars['\f'] = true - srcsetMetachars['\r'] = true - srcsetMetachars[','] = true -} - -// URLSetSanitized returns a safe srcset by individually vetting each -// substring that specifies a URL. -// -// https://html.spec.whatwg.org/multipage/images.html#srcset-attributes -func URLSetSanitized(str string) URLSet { - var buffer bytes.Buffer - - for len(str) != 0 { - // Consume one image candidate - var url, metadata string - _, str = consumeIn(str, asciiWhitespace) - url, str = consumeNotIn(str, asciiWhitespace) - _, str = consumeIn(str, asciiWhitespace) - metadata, str = consumeNotIn(str, srcsetMetachars) - _, str = consumeIn(str, asciiWhitespace) - - // Append sanitized content onto buffer. - if len(url) != 0 && isSafeURL(url) && isOptionalSrcMetadataWellFormed(metadata) { - if buffer.Len() != 0 { - // The space before the comma is necessary because - // a comma adjacent to a URL will attach to it. - buffer.WriteString(" , ") - } - // URL may contain commas. Disambiguate. - appendURLToSet(url, &buffer) - if len(metadata) != 0 { - buffer.WriteByte(' ') - buffer.WriteString(metadata) - } - } - - // Consume any trailing comma - if len(str) == 0 || str[0] != ',' { - break - } - str = str[1:] - } - - if buffer.Len() == 0 { - return URLSet{InnocuousURL} - } - - return URLSet{buffer.String()} -} - -// appendURLToSet appends a URL so that it does not start or end with a comma -// -// https://html.spec.whatwg.org/multipage/images.html#srcset-attributes -// parsing step 2 which says: -// """ -// A valid non-empty URL that does not start or end with a U+002C COMMA character (,), -// referencing a non-interactive, optionally animated, image resource that is neither -// paged nor scripted -// """ -// -// Simply replacing all commas would break data:image/png;base64,IMAGECONTENT -// Note: This breaks data URLs with empty content since they end with a comma. -// We could handle that case by appending a '#'. -func appendURLToSet(url string, buffer *bytes.Buffer) { - n := len(url) - left, right := 0, n - if url[left] == ',' { - buffer.WriteString("%2c") - left++ - } - commaAtEnd := false - if left < right && url[right-1] == ',' { - commaAtEnd = true - right-- - } - buffer.WriteString(url[left:right]) - if commaAtEnd { - buffer.WriteString("%2c") - } -} - -// consumeNotIn uses bytes in str as bit indices in mask to find -// the least index >= left whose byte corresponds to a zero bit. -func consumeNotIn(str string, mask [256]bool) (consumed, rest string) { - i, n := 0, len(str) - for ; i < n; i++ { - if mask[str[i]] { - return str[0:i], str[i:n] - } - } - return str, "" -} - -// consumeIn is like consumeNotIn but treats mask as inverted. -func consumeIn(str string, mask [256]bool) (consumed, rest string) { - for i, n := 0, len(str); i < n; i++ { - if !mask[str[i]] { - return str[0:i], str[i:n] - } - } - return str, "" -} - -// isOptionalSrcMetadataWellFormed is true when its input is empty and -// when it is a floating point number optionally followed by an ASCII letter. -func isOptionalSrcMetadataWellFormed(metadata string) bool { - // srcset for both image candidates (<img srcset>) and - // the proposal for script allow a number and an optional letter - // afterwards. - n := len(metadata) - if n == 0 { - // Metadata is optional - return true - } - metadataPrefix := metadata - if last := metadata[n-1] | 32; 'a' <= last && last <= 'z' { - metadataPrefix = metadata[0 : n-1] - } - // This overmatches - // html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-floating-point-number - // but is sufficient. - _, err := strconv.ParseFloat(metadataPrefix, 64) - return err == nil -} - -// URLSet corresponds to the value of a srcset attribute outside a -// TrustedResourceURL context. -type URLSet struct { - // We declare a URLSet not as a string but as a struct wrapping a string - // to prevent construction of URL values through string conversion. - str string -} - -// String returns the string content of a URLSet -func (s URLSet) String() string { - return s.str -} |
