forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			187 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* 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/. */
 | |
| 
 | |
| /**
 | |
|  * This module exports the SyncedTabsErrorHandler singleton, which handles
 | |
|  * error states for synced tabs.
 | |
|  */
 | |
| 
 | |
| import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | |
| 
 | |
| const lazy = {};
 | |
| 
 | |
| ChromeUtils.defineESModuleGetters(lazy, {
 | |
|   UIState: "resource://services-sync/UIState.sys.mjs",
 | |
| });
 | |
| 
 | |
| ChromeUtils.defineLazyGetter(lazy, "syncUtils", () => {
 | |
|   return ChromeUtils.importESModule("resource://services-sync/util.sys.mjs")
 | |
|     .Utils;
 | |
| });
 | |
| 
 | |
| XPCOMUtils.defineLazyServiceGetter(
 | |
|   lazy,
 | |
|   "gNetworkLinkService",
 | |
|   "@mozilla.org/network/network-link-service;1",
 | |
|   "nsINetworkLinkService"
 | |
| );
 | |
| 
 | |
| const FXA_ENABLED = "identity.fxaccounts.enabled";
 | |
| const NETWORK_STATUS_CHANGED = "network:offline-status-changed";
 | |
| const SYNC_SERVICE_ERROR = "weave:service:sync:error";
 | |
| const SYNC_SERVICE_FINISHED = "weave:service:sync:finish";
 | |
| const TOPIC_DEVICESTATE_CHANGED = "firefox-view.devicestate.changed";
 | |
| 
 | |
| const ErrorType = Object.freeze({
 | |
|   SYNC_ERROR: "sync-error",
 | |
|   FXA_ADMIN_DISABLED: "fxa-admin-disabled",
 | |
|   NETWORK_OFFLINE: "network-offline",
 | |
|   SYNC_DISCONNECTED: "sync-disconnected",
 | |
|   PASSWORD_LOCKED: "password-locked",
 | |
|   SIGNED_OUT: "signed-out",
 | |
| });
 | |
| 
 | |
