Files
codeql/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll
2022-01-20 09:41:13 +01:00

99 lines
2.9 KiB
Plaintext

/**
* Provides classes and predicates for working with the [http-proxy](https://www.npmjs.com/package/http-proxy) library.
*/
import javascript
/**
* Provides classes and predicates modeling the [http-proxy](https://www.npmjs.com/package/http-proxy) library.
*/
private module HttpProxy {
/**
* A call that creates a http proxy.
*/
class CreateServerCall extends API::CallNode, ClientRequest::Range {
CreateServerCall() {
this =
API::moduleImport("http-proxy")
.getMember(["createServer", "createProxyServer", "createProxy"])
.getACall()
}
override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").getARhs() }
override DataFlow::Node getHost() {
result = getParameter(0).getMember("target").getMember("host").getARhs()
}
override DataFlow::Node getADataNode() { none() }
}
/**
* A call that proxies a request to some target.
*/
class ProxyCall extends API::CallNode, ClientRequest::Range {
string method;
ProxyCall() {
method = ["ws", "web"] and
this = any(CreateServerCall server).getReturn().getMember(method).getACall()
}
private API::Node getOptionsObject() {
exists(int optionsIndex |
method = "web" and optionsIndex = 2
or
method = "ws" and optionsIndex = 3
|
result = getParameter(optionsIndex)
)
}
override DataFlow::Node getUrl() { result = getOptionsObject().getMember("target").getARhs() }
override DataFlow::Node getHost() {
result = getOptionsObject().getMember("target").getMember("host").getARhs()
}
override DataFlow::Node getADataNode() { none() }
}
/**
* Holds if an event handler for `event` has a HTTP request parameter at `req` and a HTTP response parameter at `res`.
*/
predicate routeHandlingEventHandler(string event, int req, int res) {
event = ["start", "end"] and req = 0 and res = 1
or
event = ["proxyReq", "proxyRes", "econnreset"] and req = 1 and res = 2
or
event = "proxyReqWs" and req = 1 and res = -10 // -10 for non-existent.
}
/**
* An http proxy event handler.
*/
class ProxyListenerCallback extends NodeJSLib::RouteHandler, DataFlow::FunctionNode {
string event;
ProxyListenerCallback() {
exists(API::CallNode call |
call = any(CreateServerCall server).getReturn().getMember(["on", "once"]).getACall() and
call.getParameter(0).getARhs().mayHaveStringValue(event) and
this = call.getParameter(1).getARhs().getAFunctionValue()
)
}
override Parameter getRequestParameter() {
exists(int req | routeHandlingEventHandler(event, req, _) |
result = getFunction().getParameter(req)
)
}
override Parameter getResponseParameter() {
exists(int res | routeHandlingEventHandler(event, _, res) |
result = getFunction().getParameter(res)
)
}
}
}