...

Source file src/html/template/content.go

Documentation: html/template

		 1  // Copyright 2011 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package template
		 6  
		 7  import (
		 8  	"fmt"
		 9  	"reflect"
		10  )
		11  
		12  // Strings of content from a trusted source.
		13  type (
		14  	// CSS encapsulates known safe content that matches any of:
		15  	//	 1. The CSS3 stylesheet production, such as `p { color: purple }`.
		16  	//	 2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
		17  	//	 3. CSS3 declaration productions, such as `color: red; margin: 2px`.
		18  	//	 4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
		19  	// See https://www.w3.org/TR/css3-syntax/#parsing and
		20  	// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
		21  	//
		22  	// Use of this type presents a security risk:
		23  	// the encapsulated content should come from a trusted source,
		24  	// as it will be included verbatim in the template output.
		25  	CSS string
		26  
		27  	// HTML encapsulates a known safe HTML document fragment.
		28  	// It should not be used for HTML from a third-party, or HTML with
		29  	// unclosed tags or comments. The outputs of a sound HTML sanitizer
		30  	// and a template escaped by this package are fine for use with HTML.
		31  	//
		32  	// Use of this type presents a security risk:
		33  	// the encapsulated content should come from a trusted source,
		34  	// as it will be included verbatim in the template output.
		35  	HTML string
		36  
		37  	// HTMLAttr encapsulates an HTML attribute from a trusted source,
		38  	// for example, ` dir="ltr"`.
		39  	//
		40  	// Use of this type presents a security risk:
		41  	// the encapsulated content should come from a trusted source,
		42  	// as it will be included verbatim in the template output.
		43  	HTMLAttr string
		44  
		45  	// JS encapsulates a known safe EcmaScript5 Expression, for example,
		46  	// `(x + y * z())`.
		47  	// Template authors are responsible for ensuring that typed expressions
		48  	// do not break the intended precedence and that there is no
		49  	// statement/expression ambiguity as when passing an expression like
		50  	// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
		51  	// valid Program with a very different meaning.
		52  	//
		53  	// Use of this type presents a security risk:
		54  	// the encapsulated content should come from a trusted source,
		55  	// as it will be included verbatim in the template output.
		56  	//
		57  	// Using JS to include valid but untrusted JSON is not safe.
		58  	// A safe alternative is to parse the JSON with json.Unmarshal and then
		59  	// pass the resultant object into the template, where it will be
		60  	// converted to sanitized JSON when presented in a JavaScript context.
		61  	JS string
		62  
		63  	// JSStr encapsulates a sequence of characters meant to be embedded
		64  	// between quotes in a JavaScript expression.
		65  	// The string must match a series of StringCharacters:
		66  	//	 StringCharacter :: SourceCharacter but not `\` or LineTerminator
		67  	//										| EscapeSequence
		68  	// Note that LineContinuations are not allowed.
		69  	// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
		70  	//
		71  	// Use of this type presents a security risk:
		72  	// the encapsulated content should come from a trusted source,
		73  	// as it will be included verbatim in the template output.
		74  	JSStr string
		75  
		76  	// URL encapsulates a known safe URL or URL substring (see RFC 3986).
		77  	// A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()`
		78  	// from a trusted source should go in the page, but by default dynamic
		79  	// `javascript:` URLs are filtered out since they are a frequently
		80  	// exploited injection vector.
		81  	//
		82  	// Use of this type presents a security risk:
		83  	// the encapsulated content should come from a trusted source,
		84  	// as it will be included verbatim in the template output.
		85  	URL string
		86  
		87  	// Srcset encapsulates a known safe srcset attribute
		88  	// (see https://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset).
		89  	//
		90  	// Use of this type presents a security risk:
		91  	// the encapsulated content should come from a trusted source,
		92  	// as it will be included verbatim in the template output.
		93  	Srcset string
		94  )
		95  
		96  type contentType uint8
		97  
		98  const (
		99  	contentTypePlain contentType = iota
	 100  	contentTypeCSS
	 101  	contentTypeHTML
	 102  	contentTypeHTMLAttr
	 103  	contentTypeJS
	 104  	contentTypeJSStr
	 105  	contentTypeURL
	 106  	contentTypeSrcset
	 107  	// contentTypeUnsafe is used in attr.go for values that affect how
	 108  	// embedded content and network messages are formed, vetted,
	 109  	// or interpreted; or which credentials network messages carry.
	 110  	contentTypeUnsafe
	 111  )
	 112  
	 113  // indirect returns the value, after dereferencing as many times
	 114  // as necessary to reach the base type (or nil).
	 115  func indirect(a interface{}) interface{} {
	 116  	if a == nil {
	 117  		return nil
	 118  	}
	 119  	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
	 120  		// Avoid creating a reflect.Value if it's not a pointer.
	 121  		return a
	 122  	}
	 123  	v := reflect.ValueOf(a)
	 124  	for v.Kind() == reflect.Ptr && !v.IsNil() {
	 125  		v = v.Elem()
	 126  	}
	 127  	return v.Interface()
	 128  }
	 129  
	 130  var (
	 131  	errorType			 = reflect.TypeOf((*error)(nil)).Elem()
	 132  	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
	 133  )
	 134  
	 135  // indirectToStringerOrError returns the value, after dereferencing as many times
	 136  // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
	 137  // or error,
	 138  func indirectToStringerOrError(a interface{}) interface{} {
	 139  	if a == nil {
	 140  		return nil
	 141  	}
	 142  	v := reflect.ValueOf(a)
	 143  	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
	 144  		v = v.Elem()
	 145  	}
	 146  	return v.Interface()
	 147  }
	 148  
	 149  // stringify converts its arguments to a string and the type of the content.
	 150  // All pointers are dereferenced, as in the text/template package.
	 151  func stringify(args ...interface{}) (string, contentType) {
	 152  	if len(args) == 1 {
	 153  		switch s := indirect(args[0]).(type) {
	 154  		case string:
	 155  			return s, contentTypePlain
	 156  		case CSS:
	 157  			return string(s), contentTypeCSS
	 158  		case HTML:
	 159  			return string(s), contentTypeHTML
	 160  		case HTMLAttr:
	 161  			return string(s), contentTypeHTMLAttr
	 162  		case JS:
	 163  			return string(s), contentTypeJS
	 164  		case JSStr:
	 165  			return string(s), contentTypeJSStr
	 166  		case URL:
	 167  			return string(s), contentTypeURL
	 168  		case Srcset:
	 169  			return string(s), contentTypeSrcset
	 170  		}
	 171  	}
	 172  	i := 0
	 173  	for _, arg := range args {
	 174  		// We skip untyped nil arguments for backward compatibility.
	 175  		// Without this they would be output as <nil>, escaped.
	 176  		// See issue 25875.
	 177  		if arg == nil {
	 178  			continue
	 179  		}
	 180  
	 181  		args[i] = indirectToStringerOrError(arg)
	 182  		i++
	 183  	}
	 184  	return fmt.Sprint(args[:i]...), contentTypePlain
	 185  }
	 186  

View as plain text