mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
JS: Move ClientRequest classes into a module and publish them
This commit is contained in:
@@ -69,6 +69,8 @@ class ClientRequest extends DataFlow::InvokeNode {
|
||||
DataFlow::Node getAResponseDataNode() { result = getAResponseDataNode(_, _) }
|
||||
}
|
||||
|
||||
deprecated class CustomClientRequest = ClientRequest::Range;
|
||||
|
||||
module ClientRequest {
|
||||
/**
|
||||
* A call that performs a request to a URL.
|
||||
@@ -101,411 +103,402 @@ module ClientRequest {
|
||||
*/
|
||||
DataFlow::Node getAResponseDataNode(string responseType, boolean promise) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
deprecated class CustomClientRequest = ClientRequest::Range;
|
||||
/**
|
||||
* Gets name of an HTTP request method, in all-lowercase.
|
||||
*/
|
||||
private string httpMethodName() { result = any(HTTP::RequestMethodName m).toLowerCase() }
|
||||
|
||||
/**
|
||||
* Gets name of an HTTP request method, in all-lowercase.
|
||||
*/
|
||||
private string httpMethodName() { result = any(HTTP::RequestMethodName m).toLowerCase() }
|
||||
/**
|
||||
* A model of a URL request made using the `request` library.
|
||||
*/
|
||||
class RequestUrlRequest extends ClientRequest::Range, DataFlow::CallNode {
|
||||
boolean promise;
|
||||
|
||||
/**
|
||||
* Gets the name of a property that likely contains a URL value.
|
||||
*/
|
||||
private string urlPropertyName() {
|
||||
result = "uri" or
|
||||
result = "url"
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `request` library.
|
||||
*/
|
||||
private class RequestUrlRequest extends ClientRequest::Range, DataFlow::CallNode {
|
||||
boolean promise;
|
||||
|
||||
RequestUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
(
|
||||
promise = false and
|
||||
moduleName = "request"
|
||||
or
|
||||
promise = true and
|
||||
RequestUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
(
|
||||
moduleName = "request-promise" or
|
||||
moduleName = "request-promise-any" or
|
||||
moduleName = "request-promise-native"
|
||||
promise = false and
|
||||
moduleName = "request"
|
||||
or
|
||||
promise = true and
|
||||
(
|
||||
moduleName = "request-promise" or
|
||||
moduleName = "request-promise-any" or
|
||||
moduleName = "request-promise-native"
|
||||
)
|
||||
) and
|
||||
(
|
||||
callee = DataFlow::moduleImport(moduleName) or
|
||||
callee = DataFlow::moduleMember(moduleName, httpMethodName())
|
||||
)
|
||||
) and
|
||||
(
|
||||
callee = DataFlow::moduleImport(moduleName) or
|
||||
callee = DataFlow::moduleMember(moduleName, httpMethodName())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(0) or
|
||||
result = getOptionArgument(0, urlPropertyName())
|
||||
}
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(0) or
|
||||
result = getOptionArgument(0, urlPropertyName())
|
||||
}
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
string getResponseFormat() {
|
||||
if getOptionArgument(0, "json").mayHaveBooleanValue(true) then
|
||||
result = "json"
|
||||
else
|
||||
result = "text"
|
||||
}
|
||||
string getResponseFormat() {
|
||||
if getOptionArgument(0, "json").mayHaveBooleanValue(true) then
|
||||
result = "json"
|
||||
else
|
||||
result = "text"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean pr) {
|
||||
responseType = getResponseFormat() and
|
||||
promise = true and
|
||||
pr = true and
|
||||
result = this
|
||||
or
|
||||
responseType = getResponseFormat() and
|
||||
promise = false and
|
||||
pr = false and
|
||||
(
|
||||
result = getCallback([1..2]).getParameter(2)
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean pr) {
|
||||
responseType = getResponseFormat() and
|
||||
promise = true and
|
||||
pr = true and
|
||||
result = this
|
||||
or
|
||||
result = getCallback([1..2]).getParameter(1).getAPropertyRead("body")
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() { result = getArgument(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `axios` library.
|
||||
*/
|
||||
private class AxiosUrlRequest extends ClientRequest::Range {
|
||||
string method;
|
||||
|
||||
AxiosUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
moduleName = "axios" and
|
||||
responseType = getResponseFormat() and
|
||||
promise = false and
|
||||
pr = false and
|
||||
(
|
||||
callee = DataFlow::moduleImport(moduleName) and method = "request"
|
||||
result = getCallback([1..2]).getParameter(2)
|
||||
or
|
||||
callee = DataFlow::moduleMember(moduleName, method) and
|
||||
(method = httpMethodName() or method = "request")
|
||||
result = getCallback([1..2]).getParameter(1).getAPropertyRead("body")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() { result = getArgument(1) }
|
||||
}
|
||||
|
||||
private DataFlow::Node getOptionArgument(string name) {
|
||||
// depends on the method name and the call arity, over-approximating slightly in the name of simplicity
|
||||
result = getOptionArgument([0 .. 2], name)
|
||||
}
|
||||
/**
|
||||
* A model of a URL request made using the `axios` library.
|
||||
*/
|
||||
class AxiosUrlRequest extends ClientRequest::Range {
|
||||
string method;
|
||||
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(0) or
|
||||
result = getOptionArgument(urlPropertyName())
|
||||
}
|
||||
AxiosUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
moduleName = "axios" and
|
||||
(
|
||||
callee = DataFlow::moduleImport(moduleName) and method = "request"
|
||||
or
|
||||
callee = DataFlow::moduleMember(moduleName, method) and
|
||||
(method = httpMethodName() or method = "request")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getHost() { result = getOptionArgument("host") }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
method = "request" and
|
||||
result = getOptionArgument(0, "data")
|
||||
or
|
||||
(method = "post" or method = "put" or method = "put") and
|
||||
(result = getArgument(1) or result = getOptionArgument(2, "data"))
|
||||
or
|
||||
exists(string name | name = "headers" or name = "params" |
|
||||
private DataFlow::Node getOptionArgument(string name) {
|
||||
// depends on the method name and the call arity, over-approximating slightly in the name of simplicity
|
||||
result = getOptionArgument([0 .. 2], name)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
string getResponseFormat() {
|
||||
exists(DataFlow::Node option | option = getOptionArgument([0 .. 2], "responseType") |
|
||||
result = option.getStringValue()
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(0) or
|
||||
result = getOptionArgument(urlPropertyName())
|
||||
}
|
||||
|
||||
override DataFlow::Node getHost() { result = getOptionArgument("host") }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
method = "request" and
|
||||
result = getOptionArgument(0, "data")
|
||||
or
|
||||
not exists(option.getStringValue()) and
|
||||
result = ""
|
||||
)
|
||||
or
|
||||
not exists(getOptionArgument([0 .. 2], "responseType")) and
|
||||
result = "json"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
responseType = getResponseFormat() and
|
||||
promise = true and
|
||||
result = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using an implementation of the `fetch` API.
|
||||
*/
|
||||
private class FetchUrlRequest extends ClientRequest::Range {
|
||||
DataFlow::Node url;
|
||||
|
||||
FetchUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
(
|
||||
moduleName = "node-fetch" or
|
||||
moduleName = "cross-fetch" or
|
||||
moduleName = "isomorphic-fetch"
|
||||
) and
|
||||
callee = DataFlow::moduleImport(moduleName) and
|
||||
url = getArgument(0)
|
||||
)
|
||||
or
|
||||
this = DataFlow::globalVarRef("fetch").getACall() and
|
||||
url = getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = url }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
exists(string name | name = "headers" or name = "body" | result = getOptionArgument(1, name))
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
responseType = "fetch.response" and
|
||||
promise = true and
|
||||
result = this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `got` library.
|
||||
*/
|
||||
private class GotUrlRequest extends ClientRequest::Range {
|
||||
GotUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
moduleName = "got" and
|
||||
(
|
||||
callee = DataFlow::moduleImport(moduleName) or
|
||||
callee = DataFlow::moduleMember(moduleName, "stream")
|
||||
(method = "post" or method = "put" or method = "put") and
|
||||
(result = getArgument(1) or result = getOptionArgument(2, "data"))
|
||||
or
|
||||
exists(string name | name = "headers" or name = "params" |
|
||||
result = getOptionArgument([0 .. 2], name)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(0) and
|
||||
not exists(getOptionArgument(1, "baseUrl"))
|
||||
}
|
||||
|
||||
override DataFlow::Node getHost() {
|
||||
exists(string name |
|
||||
name = "host" or
|
||||
name = "hostname"
|
||||
|
|
||||
result = getOptionArgument(1, name)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
exists(string name | name = "headers" or name = "body" or name = "query" |
|
||||
result = getOptionArgument(1, name)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isStream() {
|
||||
getOptionArgument(1, "stream").mayHaveBooleanValue(true)
|
||||
or
|
||||
this = DataFlow::moduleMember("got", "stream").getACall()
|
||||
}
|
||||
|
||||
predicate isJson() {
|
||||
getOptionArgument(1, "json").mayHaveBooleanValue(true)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
result = this and
|
||||
(
|
||||
isStream() and
|
||||
responseType = "stream" and
|
||||
promise = false
|
||||
string getResponseFormat() {
|
||||
exists(DataFlow::Node option | option = getOptionArgument([0 .. 2], "responseType") |
|
||||
result = option.getStringValue()
|
||||
or
|
||||
not exists(option.getStringValue()) and
|
||||
result = ""
|
||||
)
|
||||
or
|
||||
isJson() and
|
||||
responseType = "json" and
|
||||
promise = true
|
||||
or
|
||||
not isStream() and
|
||||
not isJson() and
|
||||
responseType = "text" and
|
||||
promise = true
|
||||
)
|
||||
not exists(getOptionArgument([0 .. 2], "responseType")) and
|
||||
result = "json"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
responseType = getResponseFormat() and
|
||||
promise = true and
|
||||
result = this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `superagent` library.
|
||||
*/
|
||||
private class SuperAgentUrlRequest extends ClientRequest::Range {
|
||||
DataFlow::Node url;
|
||||
/**
|
||||
* A model of a URL request made using an implementation of the `fetch` API.
|
||||
*/
|
||||
class FetchUrlRequest extends ClientRequest::Range {
|
||||
DataFlow::Node url;
|
||||
|
||||
SuperAgentUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
moduleName = "superagent" and
|
||||
callee = DataFlow::moduleMember(moduleName, httpMethodName()) and
|
||||
FetchUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
(
|
||||
moduleName = "node-fetch" or
|
||||
moduleName = "cross-fetch" or
|
||||
moduleName = "isomorphic-fetch"
|
||||
) and
|
||||
callee = DataFlow::moduleImport(moduleName) and
|
||||
url = getArgument(0)
|
||||
)
|
||||
or
|
||||
this = DataFlow::globalVarRef("fetch").getACall() and
|
||||
url = getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = url }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
exists(string name | name = "headers" or name = "body" | result = getOptionArgument(1, name))
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
responseType = "fetch.response" and
|
||||
promise = true and
|
||||
result = this
|
||||
}
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = url }
|
||||
/**
|
||||
* A model of a URL request made using the `got` library.
|
||||
*/
|
||||
class GotUrlRequest extends ClientRequest::Range {
|
||||
GotUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
moduleName = "got" and
|
||||
(
|
||||
callee = DataFlow::moduleImport(moduleName) or
|
||||
callee = DataFlow::moduleMember(moduleName, "stream")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
override DataFlow::Node getUrl() {
|
||||
result = getArgument(0) and
|
||||
not exists(getOptionArgument(1, "baseUrl"))
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
exists(string name | name = "set" or name = "send" or name = "query" |
|
||||
result = this.getAChainedMethodCall(name).getAnArgument()
|
||||
)
|
||||
override DataFlow::Node getHost() {
|
||||
exists(string name |
|
||||
name = "host" or
|
||||
name = "hostname"
|
||||
|
|
||||
result = getOptionArgument(1, name)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
exists(string name | name = "headers" or name = "body" or name = "query" |
|
||||
result = getOptionArgument(1, name)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isStream() {
|
||||
getOptionArgument(1, "stream").mayHaveBooleanValue(true)
|
||||
or
|
||||
this = DataFlow::moduleMember("got", "stream").getACall()
|
||||
}
|
||||
|
||||
predicate isJson() {
|
||||
getOptionArgument(1, "json").mayHaveBooleanValue(true)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
result = this and
|
||||
(
|
||||
isStream() and
|
||||
responseType = "stream" and
|
||||
promise = false
|
||||
or
|
||||
isJson() and
|
||||
responseType = "json" and
|
||||
promise = true
|
||||
or
|
||||
not isStream() and
|
||||
not isJson() and
|
||||
responseType = "text" and
|
||||
promise = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
responseType = "text" and
|
||||
promise = true and
|
||||
result = this
|
||||
or
|
||||
exists(DataFlow::FunctionNode callback |
|
||||
callback = getAChainedMethodCall("end").getCallback(0) and
|
||||
/**
|
||||
* A model of a URL request made using the `superagent` library.
|
||||
*/
|
||||
class SuperAgentUrlRequest extends ClientRequest::Range {
|
||||
DataFlow::Node url;
|
||||
|
||||
SuperAgentUrlRequest() {
|
||||
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
moduleName = "superagent" and
|
||||
callee = DataFlow::moduleMember(moduleName, httpMethodName()) and
|
||||
url = getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = url }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
exists(string name | name = "set" or name = "send" or name = "query" |
|
||||
result = this.getAChainedMethodCall(name).getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
responseType = "text" and
|
||||
promise = true and
|
||||
result = this
|
||||
or
|
||||
exists(DataFlow::FunctionNode callback |
|
||||
callback = getAChainedMethodCall("end").getCallback(0) and
|
||||
promise = false and
|
||||
(
|
||||
responseType = "error" and result = callback.getParameter(0)
|
||||
or
|
||||
responseType = "text" and result = callback.getParameter(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `XMLHttpRequest` browser class.
|
||||
*/
|
||||
class XMLHttpRequest extends ClientRequest::Range {
|
||||
XMLHttpRequest() {
|
||||
this = DataFlow::globalVarRef("XMLHttpRequest").getAnInstantiation()
|
||||
or
|
||||
// closure shim for XMLHttpRequest
|
||||
this = Closure::moduleImport("goog.net.XmlHttp").getAnInvocation()
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getAMethodCall("open").getArgument(1) }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() { result = getAMethodCall("send").getArgument(0) }
|
||||
|
||||
private string getAssignedResponseType() {
|
||||
getAPropertyWrite("responseType").mayHaveStringValue(result)
|
||||
or
|
||||
getAPropertyWrite("responseType").mayHaveStringValue("") and
|
||||
result = "text"
|
||||
or
|
||||
not exists(getAPropertyWrite("responseType")) and
|
||||
result = "text"
|
||||
}
|
||||
|
||||
DataFlow::FunctionNode getAnEventListener() {
|
||||
result = getAPropertyWrite("on" + any(string s)).getRhs().getAFunctionValue()
|
||||
or
|
||||
result = getAMethodCall("addEventListener").getArgument(1).getAFunctionValue()
|
||||
}
|
||||
|
||||
DataFlow::SourceNode getAnAlias() {
|
||||
result = this
|
||||
or
|
||||
// The value of `this` in an event listener refers to the XHR object
|
||||
result = getAnEventListener().getReceiver()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
promise = false and
|
||||
(
|
||||
responseType = "error" and result = callback.getParameter(0)
|
||||
exists(string prop | result = getAnAlias().getAPropertyRead(prop) |
|
||||
prop = "response" and responseType = getAssignedResponseType()
|
||||
or
|
||||
prop = "responseText" and responseType = "text"
|
||||
or
|
||||
prop = "statusText" and responseType = "text"
|
||||
or
|
||||
prop = "responseXML" and responseType = "document"
|
||||
)
|
||||
or
|
||||
responseType = "text" and result = callback.getParameter(1)
|
||||
responseType = "text" and
|
||||
exists(string method | result = getAnAlias().getAMethodCall(method) |
|
||||
method = "getAllResponseHeaders" or
|
||||
method = "getResponseHeader"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `XMLHttpRequest` browser class.
|
||||
*/
|
||||
private class XMLHttpRequest extends ClientRequest::Range {
|
||||
XMLHttpRequest() {
|
||||
this = DataFlow::globalVarRef("XMLHttpRequest").getAnInstantiation()
|
||||
or
|
||||
// closure shim for XMLHttpRequest
|
||||
this = Closure::moduleImport("goog.net.XmlHttp").getAnInvocation()
|
||||
}
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getAMethodCall("open").getArgument(1) }
|
||||
/**
|
||||
* A model of a URL request made using the `XhrIo` class from the closure library.
|
||||
*/
|
||||
class ClosureXhrIoRequest extends ClientRequest::Range {
|
||||
DataFlow::SourceNode xhrIo;
|
||||
boolean static;
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() { result = getAMethodCall("send").getArgument(0) }
|
||||
|
||||
private string getAssignedResponseType() {
|
||||
getAPropertyWrite("responseType").mayHaveStringValue(result)
|
||||
or
|
||||
getAPropertyWrite("responseType").mayHaveStringValue("") and
|
||||
result = "text"
|
||||
or
|
||||
not exists(getAPropertyWrite("responseType")) and
|
||||
result = "text"
|
||||
}
|
||||
|
||||
private DataFlow::FunctionNode getAnEventListener() {
|
||||
result = getAPropertyWrite("on" + any(string s)).getRhs().getAFunctionValue()
|
||||
or
|
||||
result = getAMethodCall("addEventListener").getArgument(1).getAFunctionValue()
|
||||
}
|
||||
|
||||
private DataFlow::SourceNode getAnAlias() {
|
||||
result = this
|
||||
or
|
||||
// The value of `this` in an event listener refers to the XHR object
|
||||
result = getAnEventListener().getReceiver()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
promise = false and
|
||||
(
|
||||
exists(string prop | result = getAnAlias().getAPropertyRead(prop) |
|
||||
prop = "response" and responseType = getAssignedResponseType()
|
||||
ClosureXhrIoRequest() {
|
||||
xhrIo = Closure::moduleImport("goog.net.XhrIo") and
|
||||
(
|
||||
this = xhrIo.getAMethodCall("send") and static = true
|
||||
or
|
||||
prop = "responseText" and responseType = "text"
|
||||
or
|
||||
prop = "statusText" and responseType = "text"
|
||||
or
|
||||
prop = "responseXML" and responseType = "document"
|
||||
this = xhrIo.getAnInstantiation().getAMethodCall("send") and static = false
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
result = getArgument(2) or
|
||||
result = getArgument(3)
|
||||
}
|
||||
|
||||
/** Gets an event listener with `this` bound to this object. */
|
||||
DataFlow::FunctionNode getAnEventListener() {
|
||||
result = getAnArgument().getAFunctionValue()
|
||||
or
|
||||
responseType = "text" and
|
||||
static = false and
|
||||
exists(DataFlow::MethodCallNode listen, string name |
|
||||
listen = getAMethodCall(name) and
|
||||
(name = "listen" or name = "listenOnce") and
|
||||
xhrIo.flowsTo(listen.getArgument(3)) and
|
||||
result = listen
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::SourceNode getAnAlias() {
|
||||
static = false and
|
||||
result = xhrIo
|
||||
or
|
||||
result = getAnEventListener().getReceiver()
|
||||
}
|
||||
|
||||
private string getAssignedResponseType() {
|
||||
getAMethodCall("setResponseType").getArgument(0).mayHaveStringValue(result)
|
||||
or
|
||||
not exists(getAMethodCall("setResponseType")) and
|
||||
result = "text"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
promise = false and
|
||||
exists(string method | result = getAnAlias().getAMethodCall(method) |
|
||||
method = "getAllResponseHeaders" or
|
||||
method = "getResponseHeader"
|
||||
method = "getResponse" and responseType = getAssignedResponseType()
|
||||
or
|
||||
method = "getResponseHeader" and responseType = "text"
|
||||
or
|
||||
method = "getResponseJson" and responseType = "json"
|
||||
or
|
||||
method = "getResponseText" and responseType = "text"
|
||||
or
|
||||
method = "getResponseXml" and responseType = "document"
|
||||
or
|
||||
method = "getStatusText" and responseType = "text"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A model of a URL request made using the `XhrIo` class from the closure library.
|
||||
*/
|
||||
private class ClosureXhrIoRequest extends ClientRequest::Range {
|
||||
DataFlow::SourceNode xhrIo;
|
||||
boolean static;
|
||||
|
||||
ClosureXhrIoRequest() {
|
||||
xhrIo = Closure::moduleImport("goog.net.XhrIo") and
|
||||
(
|
||||
this = xhrIo.getAMethodCall("send") and static = true
|
||||
or
|
||||
this = xhrIo.getAnInstantiation().getAMethodCall("send") and static = false
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = getArgument(0) }
|
||||
|
||||
override DataFlow::Node getHost() { none() }
|
||||
|
||||
override DataFlow::Node getADataNode() {
|
||||
result = getArgument(2) or
|
||||
result = getArgument(3)
|
||||
}
|
||||
|
||||
/** Gets an event listener with `this` bound to this object. */
|
||||
private DataFlow::FunctionNode getAnEventListener() {
|
||||
result = getAnArgument().getAFunctionValue()
|
||||
or
|
||||
static = false and
|
||||
exists(DataFlow::MethodCallNode listen, string name |
|
||||
listen = getAMethodCall(name) and
|
||||
(name = "listen" or name = "listenOnce") and
|
||||
xhrIo.flowsTo(listen.getArgument(3)) and
|
||||
result = listen
|
||||
)
|
||||
}
|
||||
|
||||
private DataFlow::SourceNode getAnAlias() {
|
||||
static = false and
|
||||
result = xhrIo
|
||||
or
|
||||
result = getAnEventListener().getReceiver()
|
||||
}
|
||||
|
||||
private string getAssignedResponseType() {
|
||||
getAMethodCall("setResponseType").getArgument(0).mayHaveStringValue(result)
|
||||
or
|
||||
not exists(getAMethodCall("setResponseType")) and
|
||||
result = "text"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAResponseDataNode(string responseType, boolean promise) {
|
||||
promise = false and
|
||||
exists(string method | result = getAnAlias().getAMethodCall(method) |
|
||||
method = "getResponse" and responseType = getAssignedResponseType()
|
||||
or
|
||||
method = "getResponseHeader" and responseType = "text"
|
||||
or
|
||||
method = "getResponseJson" and responseType = "json"
|
||||
or
|
||||
method = "getResponseText" and responseType = "text"
|
||||
or
|
||||
method = "getResponseXml" and responseType = "document"
|
||||
or
|
||||
method = "getStatusText" and responseType = "text"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user