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

fix($parse): fix CSP nested property evaluation, and issue that prevente... #5592

Closed
wants to merge 7 commits into from
24 changes: 16 additions & 8 deletions src/ng/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -894,16 +894,20 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];

if (pathVal == null) return key1 ? undefined : pathVal;
if (!key1) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key1];

if (pathVal == null) return key2 ? undefined : pathVal;
if (!key2) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key2];

if (pathVal == null) return key3 ? undefined : pathVal;
if (!key3) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key3];

if (pathVal == null) return key4 ? undefined : pathVal;
if (!key4) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key4];

return pathVal;
Expand All @@ -924,8 +928,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key1 ? undefined : pathVal;

if (!key1) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
Expand All @@ -936,8 +941,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key2 ? undefined : pathVal;

if (!key2) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
Expand All @@ -948,8 +954,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key3 ? undefined : pathVal;

if (!key3) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
Expand All @@ -960,8 +967,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
if (pathVal == null) return key4 ? undefined : pathVal;

if (!key4) return pathVal;
if (pathVal == null) return undefined;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
Expand Down
41 changes: 37 additions & 4 deletions test/ng/parseSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,17 @@ describe('parser', function() {

describe('csp: ' + cspEnabled + ", unwrapPromises: " + unwrapPromisesEnabled, function() {

beforeEach(function() {
// Needed for the $parse service to pick up the CSP setting at injection time.
window.document.securityPolicy = {isActive : cspEnabled};
});

beforeEach(module(function ($parseProvider) {
$parseProvider.unwrapPromises(unwrapPromisesEnabled);
}));

beforeEach(inject(function ($rootScope, $sniffer) {
beforeEach(inject(function ($rootScope) {
scope = $rootScope;
$sniffer.csp = cspEnabled;
}));

it('should parse expressions', function() {
Expand Down Expand Up @@ -344,6 +348,25 @@ describe('parser', function() {
expect(scope.$eval("a.b.c.d.e.f.g.h.i.j.k.l.m.n", scope)).toBe('nooo!');
});

forEach([2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 42, 99], function(pathLength) {
it('should resolve nested paths of length ' + pathLength, function() {
// Create a nested object {x2: {x3: {x4: ... {x[n]: 42} ... }}}.
var obj = 42;
for (var i = pathLength; i >= 2; i--) {
var newObj = {};
newObj['x' + i] = obj;
obj = newObj;
}
// Assign to x1 and build path 'x1.x2.x3. ... .x[n]' to access the final value.
scope.x1 = obj;
var path = 'x1';
for (var i = 2; i <= pathLength; i++) {
path += '.x' + i;
}
expect(scope.$eval(path)).toBe(42);
});
});

it('should be forgiving', function() {
scope.a = {b: 23};
expect(scope.$eval('b')).toBeUndefined();
Expand Down Expand Up @@ -1070,6 +1093,11 @@ describe('parser', function() {
var $log;
var PROMISE_WARNING_REGEXP = /\[\$parse\] Promise found in the expression `[^`]+`. Automatic unwrapping of promises in Angular expressions is deprecated\./;

beforeEach(function() {
// Needed for the $parse service to pick up the CSP setting at injection time.
window.document.securityPolicy = {isActive : cspEnabled};
});

beforeEach(module(function($parseProvider) {
$parseProvider.unwrapPromises(true);
}));
Expand Down Expand Up @@ -1148,9 +1176,14 @@ describe('parser', function() {
}));


beforeEach(inject(function($rootScope, $sniffer, $q) {
beforeEach(function() {
// Needed for the $parse service to pick up the CSP setting at injection time.
window.document.securityPolicy = {isActive : cspEnabled};
});


beforeEach(inject(function($rootScope, $q) {
scope = $rootScope;
$sniffer.csp = cspEnabled;

q = $q;
deferred = q.defer();
Expand Down