@@ -73,187 +73,109 @@ module Electron {
7373 /**
7474 * A reference to the `webContents` property of a browser object.
7575 */
76- class WebContents extends DataFlow:: SourceNode {
76+ class WebContents extends DataFlow:: SourceNode , NodeJSLib :: NodeJSEventEmitter {
7777 WebContents ( ) { this .( DataFlow:: PropRead ) .accesses ( any ( BrowserObject bo ) , "webContents" ) }
7878 }
7979
8080 /**
8181 * Provides classes and predicates for modelling Electron inter-process communication (IPC).
82+ * The Electron IPC are EventEmitters, but they also expose a number of methods on top of the standard EventEmitter.
8283 */
8384 private module IPC {
84- class Process extends string {
85- Process ( ) { this = "main" or this = "renderer" }
85+ DataFlow:: SourceNode main ( ) { result = DataFlow:: moduleMember ( "electron" , "ipcMain" ) }
8686
87- DataFlow:: SourceNode getAnImport ( ) {
88- this = Process:: main ( ) and result = DataFlow:: moduleMember ( "electron" , "ipcMain" )
89- or
90- this = Process:: renderer ( ) and result = DataFlow:: moduleMember ( "electron" , "ipcRenderer" )
91- }
92- }
93-
94- module Process {
95- Process main ( ) { result = "main" }
96-
97- Process renderer ( ) { result = "renderer" }
98- }
99-
100- /**
101- * An IPC callback.
102- */
103- class Callback extends DataFlow:: FunctionNode {
104- DataFlow:: Node channel ;
105- Process process ;
106-
107- Callback ( ) {
108- exists ( DataFlow:: MethodCallNode mc |
109- mc = process .getAnImport ( ) .getAMemberCall ( "on" ) and
110- this = mc .getCallback ( 1 ) and
111- channel = mc .getArgument ( 0 )
112- )
113- }
114-
115- /** Gets the process on which this callback is executed. */
116- Process getProcess ( ) { result = process }
117-
118- /** Gets the name of the channel the callback is listening on. */
119- string getChannelName ( ) { result = channel .getStringValue ( ) }
120-
121- /** Gets the data flow node containing the message received by the callback. */
122- DataFlow:: Node getMessage ( ) { result = getParameter ( 1 ) }
123- }
87+ DataFlow:: SourceNode renderer ( ) { result = DataFlow:: moduleMember ( "electron" , "ipcRenderer" ) }
12488
12589 /**
126- * An IPC message .
90+ * A model for the Main and Renderer process in an Electron app .
12791 */
128- abstract class Message extends DataFlow:: Node {
129- /** Gets the process that sends this message. */
130- abstract Process getProcess ( ) ;
131-
132- /** Gets the name of the channel this message is sent on. */
133- abstract string getChannelName ( ) ;
92+ abstract class Process extends EventEmitter:: Range {
93+ /**
94+ * Gets a node that refers to a Process object.
95+ */
96+ DataFlow:: SourceNode ref ( ) { result = EventEmitter:: trackEventEmitter ( this ) }
13497 }
13598
13699 /**
137- * An IPC message sent directly from a process.
100+ * An instance of the Main process of an Electron app.
101+ * Communication in an Electron app generally happens from the renderer process to the main process.
138102 */
139- class DirectMessage extends Message {
140- DataFlow:: MethodCallNode mc ;
141- Process process ;
142- DataFlow:: Node channel ;
143- boolean isSync ;
144-
145- DirectMessage ( ) {
146- exists ( string send |
147- send = "send" and isSync = false
148- or
149- send = "sendSync" and isSync = true
150- |
151- mc = process .getAnImport ( ) .getAMemberCall ( send ) and
152- this = mc .getArgument ( 1 ) and
153- channel = mc .getArgument ( 0 )
154- )
155- }
156-
157- override Process getProcess ( ) { result = process }
158-
159- override string getChannelName ( ) { result = channel .getStringValue ( ) }
103+ class MainProcess extends Process {
104+ MainProcess ( ) { this = main ( ) }
160105 }
161106
162107 /**
163- * A synchronous IPC message sent directly from a process .
108+ * An instance of the renderer process of an Electron app .
164109 */
165- class SyncDirectMessage extends DirectMessage {
166- SyncDirectMessage ( ) { isSync = true }
167-
168- /** Gets the data flow node holding the reply to the message. */
169- DataFlow:: Node getReply ( ) { result = mc }
110+ class RendererProcess extends Process {
111+ RendererProcess ( ) { this = renderer ( ) }
170112 }
171113
172114 /**
173- * An asynchronous IPC reply sent from within an IPC callback.
115+ * The `sender` property of the event in an IPC event handler.
116+ * This sender is used to send a response back from the main process to the renderer.
174117 */
175- class AsyncReplyMessage extends Message {
176- Callback callback ;
177- DataFlow:: Node channel ;
178-
179- AsyncReplyMessage ( ) {
180- exists ( DataFlow:: MethodCallNode mc |
181- mc = callback .getParameter ( 0 ) .getAPropertyRead ( "sender" ) .getAMemberCall ( "send" ) and
182- this = mc .getArgument ( 1 ) and
183- channel = mc .getArgument ( 0 )
118+ class ProcessSender extends Process {
119+ ProcessSender ( ) {
120+ exists ( IPCSendRegistration reg | reg .getEmitter ( ) instanceof MainProcess |
121+ this = reg .getABoundCallbackParameter ( 1 , 0 ) .getAPropertyRead ( "sender" )
184122 )
185123 }
186-
187- override Process getProcess ( ) { result = callback .getProcess ( ) }
188-
189- override string getChannelName ( ) { result = channel .getStringValue ( ) }
190124 }
191125
192126 /**
193- * A synchronous IPC reply sent from within an IPC callback.
127+ * A registration of an Electron IPC event handler.
128+ * Does mostly the same as an EventEmitter event handler,
129+ * except that values can be returned through the `event.returnValue` property.
194130 */
195- class SyncReplyMessage extends Message {
196- Callback callback ;
131+ class IPCSendRegistration extends EventRegistration:: DefaultEventRegistration ,
132+ DataFlow:: MethodCallNode {
133+ override Process emitter ;
197134
198- SyncReplyMessage ( ) {
199- this = callback .getParameter ( 0 ) .getAPropertyWrite ( "returnValue" ) .getRhs ( )
200- }
135+ IPCSendRegistration ( ) { this = emitter .ref ( ) .getAMethodCall ( EventEmitter:: on ( ) ) }
201136
202- override Process getProcess ( ) { result = callback .getProcess ( ) }
137+ override DataFlow:: Node getAReturnedValue ( ) {
138+ result = this .getABoundCallbackParameter ( 1 , 0 ) .getAPropertyWrite ( "returnValue" ) .getRhs ( )
139+ }
203140
204- override string getChannelName ( ) { result = callback .getChannelName ( ) }
141+ override IPCDispatch getAReturnDispatch ( ) {
142+ result .getCalleeName ( ) = "sendSync"
143+ }
205144 }
206145
207146 /**
208- * An asynchronous Electron IPC message sent from the main process via a `webContents` object.
147+ * A dispatch of an IPC event.
148+ * An IPC event is sent from the renderer to the main process.
149+ * And a value can be returned through the `returnValue` property of the event (first parameter in the callback).
209150 */
210- class WebContentsMessage extends Message {
211- DataFlow:: Node channel ;
212-
213- WebContentsMessage ( ) {
214- exists ( WebContents wc , DataFlow:: MethodCallNode mc |
215- wc .flowsTo ( mc .getReceiver ( ) ) and
216- this = mc .getArgument ( 1 ) and
217- channel = mc .getArgument ( 0 ) and
218- mc .getCalleeName ( ) = "send"
151+ class IPCDispatch extends EventDispatch:: DefaultEventDispatch , DataFlow:: InvokeNode {
152+ override Process emitter ;
153+
154+ IPCDispatch ( ) {
155+ exists ( string methodName | methodName = "sendSync" or methodName = "send" |
156+ this = emitter .ref ( ) .getAMemberCall ( methodName )
219157 )
220158 }
221159
222- override Process getProcess ( ) { result = Process:: main ( ) }
223-
224- override string getChannelName ( ) { result = channel .getStringValue ( ) }
225- }
226-
227- /**
228- * Holds if `pred` flows to `succ` via Electron IPC.
229- */
230- private predicate ipcFlowStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
231- // match a message sent from one process with a callback parameter in the other process
232- exists ( Callback callback , Message msg |
233- callback .getChannelName ( ) = msg .getChannelName ( ) and
234- callback .getProcess ( ) != msg .getProcess ( ) and
235- pred = msg and
236- succ = callback .getMessage ( )
237- )
238- or
239- // match a synchronous reply sent from one process with a `sendSync` call in the other process
240- exists ( SyncDirectMessage sendSync , SyncReplyMessage msg |
241- sendSync .getChannelName ( ) = msg .getChannelName ( ) and
242- sendSync .getProcess ( ) != msg .getProcess ( ) and
243- pred = msg and
244- succ = sendSync .getReply ( )
245- )
246- }
247-
248- /**
249- * An additional flow step via an Electron IPC message.
250- */
251- private class IPCAdditionalFlowStep extends DataFlow:: AdditionalFlowStep {
252- IPCAdditionalFlowStep ( ) { ipcFlowStep ( this , _) }
160+ /**
161+ * Gets the `i`th dispatched argument to the event handler.
162+ * The 0th parameter in the callback is a event generated by the IPC system,
163+ * therefore these arguments start at 1.
164+ */
165+ override DataFlow:: Node getSentItem ( int i ) {
166+ i >= 1 and
167+ result = getArgument ( i )
168+ }
253169
254- override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
255- pred = this and
256- ipcFlowStep ( pred , succ )
170+ /**
171+ * Gets a registration that this dispatch can send an event to.
172+ */
173+ override IPCSendRegistration getAReceiver ( ) {
174+ this .getEmitter ( ) instanceof RendererProcess and
175+ result .getEmitter ( ) instanceof MainProcess
176+ or
177+ this .getEmitter ( ) instanceof ProcessSender and
178+ result .getEmitter ( ) instanceof RendererProcess
257179 }
258180 }
259181 }
0 commit comments