@@ -43,6 +43,29 @@ public struct Renderer {
4343 }
4444 }
4545
46+ /// A enumeration of potential escape contexts
47+ private enum EscapeContext {
48+
49+ /// A enumeration of potential html contexts
50+ internal enum Context {
51+
52+ /// Consider an attribute value
53+ case attribute
54+
55+ /// Consider an element body
56+ case element
57+ }
58+
59+ /// Consider an html context
60+ case html( Context )
61+
62+ /// Consider a css context
63+ case css
64+
65+ /// Consider a js context
66+ case js
67+ }
68+
4669 /// The context environment used during rendering
4770 private var environment : Environment
4871
@@ -58,8 +81,11 @@ public struct Renderer {
5881 /// The logger used to log all operations
5982 private var logger : Logger
6083
61- /// The encoder used to encode html entities
84+ /// The encoder used to encode html entities
6285 private var encoder : Encoder
86+
87+ /// The sanitizer used to clean up html output
88+ private var sanitizer : Sanitizer
6389
6490 /// Initializes the renderer
6591 ///
@@ -79,6 +105,7 @@ public struct Renderer {
79105 self . features = features
80106 self . logger = logger
81107 self . encoder = Encoder ( )
108+ self . sanitizer = Sanitizer ( )
82109 }
83110
84111 /// Renders the provided view
@@ -132,7 +159,7 @@ public struct Renderer {
132159 try render ( modifier: modifier, on: & result)
133160
134161 case let value as EnvironmentValue :
135- result += escape ( content : try render ( envvalue: value) )
162+ result += escape ( try render ( envvalue: value) , as : . html ( . element ) )
136163
137164 case let statement as Statement :
138165 try render ( statement: statement, on: & result)
@@ -146,7 +173,7 @@ public struct Renderer {
146173 case let string as MarkdownString :
147174
148175 if !features. contains ( . markdown) {
149- result += escape ( content : string. raw)
176+ result += escape ( string. raw, as : . html ( . element ) )
150177
151178 } else {
152179 result += try render ( markstring: string)
@@ -158,6 +185,12 @@ public struct Renderer {
158185 case let string as HtmlString :
159186 result += string. value
160187
188+ case let string as JsString :
189+ result += escape ( string. value, as: . js)
190+
191+ case let string as CssString :
192+ result += escape ( string. value, as: . css)
193+
161194 case let doubleValue as Double :
162195 result += String ( doubleValue)
163196
@@ -168,7 +201,7 @@ public struct Renderer {
168201 result += String ( intValue)
169202
170203 case let stringValue as String :
171- result += escape ( content : stringValue )
204+ result += escape ( stringValue , as : . html ( . element ) )
172205
173206 case let date as Date :
174207
@@ -246,7 +279,7 @@ public struct Renderer {
246279
247280 result += " <!-- "
248281
249- result += escape ( content: element . content )
282+ result += escape ( element . content, as : . html ( . element ) )
250283
251284 result += " --> "
252285 }
@@ -426,10 +459,10 @@ public struct Renderer {
426459 result += try render ( localized: string)
427460
428461 case let value as EnvironmentValue :
429- result += escape ( attribute : try render ( envvalue: value) )
462+ result += escape ( try render ( envvalue: value) , as : . html ( . attribute ) )
430463
431464 default :
432- result += escape ( attribute : " \( attribute. value) " )
465+ result += escape ( " \( attribute. value) " , as : . html ( . attribute ) )
433466 }
434467
435468 result += " \" "
@@ -442,7 +475,7 @@ public struct Renderer {
442475 ///
443476 /// - Returns: The string representation
444477 private func render( markstring: MarkdownString ) throws -> String {
445- return markdown. render ( string: escape ( content : markstring. raw) )
478+ return markdown. render ( string: escape ( markstring. raw, as : . html ( . element ) ) )
446479 }
447480
448481 /// Renders a environment string
@@ -508,7 +541,7 @@ public struct Renderer {
508541 result += string. value
509542
510543 case let string as String :
511- result += escape ( content : string )
544+ result += escape ( string , as : . html ( . element ) )
512545
513546 case is EnvironmentValue :
514547
@@ -600,35 +633,43 @@ public struct Renderer {
600633 try render ( loop: envstring. values, with: value, on: & result)
601634 }
602635
603- /// Escapes special characters in the given attribute value
604- ///
605- /// The special characters for the attribute are the backslash, the ampersand and the single quotation mark.
606- ///
607- /// - Parameter value: The attribute value to be escaped
608- ///
609- /// - Returns: The escaped value
610- private func escape( attribute value: String ) -> String {
636+ /// Escapes a string according to the given context.
637+ ///
638+ /// - Parameter value: The string value to escape
639+ /// - Parameter context: The context that defines the escaping
640+ ///
641+ /// - Returns: The escaped string
642+ private func escape( _ value: String , as context: EscapeContext ) -> String {
611643
612644 if !features. contains ( . escaping) {
613645 return value
614646 }
615647
616- return encoder. encode ( value, as: . html( . attribute) )
617- }
618-
619- /// Escapes special characters in the given content value
620- ///
621- /// The special characters for the content are the Greater than, Less than symbol.
622- ///
623- /// - Parameter value: The content value to be escaped
624- ///
625- /// - Returns: The escaped value
626- private func escape( content value: String ) -> String {
648+ switch context {
649+ case . html( let context) :
650+
651+ switch context {
652+ case . attribute:
653+ return encoder. encode ( value, as: . html( . attribute) )
654+
655+ case . element:
656+ return encoder. encode ( value, as: . html( . body) )
657+ }
658+
659+ case . css:
660+
661+ // To prevent breaking out of context
662+ let sanitized = sanitizer. strip ( " style " , from: value)
627663
628- if !features. contains ( . escaping) {
629- return value
664+ return encoder. encode ( sanitized, as: . css)
665+
666+ case . js:
667+
668+ // To prevent breaking out of context
669+ let sanitized = sanitizer. strip ( " script " , from: value)
670+
671+ return encoder. encode ( sanitized, as: . js)
672+
630673 }
631-
632- return encoder. encode ( value, as: . html( . body) )
633674 }
634675}
0 commit comments