@@ -24,16 +24,20 @@ module SocketIO {
2424 result = DataFlow:: moduleImport ( "socket.io" ) .getAMemberCall ( "listen" )
2525 }
2626
27- /** A data flow node that may produce (that is, create or return) a socket.io server. */
28- class ServerNode extends DataFlow:: SourceNode {
29- ServerObject srv ;
30-
31- ServerNode ( ) {
32- this = newServer ( ) and
33- srv = MkServer ( this )
27+ /**
28+ * Gets a data flow node that may refer to the socket.io server created at `srv`, with
29+ * type tracking info stored in `t`.
30+ */
31+ private DataFlow:: SourceNode server ( ServerObject srv , DataFlow:: TypeTracker t ) {
32+ result = newServer ( ) and
33+ srv = MkServer ( result ) and
34+ t .start ( )
35+ or
36+ exists ( DataFlow:: TypeTracker s , DataFlow:: SourceNode pred | pred = server ( srv , s ) |
37+ result = pred .track ( s , t )
3438 or
3539 // invocation of a chainable method
36- exists ( ServerNode base , DataFlow:: MethodCallNode mcn , string m |
40+ exists ( DataFlow:: MethodCallNode mcn , string m |
3741 m = "adapter" or
3842 m = "attach" or
3943 m = "bind" or
@@ -44,96 +48,118 @@ module SocketIO {
4448 m = "serveClient" or
4549 m = "set"
4650 |
47- mcn = base .getAMethodCall ( m ) and
51+ mcn = pred .getAMethodCall ( m ) and
4852 // exclude getter versions
4953 exists ( mcn .getAnArgument ( ) ) and
50- this = mcn and
51- srv = base . getServer ( )
54+ result = mcn and
55+ t = s
5256 )
53- }
57+ )
58+ }
59+
60+ /** A data flow node that may produce (that is, create or return) a socket.io server. */
61+ class ServerNode extends DataFlow:: SourceNode {
62+ ServerObject srv ;
63+
64+ ServerNode ( ) { this = server ( srv , _) }
5465
5566 /** Gets the server to which this node refers. */
5667 ServerObject getServer ( ) { result = srv }
5768 }
5869
59- /** A data flow node that may produce a namespace object. */
60- class NamespaceNode extends DataFlow:: SourceNode {
61- NamespaceObject ns ;
70+ /**
71+ * Gets the name of a chainable method on socket.io namespace objects, which servers forward
72+ * to their default namespace.
73+ */
74+ private string namespaceChainableMethod ( ) {
75+ result = "binary" or
76+ result = "clients" or
77+ result = "compress" or
78+ result = "emit" or
79+ result = "in" or
80+ result = "send" or
81+ result = "to" or
82+ result = "use" or
83+ result = "write" or
84+ result = EventEmitter:: chainableMethod ( )
85+ }
6286
63- NamespaceNode ( ) {
64- // namespace lookup
65- exists ( ServerNode srv |
66- this = srv .getAPropertyRead ( "sockets" ) and
67- ns = srv .getServer ( ) .getDefaultNamespace ( )
68- or
69- exists ( DataFlow:: MethodCallNode mcn , string path |
70- mcn = srv .getAMethodCall ( "of" ) and
71- mcn .getArgument ( 0 ) .mayHaveStringValue ( path ) and
72- this = mcn and
73- ns = MkNamespace ( srv .getServer ( ) , path )
74- )
87+ /**
88+ * Gets a data flow node that may refer to the socket.io namespace created at `ns`, with
89+ * type tracking info stored in `t`.
90+ */
91+ private DataFlow:: SourceNode namespace ( NamespaceObject ns , DataFlow:: TypeTracker t ) {
92+ t .start ( ) and
93+ exists ( ServerNode srv |
94+ // namespace lookup on `srv`
95+ result = srv .getAPropertyRead ( "sockets" ) and
96+ ns = srv .getServer ( ) .getDefaultNamespace ( )
97+ or
98+ exists ( DataFlow:: MethodCallNode mcn , string path |
99+ mcn = srv .getAMethodCall ( "of" ) and
100+ mcn .getArgument ( 0 ) .mayHaveStringValue ( path ) and
101+ result = mcn and
102+ ns = MkNamespace ( srv .getServer ( ) , path )
75103 )
76104 or
105+ // invocation of a method that `srv` forwards to its default namespace
106+ result = srv .getAMethodCall ( namespaceChainableMethod ( ) ) and
107+ ns = srv .getServer ( ) .getDefaultNamespace ( )
108+ )
109+ or
110+ exists ( DataFlow:: SourceNode pred , DataFlow:: TypeTracker s | pred = namespace ( ns , s ) |
111+ result = pred .track ( s , t )
112+ or
77113 // invocation of a chainable method
78- exists ( string m |
79- m = "binary" or
80- m = "clients" or
81- m = "compress" or
82- m = "emit" or
83- m = "in" or
84- m = "send" or
85- m = "to" or
86- m = "use" or
87- m = "write" or
88- m = EventEmitter:: chainableMethod ( )
89- |
90- exists ( NamespaceNode base |
91- this = base .getAMethodCall ( m ) and
92- ns = base .getNamespace ( )
93- )
94- or
95- // server objects forward these methods to their default namespace
96- exists ( ServerNode srv |
97- this = srv .getAMethodCall ( m ) and
98- ns = srv .getServer ( ) .getDefaultNamespace ( )
99- )
100- )
114+ result = pred .getAMethodCall ( namespaceChainableMethod ( ) ) and
115+ t = s
101116 or
102117 // invocation of chainable getter method
103- exists ( NamespaceNode base , string m |
118+ exists ( string m |
104119 m = "json" or
105120 m = "local" or
106121 m = "volatile"
107122 |
108- this = base .getAPropertyRead ( m ) and
109- ns = base . getNamespace ( )
123+ result = pred .getAPropertyRead ( m ) and
124+ t = s
110125 )
111- }
126+ )
127+ }
128+
129+ /** A data flow node that may produce a namespace object. */
130+ class NamespaceNode extends DataFlow:: SourceNode {
131+ NamespaceObject ns ;
132+
133+ NamespaceNode ( ) { this = namespace ( ns , _) }
112134
113135 /** Gets the namespace to which this node refers. */
114136 NamespaceObject getNamespace ( ) { result = ns }
115137 }
116138
117- /** A data flow node that may produce a socket object. */
118- class SocketNode extends DataFlow:: SourceNode {
119- NamespaceObject ns ;
120-
121- SocketNode ( ) {
122- // callback accepting a socket
123- exists ( DataFlow:: SourceNode base , string connect , DataFlow:: MethodCallNode on |
124- (
125- ns = base .( ServerNode ) .getServer ( ) .getDefaultNamespace ( ) or
126- ns = base .( NamespaceNode ) .getNamespace ( )
127- ) and
128- ( connect = "connect" or connect = "connection" )
129- |
130- on = base .getAMethodCall ( EventEmitter:: on ( ) ) and
131- on .getArgument ( 0 ) .mayHaveStringValue ( connect ) and
132- this = on .getCallback ( 1 ) .getParameter ( 0 )
133- )
139+ /**
140+ * Gets a data flow node that may refer to a socket.io socket belonging to namespace `ns`, with
141+ * type tracking info stored in `t`.
142+ */
143+ private DataFlow:: SourceNode socket ( NamespaceObject ns , DataFlow:: TypeTracker t ) {
144+ // callback accepting a socket
145+ t .start ( ) and
146+ exists ( DataFlow:: SourceNode base , string connect , DataFlow:: MethodCallNode on |
147+ (
148+ ns = base .( ServerNode ) .getServer ( ) .getDefaultNamespace ( ) or
149+ ns = base .( NamespaceNode ) .getNamespace ( )
150+ ) and
151+ ( connect = "connect" or connect = "connection" )
152+ |
153+ on = base .getAMethodCall ( EventEmitter:: on ( ) ) and
154+ on .getArgument ( 0 ) .mayHaveStringValue ( connect ) and
155+ result = on .getCallback ( 1 ) .getParameter ( 0 )
156+ )
157+ or
158+ exists ( DataFlow:: SourceNode pred , DataFlow:: TypeTracker s | pred = socket ( ns , s ) |
159+ result = pred .track ( s , t )
134160 or
135161 // invocation of a chainable method
136- exists ( SocketNode base , string m |
162+ exists ( string m |
137163 m = "binary" or
138164 m = "compress" or
139165 m = "disconnect" or
@@ -147,21 +173,28 @@ module SocketIO {
147173 m = "write" or
148174 m = EventEmitter:: chainableMethod ( )
149175 |
150- this = base .getAMethodCall ( m ) and
151- ns = base . getNamespace ( )
176+ result = pred .getAMethodCall ( m ) and
177+ t = s
152178 )
153179 or
154180 // invocation of a chainable getter method
155- exists ( SocketNode base , string m |
181+ exists ( string m |
156182 m = "broadcast" or
157183 m = "json" or
158184 m = "local" or
159185 m = "volatile"
160186 |
161- this = base .getAPropertyRead ( m ) and
162- ns = base . getNamespace ( )
187+ result = pred .getAPropertyRead ( m ) and
188+ t = s
163189 )
164- }
190+ )
191+ }
192+
193+ /** A data flow node that may produce a socket object. */
194+ class SocketNode extends DataFlow:: SourceNode {
195+ NamespaceObject ns ;
196+
197+ SocketNode ( ) { this = socket ( ns , _) }
165198
166199 /** Gets the namespace to which this socket belongs. */
167200 NamespaceObject getNamespace ( ) { result = ns }
@@ -361,21 +394,30 @@ module SocketIO {
361394 * (npm package `socket.io-client`).
362395 */
363396module SocketIOClient {
397+ /**
398+ * Gets a data flow node that may refer to the socket.io socket created at `invk`, with
399+ * type tracking info stored in `t`.
400+ */
401+ private DataFlow:: SourceNode socket ( DataFlow:: InvokeNode invk , DataFlow:: TypeTracker t ) {
402+ t .start ( ) and
403+ exists ( DataFlow:: SourceNode io |
404+ io = DataFlow:: globalVarRef ( "io" ) or
405+ io = DataFlow:: globalVarRef ( "io" ) .getAPropertyRead ( "connect" ) or
406+ io = DataFlow:: moduleImport ( "socket.io-client" ) or
407+ io = DataFlow:: moduleMember ( "socket.io-client" , "connect" )
408+ |
409+ invk = io .getAnInvocation ( ) and
410+ result = invk
411+ )
412+ or
413+ exists ( DataFlow:: TypeTracker s | result = socket ( invk , s ) .track ( s , t ) )
414+ }
415+
364416 /** A data flow node that may produce a socket object. */
365417 class SocketNode extends DataFlow:: SourceNode {
366418 DataFlow:: InvokeNode invk ;
367419
368- SocketNode ( ) {
369- exists ( DataFlow:: SourceNode io |
370- io = DataFlow:: globalVarRef ( "io" ) or
371- io = DataFlow:: globalVarRef ( "io" ) .getAPropertyRead ( "connect" ) or
372- io = DataFlow:: moduleImport ( "socket.io-client" ) or
373- io = DataFlow:: moduleMember ( "socket.io-client" , "connect" )
374- |
375- invk = io .getAnInvocation ( ) and
376- this = invk
377- )
378- }
420+ SocketNode ( ) { this = socket ( invk , _) }
379421
380422 /** Gets the path of the namespace this socket belongs to, if it can be determined. */
381423 string getNamespacePath ( ) {
0 commit comments