init.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. 'use strict';
  2. /* eslint no-eval: "off" */
  3. /* global binding, Buffer */
  4. const events = require('events');
  5. const { EventEmitter } = events;
  6. process.electronBinding = require('@electron/internal/common/electron-binding-setup').electronBindingSetup(binding.get, 'renderer');
  7. const v8Util = process.electronBinding('v8_util');
  8. // Expose Buffer shim as a hidden value. This is used by C++ code to
  9. // deserialize Buffer instances sent from browser process.
  10. v8Util.setHiddenValue(global, 'Buffer', Buffer);
  11. // The `lib/renderer/api/ipc-renderer.ts` module looks for the ipc object in the
  12. // "ipc" hidden value
  13. v8Util.setHiddenValue(global, 'ipc', new EventEmitter());
  14. // The `lib/renderer/ipc-renderer-internal.ts` module looks for the ipc object in the
  15. // "ipc-internal" hidden value
  16. v8Util.setHiddenValue(global, 'ipc-internal', new EventEmitter());
  17. // The process object created by webpack is not an event emitter, fix it so
  18. // the API is more compatible with non-sandboxed renderers.
  19. for (const prop of Object.keys(EventEmitter.prototype)) {
  20. if (Object.prototype.hasOwnProperty.call(process, prop)) {
  21. delete process[prop];
  22. }
  23. }
  24. Object.setPrototypeOf(process, EventEmitter.prototype);
  25. const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal');
  26. const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils');
  27. const {
  28. preloadScripts,
  29. isRemoteModuleEnabled,
  30. isWebViewTagEnabled,
  31. guestInstanceId,
  32. openerId,
  33. process: processProps
  34. } = ipcRendererUtils.invokeSync('ELECTRON_BROWSER_SANDBOX_LOAD');
  35. process.isRemoteModuleEnabled = isRemoteModuleEnabled;
  36. // The electron module depends on process.electronBinding
  37. const electron = require('electron');
  38. const loadedModules = new Map([
  39. ['electron', electron],
  40. ['electron/common', electron],
  41. ['electron/renderer', electron],
  42. ['events', events],
  43. ['timers', require('timers')],
  44. ['url', require('url')]
  45. ]);
  46. // ElectronApiServiceImpl will look for the "ipcNative" hidden object when
  47. // invoking the 'onMessage' callback.
  48. v8Util.setHiddenValue(global, 'ipcNative', {
  49. onMessage (internal, channel, ports, args, senderId) {
  50. const sender = internal ? ipcRendererInternal : electron.ipcRenderer;
  51. sender.emit(channel, { sender, senderId, ports }, ...args);
  52. }
  53. });
  54. // ElectronSandboxedRendererClient will look for the "lifecycle" hidden object when
  55. v8Util.setHiddenValue(global, 'lifecycle', {
  56. onLoaded () {
  57. process.emit('loaded');
  58. },
  59. onExit () {
  60. process.emit('exit');
  61. },
  62. onDocumentStart () {
  63. process.emit('document-start');
  64. },
  65. onDocumentEnd () {
  66. process.emit('document-end');
  67. }
  68. });
  69. const { webFrameInit } = require('@electron/internal/renderer/web-frame-init');
  70. webFrameInit();
  71. // Pass different process object to the preload script(which should not have
  72. // access to things like `process.electronBinding`).
  73. const preloadProcess = new EventEmitter();
  74. Object.assign(preloadProcess, binding.process);
  75. Object.assign(preloadProcess, processProps);
  76. Object.assign(process, binding.process);
  77. Object.assign(process, processProps);
  78. Object.defineProperty(preloadProcess, 'noDeprecation', {
  79. get () {
  80. return process.noDeprecation;
  81. },
  82. set (value) {
  83. process.noDeprecation = value;
  84. }
  85. });
  86. process.on('loaded', () => preloadProcess.emit('loaded'));
  87. process.on('exit', () => preloadProcess.emit('exit'));
  88. process.on('document-start', () => preloadProcess.emit('document-start'));
  89. process.on('document-end', () => preloadProcess.emit('document-end'));
  90. // This is the `require` function that will be visible to the preload script
  91. function preloadRequire (module) {
  92. if (loadedModules.has(module)) {
  93. return loadedModules.get(module);
  94. }
  95. throw new Error(`module not found: ${module}`);
  96. }
  97. // Process command line arguments.
  98. const { hasSwitch } = process.electronBinding('command_line');
  99. // Similar to nodes --expose-internals flag, this exposes electronBinding so
  100. // that tests can call it to get access to some test only bindings
  101. if (hasSwitch('unsafely-expose-electron-internals-for-testing')) {
  102. preloadProcess.electronBinding = process.electronBinding;
  103. }
  104. const contextIsolation = hasSwitch('context-isolation');
  105. const isHiddenPage = hasSwitch('hidden-page');
  106. const rendererProcessReuseEnabled = hasSwitch('disable-electron-site-instance-overrides');
  107. const usesNativeWindowOpen = true;
  108. // The arguments to be passed to isolated world.
  109. const isolatedWorldArgs = { ipcRendererInternal, guestInstanceId, isHiddenPage, openerId, usesNativeWindowOpen, rendererProcessReuseEnabled };
  110. switch (window.location.protocol) {
  111. case 'devtools:': {
  112. // Override some inspector APIs.
  113. require('@electron/internal/renderer/inspector');
  114. break;
  115. }
  116. case 'chrome-extension:': {
  117. break;
  118. }
  119. case 'chrome': {
  120. break;
  121. }
  122. default: {
  123. // Override default web functions.
  124. const { windowSetup } = require('@electron/internal/renderer/window-setup');
  125. windowSetup(guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen, rendererProcessReuseEnabled);
  126. }
  127. }
  128. // Load webview tag implementation.
  129. if (process.isMainFrame) {
  130. const { webViewInit } = require('@electron/internal/renderer/web-view/web-view-init');
  131. webViewInit(contextIsolation, isWebViewTagEnabled, guestInstanceId);
  132. }
  133. // Pass the arguments to isolatedWorld.
  134. if (contextIsolation) {
  135. v8Util.setHiddenValue(global, 'isolated-world-args', isolatedWorldArgs);
  136. }
  137. // Wrap the script into a function executed in global scope. It won't have
  138. // access to the current scope, so we'll expose a few objects as arguments:
  139. //
  140. // - `require`: The `preloadRequire` function
  141. // - `process`: The `preloadProcess` object
  142. // - `Buffer`: Shim of `Buffer` implementation
  143. // - `global`: The window object, which is aliased to `global` by webpack.
  144. function runPreloadScript (preloadSrc) {
  145. const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate, clearImmediate, exports) {
  146. ${preloadSrc}
  147. })`;
  148. // eval in window scope
  149. const preloadFn = binding.createPreloadScript(preloadWrapperSrc);
  150. const { setImmediate, clearImmediate } = require('timers');
  151. preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate, {});
  152. }
  153. for (const { preloadPath, preloadSrc, preloadError } of preloadScripts) {
  154. try {
  155. if (preloadSrc) {
  156. runPreloadScript(preloadSrc);
  157. } else if (preloadError) {
  158. throw preloadError;
  159. }
  160. } catch (error) {
  161. console.error(`Unable to load preload script: ${preloadPath}`);
  162. console.error(error);
  163. ipcRendererInternal.send('ELECTRON_BROWSER_PRELOAD_ERROR', preloadPath, error);
  164. }
  165. }
  166. // Warn about security issues
  167. if (process.isMainFrame) {
  168. const { securityWarnings } = require('@electron/internal/renderer/security-warnings');
  169. securityWarnings();
  170. }