feat: add remote.require() / remote.getGlobal() filtering (#15014)

This commit is contained in:
Milan Burda 2018-10-18 05:36:45 +02:00 коммит произвёл Samuel Attard
Родитель dffe4fdd4f
Коммит db37ab1039
10 изменённых файлов: 177 добавлений и 5 удалений

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) 2018 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/event_emitter.h"
#include "atom/common/node_includes.h"
#include "native_mate/dictionary.h"
namespace {
v8::Local<v8::Object> CreateWithSender(v8::Isolate* isolate,
v8::Local<v8::Object> sender) {
return mate::internal::CreateJSEvent(isolate, sender, nullptr, nullptr);
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
mate::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("createWithSender", &CreateWithSender);
}
} // namespace
NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_browser_event, Initialize)

Просмотреть файл

@ -36,6 +36,7 @@
V(atom_browser_debugger) \
V(atom_browser_dialog) \
V(atom_browser_download_item) \
V(atom_browser_event) \
V(atom_browser_global_shortcut) \
V(atom_browser_in_app_purchase) \
V(atom_browser_menu) \

Просмотреть файл

@ -399,6 +399,30 @@ non-minimized.
This event is guaranteed to be emitted after the `ready` event of `app`
gets emitted.
### Event: 'remote-require'
Returns:
* `event` Event
* `webContents` [WebContents](web-contents.md)
* `moduleName` String
Emitted when `remote.require()` 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-global'
Returns:
* `event` Event
* `webContents` [WebContents](web-contents.md)
* `globalName` String
Emitted when `remote.getGlobal()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will prevent the global from being returned.
Custom value can be returned by setting `event.returnValue`.
## Methods
The `app` object has the following methods:

Просмотреть файл

@ -663,6 +663,28 @@ Returns:
Emitted when the associated window logs a console message. Will not be emitted
for windows with *offscreen rendering* enabled.
#### Event: 'remote-require'
Returns:
* `event` Event
* `moduleName` String
Emitted when `remote.require()` 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-global'
Returns:
* `event` Event
* `globalName` String
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`.
### Instance Methods
#### `contents.loadURL(url[, options])`

Просмотреть файл

@ -133,6 +133,7 @@ filenames = {
"atom/browser/api/atom_api_dialog.cc",
"atom/browser/api/atom_api_download_item.cc",
"atom/browser/api/atom_api_download_item.h",
"atom/browser/api/atom_api_event.cc",
"atom/browser/api/atom_api_global_shortcut.cc",
"atom/browser/api/atom_api_global_shortcut.h",
"atom/browser/api/atom_api_in_app_purchase.cc",

Просмотреть файл

@ -338,6 +338,14 @@ 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)
})
deprecate.event(this, 'did-get-response-details', '-did-get-response-details')
deprecate.event(this, 'did-get-redirect-request', '-did-get-redirect-request')

Просмотреть файл

@ -7,6 +7,7 @@ const fs = require('fs')
const os = require('os')
const path = require('path')
const v8Util = process.atomBinding('v8_util')
const eventBinding = process.atomBinding('event')
const { isPromise } = electron
@ -280,16 +281,38 @@ const handleRemoteCommand = function (channel, handler) {
})
}
handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, module) {
return valueToMeta(event.sender, contextId, process.mainModule.require(module))
handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, moduleName) {
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}`)
}
} 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_GLOBAL', function (event, contextId, name) {
return valueToMeta(event.sender, contextId, global[name])
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}`)
}
} else {
customEvent.returnValue = global[globalName]
}
return valueToMeta(event.sender, contextId, customEvent.returnValue)
})
handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WINDOW', function (event, contextId) {

Просмотреть файл

@ -358,6 +358,28 @@ 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()
})
w = new BrowserWindow({ show: false })
w.loadURL('about:blank')
w.webContents.executeJavaScript(`require('electron').remote.require('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()
})
w = new BrowserWindow({ show: false })
w.loadURL('about:blank')
w.webContents.executeJavaScript(`require('electron').remote.getGlobal('test')`)
})
})
describe('app.setBadgeCount', () => {

Просмотреть файл

@ -1,11 +1,16 @@
'use strict'
const assert = require('assert')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const path = require('path')
const { closeWindow } = require('./window-helpers')
const { resolveGetters } = require('./assert-helpers')
const { remote } = require('electron')
const { remote, ipcRenderer } = require('electron')
const { expect } = chai
chai.use(dirtyChai)
const comparePaths = (path1, path2) => {
if (process.platform === 'win32') {
@ -22,7 +27,29 @@ describe('remote module', () => {
afterEach(() => closeWindow(w).then(() => { w = null }))
describe('remote.getGlobal', () => {
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')
})
})
describe('remote.require', () => {
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')
})
it('should returns same object for the same module', () => {
const dialog1 = remote.require('electron')
const dialog2 = remote.require('electron')

Просмотреть файл

@ -242,6 +242,24 @@ app.on('ready', function () {
})
})
ipcMain.on('handle-next-remote-require', function (event, modulesMap = {}) {
event.sender.once('remote-require', (event, moduleName) => {
event.preventDefault()
if (modulesMap.hasOwnProperty(moduleName)) {
event.returnValue = modulesMap[moduleName]
}
})
})
ipcMain.on('handle-next-remote-get-global', function (event, globalsMap = {}) {
event.sender.once('remote-get-global', (event, globalName) => {
event.preventDefault()
if (globalsMap.hasOwnProperty(globalName)) {
event.returnValue = globalsMap[globalName]
}
})
})
ipcMain.on('set-client-certificate-option', function (event, skip) {
app.once('select-client-certificate', function (event, webContents, url, list, callback) {
event.preventDefault()