content.go 5.7 KB

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