Skip to content

Commit b2e3049

Browse files
author
Max Schaefer
authored
Merge branch 'master' into ts-typescript2.9
2 parents 7f77acf + 44e4b25 commit b2e3049

33 files changed

+447
-58
lines changed

change-notes/1.18/analysis-javascript.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@
9898

9999
## Changes to QL libraries
100100

101+
* HTTP and HTTPS requests made using the Node.js `http.request` and `https.request` APIs and the Electron `Electron.net.request` and `Electron.ClientRequest` APIs are modeled as `RemoteFlowSources`.
101102
* HTTP header names are now always normalized to lower case to reflect the fact that they are case insensitive. In particular, the result of `HeaderDefinition.getAHeaderName`, and the first parameter of `HeaderDefinition.defines`, `ExplicitHeaderDefinition.definesExplicitly` and `RouteHandler.getAResponseHeader` is now always a lower-case string.
103+
* New AST nodes for TypeScript 2.9 features have been added.
102104
* The class `JsonParseCall` has been deprecated. Use `JsonParserCall` instead.
103105
* The handling of spread arguments in the data flow library has been changed: `DataFlow::InvokeNode.getArgument(i)` is now only defined when there is no spread argument at or before argument position `i`, and similarly `InvokeNode.getNumArgument` is only defined for invocations without spread arguments.
104-
* New AST nodes for TypeScript 2.9 features have been added.

csharp/ql/test/library-tests/controlflow/graph/ElementGraph.ql

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/**
2-
* @kind graph
3-
* @id elementgraph
4-
*/
5-
61
import csharp
72
import semmle.code.csharp.controlflow.ControlFlowGraph
83

csharp/ql/test/library-tests/controlflow/graph/NodeGraph.ql

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/**
2-
* @kind graph
3-
* @id nodegraph
4-
*/
5-
61
import csharp
72
import semmle.code.csharp.controlflow.ControlFlowGraph
83

csharp/ql/test/library-tests/csharp7/IsFlow.ql

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/**
2-
* @kind graph
3-
* @id nodegraph
4-
*/
5-
61
import csharp
72
import semmle.code.csharp.controlflow.ControlFlowGraph
83

csharp/ql/test/library-tests/goto/Goto1.ql

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
/**
2-
* @kind graph
3-
* @id nodegraph
4-
*/
5-
61
import csharp
72
import semmle.code.csharp.controlflow.ControlFlowGraph
83

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,54 @@ module Electron {
3333
this = DataFlow::moduleMember("electron", "BrowserView").getAnInstantiation()
3434
}
3535
}
36+
37+
/**
38+
* A Node.js-style HTTP or HTTPS request made using an Electron module.
39+
*/
40+
abstract class ClientRequest extends NodeJSLib::ClientRequest {}
41+
42+
/**
43+
* A Node.js-style HTTP or HTTPS request made using `electron.net`, for example `net.request(url)`.
44+
*/
45+
private class NetRequest extends ClientRequest {
46+
NetRequest() {
47+
this = DataFlow::moduleMember("electron", "net").getAMemberCall("request")
48+
}
49+
50+
override DataFlow::Node getOptions() {
51+
result = this.(DataFlow::MethodCallNode).getArgument(0)
52+
}
53+
}
54+
55+
56+
/**
57+
* A Node.js-style HTTP or HTTPS request made using `electron.client`, for example `new client(url)`.
58+
*/
59+
private class NewClientRequest extends ClientRequest {
60+
NewClientRequest() {
61+
this = DataFlow::moduleMember("electron", "ClientRequest").getAnInstantiation()
62+
}
63+
64+
override DataFlow::Node getOptions() {
65+
result = this.(DataFlow::NewNode).getArgument(0)
66+
}
67+
}
68+
69+
70+
/**
71+
* A data flow node that is the parameter of a redirect callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `net.request(url).on('redirect', (res) => {})`.
72+
*/
73+
private class ClientRequestRedirectEvent extends RemoteFlowSource {
74+
ClientRequestRedirectEvent() {
75+
exists(NodeJSLib::ClientRequestHandler handler |
76+
this = handler.getParameter(0) and
77+
handler.getAHandledEvent() = "redirect" and
78+
handler.getClientRequest() instanceof ClientRequest
79+
)
80+
}
81+
82+
override string getSourceType() {
83+
result = "Electron ClientRequest redirect event"
84+
}
85+
}
3686
}

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

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,231 @@ module NodeJSLib {
501501
}
502502
}
503503

