diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /browser/components/preferences/fxaPairDevice.js | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/components/preferences/fxaPairDevice.js')
-rw-r--r-- | browser/components/preferences/fxaPairDevice.js | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/browser/components/preferences/fxaPairDevice.js b/browser/components/preferences/fxaPairDevice.js new file mode 100644 index 0000000000..42fad9f8e3 --- /dev/null +++ b/browser/components/preferences/fxaPairDevice.js @@ -0,0 +1,124 @@ +// 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/. + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { FxAccounts } = ChromeUtils.import( + "resource://gre/modules/FxAccounts.jsm" +); +const { Weave } = ChromeUtils.import("resource://services-sync/main.js"); + +XPCOMUtils.defineLazyModuleGetters(this, { + EventEmitter: "resource://gre/modules/EventEmitter.jsm", + FxAccountsPairingFlow: "resource://gre/modules/FxAccountsPairing.jsm", +}); +const { require } = ChromeUtils.import( + "resource://devtools/shared/Loader.jsm", + {} +); +const QR = require("devtools/shared/qrcode/index"); + +// This is only for "labor illusion", see +// https://www.fastcompany.com/3061519/the-ux-secret-that-will-ruin-apps-for-you +const MIN_PAIRING_LOADING_TIME_MS = 1000; + +/** + * Communication between FxAccountsPairingFlow and gFxaPairDeviceDialog + * is done using an emitter via the following messages: + * <- [view:SwitchToWebContent] - Notifies the view to navigate to a specific URL. + * <- [view:Error] - Notifies the view something went wrong during the pairing process. + * -> [view:Closed] - Notifies the pairing module the view was closed. + */ +var gFxaPairDeviceDialog = { + init() { + this._resetBackgroundQR(); + FxAccounts.config + .promiseConnectDeviceURI("pairing-modal") + .then(connectURI => { + document + .getElementById("connect-another-device-link") + .setAttribute("href", connectURI); + }); + // We let the modal show itself before eventually showing a master-password dialog later. + Services.tm.dispatchToMainThread(() => this.startPairingFlow()); + }, + + uninit() { + this.teardownListeners(); + this._emitter.emit("view:Closed"); + }, + + async startPairingFlow() { + this._resetBackgroundQR(); + document + .getElementById("qrWrapper") + .setAttribute("pairing-status", "loading"); + this._emitter = new EventEmitter(); + this.setupListeners(); + try { + if (!Weave.Utils.ensureMPUnlocked()) { + throw new Error("Master-password locked."); + } + const [, uri] = await Promise.all([ + new Promise(res => setTimeout(res, MIN_PAIRING_LOADING_TIME_MS)), + FxAccountsPairingFlow.start({ emitter: this._emitter }), + ]); + const imgData = QR.encodeToDataURI(uri, "L"); + document.getElementById( + "qrContainer" + ).style.backgroundImage = `url("${imgData.src}")`; + document + .getElementById("qrWrapper") + .setAttribute("pairing-status", "ready"); + } catch (e) { + this.onError(e); + } + }, + + _resetBackgroundQR() { + // The text we encode doesn't really matter as it is un-scannable (blurry and very transparent). + const imgData = QR.encodeToDataURI( + "https://accounts.firefox.com/pair", + "L" + ); + document.getElementById( + "qrContainer" + ).style.backgroundImage = `url("${imgData.src}")`; + }, + + onError(err) { + Cu.reportError(err); + this.teardownListeners(); + document + .getElementById("qrWrapper") + .setAttribute("pairing-status", "error"); + }, + + _switchToUrl(url) { + const browser = window.docShell.chromeEventHandler; + browser.loadURI(url, { + triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal( + {} + ), + }); + }, + + setupListeners() { + this._switchToWebContent = (_, url) => this._switchToUrl(url); + this._onError = (_, error) => this.onError(error); + this._emitter.once("view:SwitchToWebContent", this._switchToWebContent); + this._emitter.on("view:Error", this._onError); + }, + + teardownListeners() { + try { + this._emitter.off("view:SwitchToWebContent", this._switchToWebContent); + this._emitter.off("view:Error", this._onError); + } catch (e) { + console.warn("Error while tearing down listeners.", e); + } + }, +}; |