Skip to content

Commit d4e39a2

Browse files
authored
Merge pull request #1667 from xiemaisi/js/more-ranges
Approved by esben-semmle
2 parents 251d441 + 3daa974 commit d4e39a2

File tree

7 files changed

+115
-91
lines changed

7 files changed

+115
-91
lines changed

javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,58 +7,66 @@
77

88
import javascript
99

10-
/**
11-
* A call that performs a request to a URL.
12-
*
13-
* Example: An HTTP POST request is a client request that sends some
14-
* `data` to a `url`, where both the headers and the body of the request
15-
* contribute to the `data`.
16-
*/
17-
abstract class CustomClientRequest extends DataFlow::InvokeNode {
18-
/**
19-
* Gets the URL of the request.
20-
*/
21-
abstract DataFlow::Node getUrl();
22-
23-
/**
24-
* Gets the host of the request.
25-
*/
26-
abstract DataFlow::Node getHost();
27-
28-
/**
29-
* Gets a node that contributes to the data-part this request.
30-
*/
31-
abstract DataFlow::Node getADataNode();
32-
}
33-
3410
/**
3511
* A call that performs a request to a URL.
3612
*
3713
* Example: An HTTP POST request is client request that sends some
3814
* `data` to a `url`, where both the headers and the body of the request
3915
* contribute to the `data`.
16+
*
17+
* Extend this class to work with client request APIs for which there is already a model.
18+
* To model additional APIs, extend `ClientRequest::Range` and implement its abstract member
19+
* predicates.
4020
*/
4121
class ClientRequest extends DataFlow::InvokeNode {
42-
CustomClientRequest custom;
22+
ClientRequest::Range self;
4323

44-
ClientRequest() { this = custom }
24+
ClientRequest() { this = self }
4525

4626
/**
4727
* Gets the URL of the request.
4828
*/
49-
DataFlow::Node getUrl() { result = custom.getUrl() }
29+
DataFlow::Node getUrl() { result = self.getUrl() }
5030

5131
/**
5232
* Gets the host of the request.
5333
*/
54-
DataFlow::Node getHost() { result = custom.getHost() }
34+
DataFlow::Node getHost() { result = self.getHost() }
5535

5636
/**
5737
* Gets a node that contributes to the data-part this request.
5838
*/
59-
DataFlow::Node getADataNode() { result = custom.getADataNode() }
39+
DataFlow::Node getADataNode() { result = self.getADataNode() }
6040
}
6141

