Skip to content

Commit

Permalink
feat: add additional remote APIs filtering (#16688)
Browse files Browse the repository at this point in the history
  • Loading branch information
miniak authored and codebytere committed Feb 4, 2019
1 parent c00d353 commit e253c9b
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 54 deletions.
46 changes: 46 additions & 0 deletions docs/api/app.md
Expand Up @@ -422,6 +422,52 @@ Emitted when `remote.getGlobal()` is called in the renderer process of `webConte
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.

### Event: 'remote-get-builtin'

Returns:

* `event` Event
* `webContents` [WebContents](web-contents.md)
* `moduleName` String

Emitted when `remote.getBuiltin()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.

### Event: 'remote-get-current-window'

Returns:

* `event` Event
* `webContents` [WebContents](web-contents.md)

Emitted when `remote.getCurrentWindow()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.

### Event: 'remote-get-current-web-contents'

Returns:

* `event` Event
* `webContents` [WebContents](web-contents.md)

Emitted when `remote.getCurrentWebContents()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.

### Event: 'remote-get-guest-web-contents'

Returns:

* `event` Event
* `webContents` [WebContents](web-contents.md)
* `guestWebContents` [WebContents](web-contents.md)

Emitted when `<webview>.getWebContents()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.

## Methods

The `app` object has the following methods:
Expand Down
42 changes: 42 additions & 0 deletions docs/api/web-contents.md
Expand Up @@ -685,6 +685,48 @@ Emitted when `remote.getGlobal()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.

#### Event: 'remote-get-builtin'

Returns:

* `event` Event
* `moduleName` String

Emitted when `remote.getBuiltin()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the module from being returned.
Custom value can be returned by setting `event.returnValue`.

#### Event: 'remote-get-current-window'

Returns:

* `event` Event

Emitted when `remote.getCurrentWindow()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.

#### Event: 'remote-get-current-web-contents'

Returns:

* `event` Event

Emitted when `remote.getCurrentWebContents()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.

#### Event: 'remote-get-guest-web-contents'

Returns:

* `event` Event
* `guestWebContents` [WebContents](web-contents.md)

Emitted when `<webview>.getWebContents()` is called in the renderer process.
Calling `event.preventDefault()` will prevent the object from being returned.
Custom value can be returned by setting `event.returnValue`.

### Instance Methods

#### `contents.loadURL(url[, options])`
Expand Down
21 changes: 14 additions & 7 deletions lib/browser/api/web-contents.js
Expand Up @@ -369,13 +369,20 @@ WebContents.prototype._init = function () {
})
})

this.on('remote-require', (event, ...args) => {
app.emit('remote-require', event, this, ...args)
})

this.on('remote-get-global', (event, ...args) => {
app.emit('remote-get-global', event, this, ...args)
})
const forwardedEvents = [
'remote-require',
'remote-get-global',
'remote-get-builtin',
'remote-get-current-window',
'remote-get-current-web-contents',
'remote-get-guest-web-contents'
]

for (const eventName of forwardedEvents) {
this.on(eventName, (event, ...args) => {
app.emit(eventName, event, this, ...args)
})
}

deprecate.event(this, 'did-get-response-details', '-did-get-response-details')
deprecate.event(this, 'did-get-redirect-request', '-did-get-redirect-request')
Expand Down
75 changes: 60 additions & 15 deletions lib/browser/rpc-server.js
Expand Up @@ -296,42 +296,75 @@ handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, modu
const customEvent = eventBinding.createWithSender(event.sender)
event.sender.emit('remote-require', customEvent, moduleName)

if (customEvent.defaultPrevented) {
if (typeof customEvent.returnValue === 'undefined') {
throw new Error(`Invalid module: ${moduleName}`)
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.require('${moduleName}')`)
} else {
customEvent.returnValue = process.mainModule.require(moduleName)
}
} else {
customEvent.returnValue = process.mainModule.require(moduleName)
}

return valueToMeta(event.sender, contextId, customEvent.returnValue)
})

