зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1207889 - handle the webchannel changepassword command and update the signed in user. r=kitcambridge
This commit is contained in:
Родитель
c2a8ac0bf2
Коммит
cb14fb1dec
|
@ -56,6 +56,7 @@ var publicProperties = [
|
|||
"resendVerificationEmail",
|
||||
"setSignedInUser",
|
||||
"signOut",
|
||||
"updateUserAccountData",
|
||||
"updateDeviceRegistration",
|
||||
"whenVerified"
|
||||
];
|
||||
|
@ -522,6 +523,34 @@ FxAccountsInternal.prototype = {
|
|||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Update account data for the currently signed in user.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials object containing the fields to be updated.
|
||||
* This object must contain |email| and |uid| fields and they must
|
||||
* match the currently signed in user.
|
||||
*/
|
||||
updateUserAccountData(credentials) {
|
||||
log.debug("updateUserAccountData called with fields", Object.keys(credentials));
|
||||
if (logPII) {
|
||||
log.debug("updateUserAccountData called with data", credentials);
|
||||
}
|
||||
let currentAccountState = this.currentAccountState;
|
||||
return currentAccountState.promiseInitialized.then(() => {
|
||||
return currentAccountState.getUserAccountData(["email", "uid"]);
|
||||
}).then(existing => {
|
||||
if (existing.email != credentials.email || existing.uid != credentials.uid) {
|
||||
throw new Error("The specified credentials aren't for the current user");
|
||||
}
|
||||
// We need to nuke email and uid as storage will complain if we try and
|
||||
// update them (even when the value is the same)
|
||||
credentials = Cu.cloneInto(credentials, {}); // clone it first
|
||||
delete credentials.email;
|
||||
delete credentials.uid;
|
||||
return currentAccountState.updateUserAccountData(credentials);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* returns a promise that fires with the assertion. If there is no verified
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"FxAccountsStorageManagerCanStoreField",
|
||||
"FxAccountsStorageManager",
|
||||
];
|
||||
|
||||
|
@ -16,6 +17,15 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
|||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
// 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) {
|
||||
return FXA_PWDMGR_MEMORY_FIELDS.has(fieldName) ||
|
||||
FXA_PWDMGR_PLAINTEXT_FIELDS.has(fieldName) ||
|
||||
FXA_PWDMGR_SECURE_FIELDS.has(fieldName);
|
||||
}
|
||||
|
||||
// The storage manager object.
|
||||
this.FxAccountsStorageManager = function(options = {}) {
|
||||
this.options = {
|
||||
filename: options.filename || DEFAULT_STORAGE_FILENAME,
|
||||
|
|
|
@ -22,6 +22,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
|
|||
"resource://gre/modules/WebChannel.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
|
||||
"resource://gre/modules/FxAccounts.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsStorageManagerCanStoreField",
|
||||
"resource://gre/modules/FxAccountsStorage.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Weave",
|
||||
"resource://services-sync/main.js");
|
||||
|
||||
|
@ -31,6 +33,7 @@ const COMMAND_LOGIN = "fxaccounts:login";
|
|||
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 PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
|
||||
const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync-setup.ui.showCustomizationDialog";
|
||||
|
@ -172,6 +175,9 @@ this.FxAccountsWebChannel.prototype = {
|
|||
case COMMAND_SYNC_PREFERENCES:
|
||||
this._helpers.openSyncPreferences(sendingContext.browser, data.entryPoint);
|
||||
break;
|
||||
case COMMAND_CHANGE_PASSWORD:
|
||||
this._helpers.changePassword(data);
|
||||
break;
|
||||
default:
|
||||
log.warn("Unrecognized FxAccountsWebChannel command", command);
|
||||
break;
|
||||
|
@ -275,6 +281,29 @@ this.FxAccountsWebChannelHelpers.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
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
|
||||
// versions to supported field names doesn't buy us much.
|
||||
// So we just remove field names we know aren't handled.
|
||||
let newCredentials = {};
|
||||
for (let name of Object.keys(credentials)) {
|
||||
if (name == "email" || name == "uid" || FxAccountsStorageManagerCanStoreField(name)) {
|
||||
newCredentials[name] = credentials[name];
|
||||
} else {
|
||||
log.info("changePassword ignoring unsupported field", name);
|
||||
}
|
||||
}
|
||||
this._fxAccounts.updateUserAccountData(newCredentials).catch(err => {
|
||||
log.error("Failed to update account data on password change", err);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the hash of account name of the previously signed in account
|
||||
*/
|
||||
|
|
|
@ -262,6 +262,58 @@ add_task(function* test_get_signed_in_user_initially_unset() {
|
|||
do_check_eq(result, null);
|
||||
});
|
||||
|
||||
add_task(function* test_update_account_data() {
|
||||
_("Check updateUserAccountData does the right thing.");
|
||||
let account = MakeFxAccounts();
|
||||
let credentials = {
|
||||
email: "foo@example.com",
|
||||
uid: "1234@lcip.org",
|
||||
assertion: "foobar",
|
||||
sessionToken: "dead",
|
||||
kA: "beef",
|
||||
kB: "cafe",
|
||||
verified: true
|
||||
};
|
||||
yield account.setSignedInUser(credentials);
|
||||
|
||||
let newCreds = {
|
||||
email: credentials.email,
|
||||
uid: credentials.uid,
|
||||
assertion: "new_assertion",
|
||||
}
|
||||
yield account.updateUserAccountData(newCreds);
|
||||
do_check_eq((yield account.getSignedInUser()).assertion, "new_assertion",
|
||||
"new field value was saved");
|
||||
|
||||
// but we should fail attempting to change email or uid.
|
||||
newCreds = {
|
||||
email: "someoneelse@example.com",
|
||||
uid: credentials.uid,
|
||||
assertion: "new_assertion",
|
||||
}
|
||||
yield Assert.rejects(account.updateUserAccountData(newCreds));
|
||||
newCreds = {
|
||||
email: credentials.email,
|
||||
uid: "another_uid",
|
||||
assertion: "new_assertion",
|
||||
}
|
||||
yield Assert.rejects(account.updateUserAccountData(newCreds));
|
||||
|
||||
// should fail without email or uid.
|
||||
newCreds = {
|
||||
assertion: "new_assertion",
|
||||
}
|
||||
yield Assert.rejects(account.updateUserAccountData(newCreds));
|
||||
|
||||
// and should fail with a field name that's not known by storage.
|
||||
newCreds = {
|
||||
email: credentials.email,
|
||||
uid: "another_uid",
|
||||
foo: "bar",
|
||||
}
|
||||
yield Assert.rejects(account.updateUserAccountData(newCreds));
|
||||
});
|
||||
|
||||
add_task(function* test_getCertificateOffline() {
|
||||
_("getCertificateOffline()");
|
||||
let fxa = MakeFxAccounts();
|
||||
|
|
|
@ -319,6 +319,26 @@ add_test(function test_helpers_open_sync_preferences() {
|
|||
helpers.openSyncPreferences(mockBrowser, "fxa:verification_complete");
|
||||
});
|
||||
|
||||
add_test(function test_helpers_change_password() {
|
||||
let updateCalled = false;
|
||||
let helpers = new FxAccountsWebChannelHelpers({
|
||||
fxAccounts: {
|
||||
updateUserAccountData(credentials) {
|
||||
do_check_true(credentials.hasOwnProperty("email"));
|
||||
do_check_true(credentials.hasOwnProperty("uid"));
|
||||
do_check_true(credentials.hasOwnProperty("kA"));
|
||||
// "foo" isn't a field known by storage, so should be dropped.
|
||||
do_check_false(credentials.hasOwnProperty("foo"));
|
||||
updateCalled = true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
helpers.changePassword({ email: "email", uid: "uid", kA: "kA", foo: "foo" });
|
||||
do_check_true(updateCalled);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче