Skip to content

Commit 172c5cc

Browse files
committed
changes based on review
1 parent 2c18144 commit 172c5cc

File tree

1 file changed

+126
-118
lines changed
  • javascript/ql/src/semmle/javascript/frameworks

1 file changed

+126
-118
lines changed

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

Lines changed: 126 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -258,144 +258,152 @@ private class JQueryChainedElement extends DOM::Element, InvokeExpr {
258258
}
259259

260260
/**
261-
* A model of a URL request made using the `jQuery.ajax`.
261+
* Classes and predicates for modelling `ClientRequest`s in JQuery.
262262
*/
263-
private class JQueryAjaxCall extends ClientRequest::Range {
264-
JQueryAjaxCall() { this = jquery().getAMemberCall("ajax") }
263+
private module JQueryClientRequest {
264+
/**
265+
* A model of a URL request made using the `jQuery.ajax`.
266+
*/
267+
private class JQueryAjaxCall extends ClientRequest::Range {
268+
JQueryAjaxCall() { this = jquery().getAMemberCall("ajax") }
265269

266-
override DataFlow::Node getUrl() {
267-
result = getArgument(0) and not exists(getOptionArgument(0, _))
268-
or
269-
result = getOptionArgument([0 .. 1], "url")
270-
}
270+
override DataFlow::Node getUrl() {
271+
result = getArgument(0) and not exists(getOptionArgument(0, _))
272+
or
273+
result = getOptionArgument([0 .. 1], "url")
274+
}
271275

272-
override DataFlow::Node getHost() { none() }
276+
override DataFlow::Node getHost() { none() }
273277

274-
override DataFlow::Node getADataNode() { result = getOptionArgument([0 .. 1], "data") }
278+
override DataFlow::Node getADataNode() { result = getOptionArgument([0 .. 1], "data") }
275279

276-
private string getResponseType() {
277-
getOptionArgument([0 .. 1], "dataType").mayHaveStringValue(result)
278-
}
280+
private string getResponseType() {
281+
getOptionArgument([0 .. 1], "dataType").mayHaveStringValue(result)
282+
}
279283

280-
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
281-
(
282-
responseType = getResponseType()
283-
or
284-
not exists(getResponseType()) and responseType = ""
285-
) and
286-
promise = false and
287-
(
288-
result =
289-
getOptionArgument([0 .. 1], "success")
290-
.getALocalSource()
291-
.(DataFlow::FunctionNode)
292-
.getParameter(0)
293-
or
294-
result =
295-
getAResponseNodeFromAnXHRObject(getOptionArgument([0 .. 1],
296-
any(string method | method = "error" or method = "complete"))
284+
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
285+
(
286+
responseType = getResponseType()
287+
or
288+
not exists(getResponseType()) and responseType = ""
289+
) and
290+
promise = false and
291+
(
292+
result =
293+
getOptionArgument([0 .. 1], "success")
297294
.getALocalSource()
298295
.(DataFlow::FunctionNode)
299-
.getParameter(0))
300-
or
301-
result = getAnAjaxCallbackDataNode(this)
302-
or
303-
result = getAResponseNodeFromAnXHRObject(getAnXHRObject(this))
304-
)
296+
.getParameter(0)
297+
or
298+
result =
299+
getAResponseNodeFromAnXHRObject(getOptionArgument([0 .. 1],
300+
any(string method | method = "error" or method = "complete"))
301+
.getALocalSource()
302+
.(DataFlow::FunctionNode)
303+
.getParameter(0))
304+
or
305+
result = getAnAjaxCallbackDataNode(this)
306+
or
307+
result = getAResponseNodeFromAnXHRObject(getAnXHRObject(this))
308+
)
309+
}
305310
}
306-
}
307-
308-
/**
309-
* Gets the response data node from a call to a jqXHR Object.
310-
*/
311-
DataFlow::Node getAnAjaxCallbackDataNode(ClientRequest::Range request) {
312-
result =
313-
request.getAMemberCall(any(string s | s = "done" or s = "then")).getCallback(0).getParameter(0)
314-
}
315-
316-
/**
317-
* Gets the `jqXHR` object from a call to `fail` on the result from an ajax call (`request`).
318-
*/
319-
DataFlow::SourceNode getAnXHRObject(ClientRequest::Range request) {
320-
result = request.getAMemberCall("fail").getCallback(0).getParameter(0)
321-
}
322311

323-
/**
324-
* Gets a node refering to the response contained in an `jqXHR` object (`obj`).
325-
*/
326-
DataFlow::SourceNode getAResponseNodeFromAnXHRObject(DataFlow::SourceNode obj) {
327-
result =
328-
obj
329-
.getAPropertyRead(any(string s |
330-
s = "responseText" or
331-
s = "responseXML"
332-
))
333-
}
312+
/**
313+
* Gets a response data node from a call to a method on jqXHR Object.
314+
*/
315+
private DataFlow::Node getAnAjaxCallbackDataNode(ClientRequest::Range request) {
316+
result =
317+
request
318+
.getAMemberCall(any(string s | s = "done" or s = "then"))
319+
.getCallback(0)
320+
.getParameter(0)
321+
}
334322

335-
/**
336-
* A model of a URL request made using a `jQuery.ajax` shorthand.
337-
* E.g. `jQuery.getJSON`, `jQuery.post` etc.
338-
* See: https://api.jquery.com/category/ajax/shorthand-methods/.
339-
*
340-
* The method signatures:
341-
* jQuery.get( url [, data ] [, success ] [, dataType ] )
342-
* jQuery.getJSON( url [, data ] [, success ] )
343-
* jQuery.getScript( url [, success ] )
344-
* jQuery.post( url [, data ] [, success ] [, dataType ] )
345-
* .load( url [, data ] [, complete ] )
346-
*/
347-
private class JQueryAjaxShortHand extends ClientRequest::Range {
348-
string name;
323+
/**
324+
* Gets a `jqXHR` object from a call to the `fail(..)` method on jqXHR Object.
325+
*/
326+
private DataFlow::SourceNode getAnXHRObject(ClientRequest::Range request) {
327+
result = request.getAMemberCall("fail").getCallback(0).getParameter(0)
328+
}
349329

350-
JQueryAjaxShortHand() {
351-
(
352-
name = "get" or
353-
name = "getJSON" or
354-
name = "getScript" or
355-
name = "post"
356-
) and
357-
this = jquery().getAMemberCall(name)
358-
or
359-
name = "load" and
360-
this = JQuery::objectRef().getAMethodCall(name)
330+
/**
331+
* Gets a node refering to the response contained in an `jqXHR` object.
332+
*/
333+
private DataFlow::SourceNode getAResponseNodeFromAnXHRObject(DataFlow::SourceNode obj) {
334+
result =
335+
obj
336+
.getAPropertyRead(any(string s |
337+
s = "responseText" or
338+
s = "responseXML"
339+
))
361340
}
362341

363-
override DataFlow::Node getUrl() { result = getArgument(0) }
342+
/**
343+
* A model of a URL request made using a `jQuery.ajax` shorthand.
344+
* E.g. `jQuery.getJSON`, `jQuery.post` etc.
345+
* See: https://api.jquery.com/category/ajax/shorthand-methods/.
346+
*
347+
* Models the following method signatures:
348+
* - `jQuery.get( url [, data ] [, success ] [, dataType ] )`
349+
* - `jQuery.getJSON( url [, data ] [, success ] )`
350+
* - `jQuery.getScript( url [, success ] )`
351+
* - `jQuery.post( url [, data ] [, success ] [, dataType ] )`
352+
* - `.load( url [, data ] [, complete ] )`
353+
*/
354+
private class JQueryAjaxShortHand extends ClientRequest::Range {
355+
string name;
364356

365-
override DataFlow::Node getHost() { none() }
357+
JQueryAjaxShortHand() {
358+
(
359+
name = "get" or
360+
name = "getJSON" or
361+
name = "getScript" or
362+
name = "post"
363+
) and
364+
this = jquery().getAMemberCall(name)
365+
or
366+
name = "load" and
367+
this = JQuery::objectRef().getAMethodCall(name)
368+
}
366369

367-
override DataFlow::Node getADataNode() {
368-
result = getArgument(1) and
369-
not name = "getScript" and // doesn't have a data-node.
370-
not result.getALocalSource() instanceof DataFlow::FunctionNode // looks like the success callback.
371-
}
370+
override DataFlow::Node getUrl() { result = getArgument(0) }
372371

373-
string getResponseType() {
374-
(name = "get" or name = "post") and
375-
getLastArgument().mayHaveStringValue(result) and
376-
getNumArgument() > 1
377-
or
378-
name = "getJSON" and result = "json"
379-
or
380-
(name = "getScript" or name = "load") and
381-
result = "text"
382-
}
372+
override DataFlow::Node getHost() { none() }
383373

384-
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
385-
(
386-
responseType = getResponseType()
387-
or
388-
not exists(getResponseType()) and responseType = ""
389-
) and
390-
promise = false and
391-
(
392-
// one of the two last arguments
393-
result = getCallback([getNumArgument() - 2 .. getNumArgument() - 1]).getParameter(0)
374+
override DataFlow::Node getADataNode() {
375+
result = getArgument(1) and
376+
not name = "getScript" and // doesn't have a data-node.
377+
not result.getALocalSource() instanceof DataFlow::FunctionNode // looks like the success callback.
378+
}
379+
380+
private string getResponseType() {
381+
(name = "get" or name = "post") and
382+
getLastArgument().mayHaveStringValue(result) and
383+
getNumArgument() > 1
394384
or
395-
result = getAnAjaxCallbackDataNode(this)
385+
name = "getJSON" and result = "json"
396386
or
397-
result = getAResponseNodeFromAnXHRObject(getAnXHRObject(this))
398-
)
387+
(name = "getScript" or name = "load") and
388+
result = "text"
389+
}
390+
391+
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
392+
(
393+
responseType = getResponseType()
394+
or
395+
not exists(getResponseType()) and responseType = ""
396+
) and
397+
promise = false and
398+
(
399+
// one of the two last arguments
400+
result = getCallback([getNumArgument() - 2 .. getNumArgument() - 1]).getParameter(0)
401+
or
402+
result = getAnAjaxCallbackDataNode(this)
403+
or
404+
result = getAResponseNodeFromAnXHRObject(getAnXHRObject(this))
405+
)
406+
}
399407
}
400408
}
401409

0 commit comments

Comments
 (0)