handleRemoteCommand('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, module) {
return valueToMeta(event.sender, contextId, electron[module])
handleRemoteCommand('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, moduleName) {
const customEvent = eventBinding.createWithSender(event.sender)
event.sender.emit('remote-get-builtin', customEvent, moduleName)

if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getBuiltin('${moduleName}')`)
} else {
customEvent.returnValue = electron[moduleName]
}
}

return valueToMeta(event.sender, contextId, customEvent.returnValue)
})

handleRemoteCommand('ELECTRON_BROWSER_GLOBAL', function (event, contextId, globalName) {
const customEvent = eventBinding.createWithSender(event.sender)
event.sender.emit('remote-get-global', customEvent, globalName)

if (customEvent.defaultPrevented) {
if (typeof customEvent.returnValue === 'undefined') {
throw new Error(`Invalid global: ${globalName}`)
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getGlobal('${globalName}')`)
} else {
customEvent.returnValue = global[globalName]
}
} else {
customEvent.returnValue = global[globalName]
}

return valueToMeta(event.sender, contextId, customEvent.returnValue)
})

handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WINDOW', function (event, contextId) {
return valueToMeta(event.sender, contextId, event.sender.getOwnerBrowserWindow())
const customEvent = eventBinding.createWithSender(event.sender)
event.sender.emit('remote-get-current-window', customEvent)

if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error('Blocked remote.getCurrentWindow()')
} else {
customEvent.returnValue = event.sender.getOwnerBrowserWindow()
}
}

return valueToMeta(event.sender, contextId, customEvent.returnValue)
})

handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event, contextId) {
return valueToMeta(event.sender, contextId, event.sender)
const customEvent = eventBinding.createWithSender(event.sender)
event.sender.emit('remote-get-current-web-contents', customEvent)

if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error('Blocked remote.getCurrentWebContents()')
} else {
customEvent.returnValue = event.sender
}
}

return valueToMeta(event.sender, contextId, customEvent.returnValue)
})

handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId, id, args) {
Expand Down Expand Up @@ -411,7 +444,19 @@ handleRemoteCommand('ELECTRON_BROWSER_CONTEXT_RELEASE', (event, contextId) => {

handleRemoteCommand('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId) {
const guest = guestViewManager.getGuestForWebContents(guestInstanceId, event.sender)
return valueToMeta(event.sender, contextId, guest)

const customEvent = eventBinding.createWithSender(event.sender)
event.sender.emit('remote-get-guest-web-contents', customEvent, guest)

if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getGuestForWebContents()`)
} else {
customEvent.returnValue = guest
}
}

return valueToMeta(event.sender, contextId, customEvent.returnValue)
})

// Implements window.close()
Expand Down
64 changes: 50 additions & 14 deletions spec/api-app-spec.js
Expand Up @@ -359,26 +359,62 @@ describe('app module', () => {
w = new BrowserWindow({ show: false })
})

it('should emit remote-require event when remote.require() is invoked', (done) => {
app.once('remote-require', (event, webContents, moduleName) => {
expect(webContents).to.equal(w.webContents)
expect(moduleName).to.equal('test')
done()
})
it('should emit remote-require event when remote.require() is invoked', async () => {
w = new BrowserWindow({ show: false })
w.loadURL('about:blank')
await w.loadURL('about:blank')

const promise = emittedOnce(app, 'remote-require')
w.webContents.executeJavaScript(`require('electron').remote.require('test')`)

const [, webContents, moduleName] = await promise
expect(webContents).to.equal(w.webContents)
expect(moduleName).to.equal('test')
})

it('should emit remote-get-global event when remote.getGlobal() is invoked', (done) => {
app.once('remote-get-global', (event, webContents, globalName) => {
expect(webContents).to.equal(w.webContents)
expect(globalName).to.equal('test')
done()
})
it('should emit remote-get-global event when remote.getGlobal() is invoked', async () => {
w = new BrowserWindow({ show: false })
w.loadURL('about:blank')
await w.loadURL('about:blank')

const promise = emittedOnce(app, 'remote-get-global')
w.webContents.executeJavaScript(`require('electron').remote.getGlobal('test')`)

const [, webContents, globalName] = await promise
expect(webContents).to.equal(w.webContents)
expect(globalName).to.equal('test')
})

it('should emit remote-get-builtin event when remote.getBuiltin() is invoked', async () => {
w = new BrowserWindow({ show: false })
await w.loadURL('about:blank')

const promise = emittedOnce(app, 'remote-get-builtin')
w.webContents.executeJavaScript(`require('electron').remote.app`)

const [, webContents, moduleName] = await promise
expect(webContents).to.equal(w.webContents)
expect(moduleName).to.equal('app')
})

it('should emit remote-get-current-window event when remote.getCurrentWindow() is invoked', async () => {
w = new BrowserWindow({ show: false })
await w.loadURL('about:blank')

const promise = emittedOnce(app, 'remote-get-current-window')
w.webContents.executeJavaScript(`require('electron').remote.getCurrentWindow()`)

const [, webContents] = await promise
expect(webContents).to.equal(w.webContents)
})

it('should emit remote-get-current-web-contents event when remote.getCurrentWebContents() is invoked', async () => {
w = new BrowserWindow({ show: false })
await w.loadURL('about:blank')

const promise = emittedOnce(app, 'remote-get-current-web-contents')
w.webContents.executeJavaScript(`require('electron').remote.getCurrentWebContents()`)

const [, webContents] = await promise
expect(webContents).to.equal(w.webContents)
})
})

Expand Down
46 changes: 42 additions & 4 deletions spec/api-remote-spec.js
Expand Up @@ -28,29 +28,43 @@ describe('remote module', () => {

afterEach(() => closeWindow(w).then(() => { w = null }))

describe('remote.getGlobal', () => {
describe('remote.getGlobal filtering', () => {
it('can return custom values', () => {
ipcRenderer.send('handle-next-remote-get-global', { test: 'Hello World!' })
expect(remote.getGlobal('test')).to.be.equal('Hello World!')
})

it('throws when no returnValue set', () => {
ipcRenderer.send('handle-next-remote-get-global')
expect(() => remote.getGlobal('process')).to.throw('Invalid global: process')
expect(() => remote.getGlobal('test')).to.throw(`Blocked remote.getGlobal('test')`)
})
})

describe('remote.require', () => {
describe('remote.getBuiltin filtering', () => {
it('can return custom values', () => {
ipcRenderer.send('handle-next-remote-get-builtin', { test: 'Hello World!' })
expect(remote.getBuiltin('test')).to.be.equal('Hello World!')
})

it('throws when no returnValue set', () => {
ipcRenderer.send('handle-next-remote-get-builtin')
expect(() => remote.getBuiltin('test')).to.throw(`Blocked remote.getBuiltin('test')`)
})
})

describe('remote.require filtering', () => {
it('can return custom values', () => {
ipcRenderer.send('handle-next-remote-require', { test: 'Hello World!' })
expect(remote.require('test')).to.be.equal('Hello World!')
})

it('throws when no returnValue set', () => {
ipcRenderer.send('handle-next-remote-require')
expect(() => remote.require('electron')).to.throw('Invalid module: electron')
expect(() => remote.require('test')).to.throw(`Blocked remote.require('test')`)
})
})

describe('remote.require', () => {
it('should returns same object for the same module', () => {
const dialog1 = remote.require('electron')
const dialog2 = remote.require('electron')
Expand Down Expand Up @@ -450,6 +464,30 @@ describe('remote module', () => {
})
})

describe('remote.getCurrentWindow filtering', () => {
it('can return custom value', () => {
ipcRenderer.send('handle-next-remote-get-current-window', 'Hello World!')
expect(remote.getCurrentWindow()).to.be.equal('Hello World!')
})

it('throws when no returnValue set', () => {
ipcRenderer.send('handle-next-remote-get-current-window')
expect(() => remote.getCurrentWindow()).to.throw('Blocked remote.getCurrentWindow()')
})
})

describe('remote.getCurrentWebContents filtering', () => {
it('can return custom value', () => {
ipcRenderer.send('handle-next-remote-get-current-web-contents', 'Hello World!')
expect(remote.getCurrentWebContents()).to.be.equal('Hello World!')
})

it('throws when no returnValue set', () => {
ipcRenderer.send('handle-next-remote-get-current-web-contents')
expect(() => remote.getCurrentWebContents()).to.throw('Blocked remote.getCurrentWebContents()')
})
})

describe('remote class', () => {
const cl = remote.require(path.join(fixtures, 'module', 'class.js'))
const base = cl.base
Expand Down

0 comments on commit e253c9b

Please sign in to comment.