secure-handlebars
Advanced tools
Comparing version 1.1.1 to 1.2.0
{ | ||
"name": "secure-handlebars", | ||
"version": "1.1.1", | ||
"version": "1.2.0", | ||
"main": "dist/secure-handlebars.min.js", | ||
@@ -5,0 +5,0 @@ "authors": [ |
@@ -54,2 +54,6 @@ /* | ||
dest: 'dist/<%= pkg.name %>.min.js' | ||
}, | ||
buildMinWithVersion: { | ||
src: ['src/polyfills/*.js', 'dist/<%= pkg.name %>.js'], | ||
dest: 'dist/<%= pkg.name %>.<%= pkg.version %>.min.js' | ||
} | ||
@@ -96,5 +100,23 @@ }, | ||
}, | ||
bump: { | ||
options: { | ||
files: [ 'package.json', 'bower.json'], | ||
updateConfigs: ['pkg'], | ||
commit: true, | ||
commitMessage: 'Release v%VERSION%', | ||
commitFiles: ['package.json', 'bower.json', 'dist/.'], | ||
createTag: true, | ||
tagName: 'v%VERSION%', | ||
tagMessage: 'Version %VERSION%', | ||
push: false, | ||
pushTo: 'origin', | ||
gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d', | ||
globalReplace: false, | ||
prereleaseName: false, | ||
regExp: false | ||
} | ||
}, | ||
clean: { | ||
all: ['xunit.xml', 'artifacts', 'coverage', 'node_modules'], | ||
buildResidues: ['xunit.xml', 'artifacts', 'coverage'] | ||
all: ['artifacts', 'coverage', 'node_modules'], | ||
buildResidues: ['artifacts', 'coverage'] | ||
} | ||
@@ -110,2 +132,3 @@ }); | ||
grunt.loadNpmTasks('grunt-execute'); | ||
grunt.loadNpmTasks('grunt-bump'); | ||
@@ -115,3 +138,4 @@ grunt.registerTask('test', ['clean:buildResidues', 'jshint', 'execute', 'dist', 'karma', 'mocha_istanbul']); | ||
grunt.registerTask('default', ['test']); | ||
grunt.registerTask('release', ['bump-only', 'dist']) | ||
}; | ||
}; |
{ | ||
"name": "secure-handlebars", | ||
"version": "1.1.1", | ||
"licenses": [ | ||
{ | ||
"type": "BSD", | ||
"url": "https://github.com/yahoo/secure-handlebars/blob/master/LICENSE" | ||
} | ||
], | ||
"version": "1.2.0", | ||
"author": "Nera Liu", | ||
@@ -44,23 +38,31 @@ "contributors": [ | ||
"dependencies": { | ||
"bluebird": "^2.9.30", | ||
"context-parser": "^2.0.1", | ||
"glob": "^5.0.13", | ||
"handlebars": "^3.0.3", | ||
"html-decoder": "^1.0.2", | ||
"xss-filters": "^1.2.4" | ||
"minimist": "^1.2.0", | ||
"mkdirp": "^0.5.1", | ||
"xss-filters": "^1.2.6" | ||
}, | ||
"devDependencies": { | ||
"bluebird": "^2.9.30", | ||
"chai": "^2.3.0", | ||
"chai": "^3.2.0", | ||
"grunt": "^0.4.5", | ||
"grunt-bower-task": "^0.4.0", | ||
"grunt-browserify": "^3.3.0", | ||
"grunt-browserify": "^4.0.0", | ||
"grunt-bump": "^0.3.2", | ||
"grunt-cli": "^0.1.13", | ||
"grunt-contrib-clean": "^0.6.0", | ||
"grunt-contrib-jshint": "^0.11.0", | ||
"grunt-contrib-uglify": "^0.9.1", | ||
"grunt-contrib-uglify": "^0.9.2", | ||
"grunt-execute": "^0.2.2", | ||
"grunt-karma": "^0.11.0", | ||
"grunt-mocha-istanbul": "^2.3.0", | ||
"grunt-karma": "^0.12.0", | ||
"grunt-mocha-istanbul": "^3.0.1", | ||
"istanbul": "^0.3.18", | ||
"jison": "^0.4.15", | ||
"karma": "^0.12.36", | ||
"karma-mocha": "^0.1.10", | ||
"karma-phantomjs-launcher": "^0.2.0" | ||
"karma": "^0.13.9", | ||
"karma-mocha": "^0.2.0", | ||
"karma-phantomjs-launcher": "^0.2.1", | ||
"mocha": "^2.2.5", | ||
"phantomjs": "^1.9.18" | ||
}, | ||
@@ -75,3 +77,3 @@ "main": "./src/secure-handlebars.js", | ||
}, | ||
"license": "BSD" | ||
"license": "SEE LICENSE IN LICENSE" | ||
} |
@@ -11,2 +11,3 @@ /* | ||
/*jshint -W030 */ | ||
/*jshint -W083 */ | ||
(function () { | ||
@@ -27,2 +28,8 @@ "use strict"; | ||
// https://github.com/yahoo/secure-handlebars/blob/master/src/handlebars-utils.js#L76 | ||
// TODO: double check the case of allowing \/ | ||
var rePartialPattern = /^(\{\{~?>\s*)([^\s!"#%&'\(\)\*\+,\.;<=>@\[\\\]\^`\{\|\}\~]+)(.*)/, | ||
// reSJSTPartialSignature = /^SJST\/(?:\d+|SKIP)\//; | ||
reSJSTPartialSignature = /^SJST\/\d+\//; | ||
// extracted from xss-filters | ||
@@ -51,5 +58,5 @@ /* | ||
*/ | ||
function ContextParserHandlebarsException(msg, fileName, lineNo, charNo) { | ||
function ContextParserHandlebarsException(msg, filePath, lineNo, charNo) { | ||
this.msg = msg; | ||
this.fileName = fileName; | ||
this.filePath = filePath; | ||
this.lineNo = lineNo; | ||
@@ -69,6 +76,8 @@ this.charNo = charNo; | ||
function ContextParserHandlebars(config) { | ||
config || (config = {}); | ||
config.shbsPartialsCache || (config.shbsPartialsCache = {}); | ||
/* save the processed char */ | ||
this._buffer = []; | ||
/* reset the internal */ | ||
this.reset(config.processingFile); | ||
@@ -84,10 +93,39 @@ /* the configuration of ContextParserHandlebars */ | ||
/* the flags are used to set to dis/enable partial processing, defaulted to false */ | ||
this._config._enablePartialProcessing = config.shbsPartialsCache.raw !== undefined; | ||
/* the flags is used for setting the partial handling */ | ||
this._config._enablePartialCombine = (config.enablePartialCombine === true); | ||
/* this flag is used for preventing infinite lookup of partials */ | ||
this._config._maxPartialDepth = parseInt(config.maxPartialDepth) || 10; | ||
/* internal file cache */ | ||
this._config._rawPartialsCache = config.shbsPartialsCache.raw || {}; | ||
/* expose the processed partial cache */ | ||
this._config._processedPartialsCache = config.shbsPartialsCache.preprocessed || {}; | ||
} | ||
/** | ||
* @function ContextParserHandlebars.reset | ||
* | ||
* @description | ||
* All non-config internal variables are needed to reset! | ||
*/ | ||
ContextParserHandlebars.prototype.reset = function(filePath) { | ||
/* save the processed char */ | ||
this._buffer = []; | ||
this._partials = []; | ||
/* save the char/line no being processed */ | ||
this._charNo = 0; | ||
this._lineNo = 1; | ||
this._fileName = config.processingFile? config.processingFile: ''; | ||
this._filePath = filePath || ''; | ||
/* context parser for HTML5 parsing */ | ||
this.contextParser = parserUtils.getParser(); | ||
} | ||
}; | ||
@@ -163,7 +201,13 @@ /** | ||
*/ | ||
ContextParserHandlebars.prototype.analyzeContext = function(input) { | ||
ContextParserHandlebars.prototype.analyzeContext = function(input, options) { | ||
options || (options = {}); | ||
// the last parameter is the hack till we move to LR parser | ||
var ast = this.buildAst(input, 0, []); | ||
var r = this.analyzeAst(ast, this.contextParser, 0); | ||
(this._config._printCharEnable && typeof process === 'object')? process.stdout.write(r.output) : ''; | ||
var ast = this.buildAst(input, 0, []), | ||
r = this.analyzeAst(ast, options.contextParser || this.contextParser, 0); | ||
if (this._config._printCharEnable && typeof process === 'object') { | ||
options.disablePrintChar || process.stdout.write(r.output); | ||
} | ||
return r.output; | ||
@@ -339,3 +383,3 @@ }; | ||
'[ERROR] SecureHandlebars: ' + exception, | ||
this._fileName, | ||
this._filePath, | ||
this.countNewLineChar(input.slice(0, j)), j); | ||
@@ -390,4 +434,6 @@ handlebarsUtils.handleError(exceptionObj, true); | ||
/*jshint validthis: true */ | ||
var j = 0, len = tree.length, node, | ||
re, partialName, enterState, partialContent; | ||
for (var j = 0, len = tree.length, node; j < len; j++) { | ||
for (; j < len; j++) { | ||
node = tree[j]; | ||
@@ -403,3 +449,3 @@ | ||
// lookupStateForHandlebarsOpenBraceChar from current state before handle it | ||
parser.setCurrentState(ContextParserHandlebars.lookupStateForHandlebarsOpenBraceChar[parser.state]); | ||
parser.state = ContextParserHandlebars.lookupStateForHandlebarsOpenBraceChar[parser.state]; | ||
this.clearBuffer(); | ||
@@ -416,13 +462,97 @@ this.handleEscapeAndRawTemplate(node.content, 0, parser); | ||
// TODO: we support basic partial only, need to enhance it. | ||
// http://handlebarsjs.com/partials.html | ||
} else if (node.type === handlebarsUtils.PARTIAL_EXPRESSION && | ||
(re = handlebarsUtils.isValidExpression(node.content, 0, node.type)) && | ||
(partialName = re.tag)) { | ||
// if the partialName is generated by us, there is no need to reprocess it again, | ||
// just put back the partial expression is fine | ||
if (reSJSTPartialSignature.test(partialName)) { | ||
output += node.content; | ||
continue; | ||
} | ||
partialContent = this._config._rawPartialsCache[partialName]; | ||
if (this._config._enablePartialProcessing && typeof partialContent === 'string') { | ||
this._partials.push(node.content); | ||
if (this._partials.length >= this._config._maxPartialDepth) { | ||
msg = "[ERROR] SecureHandlebars: The partial inclusion chain ("; | ||
msg += this._partials.join(' > ') + ") has exceeded the maximum number of allowed depths (maxPartialDepth: "+this._config._maxPartialDepth+")."; | ||
msg += "\nPlease follow this URL to resolve - https://github.com/yahoo/secure-handlebars#warnings-and-workarounds"; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._filePath, this._lineNo, this._charNo); | ||
handlebarsUtils.handleError(exceptionObj, true); | ||
} | ||
// get the html state number right the parital is called, and analyzed | ||
enterState = parser.getCurrentState(); | ||
// TODO: this._filePath now does not reflect an error that occurs inside a partial, need to enhance it later | ||
// while analyzing the partial, use the current parser (possibly forked) and disable printChar | ||
partialContent = this.analyzeContext(partialContent, { | ||
contextParser: parser, | ||
disablePrintChar: true | ||
}); | ||
if (this._config._enablePartialCombine) { | ||
output += partialContent; | ||
} else { | ||
partialName = 'SJST/' + enterState + '/' + partialName; | ||
// rewrite the partial name, that is prefixed with the in-state | ||
output += node.content.replace(rePartialPattern, function(m, p1, p2, p3) { | ||
return p1 + partialName + p3; | ||
}); | ||
this._config._processedPartialsCache[partialName] = partialContent; | ||
} | ||
this._partials.pop(); | ||
} else { | ||
output += node.content; // this._config._strictMode=true will throw | ||
msg = (this._config._strictMode? '[ERROR]' : '[WARNING]') + " SecureHandlebars: "; | ||
if (this._config._enablePartialProcessing) { | ||
msg += (partialContent === undefined) ? | ||
"Failed to load the partial content of " : | ||
"Failed to perform contextual analysis over (pre-)compiled partial "; | ||
} else { | ||
// No matter a partial expression is placed in a data state, we don't know whether the partial content end in DATA state, so warn the user | ||
// if (parser.getCurrentState() !== stateMachine.State.STATE_DATA) { | ||
// msg += node.content + ' is placed in a non-text context.'; | ||
// } | ||
msg += 'Please enable contextual analysis over the partial content of '; | ||
} | ||
msg += node.content; | ||
msg += "\nPlease follow this URL to resolve - https://github.com/yahoo/secure-handlebars#warnings-and-workarounds"; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._filePath, this._lineNo, this._charNo); | ||
handlebarsUtils.handleError(exceptionObj, this._config._strictMode); | ||
} | ||
// TODO: content inside RAW_BLOCK should be analysed too | ||
} else if (node.type === handlebarsUtils.RAW_BLOCK || | ||
node.type === handlebarsUtils.PARTIAL_EXPRESSION || | ||
node.type === handlebarsUtils.AMPERSAND_EXPRESSION) { | ||
// if the 'rawblock', 'partial expression' and 'ampersand expression' are not in Data State, | ||
// if the 'rawblock' and 'ampersand expression' are not in Data State, | ||
// we should warn the developers or throw exception in strict mode | ||
if (parser.getCurrentState() !== stateMachine.State.STATE_DATA) { | ||
msg = (this._config._strictMode? '[ERROR]' : '[WARNING]') + " SecureHandlebars: " + node.content + ' is in non-HTML Context!'; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._fileName, this._lineNo, this._charNo); | ||
msg = (this._config._strictMode? '[ERROR]' : '[WARNING]') + " SecureHandlebars: " + node.content + ' is placed in a non-text context!'; | ||
msg += "\nPlease follow this URL to resolve - https://github.com/yahoo/secure-handlebars#warnings-and-workarounds"; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._filePath, this._lineNo, this._charNo); | ||
handlebarsUtils.handleError(exceptionObj, this._config._strictMode); | ||
} | ||
output += node.content; | ||
@@ -465,3 +595,3 @@ } else if (node.type === handlebarsUtils.BRANCH_EXPRESSION || | ||
msg += "attributeNameType:("+leftParser.getAttributeNameType()+"/"+rightParser.getAttributeNameType()+")"; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._fileName, this._lineNo, this._charNo); | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._filePath, this._lineNo, this._charNo); | ||
handlebarsUtils.handleError(exceptionObj, true); | ||
@@ -664,3 +794,3 @@ } | ||
exceptionObj = new ContextParserHandlebarsException(errorMessage, this._fileName, this._lineNo, this._charNo); | ||
exceptionObj = new ContextParserHandlebarsException(errorMessage, this._filePath, this._lineNo, this._charNo); | ||
handlebarsUtils.handleError(exceptionObj, this._config._strictMode); | ||
@@ -767,3 +897,3 @@ } else { | ||
'[ERROR] SecureHandlebars: ' + exception, | ||
this._fileName, | ||
this._filePath, | ||
this._lineNo, | ||
@@ -860,4 +990,4 @@ this._charNo); | ||
} | ||
msg = "[ERROR] SecureHandlebars: Parsing error! Cannot encounter '}}' close brace of escape expression."; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._fileName, this._lineNo, this._charNo); | ||
msg = "[ERROR] SecureHandlebars: Parse error! Cannot encounter '}}' close brace of escape expression."; | ||
exceptionObj = new ContextParserHandlebarsException(msg, this._filePath, this._lineNo, this._charNo); | ||
handlebarsUtils.handleError(exceptionObj, true); | ||
@@ -864,0 +994,0 @@ }; |
@@ -75,4 +75,5 @@ /* | ||
/* '{{' '~'? '>' '\s'* ('not \s, special-char'+) '\s'* 'not ~{}'* non-greedy '}}' and not follow by '}' */ | ||
/* slash should be allowed */ | ||
HandlebarsUtils.PARTIAL_EXPRESSION = 3; // {{>.*}} | ||
HandlebarsUtils.partialExpressionRegExp = /^\{\{~?>\s*([^\s!"#%&'\(\)\*\+,\.\/;<=>@\[\\\]\^`\{\|\}\~]+)\s*[^~\}\{]*~?\}\}(?!})/; | ||
HandlebarsUtils.partialExpressionRegExp = /^\{\{~?>\s*([^\s!"#%&'\(\)\*\+,\.;<=>@\[\\\]\^`\{\|\}\~]+)\s*([^~\}\{]*)~?\}\}(?!})/; | ||
@@ -298,3 +299,3 @@ /* '{{' '~'? '# or ^' '\s'* ('not \s, special-char'+) '\s'* 'not {}~'* '~'? non-greedy '}}' and not follow by '}' */ | ||
HandlebarsUtils.handleError = function(exceptionObj, throwErr) { | ||
HandlebarsUtils.warn(exceptionObj.msg + (exceptionObj.fileName !== ''? '\n'+exceptionObj.fileName:'') + " [lineNo:" + exceptionObj.lineNo + ",charNo:" + exceptionObj.charNo + "]"); | ||
HandlebarsUtils.warn(exceptionObj.msg + (exceptionObj.filePath !== ''? '\n'+exceptionObj.filePath:'') + " [lineNo:" + exceptionObj.lineNo + ",charNo:" + exceptionObj.charNo + "]"); | ||
if (throwErr) { | ||
@@ -337,5 +338,4 @@ throw exceptionObj; | ||
module.exports = HandlebarsUtils; | ||
})(); |
@@ -110,3 +110,3 @@ /* | ||
Parser.prototype.cloneStates = function(parser) { | ||
this.state = parser.getLastState(); | ||
this.state = parser.getCurrentState(); | ||
this.attrName = parser.getAttributeName(); | ||
@@ -128,3 +128,3 @@ this.attributeValue = parser.getAttributeValue(); | ||
enableVoidingIEConditionalComments: true, | ||
enableStateTracking: true | ||
enableStateTracking: false | ||
}); | ||
@@ -131,0 +131,0 @@ }; |
@@ -41,2 +41,4 @@ /* | ||
options = options || {}; | ||
options.printCharEnable = false; | ||
var k, parser; | ||
@@ -46,5 +48,3 @@ | ||
if (template) { | ||
parser = new ContextParserHandlebars({ printCharEnable: false, | ||
processingFile: options.processingFile, | ||
strictMode: options.strictMode}); | ||
parser = new ContextParserHandlebars(options); | ||
return parser.analyzeContext(template); | ||
@@ -73,3 +73,4 @@ } | ||
// expose the original compile | ||
// expose the original (pre-)/compile | ||
h.precompilePreprocessed = pc; | ||
h.compilePreprocessed = c; | ||
@@ -76,0 +77,0 @@ |
@@ -93,6 +93,23 @@ /* | ||
expect(output).to.be.equal('<!--hello--><a href=x-javascript:alert(1) style="background:url(##javascript:alert\\28 1\\29 )" id="12`"\'3" id=\'12`"'3\'>hello</a>'); | ||
expect(output).to.be.equal('<!--hello--><a href=x-javascript:alert(1) style="background:url(##javascript:alert%281%29)" id="12`"\'3" id=\'12`"'3\'>hello</a>'); | ||
}); | ||
}); | ||
describe("SecureHandlebars: preprocess tests", function() { | ||
it('smoke template', function(){ | ||
var html = '<!--{{hello}}--><a href={{url}} style="background:url({{url}})" id="{{id}}" id=\'{{id}}\'>{{hello}}</a>'; | ||
var data = { | ||
'id': '12`"\'3', | ||
'hello': 'hello', | ||
'url': 'javascript:alert(1)' | ||
}; | ||
var preprocessed = Handlebars.preprocess(html); | ||
expect(preprocessed).to.be.equal('<!--{{{yc hello}}}--><a href={{{yubl (yavu (yufull url))}}} style="background:url({{{yubl (yavd (yceuu url))}}})" id="{{{yavd id}}}" id=\'{{{yavs id}}}\'>{{{yd hello}}}</a>'); | ||
var output = Handlebars.compilePreprocessed(preprocessed)(data); | ||
expect(output).to.be.equal('<!--hello--><a href=x-javascript:alert(1) style="background:url(##javascript:alert%281%29)" id="12`"\'3" id=\'12`"'3\'>hello</a>'); | ||
}); | ||
}); | ||
describe("SecureHandlebars: compilation error tests", function() { | ||
@@ -99,0 +116,0 @@ it('fallback template', function(){ |
@@ -18,5 +18,7 @@ /* | ||
expect = require('chai').expect, | ||
ContextParserHandlebars = require("../../src/context-parser-handlebars"); | ||
ContextParserHandlebars = require("../../src/context-parser-handlebars"), | ||
exec = promise.promisify(require("child_process").exec); | ||
var config = {}; | ||
// TODO: need to improve the processing time of the unit test. | ||
var config = {}, t = 500; | ||
config.printCharEnable = false; | ||
@@ -42,5 +44,5 @@ | ||
it(testObj.title, function(done) { | ||
var exec = promise.promisify(require("child_process").exec); | ||
exec('./bin/handlebarspp '+testObj.file) | ||
.timeout(300) | ||
.timeout(t) | ||
.done(function(e){ | ||
@@ -58,5 +60,5 @@ testObj.result.forEach(function(r) { | ||
it(testObj.title, function(done) { | ||
var exec = promise.promisify(require("child_process").exec); | ||
exec('./bin/handlebarspp '+testObj.file) | ||
.timeout(300) | ||
exec('./bin/handlebarspp '+testObj.file+' -e .hbs -p tests/samples/files/partials') | ||
.timeout(t) | ||
.done(function(e){ | ||
@@ -71,8 +73,30 @@ testObj.result.forEach(function(r) { | ||
/* partial tests */ | ||
testPatterns.partialPatterns.forEach(function(testObj) { | ||
it(testObj.title, function(done) { | ||
var params = ' -e .hbs'; | ||
if (testObj.partialProcessing) { | ||
params += ' -p tests/samples/files/partials'; | ||
} | ||
if (testObj.combine) { | ||
params += ' -c'; | ||
} | ||
exec('./bin/handlebarspp '+ testObj.file + params) | ||
.timeout(t) | ||
.done(function(e){ | ||
testObj.result.forEach(function(r) { | ||
expect(e.toString()).to.match(r); | ||
}); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
/* exception tests */ | ||
testPatterns.exceptionPatterns.forEach(function(testObj) { | ||
it(testObj.title, function(done) { | ||
var exec = promise.promisify(require("child_process").exec); | ||
exec('./bin/handlebarspp '+testObj.file+' '+testObj.strictMode) | ||
.timeout(300) | ||
exec('./bin/handlebarspp '+testObj.file+' -e .hbs -p tests/samples/files/partials' + (testObj.strictMode ? ' -s' : '')) | ||
.timeout(t) | ||
.catch(function(e){ | ||
@@ -90,5 +114,5 @@ testObj.result.forEach(function(r) { | ||
it(testObj.title, function(done) { | ||
var exec = promise.promisify(require("child_process").exec); | ||
exec('./bin/handlebarspp '+testObj.file) | ||
.timeout(300) | ||
.timeout(t) | ||
.done(function(e){ | ||
@@ -95,0 +119,0 @@ testObj.result.forEach(function(r) { |
@@ -22,2 +22,3 @@ /* | ||
expect(secureHandlebars.compile('')(data)).to.be.equal(''); | ||
expect(secureHandlebars.preprocess('')).to.be.equal(''); | ||
}); | ||
@@ -72,2 +73,5 @@ | ||
var templatePreProcessed = secureHandlebars.preprocess(template); | ||
expect(templatePreProcessed).to.be.equal('<a href="{{{yubl (yavd (yufull url))}}}">hello</a>'); | ||
var t1 = secureHandlebars.compilePreprocessed(templatePreProcessed); | ||
@@ -74,0 +78,0 @@ |
@@ -83,3 +83,3 @@ /* | ||
parser2.cloneStates(parser1); | ||
expect(parser2.getLastState()).to.equal(1); | ||
expect(parser2.getCurrentState()).to.equal(1); | ||
expect(parser2.getAttributeName()).to.equal("href"); | ||
@@ -86,0 +86,0 @@ expect(parser2.getAttributeValue()).to.equal("http://www.abc.com"); |
@@ -188,4 +188,3 @@ /* | ||
}); | ||
}); | ||
}()); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1386917
110
18176
8
8
19
2
11
+ Addedbluebird@^2.9.30
+ Addedglob@^5.0.13
+ Addedminimist@^1.2.0
+ Addedmkdirp@^0.5.1
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbluebird@2.11.0(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedglob@5.0.15(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedwrappy@1.0.2(transitive)
Updatedxss-filters@^1.2.6