@@ -11,11 +11,14 @@ Authors: Nera Liu <neraliu@yahoo-inc.com>
1111( function ( ) {
1212"use strict" ;
1313
14- /* debug facility */
15- var debug = require ( 'debug' ) ( 'cph' ) ;
16-
1714/* import the required package */
1815var ContextParser = require ( './strict-context-parser.js' ) ,
16+ configContextParser = {
17+ enableInputPreProcessing : true ,
18+ enableCanonicalization : true ,
19+ enableIEConditionalComments : true ,
20+ enableStateTracking : true
21+ } ,
1922 handlebarsUtils = require ( './handlebars-utils.js' ) ,
2023 stateMachine = require ( 'context-parser' ) . StateMachine ;
2124
@@ -107,9 +110,8 @@ function ContextParserHandlebars(config) {
107110 this . _charNo = 0 ;
108111 this . _lineNo = 1 ;
109112
110- // TODO: enforce the strict CP by overridding the config object.
111113 /* context parser for HTML5 parsing */
112- this . contextParser = new ContextParser ( config ) ;
114+ this . contextParser = new ContextParser ( configContextParser ) ;
113115}
114116
115117/**
@@ -400,7 +402,7 @@ ContextParserHandlebars.prototype.generateNodeObject = function(type, content, s
400402ContextParserHandlebars . prototype . analyzeAst = function ( ast , contextParser , charNo ) {
401403
402404 var output = '' , leftParser , rightParser ,
403- t , msg , exceptionObj , debugString = [ ] ;
405+ t , msg , exceptionObj ;
404406
405407 this . _charNo = charNo ;
406408
@@ -412,7 +414,7 @@ ContextParserHandlebars.prototype.analyzeAst = function(ast, contextParser, char
412414
413415 if ( node . type === 'html' ) {
414416
415- output += parser . parsePartial ( node . content ) ;
417+ output += parser . contextualize ( node . content ) ;
416418
417419 } else if ( node . type === 'escapeexpression' ||
418420 node . type === 'rawexpression' ) {
@@ -426,10 +428,7 @@ ContextParserHandlebars.prototype.analyzeAst = function(ast, contextParser, char
426428 } else if ( node . type === 'node' ) {
427429
428430 t = this . analyzeAst ( node . content , parser , node . startPos ) ;
429- // cloning states from the branches
430- parser . state = t . parser . state ;
431- parser . attributeName = t . parser . attributeName ;
432- parser . attributeValue = t . parser . attributeValue ;
431+ parser . cloneStates ( t . parser ) ;
433432
434433 output += t . output ;
435434
@@ -467,7 +466,6 @@ ContextParserHandlebars.prototype.analyzeAst = function(ast, contextParser, char
467466 leftParser . getAttributeNameType ( ) !== rightParser . getAttributeNameType ( ) )
468467 )
469468 ) {
470- // debug("analyzeAst:["+r.parsers[0].state+"/"+r.parsers[1].state+"]");
471469 msg = "[ERROR] SecureHandlebars: Inconsistent HTML5 state after conditional branches. Please fix your template! " ;
472470 msg += "state:(" + leftParser . state + "/" + rightParser . state + ")," ;
473471 msg += "attributeNameType:(" + leftParser . getAttributeNameType ( ) + "/" + rightParser . getAttributeNameType ( ) + ")" ;
@@ -510,7 +508,6 @@ ContextParserHandlebars.prototype.handleTemplate = function(input, i, stateObj)
510508 if ( input [ i ] === '{' && i + 2 < len && input [ i + 1 ] === '{' && input [ i + 2 ] === '{' ) {
511509 handlebarsExpressionType = handlebarsUtils . RAW_EXPRESSION ;
512510 /* _handleRawExpression and no validation need, it is safe guard in buildAst function */
513- debug ( "handleTemplate:handlebarsExpressionType:" + handlebarsExpressionType , ",i:" + i + ",state:" + stateObj . state ) ;
514511 obj = this . consumeExpression ( input , i , handlebarsExpressionType , true ) ;
515512 return ;
516513 } else if ( input [ i ] === '{' && i + 1 < len && input [ i + 1 ] === '{' ) {
@@ -519,7 +516,6 @@ ContextParserHandlebars.prototype.handleTemplate = function(input, i, stateObj)
519516 switch ( handlebarsExpressionType ) {
520517 case handlebarsUtils . ESCAPE_EXPRESSION :
521518 /* handleEscapeExpression and no validation need, it is safe guard in buildAst function */
522- debug ( "handleTemplate:handlebarsExpressionType:" + handlebarsExpressionType , ",i:" + i + ",state:" + stateObj . state ) ;
523519 obj = this . handleEscapeExpression ( input , i , len , stateObj , true ) ;
524520 return ;
525521 default :
@@ -553,8 +549,8 @@ ContextParserHandlebars.prototype.addFilters = function(parser, input) {
553549 var isFullUri = false , filters = [ ] , f , exceptionObj , errorMessage ,
554550 state = parser . state ,
555551 tagName = parser . getStartTagName ( ) ,
556- attributeName = parser . attributeName ,
557- attributeValue = parser . attributeValue ;
552+ attributeName = parser . getAttributeName ( ) ,
553+ attributeValue = parser . getAttributeValue ( ) ;
558554
559555 try {
560556
@@ -594,9 +590,13 @@ ContextParserHandlebars.prototype.addFilters = function(parser, input) {
594590 filters . push ( f ) ;
595591
596592 } else if ( parser . getAttributeNameType ( ) === ContextParser . ATTRTYPE_CSS ) { // CSS
597-
598- attributeValue = htmlDecoder . decode ( attributeValue ) ;
599- var r = cssParserUtils . parseStyleAttributeValue ( attributeValue ) ;
593+ var r ;
594+ try {
595+ attributeValue = htmlDecoder . decode ( attributeValue ) ;
596+ r = cssParserUtils . parseStyleAttributeValue ( attributeValue ) ;
597+ } catch ( e ) {
598+ throw 'Unsafe output expression @ attribute style CSS context (Parsing error OR expression position not supported!)' ;
599+ }
600600 switch ( r . code ) {
601601 case cssParserUtils . STYLE_ATTRIBUTE_URL_UNQUOTED :
602602 filters . push ( filter . FILTER_ATTRIBUTE_VALUE_STYLE_EXPR_URL_UNQUOTED ) ;
@@ -694,11 +694,10 @@ ContextParserHandlebars.prototype.addFilters = function(parser, input) {
694694 // TODO: need tagname tracing in Context Parser such that we can have
695695 // ability to capture the case of putting output expression within dangerous tag.
696696 // like svg etc.
697- // the following will be caught by parser .isScriptableTag() anyway
698- // case stateMachine.State.STATE_SCRIPT_DATA: // 6
699- // throw 'inside <script> tag (i.e., SCRIPT_DATA state)';
697+ // the following will be caught by handlebarsUtils .isScriptableTag(tagName ) anyway
698+ case stateMachine . State . STATE_SCRIPT_DATA : // 6
699+ throw 'inside <script> tag (i.e., SCRIPT_DATA state)' ;
700700
701-
702701 // should not fall into the following states
703702 case stateMachine . State . STATE_BEFORE_ATTRIBUTE_VALUE : // 37
704703 throw 'unexpectedly BEFORE_ATTRIBUTE_VALUE state' ;
@@ -715,7 +714,7 @@ ContextParserHandlebars.prototype.addFilters = function(parser, input) {
715714 // To be secure, scriptable tags when encountered will anyway throw an error/warning
716715 // they require either special parsers of their own context (e.g., CSS/script parsers)
717716 // or an application-specific whitelisted url check (e.g., <script src=""> with yubl-yavu-yufull is not enough)
718- errorMessage += parser . isScriptableTag ( ) ? 'scriptable <' + tagName + '> tag' : exception ;
717+ errorMessage += handlebarsUtils . isScriptableTag ( tagName ) ? 'scriptable <' + tagName + '> tag' : exception ;
719718
720719 exceptionObj = new ContextParserHandlebarsException ( errorMessage , this . _lineNo , this . _charNo ) ;
721720 handlebarsUtils . handleError ( exceptionObj , this . _config . _strictMode ) ;
0 commit comments