diff --git a/docs/README.md b/docs/README.md index cf5448cba930..09fe99a2b773 100644 --- a/docs/README.md +++ b/docs/README.md @@ -108,7 +108,7 @@ These individual tutorials expand on topics discussed in the guide above. * [Synopsis](api/synopsis.md) * [Process Object](api/process.md) -* [Supported Chrome Command Line Switches](api/chrome-command-line-switches.md) +* [Supported Command Line Switches](api/command-line-switches.md) * [Environment Variables](api/environment-variables.md) * [Breaking API Changes](api/breaking-changes.md) diff --git a/docs/api/app.md b/docs/api/app.md index 37668dba70eb..7252b5b35570 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -683,7 +683,7 @@ Overrides the current application's name. Returns `String` - The current application locale. Possible return values are documented [here](locales.md). -To set the locale, you'll want to use a command line switch at app startup, which may be found [here](https://github.com/electron/electron/blob/master/docs/api/chrome-command-line-switches.md). +To set the locale, you'll want to use a command line switch at app startup, which may be found [here](https://github.com/electron/electron/blob/master/docs/api/command-line-switches.md). **Note:** When distributing your packaged app, you have to also ship the `locales` folder. diff --git a/docs/api/chrome-command-line-switches.md b/docs/api/command-line-switches.md similarity index 91% rename from docs/api/chrome-command-line-switches.md rename to docs/api/command-line-switches.md index 81d5f503cc71..f7d527f98c01 100644 --- a/docs/api/chrome-command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -1,4 +1,4 @@ -# Supported Chrome Command Line Switches +# Supported Command Line Switches > Command line switches supported by Electron. @@ -181,6 +181,17 @@ logging level for all code in the source files under a `foo/bar` directory. This switch only works when `--enable-logging` is also passed. +## --enable-api-filtering-logging + +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` +- `remote.getGuestWebContents()` / `remote-get-guest-web-contents` + ## --no-sandbox Disables Chromium sandbox, which is now enabled by default. diff --git a/docs/api/command-line.md b/docs/api/command-line.md index 886377e7c9ef..8823dfbe0c4e 100644 --- a/docs/api/command-line.md +++ b/docs/api/command-line.md @@ -12,7 +12,7 @@ app.commandLine.hasSwitch('disable-gpu') ``` For more information on what kinds of flags and switches you can use, check -out the [Chrome Command Line Switches](./chrome-command-line-switches.md) +out the [Command Line Switches](./command-line-switches.md) document. ### Instance Methods diff --git a/docs/api/net-log.md b/docs/api/net-log.md index bdf1ade1586a..0994416c2a80 100644 --- a/docs/api/net-log.md +++ b/docs/api/net-log.md @@ -15,7 +15,7 @@ app.on('ready', async () => { }) ``` -See [`--log-net-log`](chrome-command-line-switches.md#--log-net-logpath) to log network events throughout the app's lifecycle. +See [`--log-net-log`](command-line-switches.md#--log-net-logpath) to log network events throughout the app's lifecycle. **Note:** All methods unless specified can only be used after the `ready` event of the `app` module gets emitted. diff --git a/filenames.auto.gni b/filenames.auto.gni index 0445c386d66b..e110f5365389 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -9,9 +9,9 @@ auto_filenames = { "docs/api/browser-view.md", "docs/api/browser-window-proxy.md", "docs/api/browser-window.md", - "docs/api/chrome-command-line-switches.md", "docs/api/client-request.md", "docs/api/clipboard.md", + "docs/api/command-line-switches.md", "docs/api/command-line.md", "docs/api/content-tracing.md", "docs/api/cookies.md", diff --git a/lib/browser/remote/server.ts b/lib/browser/remote/server.ts index 49b807f9535f..9e9de4251dba 100644 --- a/lib/browser/remote/server.ts +++ b/lib/browser/remote/server.ts @@ -383,6 +383,12 @@ const emitCustomEvent = function (contents: electron.WebContents, eventName: str return event } +const logStack = function (contents: electron.WebContents, code: string, stack: string | undefined) { + if (stack) { + console.warn(`WebContents (${contents.id}): ${code}`, stack) + } +} + handleRemoteCommand('ELECTRON_BROWSER_WRONG_CONTEXT_ERROR', function (event, contextId, passedContextId, id) { const objectId = [passedContextId, id] if (!rendererFunctions.has(objectId)) { @@ -392,7 +398,8 @@ handleRemoteCommand('ELECTRON_BROWSER_WRONG_CONTEXT_ERROR', function (event, con removeRemoteListenersAndLogWarning(event.sender, rendererFunctions.get(objectId)) }) -handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, moduleName) { +handleRemoteCommand('ELECTRON_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) { @@ -406,7 +413,8 @@ handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, modu return valueToMeta(event.sender, contextId, customEvent.returnValue) }) -handleRemoteCommand('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, moduleName) { +handleRemoteCommand('ELECTRON_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) { @@ -420,7 +428,8 @@ handleRemoteCommand('ELECTRON_BROWSER_GET_BUILTIN', function (event, contextId, return valueToMeta(event.sender, contextId, customEvent.returnValue) }) -handleRemoteCommand('ELECTRON_BROWSER_GLOBAL', function (event, contextId, globalName) { +handleRemoteCommand('ELECTRON_BROWSER_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) { @@ -434,7 +443,8 @@ handleRemoteCommand('ELECTRON_BROWSER_GLOBAL', function (event, contextId, globa return valueToMeta(event.sender, contextId, customEvent.returnValue) }) -handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WINDOW', function (event, contextId) { +handleRemoteCommand('ELECTRON_BROWSER_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) { @@ -448,7 +458,8 @@ handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WINDOW', function (event, contextI return valueToMeta(event.sender, contextId, customEvent.returnValue) }) -handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event, contextId) { +handleRemoteCommand('ELECTRON_BROWSER_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) { @@ -549,14 +560,15 @@ handleRemoteCommand('ELECTRON_BROWSER_CONTEXT_RELEASE', (event, contextId) => { return null }) -handleRemoteCommand('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId) { +handleRemoteCommand('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, contextId, guestInstanceId, stack) { + logStack(event.sender, 'remote.getGuestWebContents()', stack) const guest = guestViewManager.getGuestForWebContents(guestInstanceId, event.sender) const customEvent = emitCustomEvent(event.sender, 'remote-get-guest-web-contents', guest) if (customEvent.returnValue === undefined) { if (customEvent.defaultPrevented) { - throw new Error(`Blocked remote.getGuestForWebContents()`) + throw new Error(`Blocked remote.getGuestWebContents()`) } else { customEvent.returnValue = guest } diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index a56c295e97e9..4db3164ef451 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -23,6 +23,12 @@ const emitCustomEvent = function (contents, eventName, ...args) { return event } +const logStack = function (contents, code, stack) { + if (stack) { + console.warn(`WebContents (${contents.id}): ${code}`, stack) + } +} + // Implements window.close() ipcMainInternal.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event) { const window = event.sender.getOwnerBrowserWindow() @@ -63,7 +69,8 @@ ipcMainUtils.handleSync('ELECTRON_BROWSER_CLIPBOARD', function (event, method, . if (features.isDesktopCapturerEnabled()) { const desktopCapturer = require('@electron/internal/browser/desktop-capturer') - ipcMainInternal.handle('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, ...args) { + ipcMainInternal.handle('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, options, stack) { + logStack(event.sender, 'desktopCapturer.getSources()', stack) const customEvent = emitCustomEvent(event.sender, 'desktop-capturer-get-sources') if (customEvent.defaultPrevented) { @@ -71,7 +78,7 @@ if (features.isDesktopCapturerEnabled()) { return [] } - return desktopCapturer.getSources(event, ...args) + return desktopCapturer.getSources(event, options) }) } diff --git a/lib/renderer/api/desktop-capturer.ts b/lib/renderer/api/desktop-capturer.ts index d8de9a35a45a..538f6be1322b 100644 --- a/lib/renderer/api/desktop-capturer.ts +++ b/lib/renderer/api/desktop-capturer.ts @@ -1,12 +1,24 @@ import { nativeImage } from 'electron' import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal' +const { hasSwitch } = process.electronBinding('command_line') + // |options.types| can't be empty and must be an array function isValid (options: Electron.SourcesOptions) { const types = options ? options.types : undefined return Array.isArray(types) } +const enableStacks = hasSwitch('enable-api-filtering-logging') + +function getCurrentStack () { + const target = {} + if (enableStacks) { + Error.captureStackTrace(target, getCurrentStack) + } + return (target as any).stack +} + export async function getSources (options: Electron.SourcesOptions) { if (!isValid(options)) throw new Error('Invalid options') @@ -21,7 +33,7 @@ export async function getSources (options: Electron.SourcesOptions) { captureScreen, thumbnailSize, fetchWindowIcons - } as ElectronInternal.GetSourcesOptions) + } as ElectronInternal.GetSourcesOptions, getCurrentStack()) return sources.map(source => ({ id: source.id, diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index 94c2bcce336e..50aef57bc743 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -1,6 +1,7 @@ 'use strict' const v8Util = process.electronBinding('v8_util') +const { hasSwitch } = process.electronBinding('command_line') const { CallbacksRegistry } = require('@electron/internal/renderer/remote/callbacks-registry') const bufferUtils = require('@electron/internal/common/remote/buffer-utils') @@ -281,6 +282,16 @@ function handleMessage (channel, handler) { }) } +const enableStacks = hasSwitch('enable-api-filtering-logging') + +function getCurrentStack () { + const target = {} + if (enableStacks) { + Error.captureStackTrace(target, getCurrentStack) + } + return target.stack +} + // Browser calls a callback in renderer. handleMessage('ELECTRON_RENDERER_CALLBACK', (id, args) => { callbacksRegistry.apply(id, metaToValue(args)) @@ -293,34 +304,34 @@ handleMessage('ELECTRON_RENDERER_RELEASE_CALLBACK', (id) => { exports.require = (module) => { const command = 'ELECTRON_BROWSER_REQUIRE' - const meta = ipcRendererInternal.sendSync(command, contextId, module) + const meta = ipcRendererInternal.sendSync(command, contextId, module, getCurrentStack()) return metaToValue(meta) } // Alias to remote.require('electron').xxx. exports.getBuiltin = (module) => { const command = 'ELECTRON_BROWSER_GET_BUILTIN' - const meta = ipcRendererInternal.sendSync(command, contextId, module) + const meta = ipcRendererInternal.sendSync(command, contextId, module, getCurrentStack()) return metaToValue(meta) } exports.getCurrentWindow = () => { const command = 'ELECTRON_BROWSER_CURRENT_WINDOW' - const meta = ipcRendererInternal.sendSync(command, contextId) + const meta = ipcRendererInternal.sendSync(command, contextId, getCurrentStack()) return metaToValue(meta) } // Get current WebContents object. exports.getCurrentWebContents = () => { const command = 'ELECTRON_BROWSER_CURRENT_WEB_CONTENTS' - const meta = ipcRendererInternal.sendSync(command, contextId) + const meta = ipcRendererInternal.sendSync(command, contextId, getCurrentStack()) return metaToValue(meta) } // Get a global object in browser. exports.getGlobal = (name) => { const command = 'ELECTRON_BROWSER_GLOBAL' - const meta = ipcRendererInternal.sendSync(command, contextId, name) + const meta = ipcRendererInternal.sendSync(command, contextId, name, getCurrentStack()) return metaToValue(meta) } @@ -339,7 +350,7 @@ exports.createFunctionWithReturnValue = (returnValue) => { // Get the guest WebContents from guestInstanceId. exports.getGuestWebContents = (guestInstanceId) => { const command = 'ELECTRON_BROWSER_GUEST_WEB_CONTENTS' - const meta = ipcRendererInternal.sendSync(command, contextId, guestInstanceId) + const meta = ipcRendererInternal.sendSync(command, contextId, guestInstanceId, getCurrentStack()) return metaToValue(meta) } diff --git a/shell/browser/atom_browser_client.cc b/shell/browser/atom_browser_client.cc index 3ec5734f9514..45c4d569b6e4 100644 --- a/shell/browser/atom_browser_client.cc +++ b/shell/browser/atom_browser_client.cc @@ -532,10 +532,10 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches( // Copy following switches to child process. static const char* const kCommonSwitchNames[] = { - switches::kStandardSchemes, switches::kEnableSandbox, - switches::kSecureSchemes, switches::kBypassCSPSchemes, - switches::kCORSSchemes, switches::kFetchSchemes, - switches::kServiceWorkerSchemes}; + switches::kStandardSchemes, switches::kEnableSandbox, + switches::kSecureSchemes, switches::kBypassCSPSchemes, + switches::kCORSSchemes, switches::kFetchSchemes, + switches::kServiceWorkerSchemes, switches::kEnableApiFilteringLogging}; command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(), kCommonSwitchNames, base::size(kCommonSwitchNames)); diff --git a/shell/common/options_switches.cc b/shell/common/options_switches.cc index 7499ecfd246b..e409c875f6f9 100644 --- a/shell/common/options_switches.cc +++ b/shell/common/options_switches.cc @@ -220,6 +220,8 @@ const char kAppUserModelId[] = "app-user-model-id"; // The application path const char kAppPath[] = "app-path"; +const char kEnableApiFilteringLogging[] = "enable-api-filtering-logging"; + // The command line switch versions of the options. const char kBackgroundColor[] = "background-color"; const char kPreloadScript[] = "preload"; diff --git a/shell/common/options_switches.h b/shell/common/options_switches.h index e562910ee00e..e24dfa2d8f59 100644 --- a/shell/common/options_switches.h +++ b/shell/common/options_switches.h @@ -107,6 +107,7 @@ extern const char kFetchSchemes[]; extern const char kCORSSchemes[]; extern const char kAppUserModelId[]; extern const char kAppPath[]; +extern const char kEnableApiFilteringLogging[]; extern const char kBackgroundColor[]; extern const char kPreloadScript[]; diff --git a/spec/ts-smoke/electron/main.ts b/spec/ts-smoke/electron/main.ts index 3a46ba9c3a6b..d9f256d2adfa 100644 --- a/spec/ts-smoke/electron/main.ts +++ b/spec/ts-smoke/electron/main.ts @@ -356,8 +356,8 @@ app.on('ready', () => { window.loadURL('https://github.com') }) -// Supported Chrome command line switches -// https://github.com/atom/electron/blob/master/docs/api/chrome-command-line-switches.md +// Supported command line switches +// https://github.com/atom/electron/blob/master/docs/api/command-line-switches.md app.commandLine.appendSwitch('remote-debugging-port', '8315') app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 5b83686fa84f..a0cc282146d6 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -1052,7 +1052,7 @@ describe(' tag', function () { await loadWebView(webview, { src }) ipcRenderer.send('handle-next-remote-get-guest-web-contents') - expect(() => webview.getWebContents()).to.throw('Blocked remote.getGuestForWebContents()') + expect(() => webview.getWebContents()).to.throw('Blocked remote.getGuestWebContents()') }) })