42+
module ClientRequest {
43+
/**
44+
* A call that performs a request to a URL.
45+
*
46+
* Extend this class and implement its abstract member predicates to model additional
47+
* client request APIs. To work with APIs for which there is already a model, extend
48+
* `ClientRequest` instead.
49+
*/
50+
abstract class Range extends DataFlow::InvokeNode {
51+
/**
52+
* Gets the URL of the request.
53+
*/
54+
abstract DataFlow::Node getUrl();
55+
56+
/**
57+
* Gets the host of the request.
58+
*/
59+
abstract DataFlow::Node getHost();
60+
61+
/**
62+
* Gets a node that contributes to the data-part this request.
63+
*/
64+
abstract DataFlow::Node getADataNode();
65+
}
66+
}
67+
68+
deprecated class CustomClientRequest = ClientRequest::Range;
69+
6270
/**
6371
* Gets name of an HTTP request method, in all-lowercase.
6472
*/
@@ -75,7 +83,7 @@ private string urlPropertyName() {
7583
/**
7684
* A model of a URL request made using the `request` library.
7785
*/
78-
private class RequestUrlRequest extends CustomClientRequest {
86+
private class RequestUrlRequest extends ClientRequest::Range {
7987
DataFlow::Node url;
8088

8189
RequestUrlRequest() {
@@ -106,7 +114,7 @@ private class RequestUrlRequest extends CustomClientRequest {
106114
/**
107115
* A model of a URL request made using the `axios` library.
108116
*/
109-
private class AxiosUrlRequest extends CustomClientRequest {
117+
private class AxiosUrlRequest extends ClientRequest::Range {
110118
string method;
111119

112120
AxiosUrlRequest() {
@@ -149,7 +157,7 @@ private class AxiosUrlRequest extends CustomClientRequest {
149157
/**
150158
* A model of a URL request made using an implementation of the `fetch` API.
151159
*/
152-
private class FetchUrlRequest extends CustomClientRequest {
160+
private class FetchUrlRequest extends ClientRequest::Range {
153161
DataFlow::Node url;
154162

155163
FetchUrlRequest() {
@@ -179,7 +187,7 @@ private class FetchUrlRequest extends CustomClientRequest {
179187
/**
180188
* A model of a URL request made using the `got` library.
181189
*/
182-
private class GotUrlRequest extends CustomClientRequest {
190+
private class GotUrlRequest extends ClientRequest::Range {
183191
GotUrlRequest() {
184192
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
185193
moduleName = "got" and
@@ -214,7 +222,7 @@ private class GotUrlRequest extends CustomClientRequest {
214222
/**
215223
* A model of a URL request made using the `superagent` library.
216224
*/
217-
private class SuperAgentUrlRequest extends CustomClientRequest {
225+
private class SuperAgentUrlRequest extends ClientRequest::Range {
218226
DataFlow::Node url;
219227

220228
SuperAgentUrlRequest() {
@@ -239,7 +247,7 @@ private class SuperAgentUrlRequest extends CustomClientRequest {
239247
/**
240248
* A model of a URL request made using the `XMLHttpRequest` browser class.
241249
*/
242-
private class XMLHttpRequest extends CustomClientRequest {
250+
private class XMLHttpRequest extends ClientRequest::Range {
243251
XMLHttpRequest() {
244252
this = DataFlow::globalVarRef("XMLHttpRequest").getAnInstantiation()
245253
or
@@ -257,7 +265,7 @@ private class XMLHttpRequest extends CustomClientRequest {
257265
/**
258266
* A model of a URL request made using the `XhrIo` class from the closure library.
259267
*/
260-
private class ClosureXhrIoRequest extends CustomClientRequest {
268+
private class ClosureXhrIoRequest extends ClientRequest::Range {
261269
ClosureXhrIoRequest() {
262270
exists(DataFlow::SourceNode xhrIo | xhrIo = Closure::moduleImport("goog.net.XhrIo") |
263271
this = xhrIo.getAMethodCall("send")

javascript/ql/src/semmle/javascript/frameworks/Electron.qll

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ module Electron {
6060
t.start() and
6161
result instanceof NewBrowserObject
6262
or
63-
exists(DataFlow::TypeTracker t2 |
64-
result = browserObject(t2).track(t2, t)
65-
)
63+
exists(DataFlow::TypeTracker t2 | result = browserObject(t2).track(t2, t))
6664
}
6765

6866
/**
@@ -122,9 +120,7 @@ module Electron {
122120
string getChannelName() { result = channel.asExpr().getStringValue() }
123121

124122
/** Gets the data flow node containing the message received by the callback. */
125-
DataFlow::Node getMessage() {
126-
result = getParameter(1)
127-
}
123+
DataFlow::Node getMessage() { result = getParameter(1) }
128124
}
129125

130126
/**
@@ -174,9 +170,7 @@ module Electron {
174170
SyncDirectMessage() { isSync = true }
175171

176172
/** Gets the data flow node holding the reply to the message. */
177-
DataFlow::Node getReply() {
178-
result = mc
179-
}
173+
DataFlow::Node getReply() { result = mc }
180174
}
181175

182176
/**
@@ -262,28 +256,32 @@ module Electron {
262256
private class IPCAdditionalFlowStep extends DataFlow::AdditionalFlowStep {
263257
IPCAdditionalFlowStep() { ipcFlowStep(this, _) }
264258

265-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
266-
ipcFlowStep(pred, succ)
267-
}
259+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { ipcFlowStep(pred, succ) }
268260
}
269261
}
270262

271-
/**
272-
* A Node.js-style HTTP or HTTPS request made using an Electron module.
273-
*/
274-
abstract class CustomElectronClientRequest extends NodeJSLib::CustomNodeJSClientRequest { }
275-
276263
/**
277264
* A Node.js-style HTTP or HTTPS request made using an Electron module.
278265
*/
279266
class ElectronClientRequest extends NodeJSLib::NodeJSClientRequest {
280-
ElectronClientRequest() { this instanceof CustomElectronClientRequest }
267+
override ElectronClientRequest::Range self;
268+
}
269+
270+
module ElectronClientRequest {
271+
/**
272+
* A Node.js-style HTTP or HTTPS request made using an Electron module.
273+
*
274+
* Extends this class to add support for new Electron client-request APIs.
275+
*/
276+
abstract class Range extends NodeJSLib::NodeJSClientRequest::Range { }
281277
}
282278

279+
deprecated class CustomElectronClientRequest = ElectronClientRequest::Range;
280+
283281
/**
284282
* A Node.js-style HTTP or HTTPS request made using `electron.ClientRequest`.
285283
*/
286-
private class NewClientRequest extends CustomElectronClientRequest {
284+
private class NewClientRequest extends ElectronClientRequest::Range {
287285
NewClientRequest() {
288286
this = DataFlow::moduleMember("electron", "ClientRequest").getAnInstantiation() or
289287
this = DataFlow::moduleMember("electron", "net").getAMemberCall("request") // alias

javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -685,21 +685,29 @@ module NodeJSLib {
685685
}
686686

687687
/**
688-
* A data flow node that is an HTTP or HTTPS client request made by a Node.js application, for example `http.request(url)`.
689-
*/
690-
abstract class CustomNodeJSClientRequest extends CustomClientRequest { }
691-
692-
/**
693-
* A data flow node that is an HTTP or HTTPS client request made by a Node.js application, for example `http.request(url)`.
688+
* A data flow node that is an HTTP or HTTPS client request made by a Node.js application,
689+
* for example `http.request(url)`.
694690
*/
695691
class NodeJSClientRequest extends ClientRequest {
696-
NodeJSClientRequest() { this instanceof CustomNodeJSClientRequest }
692+
override NodeJSClientRequest::Range self;
693+
}
694+
695+
module NodeJSClientRequest {
696+
/**
697+
* A data flow node that is an HTTP or HTTPS client request made by a Node.js application,
698+
* for example `http.request(url)`.
699+
*
700+
* Extend this class to add support for new Node.js client request APIs.
701+
*/
702+
abstract class Range extends ClientRequest::Range { }
697703
}
698704

705+
deprecated class CustomNodeJSClientRequest = NodeJSClientRequest::Range;
706+
699707
/**
700708
* A model of a URL request in the Node.js `http` library.
701709
*/
702-
private class NodeHttpUrlRequest extends CustomNodeJSClientRequest {
710+
private class NodeHttpUrlRequest extends NodeJSClientRequest::Range {
703711
DataFlow::Node url;
704712

705713
NodeHttpUrlRequest() {

javascript/ql/src/semmle/javascript/frameworks/PropertyProjection.qll

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,25 @@ import javascript
99

1010
/**
1111
* 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-
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
16-
*/
17-
abstract DataFlow::Node getObject();
18-
19-
/**
20-
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
21-
*/
22-
abstract DataFlow::Node getASelector();
23-
24-
/**
25-
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
26-
*/
27-
abstract predicate isSingletonProjection();
28-
}
29-
30-
/**
31-
* A property projection call such as `_.get(o, 'a.b')`, which is equivalent to `o.a.b`.
12+
*
13+
* Extend this class to work with property project APIs for which there is already a model.
14+
* To model additional APIs, extend `PropertyProjection::Range` and implement its abstract member
15+
* predicates.
3216
*/
3317
class PropertyProjection extends DataFlow::CallNode {
34-
CustomPropertyProjection custom;
18+
PropertyProjection::Range self;
3519

36-
PropertyProjection() { this = custom }
20+
PropertyProjection() { this = self }
3721

3822
/**
3923
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
4024
*/
41-
DataFlow::Node getObject() { result = custom.getObject() }
25+
DataFlow::Node getObject() { result = self.getObject() }
4226

4327
/**
4428
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
4529
*/
46-
DataFlow::Node getASelector() { result = custom.getASelector() }
30+
DataFlow::Node getASelector() { result = self.getASelector() }
4731

4832
/**
4933
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
@@ -52,13 +36,39 @@ class PropertyProjection extends DataFlow::CallNode {
5236
* - This predicate holds for `_.get({a: 'b'}, 'a')`, which returns `'b'`,
5337
* - This predicate does not hold for `_.pick({a: 'b', c: 'd'}}, 'a')`, which returns `{a: 'b'}`,
5438
*/
55-
predicate isSingletonProjection() { custom.isSingletonProjection() }
39+
predicate isSingletonProjection() { self.isSingletonProjection() }
40+
}
41+
42+
module PropertyProjection {
43+
/**
44+
* A property projection call such as `_.get(o, 'a.b')`, which is equivalent to `o.a.b`.
45+
*
46+
* Extends this class to add support for new property projection APIs.
47+
*/
48+
abstract class Range extends DataFlow::CallNode {
49+
/**
50+
* Gets the argument for the object to project properties from, such as `o` in `_.get(o, 'a.b')`.
51+
*/
52+
abstract DataFlow::Node getObject();
53+
54+
/**
55+
* Gets an argument that selects the properties to project, such as `'a.b'` in `_.get(o, 'a.b')`.
56+
*/
57+
abstract DataFlow::Node getASelector();
58+
59+
/**
60+
* Holds if this call returns the value of a single projected property, as opposed to an object that can contain multiple projected properties.
61+
*/
62+
abstract predicate isSingletonProjection();
63+
}
5664
}
5765

66+
deprecated class CustomPropertyProjection = PropertyProjection::Range;
67+
5868
/**
5969
* A simple model of common property projection functions.
6070
*/
61-
private class SimplePropertyProjection extends CustomPropertyProjection {
71+
private class SimplePropertyProjection extends PropertyProjection::Range {
6272
int objectIndex;
6373

6474
int selectorIndex;

javascript/ql/src/semmle/javascript/frameworks/jQuery.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ private class JQueryChainedElement extends DOM::Element {
267267
/**
268268
* A model of a URL request made using the `jQuery.ajax` or `jQuery.getJSON`.
269269
*/
270-
private class JQueryClientRequest extends CustomClientRequest {
270+
private class JQueryClientRequest extends ClientRequest::Range {
271271
JQueryClientRequest() {
272272
exists(string name |
273273
name = "ajax" or

javascript/ql/test/library-tests/frameworks/NodeJSLib/ClientRequest.qll renamed to javascript/ql/test/library-tests/frameworks/NodeJSLib/TestClientRequest.qll

File renamed without changes.

javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import SystemCommandExecution
66
import ResponseExpr
77
import HeaderDefinition
88
import RouteSetup_getServer
9-
import ClientRequest
9+
import TestClientRequest
1010
import HeaderDefinition_getAHeaderName
1111
import ServerDefinition
1212
import HeaderAccess

0 commit comments

Comments
 (0)