From 1f621179777603c104d70eec2a231f932ef5b28c Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Mon, 18 Sep 2023 11:05:02 +0200 Subject: [PATCH] [PM-3783] Add zone.js support for `chrome.runtime.onMessage` (#6188) * [PM-3783] chore: remove `ngZone.run` calls No longer needed now that we have zone-patches for `chrome.runtime.onMessage` * [PM-3783] feat: patch `chrome.runtime.onMessage` event listeners --- .../polyfills/zone-patch-chrome-runtime.ts | 36 +++++++++++++++ apps/browser/src/popup/app.component.ts | 46 +++++++------------ apps/browser/src/popup/polyfills.ts | 2 + 3 files changed, 55 insertions(+), 29 deletions(-) create mode 100644 apps/browser/src/platform/polyfills/zone-patch-chrome-runtime.ts diff --git a/apps/browser/src/platform/polyfills/zone-patch-chrome-runtime.ts b/apps/browser/src/platform/polyfills/zone-patch-chrome-runtime.ts new file mode 100644 index 0000000000..fa731840f8 --- /dev/null +++ b/apps/browser/src/platform/polyfills/zone-patch-chrome-runtime.ts @@ -0,0 +1,36 @@ +/** + * Monkey patch `chrome.runtime.onMessage` event listeners to run in the Angular zone. + */ +Zone.__load_patch("ChromeRuntimeOnMessage", (global: any, Zone: ZoneType, api: _ZonePrivate) => { + const onMessage = global.chrome.runtime.onMessage; + if (typeof global?.chrome?.runtime?.onMessage === "undefined") { + return; + } + + // eslint-disable-next-line @typescript-eslint/ban-types + api.patchMethod(onMessage, "addListener", (delegate: Function) => (self: any, args: any[]) => { + const callback = args.length > 0 ? args[0] : null; + if (typeof callback === "function") { + const wrapperedCallback = Zone.current.wrap(callback, "ChromeRuntimeOnMessage"); + callback[api.symbol("chromeRuntimeOnMessageCallback")] = wrapperedCallback; + return delegate.call(self, wrapperedCallback); + } else { + return delegate.apply(self, args); + } + }); + + // eslint-disable-next-line @typescript-eslint/ban-types + api.patchMethod(onMessage, "removeListener", (delegate: Function) => (self: any, args: any[]) => { + const callback = args.length > 0 ? args[0] : null; + if (typeof callback === "function") { + const wrapperedCallback = callback[api.symbol("chromeRuntimeOnMessageCallback")]; + if (wrapperedCallback) { + return delegate.call(self, wrapperedCallback); + } else { + return delegate.apply(self, args); + } + } else { + return delegate.apply(self, args); + } + }); +}); diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index 4af5b49b52..93f824a7dd 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -86,31 +86,25 @@ export class AppComponent implements OnInit, OnDestroy { sendResponse: any ) => { if (msg.command === "doneLoggingOut") { - this.ngZone.run(async () => { - this.authService.logOut(async () => { - if (msg.expired) { - this.showToast({ - type: "warning", - title: this.i18nService.t("loggedOut"), - text: this.i18nService.t("loginExpired"), - }); - } + this.authService.logOut(async () => { + if (msg.expired) { + this.showToast({ + type: "warning", + title: this.i18nService.t("loggedOut"), + text: this.i18nService.t("loginExpired"), + }); + } - if (this.activeUserId === null) { - this.router.navigate(["home"]); - } - }); - this.changeDetectorRef.detectChanges(); + if (this.activeUserId === null) { + this.router.navigate(["home"]); + } }); + this.changeDetectorRef.detectChanges(); } else if (msg.command === "authBlocked") { - this.ngZone.run(() => { - this.router.navigate(["home"]); - }); + this.router.navigate(["home"]); } else if (msg.command === "locked") { if (msg.userId == null || msg.userId === (await this.stateService.getUserId())) { - this.ngZone.run(() => { - this.router.navigate(["lock"]); - }); + this.router.navigate(["lock"]); } } else if (msg.command === "showDialog") { await this.ngZone.run(() => this.showDialog(msg)); @@ -118,9 +112,7 @@ export class AppComponent implements OnInit, OnDestroy { // TODO: Should be refactored to live in another service. await this.ngZone.run(() => this.showNativeMessagingFingerprintDialog(msg)); } else if (msg.command === "showToast") { - this.ngZone.run(() => { - this.showToast(msg); - }); + this.showToast(msg); } else if (msg.command === "reloadProcess") { const forceWindowReload = this.platformUtilsService.isSafari() || @@ -132,13 +124,9 @@ export class AppComponent implements OnInit, OnDestroy { 2000 ); } else if (msg.command === "reloadPopup") { - this.ngZone.run(() => { - this.router.navigate(["/"]); - }); + this.router.navigate(["/"]); } else if (msg.command === "convertAccountToKeyConnector") { - this.ngZone.run(async () => { - this.router.navigate(["/remove-password"]); - }); + this.router.navigate(["/remove-password"]); } else { msg.webExtSender = sender; this.broadcasterService.send(msg); diff --git a/apps/browser/src/popup/polyfills.ts b/apps/browser/src/popup/polyfills.ts index 8edc909639..e41e960a8d 100644 --- a/apps/browser/src/popup/polyfills.ts +++ b/apps/browser/src/popup/polyfills.ts @@ -1,3 +1,5 @@ import "core-js/stable"; import "date-input-polyfill"; import "zone.js"; + +import "../platform/polyfills/zone-patch-chrome-runtime";