diff --git a/src/background.js b/src/background.js index c256872f5..e0b64a216 100644 --- a/src/background.js +++ b/src/background.js @@ -40,6 +40,7 @@ import tabInfo from './classes/TabInfo'; import metrics from './classes/Metrics'; import account from './classes/Account'; import promoModals from './classes/PromoModals'; +import SearchMessager from './classes/SearchMessager'; // utilities import { allowAllwaysC2P } from './utils/click2play'; import * as common from './utils/common'; @@ -1622,6 +1623,18 @@ function initializeGhosteryModules() { }); } +/** + * Initialize Search Message Handler on Ghostery Browser. + * @memberOf Background + */ +async function initializeSearchMessageHandler() { + await globals.BROWSER_INFO_READY; // ensure browser info is set + if (BROWSER_INFO.name === 'ghostery_desktop') { + const sm = new SearchMessager(); + sm.init(); + } +} + /** * Application Initializer * Called whenever the browser starts or the extension is @@ -1633,6 +1646,7 @@ function init() { initializePopup(); initializeEventListeners(); initializeVersioning(); + initializeSearchMessageHandler(); return metrics.init(globals.JUST_INSTALLED).then(() => initializeGhosteryModules().then(() => { account.migrate() .then(() => { diff --git a/src/classes/Account.js b/src/classes/Account.js index c65ba35f7..47e18ce82 100644 --- a/src/classes/Account.js +++ b/src/classes/Account.js @@ -142,6 +142,8 @@ class Account { }) ) + refreshToken = () => api.refreshToken() + // @TODO a 404 here should trigger a logout getUser = () => ( this._getUserID() diff --git a/src/classes/SearchMessager.js b/src/classes/SearchMessager.js new file mode 100644 index 000000000..a5091e1db --- /dev/null +++ b/src/classes/SearchMessager.js @@ -0,0 +1,53 @@ +/** + * Search Messager + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2020 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import ExtMessenger from './ExtMessenger'; +import account from './Account'; +import { log } from '../utils/common'; + +/** + * @since 8.5.5 + * + * Class for handling cross-extension messaging. + * @memberOf BackgroundClasses + */ +export default class SearchMessager { + constructor() { + this.extensionId = 'search@ghostery.com'; + this._messageHandler = this._messageHandler.bind(this); + } + + init() { + ExtMessenger.addListener(this._messageHandler); + } + + unload() { + ExtMessenger.removeListener(this._messageHandler); + } + + _messageHandler(message, sender, sendResponse) { + if (sender.id !== this.extensionId) { + return false; + } + + // allow search extension to refresh token + if (message === 'refreshToken') { + account.refreshToken() + .then(() => sendResponse({ success: true })) + .catch(error => sendResponse({ success: false, error })); + return true; + } + log('SearchMessager error: Unhandled message', message); + return false; + } +} diff --git a/src/utils/api.js b/src/utils/api.js index 3ebea93d7..309ded82d 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -15,8 +15,7 @@ export const _getJSONAPIErrorsObject = e => [{ title: e.message || '', detail: e class Api { constructor() { - this.isRefreshing = false; - this.tokenRefreshedEventType = 'tokenRefreshed'; + this._refreshPromise = null; } init(config, opts) { @@ -27,24 +26,17 @@ class Api { } } - _refreshToken() { - if (this.isRefreshing) { - let bindedResolve; - const _processRefreshTokenEvent = (resolve, e) => { - window.removeEventListener(this.tokenRefreshedEventType, bindedResolve, false); - resolve(e.detail); - }; - return new Promise((resolve) => { - bindedResolve = _processRefreshTokenEvent.bind(null, resolve); - window.addEventListener(this.tokenRefreshedEventType, bindedResolve, false); - }); + refreshToken() { + if (this._refreshPromise) { + return this._refreshPromise; } - this.isRefreshing = true; - return fetch(`${this.config.AUTH_SERVER}/api/v2/refresh_token`, { + this._refreshPromise = fetch(`${this.config.AUTH_SERVER}/api/v2/refresh_token`, { method: 'POST', credentials: 'include', - }); + }).finally(() => { this._refreshPromise = null; }); + + return this._refreshPromise; } _sendReq(method, path, body) { @@ -107,12 +99,8 @@ class Api { }); } if (shouldRefresh) { - this._refreshToken() + this.refreshToken() .then((res) => { - this.isRefreshing = false; - window.dispatchEvent(new CustomEvent(this.tokenRefreshedEventType, { - detail: res, - })); const { status } = res; if (status >= 400) { res.json().then(data2 => ( @@ -129,7 +117,8 @@ class Api { .then(() => resolve(data3)) .catch(err => reject(err)); }); - }); + }) + .catch(err => reject(err)); } else { this._errorHandler(data.errors) .then(() => resolve(data))