Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit ed8be3c

Browse files
committed
fix($parse): block assigning to fields of a constructor
Throw when assigning to a field of a constructor.
1 parent 9e6a9b9 commit ed8be3c

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

src/ng/parse.js

+22
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ function ensureSafeFunction(obj, fullExpression) {
102102
}
103103
}
104104

105+
function ensureSafeAssignContext(obj, fullExpression) {
106+
if (obj) {
107+
if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
108+
obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
109+
throw $parseMinErr('isecaf',
110+
'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
111+
}
112+
}
113+
}
114+
105115
var OPERATORS = createMap();
106116
forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
107117
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
@@ -816,6 +826,7 @@ ASTCompiler.prototype = {
816826
'ensureSafeMemberName',
817827
'ensureSafeObject',
818828
'ensureSafeFunction',
829+
'ensureSafeAssignContext',
819830
'ifDefined',
820831
'plus',
821832
'text',
@@ -824,6 +835,7 @@ ASTCompiler.prototype = {
824835
ensureSafeMemberName,
825836
ensureSafeObject,
826837
ensureSafeFunction,
838+
ensureSafeAssignContext,
827839
ifDefined,
828840
plusFn,
829841
expression);
@@ -1050,6 +1062,7 @@ ASTCompiler.prototype = {
10501062
self.if_(self.notNull(left.context), function() {
10511063
self.recurse(ast.right, right);
10521064
self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
1065+
self.addEnsureSafeAssignContext(left.context);
10531066
expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
10541067
self.assign(intoId, expression);
10551068
recursionFn(intoId || expression);
@@ -1175,6 +1188,10 @@ ASTCompiler.prototype = {
11751188
this.current().body.push(this.ensureSafeFunction(item), ';');
11761189
},
11771190

1191+
addEnsureSafeAssignContext: function(item) {
1192+
this.current().body.push(this.ensureSafeAssignContext(item), ';');
1193+
},
1194+
11781195
ensureSafeObject: function(item) {
11791196
return 'ensureSafeObject(' + item + ',text)';
11801197
},
@@ -1187,6 +1204,10 @@ ASTCompiler.prototype = {
11871204
return 'ensureSafeFunction(' + item + ',text)';
11881205
},
11891206

1207+
ensureSafeAssignContext: function(item) {
1208+
return 'ensureSafeAssignContext(' + item + ',text)';
1209+
},
1210+
11901211
lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
11911212
var self = this;
11921213
return function() {
@@ -1364,6 +1385,7 @@ ASTInterpreter.prototype = {
13641385
var lhs = left(scope, locals, assign, inputs);
13651386
var rhs = right(scope, locals, assign, inputs);
13661387
ensureSafeObject(lhs.value, self.expression);
1388+
ensureSafeAssignContext(lhs.context);
13671389
lhs.context[lhs.name] = rhs;
13681390
return context ? {value: rhs} : rhs;
13691391
};

test/ng/parseSpec.js

+26
Original file line numberDiff line numberDiff line change
@@ -2703,6 +2703,32 @@ describe('parser', function() {
27032703
'');
27042704
}).toThrow();
27052705
});
2706+
2707+
it('should prevent assigning in the context of a constructor', function() {
2708+
expect(function() {
2709+
scope.$eval("''.constructor.join");
2710+
}).not.toThrow();
2711+
expect(function() {
2712+
scope.$eval("''.constructor.join = ''.constructor.join");
2713+
}).toThrow();
2714+
expect(function() {
2715+
scope.$eval("''.constructor[0] = ''");
2716+
}).toThrow();
2717+
expect(function() {
2718+
scope.$eval("(0).constructor[0] = ''");
2719+
}).toThrow();
2720+
expect(function() {
2721+
scope.$eval("{}.constructor[0] = ''");
2722+
}).toThrow();
2723+
// foo.constructor is the object constructor.
2724+
expect(function() {
2725+
scope.$eval("foo.constructor[0] = ''", {foo: {}});
2726+
}).toThrow();
2727+
// foo.constructor is not a constructor.
2728+
expect(function() {
2729+
scope.$eval("foo.constructor[0] = ''", {foo: {constructor: ''}});
2730+
}).not.toThrow();
2731+
});
27062732
});
27072733

27082734
it('should call the function from the received instance and not from a new one', function() {

0 commit comments

Comments
 (0)