Browse Source

feat: add --enable-api-filtering-logging commandline switch (#20335)

Milan Burda 5 years ago
parent
commit
ccff140046

+ 1 - 1
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)
 

+ 1 - 1
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.

+ 12 - 1
docs/api/chrome-command-line-switches.md → 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.

+ 1 - 1
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

+ 1 - 1
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.

+ 1 - 1
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",

+ 19 - 7
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
     }

+ 9 - 2
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)
   })
 }
 

+ 13 - 1
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,

+ 17 - 6
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)
 }
 

+ 4 - 4
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));

+ 2 - 0
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";

+ 1 - 0
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[];

+ 2 - 2
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')

+ 1 - 1
spec/webview-spec.js

@@ -1052,7 +1052,7 @@ describe('<webview> 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()')
     })
   })