Permalink
Browse files

fix($parse): prevent invocation of Function's bind, call and apply

BREAKING CHANGE:
You can no longer invoke .bind, .call or .apply on a function in angular expressions.
This is to disallow changing the behaviour of existing functions
in an unforseen fashion.
  • Loading branch information...
1 parent db713a1 commit 77ada4c82d6b8fc6d977c26f3cdb48c2f5fbe5a5 @rodyhaddad rodyhaddad committed with IgorMinar Jun 26, 2014
Showing with 75 additions and 0 deletions.
  1. +17 −0 docs/content/error/$parse/isecff.ngdoc
  2. +8 −0 src/ng/parse.js
  3. +50 −0 test/ng/parseSpec.js
@@ -0,0 +1,17 @@
+@ngdoc error
+@name $parse:isecff
+@fullName Referencing 'call', 'apply' and 'bind' Disallowed
+@description
+
+Occurs when an expression attempts to invoke Function's 'call', 'apply' or 'bind'.
+
+Angular bans the invocation of 'call', 'apply' and 'bind' from within expressions
+since access is a known way to modify the behaviour of existing functions.
+
+To resolve this error, avoid using these methods in expressions.
+
+Example expression that would result in this error:
+
+```
+<div>{{user.sendInfo.call({}, true)}}</div>
+```
View
@@ -62,12 +62,20 @@ function ensureSafeObject(obj, fullExpression) {
return obj;
}
+var CALL = Function.prototype.call;
+var APPLY = Function.prototype.apply;
+var BIND = Function.prototype.bind;
+
function ensureSafeFunction(obj, fullExpression) {
if (obj) {
if (obj.constructor === obj) {
throw $parseMinErr('isecfn',
'Referencing Function in Angular expressions is disallowed! Expression: {0}',
fullExpression);
+ } else if (obj === CALL || obj === APPLY || obj === BIND) {
+ throw $parseMinErr('isecff',
+ 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
+ fullExpression);
}
}
}
View
@@ -695,6 +695,56 @@ describe('parser', function() {
});
});
+ describe('Function prototype functions', function () {
+ it('should NOT allow invocation to Function.call', function() {
+ scope.fn = Function.prototype.call;
+
+ expect(function() {
+ scope.$eval('$eval.call()')
+ }).toThrowMinErr(
+ '$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
+ 'Expression: $eval.call()');
+
+ expect(function() {
+ scope.$eval('fn()')
+ }).toThrowMinErr(
+ '$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
+ 'Expression: fn()');
+ });
+
+ it('should NOT allow invocation to Function.apply', function() {
+ scope.apply = Function.prototype.apply;
+
+ expect(function() {
+ scope.$eval('$eval.apply()')
+ }).toThrowMinErr(
+ '$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
+ 'Expression: $eval.apply()');
+
+ expect(function() {
+ scope.$eval('apply()')
+ }).toThrowMinErr(
+ '$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
+ 'Expression: apply()');
+ });
+
+ it('should NOT allow invocation to Function.bind', function() {
+ scope.bind = Function.prototype.bind;
+
+ expect(function() {
+ scope.$eval('$eval.bind()')
+ }).toThrowMinErr(
+ '$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
+ 'Expression: $eval.bind()');
+
+ expect(function() {
+ scope.$eval('bind()')
+ }).toThrowMinErr(
+ '$parse', 'isecff', 'Referencing call, apply or bind in Angular expressions is disallowed! ' +
+ 'Expression: bind()');
+ });
+ });
+
describe('Object constructor', function() {
it('should NOT allow access to Object constructor that has been aliased', function() {

0 comments on commit 77ada4c

Please sign in to comment.