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-disabled-by-policy-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();
|