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
Closed

Conversation

dozingcat
Copy link
Contributor

...d its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes #5591

…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes <a href="https://github.com/angular/angular.js/issues/5591">#5591</a>
@@ -894,15 +894,19 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];

if (!key1) return pathVal;
if (pathVal == null) return key1 ? undefined : pathVal;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look at this line (897)... Now look at the one below it...

What we're doing here is this: if the path key is not present, and there is another path key after it, we always want to return undefined.

If there are problems with the existing algorithm, we'll need to fix it, but to undo that would be essentially reverting a desirable fix. Lets find a better solution for the csp issue.

I'm fairly sure that this changeset would have broken tests if the test suite for the changeset fixing #5442 / #2249 didn't get shrunk down, with a few test cases removed

Even if it doesn't break tests, we can make this more concise and not breaking the logic mentioned above by combining it into the second if statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's a separate issue. As I understand it given scope.a={b: null}, $eval('a.b') should return null and $eval('a.b.c') should return undefined. This changeset doesn't modify that behavior. It addresses the case where cspSafeGetterFn is called with an expression of 'a.b.c', so the key3 and key4 parameters are undefined. pathVal then becomes undefined after evaluating pathVal[key3], unless we check for the key being undefined first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the very least, it does duplicate functionality, and this could be made much more concise.

An 8 byte change || !key1 would have the same impact, and absolutely avoid breaking logic

Good catch on the csp test fixes, though

…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes <a href="https://github.com/angular/angular.js/issues/5591">#5591</a>
@dozingcat
Copy link
Contributor Author

Moved key checks to existing if statements as suggested.

…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes <a href="https://github.com/angular/angular.js/issues/5591">#5591</a>
@@ -894,16 +894,16 @@ 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 (pathVal == null || !key1) return key1 ? undefined : pathVal;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, on the other hand.. Maybe something more like

if (!key1) return pathVal;
else if (pathVal == null) return undefined;

might be cleaner / easier to read, and possibly save a comparison. Although it still technically violates the style guide.

I contradict myself a lot, you'll get used to it ;) I just want to avoid duplicating code, and try to keep it readable and straight forward

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that better too, the conditions are basically independent. If I drop the "else" I don't think it violates the style guide, since it references Google's JS style guide, which "follow[s] the C++ formatting rules in spirit", which says "Short conditional statements may be written on one line if this enhances readability." (Yay indirection). And there are several other occurrences of "if (...) return ..." in the Angular source.

Of course the most readable and concise implementation would be to iterate over the array of path components directly, but playing with jsperf showed about a 35% performance hit, which is presumably why it's unrolled into keyN parameters.

…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes <a href="https://github.com/angular/angular.js/issues/5591">#5591</a>
…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes <a href="https://github.com/angular/angular.js/issues/5591">#5591</a>
@@ -1237,6 +1243,9 @@ function $ParseProvider() {
return cache[exp];
}

// The csp option has to be set here because in tests the $sniffer service sets its csp
// property after $get has executed.
$parseOptions.csp = $sniffer.csp;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not sure about this though, it seems weird to read this every time $parse is called. If it's the best we can do then that's one thing, but is there not a better solution?

@ghost ghost assigned IgorMinar Jan 2, 2014
…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Fixes <a href="https://github.com/angular/angular.js/issues/5591">#5591</a>
@dozingcat
Copy link
Contributor Author

How about this? Setting document.securityPolicy.isActive makes the $sniffer service see that CSP is enabled at injection time (via the csp() function in Angular.js). It's a bit ugly to mess with a global object like that, but maybe in a test it's ok. The "proper" solution might be to have a CSP detection service which could be mocked in tests, but that seems like overkill.

Incidentally the promise logging tests were never enabling CSP mode; that's now fixed.

@caitp
Copy link
Contributor

caitp commented Jan 2, 2014

Messing with the global variable seems a bit worrisome --- But let's see what other folks say about it... Probably won't hear much this week, but next week is a possibility

IgorMinar pushed a commit to IgorMinar/angular.js that referenced this pull request Jan 3, 2014
…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading
the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Closes angular#5591
Closes angular#5592
@IgorMinar
Copy link
Contributor

I reviewed it and this is a really nice PR. Thanks for all the work @dozingcat

I squashed the changes, added an afterEach to restore the global state and I'm testing this all on the CI right now.

I'll merge it and sync it into google today

@IgorMinar IgorMinar closed this in 3b1a4fe Jan 3, 2014
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this pull request Jan 27, 2014
…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading
the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Closes angular#5591
Closes angular#5592
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this pull request Jan 27, 2014
…nted its tests from failing

cspSafeGetterFn incorrectly returned undefined if any of its key parameters were undefined. This
wasn't caught by the $parse unit tests because of a timing problem where $ParseProvider was reading
the CSP flag before the tests manually set it, so the CSP property evaluation tests never ran. Add
test that verifies evaluation of nested properties of multiple lengths.

Closes angular#5591
Closes angular#5592
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Nested property expressions evaluate incorrectly in CSP mode
3 participants