Show More
Commit Description:
submission report
Commit Description:
submission report
References:
File last commit:
Show/Diff file:
Action:
node_modules/static-eval/index.js
| 205 lines
| 7.3 KiB
| application/javascript
| JavascriptLexer
|
r789 | var unparse = require('escodegen').generate; | |||
module.exports = function (ast, vars) { | ||||
if (!vars) vars = {}; | ||||
var FAIL = {}; | ||||
var result = (function walk (node, noExecute) { | ||||
if (node.type === 'Literal') { | ||||
return node.value; | ||||
} | ||||
else if (node.type === 'UnaryExpression'){ | ||||
var val = walk(node.argument, noExecute) | ||||
if (node.operator === '+') return +val | ||||
if (node.operator === '-') return -val | ||||
if (node.operator === '~') return ~val | ||||
if (node.operator === '!') return !val | ||||
return FAIL | ||||
} | ||||
else if (node.type === 'ArrayExpression') { | ||||
var xs = []; | ||||
for (var i = 0, l = node.elements.length; i < l; i++) { | ||||
var x = walk(node.elements[i], noExecute); | ||||
if (x === FAIL) return FAIL; | ||||
xs.push(x); | ||||
} | ||||
return xs; | ||||
} | ||||
else if (node.type === 'ObjectExpression') { | ||||
var obj = {}; | ||||
for (var i = 0; i < node.properties.length; i++) { | ||||
var prop = node.properties[i]; | ||||
var value = prop.value === null | ||||
? prop.value | ||||
: walk(prop.value, noExecute) | ||||
; | ||||
if (value === FAIL) return FAIL; | ||||
obj[prop.key.value || prop.key.name] = value; | ||||
} | ||||
return obj; | ||||
} | ||||
else if (node.type === 'BinaryExpression' || | ||||
node.type === 'LogicalExpression') { | ||||
var op = node.operator; | ||||
if (op === '&&') { | ||||
var l = walk(node.left); | ||||
if (l === FAIL) return FAIL; | ||||
if (!l) return l; | ||||
var r = walk(node.right); | ||||
if (r === FAIL) return FAIL; | ||||
return r; | ||||
} | ||||
else if (op === '||') { | ||||
var l = walk(node.left); | ||||
if (l === FAIL) return FAIL; | ||||
if (l) return l; | ||||
var r = walk(node.right); | ||||
if (r === FAIL) return FAIL; | ||||
return r; | ||||
} | ||||
var l = walk(node.left, noExecute); | ||||
if (l === FAIL) return FAIL; | ||||
var r = walk(node.right, noExecute); | ||||
if (r === FAIL) return FAIL; | ||||
if (op === '==') return l == r; | ||||
if (op === '===') return l === r; | ||||
if (op === '!=') return l != r; | ||||
if (op === '!==') return l !== r; | ||||
if (op === '+') return l + r; | ||||
if (op === '-') return l - r; | ||||
if (op === '*') return l * r; | ||||
if (op === '/') return l / r; | ||||
if (op === '%') return l % r; | ||||
if (op === '<') return l < r; | ||||
if (op === '<=') return l <= r; | ||||
if (op === '>') return l > r; | ||||
if (op === '>=') return l >= r; | ||||
if (op === '|') return l | r; | ||||
if (op === '&') return l & r; | ||||
if (op === '^') return l ^ r; | ||||
return FAIL; | ||||
} | ||||
else if (node.type === 'Identifier') { | ||||
if ({}.hasOwnProperty.call(vars, node.name)) { | ||||
return vars[node.name]; | ||||
} | ||||
else return FAIL; | ||||
} | ||||
else if (node.type === 'ThisExpression') { | ||||
if ({}.hasOwnProperty.call(vars, 'this')) { | ||||
return vars['this']; | ||||
} | ||||
else return FAIL; | ||||
} | ||||
else if (node.type === 'CallExpression') { | ||||
var callee = walk(node.callee, noExecute); | ||||
if (callee === FAIL) return FAIL; | ||||
if (typeof callee !== 'function') return FAIL; | ||||
var ctx = node.callee.object ? walk(node.callee.object, noExecute) : FAIL; | ||||
if (ctx === FAIL) ctx = null; | ||||
var args = []; | ||||
for (var i = 0, l = node.arguments.length; i < l; i++) { | ||||
var x = walk(node.arguments[i], noExecute); | ||||
if (x === FAIL) return FAIL; | ||||
args.push(x); | ||||
} | ||||
if (noExecute) { | ||||
return undefined; | ||||
} | ||||
return callee.apply(ctx, args); | ||||
} | ||||
else if (node.type === 'MemberExpression') { | ||||
var obj = walk(node.object, noExecute); | ||||
// do not allow access to methods on Function | ||||
if((obj === FAIL) || (typeof obj == 'function')){ | ||||
return FAIL; | ||||
} | ||||
if (node.property.type === 'Identifier' && !node.computed) { | ||||
if (isUnsafeProperty(node.property.name)) return FAIL; | ||||
return obj[node.property.name]; | ||||
} | ||||
var prop = walk(node.property, noExecute); | ||||
if (prop === null || prop === FAIL) return FAIL; | ||||
if (isUnsafeProperty(prop)) return FAIL; | ||||
return obj[prop]; | ||||
} | ||||
else if (node.type === 'ConditionalExpression') { | ||||
var val = walk(node.test, noExecute) | ||||
if (val === FAIL) return FAIL; | ||||
return val ? walk(node.consequent) : walk(node.alternate, noExecute) | ||||
} | ||||
else if (node.type === 'ExpressionStatement') { | ||||
var val = walk(node.expression, noExecute) | ||||
if (val === FAIL) return FAIL; | ||||
return val; | ||||
} | ||||
else if (node.type === 'ReturnStatement') { | ||||
return walk(node.argument, noExecute) | ||||
} | ||||
else if (node.type === 'FunctionExpression') { | ||||
var bodies = node.body.body; | ||||
// Create a "scope" for our arguments | ||||
var oldVars = {}; | ||||
Object.keys(vars).forEach(function(element){ | ||||
oldVars[element] = vars[element]; | ||||
}) | ||||
for(var i=0; i<node.params.length; i++){ | ||||
var key = node.params[i]; | ||||
if(key.type == 'Identifier'){ | ||||
vars[key.name] = null; | ||||
} | ||||
else return FAIL; | ||||
} | ||||
for(var i in bodies){ | ||||
if(walk(bodies[i], true) === FAIL){ | ||||
return FAIL; | ||||
} | ||||
} | ||||
// restore the vars and scope after we walk | ||||
vars = oldVars; | ||||
var keys = Object.keys(vars); | ||||
var vals = keys.map(function(key) { | ||||
return vars[key]; | ||||
}); | ||||
return Function(keys.join(', '), 'return ' + unparse(node)).apply(null, vals); | ||||
} | ||||
else if (node.type === 'TemplateLiteral') { | ||||
var str = ''; | ||||
for (var i = 0; i < node.expressions.length; i++) { | ||||
str += walk(node.quasis[i], noExecute); | ||||
str += walk(node.expressions[i], noExecute); | ||||
} | ||||
str += walk(node.quasis[i], noExecute); | ||||
return str; | ||||
} | ||||
else if (node.type === 'TaggedTemplateExpression') { | ||||
var tag = walk(node.tag, noExecute); | ||||
var quasi = node.quasi; | ||||
var strings = quasi.quasis.map(walk); | ||||
var values = quasi.expressions.map(walk); | ||||
return tag.apply(null, [strings].concat(values)); | ||||
} | ||||
else if (node.type === 'TemplateElement') { | ||||
return node.value.cooked; | ||||
} | ||||
else return FAIL; | ||||
})(ast); | ||||
return result === FAIL ? undefined : result; | ||||
}; | ||||
function isUnsafeProperty(name) { | ||||
return name === 'constructor' || name === '__proto__'; | ||||
} | ||||