feat: add webPreferences.enableRemoteModule option (#13028)
This commit is contained in:
parent
72db5ed7cb
commit
d3efc52745
36 changed files with 303 additions and 45 deletions
|
@ -1904,6 +1904,13 @@ v8::Local<v8::Value> WebContents::GetLastWebPreferences(
|
|||
return mate::ConvertToV8(isolate, *web_preferences->last_preference());
|
||||
}
|
||||
|
||||
bool WebContents::IsRemoteModuleEnabled() const {
|
||||
if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
|
||||
return web_preferences->IsRemoteModuleEnabled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> WebContents::GetOwnerBrowserWindow() const {
|
||||
if (owner_window())
|
||||
return BrowserWindow::From(isolate(), owner_window());
|
||||
|
@ -2074,6 +2081,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("_getPreloadPath", &WebContents::GetPreloadPath)
|
||||
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
|
||||
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
|
||||
.SetMethod("_isRemoteModuleEnabled", &WebContents::IsRemoteModuleEnabled)
|
||||
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
|
||||
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
|
||||
.SetMethod("unregisterServiceWorker",
|
||||
|
|
|
@ -248,6 +248,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
v8::Local<v8::Value> GetWebPreferences(v8::Isolate* isolate) const;
|
||||
v8::Local<v8::Value> GetLastWebPreferences(v8::Isolate* isolate) const;
|
||||
|
||||
bool IsRemoteModuleEnabled() const;
|
||||
|
||||
// Returns the owner window.
|
||||
v8::Local<v8::Value> GetOwnerBrowserWindow() const;
|
||||
|
||||
|
|
|
@ -171,6 +171,10 @@ bool WebContentsPreferences::GetPreference(const base::StringPiece& name,
|
|||
return GetAsString(&preference_, name, value);
|
||||
}
|
||||
|
||||
bool WebContentsPreferences::IsRemoteModuleEnabled() const {
|
||||
return IsEnabled(options::kEnableRemoteModule, true);
|
||||
}
|
||||
|
||||
bool WebContentsPreferences::GetPreloadPath(
|
||||
base::FilePath::StringType* path) const {
|
||||
DCHECK(path);
|
||||
|
@ -267,6 +271,10 @@ void WebContentsPreferences::AppendCommandLineSwitches(
|
|||
}
|
||||
}
|
||||
|
||||
// Whether to enable the remote module
|
||||
if (!IsRemoteModuleEnabled())
|
||||
command_line->AppendSwitch(switches::kDisableRemoteModule);
|
||||
|
||||
// Run Electron APIs and preload script in isolated world
|
||||
if (IsEnabled(options::kContextIsolation))
|
||||
command_line->AppendSwitch(switches::kContextIsolation);
|
||||
|
|
|
@ -55,6 +55,9 @@ class WebContentsPreferences
|
|||
// Return true if the particular preference value exists.
|
||||
bool GetPreference(const base::StringPiece& name, std::string* value) const;
|
||||
|
||||
// Whether to enable the remote module
|
||||
bool IsRemoteModuleEnabled() const;
|
||||
|
||||
// Returns the preload script path.
|
||||
bool GetPreloadPath(base::FilePath::StringType* path) const;
|
||||
|
||||
|
|
|
@ -110,6 +110,9 @@ const char kPreloadURL[] = "preloadURL";
|
|||
// Enable the node integration.
|
||||
const char kNodeIntegration[] = "nodeIntegration";
|
||||
|
||||
// Enable the remote module
|
||||
const char kEnableRemoteModule[] = "enableRemoteModule";
|
||||
|
||||
// Enable context isolation of Electron APIs and preload script
|
||||
const char kContextIsolation[] = "contextIsolation";
|
||||
|
||||
|
@ -193,6 +196,7 @@ const char kBackgroundColor[] = "background-color";
|
|||
const char kPreloadScript[] = "preload";
|
||||
const char kPreloadScripts[] = "preload-scripts";
|
||||
const char kNodeIntegration[] = "node-integration";
|
||||
const char kDisableRemoteModule[] = "disable-remote-module";
|
||||
const char kContextIsolation[] = "context-isolation";
|
||||
const char kGuestInstanceID[] = "guest-instance-id";
|
||||
const char kOpenerID[] = "opener-id";
|
||||
|
|
|
@ -58,6 +58,7 @@ extern const char kZoomFactor[];
|
|||
extern const char kPreloadScript[];
|
||||
extern const char kPreloadURL[];
|
||||
extern const char kNodeIntegration[];
|
||||
extern const char kEnableRemoteModule[];
|
||||
extern const char kContextIsolation[];
|
||||
extern const char kGuestInstanceID[];
|
||||
extern const char kExperimentalFeatures[];
|
||||
|
@ -97,6 +98,7 @@ extern const char kBackgroundColor[];
|
|||
extern const char kPreloadScript[];
|
||||
extern const char kPreloadScripts[];
|
||||
extern const char kNodeIntegration[];
|
||||
extern const char kDisableRemoteModule[];
|
||||
extern const char kContextIsolation[];
|
||||
extern const char kGuestInstanceID[];
|
||||
extern const char kOpenerID[];
|
||||
|
|
|
@ -79,6 +79,15 @@ std::vector<std::string> ParseSchemesCLISwitch(base::CommandLine* command_line,
|
|||
base::SPLIT_WANT_NONEMPTY);
|
||||
}
|
||||
|
||||
void SetHiddenValue(v8::Handle<v8::Context> context,
|
||||
const base::StringPiece& key,
|
||||
v8::Local<v8::Value> value) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::Private> privateKey =
|
||||
v8::Private::ForApi(isolate, mate::StringToV8(isolate, key));
|
||||
context->Global()->SetPrivate(context, privateKey, value);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RendererClientBase::RendererClientBase() {
|
||||
|
@ -108,10 +117,13 @@ void RendererClientBase::DidCreateScriptContext(
|
|||
auto context_id = base::StringPrintf(
|
||||
"%s-%" PRId64, renderer_client_id_.c_str(), ++next_context_id_);
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
v8::Local<v8::String> key = mate::StringToSymbol(isolate, "contextId");
|
||||
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
|
||||
v8::Local<v8::Value> value = mate::ConvertToV8(isolate, context_id);
|
||||
context->Global()->SetPrivate(context, private_key, value);
|
||||
SetHiddenValue(context, "contextId", mate::ConvertToV8(isolate, context_id));
|
||||
|
||||
auto* command_line = base::CommandLine::ForCurrentProcess();
|
||||
bool enableRemoteModule =
|
||||
!command_line->HasSwitch(switches::kDisableRemoteModule);
|
||||
SetHiddenValue(context, "enableRemoteModule",
|
||||
mate::ConvertToV8(isolate, enableRemoteModule));
|
||||
}
|
||||
|
||||
void RendererClientBase::AddRenderBindings(
|
||||
|
|
|
@ -270,6 +270,8 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
|||
are more limited. Read more about the option [here](sandbox-option.md).
|
||||
**Note:** This option is currently experimental and may change or be
|
||||
removed in future Electron releases.
|
||||
* `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module.
|
||||
Default is `true`.
|
||||
* `session` [Session](session.md#class-session) (optional) - Sets the session used by the
|
||||
page. Instead of passing the Session object directly, you can also choose to
|
||||
use the `partition` option instead, which accepts a partition string. When
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
In the renderer process context it depends on the [`remote`](remote.md) module on Linux,
|
||||
it is therefore not available when this module is disabled.
|
||||
|
||||
The following example shows how to write a string to the clipboard:
|
||||
|
||||
```javascript
|
||||
|
|
|
@ -24,6 +24,10 @@ win.loadURL('https://github.com')
|
|||
**Note:** For the reverse (access the renderer process from the main process),
|
||||
you can use [webContents.executeJavaScript](web-contents.md#contentsexecutejavascriptcode-usergesture-callback).
|
||||
|
||||
**Note:** The remote module can be disabled for security reasons in the following contexts:
|
||||
- [`BrowserWindow`](browser-window.md) - by setting the `enableRemoteModule` option to `false`.
|
||||
- [`<webview>`](webview-tag.md) - by setting the `enableremotemodule` attribute to `false`.
|
||||
|
||||
## Remote Objects
|
||||
|
||||
Each object (including functions) returned by the `remote` module represents an
|
||||
|
@ -180,7 +184,7 @@ belongs.
|
|||
**Note:** Do not use `removeAllListeners` on [`BrowserWindow`](browser-window.md).
|
||||
Use of this can remove all [`blur`](https://developer.mozilla.org/en-US/docs/Web/Events/blur)
|
||||
listeners, disable click events on touch bar buttons, and other unintended
|
||||
consequences.
|
||||
consequences.
|
||||
|
||||
### `remote.getCurrentWebContents()`
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer
|
|||
You cannot require or use this module until the `ready` event of the `app`
|
||||
module is emitted.
|
||||
|
||||
In the renderer process context it depends on the [`remote`](remote.md) module,
|
||||
it is therefore not available when this module is disabled.
|
||||
|
||||
`screen` is an [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).
|
||||
|
||||
**Note:** In the renderer / DevTools, `window.screen` is a reserved DOM
|
||||
|
|
|
@ -126,6 +126,15 @@ integration and can use node APIs like `require` and `process` to access low
|
|||
level system resources. Node integration is disabled by default in the guest
|
||||
page.
|
||||
|
||||
### `enableremotemodule`
|
||||
|
||||
```html
|
||||
<webview src="http://www.google.com/" enableremotemodule="false"></webview>
|
||||
```
|
||||
|
||||
When this attribute is `false` the guest page in `webview` will not have access
|
||||
to the [`remote`](remote.md) module. The remote module is avaiable by default.
|
||||
|
||||
### `plugins`
|
||||
|
||||
```html
|
||||
|
@ -613,6 +622,9 @@ Shows pop-up dictionary that searches the selected word on the page.
|
|||
Returns [`WebContents`](web-contents.md) - The web contents associated with
|
||||
this `webview`.
|
||||
|
||||
It depends on the [`remote`](remote.md) module,
|
||||
it is therefore not available when this module is disabled.
|
||||
|
||||
## DOM events
|
||||
|
||||
The following DOM events are available to the `webview` tag:
|
||||
|
|
|
@ -68,6 +68,7 @@ filenames = {
|
|||
"lib/renderer/init.js",
|
||||
"lib/renderer/inspector.js",
|
||||
"lib/renderer/ipc-renderer-internal.js",
|
||||
"lib/renderer/remote.js",
|
||||
"lib/renderer/override.js",
|
||||
"lib/renderer/security-warnings.js",
|
||||
"lib/renderer/web-frame-init.js",
|
||||
|
|
|
@ -209,6 +209,7 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||
const webPreferences = {
|
||||
guestInstanceId: guestInstanceId,
|
||||
nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false,
|
||||
enableRemoteModule: params.enableremotemodule,
|
||||
plugins: params.plugins,
|
||||
zoomFactor: embedder._getZoomFactor(),
|
||||
webSecurity: !params.disablewebsecurity,
|
||||
|
@ -243,6 +244,7 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
|
|||
['javascript', false],
|
||||
['nativeWindowOpen', true],
|
||||
['nodeIntegration', false],
|
||||
['enableRemoteModule', false],
|
||||
['sandbox', true]
|
||||
])
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ const inheritedWebPreferences = new Map([
|
|||
['javascript', false],
|
||||
['nativeWindowOpen', true],
|
||||
['nodeIntegration', false],
|
||||
['enableRemoteModule', false],
|
||||
['sandbox', true],
|
||||
['webviewTag', false]
|
||||
])
|
||||
|
@ -195,7 +196,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, frameName,
|
|||
const options = {}
|
||||
|
||||
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
|
||||
const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload', 'javascript', 'contextIsolation', 'webviewTag']
|
||||
const webPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'preload', 'javascript', 'contextIsolation', 'webviewTag']
|
||||
const disposition = 'new-window'
|
||||
|
||||
// Used to store additional features
|
||||
|
|
|
@ -263,11 +263,17 @@ const callFunction = function (event, contextId, func, caller, args) {
|
|||
const handleRemoteCommand = function (channel, handler) {
|
||||
ipcMain.on(channel, (event, contextId, ...args) => {
|
||||
let returnValue
|
||||
if (!event.sender._isRemoteModuleEnabled()) {
|
||||
event.returnValue = null
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
returnValue = handler(event, contextId, ...args)
|
||||
} catch (error) {
|
||||
returnValue = exceptionToMeta(event.sender, contextId, error)
|
||||
}
|
||||
|
||||
if (returnValue !== undefined) {
|
||||
event.returnValue = returnValue
|
||||
}
|
||||
|
@ -453,12 +459,28 @@ const crashReporterInit = function (options) {
|
|||
}
|
||||
}
|
||||
|
||||
ipcMain.on('ELECTRON_CRASH_REPORTER_INIT', function (event, options) {
|
||||
const setReturnValue = function (event, getValue) {
|
||||
try {
|
||||
event.returnValue = [null, crashReporterInit(options)]
|
||||
event.returnValue = [null, getValue()]
|
||||
} catch (error) {
|
||||
event.returnValue = [errorUtils.serialize(error)]
|
||||
}
|
||||
}
|
||||
|
||||
ipcMain.on('ELECTRON_CRASH_REPORTER_INIT', function (event, options) {
|
||||
setReturnValue(event, () => crashReporterInit(options))
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_GET_LAST_WEB_PREFERENCES', function (event) {
|
||||
setReturnValue(event, () => event.sender.getLastWebPreferences())
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_CLIPBOARD_READ_FIND_TEXT', function (event) {
|
||||
setReturnValue(event, () => electron.clipboard.readFindText())
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_CLIPBOARD_WRITE_FIND_TEXT', function (event, text) {
|
||||
setReturnValue(event, () => electron.clipboard.writeFindText(text))
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
||||
|
@ -475,6 +497,7 @@ ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
|||
event.returnValue = {
|
||||
preloadSrc,
|
||||
preloadError,
|
||||
isRemoteModuleEnabled: event.sender._isRemoteModuleEnabled(),
|
||||
process: {
|
||||
arch: process.arch,
|
||||
platform: process.platform,
|
||||
|
@ -484,11 +507,3 @@ ipcMain.on('ELECTRON_BROWSER_SANDBOX_LOAD', function (event) {
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('ELECTRON_BROWSER_GET_LAST_WEB_PREFERENCES', function (event) {
|
||||
try {
|
||||
event.returnValue = [null, event.sender.getLastWebPreferences()]
|
||||
} catch (error) {
|
||||
event.returnValue = [errorUtils.serialize(error)]
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,15 +2,29 @@
|
|||
|
||||
if (process.platform === 'linux' && process.type === 'renderer') {
|
||||
// On Linux we could not access clipboard in renderer process.
|
||||
module.exports = require('electron').remote.clipboard
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('clipboard').clipboard
|
||||
} else {
|
||||
const clipboard = process.atomBinding('clipboard')
|
||||
|
||||
// Read/write to find pasteboard over IPC since only main process is notified
|
||||
// of changes
|
||||
if (process.platform === 'darwin' && process.type === 'renderer') {
|
||||
clipboard.readFindText = require('electron').remote.clipboard.readFindText
|
||||
clipboard.writeFindText = require('electron').remote.clipboard.writeFindText
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
const errorUtils = require('@electron/internal/common/error-utils')
|
||||
|
||||
const invoke = function (command, ...args) {
|
||||
const [ error, result ] = ipcRenderer.sendSync(command, ...args)
|
||||
|
||||
if (error) {
|
||||
throw errorUtils.deserialize(error)
|
||||
} else {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
clipboard.readFindText = (...args) => invoke('ELECTRON_BROWSER_CLIPBOARD_READ_FIND_TEXT', ...args)
|
||||
clipboard.writeFindText = (...args) => invoke('ELECTRON_BROWSER_CLIPBOARD_WRITE_FIND_TEXT', ...args)
|
||||
}
|
||||
|
||||
module.exports = clipboard
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
const features = process.atomBinding('features')
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
|
||||
const enableRemoteModule = v8Util.getHiddenValue(global, 'enableRemoteModule')
|
||||
|
||||
// Renderer side modules, please sort alphabetically.
|
||||
// A module is `enabled` if there is no explicit condition defined.
|
||||
|
@ -11,8 +14,8 @@ module.exports = [
|
|||
file: 'desktop-capturer',
|
||||
enabled: features.isDesktopCapturerEnabled()
|
||||
},
|
||||
{ name: 'ipcRenderer', file: 'ipc-renderer', enabled: true },
|
||||
{ name: 'remote', file: 'remote', enabled: true },
|
||||
{ name: 'screen', file: 'screen', enabled: true },
|
||||
{ name: 'webFrame', file: 'web-frame', enabled: true }
|
||||
{ name: 'ipcRenderer', file: 'ipc-renderer' },
|
||||
{ name: 'remote', file: 'remote', enabled: enableRemoteModule },
|
||||
{ name: 'screen', file: 'screen' },
|
||||
{ name: 'webFrame', file: 'web-frame' }
|
||||
]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = require('electron').remote.screen
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('screen').screen
|
||||
|
|
10
lib/renderer/remote.js
Normal file
10
lib/renderer/remote.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
'use strict'
|
||||
|
||||
const { remote } = require('electron')
|
||||
|
||||
exports.getRemoteForUsage = function (usage) {
|
||||
if (!remote) {
|
||||
throw new Error(`${usage} requires remote, which is not enabled`)
|
||||
}
|
||||
return remote
|
||||
}
|
|
@ -248,6 +248,20 @@ class WebPreferencesAttribute extends WebViewAttribute {
|
|||
}
|
||||
}
|
||||
|
||||
class EnableRemoteModuleAttribute extends WebViewAttribute {
|
||||
constructor (webViewImpl) {
|
||||
super(webViewConstants.ATTRIBUTE_ENABLEREMOTEMODULE, webViewImpl)
|
||||
}
|
||||
|
||||
getValue () {
|
||||
return this.webViewImpl.webviewNode.getAttribute(this.name) !== 'false'
|
||||
}
|
||||
|
||||
setValue (value) {
|
||||
this.webViewImpl.webviewNode.setAttribute(this.name, value ? 'true' : 'false')
|
||||
}
|
||||
}
|
||||
|
||||
// Sets up all of the webview attributes.
|
||||
WebViewImpl.prototype.setupWebViewAttributes = function () {
|
||||
this.attributes = {}
|
||||
|
@ -259,6 +273,7 @@ WebViewImpl.prototype.setupWebViewAttributes = function () {
|
|||
this.attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this)
|
||||
this.attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this)
|
||||
this.attributes[webViewConstants.ATTRIBUTE_ALLOWPOPUPS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_ALLOWPOPUPS, this)
|
||||
this.attributes[webViewConstants.ATTRIBUTE_ENABLEREMOTEMODULE] = new EnableRemoteModuleAttribute(this)
|
||||
this.attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this)
|
||||
this.attributes[webViewConstants.ATTRIBUTE_BLINKFEATURES] = new BlinkFeaturesAttribute(this)
|
||||
this.attributes[webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES] = new DisableBlinkFeaturesAttribute(this)
|
||||
|
|
|
@ -7,6 +7,7 @@ module.exports = {
|
|||
ATTRIBUTE_SRC: 'src',
|
||||
ATTRIBUTE_HTTPREFERRER: 'httpreferrer',
|
||||
ATTRIBUTE_NODEINTEGRATION: 'nodeintegration',
|
||||
ATTRIBUTE_ENABLEREMOTEMODULE: 'enableremotemodule',
|
||||
ATTRIBUTE_PLUGINS: 'plugins',
|
||||
ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity',
|
||||
ATTRIBUTE_ALLOWPOPUPS: 'allowpopups',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
const { remote, webFrame } = require('electron')
|
||||
const { webFrame } = require('electron')
|
||||
|
||||
const v8Util = process.atomBinding('v8_util')
|
||||
const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
|
||||
|
@ -337,6 +337,8 @@ const registerWebViewElement = function () {
|
|||
|
||||
// WebContents associated with this webview.
|
||||
proto.getWebContents = function () {
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
const remote = getRemoteForUsage('getWebContents()')
|
||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
||||
if (!internal.guestInstanceId) {
|
||||
internal.createGuestSync()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = require('electron').remote.require('child_process')
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('child_process').require('child_process')
|
||||
|
|
|
@ -6,6 +6,7 @@ for (const {
|
|||
name,
|
||||
load,
|
||||
enabled = true,
|
||||
configurable = false,
|
||||
private: isPrivate = false
|
||||
} of moduleList) {
|
||||
if (!enabled) {
|
||||
|
@ -13,6 +14,7 @@ for (const {
|
|||
}
|
||||
|
||||
Object.defineProperty(exports, name, {
|
||||
configurable,
|
||||
enumerable: !isPrivate,
|
||||
get: load
|
||||
})
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = require('electron').remote.require('fs')
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('fs').require('fs')
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = require('electron').remote.require('os')
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('os').require('os')
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = require('electron').remote.require('path')
|
||||
const { getRemoteForUsage } = require('@electron/internal/renderer/remote')
|
||||
module.exports = getRemoteForUsage('path').require('path')
|
||||
|
|
|
@ -16,21 +16,28 @@ module.exports = [
|
|||
name: 'ipcRenderer',
|
||||
load: () => require('@electron/internal/renderer/api/ipc-renderer')
|
||||
},
|
||||
{
|
||||
name: 'isPromise',
|
||||
load: () => require('@electron/internal/common/api/is-promise'),
|
||||
private: true
|
||||
},
|
||||
{
|
||||
name: 'nativeImage',
|
||||
load: () => require('@electron/internal/common/api/native-image')
|
||||
},
|
||||
{
|
||||
name: 'remote',
|
||||
configurable: true, // will be configured in init.js
|
||||
load: () => require('@electron/internal/renderer/api/remote')
|
||||
},
|
||||
{
|
||||
name: 'webFrame',
|
||||
load: () => require('@electron/internal/renderer/api/web-frame')
|
||||
},
|
||||
// The internal modules, invisible unless you know their names.
|
||||
{
|
||||
name: 'deprecate',
|
||||
load: () => require('@electron/internal/common/api/deprecate'),
|
||||
private: true
|
||||
},
|
||||
{
|
||||
name: 'isPromise',
|
||||
load: () => require('@electron/internal/common/api/is-promise'),
|
||||
private: true
|
||||
}
|
||||
]
|
||||
|
|
|
@ -63,9 +63,21 @@ ipcNative.onExit = function () {
|
|||
}
|
||||
|
||||
const {
|
||||
preloadSrc, preloadError, process: processProps
|
||||
preloadSrc, preloadError, isRemoteModuleEnabled, process: processProps
|
||||
} = ipcRenderer.sendSync('ELECTRON_BROWSER_SANDBOX_LOAD')
|
||||
|
||||
const makePropertyNonConfigurable = function (object, name) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(electron, name)
|
||||
descriptor.configurable = false
|
||||
Object.defineProperty(electron, name, descriptor)
|
||||
}
|
||||
|
||||
if (isRemoteModuleEnabled) {
|
||||
makePropertyNonConfigurable(electron, 'remote')
|
||||
} else {
|
||||
delete electron.remote
|
||||
}
|
||||
|
||||
require('@electron/internal/renderer/web-frame-init')()
|
||||
|
||||
// Pass different process object to the preload script(which should not have
|
||||
|
|
|
@ -1396,6 +1396,46 @@ describe('BrowserWindow module', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('"enableRemoteModule" option', () => {
|
||||
const generateSpecs = (description, sandbox) => {
|
||||
describe(description, () => {
|
||||
const preload = path.join(fixtures, 'module', 'preload-remote.js')
|
||||
|
||||
it('enables the remote module by default', async () => {
|
||||
const w = await openTheWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
preload,
|
||||
sandbox
|
||||
}
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'blank.html'))
|
||||
const [, remote] = await emittedOnce(ipcMain, 'remote')
|
||||
expect(remote).to.equal('object')
|
||||
})
|
||||
|
||||
it('disables the remote module when false', async () => {
|
||||
const w = await openTheWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
preload,
|
||||
sandbox,
|
||||
enableRemoteModule: false
|
||||
}
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'blank.html'))
|
||||
const [, remote] = await emittedOnce(ipcMain, 'remote')
|
||||
expect(remote).to.equal('undefined')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
generateSpecs('without sandbox', false)
|
||||
generateSpecs('with sandbox', true)
|
||||
})
|
||||
|
||||
describe('"sandbox" option', () => {
|
||||
function waitForEvents (emitter, events, callback) {
|
||||
let count = events.length
|
||||
|
|
|
@ -195,6 +195,11 @@ describe('crashReporter module', () => {
|
|||
preload: path.join(fixtures, 'module', 'preload-sandbox.js')
|
||||
}
|
||||
})
|
||||
generateSpecs('with remote module disabled', {
|
||||
webPreferences: {
|
||||
enableRemoteModule: false
|
||||
}
|
||||
})
|
||||
|
||||
describe('getProductName', () => {
|
||||
it('returns the product name if one is specified', () => {
|
||||
|
|
8
spec/fixtures/module/preload-disable-remote.js
vendored
Normal file
8
spec/fixtures/module/preload-disable-remote.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
setImmediate(function () {
|
||||
try {
|
||||
const { remote } = require('electron')
|
||||
console.log(JSON.stringify(typeof remote))
|
||||
} catch (e) {
|
||||
console.log(e.message)
|
||||
}
|
||||
})
|
5
spec/fixtures/module/preload-remote.js
vendored
Normal file
5
spec/fixtures/module/preload-remote.js
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
const { ipcRenderer, remote } = require('electron')
|
||||
|
||||
window.onload = function () {
|
||||
ipcRenderer.send('remote', typeof remote)
|
||||
}
|
|
@ -68,7 +68,7 @@ describe('security warnings', () => {
|
|||
w.loadURL(`http://127.0.0.1:8881/base-page-security.html`)
|
||||
})
|
||||
|
||||
const generateSpecs = (description, sandbox) => {
|
||||
const generateSpecs = (description, webPreferences) => {
|
||||
describe(description, () => {
|
||||
it('should warn about disabled webSecurity', (done) => {
|
||||
w = new BrowserWindow({
|
||||
|
@ -76,7 +76,7 @@ describe('security warnings', () => {
|
|||
webPreferences: {
|
||||
webSecurity: false,
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
w.webContents.once('console-message', (e, level, message) => {
|
||||
|
@ -92,7 +92,7 @@ describe('security warnings', () => {
|
|||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -111,7 +111,7 @@ describe('security warnings', () => {
|
|||
webPreferences: {
|
||||
allowRunningInsecureContent: true,
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
w.webContents.once('console-message', (e, level, message) => {
|
||||
|
@ -128,7 +128,7 @@ describe('security warnings', () => {
|
|||
webPreferences: {
|
||||
experimentalFeatures: true,
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
w.webContents.once('console-message', (e, level, message) => {
|
||||
|
@ -145,7 +145,7 @@ describe('security warnings', () => {
|
|||
webPreferences: {
|
||||
enableBlinkFeatures: ['my-cool-feature'],
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
w.webContents.once('console-message', (e, level, message) => {
|
||||
|
@ -161,7 +161,7 @@ describe('security warnings', () => {
|
|||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
w.webContents.once('console-message', (e, level, message) => {
|
||||
|
@ -177,7 +177,7 @@ describe('security warnings', () => {
|
|||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
sandbox
|
||||
...webPreferences
|
||||
}
|
||||
})
|
||||
w.webContents.once('console-message', (e, level, message) => {
|
||||
|
@ -191,6 +191,7 @@ describe('security warnings', () => {
|
|||
})
|
||||
}
|
||||
|
||||
generateSpecs('without sandbox', false)
|
||||
generateSpecs('with sandbox', true)
|
||||
generateSpecs('without sandbox', {})
|
||||
generateSpecs('with sandbox', { sandbox: true })
|
||||
generateSpecs('with remote module disabled', { enableRemoteModule: false })
|
||||
})
|
||||
|
|
|
@ -219,6 +219,41 @@ describe('<webview> tag', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describe('enableremotemodule attribute', () => {
|
||||
const generateSpecs = (description, sandbox) => {
|
||||
describe(description, () => {
|
||||
const preload = `${fixtures}/module/preload-disable-remote.js`
|
||||
const src = `file://${fixtures}/api/blank.html`
|
||||
|
||||
it('enables the remote module by default', async () => {
|
||||
const message = await startLoadingWebViewAndWaitForMessage(webview, {
|
||||
preload,
|
||||
src,
|
||||
sandbox
|
||||
})
|
||||
|
||||
const typeOfRemote = JSON.parse(message)
|
||||
expect(typeOfRemote).to.equal('object')
|
||||
})
|
||||
|
||||
it('disables the remote module when false', async () => {
|
||||
const message = await startLoadingWebViewAndWaitForMessage(webview, {
|
||||
preload,
|
||||
src,
|
||||
sandbox,
|
||||
enableremotemodule: false
|
||||
})
|
||||
|
||||
const typeOfRemote = JSON.parse(message)
|
||||
expect(typeOfRemote).to.equal('undefined')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
generateSpecs('without sandbox', false)
|
||||
generateSpecs('with sandbox', true)
|
||||
})
|
||||
|
||||
describe('preload attribute', () => {
|
||||
it('loads the script before other scripts in window', async () => {
|
||||
const message = await startLoadingWebViewAndWaitForMessage(webview, {
|
||||
|
@ -506,6 +541,17 @@ describe('<webview> tag', function () {
|
|||
})
|
||||
})
|
||||
|
||||
it('can disable the remote module', async () => {
|
||||
const message = await startLoadingWebViewAndWaitForMessage(webview, {
|
||||
preload: `${fixtures}/module/preload-disable-remote.js`,
|
||||
src: `file://${fixtures}/api/blank.html`,
|
||||
webpreferences: 'enableRemoteModule=no'
|
||||
})
|
||||
|
||||
const typeOfRemote = JSON.parse(message)
|
||||
expect(typeOfRemote).to.equal('undefined')
|
||||
})
|
||||
|
||||
it('can disables web security and enable nodeintegration', async () => {
|
||||
const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js')
|
||||
const src = `<script src='file://${jqueryPath}'></script> <script>console.log(typeof require);</script>`
|
||||
|
|
Loading…
Reference in a new issue