summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-07-06 15:53:52 +0200
committerjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-07-06 15:53:52 +0200
commit941e54654eabed0a3568f7fefe424a45aa02eddb (patch)
tree49aa02b174c428962d99142d8061267bfcd79e69 /services
parentad9ee72dcd7981bc47b3844a224d69fadfdfd8ef (diff)
parent0daa12376295d5d796256a116eb2a348a3a9273f (diff)
downloadUXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.gz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.lz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.xz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.zip
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into _testBranch_test_1
Diffstat (limited to 'services')
-rw-r--r--services/fxaccounts/FxAccountsManager.jsm654
-rw-r--r--services/fxaccounts/FxAccountsProfileClient.jsm4
-rw-r--r--services/fxaccounts/FxAccountsStorage.jsm9
-rw-r--r--services/fxaccounts/moz.build3
-rw-r--r--services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js2
-rw-r--r--services/fxaccounts/tests/xpcshell/test_profile_client.js2
-rw-r--r--services/sync/SyncComponents.manifest5
-rw-r--r--services/sync/Weave.js6
-rw-r--r--services/sync/locales/en-US/errors.properties2
-rw-r--r--services/sync/locales/en-US/sync.properties27
-rw-r--r--services/sync/modules/main.js1
-rw-r--r--services/sync/modules/notifications.js131
-rw-r--r--services/sync/modules/record.js4
-rw-r--r--services/sync/modules/service.js49
-rw-r--r--services/sync/moz.build8
-rw-r--r--services/sync/services-sync.js1
-rw-r--r--services/sync/tests/unit/test_service_login.js2
-rw-r--r--services/sync/tests/unit/test_syncscheduler.js2
-rw-r--r--services/sync/tests/unit/xpcshell.ini1
-rw-r--r--services/sync/tps/extensions/mozmill/resource/driver/controller.js2
-rw-r--r--services/sync/tps/extensions/mozmill/resource/modules/assertions.js2
21 files changed, 211 insertions, 706 deletions
diff --git a/services/fxaccounts/FxAccountsManager.jsm b/services/fxaccounts/FxAccountsManager.jsm
deleted file mode 100644
index 680310ff5..000000000
--- a/services/fxaccounts/FxAccountsManager.jsm
+++ /dev/null
@@ -1,654 +0,0 @@
-/* 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/. */
-
-/**
- * Temporary abstraction layer for common Fx Accounts operations.
- * For now, we will be using this module only from B2G but in the end we might
- * want this to be merged with FxAccounts.jsm and let other products also use
- * it.
- */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["FxAccountsManager"];
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/FxAccounts.jsm");
-Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://gre/modules/FxAccountsCommon.js");
-
-XPCOMUtils.defineLazyServiceGetter(this, "permissionManager",
- "@mozilla.org/permissionmanager;1",
- "nsIPermissionManager");
-
-this.FxAccountsManager = {
-
- init: function() {
- Services.obs.addObserver(this, ONLOGOUT_NOTIFICATION, false);
- Services.obs.addObserver(this, ON_FXA_UPDATE_NOTIFICATION, false);
- },
-
- observe: function(aSubject, aTopic, aData) {
- // Both topics indicate our cache is invalid
- this._activeSession = null;
-
- if (aData == ONVERIFIED_NOTIFICATION) {
- log.debug("FxAccountsManager: cache cleared, broadcasting: " + aData);
- Services.obs.notifyObservers(null, aData, null);
- }
- },
-
- // We don't really need to save fxAccounts instance but this way we allow
- // to mock FxAccounts from tests.
- _fxAccounts: fxAccounts,
-
- // We keep the session details here so consumers don't need to deal with
- // session tokens and are only required to handle the email.
- _activeSession: null,
-
- // Are we refreshing our authentication? If so, allow attempts to sign in
- // while we are already signed in.
- _refreshing: false,
-
- // We only expose the email and the verified status so far.
- get _user() {
- if (!this._activeSession || !this._activeSession.email) {
- return null;
- }
-
- return {
- email: this._activeSession.email,
- verified: this._activeSession.verified,
- profile: this._activeSession.profile,
- }
- },
-
- _error: function(aError, aDetails) {
- log.error(aError);
- let reason = {
- error: aError
- };
- if (aDetails) {
- reason.details = aDetails;
- }
- return Promise.reject(reason);
- },
-
- _getError: function(aServerResponse) {
- if (!aServerResponse || !aServerResponse.error || !aServerResponse.error.errno) {
- return;
- }
- let error = SERVER_ERRNO_TO_ERROR[aServerResponse.error.errno];
- return error;
- },
-
- _serverError: function(aServerResponse) {
- let error = this._getError({ error: aServerResponse });
- return this._error(error ? error : ERROR_SERVER_ERROR, aServerResponse);
- },
-
- // As with _fxAccounts, we don't really need this method, but this way we
- // allow tests to mock FxAccountsClient. By default, we want to return the
- // client used by the fxAccounts object because deep down they should have
- // access to the same hawk request object which will enable them to share
- // local clock skeq data.
- _getFxAccountsClient: function() {
- return this._fxAccounts.getAccountsClient();
- },
-
- _signInSignUp: function(aMethod, aEmail, aPassword, aFetchKeys) {
- if (Services.io.offline) {
- return this._error(ERROR_OFFLINE);
- }
-
- if (!aEmail) {
- return this._error(ERROR_INVALID_EMAIL);
- }
-
- if (!aPassword) {
- return this._error(ERROR_INVALID_PASSWORD);
- }
-
- // Check that there is no signed in account first.
- if ((!this._refreshing) && this._activeSession) {
- return this._error(ERROR_ALREADY_SIGNED_IN_USER, {
- user: this._user
- });
- }
-
- let client = this._getFxAccountsClient();
- return this._fxAccounts.getSignedInUser().then(
- user => {
- if ((!this._refreshing) && user) {
- return this._error(ERROR_ALREADY_SIGNED_IN_USER, {
- user: this._user
- });
- }
- return client[aMethod](aEmail, aPassword, aFetchKeys);
- }
- ).then(
- user => {
- let error = this._getError(user);
- if (!user || !user.uid || !user.sessionToken || error) {
- return this._error(error ? error : ERROR_INTERNAL_INVALID_USER, {
- user: user
- });
- }
-
- // If the user object includes an email field, it may differ in
- // capitalization from what we sent down. This is the server's
- // canonical capitalization and should be used instead.
- user.email = user.email || aEmail;
-
- // If we're using server-side sign to refreshAuthentication
- // we don't need to update local state; also because of two
- // interacting glitches we need to bypass an event emission.
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=1031580
- if (this._refreshing) {
- return Promise.resolve({user: this._user});
- }
-
- return this._fxAccounts.setSignedInUser(user).then(
- () => {
- this._activeSession = user;
- log.debug("User signed in: " + JSON.stringify(this._user) +
- " - Account created " + (aMethod == "signUp"));
-
- // There is no way to obtain the key fetch token afterwards
- // without login out the user and asking her to log in again.
- // Also, key fetch tokens are designed to be short-lived, so
- // we need to fetch kB as soon as we have the key fetch token.
- if (aFetchKeys) {
- this._fxAccounts.getKeys();
- }
-
- return this._fxAccounts.getSignedInUserProfile().catch(error => {
- // Not fetching the profile is sad but the FxA logs will already
- // have noise.
- return null;
- });
- }
- ).then(profile => {
- if (profile) {
- this._activeSession.profile = profile;
- }
-
- return Promise.resolve({
- accountCreated: aMethod === "signUp",
- user: this._user
- });
- });
- },
- reason => { return this._serverError(reason); }
- );
- },
-
- /**
- * Determine whether the incoming error means that the current account
- * has new server-side state via deletion or password change, and if so,
- * spawn the appropriate UI (sign in or refresh); otherwise re-reject.
- *
- * As of May 2014, the only HTTP call triggered by this._getAssertion()
- * is to /certificate/sign via:
- * FxAccounts.getAssertion()
- * FxAccountsInternal.getCertificateSigned()
- * FxAccountsClient.signCertificate()
- * See the latter method for possible (error code, errno) pairs.
- */
- _handleGetAssertionError: function(reason, aAudience, aPrincipal) {
- log.debug("FxAccountsManager._handleGetAssertionError()");
- let errno = (reason ? reason.errno : NaN) || NaN;
- // If the previously valid email/password pair is no longer valid ...
- if (errno == ERRNO_INVALID_AUTH_TOKEN) {
- return this._fxAccounts.accountStatus().then(
- (exists) => {
- // ... if the email still maps to an account, the password
- // must have changed, so ask the user to enter the new one ...
- if (exists) {
- return this.getAccount().then(
- (user) => {
- return this._refreshAuthentication(aAudience, user.email,
- aPrincipal,
- true /* logoutOnFailure */);
- }
- );
- }
- // ... otherwise, the account was deleted, so ask for Sign In/Up
- return this._localSignOut().then(
- () => {
- return this._uiRequest(UI_REQUEST_SIGN_IN_FLOW, aAudience,
- aPrincipal);
- },
- (reason) => {
- // reject primary problem, not signout failure
- log.error("Signing out in response to server error threw: " +
- reason);
- return this._error(reason);
- }
- );
- }
- );
- }
- return Promise.reject(reason.message ? { error: reason.message } : reason);
- },
-
- _getAssertion: function(aAudience, aPrincipal) {
- return this._fxAccounts.getAssertion(aAudience).then(
- (result) => {
- if (aPrincipal) {
- this._addPermission(aPrincipal);
- }
- return result;
- },
- (reason) => {
- return this._handleGetAssertionError(reason, aAudience, aPrincipal);
- }
- );
- },
-
- /**
- * "Refresh authentication" means:
- * Interactively demonstrate knowledge of the FxA password
- * for the currently logged-in account.
- * There are two very different scenarios:
- * 1) The password has changed on the server. Failure should log
- * the current account OUT.
- * 2) The person typing can't prove knowledge of the password used
- * to log in. Failure should do nothing.
- */
- _refreshAuthentication: function(aAudience, aEmail, aPrincipal,
- logoutOnFailure=false) {
- this._refreshing = true;
- return this._uiRequest(UI_REQUEST_REFRESH_AUTH,
- aAudience, aPrincipal, aEmail).then(
- (assertion) => {
- this._refreshing = false;
- return assertion;
- },
- (reason) => {
- this._refreshing = false;
- if (logoutOnFailure) {
- return this._signOut().then(
- () => {
- return this._error(reason);
- }
- );
- }
- return this._error(reason);
- }
- );
- },
-
- _localSignOut: function() {
- return this._fxAccounts.signOut(true);
- },
-
- _signOut: function() {
- if (!this._activeSession) {
- return Promise.resolve();
- }
-
- // We clear the local session cache as soon as we get the onlogout
- // notification triggered within FxAccounts.signOut, so we save the
- // session token value to be able to remove the remote server session
- // in case that we have network connection.
- let sessionToken = this._activeSession.sessionToken;
-
- return this._localSignOut().then(
- () => {
- // At this point the local session should already be removed.
-
- // The client can create new sessions up to the limit (100?).
- // Orphaned tokens on the server will eventually be garbage collected.
- if (Services.io.offline) {
- return Promise.resolve();
- }
- // Otherwise, we try to remove the remote session.
- let client = this._getFxAccountsClient();
- return client.signOut(sessionToken).then(
- result => {
- let error = this._getError(result);
- if (error) {
- return this._error(error, result);
- }
- log.debug("Signed out");
- return Promise.resolve();
- },
- reason => {
- return this._serverError(reason);
- }
- );
- }
- );
- },
-
- _uiRequest: function(aRequest, aAudience, aPrincipal, aParams) {
- if (Services.io.offline) {
- return this._error(ERROR_OFFLINE);
- }
- let ui = Cc["@mozilla.org/fxaccounts/fxaccounts-ui-glue;1"]
- .createInstance(Ci.nsIFxAccountsUIGlue);
- if (!ui[aRequest]) {
- return this._error(ERROR_UI_REQUEST);
- }
-
- if (!aParams || !Array.isArray(aParams)) {
- aParams = [aParams];
- }
-
- return ui[aRequest].apply(this, aParams).then(
- result => {
- // Even if we get a successful result from the UI, the account will
- // most likely be unverified, so we cannot get an assertion.
- if (result && result.verified) {
- return this._getAssertion(aAudience, aPrincipal);
- }
-
- return this._error(ERROR_UNVERIFIED_ACCOUNT, {
- user: result
- });
- },
- error => {
- return this._error(ERROR_UI_ERROR, error);
- }
- );
- },
-
- _addPermission: function(aPrincipal) {
- // This will fail from tests cause we are running them in the child
- // process until we have chrome tests in b2g. Bug 797164.
- try {
- permissionManager.addFromPrincipal(aPrincipal, FXACCOUNTS_PERMISSION,
- Ci.nsIPermissionManager.ALLOW_ACTION);
- } catch (e) {
- log.warn("Could not add permission " + e);
- }
- },
-
- // -- API --
-
- signIn: function(aEmail, aPassword, aFetchKeys) {
- return this._signInSignUp("signIn", aEmail, aPassword, aFetchKeys);
- },
-
- signUp: function(aEmail, aPassword, aFetchKeys) {
- return this._signInSignUp("signUp", aEmail, aPassword, aFetchKeys);
- },
-
- signOut: function() {
- if (!this._activeSession) {
- // If there is no cached active session, we try to get it from the
- // account storage.
- return this.getAccount().then(
- result => {
- if (!result) {
- return Promise.resolve();
- }
- return this._signOut();
- }
- );
- }
- return this._signOut();
- },
-
- resendVerificationEmail: function() {
- return this._fxAccounts.resendVerificationEmail().then(
- (result) => {
- return result;
- },
- (error) => {
- return this._error(ERROR_SERVER_ERROR, error);
- }
- );
- },
-
- getAccount: function() {
- // We check first if we have session details cached.
- if (this._activeSession) {
- // If our cache says that the account is not yet verified,
- // we kick off verification before returning what we have.
- if (!this._activeSession.verified) {
- this.verificationStatus(this._activeSession);
- }
- log.debug("Account " + JSON.stringify(this._user));
- return Promise.resolve(this._user);
- }
-
- // If no cached information, we try to get it from the persistent storage.
- return this._fxAccounts.getSignedInUser().then(
- user => {
- if (!user || !user.email) {
- log.debug("No signed in account");
- return Promise.resolve(null);
- }
-
- this._activeSession = user;
- // If we get a stored information of a not yet verified account,
- // we kick off verification before returning what we have.
- if (!user.verified) {
- this.verificationStatus(user);
- // Trying to get the profile for unverified users will fail, so we
- // don't even try in that case.
- log.debug("Account ", this._user);
- return Promise.resolve(this._user);
- }
-
- return this._fxAccounts.getSignedInUserProfile().then(profile => {
- if (profile) {
- this._activeSession.profile = profile;
- }
- log.debug("Account ", this._user);
- return Promise.resolve(this._user);
- }).catch(error => {
- // FxAccounts logs already inform about the error.
- log.debug("Account ", this._user);
- return Promise.resolve(this._user);
- });
- }
- );
- },
-
- queryAccount: function(aEmail) {
- log.debug("queryAccount " + aEmail);
- if (Services.io.offline) {
- return this._error(ERROR_OFFLINE);
- }
-
- let deferred = Promise.defer();
-
- if (!aEmail) {
- return this._error(ERROR_INVALID_EMAIL);
- }
-
- let client = this._getFxAccountsClient();
- return client.accountExists(aEmail).then(
- result => {
- log.debug("Account " + result ? "" : "does not" + " exists");
- let error = this._getError(result);
- if (error) {
- return this._error(error, result);
- }
-
- return Promise.resolve({
- registered: result
- });
- },
- reason => { this._serverError(reason); }
- );
- },
-
- verificationStatus: function() {
- log.debug("verificationStatus");
- if (!this._activeSession || !this._activeSession.sessionToken) {
- this._error(ERROR_NO_TOKEN_SESSION);
- }
-
- // There is no way to unverify an already verified account, so we just
- // return the account details of a verified account
- if (this._activeSession.verified) {
- log.debug("Account already verified");
- return;
- }
-
- if (Services.io.offline) {
- log.warn("Offline; skipping verification.");
- return;
- }
-
- let client = this._getFxAccountsClient();
- client.recoveryEmailStatus(this._activeSession.sessionToken).then(
- data => {
- let error = this._getError(data);
- if (error) {
- this._error(error, data);
- }
- // If the verification status has changed, update state.
- if (this._activeSession.verified != data.verified) {
- this._activeSession.verified = data.verified;
- this._fxAccounts.setSignedInUser(this._activeSession);
- this._fxAccounts.getSignedInUserProfile().then(profile => {
- if (profile) {
- this._activeSession.profile = profile;
- }
- }).catch(error => {
- // FxAccounts logs already inform about the error.
- });
- }
- log.debug(JSON.stringify(this._user));
- },
- reason => { this._serverError(reason); }
- );
- },
-
- /*
- * Try to get an assertion for the given audience. Here we implement
- * the heart of the response to navigator.mozId.request() on device.
- * (We can also be called via the IAC API, but it's request() that
- * makes this method complex.) The state machine looks like this,
- * ignoring simple errors:
- * If no one is signed in, and we aren't suppressing the UI:
- * trigger the sign in flow.
- * else if we were asked to refresh and the grace period is up:
- * trigger the refresh flow.
- * else:
- * request user permission to share an assertion if we don't have it
- * already and ask the core code for an assertion, which might itself
- * trigger either the sign in or refresh flows (if our account
- * changed on the server).
- *
- * aOptions can include:
- * refreshAuthentication - (bool) Force re-auth.
- * silent - (bool) Prevent any UI interaction.
- * I.e., try to get an automatic assertion.
- */
- getAssertion: function(aAudience, aPrincipal, aOptions) {
- if (!aAudience) {
- return this._error(ERROR_INVALID_AUDIENCE);
- }
-
- let principal = aPrincipal;
- log.debug("FxAccountsManager.getAssertion() aPrincipal: ",
- principal.origin, principal.appId,
- principal.isInIsolatedMozBrowserElement);
-
- return this.getAccount().then(
- user => {
- if (user) {
- // Three have-user cases to consider. First: are we unverified?
- if (!user.verified) {
- return this._error(ERROR_UNVERIFIED_ACCOUNT, {
- user: user
- });
- }
- // Second case: do we need to refresh?
- if (aOptions &&
- (typeof(aOptions.refreshAuthentication) != "undefined")) {
- let gracePeriod = aOptions.refreshAuthentication;
- if (typeof(gracePeriod) !== "number" || isNaN(gracePeriod)) {
- return this._error(ERROR_INVALID_REFRESH_AUTH_VALUE);
- }
- // Forcing refreshAuth to silent is a contradiction in terms,
- // though it might succeed silently if we didn't reject here.
- if (aOptions.silent) {
- return this._error(ERROR_NO_SILENT_REFRESH_AUTH);
- }
- let secondsSinceAuth = (Date.now() / 1000) -
- this._activeSession.authAt;
- if (secondsSinceAuth > gracePeriod) {
- return this._refreshAuthentication(aAudience, user.email,
- principal,
- false /* logoutOnFailure */);
- }
- }
- // Third case: we are all set *locally*. Probably we just return
- // the assertion, but the attempt might lead to the server saying
- // we are deleted or have a new password, which will trigger a flow.
- // Also we need to check if we have permission to get the assertion,
- // otherwise we need to show the forceAuth UI to let the user know
- // that the RP with no fxa permissions is trying to obtain an
- // assertion. Once the user authenticates herself in the forceAuth UI
- // the permission will be remembered by default.
- let permission = permissionManager.testPermissionFromPrincipal(
- principal,
- FXACCOUNTS_PERMISSION
- );
- if (permission == Ci.nsIPermissionManager.PROMPT_ACTION &&
- !this._refreshing) {
- return this._refreshAuthentication(aAudience, user.email,
- principal,
- false /* logoutOnFailure */);
- } else if (permission == Ci.nsIPermissionManager.DENY_ACTION &&
- !this._refreshing) {
- return this._error(ERROR_PERMISSION_DENIED);
- } else if (this._refreshing) {
- // If we are blocked asking for a password we should not continue
- // the getAssertion process.
- return Promise.resolve(null);
- }
- return this._getAssertion(aAudience, principal);
- }
- log.debug("No signed in user");
- if (aOptions && aOptions.silent) {
- return Promise.resolve(null);
- }
- return this._uiRequest(UI_REQUEST_SIGN_IN_FLOW, aAudience, principal);
- }
- );
- },
-
- getKeys: function() {
- let syncEnabled = false;
- try {
- syncEnabled = Services.prefs.getBoolPref("services.sync.enabled");
- } catch(e) {
- dump("Sync is disabled, so you won't get the keys. " + e + "\n");
- }
-
- if (!syncEnabled) {
- return Promise.reject(ERROR_SYNC_DISABLED);
- }
-
- return this.getAccount().then(
- user => {
- if (!user) {
- log.debug("No signed in user");
- return Promise.resolve(null);
- }
-
- if (!user.verified) {
- return this._error(ERROR_UNVERIFIED_ACCOUNT, {
- user: user
- });
- }
-
- return this._fxAccounts.getKeys();
- }
- );
- }
-};
-
-FxAccountsManager.init();
diff --git a/services/fxaccounts/FxAccountsProfileClient.jsm b/services/fxaccounts/FxAccountsProfileClient.jsm
index 37115a3fa..1e5edc634 100644
--- a/services/fxaccounts/FxAccountsProfileClient.jsm
+++ b/services/fxaccounts/FxAccountsProfileClient.jsm
@@ -89,7 +89,7 @@ this.FxAccountsProfileClient.prototype = {
try {
return (yield this._rawRequest(path, method, token));
} catch (ex) {
- if (!ex instanceof FxAccountsProfileClientError || ex.code != 401) {
+ if (!(ex instanceof FxAccountsProfileClientError) || ex.code != 401) {
throw ex;
}
// If this object was instantiated with a token then we don't refresh it.
@@ -105,7 +105,7 @@ this.FxAccountsProfileClient.prototype = {
try {
return (yield this._rawRequest(path, method, token));
} catch (ex) {
- if (!ex instanceof FxAccountsProfileClientError || ex.code != 401) {
+ if (!(ex instanceof FxAccountsProfileClientError) || ex.code != 401) {
throw ex;
}
log.info("Retry fetching the profile still returned a 401 - revoking our token and failing");
diff --git a/services/fxaccounts/FxAccountsStorage.jsm b/services/fxaccounts/FxAccountsStorage.jsm
index 021763b92..4362cdf5b 100644
--- a/services/fxaccounts/FxAccountsStorage.jsm
+++ b/services/fxaccounts/FxAccountsStorage.jsm
@@ -17,6 +17,8 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://services-common/utils.js");
+var haveLoginManager = true;
+
// A helper function so code can check what fields are able to be stored by
// the storage manager without having a reference to a manager instance.
function FxAccountsStorageManagerCanStoreField(fieldName) {
@@ -403,7 +405,7 @@ this.FxAccountsStorageManager.prototype = {
try {
yield this.secureStorage.set(this.cachedPlain.uid, toWriteSecure);
} catch (ex) {
- if (!ex instanceof this.secureStorage.STORAGE_LOCKED) {
+ if (!(ex instanceof this.secureStorage.STORAGE_LOCKED)) {
throw ex;
}
// This shouldn't be possible as once it is unlocked it can't be
@@ -602,8 +604,3 @@ LoginManagerStorage.prototype = {
}),
}
-// A global variable to indicate if the login manager is available - it doesn't
-// exist on b2g. Defined here as the use of preprocessor directives skews line
-// numbers in the runtime, meaning stack-traces etc end up off by a few lines.
-// Doing it at the end of the file makes that less of a pita.
-var haveLoginManager = !AppConstants.MOZ_B2G;
diff --git a/services/fxaccounts/moz.build b/services/fxaccounts/moz.build
index 30c8944c2..b1cd3b59c 100644
--- a/services/fxaccounts/moz.build
+++ b/services/fxaccounts/moz.build
@@ -30,6 +30,3 @@ EXTRA_JS_MODULES += [
'FxAccountsWebChannel.jsm',
]
-# For now, we will only be using the FxA manager in B2G.
-if CONFIG['MOZ_B2G']:
- EXTRA_JS_MODULES += ['FxAccountsManager.jsm']
diff --git a/services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js b/services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js
index 244b79a5e..710a65ee5 100644
--- a/services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js
+++ b/services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js
@@ -143,7 +143,7 @@ add_test(function serverErrorResponse () {
add_test(function networkErrorResponse () {
let client = new FxAccountsOAuthGrantClient({
- serverURL: "http://",
+ serverURL: "http://domain.dummy",
client_id: "abc123"
});
Services.prefs.setBoolPref("identity.fxaccounts.skipDeviceRegistration", true);
diff --git a/services/fxaccounts/tests/xpcshell/test_profile_client.js b/services/fxaccounts/tests/xpcshell/test_profile_client.js
index 2243da3aa..20ff6efc6 100644
--- a/services/fxaccounts/tests/xpcshell/test_profile_client.js
+++ b/services/fxaccounts/tests/xpcshell/test_profile_client.js
@@ -268,7 +268,7 @@ add_test(function server401ResponsePersists () {
add_test(function networkErrorResponse () {
let client = new FxAccountsProfileClient({
- serverURL: "http://",
+ serverURL: "http://domain.dummy",
fxa: mockFxa,
});
client.fetchProfile()
diff --git a/services/sync/SyncComponents.manifest b/services/sync/SyncComponents.manifest
index 6493bb224..c58286277 100644
--- a/services/sync/SyncComponents.manifest
+++ b/services/sync/SyncComponents.manifest
@@ -3,7 +3,8 @@
# Thus we restrict it to these apps:
#
# b2g: {3c2e2abc-06d4-11e1-ac3b-374f68613e61}
-# browser: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+# basilisk: {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+# pale moon: {8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}
# mobile/android: {aa3c5121-dab2-40e2-81ca-7ea25febc110}
# mobile/xul: {a23983c0-fd0e-11dc-95ff-0800200c9a66}
# suite (comm): {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
@@ -12,7 +13,7 @@
# Weave.js
component {74b89fb0-f200-4ae8-a3ec-dd164117f6de} Weave.js
contract @mozilla.org/weave/service;1 {74b89fb0-f200-4ae8-a3ec-dd164117f6de}
-category app-startup WeaveService service,@mozilla.org/weave/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} application={99bceaaa-e3c6-48c1-b981-ef9b46b67d60} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314}
+category app-startup WeaveService service,@mozilla.org/weave/service;1 application={3c2e2abc-06d4-11e1-ac3b-374f68613e61} application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} application={8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4} application={aa3c5121-dab2-40e2-81ca-7ea25febc110} application={a23983c0-fd0e-11dc-95ff-0800200c9a66} application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} application={99bceaaa-e3c6-48c1-b981-ef9b46b67d60} application={d1bfe7d9-c01e-4237-998b-7b5f960a4314}
component {d28f8a0b-95da-48f4-b712-caf37097be41} Weave.js
contract @mozilla.org/network/protocol/about;1?what=sync-log {d28f8a0b-95da-48f4-b712-caf37097be41}
diff --git a/services/sync/Weave.js b/services/sync/Weave.js
index 4d79144e3..a414fa083 100644
--- a/services/sync/Weave.js
+++ b/services/sync/Weave.js
@@ -72,10 +72,12 @@ WeaveService.prototype = {
Ci.nsISupportsWeakReference]),
ensureLoaded: function () {
+#ifndef MC_PALEMOON
// If we are loaded and not using FxA, load the migration module.
if (!this.fxAccountsEnabled) {
Cu.import("resource://services-sync/FxaMigrator.jsm");
}
+#endif
Components.utils.import("resource://services-sync/main.js");
@@ -103,6 +105,9 @@ WeaveService.prototype = {
* @return bool
*/
get fxAccountsEnabled() {
+#ifdef MC_PALEMOON
+ return false;
+#else
try {
// Old sync guarantees '@' will never appear in the username while FxA
// uses the FxA email address - so '@' is the flag we use.
@@ -111,6 +116,7 @@ WeaveService.prototype = {
} catch (_) {
return true; // No username == only allow FxA to be configured.
}
+#endif
},
/**
diff --git a/services/sync/locales/en-US/errors.properties b/services/sync/locales/en-US/errors.properties
index 3dfa074bc..f67f5ea1c 100644
--- a/services/sync/locales/en-US/errors.properties
+++ b/services/sync/locales/en-US/errors.properties
@@ -12,7 +12,7 @@ error.login.reason.server = Server incorrectly configured
error.sync.failed_partial = One or more data types could not be synced
# LOCALIZATION NOTE (error.sync.reason.serverMaintenance): We removed the extraneous period from this string
-error.sync.reason.serverMaintenance = Firefox Sync server maintenance is underway, syncing will resume automatically
+error.sync.reason.serverMaintenance = Sync server maintenance is underway, syncing will resume automatically
invalid-captcha = Incorrect words, try again
weak-password = Use a stronger password
diff --git a/services/sync/locales/en-US/sync.properties b/services/sync/locales/en-US/sync.properties
index d00183118..a1a6f76b2 100644
--- a/services/sync/locales/en-US/sync.properties
+++ b/services/sync/locales/en-US/sync.properties
@@ -12,14 +12,33 @@ lastSync2.label = Last sync: %S
# not configured.
signInToSync.description = Sign In To Sync
+error.login.title = Error While Signing In
+error.login.description = Sync encountered an error while connecting: %1$S. Please try again.
+error.login.prefs.label = Preferences…
+error.login.prefs.accesskey = P
+# should decide if we're going to show this
+error.logout.title = Error While Signing Out
+error.logout.description = Sync encountered an error while connecting. It's probably ok, and you don't have to do anything about it.
error.sync.title = Error While Syncing
error.sync.description = Sync encountered an error while syncing: %1$S. Sync will automatically retry this action.
+error.sync.prolonged_failure = Sync has not been able to complete during the last %1$S days. Please check your network settings.
+error.sync.serverStatusButton.label = Server Status
+error.sync.serverStatusButton.accesskey = V
+error.sync.needUpdate.description = You need to update Sync to continue syncing your data.
+error.sync.needUpdate.label = Update Sync
+error.sync.needUpdate.accesskey = U
+error.sync.tryAgainButton.label = Sync Now
+error.sync.tryAgainButton.accesskey = S
+warning.sync.quota.label = Approaching Server Quota
+warning.sync.quota.description = You are approaching the server quota. Please review which data to sync.
+error.sync.viewQuotaButton.label = View Quota
+error.sync.viewQuotaButton.accesskey = V
warning.sync.eol.label = Service Shutting Down
-# %1: the app name (Firefox)
-warning.sync.eol.description = Your Firefox Sync service is shutting down soon. Upgrade %1$S to keep syncing.
+# %1: the app name (Basilisk)
+warning.sync.eol.description = Your Sync service is shutting down soon. Upgrade %1$S to keep syncing.
error.sync.eol.label = Service Unavailable
-# %1: the app name (Firefox)
-error.sync.eol.description = Your Firefox Sync service is no longer available. You need to upgrade %1$S to keep syncing.
+# %1: the app name (Basilisk)
+error.sync.eol.description = Your Sync service is no longer available. You need to upgrade %1$S to keep syncing.
sync.eol.learnMore.label = Learn more
sync.eol.learnMore.accesskey = L
diff --git a/services/sync/modules/main.js b/services/sync/modules/main.js
index af3399e7a..e8e705e72 100644
--- a/services/sync/modules/main.js
+++ b/services/sync/modules/main.js
@@ -8,6 +8,7 @@ this.Weave = {};
Components.utils.import("resource://services-sync/constants.js", Weave);
var lazies = {
"jpakeclient.js": ["JPAKEClient", "SendCredentialsController"],
+ "notifications.js": ["Notifications", "Notification", "NotificationButton"],
"service.js": ["Service"],
"status.js": ["Status"],
"util.js": ['Utils', 'Svc']
diff --git a/services/sync/modules/notifications.js b/services/sync/modules/notifications.js
new file mode 100644
index 000000000..72187a4ce
--- /dev/null
+++ b/services/sync/modules/notifications.js
@@ -0,0 +1,131 @@
+/* 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.EXPORTED_SYMBOLS = ["Notifications", "Notification", "NotificationButton"];
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+var Cu = Components.utils;
+
+Cu.import("resource://services-common/observers.js");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-sync/util.js");
+
+this.Notifications = {
+ // Match the referenced values in toolkit/content/widgets/notification.xml.
+ get PRIORITY_INFO() { return 1; }, // PRIORITY_INFO_LOW
+ get PRIORITY_WARNING() { return 4; }, // PRIORITY_WARNING_LOW
+ get PRIORITY_ERROR() { return 7; }, // PRIORITY_CRITICAL_LOW
+
+ // FIXME: instead of making this public, dress the Notifications object
+ // to behave like an iterator (using generators?) and have callers access
+ // this array through the Notifications object.
+ notifications: [],
+
+ _observers: [],
+
+ // XXX Should we have a helper method for adding a simple notification?
+ // I.e. something like |function notify(title, description, priority)|.
+
+ add: function Notifications_add(notification) {
+ this.notifications.push(notification);
+ Observers.notify("weave:notification:added", notification, null);
+ },
+
+ remove: function Notifications_remove(notification) {
+ let index = this.notifications.indexOf(notification);
+
+ if (index != -1) {
+ this.notifications.splice(index, 1);
+ Observers.notify("weave:notification:removed", notification, null);
+ }
+ },
+
+ /**
+ * Replace an existing notification.
+ */
+ replace: function Notifications_replace(oldNotification, newNotification) {
+ let index = this.notifications.indexOf(oldNotification);
+
+ if (index != -1)
+ this.notifications.splice(index, 1, newNotification);
+ else {
+ this.notifications.push(newNotification);
+ // XXX Should we throw because we didn't find the existing notification?
+ // XXX Should we notify observers about weave:notification:added?
+ }
+
+ // XXX Should we notify observers about weave:notification:replaced?
+ },
+
+ /**
+ * Remove all notifications that match a title. If no title is provided, all
+ * notifications are removed.
+ *
+ * @param title [optional]
+ * Title of notifications to remove; falsy value means remove all
+ */
+ removeAll: function Notifications_removeAll(title) {
+ this.notifications.filter(old => (old.title == title || !title)).
+ forEach(old => { this.remove(old); }, this);
+ },
+
+ // replaces all existing notifications with the same title as the new one
+ replaceTitle: function Notifications_replaceTitle(notification) {
+ this.removeAll(notification.title);
+ this.add(notification);
+ }
+};
+
+
+/**
+ * A basic notification. Subclass this to create more complex notifications.
+ */
+this.Notification =
+function Notification(title, description, iconURL, priority, buttons, link) {
+ this.title = title;
+ this.description = description;
+
+ if (iconURL)
+ this.iconURL = iconURL;
+
+ if (priority)
+ this.priority = priority;
+
+ if (buttons)
+ this.buttons = buttons;
+
+ if (link)
+ this.link = link;
+}
+
+// We set each prototype property individually instead of redefining
+// the entire prototype to avoid blowing away existing properties
+// of the prototype like the the "constructor" property, which we use
+// to bind notification objects to their XBL representations.
+Notification.prototype.priority = Notifications.PRIORITY_INFO;
+Notification.prototype.iconURL = null;
+Notification.prototype.buttons = [];
+
+/**
+ * A button to display in a notification.
+ */
+this.NotificationButton =
+ function NotificationButton(label, accessKey, callback) {
+ function callbackWrapper() {
+ try {
+ callback.apply(this, arguments);
+ } catch (e) {
+ let logger = Log.repository.getLogger("Sync.Notifications");
+ logger.error("An exception occurred: " + Utils.exceptionStr(e));
+ logger.info(Utils.stackTrace(e));
+ throw e;
+ }
+ }
+
+ this.label = label;
+ this.accessKey = accessKey;
+ this.callback = callbackWrapper;
+}
diff --git a/services/sync/modules/record.js b/services/sync/modules/record.js
index 02f7f281a..f7a69d9ef 100644
--- a/services/sync/modules/record.js
+++ b/services/sync/modules/record.js
@@ -43,7 +43,7 @@ WBORecord.prototype = {
// Get thyself from your URI, then deserialize.
// Set thine 'response' field.
fetch: function fetch(resource) {
- if (!resource instanceof Resource) {
+ if (!(resource instanceof Resource)) {
throw new Error("First argument must be a Resource instance.");
}
@@ -56,7 +56,7 @@ WBORecord.prototype = {
},
upload: function upload(resource) {
- if (!resource instanceof Resource) {
+ if (!(resource instanceof Resource)) {
throw new Error("First argument must be a Resource instance.");
}
diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js
index b0eb0f41d..f8c64b0fa 100644
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -455,7 +455,7 @@ Sync11Service.prototype = {
this.clientsEngine = new ClientEngine(this);
for (let name of engines) {
- if (!name in ENGINE_MODULES) {
+ if (!(name in ENGINE_MODULES)) {
this._log.info("Do not know about engine: " + name);
continue;
}
@@ -1067,31 +1067,34 @@ Sync11Service.prototype = {
// Note: returns false if we failed for a reason other than the server not yet
// supporting the api.
_fetchServerConfiguration() {
- // This is similar to _fetchInfo, but with different error handling.
+ if (Svc.Prefs.get("APILevel") >= 2) {
+ // This is similar to _fetchInfo, but with different error handling.
+ // Only supported by later sync implementations.
- let infoURL = this.userBaseURL + "info/configuration";
- this._log.debug("Fetching server configuration", infoURL);
- let configResponse;
- try {
- configResponse = this.resource(infoURL).get();
- } catch (ex) {
- // This is probably a network or similar error.
- this._log.warn("Failed to fetch info/configuration", ex);
- this.errorHandler.checkServerError(ex);
- return false;
- }
+ let infoURL = this.userBaseURL + "info/configuration";
+ this._log.debug("Fetching server configuration", infoURL);
+ let configResponse;
+ try {
+ configResponse = this.resource(infoURL).get();
+ } catch (ex) {
+ // This is probably a network or similar error.
+ this._log.warn("Failed to fetch info/configuration", ex);
+ this.errorHandler.checkServerError(ex);
+ return false;
+ }
- if (configResponse.status == 404) {
- // This server doesn't support the URL yet - that's OK.
- this._log.debug("info/configuration returned 404 - using default upload semantics");
- } else if (configResponse.status != 200) {
- this._log.warn(`info/configuration returned ${configResponse.status} - using default configuration`);
- this.errorHandler.checkServerError(configResponse);
- return false;
- } else {
- this.serverConfiguration = configResponse.obj;
+ if (configResponse.status == 404) {
+ // This server doesn't support the URL yet - that's OK.
+ this._log.debug("info/configuration returned 404 - using default upload semantics");
+ } else if (configResponse.status != 200) {
+ this._log.warn(`info/configuration returned ${configResponse.status} - using default configuration`);
+ this.errorHandler.checkServerError(configResponse);
+ return false;
+ } else {
+ this.serverConfiguration = configResponse.obj;
+ }
+ this._log.trace("info/configuration for this server", this.serverConfiguration);
}
- this._log.trace("info/configuration for this server", this.serverConfiguration);
return true;
},
diff --git a/services/sync/moz.build b/services/sync/moz.build
index c4d3607b5..83c39274a 100644
--- a/services/sync/moz.build
+++ b/services/sync/moz.build
@@ -13,6 +13,9 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
EXTRA_COMPONENTS += [
'SyncComponents.manifest',
+]
+
+EXTRA_PP_COMPONENTS += [
'Weave.js',
]
@@ -28,11 +31,11 @@ EXTRA_JS_MODULES['services-sync'] += [
'modules/jpakeclient.js',
'modules/keys.js',
'modules/main.js',
+ 'modules/notifications.js',
'modules/policies.js',
'modules/record.js',
'modules/resource.js',
'modules/rest.js',
- 'modules/service.js',
'modules/status.js',
'modules/SyncedTabs.jsm',
'modules/telemetry.js',
@@ -42,10 +45,11 @@ EXTRA_JS_MODULES['services-sync'] += [
EXTRA_PP_JS_MODULES['services-sync'] += [
'modules/constants.js',
+ 'modules/service.js',
]
# Definitions used by constants.js
-DEFINES['weave_version'] = '1.54.0'
+DEFINES['weave_version'] = '1.54.1'
DEFINES['weave_id'] = '{340c2bbc-ce74-4362-90b5-7c26312808ef}'
EXTRA_JS_MODULES['services-sync'].engines += [
diff --git a/services/sync/services-sync.js b/services/sync/services-sync.js
index f4167c1ce..ebac4412b 100644
--- a/services/sync/services-sync.js
+++ b/services/sync/services-sync.js
@@ -12,6 +12,7 @@ pref("services.sync.syncKeyHelpURL", "https://services.mozilla.com/help/synckey"
pref("services.sync.lastversion", "firstrun");
pref("services.sync.sendVersionInfo", true);
+pref("services.sync.APILevel", 2);
pref("services.sync.scheduler.eolInterval", 604800); // 1 week
pref("services.sync.scheduler.idleInterval", 3600); // 1 hour
diff --git a/services/sync/tests/unit/test_service_login.js b/services/sync/tests/unit/test_service_login.js
index 42c163915..2ecb0a377 100644
--- a/services/sync/tests/unit/test_service_login.js
+++ b/services/sync/tests/unit/test_service_login.js
@@ -206,7 +206,7 @@ add_test(function test_login_on_sync() {
_("Old passphrase function is " + oldGetter);
Service.identity.__defineGetter__("syncKey",
function() {
- throw "User canceled Master Password entry";
+ throw "User canceled master password entry";
});
let oldClearSyncTriggers = Service.scheduler.clearSyncTriggers;
diff --git a/services/sync/tests/unit/test_syncscheduler.js b/services/sync/tests/unit/test_syncscheduler.js
index b066eae82..730a3f996 100644
--- a/services/sync/tests/unit/test_syncscheduler.js
+++ b/services/sync/tests/unit/test_syncscheduler.js
@@ -535,7 +535,7 @@ add_task(function* test_autoconnect_mp_locked() {
delete Service.identity.syncKey;
Service.identity.__defineGetter__("syncKey", function() {
_("Faking Master Password entry cancelation.");
- throw "User canceled Master Password entry";
+ throw "User canceled master password entry";
});
let deferred = Promise.defer();
diff --git a/services/sync/tests/unit/xpcshell.ini b/services/sync/tests/unit/xpcshell.ini
index 5a90652b8..609003ce9 100644
--- a/services/sync/tests/unit/xpcshell.ini
+++ b/services/sync/tests/unit/xpcshell.ini
@@ -13,7 +13,6 @@ support-files =
sync_ping_schema.json
systemaddon-search.xml
!/services/common/tests/unit/head_helpers.js
- !/toolkit/mozapps/webextensions/test/xpcshell/head_addons.js
!/toolkit/components/webextensions/test/xpcshell/head_sync.js
# The manifest is roughly ordered from low-level to high-level. When making
diff --git a/services/sync/tps/extensions/mozmill/resource/driver/controller.js b/services/sync/tps/extensions/mozmill/resource/driver/controller.js
index a378ce51f..8d66a41ae 100644
--- a/services/sync/tps/extensions/mozmill/resource/driver/controller.js
+++ b/services/sync/tps/extensions/mozmill/resource/driver/controller.js
@@ -978,7 +978,7 @@ function browserAdditions (controller) {
}, "Timeout", timeout, aInterval);
}
catch (ex) {
- if (!ex instanceof errors.TimeoutError) {
+ if (!(ex instanceof errors.TimeoutError)) {
throw ex;
}
timed_out = true;
diff --git a/services/sync/tps/extensions/mozmill/resource/modules/assertions.js b/services/sync/tps/extensions/mozmill/resource/modules/assertions.js
index c9991acf0..c76f95747 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/assertions.js
+++ b/services/sync/tps/extensions/mozmill/resource/modules/assertions.js
@@ -659,7 +659,7 @@ Expect.prototype.waitFor = function Expect_waitFor(aCallback, aMessage, aTimeout
Assert.prototype.waitFor.apply(this, arguments);
}
catch (ex) {
- if (!ex instanceof errors.AssertionError) {
+ if (!(ex instanceof errors.AssertionError)) {
throw ex;
}
message = ex.message;