From 1130e034a0e428a95b847228523a1e90fd65b638 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Wed, 2 Feb 2022 16:35:15 -0800
Subject: [PATCH 01/19] Make file url blacklist case-insensitive

---
 desktop/main.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/desktop/main.js b/desktop/main.js
index c2b537e48d4d..7c7582108f58 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -203,7 +203,7 @@ const mainWindow = (() => {
             // open the default browser instead of a new electron window
             browserWindow.webContents.on('new-window', (e, url) => {
                 // make sure local urls stay in electron perimeter
-                if (url.substr(0, 'file://'.length) === 'file://') {
+                if (url.substr(0, 'file://'.length).toLowerCase() === 'file://') {
                     return;
                 }
 

From ea9962d015a9f28df8f5dc27f39819489afb8975 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 13:44:04 -0800
Subject: [PATCH 02/19] Disable node-integration and enable context isolation

---
 config/webpack/webpack.common.js              |  4 --
 desktop/ELECTRON_EVENTS.js                    |  3 ++
 desktop/main.js                               | 11 +++---
 desktop/preload.js                            | 37 +++++++++++++++++++
 .../UpdateAppModal/index.desktop.js           |  4 +-
 .../focusApp/index.desktop.js                 |  4 +-
 .../updateUnread/index.desktop.js             |  4 +-
 src/libs/Visibility/index.js                  |  8 +---
 src/setup/platformSetup/index.desktop.js      |  7 ++--
 9 files changed, 56 insertions(+), 26 deletions(-)
 create mode 100644 desktop/preload.js

diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js
index 64e8c01ee528..e2d3ca0974af 100644
--- a/config/webpack/webpack.common.js
+++ b/config/webpack/webpack.common.js
@@ -146,8 +146,4 @@ const webpackConfig = {
     },
 };
 
-if (platform === 'desktop') {
-    webpackConfig.target = 'electron-renderer';
-}
-
 module.exports = webpackConfig;
diff --git a/desktop/ELECTRON_EVENTS.js b/desktop/ELECTRON_EVENTS.js
index 8fbc750d499a..b12910b79e99 100644
--- a/desktop/ELECTRON_EVENTS.js
+++ b/desktop/ELECTRON_EVENTS.js
@@ -2,6 +2,9 @@ const ELECTRON_EVENTS = {
     REQUEST_UPDATE_BADGE_COUNT: 'requestUpdateBadgeCount',
     REQUEST_VISIBILITY: 'requestVisibility',
     REQUEST_FOCUS_APP: 'requestFocusApp',
+    SHOW_KEYBOARD_SHORTCUTS_MODAL: 'show-keyboard-shortcuts-modal',
+    START_UPDATE: 'start-update',
+    UPDATE_DOWNLOADED: 'update-downloaded',
 };
 
 module.exports = ELECTRON_EVENTS;
diff --git a/desktop/main.js b/desktop/main.js
index 7c7582108f58..50e7202c7a8b 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -90,7 +90,7 @@ const showKeyboardShortcutsModal = (browserWindow) => {
     if (!browserWindow.isVisible()) {
         return;
     }
-    browserWindow.webContents.send('show-keyboard-shortcuts-modal');
+    browserWindow.webContents.send(ELECTRON_EVENTS.SHOW_KEYBOARD_SHORTCUTS_MODAL);
 };
 
 // Defines the system-level menu item for manually triggering an update after
@@ -109,17 +109,17 @@ const keyboardShortcutsMenu = new MenuItem({
 // Actual auto-update listeners
 const electronUpdater = browserWindow => ({
     init: () => {
-        autoUpdater.on('update-downloaded', (info) => {
+        autoUpdater.on(ELECTRON_EVENTS.UPDATE_DOWNLOADED, (info) => {
             downloadedVersion = info.version;
             updateAppMenuItem.enabled = true;
             if (browserWindow.isVisible()) {
-                browserWindow.webContents.send('update-downloaded', info.version);
+                browserWindow.webContents.send(ELECTRON_EVENTS.UPDATE_DOWNLOADED, info.version);
             } else {
                 quitAndInstallWithUpdate();
             }
         });
 
-        ipcMain.on('start-update', quitAndInstallWithUpdate);
+        ipcMain.on(ELECTRON_EVENTS.START_UPDATE, quitAndInstallWithUpdate);
         autoUpdater.checkForUpdates();
     },
     update: () => {
@@ -145,7 +145,8 @@ const mainWindow = (() => {
                 width: 1200,
                 height: 900,
                 webPreferences: {
-                    nodeIntegration: true,
+                    preload: `${__dirname}/preload.js`,
+                    contextIsolation: true,
                 },
                 titleBarStyle: 'hidden',
             });
diff --git a/desktop/preload.js b/desktop/preload.js
new file mode 100644
index 000000000000..38619a03d841
--- /dev/null
+++ b/desktop/preload.js
@@ -0,0 +1,37 @@
+const _ = require('underscore');
+const {
+    contextBridge,
+    ipcRenderer,
+} = require('electron');
+const ELECTRON_EVENTS = require('./ELECTRON_EVENTS');
+
+const WHITELIST_CHANNELS_RENDERER_TO_MAIN = [
+    ELECTRON_EVENTS.REQUEST_FOCUS_APP,
+    ELECTRON_EVENTS.REQUEST_UPDATE_BADGE_COUNT,
+    ELECTRON_EVENTS.REQUEST_VISIBILITY,
+    ELECTRON_EVENTS.START_UPDATE,
+];
+
+const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
+    ELECTRON_EVENTS.UPDATE_DOWNLOADED,
+];
+
+contextBridge.exposeInMainWorld('electronContextBridge', {
+    send: (channel, data) => {
+        if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
+            // eslint-disable-next-line no-console
+            console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
+        }
+
+        ipcRenderer.send(channel, data);
+    },
+    on: (channel, func) => {
+        if (!_.contains(WHITELIST_CHANNELS_MAIN_TO_RENDERER, channel)) {
+            // eslint-disable-next-line no-console
+            console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
+        }
+
+        // Deliberately strip event as it includes `sender`
+        ipcRenderer.on(channel, (event, ...args) => func(...args));
+    },
+});
diff --git a/src/components/UpdateAppModal/index.desktop.js b/src/components/UpdateAppModal/index.desktop.js
index 4a3c40f7b664..1a77ce1737aa 100644
--- a/src/components/UpdateAppModal/index.desktop.js
+++ b/src/components/UpdateAppModal/index.desktop.js
@@ -1,14 +1,14 @@
 import React from 'react';
-import {ipcRenderer} from 'electron';
 import BaseUpdateAppModal from './BaseUpdateAppModal';
 import {propTypes} from './updateAppModalPropTypes';
+import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
 
 const UpdateAppModal = (props) => {
     const updateApp = () => {
         if (props.onSubmit) {
             props.onSubmit();
         }
-        ipcRenderer.sendSync('start-update');
+        window.electronContextBridge.send(ELECTRON_EVENTS.START_UPDATE);
     };
     return <BaseUpdateAppModal onSubmit={updateApp} />;
 };
diff --git a/src/libs/Notification/LocalNotification/focusApp/index.desktop.js b/src/libs/Notification/LocalNotification/focusApp/index.desktop.js
index d39fd6b1d71b..1999dc20f586 100644
--- a/src/libs/Notification/LocalNotification/focusApp/index.desktop.js
+++ b/src/libs/Notification/LocalNotification/focusApp/index.desktop.js
@@ -1,7 +1,5 @@
 import ELECTRON_EVENTS from '../../../../../desktop/ELECTRON_EVENTS';
 
-const ipcRenderer = window.require('electron').ipcRenderer;
-
 export default () => {
-    ipcRenderer.send(ELECTRON_EVENTS.REQUEST_FOCUS_APP);
+    window.electronContextBridge.send(ELECTRON_EVENTS.REQUEST_FOCUS_APP);
 };
diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js
index 34176ff9b7bd..91fc21c8b4b9 100644
--- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js
+++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js
@@ -1,7 +1,5 @@
 import ELECTRON_EVENTS from '../../../../desktop/ELECTRON_EVENTS';
 
-const ipcRenderer = window.require('electron').ipcRenderer;
-
 /**
  * Set the badge on desktop
  *
@@ -10,7 +8,7 @@ const ipcRenderer = window.require('electron').ipcRenderer;
 function updateUnread(totalCount) {
     // Ask the main Electron process to update our
     // badge count in the Mac OS dock icon
-    ipcRenderer.send(ELECTRON_EVENTS.REQUEST_UPDATE_BADGE_COUNT, totalCount);
+    window.electronContextBridge.send(ELECTRON_EVENTS.REQUEST_UPDATE_BADGE_COUNT, totalCount);
 }
 
 export default updateUnread;
diff --git a/src/libs/Visibility/index.js b/src/libs/Visibility/index.js
index 4368dc15218d..40b9cc9fb482 100644
--- a/src/libs/Visibility/index.js
+++ b/src/libs/Visibility/index.js
@@ -1,9 +1,5 @@
 import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
 
-// We conditionally import the ipcRenderer here so that we can
-// communicate with the main Electron process
-const ipcRenderer = window.require ? window.require('electron').ipcRenderer : null;
-
 /**
  * Detects whether the app is visible or not. Electron supports
  * document.visibilityState, but switching to another app while
@@ -14,8 +10,8 @@ const ipcRenderer = window.require ? window.require('electron').ipcRenderer : nu
  * @returns {Boolean}
  */
 function isVisible() {
-    return ipcRenderer
-        ? ipcRenderer.sendSync(ELECTRON_EVENTS.REQUEST_VISIBILITY)
+    return window.electronContextBridge
+        ? window.electronContextBridge.send(ELECTRON_EVENTS.REQUEST_VISIBILITY)
         : document.visibilityState === 'visible';
 }
 
diff --git a/src/setup/platformSetup/index.desktop.js b/src/setup/platformSetup/index.desktop.js
index 193e67a694f4..1dfc2dcb80f9 100644
--- a/src/setup/platformSetup/index.desktop.js
+++ b/src/setup/platformSetup/index.desktop.js
@@ -1,9 +1,9 @@
 import {AppRegistry} from 'react-native';
-import {ipcRenderer} from 'electron';
 import Config from '../../CONFIG';
 import LocalNotification from '../../libs/Notification/LocalNotification';
 import * as KeyboardShortcuts from '../../libs/actions/KeyboardShortcuts';
 import DateUtils from '../../libs/DateUtils';
+import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
 
 
 export default function () {
@@ -11,12 +11,13 @@ export default function () {
         rootTag: document.getElementById('root'),
     });
 
-    ipcRenderer.on('update-downloaded', () => {
+    // Send local notification when update is downloaded
+    window.electronContextBridge.on(ELECTRON_EVENTS.UPDATE_DOWNLOADED, () => {
         LocalNotification.showUpdateAvailableNotification();
     });
 
     // Trigger action to show keyboard shortcuts
-    ipcRenderer.on('show-keyboard-shortcuts-modal', KeyboardShortcuts.showKeyboardShortcutModal);
+    window.electronContextBridge.on(ELECTRON_EVENTS.SHOW_KEYBOARD_SHORTCUTS_MODAL, KeyboardShortcuts.showKeyboardShortcutModal);
 
     // Start current date updater
     DateUtils.startCurrentDateUpdater();

From 0b4d4bd5e3adf7fff6c438f7ff753d27145f5120 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 13:46:14 -0800
Subject: [PATCH 03/19] Delete unused markdown file

---
 desktop/test.md | 1 -
 1 file changed, 1 deletion(-)
 delete mode 100644 desktop/test.md

diff --git a/desktop/test.md b/desktop/test.md
deleted file mode 100644
index eeb7d338afd6..000000000000
--- a/desktop/test.md
+++ /dev/null
@@ -1 +0,0 @@
-This is only for issue lifecycle testing purposes. I will delete it later. Change3
\ No newline at end of file

From a6f911936fab5327f787a294a3ba7563b4873edd Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 13:47:44 -0800
Subject: [PATCH 04/19] Rename window.electronContextBridge to window.electron

---
 desktop/preload.js                                            | 2 +-
 src/components/UpdateAppModal/index.desktop.js                | 2 +-
 .../Notification/LocalNotification/focusApp/index.desktop.js  | 2 +-
 src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js | 2 +-
 src/libs/Visibility/index.js                                  | 4 ++--
 src/setup/platformSetup/index.desktop.js                      | 4 ++--
 6 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/desktop/preload.js b/desktop/preload.js
index 38619a03d841..7907d0ce2e53 100644
--- a/desktop/preload.js
+++ b/desktop/preload.js
@@ -16,7 +16,7 @@ const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
     ELECTRON_EVENTS.UPDATE_DOWNLOADED,
 ];
 
-contextBridge.exposeInMainWorld('electronContextBridge', {
+contextBridge.exposeInMainWorld('electron', {
     send: (channel, data) => {
         if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
             // eslint-disable-next-line no-console
diff --git a/src/components/UpdateAppModal/index.desktop.js b/src/components/UpdateAppModal/index.desktop.js
index 1a77ce1737aa..bf3af752501b 100644
--- a/src/components/UpdateAppModal/index.desktop.js
+++ b/src/components/UpdateAppModal/index.desktop.js
@@ -8,7 +8,7 @@ const UpdateAppModal = (props) => {
         if (props.onSubmit) {
             props.onSubmit();
         }
-        window.electronContextBridge.send(ELECTRON_EVENTS.START_UPDATE);
+        window.electron.send(ELECTRON_EVENTS.START_UPDATE);
     };
     return <BaseUpdateAppModal onSubmit={updateApp} />;
 };
diff --git a/src/libs/Notification/LocalNotification/focusApp/index.desktop.js b/src/libs/Notification/LocalNotification/focusApp/index.desktop.js
index 1999dc20f586..f00c72dc1af8 100644
--- a/src/libs/Notification/LocalNotification/focusApp/index.desktop.js
+++ b/src/libs/Notification/LocalNotification/focusApp/index.desktop.js
@@ -1,5 +1,5 @@
 import ELECTRON_EVENTS from '../../../../../desktop/ELECTRON_EVENTS';
 
 export default () => {
-    window.electronContextBridge.send(ELECTRON_EVENTS.REQUEST_FOCUS_APP);
+    window.electron.send(ELECTRON_EVENTS.REQUEST_FOCUS_APP);
 };
diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js
index 91fc21c8b4b9..b9a689e89c42 100644
--- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js
+++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js
@@ -8,7 +8,7 @@ import ELECTRON_EVENTS from '../../../../desktop/ELECTRON_EVENTS';
 function updateUnread(totalCount) {
     // Ask the main Electron process to update our
     // badge count in the Mac OS dock icon
-    window.electronContextBridge.send(ELECTRON_EVENTS.REQUEST_UPDATE_BADGE_COUNT, totalCount);
+    window.electron.send(ELECTRON_EVENTS.REQUEST_UPDATE_BADGE_COUNT, totalCount);
 }
 
 export default updateUnread;
diff --git a/src/libs/Visibility/index.js b/src/libs/Visibility/index.js
index 40b9cc9fb482..10304a29ad46 100644
--- a/src/libs/Visibility/index.js
+++ b/src/libs/Visibility/index.js
@@ -10,8 +10,8 @@ import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
  * @returns {Boolean}
  */
 function isVisible() {
-    return window.electronContextBridge
-        ? window.electronContextBridge.send(ELECTRON_EVENTS.REQUEST_VISIBILITY)
+    return window.electron
+        ? window.electron.send(ELECTRON_EVENTS.REQUEST_VISIBILITY)
         : document.visibilityState === 'visible';
 }
 
diff --git a/src/setup/platformSetup/index.desktop.js b/src/setup/platformSetup/index.desktop.js
index 1dfc2dcb80f9..1a31d974b167 100644
--- a/src/setup/platformSetup/index.desktop.js
+++ b/src/setup/platformSetup/index.desktop.js
@@ -12,12 +12,12 @@ export default function () {
     });
 
     // Send local notification when update is downloaded
-    window.electronContextBridge.on(ELECTRON_EVENTS.UPDATE_DOWNLOADED, () => {
+    window.electron.on(ELECTRON_EVENTS.UPDATE_DOWNLOADED, () => {
         LocalNotification.showUpdateAvailableNotification();
     });
 
     // Trigger action to show keyboard shortcuts
-    window.electronContextBridge.on(ELECTRON_EVENTS.SHOW_KEYBOARD_SHORTCUTS_MODAL, KeyboardShortcuts.showKeyboardShortcutModal);
+    window.electron.on(ELECTRON_EVENTS.SHOW_KEYBOARD_SHORTCUTS_MODAL, KeyboardShortcuts.showKeyboardShortcutModal);
 
     // Start current date updater
     DateUtils.startCurrentDateUpdater();

From c1c5ca92e1fb8d651d7225baacdcd7ecc1fc374e Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 13:48:07 -0800
Subject: [PATCH 05/19] Fix context bridge whitelist

---
 desktop/preload.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/desktop/preload.js b/desktop/preload.js
index 7907d0ce2e53..dbe8606f5d51 100644
--- a/desktop/preload.js
+++ b/desktop/preload.js
@@ -21,6 +21,7 @@ contextBridge.exposeInMainWorld('electron', {
         if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
             // eslint-disable-next-line no-console
             console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
+            return;
         }
 
         ipcRenderer.send(channel, data);
@@ -29,6 +30,7 @@ contextBridge.exposeInMainWorld('electron', {
         if (!_.contains(WHITELIST_CHANNELS_MAIN_TO_RENDERER, channel)) {
             // eslint-disable-next-line no-console
             console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
+            return;
         }
 
         // Deliberately strip event as it includes `sender`

From e5c7140cd10c308de27b2bcf74d7c6a7ae41f4a4 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 13:49:14 -0800
Subject: [PATCH 06/19] Rename preload to contextBridge

---
 desktop/{preload.js => contextBridge.js} | 0
 desktop/main.js                          | 2 +-
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename desktop/{preload.js => contextBridge.js} (100%)

diff --git a/desktop/preload.js b/desktop/contextBridge.js
similarity index 100%
rename from desktop/preload.js
rename to desktop/contextBridge.js
diff --git a/desktop/main.js b/desktop/main.js
index 50e7202c7a8b..56fa4208118f 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -145,7 +145,7 @@ const mainWindow = (() => {
                 width: 1200,
                 height: 900,
                 webPreferences: {
-                    preload: `${__dirname}/preload.js`,
+                    preload: `${__dirname}/contextBridge.js`,
                     contextIsolation: true,
                 },
                 titleBarStyle: 'hidden',

From 66c37069471d9e067316f017c3fd013e60947b56 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 14:16:25 -0800
Subject: [PATCH 07/19] Upgrade to electron 12.x.x

---
 desktop/main.js   | 14 ++++++++------
 package-lock.json | 44 ++++++++++++++------------------------------
 package.json      |  2 +-
 3 files changed, 23 insertions(+), 37 deletions(-)

diff --git a/desktop/main.js b/desktop/main.js
index 56fa4208118f..a981210af3d1 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -202,15 +202,17 @@ const mainWindow = (() => {
 
             // When the user clicks a link that has target="_blank" (which is all external links)
             // open the default browser instead of a new electron window
-            browserWindow.webContents.on('new-window', (e, url) => {
-                // make sure local urls stay in electron perimeter
+            browserWindow.webContents.setWindowOpenHandler(({url}) => {
+                const denial = {action: 'deny'};
+
+                // Make sure local urls stay in electron perimeter
                 if (url.substr(0, 'file://'.length).toLowerCase() === 'file://') {
-                    return;
+                    return denial;
                 }
 
-                // and open every other protocol in the browser
-                e.preventDefault();
-                return shell.openExternal(url);
+                // Open every other protocol in the default browser, not Electron
+                shell.openExternal(url);
+                return denial;
             });
 
             // Flag to determine is user is trying to quit the whole application altogether
diff --git a/package-lock.json b/package-lock.json
index 3f1a89c2118a..a0c2e9d14652 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2767,15 +2767,15 @@
       }
     },
     "@electron/get": {
-      "version": "1.12.4",
-      "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.4.tgz",
-      "integrity": "sha512-6nr9DbJPUR9Xujw6zD3y+rS95TyItEVM0NVjt1EehY2vUWfIgPiIPVHxCvaTS0xr2B+DRxovYVKbuOWqC35kjg==",
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz",
+      "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==",
       "dev": true,
       "requires": {
         "debug": "^4.1.1",
         "env-paths": "^2.2.0",
         "fs-extra": "^8.1.0",
-        "global-agent": "^2.0.2",
+        "global-agent": "^3.0.0",
         "global-tunnel-ng": "^2.7.1",
         "got": "^9.6.0",
         "progress": "^2.0.3",
@@ -18228,9 +18228,9 @@
       "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
     },
     "boolean": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.0.tgz",
-      "integrity": "sha512-K6r5tvO1ykeYerI7jIyTvSFw2l6D6DzqkljGj2E2uyYAAdDo2SV4qGJIV75cHIQpTFyb6BB0BEHiDdDrFsNI+g==",
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz",
+      "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==",
       "dev": true,
       "optional": true
     },
@@ -21770,22 +21770,14 @@
       }
     },
     "electron": {
-      "version": "11.4.8",
-      "resolved": "https://registry.npmjs.org/electron/-/electron-11.4.8.tgz",
-      "integrity": "sha512-NrxlDZN1sWiDCWWOm5aX+tPGtiLgsCUwNqNFP3eJfY+RPdYLsxYRJDFa1vc4GcuCZEp9kZusINjmpPWsvJdspQ==",
+      "version": "12.2.3",
+      "resolved": "https://registry.npmjs.org/electron/-/electron-12.2.3.tgz",
+      "integrity": "sha512-B27c7eqx1bC5kea6An8oVhk1pShNC4VGqWarHMhD47MDtmg54KepHO5AbAvmKKZK/jWN7NTC7wyCYTDElJNtQA==",
       "dev": true,
       "requires": {
         "@electron/get": "^1.0.1",
-        "@types/node": "^12.0.12",
+        "@types/node": "^14.6.2",
         "extract-zip": "^1.0.3"
-      },
-      "dependencies": {
-        "@types/node": {
-          "version": "12.20.14",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.14.tgz",
-          "integrity": "sha512-iFJOS5Q470FF+r4Ol2pSley7/wCNVqf+jgjhtxLLaJcDs+To2iCxlXIkJXrGLD9w9G/oJ9ibySu7z92DCwr7Pg==",
-          "dev": true
-        }
       }
     },
     "electron-builder": {
@@ -25471,14 +25463,13 @@
       }
     },
     "global-agent": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.2.0.tgz",
-      "integrity": "sha512-+20KpaW6DDLqhG7JDiJpD1JvNvb8ts+TNl7BPOYcURqCrXqnN1Vf+XVOrkKJAFPqfX+oEhsdzOj1hLWkBTdNJg==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
+      "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
       "dev": true,
       "optional": true,
       "requires": {
         "boolean": "^3.0.1",
-        "core-js": "^3.6.5",
         "es6-error": "^4.1.1",
         "matcher": "^3.0.0",
         "roarr": "^2.15.3",
@@ -25486,13 +25477,6 @@
         "serialize-error": "^7.0.1"
       },
       "dependencies": {
-        "core-js": {
-          "version": "3.13.1",
-          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.13.1.tgz",
-          "integrity": "sha512-JqveUc4igkqwStL2RTRn/EPFGBOfEZHxJl/8ej1mXJR75V3go2mFF4bmUYkEIT1rveHKnkUlcJX/c+f1TyIovQ==",
-          "dev": true,
-          "optional": true
-        },
         "serialize-error": {
           "version": "7.0.1",
           "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
diff --git a/package.json b/package.json
index 9a0c3cc6d98d..15ec389cd8e4 100644
--- a/package.json
+++ b/package.json
@@ -152,7 +152,7 @@
     "css-loader": "^5.2.4",
     "detox": "^17.8.3",
     "diff-so-fancy": "^1.3.0",
-    "electron": "^11.4.8",
+    "electron": "^12.0.0",
     "electron-builder": "^22.13.1",
     "electron-notarize": "^1.0.0",
     "electron-reloader": "^1.2.0",

From 196870765289c6bee3b5e2a5d1524bc1b197d091 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 14:39:50 -0800
Subject: [PATCH 08/19] Upgrade electron to 17.0.0

---
 package-lock.json | 53 +++++++++++++++++++++++------------------------
 package.json      |  4 ++--
 2 files changed, 28 insertions(+), 29 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index a0c2e9d14652..ed3aca2affbc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21770,12 +21770,12 @@
       }
     },
     "electron": {
-      "version": "12.2.3",
-      "resolved": "https://registry.npmjs.org/electron/-/electron-12.2.3.tgz",
-      "integrity": "sha512-B27c7eqx1bC5kea6An8oVhk1pShNC4VGqWarHMhD47MDtmg54KepHO5AbAvmKKZK/jWN7NTC7wyCYTDElJNtQA==",
+      "version": "17.0.0",
+      "resolved": "https://registry.npmjs.org/electron/-/electron-17.0.0.tgz",
+      "integrity": "sha512-3UXcBQMwbMWdPvGHaSdPMluHrd+/bc+K143MyvE5zVZ+S1XCHt4sau7dj6svJHns5llN0YG/c6h/vRfadIp8Zg==",
       "dev": true,
       "requires": {
-        "@electron/get": "^1.0.1",
+        "@electron/get": "^1.13.0",
         "@types/node": "^14.6.2",
         "extract-zip": "^1.0.3"
       }
@@ -22083,9 +22083,9 @@
       }
     },
     "electron-reloader": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/electron-reloader/-/electron-reloader-1.2.0.tgz",
-      "integrity": "sha512-xLExyxtf7hICsoh8o+ylWQlmNE2scfTaYvUuyOYU9bWvj/Hlk5LqAnZE4nsT0LNKF1o7mrnAgixj/TJq8RV+Zw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/electron-reloader/-/electron-reloader-1.2.1.tgz",
+      "integrity": "sha512-S7rcXXImlGXsEAGwB8tJ/nLrvAFzO95IS0Ux27A8XjRrDRFKj46O2aahaZ9D908FIj+BzywgNCofHQO5EhwioA==",
       "dev": true,
       "requires": {
         "chalk": "^4.1.0",
@@ -22096,9 +22096,9 @@
       },
       "dependencies": {
         "anymatch": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-          "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+          "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
           "dev": true,
           "requires": {
             "normalize-path": "^3.0.0",
@@ -22114,30 +22114,20 @@
             "fill-range": "^7.0.1"
           }
         },
-        "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
         "chokidar": {
-          "version": "3.5.1",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
-          "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
+          "version": "3.5.3",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+          "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
           "dev": true,
           "requires": {
-            "anymatch": "~3.1.1",
+            "anymatch": "~3.1.2",
             "braces": "~3.0.2",
-            "fsevents": "~2.3.1",
-            "glob-parent": "~5.1.0",
+            "fsevents": "~2.3.2",
+            "glob-parent": "~5.1.2",
             "is-binary-path": "~2.1.0",
             "is-glob": "~4.0.1",
             "normalize-path": "~3.0.0",
-            "readdirp": "~3.5.0"
+            "readdirp": "~3.6.0"
           }
         },
         "fill-range": {
@@ -22205,6 +22195,15 @@
             "p-limit": "^3.0.2"
           }
         },
+        "readdirp": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+          "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+          "dev": true,
+          "requires": {
+            "picomatch": "^2.2.1"
+          }
+        },
         "to-regex-range": {
           "version": "5.0.1",
           "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
diff --git a/package.json b/package.json
index 15ec389cd8e4..d72964b8e634 100644
--- a/package.json
+++ b/package.json
@@ -152,10 +152,10 @@
     "css-loader": "^5.2.4",
     "detox": "^17.8.3",
     "diff-so-fancy": "^1.3.0",
-    "electron": "^12.0.0",
+    "electron": "^17.0.0",
     "electron-builder": "^22.13.1",
     "electron-notarize": "^1.0.0",
-    "electron-reloader": "^1.2.0",
+    "electron-reloader": "^1.2.1",
     "eslint": "^7.6.0",
     "eslint-config-expensify": "2.0.23",
     "eslint-loader": "^4.0.2",

From 2a8fa20e68075a99e930009e2e0b26addac05e06 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 14:45:05 -0800
Subject: [PATCH 09/19] Enable chromium sandbox

---
 desktop/main.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/desktop/main.js b/desktop/main.js
index a981210af3d1..84ba3d909d07 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -147,6 +147,7 @@ const mainWindow = (() => {
                 webPreferences: {
                     preload: `${__dirname}/contextBridge.js`,
                     contextIsolation: true,
+                    sandbox: true,
                 },
                 titleBarStyle: 'hidden',
             });

From 35350943ae2569c57dde072133a3f1506dabf2f3 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 14:47:26 -0800
Subject: [PATCH 10/19] Enable web-security

---
 desktop/main.js | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/desktop/main.js b/desktop/main.js
index 84ba3d909d07..12a3d021f9f7 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -23,10 +23,6 @@ const port = process.env.PORT || 8080;
  * @see: https://www.electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes
  */
 
-// TODO: Turn this off, use web-security after alpha launch, currently we receive a CORS issue preventing
-// the electron app from making any API requests.
-app.commandLine.appendSwitch('disable-web-security');
-
 // This is necessary for NetInfo to work correctly as it does not handle the NetworkInformation API events correctly
 // See: https://github.com/electron/electron/issues/22597
 app.commandLine.appendSwitch('enable-network-information-downlink-max');

From 9f88a529ae359bf52b6e193b19b88ce873ed4372 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Thu, 3 Feb 2022 18:18:09 -0800
Subject: [PATCH 11/19] Disable sandbox

---
 desktop/main.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/desktop/main.js b/desktop/main.js
index 12a3d021f9f7..7048db19f306 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -143,7 +143,6 @@ const mainWindow = (() => {
                 webPreferences: {
                     preload: `${__dirname}/contextBridge.js`,
                     contextIsolation: true,
-                    sandbox: true,
                 },
                 titleBarStyle: 'hidden',
             });

From 4705676ea785031bba8c423282400d22ac8b955e Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 10:28:36 -0800
Subject: [PATCH 12/19] Add SHOW_KEYBOARD_SHORTCUTS_MODAL to whitelist

---
 desktop/contextBridge.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/desktop/contextBridge.js b/desktop/contextBridge.js
index dbe8606f5d51..bb0125770c88 100644
--- a/desktop/contextBridge.js
+++ b/desktop/contextBridge.js
@@ -13,6 +13,7 @@ const WHITELIST_CHANNELS_RENDERER_TO_MAIN = [
 ];
 
 const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
+    ELECTRON_EVENTS.SHOW_KEYBOARD_SHORTCUTS_MODAL,
     ELECTRON_EVENTS.UPDATE_DOWNLOADED,
 ];
 

From 2e085c90a690a11ed1005285ba05c01aee18960f Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 11:23:49 -0800
Subject: [PATCH 13/19] Update the desktop README

---
 desktop/README.md    |  44 +++++++++++++++++++++++++++++++++++++++++++
 desktop/electron.png | Bin 0 -> 157993 bytes
 2 files changed, 44 insertions(+)
 create mode 100644 desktop/electron.png

diff --git a/desktop/README.md b/desktop/README.md
index f8fe66be27c6..0af38e24e40b 100644
--- a/desktop/README.md
+++ b/desktop/README.md
@@ -1,3 +1,47 @@
+<div align="center">
+    <div style="display: flex; flex-direction: row; justify-content: center; align-items: center;">
+        <a href="https://new.expensify.com">
+            <img src="https://raw.githubusercontent.com/Expensify/App/main/web/favicon.png" width="64" height="64" alt="New Expensify Icon">
+        </a>
+        <h1 style="padding: 24px">+</h1>
+        <a href="https://www.electronjs.org/">
+            <img src="https://raw.githubusercontent.com/Expensify/App/main/desktop/electron.png" width="64" height="64" alt="Electron Icon"/>
+        </a>
+    </div>
+    <h1>
+        <a href="https://new.expensify.com">
+            New Expensify
+        </a>
+        +
+        <a href="https://www.electronjs.org/">
+            Electron
+        </a>
+    </h1>
+</div>
+
+#### Table of Contents
+
+* [Architecture](#architecture)
+* [Testing Electron Auto-Update](#testing-electron-auto-update)
+
+# Architecture
+The New Expensify desktop app is built using [Electron.js](https://www.electronjs.org/). We try our best to maintain Electron best practices, particularly when it comes to [security](https://www.electronjs.org/docs/latest/tutorial/security). 
+
+The desktop app is organized in three pieces:
+
+1. The Electron main process 
+   - Implemented in https://github.com/Expensify/App/blob/main/desktop/main.js.
+   - This file has access to the full set of Electron and Node.JS APIs. 
+2. The Electron renderer process
+   - This is the webpack-bundled version of our react-native-web app (except using `index.desktop.js` files instead of `index.website.js`, where applicable)
+   - This is _very_ similar to our web app, and code in this process should assume it will be run in the context of a browser (no access to `require`, Electron, or Node.js APis)
+3. The context bridge
+   - Implemented in https://github.com/Expensify/App/blob/main/desktop/contextBridge.js
+   - The context bridge enables communication between the main and renderer processes. For example, if the renderer process needs to make use of a Node.js or Electron API it must:
+     1. Define an event in https://github.com/Expensify/App/blob/main/desktop/ELECTRON_EVENTS.js
+     2. Add that event to the whitelist defined in the context bridge
+     3. Set up a handler for the event in the main process that can respond to the renderer process back through the bridge, if necessary.
+
 # Testing Electron Auto-Update
 Testing the auto-update process can be a little involved. The most effective way to test this involves setting up your own release channel locally and making sure that you can notarize your builds.
 
diff --git a/desktop/electron.png b/desktop/electron.png
new file mode 100644
index 0000000000000000000000000000000000000000..e80796026c67b00e69b6a9181f176447621b1945
GIT binary patch

From fb6d3f6589d7f1aafcb5bc9d0d6f3048ee76f9dd Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 11:37:41 -0800
Subject: [PATCH 14/19] Patch README html

---
 desktop/README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/desktop/README.md b/desktop/README.md
index 0af38e24e40b..85d2d7273028 100644
--- a/desktop/README.md
+++ b/desktop/README.md
@@ -1,9 +1,9 @@
 <div align="center">
-    <div style="display: flex; flex-direction: row; justify-content: center; align-items: center;">
+    <div style="display: flex; justify-content: center; align-items: center;">
         <a href="https://new.expensify.com">
             <img src="https://raw.githubusercontent.com/Expensify/App/main/web/favicon.png" width="64" height="64" alt="New Expensify Icon">
         </a>
-        <h1 style="padding: 24px">+</h1>
+        <h1 style="margin: 24px">+</h1>
         <a href="https://www.electronjs.org/">
             <img src="https://raw.githubusercontent.com/Expensify/App/main/desktop/electron.png" width="64" height="64" alt="Electron Icon"/>
         </a>

From cec59b0aea734caad08aaebb201022059de8b440 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 11:40:46 -0800
Subject: [PATCH 15/19] Implement sendSync

---
 desktop/contextBridge.js     | 9 +++++++++
 src/libs/Visibility/index.js | 2 +-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/desktop/contextBridge.js b/desktop/contextBridge.js
index bb0125770c88..201850ab650c 100644
--- a/desktop/contextBridge.js
+++ b/desktop/contextBridge.js
@@ -27,6 +27,15 @@ contextBridge.exposeInMainWorld('electron', {
 
         ipcRenderer.send(channel, data);
     },
+    sendSync: (channel, data) => {
+        if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
+            // eslint-disable-next-line no-console
+            console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
+            return;
+        }
+
+        return ipcRenderer.sendSync(channel, data);
+    },
     on: (channel, func) => {
         if (!_.contains(WHITELIST_CHANNELS_MAIN_TO_RENDERER, channel)) {
             // eslint-disable-next-line no-console
diff --git a/src/libs/Visibility/index.js b/src/libs/Visibility/index.js
index 10304a29ad46..58bb895e6aff 100644
--- a/src/libs/Visibility/index.js
+++ b/src/libs/Visibility/index.js
@@ -11,7 +11,7 @@ import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
  */
 function isVisible() {
     return window.electron
-        ? window.electron.send(ELECTRON_EVENTS.REQUEST_VISIBILITY)
+        ? window.electron.sendSync(ELECTRON_EVENTS.REQUEST_VISIBILITY)
         : document.visibilityState === 'visible';
 }
 

From cb2308613a5d6957d40a020099ac14336201a562 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 13:05:34 -0800
Subject: [PATCH 16/19] Exit both renderer and main processes together

---
 desktop/start.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/desktop/start.js b/desktop/start.js
index c4555dacdff6..cf28e08ed310 100644
--- a/desktop/start.js
+++ b/desktop/start.js
@@ -23,8 +23,10 @@ portfinder.getPortPromise({
     ];
     concurrently(processes, {
         inputStream: process.stdin,
-        killOthers: ['failure'],
         prefix: 'name',
+
+        // Like Harry Potter and he-who-must-not-be-named, "neither can live while the other survives"
+        killOthers: ['success', 'failure'],
     }).then(
         () => process.exit(0),
         () => process.exit(1),

From eb2fa4033e68de4551953e1fba4c520d060fefe6 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 14:52:14 -0800
Subject: [PATCH 17/19] Throw an error instead of logging a warning

---
 desktop/contextBridge.js | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/desktop/contextBridge.js b/desktop/contextBridge.js
index 201850ab650c..9e234557b055 100644
--- a/desktop/contextBridge.js
+++ b/desktop/contextBridge.js
@@ -20,27 +20,21 @@ const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
 contextBridge.exposeInMainWorld('electron', {
     send: (channel, data) => {
         if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
-            // eslint-disable-next-line no-console
-            console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
-            return;
+            throw new Error(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
         }
 
         ipcRenderer.send(channel, data);
     },
     sendSync: (channel, data) => {
         if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
-            // eslint-disable-next-line no-console
-            console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
-            return;
+            throw new Error(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
         }
 
         return ipcRenderer.sendSync(channel, data);
     },
     on: (channel, func) => {
         if (!_.contains(WHITELIST_CHANNELS_MAIN_TO_RENDERER, channel)) {
-            // eslint-disable-next-line no-console
-            console.warn(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
-            return;
+            throw new Error(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
         }
 
         // Deliberately strip event as it includes `sender`

From 903dc0f6c4cd4b003fad306eb426a18db2a72894 Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 14:58:05 -0800
Subject: [PATCH 18/19] Add JSDocs in ContextBridge

---
 desktop/contextBridge.js | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/desktop/contextBridge.js b/desktop/contextBridge.js
index 9e234557b055..c52de13721d8 100644
--- a/desktop/contextBridge.js
+++ b/desktop/contextBridge.js
@@ -18,6 +18,16 @@ const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
 ];
 
 contextBridge.exposeInMainWorld('electron', {
+    /**
+     * Send data asynchronously from renderer process to main process.
+     * Note that this is a one-way channel – main will not respond. In order to get a response from main, either:
+     *
+     * - Use `sendSync`
+     * - Or implement `invoke` if you want to maintain asynchronous communication: https://www.electronjs.org/docs/latest/api/ipc-renderer#ipcrendererinvokechannel-args
+     *
+     * @param {String} channel
+     * @param {*} data
+     */
     send: (channel, data) => {
         if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
             throw new Error(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
@@ -25,6 +35,14 @@ contextBridge.exposeInMainWorld('electron', {
 
         ipcRenderer.send(channel, data);
     },
+
+    /**
+     * Send data synchronously from renderer process to main process. Main process may return a result.
+     *
+     * @param {String} channel
+     * @param {*} data
+     * @returns {*}
+     */
     sendSync: (channel, data) => {
         if (!_.contains(WHITELIST_CHANNELS_RENDERER_TO_MAIN, channel)) {
             throw new Error(`Attempt to send data across electron context bridge with invalid channel ${channel}`);
@@ -32,6 +50,13 @@ contextBridge.exposeInMainWorld('electron', {
 
         return ipcRenderer.sendSync(channel, data);
     },
+
+    /**
+     * Set up a listener for events emitted from the main process and sent to the renderer process.
+     *
+     * @param {String} channel
+     * @param {Function} func
+     */
     on: (channel, func) => {
         if (!_.contains(WHITELIST_CHANNELS_MAIN_TO_RENDERER, channel)) {
             throw new Error(`Attempt to send data across electron context bridge with invalid channel ${channel}`);

From 263ef8d2ae3cb666b3ba9422f2848e90f094f08d Mon Sep 17 00:00:00 2001
From: Rory Abraham <rory@expensify.com>
Date: Fri, 4 Feb 2022 14:59:39 -0800
Subject: [PATCH 19/19] Add comment to contextBridge explaining how to access
 those methods

---
 desktop/contextBridge.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/desktop/contextBridge.js b/desktop/contextBridge.js
index c52de13721d8..d95f5244b1f9 100644
--- a/desktop/contextBridge.js
+++ b/desktop/contextBridge.js
@@ -17,6 +17,9 @@ const WHITELIST_CHANNELS_MAIN_TO_RENDERER = [
     ELECTRON_EVENTS.UPDATE_DOWNLOADED,
 ];
 
+/**
+ * The following methods will be available in the renderer process under `window.electron`.
+ */
 contextBridge.exposeInMainWorld('electron', {
     /**
      * Send data asynchronously from renderer process to main process.
