Skip to content

Commit 29bcd7c

Browse files
authored
Merge pull request github#6572 from erik-krogh/live-server
Approved by esbena
2 parents 50a9b18 + f8d4667 commit 29bcd7c

26 files changed

+192
-167
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
lgtm,codescanning
2+
* The dataflow libraries now model sources and sinks from the `live-server` library.
3+
The model for `connect` has improved to recognize more sources and sinks.
4+
Affected packages are
5+
[live-server](https://www.npmjs.com/package/live-server),
6+
[connect](https://www.npmjs.com/package/connect)

javascript/ql/lib/semmle/javascript/frameworks/Connect.qll

Lines changed: 6 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ module Connect {
2424
* but support for other kinds of route handlers can be added by implementing
2525
* additional subclasses of this class.
2626
*/
27-
abstract class RouteHandler extends HTTP::Servers::StandardRouteHandler, DataFlow::ValueNode {
27+
abstract class RouteHandler extends NodeJSLib::RouteHandler, DataFlow::ValueNode {
2828
/**
2929
* Gets the parameter of kind `kind` of this route handler.
3030
*
@@ -35,12 +35,12 @@ module Connect {
3535
/**
3636
* Gets the parameter of the route handler that contains the request object.
3737
*/
38-
Parameter getRequestParameter() { result = getRouteHandlerParameter("request") }
38+
override Parameter getRequestParameter() { result = getRouteHandlerParameter("request") }
3939

4040
/**
4141
* Gets the parameter of the route handler that contains the response object.
4242
*/
43-
Parameter getResponseParameter() { result = getRouteHandlerParameter("response") }
43+
override Parameter getResponseParameter() { result = getRouteHandlerParameter("response") }
4444
}
4545

4646
/**
@@ -56,50 +56,6 @@ module Connect {
5656
}
5757
}
5858

59-
/**
60-
* A Connect response source, that is, the response parameter of a
61-
* route handler.
62-
*/
63-
private class ResponseSource extends HTTP::Servers::ResponseSource {
64-
RouteHandler rh;
65-
66-
ResponseSource() { this = DataFlow::parameterNode(rh.getResponseParameter()) }
67-
68-
/**
69-
* Gets the route handler that provides this response.
70-
*/
71-
override RouteHandler getRouteHandler() { result = rh }
72-
}
73-
74-
/**
75-
* A Connect request source, that is, the request parameter of a
76-
* route handler.
77-
*/
78-
private class RequestSource extends HTTP::Servers::RequestSource {
79-
RouteHandler rh;
80-
81-
RequestSource() { this = DataFlow::parameterNode(rh.getRequestParameter()) }
82-
83-
/**
84-
* Gets the route handler that handles this request.
85-
*/
86-
override RouteHandler getRouteHandler() { result = rh }
87-
}
88-
89-
/**
90-
* A Node.js HTTP response provided by Connect.
91-
*/
92-
class ResponseExpr extends NodeJSLib::ResponseExpr {
93-
ResponseExpr() { src instanceof ResponseSource }
94-
}
95-
96-
/**
97-
* A Node.js HTTP request provided by Connect.
98-
*/
99-
class RequestExpr extends NodeJSLib::RequestExpr {
100-
RequestExpr() { src instanceof RequestSource }
101-
}
102-
10359
/**
10460
* A call to a Connect method that sets up a route.
10561
*/
@@ -152,6 +108,8 @@ module Connect {
152108
override string getCredentialsKind() { result = kind }
153109
}
154110

111+
class RequestExpr = NodeJSLib::RequestExpr;
112+
155113
/**
156114
* An access to a user-controlled Connect request input.
157115
*/
@@ -160,6 +118,7 @@ module Connect {
160118
string kind;
161119

162120
RequestInputAccess() {
121+
request.getRouteHandler() instanceof StandardRouteHandler and
163122
exists(PropAccess cookies |
164123
// `req.cookies.get(<name>)`
165124
kind = "cookie" and
@@ -172,33 +131,4 @@ module Connect {
172131

173132
override string getKind() { result = kind }
174133
}
175-
176-
/**
177-
* A function that flows to a route setup.
178-
*/
179-
private class TrackedRouteHandlerCandidateWithSetup extends RouteHandler,
180-
HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode {
181-
TrackedRouteHandlerCandidateWithSetup() { this = any(RouteSetup s).getARouteHandler() }
182-
183-
override Parameter getRouteHandlerParameter(string kind) {
184-
result = getRouteHandlerParameter(astNode, kind)
185-
}
186-
}
187-
188-
/**
189-
* A call that looks like a route setup on a Connect server.
190-
*
191-
* For example, this could be the call `router.use(handler)` where
192-
* it is unknown if `router` is a Connect router.
193-
*/
194-
class RouteSetupCandidate extends HTTP::RouteSetupCandidate, DataFlow::MethodCallNode {
195-
DataFlow::ValueNode routeHandlerArg;
196-
197-
RouteSetupCandidate() {
198-
getMethodName() = "use" and
199-
routeHandlerArg = getAnArgument()
200-
}
201-
202-
override DataFlow::ValueNode getARouteHandlerArg() { result = routeHandlerArg }
203-
}
204134
}

javascript/ql/lib/semmle/javascript/frameworks/HttpFrameworks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import semmle.javascript.frameworks.Express
22
import semmle.javascript.frameworks.Hapi
33
import semmle.javascript.frameworks.Koa
4+
import semmle.javascript.frameworks.LiveServer
45
import semmle.javascript.frameworks.NodeJSLib
56
import semmle.javascript.frameworks.Micro
67
import semmle.javascript.frameworks.Restify
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Provides classes modelling the [live-server](https://npmjs.com/package/live-server) package.
3+
*/
4+
5+
import javascript
6+
private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpressShared as ConnectExpressShared
7+
8+
private module LiveServer {
9+
/**
10+
* An expression that imports the live-server package, seen as a server-definition.
11+
*/
12+
class ServerDefinition extends HTTP::Servers::StandardServerDefinition {
13+
API::Node imp;
14+
15+
ServerDefinition() {
16+
imp = API::moduleImport("live-server") and
17+
this = imp.getAnImmediateUse().asExpr()
18+
}
19+
20+
API::Node getImportNode() { result = imp }
21+
}
22+
23+
/**
24+
* A live-server middleware definition.
25+
* `live-server` uses the `connect` library under the hood, so the model is based on the `connect` model.
26+
*/
27+
class RouteHandler extends Connect::RouteHandler, DataFlow::FunctionNode {
28+
RouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
29+
30+
override Parameter getRouteHandlerParameter(string kind) {
31+
result = ConnectExpressShared::getRouteHandlerParameter(astNode, kind)
32+
}
33+
}
34+
35+
/**
36+
* The call to `require("live-server").start()`, seen as a route setup.
37+
*/
38+
class RouteSetup extends MethodCallExpr, HTTP::Servers::StandardRouteSetup {
39+
ServerDefinition server;
40+
API::CallNode call;
41+
42+
RouteSetup() {
43+
call = server.getImportNode().getMember("start").getACall() and
44+
this = call.asExpr()
45+
}
46+
47+
override DataFlow::SourceNode getARouteHandler() {
48+
exists(DataFlow::SourceNode middleware |
49+
middleware = call.getParameter(0).getMember("middleware").getAValueReachingRhs()
50+
|
51+
result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue()
52+
or
53+
result = middleware.(DataFlow::ArrayCreationNode).getAnElement().getAFunctionValue()
54+
)
55+
}
56+
57+
override Expr getServer() { result = server }
58+
}
59+
}

javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ private import semmle.javascript.frameworks.ConnectExpressShared::ConnectExpress
2929
/**
3030
* A route handler that should be rate-limited.
3131
*/
32-
abstract class ExpensiveRouteHandler extends HTTP::RouteHandler {
32+
abstract class ExpensiveRouteHandler extends DataFlow::Node {
3333
Express::RouteHandler impl;
3434

3535
ExpensiveRouteHandler() { this = impl }
@@ -42,10 +42,6 @@ abstract class ExpensiveRouteHandler extends HTTP::RouteHandler {
4242
* `referenceLabel` are ignored and should be bound to dummy values.
4343
*/
4444
abstract predicate explain(string explanation, DataFlow::Node reference, string referenceLabel);
45-
46-
override HTTP::HeaderDefinition getAResponseHeader(string name) {
47-
result = impl.getAResponseHeader(name)
48-
}
4945
}
5046

5147
/**

javascript/ql/test/library-tests/frameworks/connect/Credentials.qll

Lines changed: 0 additions & 5 deletions
This file was deleted.

javascript/ql/test/library-tests/frameworks/connect/HeaderDefinition.qll

Lines changed: 0 additions & 5 deletions
This file was deleted.

javascript/ql/test/library-tests/frameworks/connect/HeaderDefinition_defines.qll

Lines changed: 0 additions & 5 deletions
This file was deleted.

javascript/ql/test/library-tests/frameworks/connect/HeaderDefinition_getAHeaderName.qll

Lines changed: 0 additions & 5 deletions
This file was deleted.

javascript/ql/test/library-tests/frameworks/connect/RequestExpr.qll

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)