1+ /**
2+ * Provides classes for modelling property projection functions.
3+ *
4+ * Subclass `PropertyProjection` to refine the behavior of the analysis on existing property projections.
5+ * Subclass `CustomPropertyProjection` to introduce new kinds of property projections.
6+ */
7+
8+ import javascript
9+
10+ /**
11+ * A property projection call such as `_.get(o, 'a.b')`, which is equivalent to `o.a.b`.
12+ */
13+ abstract class CustomPropertyProjection extends DataFlow:: CallNode {
14+
15+ /**
16+ * Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
17+ */
18+ abstract DataFlow:: Node getObject ( ) ;
19+
20+ /**
21+ * Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
22+ */
23+ abstract DataFlow:: Node getASelector ( ) ;
24+
25+ /**
26+ * Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
27+ */
28+ abstract predicate isSingletonProjection ( ) ;
29+
30+ }
31+
32+ /**
33+ * A property projection call such as `_.get(o, 'a.b')`, which is equivalent to `o.a.b`.
34+ */
35+ class PropertyProjection extends DataFlow:: CallNode {
36+
37+ CustomPropertyProjection custom ;
38+
39+ PropertyProjection ( ) { this = custom }
40+
41+ /**
42+ * Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
43+ */
44+ DataFlow:: Node getObject ( ) { result = custom .getObject ( ) }
45+
46+ /**
47+ * Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
48+ */
49+ DataFlow:: Node getASelector ( ) { result = custom .getASelector ( ) }
50+
51+ /**
52+ * Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
53+ *
54+ * Examples:
55+ * - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`,
56+ * - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`,
57+ */
58+ predicate isSingletonProjection ( ) { custom .isSingletonProjection ( ) }
59+
60+ }
61+
62+ /**
63+ * A simple model of common property projection functions.
64+ */
65+ private class SimplePropertyProjection extends CustomPropertyProjection {
66+
67+ int objectIndex ;
68+ int selectorIndex ;
69+ boolean singleton ;
70+
71+ SimplePropertyProjection ( ) {
72+ exists ( DataFlow:: SourceNode callee |
73+ this = callee .getACall ( ) |
74+ singleton = false and (
75+ (
76+ callee = LodashUnderscore:: member ( "pick" ) and
77+ objectIndex = 0 and
78+ selectorIndex = [ 1 ..getNumArgument ( ) ]
79+ )
80+ or
81+ (
82+ callee = LodashUnderscore:: member ( "pickBy" ) and
83+ objectIndex = 0 and
84+ selectorIndex = 1
85+ )
86+ or
87+ exists ( string name |
88+ name = "pick" or
89+ name = "pickAll" or
90+ name = "pickBy" |
91+ callee = DataFlow:: moduleMember ( "ramda" , name ) and
92+ objectIndex = 1 and
93+ selectorIndex = 0
94+ )
95+ or
96+ (
97+ callee = DataFlow:: moduleMember ( "dotty" , "search" ) and
98+ objectIndex = 0 and
99+ selectorIndex = 1
100+ )
101+ )
102+ or
103+ singleton = true and (
104+ (
105+ callee = LodashUnderscore:: member ( "get" ) and
106+ objectIndex = 0 and
107+ selectorIndex = 1
108+ )
109+ or
110+ (
111+ callee = DataFlow:: moduleMember ( "ramda" , "path" ) and
112+ objectIndex = 1 and
113+ selectorIndex = 0
114+ )
115+ or
116+ (
117+ callee = DataFlow:: moduleMember ( "dottie" , "get" ) and
118+ objectIndex = 0 and
119+ selectorIndex = 1
120+ )
121+ or
122+ (
123+ callee = DataFlow:: moduleMember ( "dotty" , "get" ) and
124+ objectIndex = 0 and
125+ selectorIndex = 1
126+ )
127+ )
128+ )
129+ }
130+
131+ override DataFlow:: Node getObject ( ) { result = getArgument ( objectIndex ) }
132+
133+ override DataFlow:: Node getASelector ( ) { result = getArgument ( selectorIndex ) }
134+
135+ override predicate isSingletonProjection ( ) { singleton = true }
136+
137+ }
138+
139+ /**
140+ * A taint step for a property projection.
141+ */
142+ private class PropertyProjectionTaintStep extends TaintTracking:: AdditionalTaintStep {
143+
144+ PropertyProjection projection ;
145+
146+ PropertyProjectionTaintStep ( ) {
147+ projection = this
148+ }
149+
150+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
151+ // reading from a tainted object yields a tainted result
152+ this = succ and
153+ pred = projection .getObject ( )
154+ }
155+ }
0 commit comments