@@ -6,7 +6,17 @@ import javascript
66
77module NoSQL {
88 /** An expression that is interpreted as a NoSQL query. */
9- abstract class Query extends Expr { }
9+ abstract class Query extends Expr {
10+ /** Gets an expression that is interpreted as a code operator in this query. */
11+ DataFlow:: Node getACodeOperator ( ) { none ( ) }
12+ }
13+ }
14+
15+ /**
16+ * Gets the value of a `$where` property of an object that flows to `n`.
17+ */
18+ private DataFlow:: Node getADollarWherePropertyValue ( DataFlow:: Node n ) {
19+ result = n .getALocalSource ( ) .getAPropertyWrite ( "$where" ) .getRhs ( )
1020}
1121
1222/**
@@ -190,6 +200,10 @@ private module MongoDB {
190200 */
191201 class Query extends NoSQL:: Query {
192202 Query ( ) { this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( ) }
203+
204+ override DataFlow:: Node getACodeOperator ( ) {
205+ result = getADollarWherePropertyValue ( this .flow ( ) )
206+ }
193207 }
194208}
195209
@@ -678,6 +692,10 @@ private module Mongoose {
678692 */
679693 class MongoDBQueryPart extends NoSQL:: Query {
680694 MongoDBQueryPart ( ) { any ( InvokeNode call ) .interpretsArgumentAsQuery ( this .flow ( ) ) }
695+
696+ override DataFlow:: Node getACodeOperator ( ) {
697+ result = getADollarWherePropertyValue ( this .flow ( ) )
698+ }
681699 }
682700
683701 /**
@@ -713,3 +731,116 @@ private module Mongoose {
713731 }
714732 }
715733}
734+
735+ /**
736+ * Provides classes modeling the Minimongo library.
737+ */
738+ private module Minimongo {
739+ /**
740+ * Gets an expression that may refer to a Minimongo database.
741+ */
742+ private DataFlow:: SourceNode getADb ( DataFlow:: TypeTracker t ) {
743+ t .start ( ) and
744+ // new (require('minimongo')[DBKINDNAME])()
745+ result = DataFlow:: moduleImport ( "minimongo" ) .getAPropertyRead ( ) .getAnInvocation ( )
746+ or
747+ exists ( DataFlow:: TypeTracker t2 | result = getADb ( t2 ) .track ( t2 , t ) )
748+ }
749+
750+ /** Gets a data flow node referring to a Minimongo collection. */
751+ private DataFlow:: SourceNode getACollection ( DataFlow:: TypeTracker t ) {
752+ t .start ( ) and
753+ // db[COLLECTIONNAME]
754+ result = getADb ( DataFlow:: TypeTracker:: end ( ) ) .getAPropertyRead ( )
755+ or
756+ exists ( DataFlow:: TypeTracker t2 | result = getACollection ( t2 ) .track ( t2 , t ) )
757+ }
758+
759+ /**
760+ * Provides signatures for the Collection methods.
761+ */
762+ module CollectionMethodSignatures {
763+ /**
764+ * Holds if Collection method `name` interprets parameter `n` as a query.
765+ */
766+ predicate interpretsArgumentAsQuery ( string m , int queryArgIdx ) {
767+ // implements most of the MongoDB interface
768+ MongoDB:: CollectionMethodSignatures:: interpretsArgumentAsQuery ( m , queryArgIdx )
769+ }
770+ }
771+
772+ /** A call to a Minimongo query method. */
773+ private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
774+ int queryArgIdx ;
775+
776+ QueryCall ( ) {
777+ exists ( string m | this = getACollection ( DataFlow:: TypeTracker:: end ( ) ) .getAMethodCall ( m ) |
778+ CollectionMethodSignatures:: interpretsArgumentAsQuery ( m , queryArgIdx )
779+ )
780+ }
781+
782+ override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( queryArgIdx ) }
783+ }
784+
785+ /**
786+ * An expression that is interpreted as a Minimongo query.
787+ */
788+ class Query extends NoSQL:: Query {
789+ Query ( ) { this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( ) }
790+
791+ override DataFlow:: Node getACodeOperator ( ) {
792+ result = getADollarWherePropertyValue ( this .flow ( ) )
793+ }
794+ }
795+ }
796+
797+ /**
798+ * Provides classes modeling the MarsDB library.
799+ */
800+ private module MarsDB {
801+ /**
802+ * Gets an expression that may refer to a MarsDB database.
803+ */
804+ private DataFlow:: SourceNode getADb ( DataFlow:: TypeTracker t ) {
805+ t .start ( ) and
806+ // Collection = require('marsdb')
807+ result = DataFlow:: moduleImport ( "marsdb" )
808+ or
809+ exists ( DataFlow:: TypeTracker t2 | result = getADb ( t2 ) .track ( t2 , t ) )
810+ }
811+
812+ /** Gets a data flow node referring to a MarsDB collection. */
813+ private DataFlow:: SourceNode getACollection ( DataFlow:: TypeTracker t ) {
814+ t .start ( ) and
815+ // new Collection(...)
816+ result =
817+ getADb ( DataFlow:: TypeTracker:: end ( ) ) .getAPropertyRead ( "Collection" ) .getAnInstantiation ( )
818+ or
819+ exists ( DataFlow:: TypeTracker t2 | result = getACollection ( t2 ) .track ( t2 , t ) )
820+ }
821+
822+ /** A call to a MarsDB query method. */
823+ private class QueryCall extends DatabaseAccess , DataFlow:: MethodCallNode {
824+ int queryArgIdx ;
825+
826+ QueryCall ( ) {
827+ exists ( string m | this = getACollection ( DataFlow:: TypeTracker:: end ( ) ) .getAMethodCall ( m ) |
828+ // implements parts of the Minimongo interface
829+ Minimongo:: CollectionMethodSignatures:: interpretsArgumentAsQuery ( m , queryArgIdx )
830+ )
831+ }
832+
833+ override DataFlow:: Node getAQueryArgument ( ) { result = getArgument ( queryArgIdx ) }
834+ }
835+
836+ /**
837+ * An expression that is interpreted as a MarsDB query.
838+ */
839+ class Query extends NoSQL:: Query {
840+ Query ( ) { this = any ( QueryCall qc ) .getAQueryArgument ( ) .asExpr ( ) }
841+
842+ override DataFlow:: Node getACodeOperator ( ) {
843+ result = getADollarWherePropertyValue ( this .flow ( ) )
844+ }
845+ }
846+ }
0 commit comments