add support for the promise polyfill

This commit is contained in:
Erik Krogh Kristensen
2021-06-18 16:06:39 +02:00
parent 967ccfef0c
commit f095e190a9
4 changed files with 34 additions and 7 deletions

View File

@@ -1,4 +1,5 @@
lgtm,codescanning
* The security queries now track flow through various `Promise` polyfills.
Affected packages are
[kew](https://npmjs.com/package/kew)
[kew](https://npmjs.com/package/kew),
[promise](https://npmjs.com/package/promise)

View File

@@ -58,6 +58,22 @@ private predicate hasHandler(DataFlow::InvokeNode promise, string m, int i) {
exists(promise.getAMethodCall(m).getCallback(i))
}
/**
* Gets a reference to the `Promise` object.
* Either from the standard library, a polyfill import, or a polyfill that defines the global `Promise` variable.
*/
private DataFlow::SourceNode getAPromiseObject() {
// Standard library, or polyfills like [es6-shim](https://npmjs.org/package/es6-shim).
result = DataFlow::globalVarRef("Promise")
or
// polyfills from the [`promise`](https://npmjs.org/package/promise) library.
result =
DataFlow::moduleImport([
"promise", "promise/domains", "promise/setimmediate", "promise/lib/es6-extensions",
"promise/domains/es6-extensions", "promise/setimmediate/es6-extensions"
])
}
/**
* A call that looks like a Promise.
*
@@ -75,7 +91,7 @@ class PromiseCandidate extends DataFlow::InvokeNode {
* A promise object created by the standard ECMAScript 2015 `Promise` constructor.
*/
private class ES2015PromiseDefinition extends PromiseDefinition, DataFlow::NewNode {
ES2015PromiseDefinition() { this = DataFlow::globalVarRef("Promise").getAnInstantiation() }
ES2015PromiseDefinition() { this = getAPromiseObject().getAnInstantiation() }
override DataFlow::FunctionNode getExecutor() { result = getCallback(0) }
}
@@ -109,9 +125,7 @@ abstract class PromiseAllCreation extends PromiseCreationCall {
* A resolved promise created by the standard ECMAScript 2015 `Promise.resolve` function.
*/
class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition {
ResolvedES2015PromiseDefinition() {
this = DataFlow::globalVarRef("Promise").getAMemberCall("resolve")
}
ResolvedES2015PromiseDefinition() { this = getAPromiseObject().getAMemberCall("resolve") }
override DataFlow::Node getValue() { result = getArgument(0) }
}
@@ -121,8 +135,7 @@ class ResolvedES2015PromiseDefinition extends ResolvedPromiseDefinition {
*/
class AggregateES2015PromiseDefinition extends PromiseCreationCall {
AggregateES2015PromiseDefinition() {
exists(string m | m = "all" or m = "race" or m = "any" |
this = DataFlow::globalVarRef("Promise").getAMemberCall(m)
this = getAPromiseObject().getAMemberCall(m)
)
}

View File

@@ -92,3 +92,10 @@
var sink = val;
});
})();
(function() {
var PromiseA = require('promise');
var PromiseB = require('promise/domains');
PromiseA.resolve(source);
PromiseB.resolve(source);
})();

View File

@@ -36,6 +36,8 @@ test_ResolvedPromiseDefinition
| promises.js:62:19:62:41 | Promise ... source) | promises.js:62:35:62:40 | source |
| promises.js:71:5:71:27 | Promise ... source) | promises.js:71:21:71:26 | source |
| promises.js:79:19:79:41 | Promise ... source) | promises.js:79:35:79:40 | source |
| promises.js:99:3:99:26 | Promise ... source) | promises.js:99:20:99:25 | source |
| promises.js:100:3:100:26 | Promise ... source) | promises.js:100:20:100:25 | source |
test_PromiseDefinition_getARejectHandler
| flow.js:26:2:26:49 | new Pro ... ource)) | flow.js:26:69:26:80 | y => sink(y) |
| flow.js:32:2:32:49 | new Pro ... ource)) | flow.js:32:57:32:68 | x => sink(x) |
@@ -407,3 +409,7 @@ typetrack
| promises.js:75:27:75:29 | val | promises.js:75:5:75:20 | resolver.promise | load $PromiseResolveField$ |
| promises.js:88:17:90:4 | Q.Promi ... );\\n }) | promises.js:89:15:89:20 | source | copy $PromiseResolveField$ |
| promises.js:88:17:90:4 | Q.Promi ... );\\n }) | promises.js:89:15:89:20 | source | store $PromiseResolveField$ |
| promises.js:99:3:99:26 | Promise ... source) | promises.js:99:20:99:25 | source | copy $PromiseResolveField$ |
| promises.js:99:3:99:26 | Promise ... source) | promises.js:99:20:99:25 | source | store $PromiseResolveField$ |
| promises.js:100:3:100:26 | Promise ... source) | promises.js:100:20:100:25 | source | copy $PromiseResolveField$ |
| promises.js:100:3:100:26 | Promise ... source) | promises.js:100:20:100:25 | source | store $PromiseResolveField$ |