Skip to content

Commit 2044b4b

Browse files
committed
changes based on review
1 parent 6345e9b commit 2044b4b

File tree

1 file changed

+45
-38
lines changed

1 file changed

+45
-38
lines changed

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

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
2-
* Provides classes for working with [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket).
2+
* Provides classes for working with [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) and [ws](https://github.com/websockets/ws).
33
*
4-
* The model is based on the EventEmitter model, and there a therefore a
4+
* The model is based on the EventEmitter model, and there is therefore a
55
* data-flow step from where a WebSocket event is send to where the message
66
* is received.
77
*
8-
* WebSockets include no concept of channels, therefore every client can send
9-
* to every server (and vice versa).
8+
* Data flow is modeled both from clients to servers, and from servers to clients.
9+
* The model models that clients can send messages to all servers, and servers can send messages to all clients.
1010
*/
1111

1212
import javascript
@@ -18,6 +18,9 @@ import javascript
1818
*/
1919
private string channelName() { result = "message" }
2020

21+
/**
22+
* Provides classes that model WebSockets clients.
23+
*/
2124
module ClientWebSocket {
2225
/**
2326
* A class that can be used to instantiate a WebSocket instance.
@@ -69,55 +72,59 @@ module ClientWebSocket {
6972
}
7073

7174
/**
72-
* Gets a methodName that can be used to register a listener for WebSocket messages on a given socket.
75+
* A handler that is registered to receive messages from a WebSocket.
7376
*/
74-
string getARegisterMethodName(ClientSocket socket) {
75-
result = "addEventListener"
76-
or
77-
socket.isNode() and
78-
result = EventEmitter::on()
77+
abstract class ReceiveNode extends EventRegistration::Range, DataFlow::FunctionNode {
78+
override ClientSocket emitter;
79+
80+
override string getChannel() { result = channelName() }
7981
}
8082

8183
/**
82-
* A handler that is registered to receive messages from a WebSocket.
83-
*
84-
* If the registration happens with the "addEventListener" method or the "onmessage" setter property, then the handler receives an event with a "data" property.
85-
* Otherwise the handler receives the data directly.
86-
*
87-
* This confusing API is caused by the "ws" library only mostly using their own API, where event objects are not used.
88-
* But the "ws" library additionally supports the WebSocket API from browsers, which exclusively use event objects with a "data" property.
84+
* Gets a handler, that is registered using method `methodName` and receives messages send to `emitter`.
8985
*/
90-
class ReceiveNode extends EventRegistration::Range, DataFlow::FunctionNode {
91-
override ClientSocket emitter;
92-
boolean receivesEvent;
86+
private DataFlow::FunctionNode getAMessageHandler(ClientWebSocket::ClientSocket emitter, string methodName) {
87+
exists(DataFlow::CallNode call |
88+
call = emitter.getAMemberCall(methodName) and
89+
call.getArgument(0).mayHaveStringValue("message") and
90+
result = call.getCallback(1)
91+
)
92+
}
9393

94-
ReceiveNode() {
95-
exists(DataFlow::CallNode call, string methodName |
96-
methodName = getARegisterMethodName(emitter) and
97-
call = emitter.getAMemberCall(methodName) and
98-
call.getArgument(0).mayHaveStringValue("message") and
99-
this = call.getCallback(1) and
100-
if methodName = "addEventListener" then receivesEvent = true else receivesEvent = false
101-
)
94+
/**
95+
* A handler that receives a message using the WebSocket API.
96+
* The "ws" library implements a superset of the WebSocket API, and this class therefore models both WebSocket and "ws".
97+
*/
98+
private class WebSocketReceiveNode extends ClientWebSocket::ReceiveNode {
99+
WebSocketReceiveNode() {
100+
this = getAMessageHandler(emitter, "addEventListener")
102101
or
103-
this = emitter.getAPropertyWrite("onmessage").getRhs() and
104-
receivesEvent = true
102+
this = emitter.getAPropertyWrite("onmessage").getRhs()
105103
}
106104

107-
override string getChannel() { result = channelName() }
105+
override DataFlow::Node getReceivedItem(int i) {
106+
i = 0 and result = this.getParameter(0).getAPropertyRead("data")
107+
}
108+
}
109+
110+
/**
111+
* A handler that receives a message using the API from the "ws" library.
112+
*/
113+
private class WSReceiveNode extends ClientWebSocket::ReceiveNode {
114+
WSReceiveNode () {
115+
emitter.isNode() and
116+
this = getAMessageHandler(emitter, EventEmitter::on())
117+
}
108118

109119
override DataFlow::Node getReceivedItem(int i) {
110-
i = 0 and
111-
result = this.getParameter(0).getAPropertyRead("data") and
112-
receivesEvent = true
113-
or
114-
i = 0 and
115-
result = this.getParameter(0) and
116-
receivesEvent = false
120+
i = 0 and result = this.getParameter(0)
117121
}
118122
}
119123
}
120124

125+
/**
126+
* Provides classes that model WebSocket servers.
127+
*/
121128
module ServerWebSocket {
122129
/**
123130
* A server WebSocket instance.

0 commit comments

Comments
 (0)