chore: remove deprecated remote module (#25734)

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
This commit is contained in:
Milan Burda 2021-03-10 02:12:40 +01:00 коммит произвёл GitHub
Родитель d274df7e3a
Коммит 5b205731f6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
75 изменённых файлов: 18 добавлений и 3650 удалений

6
.github/CODEOWNERS поставляемый
Просмотреть файл

@ -13,9 +13,3 @@ DEPS @electron/wg-upgrades
# Security WG
/lib/browser/rpc-server.ts @electron/wg-security
# Remote Change Disliker
/lib/browser/remote/ @nornagon
/lib/renderer/remote/ @nornagon
/lib/renderer/api/remote.ts @nornagon
/docs/api/remote.md @nornagon

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

@ -61,13 +61,6 @@ module.exports = ({
);
}
if (defines.ENABLE_REMOTE_MODULE === 'false') {
ignoredModules.push(
'@electron/internal/browser/remote/server',
'@electron/internal/renderer/api/remote'
);
}
if (defines.ENABLE_VIEWS_API === 'false') {
ignoredModules.push(
'@electron/internal/browser/api/views/image-view.js'

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

@ -12,7 +12,6 @@ buildflag_header("buildflags") {
"ENABLE_DESKTOP_CAPTURER=$enable_desktop_capturer",
"ENABLE_RUN_AS_NODE=$enable_run_as_node",
"ENABLE_OSR=$enable_osr",
"ENABLE_REMOTE_MODULE=$enable_remote_module",
"ENABLE_VIEWS_API=$enable_views_api",
"ENABLE_PDF_VIEWER=$enable_pdf_viewer",
"ENABLE_TTS=$enable_tts",

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

@ -10,8 +10,6 @@ declare_args() {
enable_osr = true
enable_remote_module = true
enable_views_api = true
enable_pdf_viewer = true

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

@ -52,8 +52,7 @@ async function createWindow () {
webPreferences: {
preload: path.resolve(__dirname, 'preload.js'),
contextIsolation: true,
sandbox: true,
enableRemoteModule: false
sandbox: true
},
useContentSize: true,
show: false

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

@ -146,7 +146,6 @@ These individual tutorials expand on topics discussed in the guide above.
* [contextBridge](api/context-bridge.md)
* [desktopCapturer](api/desktop-capturer.md)
* [ipcRenderer](api/ipc-renderer.md)
* [remote](api/remote.md)
* [webFrame](api/web-frame.md)
### Modules for Both Processes:

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

@ -507,64 +507,6 @@ Returns:
Emitted when `desktopCapturer.getSources()` is called in the renderer process of `webContents`.
Calling `event.preventDefault()` will make it return empty sources.
### Event: 'remote-require' _Deprecated_
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' _Deprecated_
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`.
### Event: 'remote-get-builtin' _Deprecated_
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' _Deprecated_
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' _Deprecated_
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`.
## Methods
The `app` object has the following methods:

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

@ -273,8 +273,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
OS-level sandbox and disabling the Node.js engine. This is not the same as
the `nodeIntegration` option and the APIs available to the preload script
are more limited. Read more about the option [here](sandbox-option.md).
* `enableRemoteModule` Boolean (optional) - Whether to enable the [`remote`](remote.md) module.
Default is `false`.
* `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

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

@ -66,11 +66,6 @@ Forces the maximum disk space to be used by the disk cache, in bytes.
Enables caller stack logging for the following APIs (filtering events):
* `desktopCapturer.getSources()` / `desktop-capturer-get-sources`
* `remote.require()` / `remote-require`
* `remote.getGlobal()` / `remote-get-builtin`
* `remote.getBuiltin()` / `remote-get-global`
* `remote.getCurrentWindow()` / `remote-get-current-window`
* `remote.getCurrentWebContents()` / `remote-get-current-web-contents`
### --enable-logging

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

@ -1,217 +0,0 @@
# remote
> Use main process modules from the renderer process.
Process: [Renderer](../glossary.md#renderer-process)
> ⚠️ WARNING ⚠️
> The `remote` module is [deprecated](https://github.com/electron/electron/issues/21408).
> Instead of `remote`, use [`ipcRenderer`](ipc-renderer.md) and
> [`ipcMain`](ipc-main.md).
>
> Read more about why the `remote` module is deprecated [here](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31).
>
> If you still want to use `remote` despite the performance and security
> concerns, see [@electron/remote](https://github.com/electron/remote).
The `remote` module provides a simple way to do inter-process communication
(IPC) between the renderer process (web page) and the main process.
In Electron, GUI-related modules (such as `dialog`, `menu` etc.) are only
available in the main process, not in the renderer process. In order to use them
from the renderer process, the `ipc` module is necessary to send inter-process
messages to the main process. With the `remote` module, you can invoke methods
of the main process object without explicitly sending inter-process messages,
similar to Java's [RMI][rmi]. An example of creating a browser window from a
renderer process:
```javascript
const { BrowserWindow } = require('electron').remote
const win = new BrowserWindow({ width: 800, height: 600 })
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).
**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
object in the main process (we call it a remote object or remote function).
When you invoke methods of a remote object, call a remote function, or create
a new object with the remote constructor (function), you are actually sending
synchronous inter-process messages.
In the example above, both [`BrowserWindow`](browser-window.md) and `win` were remote objects and
`new BrowserWindow` didn't create a `BrowserWindow` object in the renderer
process. Instead, it created a `BrowserWindow` object in the main process and
returned the corresponding remote object in the renderer process, namely the
`win` object.
**Note:** Only [enumerable properties][enumerable-properties] which are present
when the remote object is first referenced are accessible via remote.
**Note:** Arrays and Buffers are copied over IPC when accessed via the `remote`
module. Modifying them in the renderer process does not modify them in the main
process and vice versa.
## Lifetime of Remote Objects
Electron makes sure that as long as the remote object in the renderer process
lives (in other words, has not been garbage collected), the corresponding object
in the main process will not be released. When the remote object has been
garbage collected, the corresponding object in the main process will be
dereferenced.
If the remote object is leaked in the renderer process (e.g. stored in a map but
never freed), the corresponding object in the main process will also be leaked,
so you should be very careful not to leak remote objects.
Primary value types like strings and numbers, however, are sent by copy.
## Passing callbacks to the main process
Code in the main process can accept callbacks from the renderer - for instance
the `remote` module - but you should be extremely careful when using this
feature.
First, in order to avoid deadlocks, the callbacks passed to the main process
are called asynchronously. You should not expect the main process to
get the return value of the passed callbacks.
For instance you can't use a function from the renderer process in an
`Array.map` called in the main process:
```javascript
// main process mapNumbers.js
exports.withRendererCallback = (mapper) => {
return [1, 2, 3].map(mapper)
}
exports.withLocalCallback = () => {
return [1, 2, 3].map(x => x + 1)
}
```
```javascript
// renderer process
const mapNumbers = require('electron').remote.require('./mapNumbers')
const withRendererCb = mapNumbers.withRendererCallback(x => x + 1)
const withLocalCb = mapNumbers.withLocalCallback()
console.log(withRendererCb, withLocalCb)
// [undefined, undefined, undefined], [2, 3, 4]
```
As you can see, the renderer callback's synchronous return value was not as
expected, and didn't match the return value of an identical callback that lives
in the main process.
Second, the callbacks passed to the main process will persist until the
main process garbage-collects them.
For example, the following code seems innocent at first glance. It installs a
callback for the `close` event on a remote object:
```javascript
require('electron').remote.getCurrentWindow().on('close', () => {
// window was closed...
})
```
But remember the callback is referenced by the main process until you
explicitly uninstall it. If you do not, each time you reload your window the
callback will be installed again, leaking one callback for each restart.
To make things worse, since the context of previously installed callbacks has
been released, exceptions will be raised in the main process when the `close`
event is emitted.
To avoid this problem, ensure you clean up any references to renderer callbacks
passed to the main process. This involves cleaning up event handlers, or
ensuring the main process is explicitly told to dereference callbacks that came
from a renderer process that is exiting.
## Accessing built-in modules in the main process
The built-in modules in the main process are added as getters in the `remote`
module, so you can use them directly like the `electron` module.
```javascript
const app = require('electron').remote.app
console.log(app)
```
## Methods
The `remote` module has the following methods:
### `remote.getCurrentWindow()`
Returns [`BrowserWindow`](browser-window.md) - The window to which this web page
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.
### `remote.getCurrentWebContents()`
Returns [`WebContents`](web-contents.md) - The web contents of this web page.
### `remote.getGlobal(name)`
* `name` String
Returns `any` - The global variable of `name` (e.g. `global[name]`) in the main
process.
## Properties
### `remote.require`
A `NodeJS.Require` function equivalent to `require(module)` in the main process.
Modules specified by their relative path will resolve relative to the entrypoint
of the main process.
e.g.
```sh
project/
├── main
│   ├── foo.js
│   └── index.js
├── package.json
└── renderer
└── index.js
```
```js
// main process: main/index.js
const { app } = require('electron')
app.whenReady().then(() => { /* ... */ })
```
```js
// some relative module: main/foo.js
module.exports = 'bar'
```
```js
// renderer process: renderer/index.js
const foo = require('electron').remote.require('./foo') // bar
```
### `remote.process` _Readonly_
A `NodeJS.Process` object. The `process` object in the main process. This is the same as
`remote.getGlobal('process')` but is cached.
[rmi]: https://en.wikipedia.org/wiki/Java_remote_method_invocation
[enumerable-properties]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties

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

@ -839,59 +839,6 @@ Returns:
Emitted when `desktopCapturer.getSources()` is called in the renderer process.
Calling `event.preventDefault()` will make it return empty sources.
#### Event: 'remote-require' _Deprecated_
Returns:
* `event` IpcMainEvent
* `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' _Deprecated_
Returns:
* `event` IpcMainEvent
* `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`.
#### Event: 'remote-get-builtin' _Deprecated_
Returns:
* `event` IpcMainEvent
* `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' _Deprecated_
Returns:
* `event` IpcMainEvent
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' _Deprecated_
Returns:
* `event` IpcMainEvent
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: 'preferred-size-changed'
Returns:

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

@ -130,15 +130,6 @@ inside the `webview`. All your preloads will load for every iframe, you can
use `process.isMainFrame` to determine if you are in the main frame or not.
This option is disabled by default in the guest page.
### `enableremotemodule`
```html
<webview src="http://www.google.com/" enableremotemodule="false"></webview>
```
A `Boolean`. When this attribute is `false` the guest page in `webview` will not have access
to the [`remote`](remote.md) module. The remote module is unavailable by default.
### `plugins`
```html

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

@ -44,7 +44,7 @@ Chromium shared library and Node.js. Vulnerabilities affecting these components
may impact the security of your application. By updating Electron to the latest
version, you ensure that critical vulnerabilities (such as *nodeIntegration bypasses*)
are already patched and cannot be exploited in your application. For more information,
see "[Use a current version of Electron](#17-use-a-current-version-of-electron)".
see "[Use a current version of Electron](#15-use-a-current-version-of-electron)".
* **Evaluate your dependencies.** While NPM provides half a million reusable packages,
it is your responsibility to choose trusted 3rd-party libraries. If you use outdated
@ -99,9 +99,7 @@ You should at least follow these steps to improve the security of your applicati
12. [Disable or limit navigation](#12-disable-or-limit-navigation)
13. [Disable or limit creation of new windows](#13-disable-or-limit-creation-of-new-windows)
14. [Do not use `openExternal` with untrusted content](#14-do-not-use-openexternal-with-untrusted-content)
15. [Disable the `remote` module](#15-disable-the-remote-module)
16. [Filter the `remote` module](#16-filter-the-remote-module)
17. [Use a current version of Electron](#17-use-a-current-version-of-electron)
15. [Use a current version of Electron](#15-use-a-current-version-of-electron)
To automate the detection of misconfigurations and insecure patterns, it is
possible to use
@ -665,134 +663,7 @@ const { shell } = require('electron')
shell.openExternal('https://example.com/index.html')
```
## 15) Disable the `remote` module
The `remote` module provides a way for the renderer processes to
access APIs normally only available in the main process. Using it, a
renderer can invoke methods of a main process object without explicitly sending
inter-process messages. If your desktop application does not run untrusted
content, this can be a useful way to have your renderer processes access and
work with modules that are only available to the main process, such as
GUI-related modules (dialogs, menus, etc.).
However, if your app can run untrusted content and even if you
[sandbox][sandbox] your renderer processes accordingly, the `remote` module
makes it easy for malicious code to escape the sandbox and have access to
system resources via the higher privileges of the main process. Therefore,
it should be disabled in such circumstances.
### Why?
`remote` uses an internal IPC channel to communicate with the main process.
"Prototype pollution" attacks can grant malicious code access to the internal
IPC channel, which can then be used to escape the sandbox by mimicking `remote`
IPC messages and getting access to main process modules running with higher
privileges.
Additionally, it's possible for preload scripts to accidentally leak modules to a
sandboxed renderer. Leaking `remote` arms malicious code with a multitude
of main process modules with which to perform an attack.
Disabling the `remote` module eliminates these attack vectors. Enabling
context isolation also prevents the "prototype pollution" attacks from
succeeding.
### How?
```js
// Bad if the renderer can run untrusted content
const mainWindow = new BrowserWindow({
webPreferences: {
enableRemoteModule: true
}
})
```
```js
// Good
const mainWindow = new BrowserWindow({
webPreferences: {
enableRemoteModule: false
}
})
```
```html
<!-- Bad if the renderer can run untrusted content -->
<webview enableremotemodule="true" src="page.html"></webview>
<!-- Good -->
<webview enableremotemodule="false" src="page.html"></webview>
```
> **Note:** The default value of `enableRemoteModule` is `false` starting
> from Electron 10. For prior versions, you need to explicitly disable
> the `remote` module by the means above.
## 16) Filter the `remote` module
If you cannot disable the `remote` module, you should filter the globals,
Node, and Electron modules (so-called built-ins) accessible via `remote`
that your application does not require. This can be done by blocking
certain modules entirely and by replacing others with proxies that
expose only the functionality that your app needs.
### Why?
Due to the system access privileges of the main process, functionality
provided by the main process modules may be dangerous in the hands of
malicious code running in a compromised renderer process. By limiting
the set of accessible modules to the minimum that your app needs and
filtering out the others, you reduce the toolset that malicious code
can use to attack the system.
Note that the safest option is to
[fully disable the remote module](#15-disable-the-remote-module). If
you choose to filter access rather than completely disable the module,
you must be very careful to ensure that no escalation of privilege is
possible through the modules you allow past the filter.
### How?
```js
const readOnlyFsProxy = require(/* ... */) // exposes only file read functionality
const allowedModules = new Set(['crypto'])
const proxiedModules = new Map([['fs', readOnlyFsProxy]])
const allowedElectronModules = new Set(['shell'])
const allowedGlobals = new Set()
app.on('remote-require', (event, webContents, moduleName) => {
if (proxiedModules.has(moduleName)) {
event.returnValue = proxiedModules.get(moduleName)
}
if (!allowedModules.has(moduleName)) {
event.preventDefault()
}
})
app.on('remote-get-builtin', (event, webContents, moduleName) => {
if (!allowedElectronModules.has(moduleName)) {
event.preventDefault()
}
})
app.on('remote-get-global', (event, webContents, globalName) => {
if (!allowedGlobals.has(globalName)) {
event.preventDefault()
}
})
app.on('remote-get-current-window', (event, webContents) => {
event.preventDefault()
})
app.on('remote-get-current-web-contents', (event, webContents) => {
event.preventDefault()
})
```
## 17) Use a current version of Electron
## 15) Use a current version of Electron
You should strive for always using the latest available version of Electron.
Whenever a new major version is released, you should attempt to update your

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

@ -43,7 +43,6 @@ auto_filenames = {
"docs/api/power-save-blocker.md",
"docs/api/process.md",
"docs/api/protocol.md",
"docs/api/remote.md",
"docs/api/sandbox-option.md",
"docs/api/screen.md",
"docs/api/service-workers.md",
@ -135,29 +134,21 @@ auto_filenames = {
]
sandbox_bundle_deps = [
"lib/browser/api/module-names.ts",
"lib/common/api/clipboard.ts",
"lib/common/api/deprecate.ts",
"lib/common/api/module-list.ts",
"lib/common/api/shell.ts",
"lib/common/define-properties.ts",
"lib/common/ipc-messages.ts",
"lib/common/remote/ipc-messages.ts",
"lib/common/type-utils.ts",
"lib/common/web-view-events.ts",
"lib/common/web-view-methods.ts",
"lib/common/webpack-globals-provider.ts",
"lib/renderer/api/context-bridge.ts",
"lib/renderer/api/crash-reporter.ts",
"lib/renderer/api/desktop-capturer.ts",
"lib/renderer/api/ipc-renderer.ts",
"lib/renderer/api/native-image.ts",
"lib/renderer/api/remote.ts",
"lib/renderer/api/web-frame.ts",
"lib/renderer/inspector.ts",
"lib/renderer/ipc-renderer-internal-utils.ts",
"lib/renderer/ipc-renderer-internal.ts",
"lib/renderer/remote/callbacks-registry.ts",
"lib/renderer/security-warnings.ts",
"lib/renderer/web-frame-init.ts",
"lib/renderer/web-view/guest-view-internal.ts",
@ -242,8 +233,6 @@ auto_filenames = {
"lib/browser/ipc-main-internal.ts",
"lib/browser/message-port-main.ts",
"lib/browser/navigation-controller.ts",
"lib/browser/remote/objects-registry.ts",
"lib/browser/remote/server.ts",
"lib/browser/rpc-server.ts",
"lib/common/api/clipboard.ts",
"lib/common/api/deprecate.ts",
@ -253,7 +242,6 @@ auto_filenames = {
"lib/common/init.ts",
"lib/common/ipc-messages.ts",
"lib/common/parse-features-string.ts",
"lib/common/remote/ipc-messages.ts",
"lib/common/reset-search-paths.ts",
"lib/common/type-utils.ts",
"lib/common/web-view-events.ts",
@ -269,7 +257,6 @@ auto_filenames = {
]
renderer_bundle_deps = [
"lib/browser/api/module-names.ts",
"lib/common/api/clipboard.ts",
"lib/common/api/deprecate.ts",
"lib/common/api/module-list.ts",
@ -277,12 +264,10 @@ auto_filenames = {
"lib/common/define-properties.ts",
"lib/common/init.ts",
"lib/common/ipc-messages.ts",
"lib/common/remote/ipc-messages.ts",
"lib/common/reset-search-paths.ts",
"lib/common/type-utils.ts",
"lib/common/web-view-events.ts",
"lib/common/web-view-methods.ts",
"lib/common/webpack-globals-provider.ts",
"lib/common/webpack-provider.ts",
"lib/renderer/api/context-bridge.ts",
"lib/renderer/api/crash-reporter.ts",
@ -291,13 +276,11 @@ auto_filenames = {
"lib/renderer/api/ipc-renderer.ts",
"lib/renderer/api/module-list.ts",
"lib/renderer/api/native-image.ts",
"lib/renderer/api/remote.ts",
"lib/renderer/api/web-frame.ts",
"lib/renderer/init.ts",
"lib/renderer/inspector.ts",
"lib/renderer/ipc-renderer-internal-utils.ts",
"lib/renderer/ipc-renderer-internal.ts",
"lib/renderer/remote/callbacks-registry.ts",
"lib/renderer/security-warnings.ts",
"lib/renderer/web-frame-init.ts",
"lib/renderer/web-view/guest-view-internal.ts",
@ -315,7 +298,6 @@ auto_filenames = {
]
worker_bundle_deps = [
"lib/browser/api/module-names.ts",
"lib/common/api/clipboard.ts",
"lib/common/api/deprecate.ts",
"lib/common/api/module-list.ts",
@ -323,10 +305,8 @@ auto_filenames = {
"lib/common/define-properties.ts",
"lib/common/init.ts",
"lib/common/ipc-messages.ts",
"lib/common/remote/ipc-messages.ts",
"lib/common/reset-search-paths.ts",
"lib/common/type-utils.ts",
"lib/common/webpack-globals-provider.ts",
"lib/common/webpack-provider.ts",
"lib/renderer/api/context-bridge.ts",
"lib/renderer/api/crash-reporter.ts",
@ -335,11 +315,9 @@ auto_filenames = {
"lib/renderer/api/ipc-renderer.ts",
"lib/renderer/api/module-list.ts",
"lib/renderer/api/native-image.ts",
"lib/renderer/api/remote.ts",
"lib/renderer/api/web-frame.ts",
"lib/renderer/ipc-renderer-internal-utils.ts",
"lib/renderer/ipc-renderer-internal.ts",
"lib/renderer/remote/callbacks-registry.ts",
"lib/worker/init.ts",
"package.json",
"tsconfig.electron.json",

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

@ -1,50 +0,0 @@
// TODO: Figure out a way to not duplicate this information between here and module-list
// It is currently duplicated as module-list "require"s all the browser API file and the
// remote module in the renderer process depends on that file. As a result webpack
// includes all the browser API files in the renderer process as well and we want to avoid that
// Browser side modules, please sort alphabetically.
export const browserModuleNames = [
'app',
'autoUpdater',
'BaseWindow',
'BrowserView',
'BrowserWindow',
'contentTracing',
'crashReporter',
'dialog',
'globalShortcut',
'ipcMain',
'inAppPurchase',
'Menu',
'MenuItem',
'nativeImage',
'nativeTheme',
'net',
'netLog',
'MessageChannelMain',
'Notification',
'powerMonitor',
'powerSaveBlocker',
'protocol',
'screen',
'session',
'ShareMenu',
'systemPreferences',
'TouchBar',
'Tray',
'View',
'webContents',
'WebContentsView',
'webFrameMain'
];
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
browserModuleNames.push('desktopCapturer');
}
if (BUILDFLAG(ENABLE_VIEWS_API)) {
browserModuleNames.push(
'ImageView'
);
}

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

@ -498,10 +498,6 @@ WebContents.prototype._init = function () {
this._windowOpenHandler = null;
// Every remote callback from renderer process would add a listener to the
// render-view-deleted event, so ignore the listeners warning.
this.setMaxListeners(0);
// Dispatch IPC messages to the ipc module.
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
addSenderFrameToEvent(event);

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

@ -168,7 +168,6 @@ const attachGuest = function (event: Electron.IpcMainInvokeEvent,
guestInstanceId: guestInstanceId,
nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false,
nodeIntegrationInSubFrames: params.nodeintegrationinsubframes != null ? params.nodeintegrationinsubframes : false,
enableRemoteModule: params.enableremotemodule,
plugins: params.plugins,
zoomFactor: embedder.zoomFactor,
disablePopups: !params.allowpopups,
@ -188,7 +187,6 @@ const attachGuest = function (event: Electron.IpcMainInvokeEvent,
['javascript', false],
['nativeWindowOpen', true],
['nodeIntegration', false],
['enableRemoteModule', false],
['sandbox', true],
['nodeIntegrationInSubFrames', false],
['enableWebSQL', false]

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

@ -191,7 +191,6 @@ const securityWebPreferences: { [key: string]: boolean } = {
javascript: false,
nativeWindowOpen: true,
nodeIntegration: false,
enableRemoteModule: false,
sandbox: true,
webviewTag: false,
nodeIntegrationInSubFrames: false,

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

@ -132,10 +132,6 @@ app._setDefaultAppPaths(packagePath);
// Load the chrome devtools support.
require('@electron/internal/browser/devtools');
if (BUILDFLAG(ENABLE_REMOTE_MODULE)) {
require('@electron/internal/browser/remote/server');
}
// Load protocol module to ensure it is populated on app ready
require('@electron/internal/browser/api/protocol');

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

@ -1,128 +0,0 @@
import { WebContents } from 'electron/main';
const getOwnerKey = (webContents: WebContents, contextId: string) => {
return `${webContents.id}-${contextId}`;
};
class ObjectsRegistry {
private nextId: number = 0
// Stores all objects by ref-counting.
// (id) => {object, count}
private storage: Record<number, { count: number, object: any }> = {}
// Stores the IDs + refCounts of objects referenced by WebContents.
// (ownerKey) => { id: refCount }
private owners: Record<string, Map<number, number>> = {}
private electronIds = new WeakMap<Object, number>();
// Register a new object and return its assigned ID. If the object is already
// registered then the already assigned ID would be returned.
add (webContents: WebContents, contextId: string, obj: any) {
// Get or assign an ID to the object.
const id = this.saveToStorage(obj);
// Add object to the set of referenced objects.
const ownerKey = getOwnerKey(webContents, contextId);
let owner = this.owners[ownerKey];
if (!owner) {
owner = this.owners[ownerKey] = new Map();
this.registerDeleteListener(webContents, contextId);
}
if (!owner.has(id)) {
owner.set(id, 0);
// Increase reference count if not referenced before.
this.storage[id].count++;
}
owner.set(id, owner.get(id)! + 1);
return id;
}
// Get an object according to its ID.
get (id: number) {
const pointer = this.storage[id];
if (pointer != null) return pointer.object;
}
// Dereference an object according to its ID.
// Note that an object may be double-freed (cleared when page is reloaded, and
// then garbage collected in old page).
remove (webContents: WebContents, contextId: string, id: number) {
const ownerKey = getOwnerKey(webContents, contextId);
const owner = this.owners[ownerKey];
if (owner && owner.has(id)) {
const newRefCount = owner.get(id)! - 1;
// Only completely remove if the number of references GCed in the
// renderer is the same as the number of references we sent them
if (newRefCount <= 0) {
// Remove the reference in owner.
owner.delete(id);
// Dereference from the storage.
this.dereference(id);
} else {
owner.set(id, newRefCount);
}
}
}
// Clear all references to objects refrenced by the WebContents.
clear (webContents: WebContents, contextId: string) {
const ownerKey = getOwnerKey(webContents, contextId);
const owner = this.owners[ownerKey];
if (!owner) return;
for (const id of owner.keys()) this.dereference(id);
delete this.owners[ownerKey];
}
// Private: Saves the object into storage and assigns an ID for it.
saveToStorage (object: any) {
let id = this.electronIds.get(object);
if (!id) {
id = ++this.nextId;
this.storage[id] = {
count: 0,
object: object
};
this.electronIds.set(object, id);
}
return id;
}
// Private: Dereference the object from store.
dereference (id: number) {
const pointer = this.storage[id];
if (pointer == null) {
return;
}
pointer.count -= 1;
if (pointer.count === 0) {
this.electronIds.delete(pointer.object);
delete this.storage[id];
}
}
// Private: Clear the storage when renderer process is destroyed.
registerDeleteListener (webContents: WebContents, contextId: string) {
// contextId => ${processHostId}-${contextCount}
const processHostId = contextId.split('-')[0];
const listener = (_: any, deletedProcessHostId: string) => {
if (deletedProcessHostId &&
deletedProcessHostId.toString() === processHostId) {
webContents.removeListener('render-view-deleted' as any, listener);
this.clear(webContents, contextId);
}
};
// Note that the "render-view-deleted" event may not be emitted on time when
// the renderer process get destroyed because of navigation, we rely on the
// renderer process to send "ELECTRON_BROWSER_CONTEXT_RELEASE" message to
// guard this situation.
webContents.on('render-view-deleted' as any, listener);
}
}
export default new ObjectsRegistry();

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

@ -1,519 +0,0 @@
import * as electron from 'electron/main';
import { EventEmitter } from 'events';
import objectsRegistry from '@electron/internal/browser/remote/objects-registry';
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
import { isPromise, isSerializableObject, deserialize, serialize } from '@electron/internal/common/type-utils';
import type { MetaTypeFromRenderer, ObjectMember, MetaType, ObjProtoDescriptor } from '@electron/internal/common/remote/types';
import { IPC_MESSAGES } from '@electron/internal/common/remote/ipc-messages';
const v8Util = process._linkedBinding('electron_common_v8_util');
const eventBinding = process._linkedBinding('electron_browser_event');
const features = process._linkedBinding('electron_common_features');
if (!features.isRemoteModuleEnabled()) {
throw new Error('remote module is disabled');
}
// The internal properties of Function.
const FUNCTION_PROPERTIES = [
'length', 'name', 'arguments', 'caller', 'prototype'
];
type RendererFunctionId = [string, number] // [contextId, funcId]
type FinalizerInfo = { id: RendererFunctionId, webContents: electron.WebContents, frameId: [number, number] };
type CallIntoRenderer = (...args: any[]) => void
// The remote functions in renderer processes.
const rendererFunctionCache = new Map<string, WeakRef<CallIntoRenderer>>();
// eslint-disable-next-line no-undef
const finalizationRegistry = new FinalizationRegistry((fi: FinalizerInfo) => {
const mapKey = fi.id[0] + '~' + fi.id[1];
const ref = rendererFunctionCache.get(mapKey);
if (ref !== undefined && ref.deref() === undefined) {
rendererFunctionCache.delete(mapKey);
if (!fi.webContents.isDestroyed()) {
try {
fi.webContents._sendToFrameInternal(fi.frameId, IPC_MESSAGES.RENDERER_RELEASE_CALLBACK, fi.id[0], fi.id[1]);
} catch (error) {
console.warn(`_sendToFrameInternal() failed: ${error}`);
}
}
}
});
function getCachedRendererFunction (id: RendererFunctionId): CallIntoRenderer | undefined {
const mapKey = id[0] + '~' + id[1];
const ref = rendererFunctionCache.get(mapKey);
if (ref !== undefined) {
const deref = ref.deref();
if (deref !== undefined) return deref;
}
}
function setCachedRendererFunction (id: RendererFunctionId, wc: electron.WebContents, frameId: [number, number], value: CallIntoRenderer) {
// eslint-disable-next-line no-undef
const wr = new WeakRef<CallIntoRenderer>(value);
const mapKey = id[0] + '~' + id[1];
rendererFunctionCache.set(mapKey, wr);
finalizationRegistry.register(value, {
id,
webContents: wc,
frameId
} as FinalizerInfo);
return value;
}
const locationInfo = new WeakMap<Object, string>();
// Return the description of object's members:
const getObjectMembers = function (object: any): ObjectMember[] {
let names = Object.getOwnPropertyNames(object);
// For Function, we should not override following properties even though they
// are "own" properties.
if (typeof object === 'function') {
names = names.filter((name) => {
return !FUNCTION_PROPERTIES.includes(name);
});
}
// Map properties to descriptors.
return names.map((name) => {
const descriptor = Object.getOwnPropertyDescriptor(object, name)!;
let type: ObjectMember['type'];
let writable = false;
if (descriptor.get === undefined && typeof object[name] === 'function') {
type = 'method';
} else {
if (descriptor.set || descriptor.writable) writable = true;
type = 'get';
}
return { name, enumerable: descriptor.enumerable, writable, type };
});
};
// Return the description of object's prototype.
const getObjectPrototype = function (object: any): ObjProtoDescriptor {
const proto = Object.getPrototypeOf(object);
if (proto === null || proto === Object.prototype) return null;
return {
members: getObjectMembers(proto),
proto: getObjectPrototype(proto)
};
};
// Convert a real value into meta data.
const valueToMeta = function (sender: electron.WebContents, contextId: string, value: any, optimizeSimpleObject = false): MetaType {
// Determine the type of value.
let type: MetaType['type'];
switch (typeof value) {
case 'object':
// Recognize certain types of objects.
if (value instanceof Buffer) {
type = 'buffer';
} else if (value && value.constructor && value.constructor.name === 'NativeImage') {
type = 'nativeimage';
} else if (Array.isArray(value)) {
type = 'array';
} else if (value instanceof Error) {
type = 'error';
} else if (isSerializableObject(value)) {
type = 'value';
} else if (isPromise(value)) {
type = 'promise';
} else if (Object.prototype.hasOwnProperty.call(value, 'callee') && value.length != null) {
// Treat the arguments object as array.
type = 'array';
} else if (optimizeSimpleObject && v8Util.getHiddenValue(value, 'simple')) {
// Treat simple objects as value.
type = 'value';
} else {
type = 'object';
}
break;
case 'function':
type = 'function';
break;
default:
type = 'value';
break;
}
// Fill the meta object according to value's type.
if (type === 'array') {
return {
type,
members: value.map((el: any) => valueToMeta(sender, contextId, el, optimizeSimpleObject))
};
} else if (type === 'nativeimage') {
return { type, value: serialize(value) };
} else if (type === 'object' || type === 'function') {
return {
type,
name: value.constructor ? value.constructor.name : '',
// Reference the original value if it's an object, because when it's
// passed to renderer we would assume the renderer keeps a reference of
// it.
id: objectsRegistry.add(sender, contextId, value),
members: getObjectMembers(value),
proto: getObjectPrototype(value)
};
} else if (type === 'buffer') {
return { type, value };
} else if (type === 'promise') {
// Add default handler to prevent unhandled rejections in main process
// Instead they should appear in the renderer process
value.then(function () {}, function () {});
return {
type,
then: valueToMeta(sender, contextId, function (onFulfilled: Function, onRejected: Function) {
value.then(onFulfilled, onRejected);
})
};
} else if (type === 'error') {
return {
type,
value,
members: Object.keys(value).map(name => ({
name,
value: valueToMeta(sender, contextId, value[name])
}))
};
} else {
return {
type: 'value',
value
};
}
};
const throwRPCError = function (message: string) {
const error = new Error(message) as Error & {code: string, errno: number};
error.code = 'EBADRPC';
error.errno = -72;
throw error;
};
const removeRemoteListenersAndLogWarning = (sender: any, callIntoRenderer: (...args: any[]) => void) => {
const location = locationInfo.get(callIntoRenderer);
let message = 'Attempting to call a function in a renderer window that has been closed or released.' +
`\nFunction provided here: ${location}`;
if (sender instanceof EventEmitter) {
const remoteEvents = sender.eventNames().filter((eventName) => {
return sender.listeners(eventName).includes(callIntoRenderer);
});
if (remoteEvents.length > 0) {
message += `\nRemote event names: ${remoteEvents.join(', ')}`;
remoteEvents.forEach((eventName) => {
sender.removeListener(eventName, callIntoRenderer);
});
}
}
console.warn(message);
};
const fakeConstructor = (constructor: Function, name: string) =>
new Proxy(Object, {
get (target, prop, receiver) {
if (prop === 'name') {
return name;
} else {
return Reflect.get(target, prop, receiver);
}
}
});
// Convert array of meta data from renderer into array of real values.
const unwrapArgs = function (sender: electron.WebContents, frameId: [number, number], contextId: string, args: any[]) {
const metaToValue = function (meta: MetaTypeFromRenderer): any {
switch (meta.type) {
case 'nativeimage':
return deserialize(meta.value);
case 'value':
return meta.value;
case 'remote-object':
return objectsRegistry.get(meta.id);
case 'array':
return unwrapArgs(sender, frameId, contextId, meta.value);
case 'buffer':
return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength);
case 'promise':
return Promise.resolve({
then: metaToValue(meta.then)
});
case 'object': {
const ret: any = meta.name !== 'Object' ? Object.create({
constructor: fakeConstructor(Object, meta.name)
}) : {};
for (const { name, value } of meta.members) {
ret[name] = metaToValue(value);
}
return ret;
}
case 'function-with-return-value': {
const returnValue = metaToValue(meta.value);
return function () {
return returnValue;
};
}
case 'function': {
// Merge contextId and meta.id, since meta.id can be the same in
// different webContents.
const objectId: [string, number] = [contextId, meta.id];
// Cache the callbacks in renderer.
const cachedFunction = getCachedRendererFunction(objectId);
if (cachedFunction !== undefined) { return cachedFunction; }
const callIntoRenderer = function (this: any, ...args: any[]) {
let succeed = false;
if (!sender.isDestroyed()) {
try {
succeed = sender._sendToFrameInternal(frameId, IPC_MESSAGES.RENDERER_CALLBACK, contextId, meta.id, valueToMeta(sender, contextId, args));
} catch (error) {
console.warn(`_sendToFrameInternal() failed: ${error}`);
}
}
if (!succeed) {
removeRemoteListenersAndLogWarning(this, callIntoRenderer);
}
};
locationInfo.set(callIntoRenderer, meta.location);
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length });
setCachedRendererFunction(objectId, sender, frameId, callIntoRenderer);
return callIntoRenderer;
}
default:
throw new TypeError(`Unknown type: ${(meta as any).type}`);
}
};
return args.map(metaToValue);
};
const isRemoteModuleEnabledImpl = function (contents: electron.WebContents) {
const webPreferences = contents.getLastWebPreferences() || {};
return webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : false;
};
const isRemoteModuleEnabledCache = new WeakMap();
export const isRemoteModuleEnabled = function (contents: electron.WebContents) {
if (!isRemoteModuleEnabledCache.has(contents)) {
isRemoteModuleEnabledCache.set(contents, isRemoteModuleEnabledImpl(contents));
}
return isRemoteModuleEnabledCache.get(contents);
};
const handleRemoteCommand = function (channel: string, handler: (event: ElectronInternal.IpcMainInternalEvent, contextId: string, ...args: any[]) => void) {
ipcMainInternal.on(channel, (event, contextId: string, ...args: any[]) => {
let returnValue;
if (!isRemoteModuleEnabled(event.sender)) {
event.returnValue = null;
return;
}
try {
returnValue = handler(event, contextId, ...args);
} catch (error) {
returnValue = {
type: 'exception',
value: valueToMeta(event.sender, contextId, error)
};
}
if (returnValue !== undefined) {
event.returnValue = returnValue;
}
});
};
const emitCustomEvent = function (contents: electron.WebContents, eventName: string, ...args: any[]) {
const event = eventBinding.createWithSender(contents);
electron.app.emit(eventName, event, contents, ...args);
contents.emit(eventName, event, ...args);
return event;
};
const logStack = function (contents: electron.WebContents, code: string, stack: string | undefined) {
if (stack) {
console.warn(`WebContents (${contents.id}): ${code}`, stack);
}
};
handleRemoteCommand(IPC_MESSAGES.BROWSER_WRONG_CONTEXT_ERROR, function (event, contextId, passedContextId, id) {
const objectId: [string, number] = [passedContextId, id];
const cachedFunction = getCachedRendererFunction(objectId);
if (cachedFunction === undefined) {
// Do nothing if the error has already been reported before.
return;
}
removeRemoteListenersAndLogWarning(event.sender, cachedFunction);
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_REQUIRE, function (event, contextId, moduleName, stack) {
logStack(event.sender, `remote.require('${moduleName}')`, stack);
const customEvent = emitCustomEvent(event.sender, 'remote-require', moduleName);
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.require('${moduleName}')`);
} else {
customEvent.returnValue = process.mainModule.require(moduleName);
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_GET_BUILTIN, function (event, contextId, moduleName, stack) {
logStack(event.sender, `remote.getBuiltin('${moduleName}')`, stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-builtin', moduleName);
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getBuiltin('${moduleName}')`);
} else {
customEvent.returnValue = (electron as any)[moduleName];
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_GET_GLOBAL, function (event, contextId, globalName, stack) {
logStack(event.sender, `remote.getGlobal('${globalName}')`, stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-global', globalName);
if (customEvent.returnValue === undefined) {
if (customEvent.defaultPrevented) {
throw new Error(`Blocked remote.getGlobal('${globalName}')`);
} else {
customEvent.returnValue = (global as any)[globalName];
}
}
return valueToMeta(event.sender, contextId, customEvent.returnValue);
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_GET_CURRENT_WINDOW, function (event, contextId, stack) {
logStack(event.sender, 'remote.getCurrentWindow()', stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-current-window');
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(IPC_MESSAGES.BROWSER_GET_CURRENT_WEB_CONTENTS, function (event, contextId, stack) {
logStack(event.sender, 'remote.getCurrentWebContents()', stack);
const customEvent = emitCustomEvent(event.sender, 'remote-get-current-web-contents');
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(IPC_MESSAGES.BROWSER_CONSTRUCTOR, function (event, contextId, id, args) {
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
const constructor = objectsRegistry.get(id);
if (constructor == null) {
throwRPCError(`Cannot call constructor on missing remote object ${id}`);
}
return valueToMeta(event.sender, contextId, new constructor(...args));
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_FUNCTION_CALL, function (event, contextId, id, args) {
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
const func = objectsRegistry.get(id);
if (func == null) {
throwRPCError(`Cannot call function on missing remote object ${id}`);
}
try {
return valueToMeta(event.sender, contextId, func(...args), true);
} catch (error) {
const err = new Error(`Could not call remote function '${func.name || 'anonymous'}'. Check that the function signature is correct. Underlying error: ${error.message}\nUnderlying stack: ${error.stack}\n`);
(err as any).cause = error;
throw err;
}
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_CONSTRUCTOR, function (event, contextId, id, method, args) {
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
const object = objectsRegistry.get(id);
if (object == null) {
throwRPCError(`Cannot call constructor '${method}' on missing remote object ${id}`);
}
return valueToMeta(event.sender, contextId, new object[method](...args));
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_CALL, function (event, contextId, id, method, args) {
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
const object = objectsRegistry.get(id);
if (object == null) {
throwRPCError(`Cannot call method '${method}' on missing remote object ${id}`);
}
try {
return valueToMeta(event.sender, contextId, object[method](...args), true);
} catch (error) {
const err = new Error(`Could not call remote method '${method}'. Check that the method signature is correct. Underlying error: ${error.message}\nUnderlying stack: ${error.stack}\n`);
(err as any).cause = error;
throw err;
}
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_SET, function (event, contextId, id, name, args) {
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
const obj = objectsRegistry.get(id);
if (obj == null) {
throwRPCError(`Cannot set property '${name}' on missing remote object ${id}`);
}
obj[name] = args[0];
return null;
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_MEMBER_GET, function (event, contextId, id, name) {
const obj = objectsRegistry.get(id);
if (obj == null) {
throwRPCError(`Cannot get property '${name}' on missing remote object ${id}`);
}
return valueToMeta(event.sender, contextId, obj[name]);
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_DEREFERENCE, function (event, contextId, id) {
objectsRegistry.remove(event.sender, contextId, id);
});
handleRemoteCommand(IPC_MESSAGES.BROWSER_CONTEXT_RELEASE, (event, contextId) => {
objectsRegistry.clear(event.sender, contextId);
});

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

@ -75,7 +75,7 @@ export function parseWebViewWebPreferences (preferences: string) {
return parseCommaSeparatedKeyValue(preferences, false).parsed;
}
const allowedWebPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'javascript', 'contextIsolation', 'webviewTag'] as const;
const allowedWebPreferences = ['zoomFactor', 'nodeIntegration', 'javascript', 'contextIsolation', 'webviewTag'] as const;
type AllowedWebPreference = (typeof allowedWebPreferences)[number];
/**

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

@ -1,85 +0,0 @@
import type { Size } from 'electron/main';
import type { NativeImage } from 'electron/common';
export type ObjectMember = {
name: string,
value?: any,
enumerable?: boolean,
writable?: boolean,
type?: 'method' | 'get'
}
export type ObjProtoDescriptor = {
members: ObjectMember[],
proto: ObjProtoDescriptor
} | null
export type MetaType = {
type: 'object' | 'function',
name: string,
members: ObjectMember[],
proto: ObjProtoDescriptor,
id: number,
} | {
type: 'value',
value: any,
} | {
type: 'buffer',
value: Uint8Array,
} | {
type: 'array',
members: MetaType[]
} | {
type: 'error',
value: Error,
members: ObjectMember[]
} | {
type: 'exception',
value: MetaType,
} | {
type: 'promise',
then: MetaType
} | {
type: 'nativeimage'
value: NativeImage
}
export type MetaTypeFromRenderer = {
type: 'value',
value: any
} | {
type: 'remote-object',
id: number
} | {
type: 'array',
value: MetaTypeFromRenderer[]
} | {
type: 'buffer',
value: Uint8Array
} | {
type: 'promise',
then: MetaTypeFromRenderer
} | {
type: 'object',
name: string,
members: {
name: string,
value: MetaTypeFromRenderer
}[]
} | {
type: 'function-with-return-value',
value: MetaTypeFromRenderer
} | {
type: 'function',
id: number,
location: string,
length: number
} | {
type: 'nativeimage',
value: {
size: Size,
buffer: Buffer,
scaleFactor: number,
dataURL: string
}[]
}

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

@ -1,7 +1,3 @@
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
const enableRemoteModule = getWebPreference(window, 'enableRemoteModule');
// Renderer side modules, please sort alphabetically.
export const rendererModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'contextBridge', loader: () => require('./context-bridge') },
@ -17,10 +13,3 @@ if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
loader: () => require('@electron/internal/renderer/api/desktop-capturer')
});
}
if (BUILDFLAG(ENABLE_REMOTE_MODULE) && enableRemoteModule) {
rendererModuleList.push({
name: 'remote',
loader: () => require('@electron/internal/renderer/api/remote')
});
}

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

@ -1,395 +0,0 @@
import { CallbacksRegistry } from '../remote/callbacks-registry';
import { isPromise, isSerializableObject, serialize, deserialize } from '../../common/type-utils';
import { MetaTypeFromRenderer, ObjectMember, ObjProtoDescriptor, MetaType } from '../../common/remote/types';
import { ipcRendererInternal } from '../ipc-renderer-internal';
import type { BrowserWindow, WebContents } from 'electron/main';
import deprecate from '@electron/internal/common/api/deprecate';
import { browserModuleNames } from '@electron/internal/browser/api/module-names';
import { commonModuleList } from '@electron/internal/common/api/module-list';
import { IPC_MESSAGES } from '@electron/internal/common/remote/ipc-messages';
deprecate.log('The remote module is deprecated. Use https://github.com/electron/remote instead.');
const v8Util = process._linkedBinding('electron_common_v8_util');
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
const callbacksRegistry = new CallbacksRegistry();
const remoteObjectCache = new Map();
const finalizationRegistry = new FinalizationRegistry((id: number) => {
const ref = remoteObjectCache.get(id);
if (ref !== undefined && ref.deref() === undefined) {
remoteObjectCache.delete(id);
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_DEREFERENCE, contextId, id, 0);
}
});
const electronIds = new WeakMap<Object, number>();
const isReturnValue = new WeakSet<Object>();
function getCachedRemoteObject (id: number) {
const ref = remoteObjectCache.get(id);
if (ref !== undefined) {
const deref = ref.deref();
if (deref !== undefined) return deref;
}
}
function setCachedRemoteObject (id: number, value: any) {
const wr = new WeakRef(value);
remoteObjectCache.set(id, wr);
finalizationRegistry.register(value, id);
return value;
}
// An unique ID that can represent current context.
const contextId = v8Util.getHiddenValue<string>(global, 'contextId');
// Notify the main process when current context is going to be released.
// Note that when the renderer process is destroyed, the message may not be
// sent, we also listen to the "render-view-deleted" event in the main process
// to guard that situation.
process.on('exit', () => {
const command = IPC_MESSAGES.BROWSER_CONTEXT_RELEASE;
ipcRendererInternal.send(command, contextId);
});
const IS_REMOTE_PROXY = Symbol('is-remote-proxy');
// Convert the arguments object into an array of meta data.
function wrapArgs (args: any[], visited = new Set()): any {
const valueToMeta = (value: any): any => {
// Check for circular reference.
if (visited.has(value)) {
return {
type: 'value',
value: null
};
}
if (value && value.constructor && value.constructor.name === 'NativeImage') {
return { type: 'nativeimage', value: serialize(value) };
} else if (Array.isArray(value)) {
visited.add(value);
const meta = {
type: 'array',
value: wrapArgs(value, visited)
};
visited.delete(value);
return meta;
} else if (value instanceof Buffer) {
return {
type: 'buffer',
value
};
} else if (isSerializableObject(value)) {
return {
type: 'value',
value
};
} else if (typeof value === 'object') {
if (isPromise(value)) {
return {
type: 'promise',
then: valueToMeta(function (onFulfilled: Function, onRejected: Function) {
value.then(onFulfilled, onRejected);
})
};
} else if (electronIds.has(value)) {
return {
type: 'remote-object',
id: electronIds.get(value)
};
}
const meta: MetaTypeFromRenderer = {
type: 'object',
name: value.constructor ? value.constructor.name : '',
members: []
};
visited.add(value);
for (const prop in value) { // eslint-disable-line guard-for-in
meta.members.push({
name: prop,
value: valueToMeta(value[prop])
});
}
visited.delete(value);
return meta;
} else if (typeof value === 'function' && isReturnValue.has(value)) {
return {
type: 'function-with-return-value',
value: valueToMeta(value())
};
} else if (typeof value === 'function') {
return {
type: 'function',
id: callbacksRegistry.add(value),
location: callbacksRegistry.getLocation(value),
length: value.length
};
} else {
return {
type: 'value',
value
};
}
};
return args.map(valueToMeta);
}
// Populate object's members from descriptors.
// The |ref| will be kept referenced by |members|.
// This matches |getObjectMembers| in rpc-server.
function setObjectMembers (ref: any, object: any, metaId: number, members: ObjectMember[]) {
if (!Array.isArray(members)) return;
for (const member of members) {
if (Object.prototype.hasOwnProperty.call(object, member.name)) continue;
const descriptor: PropertyDescriptor = { enumerable: member.enumerable };
if (member.type === 'method') {
const remoteMemberFunction = function (this: any, ...args: any[]) {
let command;
if (this && this.constructor === remoteMemberFunction) {
command = IPC_MESSAGES.BROWSER_MEMBER_CONSTRUCTOR;
} else {
command = IPC_MESSAGES.BROWSER_MEMBER_CALL;
}
const ret = ipcRendererInternal.sendSync(command, contextId, metaId, member.name, wrapArgs(args));
return metaToValue(ret);
};
let descriptorFunction = proxyFunctionProperties(remoteMemberFunction, metaId, member.name);
descriptor.get = () => {
descriptorFunction.ref = ref; // The member should reference its object.
return descriptorFunction;
};
// Enable monkey-patch the method
descriptor.set = (value) => {
descriptorFunction = value;
return value;
};
descriptor.configurable = true;
} else if (member.type === 'get') {
descriptor.get = () => {
const command = IPC_MESSAGES.BROWSER_MEMBER_GET;
const meta = ipcRendererInternal.sendSync(command, contextId, metaId, member.name);
return metaToValue(meta);
};
if (member.writable) {
descriptor.set = (value) => {
const args = wrapArgs([value]);
const command = IPC_MESSAGES.BROWSER_MEMBER_SET;
const meta = ipcRendererInternal.sendSync(command, contextId, metaId, member.name, args);
if (meta != null) metaToValue(meta);
return value;
};
}
}
Object.defineProperty(object, member.name, descriptor);
}
}
// Populate object's prototype from descriptor.
// This matches |getObjectPrototype| in rpc-server.
function setObjectPrototype (ref: any, object: any, metaId: number, descriptor: ObjProtoDescriptor) {
if (descriptor === null) return;
const proto = {};
setObjectMembers(ref, proto, metaId, descriptor.members);
setObjectPrototype(ref, proto, metaId, descriptor.proto);
Object.setPrototypeOf(object, proto);
}
// Wrap function in Proxy for accessing remote properties
function proxyFunctionProperties (remoteMemberFunction: Function, metaId: number, name: string) {
let loaded = false;
// Lazily load function properties
const loadRemoteProperties = () => {
if (loaded) return;
loaded = true;
const command = IPC_MESSAGES.BROWSER_MEMBER_GET;
const meta = ipcRendererInternal.sendSync(command, contextId, metaId, name);
setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members);
};
return new Proxy(remoteMemberFunction as any, {
set: (target, property, value) => {
if (property !== 'ref') loadRemoteProperties();
target[property] = value;
return true;
},
get: (target, property) => {
if (property === IS_REMOTE_PROXY) return true;
if (!Object.prototype.hasOwnProperty.call(target, property)) loadRemoteProperties();
const value = target[property];
if (property === 'toString' && typeof value === 'function') {
return value.bind(target);
}
return value;
},
ownKeys: (target) => {
loadRemoteProperties();
return Object.getOwnPropertyNames(target);
},
getOwnPropertyDescriptor: (target, property) => {
const descriptor = Object.getOwnPropertyDescriptor(target, property);
if (descriptor) return descriptor;
loadRemoteProperties();
return Object.getOwnPropertyDescriptor(target, property);
}
});
}
// Convert meta data from browser into real value.
function metaToValue (meta: MetaType): any {
if (meta.type === 'value') {
return meta.value;
} else if (meta.type === 'array') {
return meta.members.map((member) => metaToValue(member));
} else if (meta.type === 'nativeimage') {
return deserialize(meta.value);
} else if (meta.type === 'buffer') {
return Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength);
} else if (meta.type === 'promise') {
return Promise.resolve({ then: metaToValue(meta.then) });
} else if (meta.type === 'error') {
return metaToError(meta);
} else if (meta.type === 'exception') {
if (meta.value.type === 'error') { throw metaToError(meta.value); } else { throw new Error(`Unexpected value type in exception: ${meta.value.type}`); }
} else {
let ret;
if ('id' in meta) {
const cached = getCachedRemoteObject(meta.id);
if (cached !== undefined) { return cached; }
}
// A shadow class to represent the remote function object.
if (meta.type === 'function') {
const remoteFunction = function (this: any, ...args: any[]) {
let command;
if (this && this.constructor === remoteFunction) {
command = IPC_MESSAGES.BROWSER_CONSTRUCTOR;
} else {
command = IPC_MESSAGES.BROWSER_FUNCTION_CALL;
}
const obj = ipcRendererInternal.sendSync(command, contextId, meta.id, wrapArgs(args));
return metaToValue(obj);
};
ret = remoteFunction;
} else {
ret = {};
}
setObjectMembers(ret, ret, meta.id, meta.members);
setObjectPrototype(ret, ret, meta.id, meta.proto);
if (ret.constructor && (ret.constructor as any)[IS_REMOTE_PROXY]) {
Object.defineProperty(ret.constructor, 'name', { value: meta.name });
}
// Track delegate obj's lifetime & tell browser to clean up when object is GCed.
electronIds.set(ret, meta.id);
setCachedRemoteObject(meta.id, ret);
return ret;
}
}
function metaToError (meta: { type: 'error', value: any, members: ObjectMember[] }) {
const obj = meta.value;
for (const { name, value } of meta.members) {
obj[name] = metaToValue(value);
}
return obj;
}
function handleMessage (channel: string, handler: Function) {
ipcRendererInternal.on(channel, (event, passedContextId, id, ...args) => {
if (passedContextId === contextId) {
handler(id, ...args);
} else {
// Message sent to an un-exist context, notify the error to main process.
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_WRONG_CONTEXT_ERROR, contextId, passedContextId, id);
}
});
}
const enableStacks = hasSwitch('enable-api-filtering-logging');
function getCurrentStack (): string | undefined {
const target = { stack: undefined as string | undefined };
if (enableStacks) {
Error.captureStackTrace(target, getCurrentStack);
}
return target.stack;
}
// Browser calls a callback in renderer.
handleMessage(IPC_MESSAGES.RENDERER_CALLBACK, (id: number, args: any) => {
callbacksRegistry.apply(id, metaToValue(args));
});
// A callback in browser is released.
handleMessage(IPC_MESSAGES.RENDERER_RELEASE_CALLBACK, (id: number) => {
callbacksRegistry.remove(id);
});
exports.require = (module: string) => {
const command = IPC_MESSAGES.BROWSER_REQUIRE;
const meta = ipcRendererInternal.sendSync(command, contextId, module, getCurrentStack());
return metaToValue(meta);
};
// Alias to remote.require('electron').xxx.
export function getBuiltin (module: string) {
const command = IPC_MESSAGES.BROWSER_GET_BUILTIN;
const meta = ipcRendererInternal.sendSync(command, contextId, module, getCurrentStack());
return metaToValue(meta);
}
export function getCurrentWindow (): BrowserWindow {
const command = IPC_MESSAGES.BROWSER_GET_CURRENT_WINDOW;
const meta = ipcRendererInternal.sendSync(command, contextId, getCurrentStack());
return metaToValue(meta);
}
// Get current WebContents object.
export function getCurrentWebContents (): WebContents {
const command = IPC_MESSAGES.BROWSER_GET_CURRENT_WEB_CONTENTS;
const meta = ipcRendererInternal.sendSync(command, contextId, getCurrentStack());
return metaToValue(meta);
}
// Get a global object in browser.
export function getGlobal<T = any> (name: string): T {
const command = IPC_MESSAGES.BROWSER_GET_GLOBAL;
const meta = ipcRendererInternal.sendSync(command, contextId, name, getCurrentStack());
return metaToValue(meta);
}
// Get the process object in browser.
Object.defineProperty(exports, 'process', {
get: () => exports.getGlobal('process')
});
// Create a function that will return the specified value when called in browser.
export function createFunctionWithReturnValue<T> (returnValue: T): () => T {
const func = () => returnValue;
isReturnValue.add(func);
return func;
}
const addBuiltinProperty = (name: string) => {
Object.defineProperty(exports, name, {
get: () => exports.getBuiltin(name)
});
};
const browserModules = commonModuleList.concat(browserModuleNames.map(name => ({ name, loader: () => {} })));
// And add a helper receiver for each one.
browserModules
.filter((m) => !m.private)
.map((m) => m.name)
.forEach(addBuiltinProperty);

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

@ -1,59 +0,0 @@
export class CallbacksRegistry {
private nextId: number = 0
private callbacks = new Map<number, Function>()
private callbackIds = new WeakMap<Function, number>();
private locationInfo = new WeakMap<Function, string>();
add (callback: Function) {
// The callback is already added.
let id = this.callbackIds.get(callback);
if (id != null) return id;
id = this.nextId += 1;
// Capture the location of the function and put it in the ID string,
// so that release errors can be tracked down easily.
const regexp = /at (.*)/gi;
const stackString = (new Error()).stack;
if (!stackString) return;
let filenameAndLine: string;
let match;
while ((match = regexp.exec(stackString)) !== null) {
const location = match[1];
if (location.includes('(native)')) continue;
if (location.includes('(<anonymous>)')) continue;
if (location.includes('electron/js2c')) continue;
const ref = /([^/^)]*)\)?$/gi.exec(location);
if (ref) filenameAndLine = ref![1];
break;
}
this.callbacks.set(id, callback);
this.callbackIds.set(callback, id);
this.locationInfo.set(callback, filenameAndLine!);
return id;
}
get (id: number) {
return this.callbacks.get(id) || function () {};
}
getLocation (callback: Function) {
return this.locationInfo.get(callback);
}
apply (id: number, ...args: any[]) {
return this.get(id).apply(global, ...args);
}
remove (id: number) {
const callback = this.callbacks.get(id);
if (callback) {
this.callbackIds.delete(callback);
this.callbacks.delete(id);
}
}
}

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

@ -266,27 +266,6 @@ const warnAboutAllowedPopups = function () {
// #13 Disable or limit creation of new windows
// #14 Do not use `openExternal` with untrusted content
// #15 on the checklist: Disable the `remote` module
// Logs a warning message about the remote module
const warnAboutRemoteModuleWithRemoteContent = function (webPreferences?: Electron.WebPreferences) {
if (!webPreferences || isLocalhost()) return;
const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : true;
if (!remoteModuleEnabled) return;
if (getIsRemoteProtocol()) {
const warning = `This renderer process has "enableRemoteModule" enabled
and attempted to load remote content from '${window.location}'. This
exposes users of this app to unnecessary security risks.\n${moreInformation}`;
console.warn('%cElectron Security Warning (enableRemoteModule)',
'font-weight: bold;', warning);
}
};
// Currently missing since we can't easily programmatically check for it:
// #16 Filter the `remote` module
const logSecurityWarnings = function (
webPreferences: Electron.WebPreferences | undefined, nodeIntegration: boolean
) {
@ -298,7 +277,6 @@ const logSecurityWarnings = function (
warnAboutEnableBlinkFeatures(webPreferences);
warnAboutInsecureCSP();
warnAboutAllowedPopups();
warnAboutRemoteModuleWithRemoteContent(webPreferences);
};
const getWebPreferences = async function () {

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

@ -259,20 +259,6 @@ class WebPreferencesAttribute extends WebViewAttribute {
}
}
class EnableRemoteModuleAttribute extends WebViewAttribute {
constructor (webViewImpl: WebViewImpl) {
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_ENABLEREMOTEMODULE, webViewImpl);
}
public getValue () {
return this.webViewImpl.webviewNode.getAttribute(this.name) !== 'false';
}
public setValue (value: any) {
this.webViewImpl.webviewNode.setAttribute(this.name, value ? 'true' : 'false');
}
}
// Sets up all of the webview attributes.
WebViewImpl.prototype.setupWebViewAttributes = function () {
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION, new PartitionAttribute(this));
@ -284,7 +270,6 @@ WebViewImpl.prototype.setupWebViewAttributes = function () {
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_PLUGINS, new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_PLUGINS, this));
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEWEBSECURITY, new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEWEBSECURITY, this));
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_ALLOWPOPUPS, new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_ALLOWPOPUPS, this));
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_ENABLEREMOTEMODULE, new EnableRemoteModuleAttribute(this));
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_PRELOAD, new PreloadAttribute(this));
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_BLINKFEATURES, new BlinkFeaturesAttribute(this));
this.attributes.set(WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEBLINKFEATURES, new DisableBlinkFeaturesAttribute(this));

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

@ -6,7 +6,6 @@ export const enum WEB_VIEW_CONSTANTS {
ATTRIBUTE_HTTPREFERRER = 'httpreferrer',
ATTRIBUTE_NODEINTEGRATION = 'nodeintegration',
ATTRIBUTE_NODEINTEGRATIONINSUBFRAMES = 'nodeintegrationinsubframes',
ATTRIBUTE_ENABLEREMOTEMODULE = 'enableremotemodule',
ATTRIBUTE_PLUGINS = 'plugins',
ATTRIBUTE_DISABLEWEBSECURITY = 'disablewebsecurity',
ATTRIBUTE_ALLOWPOPUPS = 'allowpopups',

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

@ -29,7 +29,6 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof
WEB_VIEW_CONSTANTS.ATTRIBUTE_PLUGINS,
WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEWEBSECURITY,
WEB_VIEW_CONSTANTS.ATTRIBUTE_ALLOWPOPUPS,
WEB_VIEW_CONSTANTS.ATTRIBUTE_ENABLEREMOTEMODULE,
WEB_VIEW_CONSTANTS.ATTRIBUTE_PRELOAD,
WEB_VIEW_CONSTANTS.ATTRIBUTE_BLINKFEATURES,
WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEBLINKFEATURES,

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

@ -1,7 +1,3 @@
const { getWebPreference } = process._linkedBinding('electron_renderer_web_frame');
const enableRemoteModule = getWebPreference(window, 'enableRemoteModule');
export const moduleList: ElectronInternal.ModuleEntry[] = [
{
name: 'contextBridge',
@ -37,10 +33,3 @@ if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
loader: () => require('@electron/internal/renderer/api/desktop-capturer')
});
}
if (BUILDFLAG(ENABLE_REMOTE_MODULE) && enableRemoteModule) {
moduleList.push({
name: 'remote',
loader: () => require('@electron/internal/renderer/api/remote')
});
}

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

@ -8,10 +8,10 @@ WebPreferences of in-process child windows, rather than relying on
process-level command line switches, as before.
diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc
index 758b0b1616ecf86b7dd090adce94395851d9baf2..55f20eb6266368c65fc0ec80d52caa332f85ecfb 100644
index 758b0b1616ecf86b7dd090adce94395851d9baf2..43eed39329d5d4337471a2ae8512714d6c6cb841 100644
--- a/third_party/blink/common/web_preferences/web_preferences.cc
+++ b/third_party/blink/common/web_preferences/web_preferences.cc
@@ -146,6 +146,29 @@ WebPreferences::WebPreferences()
@@ -146,6 +146,28 @@ WebPreferences::WebPreferences()
navigate_on_drag_drop(true),
v8_cache_options(blink::mojom::V8CacheOptions::kDefault),
record_whole_document(false),
@ -21,7 +21,6 @@ index 758b0b1616ecf86b7dd090adce94395851d9baf2..55f20eb6266368c65fc0ec80d52caa33
+ background_color(base::EmptyString()),
+ opener_id(0),
+ context_isolation(false),
+ enable_remote_module(false),
+ world_safe_execute_javascript(false),
+ guest_instance_id(0),
+ hidden_page(false),
@ -42,7 +41,7 @@ index 758b0b1616ecf86b7dd090adce94395851d9baf2..55f20eb6266368c65fc0ec80d52caa33
accelerated_video_decode_enabled(false),
animation_policy(
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
index ba1ba323ec45296c33b5931652a001d6bd24dbe0..663d47894592499531ff924c78b518325020dc04 100644
index ba1ba323ec45296c33b5931652a001d6bd24dbe0..178cae9c389e48733fde982f4906d9748004dbe3 100644
--- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
+++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
@@ -24,6 +24,11 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
@ -57,7 +56,7 @@ index ba1ba323ec45296c33b5931652a001d6bd24dbe0..663d47894592499531ff924c78b51832
!data.ReadLazyFrameLoadingDistanceThresholdsPx(
&out->lazy_frame_loading_distance_thresholds_px) ||
!data.ReadLazyImageLoadingDistanceThresholdsPx(
@@ -152,6 +157,27 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
@@ -152,6 +157,26 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
out->navigate_on_drag_drop = data.navigate_on_drag_drop();
out->v8_cache_options = data.v8_cache_options();
out->record_whole_document = data.record_whole_document();
@ -66,7 +65,6 @@ index ba1ba323ec45296c33b5931652a001d6bd24dbe0..663d47894592499531ff924c78b51832
+ out->disable_electron_site_instance_overrides = data.disable_electron_site_instance_overrides();
+ out->opener_id = data.opener_id();
+ out->context_isolation = data.context_isolation();
+ out->enable_remote_module = data.enable_remote_module();
+ out->world_safe_execute_javascript = data.world_safe_execute_javascript();
+ out->guest_instance_id = data.guest_instance_id();
+ out->hidden_page = data.hidden_page();
@ -86,7 +84,7 @@ index ba1ba323ec45296c33b5931652a001d6bd24dbe0..663d47894592499531ff924c78b51832
out->accelerated_video_decode_enabled =
data.accelerated_video_decode_enabled();
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h
index ab727750abcb0253463e83c984bf1afd9e296021..cd4598e022b144c728990b47957baa031097dfc9 100644
index ab727750abcb0253463e83c984bf1afd9e296021..fd2a58f20e0a725fb441dc8607e862717537bcf6 100644
--- a/third_party/blink/public/common/web_preferences/web_preferences.h
+++ b/third_party/blink/public/common/web_preferences/web_preferences.h
@@ -9,6 +9,7 @@
@ -97,7 +95,7 @@ index ab727750abcb0253463e83c984bf1afd9e296021..cd4598e022b144c728990b47957baa03
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -161,6 +162,29 @@ struct BLINK_COMMON_EXPORT WebPreferences {
@@ -161,6 +162,28 @@ struct BLINK_COMMON_EXPORT WebPreferences {
blink::mojom::V8CacheOptions v8_cache_options;
bool record_whole_document;
@ -107,7 +105,6 @@ index ab727750abcb0253463e83c984bf1afd9e296021..cd4598e022b144c728990b47957baa03
+ std::string background_color;
+ int opener_id;
+ bool context_isolation;
+ bool enable_remote_module;
+ bool world_safe_execute_javascript;
+ int guest_instance_id;
+ bool hidden_page;
@ -128,7 +125,7 @@ index ab727750abcb0253463e83c984bf1afd9e296021..cd4598e022b144c728990b47957baa03
// only controls whether or not the "document.cookie" field is properly
// connected to the backing store, for instance if you wanted to be able to
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
index 68d33ca3be294fc79f6d5d1a6ae6a8dfd427f4b1..9663462132151638ad480f8431a0ea428c6f0563 100644
index 68d33ca3be294fc79f6d5d1a6ae6a8dfd427f4b1..e8a2c0f48f61f31a96290c02489378795a9e9f6a 100644
--- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
+++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
@@ -6,6 +6,7 @@
@ -139,7 +136,7 @@ index 68d33ca3be294fc79f6d5d1a6ae6a8dfd427f4b1..9663462132151638ad480f8431a0ea42
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/nqe/effective_connection_type.h"
#include "third_party/blink/public/common/common_export.h"
@@ -441,6 +442,88 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
@@ -441,6 +442,84 @@ struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::WebPreferencesDataView,
return r.record_whole_document;
}
@ -164,10 +161,6 @@ index 68d33ca3be294fc79f6d5d1a6ae6a8dfd427f4b1..9663462132151638ad480f8431a0ea42
+ return r.context_isolation;
+ }
+
+ static bool enable_remote_module(const blink::web_pref::WebPreferences& r) {
+ return r.enable_remote_module;
+ }
+
+ static bool world_safe_execute_javascript(const blink::web_pref::WebPreferences& r) {
+ return r.world_safe_execute_javascript;
+ }
@ -229,7 +222,7 @@ index 68d33ca3be294fc79f6d5d1a6ae6a8dfd427f4b1..9663462132151638ad480f8431a0ea42
return r.cookie_enabled;
}
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
index 5428fa6e79ed60774fcd6e87dcd6a602143158b7..eb21ecde85e91aef14cbe8ad6fc9e1e7d9150a61 100644
index 5428fa6e79ed60774fcd6e87dcd6a602143158b7..3f86e539fb4c70c690286f9eecf8d60bd23939af 100644
--- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
+++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
@@ -9,6 +9,7 @@ import "third_party/blink/public/mojom/css/preferred_contrast.mojom";
@ -240,7 +233,7 @@ index 5428fa6e79ed60774fcd6e87dcd6a602143158b7..eb21ecde85e91aef14cbe8ad6fc9e1e7
enum PointerType {
kPointerNone = 1, // 1 << 0
@@ -211,6 +212,29 @@ struct WebPreferences {
@@ -211,6 +212,28 @@ struct WebPreferences {
V8CacheOptions v8_cache_options;
bool record_whole_document;
@ -250,7 +243,6 @@ index 5428fa6e79ed60774fcd6e87dcd6a602143158b7..eb21ecde85e91aef14cbe8ad6fc9e1e7
+ string background_color;
+ int32 opener_id;
+ bool context_isolation;
+ bool enable_remote_module;
+ bool world_safe_execute_javascript;
+ int32 guest_instance_id;
+ bool hidden_page;

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

@ -422,11 +422,6 @@ void WebContentsPreferences::OverrideWebkitPrefs(
// Run Electron APIs and preload script in isolated world
prefs->context_isolation = IsEnabled(options::kContextIsolation, true);
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
// Whether to enable the remote module
prefs->enable_remote_module = IsEnabled(options::kEnableRemoteModule, false);
#endif
prefs->world_safe_execute_javascript =
IsEnabled(options::kWorldSafeExecuteJavaScript, true);

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

@ -14,9 +14,4 @@ mojom("mojo") {
# interfaces aready included in blink_common.dll
overridden_deps = [ "//third_party/blink/public/mojom:mojom_core" ]
component_deps = [ "//third_party/blink/public/common" ]
enabled_features = []
if (enable_remote_module) {
enabled_features += [ "enable_remote_module" ]
}
}

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

@ -22,10 +22,6 @@ bool IsOffscreenRenderingEnabled() {
return BUILDFLAG(ENABLE_OSR);
}
bool IsRemoteModuleEnabled() {
return BUILDFLAG(ENABLE_REMOTE_MODULE);
}
bool IsPDFViewerEnabled() {
return BUILDFLAG(ENABLE_PDF_VIEWER);
}
@ -78,7 +74,6 @@ void Initialize(v8::Local<v8::Object> exports,
dict.SetMethod("isBuiltinSpellCheckerEnabled", &IsBuiltinSpellCheckerEnabled);
dict.SetMethod("isDesktopCapturerEnabled", &IsDesktopCapturerEnabled);
dict.SetMethod("isOffscreenRenderingEnabled", &IsOffscreenRenderingEnabled);
dict.SetMethod("isRemoteModuleEnabled", &IsRemoteModuleEnabled);
dict.SetMethod("isPDFViewerEnabled", &IsPDFViewerEnabled);
dict.SetMethod("isRunAsNodeEnabled", &IsRunAsNodeEnabled);
dict.SetMethod("isFakeLocationProviderEnabled",

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

@ -193,10 +193,6 @@ const char kHiddenPage[] = "hiddenPage";
const char kSpellcheck[] = "spellcheck";
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
const char kEnableRemoteModule[] = "enableRemoteModule";
#endif
const char kEnableWebSQL[] = "enableWebSQL";
const char kEnablePreferredSizeMode[] = "enablePreferredSizeMode";

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

@ -99,10 +99,6 @@ extern const char kHiddenPage[];
extern const char kSpellcheck[];
#endif
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
extern const char kEnableRemoteModule[];
#endif
} // namespace options
// Following are actually command line switches, should be moved to other files.

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

@ -427,10 +427,6 @@ v8::Local<v8::Value> GetWebPreference(v8::Isolate* isolate,
return gin::ConvertToV8(isolate, prefs.opener_id);
} else if (pref_name == options::kContextIsolation) {
return gin::ConvertToV8(isolate, prefs.context_isolation);
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
} else if (pref_name == options::kEnableRemoteModule) {
return gin::ConvertToV8(isolate, prefs.enable_remote_module);
#endif
} else if (pref_name == options::kWorldSafeExecuteJavaScript) {
return gin::ConvertToV8(isolate, prefs.world_safe_execute_javascript);
} else if (pref_name == options::kGuestInstanceID) {

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

@ -466,101 +466,6 @@ describe('app module', () => {
expect(webContents).to.equal(w.webContents);
});
});
ifdescribe(features.isRemoteModuleEnabled())('remote module filtering', () => {
it('should emit remote-require event when remote.require() is invoked', async () => {
w = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false
}
});
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', async () => {
w = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false
}
});
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,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: 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,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: 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,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: 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);
});
});
});
describe('app.badgeCount', () => {

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

@ -2031,21 +2031,6 @@ describe('BrowserWindow module', () => {
const [, test] = await emittedOnce(ipcMain, 'answer');
expect(test).to.eql('preload');
});
ifit(features.isRemoteModuleEnabled())('can successfully delete the Buffer global', async () => {
const preload = path.join(__dirname, 'fixtures', 'remote', 'delete-buffer.js');
const w = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
preload
}
});
w.loadFile(path.join(fixtures, 'api', 'preload.html'));
const [, test] = await emittedOnce(ipcMain, 'answer');
expect(test).to.eql(Buffer.from('buffer'));
});
it('has synchronous access to all eventual window APIs', async () => {
const preload = path.join(fixtures, 'module', 'access-blink-apis.js');
const w = new BrowserWindow({
@ -2158,61 +2143,6 @@ describe('BrowserWindow module', () => {
});
});
ifdescribe(features.isRemoteModuleEnabled())('"enableRemoteModule" option', () => {
const generateSpecs = (description: string, sandbox: boolean) => {
describe(description, () => {
const preload = path.join(__dirname, 'fixtures', 'remote', 'preload-remote.js');
it('disables the remote module by default', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
preload,
sandbox
}
});
const p = emittedOnce(ipcMain, 'remote');
w.loadFile(path.join(fixtures, 'api', 'blank.html'));
const [, remote] = await p;
expect(remote).to.equal('undefined');
});
it('disables the remote module when false', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
preload,
sandbox,
enableRemoteModule: false
}
});
const p = emittedOnce(ipcMain, 'remote');
w.loadFile(path.join(fixtures, 'api', 'blank.html'));
const [, remote] = await p;
expect(remote).to.equal('undefined');
});
it('enables the remote module when true', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
preload,
sandbox,
enableRemoteModule: true
}
});
const p = emittedOnce(ipcMain, 'remote');
w.loadFile(path.join(fixtures, 'api', 'blank.html'));
const [, remote] = await p;
expect(remote).to.equal('object');
});
});
};
generateSpecs('without sandbox', false);
generateSpecs('with sandbox', true);
});
describe('"sandbox" option', () => {
const preload = path.join(path.resolve(__dirname, 'fixtures'), 'module', 'preload-sandbox.js');
@ -2528,85 +2458,6 @@ describe('BrowserWindow module', () => {
w.loadFile(path.join(fixtures, 'pages', 'window-open.html'));
});
// see #9387
ifit(features.isRemoteModuleEnabled())('properly manages remote object references after page reload', (done) => {
const w = new BrowserWindow({
show: false,
webPreferences: {
preload,
sandbox: true,
enableRemoteModule: true,
contextIsolation: false
}
});
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'reload-remote' });
ipcMain.on('get-remote-module-path', (event) => {
event.returnValue = path.join(fixtures, 'module', 'hello.js');
});
let reload = false;
ipcMain.on('reloaded', (event) => {
event.returnValue = reload;
reload = !reload;
});
ipcMain.once('reload', (event) => {
event.sender.reload();
});
ipcMain.once('answer', (event, arg) => {
ipcMain.removeAllListeners('reloaded');
ipcMain.removeAllListeners('get-remote-module-path');
try {
expect(arg).to.equal('hi');
done();
} catch (e) {
done(e);
}
});
});
ifit(features.isRemoteModuleEnabled())('properly manages remote object references after page reload in child window', (done) => {
const w = new BrowserWindow({
show: false,
webPreferences: {
preload,
sandbox: true,
enableRemoteModule: true,
contextIsolation: false
}
});
w.webContents.setWindowOpenHandler(() => ({ action: 'allow', overrideBrowserWindowOptions: { webPreferences: { preload } } }));
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'reload-remote-child' });
ipcMain.on('get-remote-module-path', (event) => {
event.returnValue = path.join(fixtures, 'module', 'hello-child.js');
});
let reload = false;
ipcMain.on('reloaded', (event) => {
event.returnValue = reload;
reload = !reload;
});
ipcMain.once('reload', (event) => {
event.sender.reload();
});
ipcMain.once('answer', (event, arg) => {
ipcMain.removeAllListeners('reloaded');
ipcMain.removeAllListeners('get-remote-module-path');
try {
expect(arg).to.equal('hi child window');
done();
} catch (e) {
done(e);
}
});
});
it('validates process APIs access in sandboxed renderer', async () => {
const w = new BrowserWindow({
show: false,

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

@ -1,47 +0,0 @@
import { expect } from 'chai';
import { CallbacksRegistry } from '../lib/renderer/remote/callbacks-registry';
import { ifdescribe } from './spec-helpers';
const features = process._linkedBinding('electron_common_features');
ifdescribe(features.isRemoteModuleEnabled())('CallbacksRegistry module', () => {
let registry: CallbacksRegistry;
beforeEach(() => {
registry = new CallbacksRegistry();
});
it('adds a callback to the registry', () => {
const cb = () => [1, 2, 3, 4, 5];
const key = registry.add(cb);
expect(key).to.exist('key');
});
it('returns a specified callback if it is in the registry', () => {
const cb = () => [1, 2, 3, 4, 5];
const key = registry.add(cb);
expect(key).to.exist('key');
const callback = registry.get(key!);
expect(callback.toString()).equal(cb.toString());
});
it('returns an empty function if the cb doesnt exist', () => {
const callback = registry.get(1);
expect(callback).to.be.a('function');
});
it('removes a callback to the registry', () => {
const cb = () => [1, 2, 3, 4, 5];
const key = registry.add(cb);
expect(key).to.exist('key');
registry.remove(key!);
const afterCB = registry.get(key!);
expect(afterCB).to.be.a('function');
expect(afterCB.toString()).to.not.equal(cb.toString());
});
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,7 +0,0 @@
exports.call = function (func) {
return func();
};
exports.constructor = function () {
this.test = 'test';
};

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

@ -1,3 +0,0 @@
exports.returnArgs = function (...args) {
return args;
};

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

@ -1,29 +0,0 @@
'use strict';
let value = 'old';
class BaseClass {
method () {
return 'method';
}
get readonly () {
return 'readonly';
}
get value () {
return value;
}
set value (val) {
value = val;
}
}
class DerivedClass extends BaseClass {
}
module.exports = {
base: new BaseClass(),
derived: new DerivedClass()
};

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

@ -1,11 +0,0 @@
const path = require('path');
const { remote } = require('electron');
const { Buffer } = window;
delete window.Buffer;
delete global.Buffer;
// Test that remote.js doesn't use Buffer global
remote.require(path.join(__dirname, 'print_name.js')).echo(Buffer.from('bar'));
window.test = Buffer.from('buffer');

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

@ -1,11 +0,0 @@
class Foo {
set bar (value) {
throw new Error('setting error');
}
get bar () {
throw new Error('getting error');
}
}
module.exports = new Foo();

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

@ -1,3 +0,0 @@
module.exports = function (error) {
throw error;
};

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

@ -1,4 +0,0 @@
function foo () {}
foo.bar = 'baz';
module.exports = foo;

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

@ -1,3 +0,0 @@
module.exports = function (cb) {
return cb.length;
};

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

@ -1,13 +0,0 @@
exports.setup = function () {
const foo = {};
foo.bar = function () {
return delete foo.bar.baz && delete foo.bar;
};
foo.bar.baz = function () {
return 3;
};
return foo;
};

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

@ -1,17 +0,0 @@
function foo () {
return 'hello';
}
foo.bar = 'baz';
foo.nested = {
prop: 'yes'
};
foo.method1 = function () {
return 'world';
};
foo.method1.prop1 = function () {
return 123;
};
module.exports = {
foo: foo
};

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

@ -1 +0,0 @@
exports.aFunction = function () { return 1127; };

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

@ -1 +0,0 @@
exports.id = 1127;

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

@ -1,11 +0,0 @@
const foo = Object.create(null);
foo.bar = 'baz';
foo.baz = false;
module.exports = {
foo: foo,
bar: 1234,
anonymous: new (class {})(),
getConstructorName: function (value) {
return value.constructor.name;
}
};

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

@ -1,5 +0,0 @@
const { remote, ipcRenderer } = require('electron');
remote.getCurrentWindow().rendererFunc = () => {
ipcRenderer.send('done');
};
remote.getCurrentWindow().rendererFunc();

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

@ -1,5 +0,0 @@
const { ipcRenderer, remote } = require('electron');
window.onload = function () {
ipcRenderer.send('remote', typeof remote);
};

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

@ -1,36 +0,0 @@
exports.print = function (obj) {
return obj.constructor.name;
};
exports.echo = function (obj) {
return obj;
};
const typedArrays = {
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
};
exports.typedArray = function (type, values) {
const constructor = typedArrays[type];
const array = new constructor(values.length);
for (let i = 0; i < values.length; ++i) {
array[i] = values[i];
}
return array;
};
exports.getNaN = function () {
return NaN;
};
exports.getInfinity = function () {
return Infinity;
};

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

@ -1,5 +0,0 @@
exports.twicePromise = function (promise) {
return promise.then(function (value) {
return value * 2;
});
};

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

@ -1,11 +0,0 @@
exports.property = 1127;
function func () {
}
func.property = 'foo';
exports.func = func;
exports.getFunctionProperty = () => {
return `${func.property}-${process.type}`;
};

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

@ -1,5 +0,0 @@
exports.reject = function (promise) {
return promise.then(function () {
throw Error('rejected');
});
};

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

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
const {remote} = require('electron')
const browserWindow = remote.getCurrentWindow()
const handler = () => {}
browserWindow.webContents.on('remote-handler', handler)
browserWindow.webContents.on('other-remote-handler', handler)
</script>
</head>
<body>
</body>
</html>

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

@ -1,11 +0,0 @@
const { BrowserWindow } = require('electron');
class Foo {
set bar (value) { // eslint-disable-line accessor-pairs
if (!(value instanceof BrowserWindow)) {
throw new Error('setting error');
}
}
}
module.exports = new Foo();

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

@ -1,15 +0,0 @@
class Foo {
static foo () {
return 3;
}
baz () {
return 123;
}
}
Foo.bar = 'baz';
module.exports = {
Foo: Foo
};

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

@ -1,32 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
const {ipcRenderer, remote} = require('electron')
const contents = remote.getCurrentWebContents()
// This should not trigger a dereference and a remote getURL call should not fail
contents.emit('render-view-deleted', {}, 'not-a-process-id')
try {
contents.getURL()
} catch (error) {
ipcRenderer.send('error-message', 'Unexpected error on getURL call')
}
// This should trigger a dereference and a remote getURL call should fail
contents.emit('render-view-deleted', {}, contents.getProcessId())
try {
contents.getURL()
ipcRenderer.send('error-message', 'No error thrown')
} catch (error) {
ipcRenderer.send('error-message', error.message)
}
</script>
</head>
<body>
</body>
</html>

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

@ -1,11 +0,0 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer} = require('electron')
process.on('exit', () => {
ipcRenderer.send('SENT_ON_EXIT')
})
</script>
</body>
</html>

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

@ -1,4 +0,0 @@
function hello () {
}
hello.toString = 'hello';
module.exports = { functionWithToStringProperty: hello };

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

@ -1,3 +0,0 @@
exports.reject = function () {
return Promise.reject(new Error('rejected'));
};

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

@ -123,10 +123,7 @@ describe('security warnings', () => {
it('should warn about insecure Content-Security-Policy', async () => {
w = new BrowserWindow({
show: false,
webPreferences: {
enableRemoteModule: false,
...webPreferences
}
webPreferences
});
useCsp = false;
@ -138,10 +135,7 @@ describe('security warnings', () => {
it('should warn about insecure Content-Security-Policy (Trusted Types)', async () => {
w = new BrowserWindow({
show: false,
webPreferences: {
enableRemoteModule: false,
...webPreferences
}
webPreferences
});
useCsp = false;
@ -207,7 +201,7 @@ describe('security warnings', () => {
it('should warn about insecure resources', async () => {
w = new BrowserWindow({
show: false,
webPreferences: { ...webPreferences }
webPreferences
});
w.loadURL(`${serverUrl}/insecure-resources.html`);
@ -225,27 +219,6 @@ describe('security warnings', () => {
const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
expect(message).to.not.include('insecure-resources.html');
});
it('should warn about enabled remote module with remote content', async () => {
w = new BrowserWindow({
show: false,
webPreferences
});
w.loadURL(`${serverUrl}/base-page-security.html`);
const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
expect(message).to.include('enableRemoteModule');
});
it('should not warn about enabled remote module with remote content from localhost', async () => {
w = new BrowserWindow({
show: false,
webPreferences
});
w.loadURL(`${serverUrl}/base-page-security-onload-message.html`);
const [,, message] = await emittedUntil(w.webContents, 'console-message', isLoaded);
expect(message).to.not.include('enableRemoteModule');
});
});
};

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

@ -3,11 +3,8 @@ import * as url from 'url';
import { BrowserWindow, session, ipcMain, app, WebContents } from 'electron/main';
import { closeAllWindows } from './window-helpers';
import { emittedOnce, emittedUntil } from './events-helpers';
import { ifdescribe } from './spec-helpers';
import { expect } from 'chai';
const features = process._linkedBinding('electron_common_features');
async function loadWebView (w: WebContents, attributes: Record<string, string>, openDevTools: boolean = false): Promise<void> {
await w.executeJavaScript(`
new Promise((resolve, reject) => {
@ -654,52 +651,6 @@ describe('<webview> tag', function () {
});
});
ifdescribe(features.isRemoteModuleEnabled())('enableremotemodule attribute', () => {
let w: BrowserWindow;
beforeEach(async () => {
w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, webviewTag: true } });
await w.loadURL('about:blank');
});
afterEach(closeAllWindows);
const generateSpecs = (description: string, sandbox: boolean) => {
describe(description, () => {
const preload = `file://${fixtures}/module/preload-disable-remote.js`;
const src = `file://${fixtures}/api/blank.html`;
it('enables the remote module by default', async () => {
loadWebView(w.webContents, {
preload,
src,
sandbox: sandbox.toString()
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, , message] = await emittedUntil(webViewContents, 'console-message', (event: any, level: any, message: string) => !/deprecated/.test(message));
const typeOfRemote = JSON.parse(message);
expect(typeOfRemote).to.equal('object');
});
it('disables the remote module when false', async () => {
loadWebView(w.webContents, {
preload,
src,
sandbox: sandbox.toString(),
enableremotemodule: 'false'
});
const [, webViewContents] = await emittedOnce(app, 'web-contents-created');
const [, , message] = await emittedOnce(webViewContents, 'console-message');
const typeOfRemote = JSON.parse(message);
expect(typeOfRemote).to.equal('undefined');
});
});
};
generateSpecs('without sandbox', false);
generateSpecs('with sandbox', true);
});
describe('DOM events', () => {
afterEach(closeAllWindows);
it('receives extra properties on DOM events when contextIsolation is enabled', async () => {

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

@ -1,8 +0,0 @@
setImmediate(function () {
try {
const { remote } = require('electron');
console.log(JSON.stringify(typeof remote));
} catch (e) {
console.log(e.message);
}
});

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

@ -108,7 +108,6 @@ app.whenReady().then(async function () {
webPreferences: {
backgroundThrottling: false,
nodeIntegration: true,
enableRemoteModule: false,
webviewTag: true,
contextIsolation: false
}

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

@ -2,11 +2,9 @@
import {
desktopCapturer,
ipcRenderer,
remote,
webFrame,
clipboard,
crashReporter,
screen,
shell
} from 'electron'
@ -23,31 +21,6 @@ ipcRenderer.on('asynchronous-reply', (event, arg: any) => {
ipcRenderer.send('asynchronous-message', 'ping')
// remote
// https://github.com/electron/electron/blob/master/docs/api/remote.md
const BrowserWindow = remote.BrowserWindow
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('https://github.com')
remote.getCurrentWindow().on('close', () => {
// blabla...
})
remote.getCurrentWindow().capturePage().then(image => {
fs.writeFile('/tmp/screenshot.png', image.toBitmap(), err => {
console.log(err)
})
})
remote.getCurrentWebContents().print()
remote.getCurrentWindow().capturePage().then(image => {
remote.require('fs').writeFile('/tmp/screenshot.png', image.toBitmap(), (err: Error) => {
console.log(err)
})
})
// web-frame
// https://github.com/electron/electron/blob/master/docs/api/web-frame.md
@ -166,12 +139,7 @@ holder.ondrop = function (e) {
// nativeImage
// https://github.com/electron/electron/blob/master/docs/api/native-image.md
const Tray = remote.Tray
const appIcon2 = new Tray('/Users/somebody/images/icon.png')
const window2 = new BrowserWindow({ icon: '/Users/somebody/images/window.png' })
const image = clipboard.readImage()
const appIcon3 = new Tray(image)
const appIcon4 = new Tray('/Users/somebody/images/icon.png')
// https://github.com/electron/electron/blob/master/docs/api/process.md
@ -183,36 +151,6 @@ process.once('loaded', function () {
global.clearImmediate = _clearImmediate
})
// screen
// https://github.com/electron/electron/blob/master/docs/api/screen.md
const app = remote.app
let mainWindow: Electron.BrowserWindow = null
app.whenReady().then(() => {
const size = screen.getPrimaryDisplay().workAreaSize
mainWindow = new BrowserWindow({ width: size.width, height: size.height })
})
app.whenReady().then(() => {
const displays = screen.getAllDisplays()
let externalDisplay: any = null
for (const i in displays) {
if (displays[i].bounds.x > 0 || displays[i].bounds.y > 0) {
externalDisplay = displays[i]
break
}
}
if (externalDisplay) {
mainWindow = new BrowserWindow({
x: externalDisplay.bounds.x + 50,
y: externalDisplay.bounds.y + 50
})
}
})
// shell
// https://github.com/electron/electron/blob/master/docs/api/shell.md

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

@ -482,17 +482,6 @@ describe('<webview> tag', function () {
});
});
ifit(features.isRemoteModuleEnabled())('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>`;

3
typings/internal-ambient.d.ts поставляемый
Просмотреть файл

@ -7,7 +7,6 @@ declare var binding: { get: (name: string) => any; process: NodeJS.Process; crea
declare const BUILDFLAG: (flag: boolean) => boolean;
declare const ENABLE_DESKTOP_CAPTURER: boolean;
declare const ENABLE_REMOTE_MODULE: boolean;
declare const ENABLE_VIEWS_API: boolean;
declare namespace NodeJS {
@ -15,7 +14,6 @@ declare namespace NodeJS {
isBuiltinSpellCheckerEnabled(): boolean;
isDesktopCapturerEnabled(): boolean;
isOffscreenRenderingEnabled(): boolean;
isRemoteModuleEnabled(): boolean;
isPDFViewerEnabled(): boolean;
isRunAsNodeEnabled(): boolean;
isFakeLocationProviderEnabled(): boolean;
@ -45,7 +43,6 @@ declare namespace NodeJS {
weaklyTrackValue(value: any): void;
clearWeaklyTrackedValues(): void;
getWeaklyTrackedValues(): any[];
addRemoteObjectRef(contextId: string, id: number): void;
isSameOrigin(a: string, b: string): boolean;
triggerFatalErrorForTesting(): void;
}