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

Commit a7f3761

Browse files
lgalfasopetebacondarwin
authored andcommitted
fix($parse): block assigning to fields of a constructor
Throw when assigning to a field of a constructor. Closes #12860
1 parent 5a98e80 commit a7f3761

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/ng/parse.js

+22
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ function ensureSafeFunction(obj, fullExpression) {
112112
}
113113
}
114114

115+
function ensureSafeAssignContext(obj, fullExpression) {
116+
if (obj) {
117+
if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
118+
obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
119+
throw $parseMinErr('isecaf',
120+
'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
121+
}
122+
}
123+
}
124+
115125
var OPERATORS = createMap();
116126
forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
117127
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
@@ -827,6 +837,7 @@ ASTCompiler.prototype = {
827837
'ensureSafeObject',
828838
'ensureSafeFunction',
829839
'getStringValue',
840+
'ensureSafeAssignContext',
830841
'ifDefined',
831842
'plus',
832843
'text',
@@ -836,6 +847,7 @@ ASTCompiler.prototype = {
836847
ensureSafeObject,
837848
ensureSafeFunction,
838849
getStringValue,
850+
ensureSafeAssignContext,
839851
ifDefined,
840852
plusFn,
841853
expression);
@@ -1063,6 +1075,7 @@ ASTCompiler.prototype = {
10631075
self.if_(self.notNull(left.context), function() {
10641076
self.recurse(ast.right, right);
10651077
self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
1078+
self.addEnsureSafeAssignContext(left.context);
10661079
expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
10671080
self.assign(intoId, expression);
10681081
recursionFn(intoId || expression);
@@ -1188,6 +1201,10 @@ ASTCompiler.prototype = {
11881201
this.current().body.push(this.ensureSafeFunction(item), ';');
11891202
},
11901203

1204+
addEnsureSafeAssignContext: function(item) {
1205+
this.current().body.push(this.ensureSafeAssignContext(item), ';');
1206+
},
1207+
11911208
ensureSafeObject: function(item) {
11921209
return 'ensureSafeObject(' + item + ',text)';
11931210
},
@@ -1204,6 +1221,10 @@ ASTCompiler.prototype = {
12041221
this.assign(item, 'getStringValue(' + item + ',text)');
12051222
},
12061223

1224+
ensureSafeAssignContext: function(item) {
1225+
return 'ensureSafeAssignContext(' + item + ',text)';
1226+
},
1227+
12071228
lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
12081229
var self = this;
12091230
return function() {
@@ -1381,6 +1402,7 @@ ASTInterpreter.prototype = {
13811402
var lhs = left(scope, locals, assign, inputs);
13821403
var rhs = right(scope, locals, assign, inputs);
13831404
ensureSafeObject(lhs.value, self.expression);
1405+
ensureSafeAssignContext(lhs.context);
13841406
lhs.context[lhs.name] = rhs;
13851407
return context ? {value: rhs} : rhs;
13861408
};

test/ng/parseSpec.js

+29
Original file line numberDiff line numberDiff line change
@@ -2712,6 +2712,35 @@ describe('parser', function() {
27122712
'');
27132713
}).toThrow();
27142714
});
2715+
2716+
it('should prevent assigning in the context of a constructor', function() {
2717+
expect(function() {
2718+
scope.$eval("''.constructor.join");
2719+
}).not.toThrow();
2720+
expect(function() {
2721+
scope.$eval("''.constructor.join = ''.constructor.join");
2722+
}).toThrow();
2723+
expect(function() {
2724+
scope.$eval("''.constructor[0] = ''");
2725+
}).toThrow();
2726+
expect(function() {
2727+
scope.$eval("(0).constructor[0] = ''");
2728+
}).toThrow();
2729+
expect(function() {
2730+
scope.$eval("{}.constructor[0] = ''");
2731+
}).toThrow();
2732+
// foo.constructor is the object constructor.
2733+
expect(function() {
2734+
scope.$eval("foo.constructor[0] = ''", {foo: {}});
2735+
}).toThrow();
2736+
// foo.constructor is not a constructor.
2737+
expect(function() {
2738+
scope.$eval("foo.constructor[0] = ''", {foo: {constructor: ''}});
2739+
}).not.toThrow();
2740+
expect(function() {
2741+
scope.$eval("objConstructor = {}.constructor; objConstructor.join = ''");
2742+
}).toThrow();
2743+
});
27152744
});
27162745

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

0 commit comments

Comments
 (0)