@@ -157,7 +157,7 @@ function renderNamespace(str) {
157157function renderObject ( obj , namespace ) {
158158 return Object . keys ( obj ) . map ( function ( key ) {
159159 var val = obj [ key ] ;
160- return namespace + '["' + key + '"] = ' + string ( val ) + ';' ;
160+ return namespace + '["' + escape_js_string ( key ) + '"] = ' + string ( val ) + ';' ;
161161 } ) . join ( '\n' ) ;
162162}
163163
@@ -180,61 +180,49 @@ function string(obj) {
180180 }
181181 else if ( '[object Object]' === Object . prototype . toString . call ( obj ) ) {
182182 return '{' + Object . keys ( obj ) . map ( function ( key ) {
183- return '"' + key + '":' + string ( obj [ key ] ) ;
183+ return '"' + escape_js_string ( key ) + '":' + string ( obj [ key ] ) ;
184184 } ) . join ( ', ' ) + '}' ;
185185 }
186186 else {
187- obj = escape_html ( JSON . stringify ( obj ) ) ;
187+ obj = JSON . stringify ( obj ) ;
188188 if ( obj ) {
189+ // Only escape things that could break out of script context
189190 obj = obj . replace ( / < \/ s c r i p t > / ig, '</scr"+"ipt>' ) ;
191+ obj = obj . replace ( / < ! - - / g, '<\\!--' ) ;
192+ obj = obj . replace ( / \u2028 / g, '\\u2028' ) ; // Line separator
193+ obj = obj . replace ( / \u2029 / g, '\\u2029' ) ; // Paragraph separator
190194 }
191195 return obj ;
192196 }
193197}
194198
195- var matchHtmlRegExp = / [ < > ] / ;
196-
197199/**
198- * Escape special characters in the given string of html.
200+ * Escape special characters that could break JavaScript string context
199201*
200- * @param {string } str - The string to escape for inserting into HTML
202+ * @param {string } str - The string to escape
201203* @return {string } escaped string
202204* @public
203205*/
204- function escape_html ( str ) {
205- str = '' + str ;
206- var match = matchHtmlRegExp . exec ( str ) ;
207-
208- if ( ! match ) {
206+ function escape_js_string ( str ) {
207+ if ( typeof str !== 'string' ) {
209208 return str ;
210209 }
211210
212- var escape ;
213- var html = '' ;
214- var index = 0 ;
215- var lastIndex = 0 ;
216-
217- for ( index = match . index ; index < str . length ; index ++ ) {
218- switch ( str . charCodeAt ( index ) ) {
219- case 60 : // <
220- escape = '<' ;
221- break ;
222- case 62 : // >
223- escape = '>' ;
224- break ;
225- default :
226- continue ;
227- }
228-
229- if ( lastIndex !== index ) {
230- html += str . substring ( lastIndex , index ) ;
231- }
232-
233- lastIndex = index + 1 ;
234- html += escape ;
235- }
236-
237- return lastIndex !== index ? html + str . substring ( lastIndex , index ) : html ;
211+ return str
212+ . replace ( / \\ / g, '\\\\' ) // Backslash
213+ . replace ( / " / g, '\\"' ) // Double quote
214+ . replace ( / ' / g, "\\'" ) // Single quote
215+ . replace ( / ` / g, '\\`' ) // Backtick (template literal)
216+ . replace ( / \$ / g, '\\$' ) // Dollar sign (template literal)
217+ . replace ( / \n / g, '\\n' ) // Newline
218+ . replace ( / \r / g, '\\r' ) // Carriage return
219+ . replace ( / \t / g, '\\t' ) // Tab
220+ . replace ( / \f / g, '\\f' ) // Form feed
221+ . replace ( / \v / g, '\\v' ) // Vertical tab
222+ . replace ( / \0 / g, '\\0' ) // Null character
223+ . replace ( / [ \u0000 - \u001F \u007F - \u009F ] / g, function ( ch ) {
224+ return '\\u' + ( '0000' + ch . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 4 ) ;
225+ } ) ;
238226}
239227
240228exports = module . exports = function ( app ) {
0 commit comments