From 58eca1aa7db7d8b0947dd1b90930230f6ccd996a Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" <jryans@gmail.com>
Date: Wed, 13 Jan 2021 15:39:18 +0000
Subject: [PATCH] Use isolated IPC API

This adjusts to match changes on the desktop side where we now use Electron's
context isolation feature to expose only the IPC channels and methods we
actually expect to use.
---
 src/@types/global.d.ts                   | 23 ++++++++++++++--
 src/vector/init.tsx                      |  4 +--
 src/vector/platform/ElectronPlatform.tsx | 35 ++++++++++++------------
 3 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts
index 469ef59c69..f498103d60 100644
--- a/src/@types/global.d.ts
+++ b/src/@types/global.d.ts
@@ -1,5 +1,5 @@
 /*
-Copyright 2020 New Vector Ltd
+Copyright 2020, 2021 New Vector Ltd
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -17,13 +17,32 @@ limitations under the License.
 import "matrix-react-sdk/src/@types/global"; // load matrix-react-sdk's type extensions first
 import type {Renderer} from "react-dom";
 
+type ElectronChannel =
+    "app_onAction" |
+    "before-quit" |
+    "check_updates" |
+    "install_update" |
+    "ipcCall" |
+    "ipcReply" |
+    "loudNotification" |
+    "preferences" |
+    "seshat" |
+    "seshatReply" |
+    "setBadgeCount" |
+    "update-downloaded" |
+    "userDownloadCompleted" |
+    "userDownloadOpen";
+
 declare global {
     interface Window {
         mxSendRageshake: (text: string, withLogs?: boolean) => void;
         matrixChat: ReturnType<Renderer>;
 
         // electron-only
-        ipcRenderer: any;
+        electron: {
+            on(channel: ElectronChannel, listener: (event: Event, ...args: any[]) => void): void;
+            send(channel: ElectronChannel, ...args: any[]): void;
+        }
 
         // opera-only
         opera: any;
diff --git a/src/vector/init.tsx b/src/vector/init.tsx
index f625644d04..de022622db 100644
--- a/src/vector/init.tsx
+++ b/src/vector/init.tsx
@@ -1,8 +1,8 @@
 /*
 Copyright 2015, 2016 OpenMarket Ltd
 Copyright 2017 Vector Creations Ltd
-Copyright 2018, 2019, 2020 New Vector Ltd
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
+Copyright 2018 - 2021 New Vector Ltd
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ import { initRageshake } from "./rageshakesetup";
 export const rageshakePromise = initRageshake();
 
 export function preparePlatform() {
-    if (window.ipcRenderer) {
+    if (window.electron) {
         console.log("Using Electron platform");
         PlatformPeg.set(new ElectronPlatform());
     } else if (window.matchMedia('(display-mode: standalone)').matches) {
diff --git a/src/vector/platform/ElectronPlatform.tsx b/src/vector/platform/ElectronPlatform.tsx
index 10a9600608..722892649b 100644
--- a/src/vector/platform/ElectronPlatform.tsx
+++ b/src/vector/platform/ElectronPlatform.tsx
@@ -1,9 +1,8 @@
 /*
 Copyright 2016 Aviral Dasgupta
 Copyright 2016 OpenMarket Ltd
-Copyright 2018 New Vector Ltd
 Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
-Copyright 2020 The Matrix.org Foundation C.I.C.
+Copyright 2018 - 2021 New Vector Ltd
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -49,7 +48,7 @@ import {CheckUpdatesPayload} from "matrix-react-sdk/src/dispatcher/payloads/Chec
 import ToastStore from "matrix-react-sdk/src/stores/ToastStore";
 import GenericExpiringToast from "matrix-react-sdk/src/components/views/toasts/GenericExpiringToast";
 
-const ipcRenderer = window.ipcRenderer;
+const electron = window.electron;
 const isMac = navigator.platform.toUpperCase().includes('MAC');
 
 function platformFriendlyName(): string {
@@ -74,7 +73,7 @@ function platformFriendlyName(): string {
 function _onAction(payload: ActionPayload) {
     // Whitelist payload actions, no point sending most across
     if (['call_state'].includes(payload.action)) {
-        ipcRenderer.send('app_onAction', payload);
+        electron.send('app_onAction', payload);
     }
 }
 
@@ -104,7 +103,7 @@ class SeshatIndexManager extends BaseEventIndexManager {
     constructor() {
         super();
 
-        ipcRenderer.on('seshatReply', this._onIpcReply);
+        electron.on('seshatReply', this._onIpcReply);
     }
 
     async _ipcCall(name: string, ...args: any[]): Promise<any> {
@@ -112,7 +111,7 @@ class SeshatIndexManager extends BaseEventIndexManager {
         const ipcCallId = ++this.nextIpcCallId;
         return new Promise((resolve, reject) => {
             this.pendingIpcCalls[ipcCallId] = {resolve, reject};
-            window.ipcRenderer.send('seshat', {id: ipcCallId, name, args});
+            window.electron.send('seshat', {id: ipcCallId, name, args});
         });
     }
 
@@ -230,7 +229,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
             false if there is not
             or the error if one is encountered
          */
