Skip to content

Commit afee864

Browse files
committed
JS: make use of the colletions type tracking steps
1 parent 36b7574 commit afee864

File tree

6 files changed

+154
-45
lines changed

6 files changed

+154
-45
lines changed

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

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -585,29 +585,26 @@ module HTTP {
585585
)
586586
}
587587

588-
override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) {
589-
result instanceof RouteHandlerCandidate and
588+
DataFlow::SourceNode trackRouteHandler(
589+
DataFlow::TypeTracker t, RouteHandlerCandidate candidate
590+
) {
590591
exists(DataFlow::MethodCallNode set, DataFlow::Node setKey |
591592
setKey = set.getArgument(0) and
592593
this.getAMethodCall("set") = set and
593-
result.flowsTo(set.getArgument(1))
594-
|
595-
exists(DataFlow::MethodCallNode get, DataFlow::Node getKey |
596-
get = access and
597-
getKey = get.getArgument(0) and
598-
ref(this).getAMethodCall("get") = get
599-
|
600-
exists(string name |
601-
getKey.mayHaveStringValue(name) and
602-
setKey.mayHaveStringValue(name)
603-
)
604-
)
605-
or
606-
exists(DataFlow::MethodCallNode forEach |
607-
forEach = ref(this).getAMethodCall("forEach") and
608-
forEach.getCallback(0).getParameter(0) = access
609-
)
594+
candidate.flowsTo(set.getArgument(1)) and
595+
result = this and // start type tracking on the Map object, because the route-handler is contained inside the Map.
596+
t.startInProp(DataFlow::PseudoProperties::mapValue(setKey))
610597
)
598+
or
599+
exists(DataFlow::TypeTracker t2 | result = trackRouteHandler(t2, candidate).track(t2, t))
600+
or
601+
exists(DataFlow::TypeTracker t2 |
602+
result = CollectionsTypeTracking::collectionStep(trackRouteHandler(t2, candidate), t, t2)
603+
)
604+
}
605+
606+
override DataFlow::SourceNode getRouteHandler(DataFlow::SourceNode access) {
607+
access = trackRouteHandler(DataFlow::TypeTracker::end(), result)
611608
}
612609
}
613610
}

javascript/ql/test/library-tests/frameworks/Express/RouteHandlerContainer.expected

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import javascript
2+
3+
query predicate getRouteHandlerContainerStep(
4+
HTTP::RouteHandlerCandidateContainer container, DataFlow::SourceNode handler, DataFlow::SourceNode access
5+
) {
6+
handler = container.getRouteHandler(access)
7+
}

javascript/ql/test/library-tests/frameworks/Express/src/advanced-routehandler-registration.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ routesMap.set("a", (req, res) => console.log(req));
124124
routesMap.set("b", (req, res) => console.log(req));
125125
routesMap.forEach((v, k) => app.get(k, v));
126126
app.get("a", routesMap.get("a"));
127-
app.get("b", routesMap.get("a"));
127+
app.get("b", routesMap.get("b"));
128128

129129
let method = "GET";
130130
app[method.toLowerCase()](path, (req, res) => undefined);
@@ -145,3 +145,9 @@ app.use.apply(options.app, args);
145145

146146
let handlers = { handlerA: (req, res) => undefined};
147147
app.use(handlers.handlerA.bind(data));
148+
149+
for ([k, v] of routesMap) {
150+
app.get(k, v)
151+
}
152+
153+
app.get("b", routesMap.get("NOT_A_KEY!")); // no.

0 commit comments

Comments
 (0)