504+
/**
505+
* A data flow node that is an HTTP or HTTPS client request made by a Node.js server, for example `http.request(url)`.
506+
*/
507+
abstract class ClientRequest extends DataFlow::DefaultSourceNode {
508+
/**
509+
* Gets the options object or string URL used to make the request.
510+
*/
511+
abstract DataFlow::Node getOptions();
512+
}
513+
514+
/**
515+
* A data flow node that is an HTTP or HTTPS client request made by a Node.js server, for example `http.request(url)`.
516+
*/
517+
private class HttpRequest extends ClientRequest {
518+
HttpRequest() {
519+
exists(string protocol |
520+
(
521+
protocol = "http" or
522+
protocol = "https"
523+
)
524+
and
525+
this = DataFlow::moduleImport(protocol).getAMemberCall("request")
526+
)
527+
}
528+
529+
override DataFlow::Node getOptions() {
530+
result = this.(DataFlow::MethodCallNode).getArgument(0)
531+
}
532+
}
533+
534+
/**
535+
* A data flow node that is an HTTP or HTTPS client request made by a Node.js process, for example `https.get(url)`.
536+
*/
537+
private class HttpGet extends ClientRequest {
538+
HttpGet() {
539+
exists(string protocol |
540+
(
541+
protocol = "http" or
542+
protocol = "https"
543+
)
544+
and
545+
this = DataFlow::moduleImport(protocol).getAMemberCall("get")
546+
)
547+
}
548+
549+
override DataFlow::Node getOptions() {
550+
result = this.(DataFlow::MethodCallNode).getArgument(0)
551+
}
552+
}
553+
554+
/**
555+
* A data flow node that is the parameter of a result callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `https.request(url, (res) => {})`.
556+
*/
557+
private class ClientRequestCallbackParam extends DataFlow::ParameterNode, RemoteFlowSource {
558+
ClientRequestCallbackParam() {
559+
exists(ClientRequest req |
560+
this = req.(DataFlow::MethodCallNode).getCallback(1).getParameter(0)
561+
)
562+
}
563+
564+
override string getSourceType() {
565+
result = "ClientRequest callback parameter"
566+
}
567+
}
568+
569+
/**
570+
* A data flow node that is the parameter of a data callback for an HTTP or HTTPS request made by a Node.js process, for example `body` in `http.request(url, (res) => {res.on('data', (body) => {})})`.
571+
*/
572+
private class ClientRequestCallbackData extends RemoteFlowSource {
573+
ClientRequestCallbackData() {
574+
exists(ClientRequestCallbackParam rcp, DataFlow::MethodCallNode mcn |
575+
rcp.getAMethodCall("on") = mcn and
576+
mcn.getArgument(0).mayHaveStringValue("data") and
577+
this = mcn.getCallback(1).getParameter(0)
578+
)
579+
}
580+
581+
override string getSourceType() {
582+
result = "http.request data parameter"
583+
}
584+
}
585+
586+
587+
/**
588+
* A data flow node that is registered as a callback for an HTTP or HTTPS request made by a Node.js process, for example the function `handler` in `http.request(url).on(message, handler)`.
589+
*/
590+
class ClientRequestHandler extends DataFlow::FunctionNode {
591+
string handledEvent;
592+
ClientRequest clientRequest;
593+
594+
ClientRequestHandler() {
595+
exists(DataFlow::MethodCallNode mcn |
596+
clientRequest.getAMethodCall("on") = mcn and
597+
mcn.getArgument(0).mayHaveStringValue(handledEvent) and
598+
flowsTo(mcn.getArgument(1))
599+
)
600+
}
601+
602+
/**
603+
* Gets the name of an event this callback is registered for.
604+
*/
605+
string getAHandledEvent() {
606+
result = handledEvent
607+
}
608+
609+
/**
610+
* Gets a request this callback is registered for.
611+
*/
612+
ClientRequest getClientRequest() {
613+
result = clientRequest
614+
}
615+
}
616+
617+
/**
618+
* A data flow node that is the parameter of a response callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `http.request(url).on('response', (res) => {})`.
619+
*/
620+
private class ClientRequestResponseEvent extends RemoteFlowSource, DataFlow::ParameterNode {
621+
ClientRequestResponseEvent() {
622+
exists(ClientRequestHandler handler |
623+
this = handler.getParameter(0) and
624+
handler.getAHandledEvent() = "response"
625+
)
626+
}
627+
628+
override string getSourceType() {
629+
result = "ClientRequest response event"
630+
}
631+
}
632+
633+
/**
634+
* A data flow node that is the parameter of a data callback for an HTTP or HTTPS request made by a Node.js process, for example `chunk` in `http.request(url).on('response', (res) => {res.on('data', (chunk) => {})})`.
635+
*/
636+
private class ClientRequestDataEvent extends RemoteFlowSource {
637+
ClientRequestDataEvent() {
638+
exists(DataFlow::MethodCallNode mcn, ClientRequestResponseEvent cr |
639+
cr.getAMethodCall("on") = mcn and
640+
mcn.getArgument(0).mayHaveStringValue("data") and
641+
this = mcn.getCallback(1).getParameter(0)
642+
)
643+
}
644+
645+
override string getSourceType() {
646+
result = "ClientRequest data event"
647+
}
648+
}
649+
650+
/**
651+
* A data flow node that is a login callback for an HTTP or HTTPS request made by a Node.js process.
652+
*/
653+
private class ClientRequestLoginHandler extends ClientRequestHandler {
654+
ClientRequestLoginHandler() {
655+
getAHandledEvent() = "login"
656+
}
657+
}
658+
659+
/**
660+
* A data flow node that is a parameter of a login callback for an HTTP or HTTPS request made by a Node.js process, for example `res` in `http.request(url).on('login', (res, callback) => {})`.
661+
*/
662+
private class ClientRequestLoginEvent extends RemoteFlowSource {
663+
ClientRequestLoginEvent() {
664+
exists(ClientRequestLoginHandler handler |
665+
this = handler.getParameter(0)
666+
)
667+
}
668+
669+
override string getSourceType() {
670+
result = "ClientRequest login event"
671+
}
672+
}
673+
674+
/**
675+
* A data flow node that is the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `callback` in `http.request(url).on('login', (res, callback) => {})`.
676+
*/
677+
class ClientRequestLoginCallback extends DataFlow::ParameterNode {
678+
ClientRequestLoginCallback() {
679+
exists(ClientRequestLoginHandler handler |
680+
this = handler.getParameter(1)
681+
)
682+
}
683+
}
684+
685+
/**
686+
* A data flow node that is the username passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `username` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
687+
*/
688+
private class ClientRequestLoginUsername extends CredentialsExpr {
689+
ClientRequestLoginUsername() {
690+
exists(ClientRequestLoginCallback callback |
691+
this = callback.getACall().getArgument(0).asExpr()
692+
)
693+
}
694+
695+
override string getCredentialsKind() {
696+
result = "Node.js http(s) client login username"
697+
}
698+
}
699+
700+
/**
701+
* A data flow node that is the password passed to the login callback provided by an HTTP or HTTPS request made by a Node.js process, for example `password` in `http.request(url).on('login', (res, cb) => {cb(username, password)})`.
702+
*/
703+
private class ClientRequestLoginPassword extends CredentialsExpr {
704+
ClientRequestLoginPassword() {
705+
exists(ClientRequestLoginCallback callback |
706+
this = callback.getACall().getArgument(1).asExpr()
707+
)
708+
}
709+
710+
override string getCredentialsKind() {
711+
result = "Node.js http(s) client login password"
712+
}
713+
}
714+
715+
716+
/**
717+
* A data flow node that is the parameter of an error callback for an HTTP or HTTPS request made by a Node.js process, for example `err` in `http.request(url).on('error', (err) => {})`.
718+
*/
719+
private class ClientRequestErrorEvent extends RemoteFlowSource {
720+
ClientRequestErrorEvent() {
721+
exists(ClientRequestHandler handler |
722+
this = handler.getParameter(0) and
723+
handler.getAHandledEvent() = "error"
724+
)
725+
}
726+
727+
override string getSourceType() {
728+
result = "ClientRequest error event"
729+
}
730+
}
504731
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| electron.js:7:5:7:38 | net.req ... e.com') |
2+
| electron.js:8:16:8:78 | new Cli ... POST'}) |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from NodeJSLib::ClientRequest cr
4+
select cr
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| electron.js:10:26:10:33 | response |
2+
| electron.js:11:28:11:32 | chunk |
3+
| electron.js:16:26:16:33 | redirect |
4+
| electron.js:21:23:21:30 | authInfo |
5+
| electron.js:26:23:26:27 | error |

0 commit comments

Comments
 (0)