| export const SyncedTabsErrorHandler = {
 | |
|   init() {
 | |
|     this.networkIsOnline =
 | |
|       lazy.gNetworkLinkService.linkStatusKnown &&
 | |
|       lazy.gNetworkLinkService.isLinkUp;
 | |
|     this.syncIsConnected = lazy.UIState.get().syncEnabled;
 | |
|     this.syncIsWorking = true;
 | |
| 
 | |
|     Services.obs.addObserver(this, NETWORK_STATUS_CHANGED);
 | |
|     Services.obs.addObserver(this, lazy.UIState.ON_UPDATE);
 | |
|     Services.obs.addObserver(this, SYNC_SERVICE_ERROR);
 | |
|     Services.obs.addObserver(this, SYNC_SERVICE_FINISHED);
 | |
|     Services.obs.addObserver(this, TOPIC_DEVICESTATE_CHANGED);
 | |
| 
 | |
|     return this;
 | |
|   },
 | |
| 
 | |
|   get fxaSignedIn() {
 | |
|     let { UIState } = lazy;
 | |
|     let syncState = UIState.get();
 | |
|     return (
 | |
|       UIState.isReady() &&
 | |
|       syncState.status === UIState.STATUS_SIGNED_IN &&
 | |
|       // syncEnabled just checks the "services.sync.username" pref has a value
 | |
|       syncState.syncEnabled
 | |
|     );
 | |
|   },
 | |
| 
 | |
|   getErrorType() {
 | |
|     // this ordering is important for dealing with multiple errors at once
 | |
|     const errorStates = {
 | |
|       [ErrorType.NETWORK_OFFLINE]: !this.networkIsOnline,
 | |
|       [ErrorType.FXA_ADMIN_DISABLED]: Services.prefs.prefIsLocked(FXA_ENABLED),
 | |
|       [ErrorType.PASSWORD_LOCKED]: this.isPrimaryPasswordLocked,
 | |
|       [ErrorType.SIGNED_OUT]:
 | |
|         lazy.UIState.get().status === lazy.UIState.STATUS_LOGIN_FAILED,
 | |
|       [ErrorType.SYNC_DISCONNECTED]: !this.syncIsConnected,
 | |
|       [ErrorType.SYNC_ERROR]: !this.syncIsWorking && !this.syncHasWorked,
 | |
|     };
 | |
| 
 | |
|     for (let [type, value] of Object.entries(errorStates)) {
 | |
|       if (value) {
 | |
|         return type;
 | |
|       }
 | |
|     }
 | |
|     return null;
 | |
|   },
 | |
| 
 | |
|   getFluentStringsForErrorType(type) {
 | |
|     return Object.freeze(this._errorStateStringMappings[type]);
 | |
|   },
 | |
| 
 | |
|   get isPrimaryPasswordLocked() {
 | |
|     return lazy.syncUtils.mpLocked();
 | |
|   },
 | |
| 
 | |
|   isSyncReady() {
 | |
|     const fxaStatus = lazy.UIState.get().status;
 | |
|     return (
 | |
|       this.networkIsOnline &&
 | |
|       (this.syncIsWorking || this.syncHasWorked) &&
 | |
|       !Services.prefs.prefIsLocked(FXA_ENABLED) &&
 | |
|       // it's an error for sync to not be connected if we are signed-in,
 | |
|       // or for sync to be connected if the FxA status is "login_failed",
 | |
|       // which can happen if a user updates their password on another device
 | |
|       ((!this.syncIsConnected && fxaStatus !== lazy.UIState.STATUS_SIGNED_IN) ||
 | |
|         (this.syncIsConnected &&
 | |
|           fxaStatus !== lazy.UIState.STATUS_LOGIN_FAILED)) &&
 | |
|       // We treat a locked primary password as an error if we are signed-in.
 | |
|       // If the user dismisses the prompt to unlock, they can use the "Try again" button to prompt again
 | |
|       (!this.isPrimaryPasswordLocked || !this.fxaSignedIn)
 | |
|     );
 | |
|   },
 | |
| 
 | |
|   observe(_, topic, data) {
 | |
|     switch (topic) {
 | |
|       case NETWORK_STATUS_CHANGED:
 | |
|         this.networkIsOnline = data == "online";
 | |
|         break;
 | |
|       case lazy.UIState.ON_UPDATE:
 | |
|         this.syncIsConnected = lazy.UIState.get().syncEnabled;
 | |
|         break;
 | |
|       case SYNC_SERVICE_ERROR:
 | |
|         if (lazy.UIState.get().status == lazy.UIState.STATUS_SIGNED_IN) {
 | |
|           this.syncIsWorking = false;
 | |
|         }
 | |
|         break;
 | |
|       case SYNC_SERVICE_FINISHED:
 | |
|         if (!this.syncIsWorking) {
 | |
|           this.syncIsWorking = true;
 | |
|           this.syncHasWorked = true;
 | |
|         }
 | |
|         break;
 | |
|       case TOPIC_DEVICESTATE_CHANGED:
 | |
|         this.syncHasWorked = false;
 | |
|     }
 | |
|   },
 | |
| 
 | |
|   ErrorType,
 | |
| 
 | |
|   // We map the error state strings to Fluent string IDs so that it's easier
 | |
|   // to change strings in the future without having to update all of the
 | |
|   // error state strings.
 | |
|   _errorStateStringMappings: {
 | |
|     [ErrorType.SYNC_ERROR]: {
 | |
|       header: "firefoxview-tabpickup-sync-error-header",
 | |
|       description: "firefoxview-tabpickup-generic-sync-error-description",
 | |
|       buttonLabel: "firefoxview-tabpickup-sync-error-primarybutton",
 | |
|     },
 | |
|     [ErrorType.FXA_ADMIN_DISABLED]: {
 | |
|       header: "firefoxview-tabpickup-fxa-admin-disabled-header",
 | |
|       description: "firefoxview-tabpickup-fxa-admin-disabled-description",
 | |
|       // The button is hidden for this errorState, so we don't include the
 | |
|       // buttonLabel property.
 | |
|     },
 | |
|     [ErrorType.NETWORK_OFFLINE]: {
 | |
|       header: "firefoxview-tabpickup-network-offline-header",
 | |
|       description: "firefoxview-tabpickup-network-offline-description",
 | |
|       buttonLabel: "firefoxview-tabpickup-network-offline-primarybutton",
 | |
|     },
 | |
|     [ErrorType.SYNC_DISCONNECTED]: {
 | |
|       header: "firefoxview-tabpickup-sync-disconnected-header",
 | |
|       description: "firefoxview-tabpickup-sync-disconnected-description",
 | |
|       buttonLabel: "firefoxview-tabpickup-sync-disconnected-primarybutton",
 | |
|     },
 | |
|     [ErrorType.PASSWORD_LOCKED]: {
 | |
|       header: "firefoxview-tabpickup-password-locked-header",
 | |
|       description: "firefoxview-tabpickup-password-locked-description",
 | |
|       buttonLabel: "firefoxview-tabpickup-password-locked-primarybutton",
 | |
|       link: {
 | |
|         label: "firefoxview-tabpickup-password-locked-link",
 | |
|         href:
 | |
|           Services.urlFormatter.formatURLPref("app.support.baseURL") +
 | |
|           "primary-password-stored-logins",
 | |
|       },
 | |
|     },
 | |
|     [ErrorType.SIGNED_OUT]: {
 | |
|       header: "firefoxview-tabpickup-signed-out-header",
 | |
|       description: "firefoxview-tabpickup-signed-out-description2",
 | |
|       buttonLabel: "firefoxview-tabpickup-signed-out-primarybutton",
 | |
|     },
 | |
|   },
 | |
| }.init();
 | 
