From 06b085107226afb13141314717644425eab79009 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 12 Feb 2019 11:02:29 +0000 Subject: [PATCH 01/14] JS: Add Firebase model --- javascript/ql/src/javascript.qll | 1 + .../src/semmle/javascript/StandardLibrary.qll | 2 +- .../semmle/javascript/frameworks/Firebase.qll | 160 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Firebase.qll diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 9f497f83b640..d8c4396a394a 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -69,6 +69,7 @@ import semmle.javascript.frameworks.CryptoLibraries import semmle.javascript.frameworks.DigitalOcean import semmle.javascript.frameworks.Electron import semmle.javascript.frameworks.Files +import semmle.javascript.frameworks.Firebase import semmle.javascript.frameworks.jQuery import semmle.javascript.frameworks.LodashUnderscore import semmle.javascript.frameworks.Logging diff --git a/javascript/ql/src/semmle/javascript/StandardLibrary.qll b/javascript/ql/src/semmle/javascript/StandardLibrary.qll index 68ad116f7f91..6afc5e82b863 100644 --- a/javascript/ql/src/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/src/semmle/javascript/StandardLibrary.qll @@ -189,7 +189,7 @@ private class PromiseFlowStep extends DataFlow::AdditionalFlowStep { /** * Holds if taint propagates from `pred` to `succ` through promises. */ -private predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) { +predicate promiseTaintStep(DataFlow::Node pred, DataFlow::Node succ) { // from `x` to `new Promise((res, rej) => res(x))` pred = succ.(PromiseDefinition).getResolveParameter().getACall().getArgument(0) or diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll new file mode 100644 index 000000000000..ee6c2182ef7b --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -0,0 +1,160 @@ +import javascript + +module Firebase { + + /** Gets a reference to the firebase API object. */ + private DataFlow::SourceNode firebase(DataFlow::TypeTracker t) { + result = DataFlow::moduleImport("firebase/app") and t.start() + or + result = DataFlow::globalVarRef("firebase") and t.start() + or + exists (DataFlow::TypeTracker t2 | + result = firebase(t2).track(t2, t) + ) + } + + /** Gets a reference to the firebase API object. */ + DataFlow::SourceNode firebase() { + result = firebase(_) + } + + /** Gets a reference to a firebase app created with `initializeApp`. */ + private DataFlow::SourceNode initApp(DataFlow::TypeTracker t) { + result = firebase().getAMethodCall("initializeApp") and t.start() + or + exists (DataFlow::TypeTracker t2 | + result = initApp(t2).track(t2, t) + ) + } + + /** + * Gets a reference to a firebase app, either the `firebase` object or an + * app created explicitly with `initializeApp()`. + */ + DataFlow::SourceNode app() { + result = firebase(_) or result = initApp(_) + } + + /** Gets a reference to a firebase database object, such as `firebase.database()`. */ + private DataFlow::SourceNode database(DataFlow::TypeTracker t) { + result = app().getAMethodCall("database") and t.start() + or + exists (DataFlow::TypeTracker t2 | + result = database(t2).track(t2, t) + ) + } + + /** Gets a reference to a firebase database object, such as `firebase.database()`. */ + DataFlow::SourceNode database() { + result = database(_) + } + + /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ + DataFlow::SourceNode ref(DataFlow::TypeTracker t) { + t.start() and + ( + exists (string name | result = database().getAMethodCall(name) | + name = "ref" or + name = "refFromURL" + ) + or + exists (string name | result = ref(_).getAMethodCall(name) | + name = "push" or + name = "child" + ) + or + exists (string name | result = ref(_).getAPropertyRead(name) | + name = "parent" or + name = "root" + ) + or + result = snapshot().getAPropertyRead("ref") + ) + or + exists (DataFlow::TypeTracker t2 | + result = ref(t2).track(t2, t) + ) + } + + /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ + DataFlow::SourceNode ref() { + result = ref(_) + } + + /** + * A call of form `ref.on(...)` or `ref.once(...)`. + */ + class RefListenCall extends DataFlow::MethodCallNode { + RefListenCall() { + this = ref().getAMethodCall() and + (getMethodName() = "on" or getMethodName() = "once") + } + + DataFlow::Node getCallbackNode() { + result = getArgument(1) + } + } + + /** + * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. + */ + DataFlow::SourceNode snapshotCallback(DataFlow::TypeTracker t) { + t.start() and + result = any(RefListenCall call).getCallbackNode().getALocalSource() + or + exists (DataFlow::TypeTracker t2 | + result = snapshotCallback(t2).backtrack(t2, t) + ) + } + + /** + * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. + */ + DataFlow::SourceNode snapshotCallback() { + result = snapshotCallback(_) + } + + /** + * Gets a node that refers to a `DataSnapshot` value, such as `x` in + * `firebase.database().ref().on('value', x => {...})`. + */ + DataFlow::SourceNode snapshot(DataFlow::TypeTracker t) { + t.start() and + ( + result = snapshotCallback().(DataFlow::FunctionNode).getParameter(0) + or + result instanceof RefListenCall // returns promise + or + result = snapshot(_).getAMethodCall("child") + or + result = snapshot(_).getAMethodCall("forEach").getCallback(0).getParameter(0) + ) + or + promiseTaintStep(snapshot(t), result) + or + exists (DataFlow::TypeTracker t2 | + result = ref(t2).track(t2, t) + ) + } + + /** + * Gets a node that refers to a `DataSnapshot` value, such as `x` in + * `firebase.database().ref().on('value', x => {...})`. + */ + DataFlow::SourceNode snapshot() { + result = snapshot(_) + } + + class FirebaseVal extends RemoteFlowSource { + FirebaseVal() { + exists (string name | this = snapshot().getAMethodCall(name) | + name = "val" or + name = "exportVal" + ) + } + + override string getSourceType() { + result = "Firebase database" + } + } +} From e0c06cb5188971336e4832170422f051cd5adba6 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 28 Jan 2019 16:42:10 +0000 Subject: [PATCH 02/14] JS: handle Query methods --- .../semmle/javascript/frameworks/Firebase.qll | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index ee6c2182ef7b..e35a454d1143 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -80,13 +80,37 @@ module Firebase { DataFlow::SourceNode ref() { result = ref(_) } + + /** Gets a node that refers to a `Query` or `Reference` object. */ + DataFlow::SourceNode query(DataFlow::TypeTracker t) { + t.start() and + ( + result = ref(t) // a Reference can be used as a Query + or + exists (string name | result = query(_).getAMethodCall(name) | + name = "endAt" or + name = "limitTo" + any(string s) or + name = "orderBy" + any(string s) or + name = "startAt" + ) + ) + or + exists (DataFlow::TypeTracker t2 | + result = query(t2).track(t2, t) + ) + } + + /** Gets a node that refers to a `Query` or `Reference` object. */ + DataFlow::SourceNode query() { + result = query(_) + } /** - * A call of form `ref.on(...)` or `ref.once(...)`. + * A call of form `query.on(...)` or `query.once(...)`. */ - class RefListenCall extends DataFlow::MethodCallNode { - RefListenCall() { - this = ref().getAMethodCall() and + class QueryListenCall extends DataFlow::MethodCallNode { + QueryListenCall() { + this = query().getAMethodCall() and (getMethodName() = "on" or getMethodName() = "once") } @@ -100,7 +124,7 @@ module Firebase { */ DataFlow::SourceNode snapshotCallback(DataFlow::TypeTracker t) { t.start() and - result = any(RefListenCall call).getCallbackNode().getALocalSource() + result = any(QueryListenCall call).getCallbackNode().getALocalSource() or exists (DataFlow::TypeTracker t2 | result = snapshotCallback(t2).backtrack(t2, t) @@ -115,15 +139,14 @@ module Firebase { } /** - * Gets a node that refers to a `DataSnapshot` value, such as `x` in - * `firebase.database().ref().on('value', x => {...})`. + * Gets a node that refers to a `DataSnapshot` value or a promise thereof. */ DataFlow::SourceNode snapshot(DataFlow::TypeTracker t) { t.start() and ( result = snapshotCallback().(DataFlow::FunctionNode).getParameter(0) or - result instanceof RefListenCall // returns promise + result instanceof QueryListenCall // returns promise or result = snapshot(_).getAMethodCall("child") or From f554f859aae0bcbca33eb316bd1e753a30c385cb Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 29 Jan 2019 16:31:41 +0000 Subject: [PATCH 03/14] JS: handle 'firebase-admin' package --- .../ql/src/semmle/javascript/frameworks/Firebase.qll | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index e35a454d1143..96e49d47ef48 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -4,9 +4,14 @@ module Firebase { /** Gets a reference to the firebase API object. */ private DataFlow::SourceNode firebase(DataFlow::TypeTracker t) { - result = DataFlow::moduleImport("firebase/app") and t.start() - or - result = DataFlow::globalVarRef("firebase") and t.start() + t.start() and + ( + result = DataFlow::moduleImport("firebase/app") + or + result = DataFlow::moduleImport("firebase-admin") + or + result = DataFlow::globalVarRef("firebase") + ) or exists (DataFlow::TypeTracker t2 | result = firebase(t2).track(t2, t) From 49a746b87ac80c972a239c9057121b4bf57cebf8 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 5 Feb 2019 17:33:14 +0000 Subject: [PATCH 04/14] JS: handle Reference.transaction() --- .../semmle/javascript/frameworks/Firebase.qll | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 96e49d47ef48..b3c5b7d96327 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -172,6 +172,25 @@ module Firebase { DataFlow::SourceNode snapshot() { result = snapshot(_) } + + /** + * Gets a node that is passed as the callback to a `Reference.transaction` call. + */ + DataFlow::SourceNode transactionCallback(DataFlow::TypeTracker t) { + t.start() and + result = ref().getAMethodCall("transaction").getArgument(0).getALocalSource() + or + exists (DataFlow::TypeTracker t2 | + result = transactionCallback(t2).backtrack(t2, t) + ) + } + + /** + * Gets a node that is passed as the callback to a `Reference.transaction` call. + */ + DataFlow::SourceNode transactionCallback() { + result = transactionCallback(_) + } class FirebaseVal extends RemoteFlowSource { FirebaseVal() { @@ -179,6 +198,8 @@ module Firebase { name = "val" or name = "exportVal" ) + or + this = transactionCallback().(DataFlow::FunctionNode).getParameter(0) } override string getSourceType() { From 0401b26b48e6ac2740a17a79274ff35c00c60637 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 31 Jan 2019 13:01:54 +0000 Subject: [PATCH 05/14] JS: handle CloudFunctions --- .../semmle/javascript/frameworks/Firebase.qll | 262 ++++++++++++------ 1 file changed, 170 insertions(+), 92 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index b3c5b7d96327..8fc657d61013 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -1,7 +1,9 @@ +/** + * Provides classes and predicates for reasoning about code using the Firebase API. + */ import javascript module Firebase { - /** Gets a reference to the firebase API object. */ private DataFlow::SourceNode firebase(DataFlow::TypeTracker t) { t.start() and @@ -18,7 +20,7 @@ module Firebase { ) } - /** Gets a reference to the firebase API object. */ + /** Gets a reference to the `firebase/app` or `firebase-admin` API object. */ DataFlow::SourceNode firebase() { result = firebase(_) } @@ -31,7 +33,7 @@ module Firebase { result = initApp(t2).track(t2, t) ) } - + /** * Gets a reference to a firebase app, either the `firebase` object or an * app created explicitly with `initializeApp()`. @@ -40,96 +42,188 @@ module Firebase { result = firebase(_) or result = initApp(_) } - /** Gets a reference to a firebase database object, such as `firebase.database()`. */ - private DataFlow::SourceNode database(DataFlow::TypeTracker t) { - result = app().getAMethodCall("database") and t.start() - or - exists (DataFlow::TypeTracker t2 | - result = database(t2).track(t2, t) - ) - } - - /** Gets a reference to a firebase database object, such as `firebase.database()`. */ - DataFlow::SourceNode database() { - result = database(_) - } - - /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ - DataFlow::SourceNode ref(DataFlow::TypeTracker t) { - t.start() and - ( - exists (string name | result = database().getAMethodCall(name) | - name = "ref" or - name = "refFromURL" + module Database { + + /** Gets a reference to a firebase database object, such as `firebase.database()`. */ + private DataFlow::SourceNode database(DataFlow::TypeTracker t) { + result = app().getAMethodCall("database") and t.start() + or + exists (DataFlow::TypeTracker t2 | + result = database(t2).track(t2, t) + ) + } + + /** Gets a reference to a firebase database object, such as `firebase.database()`. */ + DataFlow::SourceNode database() { + result = database(_) + } + + /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ + DataFlow::SourceNode ref(DataFlow::TypeTracker t) { + t.start() and + ( + exists (string name | result = database().getAMethodCall(name) | + name = "ref" or + name = "refFromURL" + ) + or + exists (string name | result = ref(_).getAMethodCall(name) | + name = "push" or + name = "child" + ) + or + exists (string name | result = ref(_).getAPropertyRead(name) | + name = "parent" or + name = "root" + ) + or + result = snapshot().getAPropertyRead("ref") ) or - exists (string name | result = ref(_).getAMethodCall(name) | - name = "push" or - name = "child" + exists (DataFlow::TypeTracker t2 | + result = ref(t2).track(t2, t) + ) + } + + /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ + DataFlow::SourceNode ref() { + result = ref(_) + } + + /** Gets a node that refers to a `Query` or `Reference` object. */ + DataFlow::SourceNode query(DataFlow::TypeTracker t) { + t.start() and + ( + result = ref(t) // a Reference can be used as a Query + or + exists (string name | result = query(_).getAMethodCall(name) | + name = "endAt" or + name = "limitTo" + any(string s) or + name = "orderBy" + any(string s) or + name = "startAt" + ) ) or - exists (string name | result = ref(_).getAPropertyRead(name) | - name = "parent" or - name = "root" + exists (DataFlow::TypeTracker t2 | + result = query(t2).track(t2, t) ) + } + + /** Gets a node that refers to a `Query` or `Reference` object. */ + DataFlow::SourceNode query() { + result = query(_) + } + + /** + * A call of form `query.on(...)` or `query.once(...)`. + */ + class QueryListenCall extends DataFlow::MethodCallNode { + QueryListenCall() { + this = query().getAMethodCall() and + (getMethodName() = "on" or getMethodName() = "once") + } + + DataFlow::Node getCallbackNode() { + result = getArgument(1) + } + } + + /** + * Gets a node that is passed as the callback to a `Reference.transaction` call. + */ + DataFlow::SourceNode transactionCallback(DataFlow::TypeTracker t) { + t.start() and + result = ref().getAMethodCall("transaction").getArgument(0).getALocalSource() or - result = snapshot().getAPropertyRead("ref") - ) - or - exists (DataFlow::TypeTracker t2 | - result = ref(t2).track(t2, t) - ) + exists (DataFlow::TypeTracker t2 | + result = transactionCallback(t2).backtrack(t2, t) + ) + } + + /** + * Gets a node that is passed as the callback to a `Reference.transaction` call. + */ + DataFlow::SourceNode transactionCallback() { + result = transactionCallback(_) + } } - /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ - DataFlow::SourceNode ref() { - result = ref(_) - } + /** + * Provides predicates for reasoning about the the Firebase Cloud Functions API, + * sometimes referred to just as just "Firebase Functions". + */ + module CloudFunctions { + /** Gets a reference to the Cloud Functions namespace. */ + DataFlow::SourceNode namespace(DataFlow::TypeTracker t) { + t.start() and + result = DataFlow::moduleImport("firebase-functions") + or + exists (DataFlow::TypeTracker t2 | + result = namespace(t2).track(t2, t) + ) + } + + /** Gets a reference to the Cloud Functions namespace. */ + DataFlow::SourceNode namespace() { + result = namespace(_) + } - /** Gets a node that refers to a `Query` or `Reference` object. */ - DataFlow::SourceNode query(DataFlow::TypeTracker t) { - t.start() and - ( - result = ref(t) // a Reference can be used as a Query + /** Gets a reference to a Cloud Functions database object. */ + DataFlow::SourceNode database(DataFlow::TypeTracker t) { + t.start() and + result = namespace().getAPropertyRead("database") or - exists (string name | result = query(_).getAMethodCall(name) | - name = "endAt" or - name = "limitTo" + any(string s) or - name = "orderBy" + any(string s) or - name = "startAt" + exists (DataFlow::TypeTracker t2 | + result = database(t2).track(t2, t) ) - ) - or - exists (DataFlow::TypeTracker t2 | - result = query(t2).track(t2, t) - ) - } + } - /** Gets a node that refers to a `Query` or `Reference` object. */ - DataFlow::SourceNode query() { - result = query(_) - } - - /** - * A call of form `query.on(...)` or `query.once(...)`. - */ - class QueryListenCall extends DataFlow::MethodCallNode { - QueryListenCall() { - this = query().getAMethodCall() and - (getMethodName() = "on" or getMethodName() = "once") + /** Gets a reference to a Cloud Functions database object. */ + DataFlow::SourceNode database() { + result = database(_) + } + + /** Gets a dataflow node holding a `RefBuilder` object. */ + DataFlow::SourceNode refBuilder(DataFlow::TypeTracker t) { + t.start() and + result = database().getAMethodCall("ref") + or + exists (DataFlow::TypeTracker t2 | + result = refBuilder(t2).track(t2, t) + ) } - DataFlow::Node getCallbackNode() { - result = getArgument(1) + /** Gets a dataflow node holding a `RefBuilder` object. */ + DataFlow::SourceNode ref() { + result = refBuilder(_) } - } + /** Gets a call that registers a listener on a `RefBuilder`, such as `ref.onCreate(...)`. */ + class RefBuilderListenCall extends DataFlow::MethodCallNode { + RefBuilderListenCall() { + this = ref().getAMethodCall() and + getMethodName() = "on" + any(string s) + } + + /** + * Gets the dataflow node holding the listener callback. + */ + DataFlow::Node getCallbackNode() { + result = getArgument(0) + } + } + } + /** * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. */ DataFlow::SourceNode snapshotCallback(DataFlow::TypeTracker t) { t.start() and - result = any(QueryListenCall call).getCallbackNode().getALocalSource() + ( + result = any(Database::QueryListenCall call).getCallbackNode().getALocalSource() + or + result = any(CloudFunctions::RefBuilderListenCall call).getCallbackNode().getALocalSource() + ) or exists (DataFlow::TypeTracker t2 | result = snapshotCallback(t2).backtrack(t2, t) @@ -151,7 +245,7 @@ module Firebase { ( result = snapshotCallback().(DataFlow::FunctionNode).getParameter(0) or - result instanceof QueryListenCall // returns promise + result instanceof Database::QueryListenCall // returns promise or result = snapshot(_).getAMethodCall("child") or @@ -161,7 +255,7 @@ module Firebase { promiseTaintStep(snapshot(t), result) or exists (DataFlow::TypeTracker t2 | - result = ref(t2).track(t2, t) + result = snapshot(t2).track(t2, t) ) } @@ -174,24 +268,8 @@ module Firebase { } /** - * Gets a node that is passed as the callback to a `Reference.transaction` call. + * A reference to a value obtained from a Firebase database. */ - DataFlow::SourceNode transactionCallback(DataFlow::TypeTracker t) { - t.start() and - result = ref().getAMethodCall("transaction").getArgument(0).getALocalSource() - or - exists (DataFlow::TypeTracker t2 | - result = transactionCallback(t2).backtrack(t2, t) - ) - } - - /** - * Gets a node that is passed as the callback to a `Reference.transaction` call. - */ - DataFlow::SourceNode transactionCallback() { - result = transactionCallback(_) - } - class FirebaseVal extends RemoteFlowSource { FirebaseVal() { exists (string name | this = snapshot().getAMethodCall(name) | @@ -199,7 +277,7 @@ module Firebase { name = "exportVal" ) or - this = transactionCallback().(DataFlow::FunctionNode).getParameter(0) + this = Database::transactionCallback().(DataFlow::FunctionNode).getParameter(0) } override string getSourceType() { From ad592d7cd1a28fe978c1b9a52190ac8808348a20 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 31 Jan 2019 15:58:27 +0000 Subject: [PATCH 06/14] JS: handle .after and .before --- .../ql/src/semmle/javascript/frameworks/Firebase.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 8fc657d61013..e6976dd3b2e9 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -238,7 +238,8 @@ module Firebase { } /** - * Gets a node that refers to a `DataSnapshot` value or a promise thereof. + * Gets a node that refers to a `DataSnapshot` value or a promise or `Change` + * object containing `DataSnapshot`s. */ DataFlow::SourceNode snapshot(DataFlow::TypeTracker t) { t.start() and @@ -250,6 +251,11 @@ module Firebase { result = snapshot(_).getAMethodCall("child") or result = snapshot(_).getAMethodCall("forEach").getCallback(0).getParameter(0) + or + exists (string prop | result = snapshot(_).getAPropertyRead(prop) | + prop = "before" or // only defined on Change objects + prop = "after" + ) ) or promiseTaintStep(snapshot(t), result) From 42c0efd54931335d73654e78f156bf75a8cdb51c Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 5 Feb 2019 18:27:29 +0000 Subject: [PATCH 07/14] JS: add test --- .../frameworks/Firebase/FirebaseRef.expected | 17 +++++ .../frameworks/Firebase/FirebaseRef.ql | 3 + .../Firebase/FirebaseSnapshot.expected | 10 +++ .../frameworks/Firebase/FirebaseSnapshot.ql | 3 + .../frameworks/Firebase/FirebaseVal.expected | 6 ++ .../frameworks/Firebase/FirebaseVal.ql | 4 ++ .../library-tests/frameworks/Firebase/tst.js | 70 +++++++++++++++++++ 7 files changed, 113 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.ql create mode 100644 javascript/ql/test/library-tests/frameworks/Firebase/tst.js diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.expected b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.expected new file mode 100644 index 000000000000..2bcf33333c49 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.expected @@ -0,0 +1,17 @@ +| tst.js:5:1:5:22 | fb.data ... ef('x') | +| tst.js:7:3:7:7 | x.ref | +| tst.js:7:3:7:14 | x.ref.parent | +| tst.js:10:1:10:25 | admin.d ... ef('x') | +| tst.js:12:3:12:7 | x.ref | +| tst.js:12:3:12:14 | x.ref.parent | +| tst.js:17:3:17:7 | x.ref | +| tst.js:17:3:17:14 | x.ref.parent | +| tst.js:23:3:23:7 | x.ref | +| tst.js:23:3:23:14 | x.ref.parent | +| tst.js:32:12:32:42 | this.fi ... .ref(x) | +| tst.js:46:12:46:42 | this.fi ... .ref(x) | +| tst.js:50:12:50:25 | this.getRef(x) | +| tst.js:50:12:50:34 | this.ge ... hild(x) | +| tst.js:54:5:54:37 | this.fi ... ef('x') | +| tst.js:58:1:58:61 | new Fir ... /news') | +| tst.js:59:1:59:38 | new Fir ... /news') | diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.ql b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.ql new file mode 100644 index 000000000000..49e3890869eb --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseRef.ql @@ -0,0 +1,3 @@ +import javascript + +select Firebase::Database::ref() diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.expected b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.expected new file mode 100644 index 000000000000..a2d57b9f5ef8 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.expected @@ -0,0 +1,10 @@ +| tst.js:5:1:8:2 | fb.data ... ent;\\n}) | +| tst.js:5:38:5:38 | x | +| tst.js:10:1:13:2 | admin.d ... ent;\\n}) | +| tst.js:10:41:10:41 | x | +| tst.js:15:38:15:38 | x | +| tst.js:20:38:20:38 | x | +| tst.js:21:3:21:10 | x.before | +| tst.js:22:3:22:9 | x.after | +| tst.js:50:12:50:48 | this.ge ... value') | +| tst.js:60:1:60:39 | new Fir ... em('x') | diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.ql b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.ql new file mode 100644 index 000000000000..6b20bd3944e4 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseSnapshot.ql @@ -0,0 +1,3 @@ +import javascript + +select Firebase::snapshot() diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.expected b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.expected new file mode 100644 index 000000000000..1d22bbfed8b6 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.expected @@ -0,0 +1,6 @@ +| tst.js:6:3:6:9 | x.val() | +| tst.js:11:3:11:9 | x.val() | +| tst.js:16:3:16:9 | x.val() | +| tst.js:21:3:21:16 | x.before.val() | +| tst.js:22:3:22:15 | x.after.val() | +| tst.js:61:36:61:36 | x | diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.ql b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.ql new file mode 100644 index 000000000000..cf541fd3ca0c --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/FirebaseVal.ql @@ -0,0 +1,4 @@ +import javascript + +from Firebase::FirebaseVal val +select val diff --git a/javascript/ql/test/library-tests/frameworks/Firebase/tst.js b/javascript/ql/test/library-tests/frameworks/Firebase/tst.js new file mode 100644 index 000000000000..b0b7d025b539 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Firebase/tst.js @@ -0,0 +1,70 @@ +import * as fb from 'firebase/app'; +import * as admin from 'firebase-admin'; +import * as functions from 'firebase-functions'; + +fb.database().ref('x').once('value', x => { + x.val(); + x.ref.parent; +}); + +admin.database().ref('x').once('value', x => { + x.val(); + x.ref.parent; +}); + +functions.database.ref('x').onCreate(x => { + x.val(); + x.ref.parent; +}); + +functions.database.ref('x').onUpdate(x => { + x.before.val(); + x.after.val(); + x.ref.parent; +}); + +class FirebaseWrapper { + constructor(firebase) { + this.firebase = firebase; + } + + getRef(x) { + return this.firebase.database().ref(x); + } +} + +class FirebaseWrapper2 { + constructor() { + this.init(); + } + + init() { + this.firebase = fb.initializeApp(); + } + + getRef(x) { + return this.firebase.database().ref(x); + } + + getNewsItem(x) { + return this.getRef(x).child(x).once('value'); + } + + adjustValue(fn) { + this.firebase.database().ref('x').transaction(fn); + } +} + +new FirebaseWrapper(firebase.initializeApp()).getRef('/news'); +new FirebaseWrapper2().getRef('/news'); +new FirebaseWrapper2().getNewsItem('x'); +new FirebaseWrapper2().adjustValue(x => x + 1); + +class Box { + constructor(x) { + this.x = x; + } +} +let box1 = new Box(fb.database()); +let box2 = new Box(whatever()); +box2.x.ref(); // not a firebase ref From 99cc09df8cde6acce07804df057146766e5fa0a2 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 18 Mar 2019 16:41:36 +0000 Subject: [PATCH 08/14] JS: use TypeBackTracker where appropriate --- .../ql/src/semmle/javascript/frameworks/Firebase.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index e6976dd3b2e9..20251a5246e3 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -131,11 +131,11 @@ module Firebase { /** * Gets a node that is passed as the callback to a `Reference.transaction` call. */ - DataFlow::SourceNode transactionCallback(DataFlow::TypeTracker t) { + DataFlow::SourceNode transactionCallback(DataFlow::TypeBackTracker t) { t.start() and result = ref().getAMethodCall("transaction").getArgument(0).getALocalSource() or - exists (DataFlow::TypeTracker t2 | + exists (DataFlow::TypeBackTracker t2 | result = transactionCallback(t2).backtrack(t2, t) ) } @@ -217,7 +217,7 @@ module Firebase { /** * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. */ - DataFlow::SourceNode snapshotCallback(DataFlow::TypeTracker t) { + DataFlow::SourceNode snapshotCallback(DataFlow::TypeBackTracker t) { t.start() and ( result = any(Database::QueryListenCall call).getCallbackNode().getALocalSource() @@ -225,7 +225,7 @@ module Firebase { result = any(CloudFunctions::RefBuilderListenCall call).getCallbackNode().getALocalSource() ) or - exists (DataFlow::TypeTracker t2 | + exists (DataFlow::TypeBackTracker t2 | result = snapshotCallback(t2).backtrack(t2, t) ) } From c0b58f6b095243ad157fae5f5079a6569fed9c69 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Mar 2019 14:40:11 +0000 Subject: [PATCH 09/14] JS: Capitalize Firebase in comments --- .../ql/src/semmle/javascript/frameworks/Firebase.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 20251a5246e3..78d8503f80dd 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -4,7 +4,7 @@ import javascript module Firebase { - /** Gets a reference to the firebase API object. */ + /** Gets a reference to the Firebase API object. */ private DataFlow::SourceNode firebase(DataFlow::TypeTracker t) { t.start() and ( @@ -25,7 +25,7 @@ module Firebase { result = firebase(_) } - /** Gets a reference to a firebase app created with `initializeApp`. */ + /** Gets a reference to a Firebase app created with `initializeApp`. */ private DataFlow::SourceNode initApp(DataFlow::TypeTracker t) { result = firebase().getAMethodCall("initializeApp") and t.start() or @@ -35,7 +35,7 @@ module Firebase { } /** - * Gets a reference to a firebase app, either the `firebase` object or an + * Gets a reference to a Firebase app, either the `firebase` object or an * app created explicitly with `initializeApp()`. */ DataFlow::SourceNode app() { @@ -44,7 +44,7 @@ module Firebase { module Database { - /** Gets a reference to a firebase database object, such as `firebase.database()`. */ + /** Gets a reference to a Firebase database object, such as `firebase.database()`. */ private DataFlow::SourceNode database(DataFlow::TypeTracker t) { result = app().getAMethodCall("database") and t.start() or @@ -53,7 +53,7 @@ module Firebase { ) } - /** Gets a reference to a firebase database object, such as `firebase.database()`. */ + /** Gets a reference to a Firebase database object, such as `firebase.database()`. */ DataFlow::SourceNode database() { result = database(_) } From 28a776a82bbca1556e705be35126ee6346693f55 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Mar 2019 14:40:48 +0000 Subject: [PATCH 10/14] JS: dataflow -> data flow --- javascript/ql/src/semmle/javascript/frameworks/Firebase.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 78d8503f80dd..89f70a3b7ed5 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -183,7 +183,7 @@ module Firebase { result = database(_) } - /** Gets a dataflow node holding a `RefBuilder` object. */ + /** Gets a data flow node holding a `RefBuilder` object. */ DataFlow::SourceNode refBuilder(DataFlow::TypeTracker t) { t.start() and result = database().getAMethodCall("ref") @@ -193,7 +193,7 @@ module Firebase { ) } - /** Gets a dataflow node holding a `RefBuilder` object. */ + /** Gets a data flow node holding a `RefBuilder` object. */ DataFlow::SourceNode ref() { result = refBuilder(_) } @@ -206,7 +206,7 @@ module Firebase { } /** - * Gets the dataflow node holding the listener callback. + * Gets the data flow node holding the listener callback. */ DataFlow::Node getCallbackNode() { result = getArgument(0) From 9bbdf84e5d4cd1eb43ed6c445c96582e5a4fc33d Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Mar 2019 14:42:01 +0000 Subject: [PATCH 11/14] JS: missing qldoc --- javascript/ql/src/semmle/javascript/frameworks/Firebase.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 89f70a3b7ed5..f610c9b5496c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -123,6 +123,9 @@ module Firebase { (getMethodName() = "on" or getMethodName() = "once") } + /** + * Gets the argument in which the callback is passed. + */ DataFlow::Node getCallbackNode() { result = getArgument(1) } From 7bfad8c3601eb630b2bbf64f76f61cc67cbccaa7 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Mar 2019 14:42:32 +0000 Subject: [PATCH 12/14] JS: trailing whitespace --- .../semmle/javascript/frameworks/Firebase.qll | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index f610c9b5496c..9c4bef2129f7 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -33,7 +33,7 @@ module Firebase { result = initApp(t2).track(t2, t) ) } - + /** * Gets a reference to a Firebase app, either the `firebase` object or an * app created explicitly with `initializeApp()`. @@ -43,7 +43,7 @@ module Firebase { } module Database { - + /** Gets a reference to a Firebase database object, such as `firebase.database()`. */ private DataFlow::SourceNode database(DataFlow::TypeTracker t) { result = app().getAMethodCall("database") and t.start() @@ -52,12 +52,12 @@ module Firebase { result = database(t2).track(t2, t) ) } - + /** Gets a reference to a Firebase database object, such as `firebase.database()`. */ DataFlow::SourceNode database() { result = database(_) } - + /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and @@ -84,12 +84,12 @@ module Firebase { result = ref(t2).track(t2, t) ) } - + /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ DataFlow::SourceNode ref() { result = ref(_) } - + /** Gets a node that refers to a `Query` or `Reference` object. */ DataFlow::SourceNode query(DataFlow::TypeTracker t) { t.start() and @@ -108,12 +108,12 @@ module Firebase { result = query(t2).track(t2, t) ) } - + /** Gets a node that refers to a `Query` or `Reference` object. */ DataFlow::SourceNode query() { result = query(_) } - + /** * A call of form `query.on(...)` or `query.once(...)`. */ @@ -122,7 +122,7 @@ module Firebase { this = query().getAMethodCall() and (getMethodName() = "on" or getMethodName() = "once") } - + /** * Gets the argument in which the callback is passed. */ @@ -130,7 +130,7 @@ module Firebase { result = getArgument(1) } } - + /** * Gets a node that is passed as the callback to a `Reference.transaction` call. */ @@ -142,7 +142,7 @@ module Firebase { result = transactionCallback(t2).backtrack(t2, t) ) } - + /** * Gets a node that is passed as the callback to a `Reference.transaction` call. */ @@ -165,7 +165,7 @@ module Firebase { result = namespace(t2).track(t2, t) ) } - + /** Gets a reference to the Cloud Functions namespace. */ DataFlow::SourceNode namespace() { result = namespace(_) @@ -185,7 +185,7 @@ module Firebase { DataFlow::SourceNode database() { result = database(_) } - + /** Gets a data flow node holding a `RefBuilder` object. */ DataFlow::SourceNode refBuilder(DataFlow::TypeTracker t) { t.start() and @@ -207,7 +207,7 @@ module Firebase { this = ref().getAMethodCall() and getMethodName() = "on" + any(string s) } - + /** * Gets the data flow node holding the listener callback. */ @@ -216,7 +216,7 @@ module Firebase { } } } - + /** * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. */ From 208bcd438bc0c4d8d47ea8f476d5ec453407fafe Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 19 Mar 2019 14:43:32 +0000 Subject: [PATCH 13/14] JS: Make type-tracking predicates private --- .../semmle/javascript/frameworks/Firebase.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 9c4bef2129f7..71182cf24f91 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -59,7 +59,7 @@ module Firebase { } /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ - DataFlow::SourceNode ref(DataFlow::TypeTracker t) { + private DataFlow::SourceNode ref(DataFlow::TypeTracker t) { t.start() and ( exists (string name | result = database().getAMethodCall(name) | @@ -91,7 +91,7 @@ module Firebase { } /** Gets a node that refers to a `Query` or `Reference` object. */ - DataFlow::SourceNode query(DataFlow::TypeTracker t) { + private DataFlow::SourceNode query(DataFlow::TypeTracker t) { t.start() and ( result = ref(t) // a Reference can be used as a Query @@ -134,7 +134,7 @@ module Firebase { /** * Gets a node that is passed as the callback to a `Reference.transaction` call. */ - DataFlow::SourceNode transactionCallback(DataFlow::TypeBackTracker t) { + private DataFlow::SourceNode transactionCallback(DataFlow::TypeBackTracker t) { t.start() and result = ref().getAMethodCall("transaction").getArgument(0).getALocalSource() or @@ -157,7 +157,7 @@ module Firebase { */ module CloudFunctions { /** Gets a reference to the Cloud Functions namespace. */ - DataFlow::SourceNode namespace(DataFlow::TypeTracker t) { + private DataFlow::SourceNode namespace(DataFlow::TypeTracker t) { t.start() and result = DataFlow::moduleImport("firebase-functions") or @@ -172,7 +172,7 @@ module Firebase { } /** Gets a reference to a Cloud Functions database object. */ - DataFlow::SourceNode database(DataFlow::TypeTracker t) { + private DataFlow::SourceNode database(DataFlow::TypeTracker t) { t.start() and result = namespace().getAPropertyRead("database") or @@ -187,7 +187,7 @@ module Firebase { } /** Gets a data flow node holding a `RefBuilder` object. */ - DataFlow::SourceNode refBuilder(DataFlow::TypeTracker t) { + private DataFlow::SourceNode refBuilder(DataFlow::TypeTracker t) { t.start() and result = database().getAMethodCall("ref") or @@ -220,7 +220,7 @@ module Firebase { /** * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. */ - DataFlow::SourceNode snapshotCallback(DataFlow::TypeBackTracker t) { + private DataFlow::SourceNode snapshotCallback(DataFlow::TypeBackTracker t) { t.start() and ( result = any(Database::QueryListenCall call).getCallbackNode().getALocalSource() @@ -244,7 +244,7 @@ module Firebase { * Gets a node that refers to a `DataSnapshot` value or a promise or `Change` * object containing `DataSnapshot`s. */ - DataFlow::SourceNode snapshot(DataFlow::TypeTracker t) { + private DataFlow::SourceNode snapshot(DataFlow::TypeTracker t) { t.start() and ( result = snapshotCallback().(DataFlow::FunctionNode).getParameter(0) From 0eb9231cb1f8b73fccc482f96384ce0ca8a5e742 Mon Sep 17 00:00:00 2001 From: Asger F Date: Wed, 27 Mar 2019 13:25:01 +0000 Subject: [PATCH 14/14] JS: Make use of TypeTracker::end() --- .../semmle/javascript/frameworks/Firebase.qll | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll index 71182cf24f91..a343be69f084 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Firebase.qll @@ -22,7 +22,7 @@ module Firebase { /** Gets a reference to the `firebase/app` or `firebase-admin` API object. */ DataFlow::SourceNode firebase() { - result = firebase(_) + result = firebase(DataFlow::TypeTracker::end()) } /** Gets a reference to a Firebase app created with `initializeApp`. */ @@ -39,7 +39,7 @@ module Firebase { * app created explicitly with `initializeApp()`. */ DataFlow::SourceNode app() { - result = firebase(_) or result = initApp(_) + result = firebase(DataFlow::TypeTracker::end()) or result = initApp(DataFlow::TypeTracker::end()) } module Database { @@ -55,7 +55,7 @@ module Firebase { /** Gets a reference to a Firebase database object, such as `firebase.database()`. */ DataFlow::SourceNode database() { - result = database(_) + result = database(DataFlow::TypeTracker::end()) } /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ @@ -67,12 +67,12 @@ module Firebase { name = "refFromURL" ) or - exists (string name | result = ref(_).getAMethodCall(name) | + exists (string name | result = ref().getAMethodCall(name) | name = "push" or name = "child" ) or - exists (string name | result = ref(_).getAPropertyRead(name) | + exists (string name | result = ref().getAPropertyRead(name) | name = "parent" or name = "root" ) @@ -87,7 +87,7 @@ module Firebase { /** Gets a node that refers to a `Reference` object, such as `firebase.database().ref()`. */ DataFlow::SourceNode ref() { - result = ref(_) + result = ref(DataFlow::TypeTracker::end()) } /** Gets a node that refers to a `Query` or `Reference` object. */ @@ -96,7 +96,7 @@ module Firebase { ( result = ref(t) // a Reference can be used as a Query or - exists (string name | result = query(_).getAMethodCall(name) | + exists (string name | result = query().getAMethodCall(name) | name = "endAt" or name = "limitTo" + any(string s) or name = "orderBy" + any(string s) or @@ -111,7 +111,7 @@ module Firebase { /** Gets a node that refers to a `Query` or `Reference` object. */ DataFlow::SourceNode query() { - result = query(_) + result = query(DataFlow::TypeTracker::end()) } /** @@ -147,7 +147,7 @@ module Firebase { * Gets a node that is passed as the callback to a `Reference.transaction` call. */ DataFlow::SourceNode transactionCallback() { - result = transactionCallback(_) + result = transactionCallback(DataFlow::TypeBackTracker::end()) } } @@ -168,7 +168,7 @@ module Firebase { /** Gets a reference to the Cloud Functions namespace. */ DataFlow::SourceNode namespace() { - result = namespace(_) + result = namespace(DataFlow::TypeTracker::end()) } /** Gets a reference to a Cloud Functions database object. */ @@ -183,7 +183,7 @@ module Firebase { /** Gets a reference to a Cloud Functions database object. */ DataFlow::SourceNode database() { - result = database(_) + result = database(DataFlow::TypeTracker::end()) } /** Gets a data flow node holding a `RefBuilder` object. */ @@ -198,7 +198,7 @@ module Firebase { /** Gets a data flow node holding a `RefBuilder` object. */ DataFlow::SourceNode ref() { - result = refBuilder(_) + result = refBuilder(DataFlow::TypeTracker::end()) } /** Gets a call that registers a listener on a `RefBuilder`, such as `ref.onCreate(...)`. */ @@ -237,7 +237,7 @@ module Firebase { * Gets a value that will be invoked with a `DataSnapshot` value as its first parameter. */ DataFlow::SourceNode snapshotCallback() { - result = snapshotCallback(_) + result = snapshotCallback(DataFlow::TypeBackTracker::end()) } /** @@ -251,11 +251,11 @@ module Firebase { or result instanceof Database::QueryListenCall // returns promise or - result = snapshot(_).getAMethodCall("child") + result = snapshot().getAMethodCall("child") or - result = snapshot(_).getAMethodCall("forEach").getCallback(0).getParameter(0) + result = snapshot().getAMethodCall("forEach").getCallback(0).getParameter(0) or - exists (string prop | result = snapshot(_).getAPropertyRead(prop) | + exists (string prop | result = snapshot().getAPropertyRead(prop) | prop = "before" or // only defined on Change objects prop = "after" ) @@ -273,7 +273,7 @@ module Firebase { * `firebase.database().ref().on('value', x => {...})`. */ DataFlow::SourceNode snapshot() { - result = snapshot(_) + result = snapshot(DataFlow::TypeTracker::end()) } /**