rpc-server.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import { app } from 'electron/main';
  2. import type { IpcMainInvokeEvent, WebContents } from 'electron/main';
  3. import { clipboard, crashReporter } from 'electron/common';
  4. import * as fs from 'fs';
  5. import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
  6. import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
  7. import * as guestViewManager from '@electron/internal/browser/guest-view-manager';
  8. import * as typeUtils from '@electron/internal/common/type-utils';
  9. const eventBinding = process._linkedBinding('electron_browser_event');
  10. const emitCustomEvent = function (contents: WebContents, eventName: string, ...args: any[]) {
  11. const event = eventBinding.createWithSender(contents);
  12. app.emit(eventName, event, contents, ...args);
  13. contents.emit(eventName, event, ...args);
  14. return event;
  15. };
  16. const logStack = function (contents: WebContents, code: string, stack: string) {
  17. if (stack) {
  18. console.warn(`WebContents (${contents.id}): ${code}`, stack);
  19. }
  20. };
  21. // Implements window.close()
  22. ipcMainInternal.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event: ElectronInternal.IpcMainInternalEvent) {
  23. const window = event.sender.getOwnerBrowserWindow();
  24. if (window) {
  25. window.close();
  26. }
  27. event.returnValue = null;
  28. });
  29. ipcMainInternal.handle('ELECTRON_BROWSER_GET_LAST_WEB_PREFERENCES', function (event: IpcMainInvokeEvent) {
  30. return event.sender.getLastWebPreferences();
  31. });
  32. // Methods not listed in this set are called directly in the renderer process.
  33. const allowedClipboardMethods = (() => {
  34. switch (process.platform) {
  35. case 'darwin':
  36. return new Set(['readFindText', 'writeFindText']);
  37. case 'linux':
  38. return new Set(Object.keys(clipboard));
  39. default:
  40. return new Set();
  41. }
  42. })();
  43. ipcMainUtils.handleSync('ELECTRON_BROWSER_CLIPBOARD_SYNC', function (event: IpcMainInvokeEvent, method: string, ...args: any[]) {
  44. if (!allowedClipboardMethods.has(method)) {
  45. throw new Error(`Invalid method: ${method}`);
  46. }
  47. return typeUtils.serialize((clipboard as any)[method](...typeUtils.deserialize(args)));
  48. });
  49. if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
  50. const desktopCapturer = require('@electron/internal/browser/desktop-capturer');
  51. ipcMainInternal.handle('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', async function (event: IpcMainInvokeEvent, options: Electron.SourcesOptions, stack: string) {
  52. logStack(event.sender, 'desktopCapturer.getSources()', stack);
  53. const customEvent = emitCustomEvent(event.sender, 'desktop-capturer-get-sources');
  54. if (customEvent.defaultPrevented) {
  55. console.error('Blocked desktopCapturer.getSources()');
  56. return [];
  57. }
  58. return typeUtils.serialize(await desktopCapturer.getSourcesImpl(event, options));
  59. });
  60. }
  61. const isRemoteModuleEnabled = BUILDFLAG(ENABLE_REMOTE_MODULE)
  62. ? require('@electron/internal/browser/remote/server').isRemoteModuleEnabled
  63. : () => false;
  64. const getPreloadScript = async function (preloadPath: string) {
  65. let preloadSrc = null;
  66. let preloadError = null;
  67. try {
  68. preloadSrc = await fs.promises.readFile(preloadPath, 'utf8');
  69. } catch (error) {
  70. preloadError = error;
  71. }
  72. return { preloadPath, preloadSrc, preloadError };
  73. };
  74. ipcMainUtils.handleSync('ELECTRON_BROWSER_SANDBOX_LOAD', async function (event: IpcMainInvokeEvent) {
  75. const preloadPaths = event.sender._getPreloadPaths();
  76. const webPreferences = event.sender.getLastWebPreferences() || {};
  77. return {
  78. preloadScripts: await Promise.all(preloadPaths.map(path => getPreloadScript(path))),
  79. isRemoteModuleEnabled: isRemoteModuleEnabled(event.sender),
  80. isWebViewTagEnabled: guestViewManager.isWebViewTagEnabled(event.sender),
  81. guestInstanceId: webPreferences.guestInstanceId,
  82. openerId: webPreferences.openerId,
  83. process: {
  84. arch: process.arch,
  85. platform: process.platform,
  86. env: { ...process.env },
  87. version: process.version,
  88. versions: process.versions,
  89. execPath: process.helperExecPath
  90. }
  91. };
  92. });
  93. ipcMainInternal.on('ELECTRON_BROWSER_PRELOAD_ERROR', function (event: ElectronInternal.IpcMainInternalEvent, preloadPath: string, error: Error) {
  94. event.sender.emit('preload-error', event, preloadPath, error);
  95. });
  96. ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_GET_LAST_CRASH_REPORT', () => {
  97. return crashReporter.getLastCrashReport();
  98. });
  99. ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_GET_UPLOADED_REPORTS', () => {
  100. return crashReporter.getUploadedReports();
  101. });
  102. ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_GET_UPLOAD_TO_SERVER', () => {
  103. return crashReporter.getUploadToServer();
  104. });
  105. ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_SET_UPLOAD_TO_SERVER', (event: IpcMainInvokeEvent, uploadToServer: boolean) => {
  106. return crashReporter.setUploadToServer(uploadToServer);
  107. });
  108. ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_GET_CRASHES_DIRECTORY', () => {
  109. return crashReporter.getCrashesDirectory();
  110. });