Bug 1374501 - Allow extra sync engines to be activited using FxA Web Channels. r?markh
MozReview-Commit-ID: HykDad81Ifh
--- a/services/fxaccounts/FxAccountsWebChannel.jsm
+++ b/services/fxaccounts/FxAccountsWebChannel.jsm
@@ -33,16 +33,21 @@ const COMMAND_LOGIN = "fx
const COMMAND_LOGOUT = "fxaccounts:logout";
const COMMAND_DELETE = "fxaccounts:delete";
const COMMAND_SYNC_PREFERENCES = "fxaccounts:sync_preferences";
const COMMAND_CHANGE_PASSWORD = "fxaccounts:change_password";
const COMMAND_FXA_STATUS = "fxaccounts:fxa_status";
const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
+// These engines were added years after Sync had been introduced, they need
+// special handling since they are system add-ons and are un-available on
+// older versions of Firefox.
+const EXTRA_ENGINES = ["addresses", "creditcards"];
+
/**
* A helper function that extracts the message and stack from an error object.
* Returns a `{ message, stack }` tuple. `stack` will be null if the error
* doesn't have a stack trace.
*/
function getErrorDetails(error) {
let details = { message: String(error), stack: null };
@@ -275,16 +280,27 @@ this.FxAccountsWebChannelHelpers.prototy
* @param accountData the user's account data and credentials
*/
login(accountData) {
// We don't act on customizeSync anymore, it used to open a dialog inside
// the browser to selecte the engines to sync but we do it on the web now.
delete accountData.customizeSync;
+ if (accountData.offeredSyncEngines) {
+ EXTRA_ENGINES.forEach(engine => {
+ if (accountData.offeredSyncEngines.includes(engine) &&
+ !accountData.declinedSyncEngines.includes(engine)) {
+ // These extra engines are disabled by default.
+ Services.prefs.setBoolPref(`services.sync.engine.${engine}`, true);
+ }
+ });
+ delete accountData.offeredSyncEngines;
+ }
+
if (accountData.declinedSyncEngines) {
let declinedSyncEngines = accountData.declinedSyncEngines;
log.debug("Received declined engines", declinedSyncEngines);
Weave.Service.engineManager.setDeclined(declinedSyncEngines);
declinedSyncEngines.forEach(engine => {
Services.prefs.setBoolPref("services.sync.engine." + engine, false);
});
delete accountData.declinedSyncEngines;
@@ -379,20 +395,33 @@ this.FxAccountsWebChannelHelpers.prototy
sessionToken: userData.sessionToken,
uid: userData.uid,
verified: userData.verified
};
}
}
return {
- signedInUser
+ signedInUser,
+ capabilities: {
+ engines: this._getAvailableExtraEngines()
+ }
};
},
+ _getAvailableExtraEngines() {
+ return EXTRA_ENGINES.filter(engineName => {
+ try {
+ return Services.prefs.getBoolPref(`services.sync.engine.${engineName}.available`);
+ } catch (e) {
+ return false;
+ }
+ });
+ },
+
changePassword(credentials) {
// If |credentials| has fields that aren't handled by accounts storage,
// updateUserAccountData will throw - mainly to prevent errors in code
// that hard-codes field names.
// However, in this case the field names aren't really in our control.
// We *could* still insist the server know what fields names are valid,
// but that makes life difficult for the server when Firefox adds new
// features (ie, new fields) - forcing the server to track a map of
--- a/services/fxaccounts/tests/xpcshell/test_web_channel.js
+++ b/services/fxaccounts/tests/xpcshell/test_web_channel.js
@@ -254,16 +254,19 @@ add_test(function test_fxa_status_messag
helpers: {
async getFxaStatus() {
return {
signedInUser: {
email: "testuser@testuser.com",
sessionToken: "session-token",
uid: "uid",
verified: true
+ },
+ capabilities: {
+ engines: ["creditcards", "addresses"]
}
};
}
}
});
channel._channel = {
send(response, sendingContext) {
@@ -272,16 +275,18 @@ add_test(function test_fxa_status_messag
let signedInUser = response.data.signedInUser;
do_check_true(!!signedInUser);
do_check_eq(signedInUser.email, "testuser@testuser.com");
do_check_eq(signedInUser.sessionToken, "session-token");
do_check_eq(signedInUser.uid, "uid");
do_check_eq(signedInUser.verified, true);
+ deepEqual(response.data.capabilities.engines, ["creditcards", "addresses"]);
+
run_next_test();
}
};
channel._channelCallback(WEBCHANNEL_ID, mockMessage, mockSendingContext);
});
add_test(function test_unrecognized_message() {
@@ -412,32 +417,93 @@ add_task(function* test_helpers_login_wi
yield helpers.login({
email: "testuser@testuser.com",
verifiedCanLinkAccount: true,
customizeSync: true,
declinedSyncEngines: ["addons", "prefs"]
});
});
+add_task(async function test_helpers_login_with_offered_sync_engines() {
+ let helpers;
+ const setSignedInUserCalled = new Promise(resolve => {
+ helpers = new FxAccountsWebChannelHelpers({
+ fxAccounts: {
+ async setSignedInUser(accountData) {
+ resolve(accountData);
+ }
+ }
+ });
+ });
+
+ Services.prefs.setBoolPref("services.sync.engine.creditcards", false);
+ Services.prefs.setBoolPref("services.sync.engine.addresses", false);
+
+ await helpers.login({
+ email: "testuser@testuser.com",
+ verifiedCanLinkAccount: true,
+ customizeSync: true,
+ declinedSyncEngines: ["addresses"],
+ offeredSyncEngines: ["creditcards", "addresses"]
+ });
+
+ const accountData = await setSignedInUserCalled;
+
+ // ensure fxAccounts is informed of the new user being signed in.
+ equal(accountData.email, "testuser@testuser.com");
+
+ // offeredSyncEngines should be stripped in the data.
+ ok(!("offeredSyncEngines" in accountData));
+ // credit cards was offered but not declined.
+ equal(Services.prefs.getBoolPref("services.sync.engine.creditcards"), true);
+ // addresses was offered and explicitely declined.
+ equal(Services.prefs.getBoolPref("services.sync.engine.addresses"), false);
+});
+
add_test(function test_helpers_open_sync_preferences() {
let helpers = new FxAccountsWebChannelHelpers({
fxAccounts: {
}
});
let mockBrowser = {
loadURI(uri) {
do_check_eq(uri, "about:preferences?entrypoint=fxa%3Averification_complete#sync");
run_next_test();
}
};
helpers.openSyncPreferences(mockBrowser, "fxa:verification_complete");
});
+add_task(async function test_helpers_getFxAStatus_extra_engines() {
+ let helpers = new FxAccountsWebChannelHelpers({
+ fxAccounts: {
+ getSignedInUser() {
+ return Promise.resolve({
+ email: "testuser@testuser.com",
+ kA: "kA",
+ kb: "kB",
+ sessionToken: "sessionToken",
+ uid: "uid",
+ verified: true
+ });
+ }
+ }
+ });
+
+ Services.prefs.setBoolPref("services.sync.engine.creditcards.available", true);
+ // Not defining "services.sync.engine.addresses.available" on purpose.
+
+ let fxaStatus = await helpers.getFxaStatus("sync", mockSendingContext);
+ ok(!!fxaStatus);
+ ok(!!fxaStatus.signedInUser);
+ deepEqual(fxaStatus.capabilities.engines, ["creditcards"]);
+});
+
add_task(function* test_helpers_getFxaStatus_allowed_signedInUser() {
let wasCalled = {
getSignedInUser: false,
shouldAllowFxaStatus: false
};
let helpers = new FxAccountsWebChannelHelpers({