-        ipcRenderer.on('check_updates', (event, status) => {
+        electron.on('check_updates', (event, status) => {
             dis.dispatch<CheckUpdatesPayload>({
                 action: Action.CheckUpdates,
                 ...getUpdateCheckStatus(status),
@@ -238,21 +237,21 @@ export default class ElectronPlatform extends VectorBasePlatform {
         });
 
         // try to flush the rageshake logs to indexeddb before quit.
-        ipcRenderer.on('before-quit', function() {
+        electron.on('before-quit', function() {
             console.log('element-desktop closing');
             rageshake.flush();
         });
 
-        ipcRenderer.on('ipcReply', this._onIpcReply);
-        ipcRenderer.on('update-downloaded', this.onUpdateDownloaded);
+        electron.on('ipcReply', this._onIpcReply);
+        electron.on('update-downloaded', this.onUpdateDownloaded);
 
-        ipcRenderer.on('preferences', () => {
+        electron.on('preferences', () => {
             dis.fire(Action.ViewUserSettings);
         });
 
-        ipcRenderer.on('userDownloadCompleted', (ev, {path, name}) => {
+        electron.on('userDownloadCompleted', (ev, {path, name}) => {
             const onAccept = () => {
-                ipcRenderer.send('userDownloadOpen', {path});
+                electron.send('userDownloadOpen', {path});
             };
 
             ToastStore.sharedInstance().addOrReplaceToast({
@@ -328,7 +327,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
         if (this.notificationCount === count) return;
         super.setNotificationCount(count);
 
-        ipcRenderer.send('setBadgeCount', count);
+        electron.send('setBadgeCount', count);
     }
 
     supportsNotifications(): boolean {
@@ -371,7 +370,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
     }
 
     loudNotification(ev: Event, room: Object) {
-        ipcRenderer.send('loudNotification');
+        electron.send('loudNotification');
     }
 
     async getAppVersion(): Promise<string> {
@@ -423,14 +422,14 @@ export default class ElectronPlatform extends VectorBasePlatform {
 
     startUpdateCheck() {
         super.startUpdateCheck();
-        ipcRenderer.send('check_updates');
+        electron.send('check_updates');
     }
 
     installUpdate() {
         // IPC to the main process to install the update, since quitAndInstall
         // doesn't fire the before-quit event so the main process needs to know
         // it should exit.
-        ipcRenderer.send('install_update');
+        electron.send('install_update');
     }
 
     getDefaultDeviceDisplayName(): string {
@@ -460,7 +459,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
         const ipcCallId = ++this.nextIpcCallId;
         return new Promise((resolve, reject) => {
             this.pendingIpcCalls[ipcCallId] = {resolve, reject};
-            window.ipcRenderer.send('ipcCall', {id: ipcCallId, name, args});
+            window.electron.send('ipcCall', {id: ipcCallId, name, args});
             // Maybe add a timeout to these? Probably not necessary.
         });
     }