change RouteSetup to a DataFlow::Node

This commit is contained in:
Erik Krogh Kristensen
2022-03-30 14:17:01 +02:00
committed by erik-krogh
parent d98028be1a
commit 9cb7522bc1
30 changed files with 124 additions and 120 deletions

View File

@@ -59,17 +59,17 @@ module Connect {
/**
* A call to a Connect method that sets up a route.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
RouteSetup() {
getMethodName() = "use" and
(
// app.use(fun)
server.ref().flowsToExpr(getReceiver())
server.ref().getAMethodCall() = this
or
// app.use(...).use(fun)
this.getReceiver().(RouteSetup).getServer() = server.asExpr()
this.getReceiver().(RouteSetup).getServer() = server
)
}
@@ -84,10 +84,10 @@ module Connect {
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t))
}
override Expr getServer() { result = server.asExpr() }
override DataFlow::Node getServer() { result = server }
/** Gets an argument that represents a route handler being registered. */
Expr getARouteHandlerExpr() { result = getAnArgument() }
Expr getARouteHandlerExpr() { result = getAnArgument().asExpr() } // TODO: DataFlow::Node
}
/** An expression that is passed as `basicAuthConnect(<user>, <password>)`. */

View File

@@ -49,6 +49,7 @@ module Express {
* Holds if `e` may refer to a router object.
*/
private predicate isRouter(Expr e) {
// TODO: DataFlow::Node
isRouter(e, _)
or
e.getType().hasUnderlyingType("express", "Router")
@@ -89,7 +90,7 @@ module Express {
}
private class RoutingTreeSetup extends Routing::RouteSetup::MethodCall {
RoutingTreeSetup() { this.asExpr() instanceof RouteSetup }
RoutingTreeSetup() { this instanceof RouteSetup }
override string getRelativePath() {
not this.getMethodName() = "param" and // do not treat parameter name as a path
@@ -140,9 +141,9 @@ module Express {
/**
* A call to an Express router method that sets up a route.
*/
class RouteSetup extends HTTP::Servers::StandardRouteSetup, MethodCallExpr {
class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::MethodCallNode {
RouteSetup() {
isRouter(this.getReceiver()) and
isRouter(this.getReceiver().asExpr()) and
this.getMethodName() = routeSetupMethodName()
}
@@ -150,7 +151,7 @@ module Express {
string getPath() { this.getArgument(0).mayHaveStringValue(result) }
/** Gets the router on which handlers are being registered. */
RouterDefinition getRouter() { isRouter(this.getReceiver(), result) }
RouterDefinition getRouter() { isRouter(this.getReceiver().asExpr(), result) }
/** Holds if this is a call `use`, such as `app.use(handler)`. */
predicate isUseCall() { this.getMethodName() = "use" }
@@ -162,13 +163,14 @@ module Express {
* returned, not its dataflow source.
*/
Expr getRouteHandlerExpr(int index) {
// TODO: DataFlow::Node
// The first argument is a URI pattern if it is a string. If it could possibly be
// a function, we consider it to be a route handler, otherwise a URI pattern.
exists(AnalyzedNode firstArg | firstArg = this.getArgument(0).analyze() |
if firstArg.getAType() = TTFunction()
then result = this.getArgument(index)
then result = this.getArgument(index).asExpr()
else (
index >= 0 and result = this.getArgument(index + 1)
index >= 0 and result = this.getArgument(index + 1).asExpr()
)
)
}
@@ -199,9 +201,8 @@ module Express {
)
}
override Expr getServer() {
any(DataFlow::Node n | n.asExpr() = result).(Application).getARouteHandler() =
this.getARouteHandler()
override DataFlow::Node getServer() {
result.(Application).getARouteHandler() = this.getARouteHandler()
}
/**
@@ -236,16 +237,16 @@ module Express {
/**
* A call that sets up a Passport router that includes the request object.
*/
private class PassportRouteSetup extends HTTP::Servers::StandardRouteSetup, CallExpr {
private class PassportRouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::CallNode {
DataFlow::ModuleImportNode importNode;
DataFlow::FunctionNode callback;
// looks for this pattern: passport.use(new Strategy({passReqToCallback: true}, callback))
PassportRouteSetup() {
importNode = DataFlow::moduleImport("passport") and
this = importNode.getAMemberCall("use").asExpr() and
this = importNode.getAMemberCall("use") and
exists(DataFlow::NewNode strategy |
strategy.flowsToExpr(this.getArgument(0)) and
strategy.flowsTo(this.getArgument(0)) and
strategy.getNumArgument() = 2 and
// new Strategy({passReqToCallback: true}, ...)
strategy.getOptionArgument(0, "passReqToCallback").mayHaveBooleanValue(true) and
@@ -253,7 +254,7 @@ module Express {
)
}
override Expr getServer() { result = importNode.asExpr() }
override DataFlow::Node getServer() { result = importNode }
override DataFlow::SourceNode getARouteHandler() { result = callback }
}
@@ -335,7 +336,8 @@ module Express {
* same requests.
*/
Express::RouteHandlerExpr getPreviousMiddleware() {
index = 0 and result = setup.getRouter().getMiddlewareStackAt(setup.getAPredecessor())
index = 0 and
result = setup.getRouter().getMiddlewareStackAt(setup.asExpr().getAPredecessor())
or
index > 0 and result = setup.getRouteHandlerExpr(index - 1)
or
@@ -867,7 +869,7 @@ module Express {
/**
* Gets a `RouteSetup` that was used for setting up a route on this router.
*/
private RouteSetup getARouteSetup() { this.ref().flowsToExpr(result.getReceiver()) }
private RouteSetup getARouteSetup() { this.ref().flowsTo(result.getReceiver()) }
/**
* Gets a sub-router registered on this router.
@@ -875,7 +877,7 @@ module Express {
* Example: `router2` for `router1.use(router2)` or `router1.use("/route2", router2)`
*/
RouterDefinition getASubRouter() {
result.ref().flowsToExpr(this.getARouteSetup().getAnArgument())
result.ref().flowsTo(this.getARouteSetup().getAnArgument())
}
/**
@@ -884,7 +886,7 @@ module Express {
* Example: `fun` for `router1.use(fun)` or `router.use("/route", fun)`
*/
HTTP::RouteHandler getARouteHandler() {
result.(DataFlow::SourceNode).flowsToExpr(this.getARouteSetup().getAnArgument())
result.(DataFlow::SourceNode).flowsToExpr(this.getARouteSetup().getAnArgument().asExpr())
}
/**
@@ -904,10 +906,10 @@ module Express {
*/
Express::RouteHandlerExpr getMiddlewareStackAt(ControlFlowNode node) {
if
exists(Express::RouteSetup setup | node = setup and setup.getRouter() = this |
exists(Express::RouteSetup setup | node = setup.asExpr() and setup.getRouter() = this |
setup.isUseCall()
)
then result = node.(Express::RouteSetup).getLastRouteHandlerExpr()
then result = node.(AST::ValueNode).flow().(Express::RouteSetup).getLastRouteHandlerExpr()
else result = this.getMiddlewareStackAt(node.getAPredecessor())
}

View File

@@ -132,12 +132,12 @@ module Fastify {
/**
* A call to a Fastify method that sets up a route.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
string methodName;
RouteSetup() {
this = server(server).getAMethodCall(methodName).asExpr() and
this = server(server).getAMethodCall(methodName) and
methodName = ["route", "get", "head", "post", "put", "delete", "options", "patch"]
}
@@ -152,20 +152,19 @@ module Fastify {
exists(DataFlow::TypeBackTracker t2 | result = this.getARouteHandler(t2).backtrack(t2, t))
}
override Expr getServer() { result = server.asExpr() }
override DataFlow::SourceNode getServer() { result = server }
/** Gets an argument that represents a route handler being registered. */
DataFlow::Node getARouteHandlerExpr() {
if methodName = "route"
then
result = this.flow().(DataFlow::MethodCallNode).getOptionArgument(0, getNthHandlerName(_))
else result = this.getLastArgument().flow()
then result = this.getOptionArgument(0, getNthHandlerName(_))
else result = this.getLastArgument()
}
}
private class ShorthandRoutingTreeSetup extends Routing::RouteSetup::MethodCall {
ShorthandRoutingTreeSetup() {
this.asExpr() instanceof RouteSetup and
this instanceof RouteSetup and
not this.getMethodName() = "route"
}
@@ -183,7 +182,7 @@ module Fastify {
private class FullRoutingTreeSetup extends Routing::RouteSetup::MethodCall {
FullRoutingTreeSetup() {
this.asExpr() instanceof RouteSetup and
this instanceof RouteSetup and
this.getMethodName() = "route"
}
@@ -285,13 +284,7 @@ module Fastify {
*/
private predicate usesFastifyPlugin(RouteHandler rh, DataFlow::SourceNode plugin) {
exists(RouteSetup setup |
plugin
.flowsTo(setup
.getServer()
.flow()
.(DataFlow::SourceNode)
.getAMethodCall("register")
.getArgument(0)) and // only matches the plugins that apply to all routes
plugin.flowsTo(setup.getServer().getAMethodCall("register").getArgument(0)) and // only matches the plugins that apply to all routes
rh = setup.getARouteHandler()
)
}
@@ -301,13 +294,7 @@ module Fastify {
*/
private predicate usesMiddleware(RouteHandler rh, DataFlow::SourceNode middleware) {
exists(RouteSetup setup |
middleware
.flowsTo(setup
.getServer()
.flow()
.(DataFlow::SourceNode)
.getAMethodCall("use")
.getArgument(0)) and // only matches the middlewares that apply to all routes
middleware.flowsTo(setup.getServer().getAMethodCall("use").getArgument(0)) and // only matches the middlewares that apply to all routes
rh = setup.getARouteHandler()
)
}

View File

@@ -195,10 +195,8 @@ module Firebase {
/**
* A call to a Firebase method that sets up a route.
*/
private class RouteSetup extends HTTP::Servers::StandardRouteSetup, CallExpr {
RouteSetup() {
this = namespace().getAPropertyRead("https").getAMemberCall("onRequest").asExpr()
}
private class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::CallNode {
RouteSetup() { this = namespace().getAPropertyRead("https").getAMemberCall("onRequest") }
override DataFlow::SourceNode getARouteHandler() {
result = getARouteHandler(DataFlow::TypeBackTracker::end())
@@ -206,12 +204,12 @@ module Firebase {
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and
result = getArgument(0).flow().getALocalSource()
result = getArgument(0).getALocalSource()
or
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t))
}
override Expr getServer() { none() }
override DataFlow::Node getServer() { none() }
}
/**

View File

@@ -242,7 +242,7 @@ module HTTP {
/**
* An expression that sets up a route on a server.
*/
abstract class RouteSetup extends Expr { } // TODO: DataFlow::Node
abstract class RouteSetup extends DataFlow::Node { }
/**
* An expression that may contain a request object.
@@ -275,9 +275,7 @@ module HTTP {
* A standard server definition.
*/
abstract class StandardServerDefinition extends ServerDefinition {
override RouteHandler getARouteHandler() {
result.(StandardRouteHandler).getServer() = this.asExpr()
}
override RouteHandler getARouteHandler() { result.(StandardRouteHandler).getServer() = this }
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and
@@ -308,8 +306,7 @@ module HTTP {
/**
* Gets the server this route handler is registered on.
*/
Expr getServer() {
// TODO: DataFlow::Node
DataFlow::Node getServer() {
exists(StandardRouteSetup setup | setup.getARouteHandler() = this |
result = setup.getServer()
)
@@ -414,7 +411,7 @@ module HTTP {
/**
* Gets the server on which this route setup sets up routes.
*/
abstract Expr getServer(); // TODO: DataFlow::Node
abstract DataFlow::Node getServer();
}
/**

View File

@@ -186,16 +186,16 @@ module Hapi {
/**
* A call to a Hapi method that sets up a route.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
Expr handler;
DataFlow::Node handler;
RouteSetup() {
server.ref().flowsToExpr(getReceiver()) and
server.ref().getAMethodCall() = this and
(
// server.route({ handler: fun })
getMethodName() = "route" and
hasOptionArgument(0, "handler", handler)
getOptionArgument(0, "handler") = handler
or
// server.ext('/', fun)
getMethodName() = "ext" and
@@ -215,11 +215,11 @@ module Hapi {
}
pragma[noinline]
private DataFlow::Node getRouteHandler() { result = handler.flow() }
private DataFlow::Node getRouteHandler() { result = handler }
Expr getRouteHandlerExpr() { result = handler }
Expr getRouteHandlerExpr() { result = handler.asExpr() } // TODO: DataFlow::Node
override Expr getServer() { result = server.asExpr() }
override DataFlow::Node getServer() { result = server }
}
/**

View File

@@ -384,24 +384,23 @@ module Koa {
/**
* A call to a Koa method that sets up a route.
*/
class RouteSetup extends HTTP::Servers::StandardRouteSetup, MethodCallExpr {
class RouteSetup extends HTTP::Servers::StandardRouteSetup, DataFlow::MethodCallNode {
AppDefinition server;
RouteSetup() {
// app.use(fun)
server.ref().flowsToExpr(this.getReceiver()) and
this.getMethodName() = "use"
server.ref().getAMethodCall("use") = this
}
override DataFlow::SourceNode getARouteHandler() {
// `StandardRouteHandler` uses this predicate in it's charpred, so making this predicate return a `RouteHandler` would give an empty recursion.
result.flowsToExpr(this.getArgument(0))
result.flowsToExpr(this.getArgument(0).asExpr())
or
// For the route-handlers that does not depend on this predicate in their charpred.
result.(RouteHandler).getARouteHandlerRegistrationObject().flowsToExpr(this.getArgument(0))
result.(RouteHandler).getARouteHandlerRegistrationObject().flowsTo(this.getArgument(0))
}
override Expr getServer() { result = server.asExpr() }
override DataFlow::Node getServer() { result = server }
}
/**

View File

@@ -30,18 +30,14 @@ private module LiveServer {
/**
* The call to `require("live-server").start()`, seen as a route setup.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends HTTP::Servers::StandardRouteSetup instanceof API::CallNode {
ServerDefinition server;
API::CallNode call;
RouteSetup() {
call = server.getImportNode().getMember("start").getACall() and
this = call.asExpr()
}
RouteSetup() { this = server.getImportNode().getMember("start").getACall() }
override DataFlow::SourceNode getARouteHandler() {
exists(DataFlow::SourceNode middleware |
middleware = call.getParameter(0).getMember("middleware").getAValueReachingSink()
middleware = super.getParameter(0).getMember("middleware").getAValueReachingSink()
|
result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue()
or
@@ -49,6 +45,6 @@ private module LiveServer {
)
}
override Expr getServer() { result = server.asExpr() }
override DataFlow::Node getServer() { result = server }
}
}

View File

@@ -217,16 +217,16 @@ module NodeJSLib {
RequestExpr getRequest() { result = request }
}
class RouteSetup extends CallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends DataFlow::CallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
Expr handler;
DataFlow::Node handler;
RouteSetup() {
server.ref().flowsToExpr(this) and
server.ref() = this and
handler = this.getLastArgument()
or
server.ref().flowsToExpr(this.getReceiver()) and
this.(MethodCallExpr).getMethodName().regexpMatch("on(ce)?") and
server.ref().getAMethodCall() = this and
this.getCalleeName().regexpMatch("on(ce)?") and
this.getArgument(0).getStringValue() = "request" and
handler = this.getArgument(1)
}
@@ -237,7 +237,7 @@ module NodeJSLib {
private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) {
t.start() and
result = handler.flow().getALocalSource()
result = handler.getALocalSource()
or
exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ |
succ = this.getARouteHandler(t2)
@@ -249,12 +249,12 @@ module NodeJSLib {
)
}
override Expr getServer() { result = server.asExpr() }
override DataFlow::Node getServer() { result = server }
/**
* Gets the expression for the handler registered by this setup.
*/
Expr getRouteHandlerExpr() { result = handler }
Expr getRouteHandlerExpr() { result = handler.asExpr() } // TODO: DataFlow::Node
}
abstract private class HeaderDefinition extends HTTP::Servers::StandardHeaderDefinition {

View File

@@ -142,18 +142,17 @@ module Restify {
/**
* A call to a Restify method that sets up a route.
*/
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
class RouteSetup extends DataFlow::MethodCallNode, HTTP::Servers::StandardRouteSetup {
ServerDefinition server;
RouteSetup() {
// server.get('/', fun)
// server.head('/', fun)
server.ref().flowsToExpr(getReceiver()) and
getMethodName() = any(HTTP::RequestMethodName m).toLowerCase()
server.ref().getAMethodCall(any(HTTP::RequestMethodName m).toLowerCase()) = this
}
override DataFlow::SourceNode getARouteHandler() { result.flowsToExpr(getArgument(1)) }
override DataFlow::SourceNode getARouteHandler() { result.flowsTo(getArgument(1)) }
override Expr getServer() { result = server.asExpr() }
override DataFlow::Node getServer() { result = server }
}
}