Skip to content

Commit

Permalink
fix: senderId removed in Electron 28 (#171)
Browse files Browse the repository at this point in the history
* Accepting ipc events without senderId

Since the property has been removed with Electron 28

* Access senderId on cast event object to be compatible with Electron 28, where "senderId" is removed from IpcRendererEvent

* fix type error

* Implement interface for missing senderId check

* replace process.mainModule with a while loop to get the topmost parent

* disable test using removed APIs

* split the codepaths for electron 28 and electron < 28

* prefix comment for skipped test with TODO

* chore: formatting

---------

Co-authored-by: Jeremy Rose <[email protected]>
Co-authored-by: Kilian Valkhof <[email protected]>
Co-authored-by: David Sanders <[email protected]>
  • Loading branch information
4 people authored Dec 12, 2023
1 parent 642040d commit 51ff1b4
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 7 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ workflows:
- 25
- 26
- 27
- 28
- cfa/release:
requires:
- test-electron
Expand Down
12 changes: 11 additions & 1 deletion src/main/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,17 @@ export function initialize() {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.require('${moduleName}')`)
} else {
customEvent.returnValue = process.mainModule!.require(moduleName)
// electron < 28
if (process.mainModule) {
customEvent.returnValue = process.mainModule!.require(moduleName)
} else {
// electron >= 28
let mainModule = module;
while (mainModule.parent) {
mainModule = mainModule.parent;
}
customEvent.returnValue = mainModule.require(moduleName)
}
}
}

Expand Down
19 changes: 15 additions & 4 deletions src/renderer/remote.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CallbacksRegistry } from './callbacks-registry'
import { isPromise, isSerializableObject, serialize, deserialize } from '../common/type-utils'
import { MetaTypeFromRenderer, ObjectMember, ObjProtoDescriptor, MetaType } from '../common/types'
import { BrowserWindow, WebContents, ipcRenderer } from 'electron'
import { BrowserWindow, WebContents, ipcRenderer, IpcRendererEvent } from 'electron'
import { browserModuleNames } from '../common/module-names'
import { getElectronBinding } from '../common/get-electron-binding'
import { IPC_MESSAGES } from '../common/ipc-messages';
Expand Down Expand Up @@ -309,11 +309,22 @@ function metaToError (meta: { type: 'error', value: any, members: ObjectMember[]
return obj
}

// Backwards compatibility interface for Electron < v28
interface IpcRendererEventWithSenderId extends IpcRendererEvent {
senderId: number
}

function hasSenderId(input: any): input is IpcRendererEventWithSenderId {
return typeof input.senderId === "number"
}

function handleMessage (channel: string, handler: Function) {
ipcRenderer.on(channel, (event, passedContextId, id, ...args) => {
if (event.senderId !== 0) {
console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`);
return;
if (hasSenderId(event)) {
if (event.senderId !== 0 && event.senderId !== undefined) {
console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`);
return;
}
}

if (passedContextId === contextId) {
Expand Down
9 changes: 7 additions & 2 deletions test/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,12 @@ describe('remote module', () => {
expect(a.getConstructorName(new (class {})())).to.equal('')
})

it('should search module from the user app', async () => {
/* TODO: Electron 28 removed process.mainModule, so we need to find an alternative way to test that the remotely
required module in the renderer uses the same main module as the main process. In src/main/server.ts:388 we do so
by looping over the module parents until getting the top most one and using their require, but that require
doesn't send along the module paths, so we can't use it here. */

it.skip('should search module from the user app', async () => {
expectPathsEqual(
path.normalize(await remotely(() => require('./renderer').process.mainModule!.filename)),
path.resolve(__dirname, 'index.js')
Expand Down Expand Up @@ -887,7 +892,7 @@ describe('remote module', () => {
} catch (e) {
done(e)
} finally {
process.off('unhandledRejection', onUnhandledRejection)
process.off('unhandledRejection' as any, onUnhandledRejection)
}
})
})
Expand Down

0 comments on commit 51ff1b4

Please sign in to comment.