@@ -43,29 +43,6 @@ 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-
6946 /// The context environment used during rendering
7047 private var environment : Environment
7148
@@ -159,7 +136,7 @@ public struct Renderer {
159136 try render ( modifier: modifier, on: & result)
160137
161138 case let value as EnvironmentValue :
162- result += escape ( try render ( envvalue: value) , as: . html( . element) )
139+ result += escape ( tainted : . init ( try render ( envvalue: value) , as: . html( . element) ) )
163140
164141 case let statement as Statement :
165142 try render ( statement: statement, on: & result)
@@ -173,7 +150,7 @@ public struct Renderer {
173150 case let string as MarkdownString :
174151
175152 if !features. contains ( . markdown) {
176- result += escape ( string. raw, as: . html( . element) )
153+ result += escape ( tainted : . init ( string. raw, as: . html( . element) ) )
177154
178155 } else {
179156 result += try render ( markstring: string)
@@ -185,11 +162,8 @@ public struct Renderer {
185162 case let string as HtmlString :
186163 result += string. value
187164
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)
165+ case let string as TaintedString :
166+ result += escape ( tainted: string)
193167
194168 case let doubleValue as Double :
195169 result += String ( doubleValue)
@@ -201,7 +175,7 @@ public struct Renderer {
201175 result += String ( intValue)
202176
203177 case let stringValue as String :
204- result += escape ( stringValue, as: . html( . element) )
178+ result += escape ( tainted : . init ( stringValue, as: . html( . element) ) )
205179
206180 case let date as Date :
207181
@@ -279,7 +253,7 @@ public struct Renderer {
279253
280254 result += " <!-- "
281255
282- result += escape ( element. content, as: . html( . element) )
256+ result += escape ( tainted : . init ( element. content, as: . html( . element) ) )
283257
284258 result += " --> "
285259 }
@@ -459,10 +433,10 @@ public struct Renderer {
459433 result += try render ( localized: string)
460434
461435 case let value as EnvironmentValue :
462- result += escape ( try render ( envvalue: value) , as: . html( . attribute) )
436+ result += escape ( tainted : . init ( try render ( envvalue: value) , as: . html( . attribute) ) )
463437
464438 default :
465- result += escape ( " \( attribute. value) " , as: . html( . attribute) )
439+ result += escape ( tainted : . init ( " \( attribute. value) " , as: . html( . attribute) ) )
466440 }
467441
468442 result += " \" "
@@ -475,7 +449,7 @@ public struct Renderer {
475449 ///
476450 /// - Returns: The string representation
477451 private func render( markstring: MarkdownString ) throws -> String {
478- return markdown. render ( string: escape ( markstring. raw, as: . html( . element) ) )
452+ return markdown. render ( string: escape ( tainted : . init ( markstring. raw, as: . html( . element) ) ) )
479453 }
480454
481455 /// Renders a environment string
@@ -540,8 +514,11 @@ public struct Renderer {
540514 case let string as HtmlString :
541515 result += string. value
542516
517+ case let string as TaintedString :
518+ result += escape ( tainted: string)
519+
543520 case let string as String :
544- result += escape ( string, as: . html( . element) )
521+ result += escape ( tainted : . init ( string, as: . html( . element) ) )
545522
546523 case is EnvironmentValue :
547524
@@ -633,40 +610,44 @@ public struct Renderer {
633610 try render ( loop: envstring. values, with: value, on: & result)
634611 }
635612
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
613+ /// Escapes a tainted string
614+ ///
615+ /// It takes precautions such as character encoding and input sanitization to ensure a safe output. Though the escaping alone
616+ /// does not guarantee complete safety. It only helps mitigate the risk.
617+ ///
618+ /// - Parameter string: The string value to escape.
640619 ///
641- /// - Returns: The escaped string
642- private func escape( _ value : String , as context : EscapeContext ) -> String {
643-
620+ /// - Returns: The untainted string
621+ private func escape( tainted string : TaintedString ) -> String {
622+
644623 if !features. contains ( . escaping) {
645- return value
624+
625+ // Bail early, if the escaping is not desired
626+ return string. value
646627 }
647628
648- switch context {
629+ switch string . context {
649630 case . html( let context) :
650631
651632 switch context {
652633 case . attribute:
653- return encoder. encode ( value, as: . html( . attribute) )
634+ return encoder. encode ( string . value, as: . html( . attribute) )
654635
655636 case . element:
656- return encoder. encode ( value, as: . html( . body ) )
637+ return encoder. encode ( string . value, as: . html( . element ) )
657638 }
658639
659640 case . css:
660641
661642 // To prevent breaking out of context
662- let sanitized = sanitizer. strip ( " style " , from: value)
643+ let sanitized = sanitizer. strip ( " style " , from: string . value)
663644
664645 return encoder. encode ( sanitized, as: . css)
665646
666647 case . js:
667648
668649 // To prevent breaking out of context
669- let sanitized = sanitizer. strip ( " script " , from: value)
650+ let sanitized = sanitizer. strip ( " script " , from: string . value)
670651
671652 return encoder. encode ( sanitized, as: . js)
672653
0 commit comments