mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 04:38:02 +00:00
Bug 1383663 part 3 - Update FxA local state on profile email change. r=markh
MozReview-Commit-ID: 5epKjoT4TF3 --HG-- extra : rebase_source : 3c9737d304d2a4a4448e43c1f4a13e738716453e
This commit is contained in:
parent
16c757d39c
commit
dc3b62bea0
@ -113,6 +113,15 @@ this.CryptoUtils = {
|
||||
return CommonUtils.bytesAsHex(CryptoUtils.digestUTF8(message, hasher));
|
||||
},
|
||||
|
||||
sha256Base64(message) {
|
||||
let data = this._utf8Converter.convertToByteArray(message, {});
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(hasher.SHA256);
|
||||
hasher.update(data, data.length);
|
||||
return hasher.finish(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Produce an HMAC key object from a key string.
|
||||
*/
|
||||
|
@ -51,8 +51,9 @@ var publicProperties = [
|
||||
"getProfileCache",
|
||||
"getSignedInUser",
|
||||
"getSignedInUserProfile",
|
||||
"handleDeviceDisconnection",
|
||||
"handleAccountDestroyed",
|
||||
"handleDeviceDisconnection",
|
||||
"handleEmailUpdated",
|
||||
"hasLocalSession",
|
||||
"invalidateCertificate",
|
||||
"loadAndPoll",
|
||||
@ -593,7 +594,7 @@ FxAccountsInternal.prototype = {
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials object containing the fields to be updated.
|
||||
* This object must contain |email| and |uid| fields and they must
|
||||
* This object must contain the |uid| field and it must
|
||||
* match the currently signed in user.
|
||||
*/
|
||||
updateUserAccountData(credentials) {
|
||||
@ -603,15 +604,14 @@ FxAccountsInternal.prototype = {
|
||||
}
|
||||
let currentAccountState = this.currentAccountState;
|
||||
return currentAccountState.promiseInitialized.then(() => {
|
||||
return currentAccountState.getUserAccountData(["email", "uid"]);
|
||||
return currentAccountState.getUserAccountData(["uid"]);
|
||||
}).then(existing => {
|
||||
if (existing.email != credentials.email || existing.uid != credentials.uid) {
|
||||
if (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)
|
||||
// We need to nuke uid as storage will complain if we try and
|
||||
// update it (even when the value is the same)
|
||||
credentials = Cu.cloneInto(credentials, {}); // clone it first
|
||||
delete credentials.email;
|
||||
delete credentials.uid;
|
||||
return currentAccountState.updateUserAccountData(credentials);
|
||||
});
|
||||
@ -1607,6 +1607,11 @@ FxAccountsInternal.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
handleEmailUpdated(newEmail) {
|
||||
Services.prefs.setStringPref(PREF_LAST_FXA_USER, CryptoUtils.sha256Base64(newEmail));
|
||||
return this.currentAccountState.updateUserAccountData({ email: newEmail });
|
||||
},
|
||||
|
||||
async handleAccountDestroyed(uid) {
|
||||
const accountData = await this.currentAccountState.getUserAccountData();
|
||||
const localUid = accountData ? accountData.uid : null;
|
||||
|
@ -113,6 +113,8 @@ exports.FX_OAUTH_CLIENT_ID = "5882386c6d801776";
|
||||
// Firefox Accounts WebChannel ID
|
||||
exports.WEBCHANNEL_ID = "account_updates";
|
||||
|
||||
exports.PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
|
||||
|
||||
// Server errno.
|
||||
// From https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
|
||||
exports.ERRNO_ACCOUNT_ALREADY_EXISTS = 101;
|
||||
|
@ -71,45 +71,40 @@ this.FxAccountsProfile.prototype = {
|
||||
},
|
||||
|
||||
// Cache fetched data and send out a notification so that UI can update.
|
||||
_cacheProfile(response) {
|
||||
async _cacheProfile(response) {
|
||||
const profile = response.body;
|
||||
const userData = await this.fxa.getSignedInUser();
|
||||
if (profile.uid != userData.uid) {
|
||||
throw new Error("The fetched profile does not correspond with the current account.")
|
||||
}
|
||||
let profileCache = {
|
||||
profile: response.body,
|
||||
profile,
|
||||
etag: response.etag
|
||||
};
|
||||
|
||||
return this.fxa.setProfileCache(profileCache)
|
||||
.then(() => {
|
||||
return this.fxa.getSignedInUser();
|
||||
})
|
||||
.then(userData => {
|
||||
log.debug("notifying profile changed for user ${uid}", userData);
|
||||
this._notifyProfileChange(userData.uid);
|
||||
return response.body;
|
||||
});
|
||||
await this.fxa.setProfileCache(profileCache);
|
||||
if (profile.email != userData.email) {
|
||||
await this.fxa.handleEmailUpdated(profile.email);
|
||||
}
|
||||
log.debug("notifying profile changed for user ${uid}", userData);
|
||||
this._notifyProfileChange(userData.uid);
|
||||
return profile;
|
||||
},
|
||||
|
||||
_fetchAndCacheProfileInternal() {
|
||||
let onFinally = () => {
|
||||
async _fetchAndCacheProfileInternal() {
|
||||
try {
|
||||
const profileCache = await this.fxa.getProfileCache();
|
||||
const etag = profileCache ? profileCache.etag : null;
|
||||
const response = await this.client.fetchProfile(etag);
|
||||
|
||||
// response may be null if the profile was not modified (same ETag).
|
||||
if (!response) {
|
||||
return null;
|
||||
}
|
||||
return await this._cacheProfile(response);
|
||||
} finally {
|
||||
this._cachedAt = Date.now();
|
||||
this._currentFetchPromise = null;
|
||||
}
|
||||
return this.fxa.getProfileCache()
|
||||
.then(profileCache => {
|
||||
const etag = profileCache ? profileCache.etag : null;
|
||||
return this.client.fetchProfile(etag);
|
||||
})
|
||||
.then(response => {
|
||||
// response may be null if the profile was not modified (same ETag).
|
||||
return response ? this._cacheProfile(response) : null;
|
||||
})
|
||||
.then(body => { // finally block
|
||||
onFinally();
|
||||
// body may be null if the profile was not modified
|
||||
return body;
|
||||
}, err => {
|
||||
onFinally();
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
_fetchAndCacheProfile() {
|
||||
@ -122,23 +117,21 @@ this.FxAccountsProfile.prototype = {
|
||||
// Returns cached data right away if available, then fetches the latest profile
|
||||
// data in the background. After data is fetched a notification will be sent
|
||||
// out if the profile has changed.
|
||||
getProfile() {
|
||||
return this.fxa.getProfileCache()
|
||||
.then(profileCache => {
|
||||
if (profileCache) {
|
||||
if (Date.now() > this._cachedAt + this.PROFILE_FRESHNESS_THRESHOLD) {
|
||||
// Note that _fetchAndCacheProfile isn't returned, so continues
|
||||
// in the background.
|
||||
this._fetchAndCacheProfile().catch(err => {
|
||||
log.error("Background refresh of profile failed", err);
|
||||
});
|
||||
} else {
|
||||
log.trace("not checking freshness of profile as it remains recent");
|
||||
}
|
||||
return profileCache.profile;
|
||||
}
|
||||
return this._fetchAndCacheProfile();
|
||||
async getProfile() {
|
||||
const profileCache = await this.fxa.getProfileCache();
|
||||
if (!profileCache) {
|
||||
return this._fetchAndCacheProfile();
|
||||
}
|
||||
if (Date.now() > this._cachedAt + this.PROFILE_FRESHNESS_THRESHOLD) {
|
||||
// Note that _fetchAndCacheProfile isn't returned, so continues
|
||||
// in the background.
|
||||
this._fetchAndCacheProfile().catch(err => {
|
||||
log.error("Background refresh of profile failed", err);
|
||||
});
|
||||
} else {
|
||||
log.trace("not checking freshness of profile as it remains recent");
|
||||
}
|
||||
return profileCache.profile;
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
|
@ -208,11 +208,8 @@ this.FxAccountsStorageManager.prototype = {
|
||||
// update fields.
|
||||
throw new Error("No user is logged in");
|
||||
}
|
||||
if (!newFields || "uid" in newFields || "email" in newFields) {
|
||||
// Once we support
|
||||
// user changing email address this may need to change, but it's not
|
||||
// clear how we would be told of such a change anyway...
|
||||
throw new Error("Can't change uid or email address");
|
||||
if (!newFields || "uid" in newFields) {
|
||||
throw new Error("Can't change uid");
|
||||
}
|
||||
log.debug("_updateAccountData with items", Object.keys(newFields));
|
||||
// work out what bucket.
|
||||
|
@ -29,6 +29,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Weave",
|
||||
"resource://services-sync/main.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils",
|
||||
"resource://services-crypto/utils.js");
|
||||
|
||||
const COMMAND_PROFILE_CHANGE = "profile:change";
|
||||
const COMMAND_CAN_LINK_ACCOUNT = "fxaccounts:can_link_account";
|
||||
@ -39,8 +41,6 @@ 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.
|
||||
@ -459,24 +459,7 @@ this.FxAccountsWebChannelHelpers.prototype = {
|
||||
* @param acctName the account name of the user's account.
|
||||
*/
|
||||
setPreviousAccountNameHashPref(acctName) {
|
||||
Services.prefs.setStringPref(PREF_LAST_FXA_USER, this.sha256(acctName));
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a string, returns the SHA265 hash in base64
|
||||
*/
|
||||
sha256(str) {
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
// Data is an array of bytes.
|
||||
let data = converter.convertToByteArray(str, {});
|
||||
let hasher = Cc["@mozilla.org/security/hash;1"]
|
||||
.createInstance(Ci.nsICryptoHash);
|
||||
hasher.init(hasher.SHA256);
|
||||
hasher.update(data, data.length);
|
||||
|
||||
return hasher.finish(true);
|
||||
Services.prefs.setStringPref(PREF_LAST_FXA_USER, CryptoUtils.sha256Base64(acctName));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -504,7 +487,7 @@ this.FxAccountsWebChannelHelpers.prototype = {
|
||||
*/
|
||||
_needRelinkWarning(acctName) {
|
||||
let prevAcctHash = this.getPreviousAccountNameHashPref();
|
||||
return prevAcctHash && prevAcctHash != this.sha256(acctName);
|
||||
return prevAcctHash && prevAcctHash != CryptoUtils.sha256Base64(acctName);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -299,13 +299,7 @@ add_task(async function test_update_account_data() {
|
||||
do_check_eq((await 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",
|
||||
}
|
||||
await Assert.rejects(account.updateUserAccountData(newCreds));
|
||||
// but we should fail attempting to change the uid.
|
||||
newCreds = {
|
||||
email: credentials.email,
|
||||
uid: "another_uid",
|
||||
@ -313,7 +307,7 @@ add_task(async function test_update_account_data() {
|
||||
}
|
||||
await Assert.rejects(account.updateUserAccountData(newCreds));
|
||||
|
||||
// should fail without email or uid.
|
||||
// should fail without the uid.
|
||||
newCreds = {
|
||||
assertion: "new_assertion",
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
Cu.import("resource://gre/modules/FxAccountsProfileClient.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccountsProfile.jsm");
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
|
||||
const URL_STRING = "https://example.com";
|
||||
Services.prefs.setCharPref("identity.fxaccounts.settings.uri", "https://example.com/settings");
|
||||
@ -59,8 +60,11 @@ let mockClient = function(fxa) {
|
||||
return new FxAccountsProfileClient(options);
|
||||
};
|
||||
|
||||
const ACCOUNT_UID = "abc123";
|
||||
const ACCOUNT_EMAIL = "foo@bar.com";
|
||||
const ACCOUNT_DATA = {
|
||||
uid: "abc123"
|
||||
uid: ACCOUNT_UID,
|
||||
email: ACCOUNT_EMAIL
|
||||
};
|
||||
|
||||
function FxaMock() {
|
||||
@ -122,13 +126,13 @@ add_test(function cacheProfile_change() {
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
return profile._cacheProfile({ body: { avatar: "myurl" }, etag: "bogusetag" });
|
||||
return profile._cacheProfile({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myurl" }, etag: "bogusetag" });
|
||||
});
|
||||
|
||||
add_test(function fetchAndCacheProfile_ok() {
|
||||
let client = mockClient(mockFxa());
|
||||
client.fetchProfile = function() {
|
||||
return Promise.resolve({ body: { avatar: "myimg"} });
|
||||
return Promise.resolve({ body: { uid: ACCOUNT_UID, avatar: "myimg"} });
|
||||
};
|
||||
let profile = CreateFxAccountsProfile(null, client);
|
||||
profile._cachedAt = 12345;
|
||||
@ -169,7 +173,7 @@ add_test(function fetchAndCacheProfile_sendsETag() {
|
||||
let client = mockClient(fxa);
|
||||
client.fetchProfile = function(etag) {
|
||||
do_check_eq(etag, "bogusETag");
|
||||
return Promise.resolve({ body: { avatar: "myimg"} });
|
||||
return Promise.resolve({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"} });
|
||||
};
|
||||
let profile = CreateFxAccountsProfile(fxa, client);
|
||||
|
||||
@ -195,26 +199,18 @@ add_task(async function fetchAndCacheProfileOnce() {
|
||||
return promiseProfile;
|
||||
};
|
||||
let fxa = mockFxa();
|
||||
fxa.getProfileCache = () => {
|
||||
// We do this because we are gonna have a race condition and fetchProfile will
|
||||
// not be called before we check numFetches.
|
||||
return {
|
||||
then(thenFunc) {
|
||||
return thenFunc();
|
||||
}
|
||||
}
|
||||
};
|
||||
let profile = CreateFxAccountsProfile(fxa, client);
|
||||
|
||||
let request1 = profile._fetchAndCacheProfile();
|
||||
profile._fetchAndCacheProfile();
|
||||
await new Promise(res => setTimeout(res, 0)); // Yield so fetchProfile() is called (promise)
|
||||
|
||||
// should be one request made to fetch the profile (but the promise returned
|
||||
// by it remains unresolved)
|
||||
do_check_eq(numFetches, 1);
|
||||
|
||||
// resolve the promise.
|
||||
resolveProfile({ body: { avatar: "myimg"} });
|
||||
resolveProfile({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"} });
|
||||
|
||||
// both requests should complete with the same data.
|
||||
let got1 = await request1;
|
||||
@ -242,19 +238,11 @@ add_task(async function fetchAndCacheProfileOnce() {
|
||||
return promiseProfile;
|
||||
};
|
||||
let fxa = mockFxa();
|
||||
fxa.getProfileCache = () => {
|
||||
// We do this because we are gonna have a race condition and fetchProfile will
|
||||
// not be called before we check numFetches.
|
||||
return {
|
||||
then(thenFunc) {
|
||||
return thenFunc();
|
||||
}
|
||||
}
|
||||
};
|
||||
let profile = CreateFxAccountsProfile(fxa, client);
|
||||
|
||||
let request1 = profile._fetchAndCacheProfile();
|
||||
let request2 = profile._fetchAndCacheProfile();
|
||||
await new Promise(res => setTimeout(res, 0)); // Yield so fetchProfile() is called (promise)
|
||||
|
||||
// should be one request made to fetch the profile (but the promise returned
|
||||
// by it remains unresolved)
|
||||
@ -283,7 +271,7 @@ add_task(async function fetchAndCacheProfileOnce() {
|
||||
|
||||
// but a new request should works.
|
||||
client.fetchProfile = function() {
|
||||
return Promise.resolve({body: { avatar: "myimg"}});
|
||||
return Promise.resolve({body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"}});
|
||||
};
|
||||
|
||||
let got = await profile._fetchAndCacheProfile();
|
||||
@ -293,7 +281,7 @@ add_task(async function fetchAndCacheProfileOnce() {
|
||||
add_test(function fetchAndCacheProfile_alreadyCached() {
|
||||
let cachedUrl = "cachedurl";
|
||||
let fxa = mockFxa();
|
||||
fxa.profileCache = { profile: { avatar: cachedUrl }, etag: "bogusETag" };
|
||||
fxa.profileCache = { profile: { uid: ACCOUNT_UID, avatar: cachedUrl }, etag: "bogusETag" };
|
||||
let client = mockClient(fxa);
|
||||
client.fetchProfile = function(etag) {
|
||||
do_check_eq(etag, "bogusETag");
|
||||
@ -318,9 +306,9 @@ add_test(function fetchAndCacheProfile_alreadyCached() {
|
||||
add_task(async function fetchAndCacheProfileAfterThreshold() {
|
||||
let numFetches = 0;
|
||||
let client = mockClient(mockFxa());
|
||||
client.fetchProfile = function() {
|
||||
client.fetchProfile = async function() {
|
||||
numFetches += 1;
|
||||
return Promise.resolve({ avatar: "myimg"});
|
||||
return {body: {uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"}};
|
||||
};
|
||||
let profile = CreateFxAccountsProfile(null, client);
|
||||
profile.PROFILE_FRESHNESS_THRESHOLD = 1000;
|
||||
@ -335,7 +323,14 @@ add_task(async function fetchAndCacheProfileAfterThreshold() {
|
||||
do_timeout(1000, resolve);
|
||||
});
|
||||
|
||||
let origFetchAndCatch = profile._fetchAndCacheProfile;
|
||||
let backgroundFetchDone = PromiseUtils.defer();
|
||||
profile._fetchAndCacheProfile = async () => {
|
||||
await origFetchAndCatch.call(profile);
|
||||
backgroundFetchDone.resolve();
|
||||
}
|
||||
await profile.getProfile();
|
||||
await backgroundFetchDone.promise;
|
||||
do_check_eq(numFetches, 2);
|
||||
});
|
||||
|
||||
@ -345,9 +340,9 @@ add_task(async function fetchAndCacheProfileAfterThreshold() {
|
||||
add_task(async function fetchAndCacheProfileBeforeThresholdOnNotification() {
|
||||
let numFetches = 0;
|
||||
let client = mockClient(mockFxa());
|
||||
client.fetchProfile = function() {
|
||||
client.fetchProfile = async function() {
|
||||
numFetches += 1;
|
||||
return Promise.resolve({ avatar: "myimg"});
|
||||
return {body: {uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg"}};
|
||||
};
|
||||
let profile = CreateFxAccountsProfile(null, client);
|
||||
profile.PROFILE_FRESHNESS_THRESHOLD = 1000;
|
||||
@ -357,7 +352,14 @@ add_task(async function fetchAndCacheProfileBeforeThresholdOnNotification() {
|
||||
|
||||
Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION);
|
||||
|
||||
let origFetchAndCatch = profile._fetchAndCacheProfile;
|
||||
let backgroundFetchDone = PromiseUtils.defer();
|
||||
profile._fetchAndCacheProfile = async () => {
|
||||
await origFetchAndCatch.call(profile);
|
||||
backgroundFetchDone.resolve();
|
||||
}
|
||||
await profile.getProfile();
|
||||
await backgroundFetchDone.promise;
|
||||
do_check_eq(numFetches, 2);
|
||||
});
|
||||
|
||||
@ -379,7 +381,7 @@ add_test(function getProfile_ok() {
|
||||
let didFetch = false;
|
||||
|
||||
let fxa = mockFxa();
|
||||
fxa.profileCache = { profile: { avatar: cachedUrl } };
|
||||
fxa.profileCache = { profile: { uid: ACCOUNT_UID, avatar: cachedUrl } };
|
||||
let profile = CreateFxAccountsProfile(fxa);
|
||||
|
||||
profile._fetchAndCacheProfile = function() {
|
||||
@ -402,7 +404,7 @@ add_test(function getProfile_no_cache() {
|
||||
let profile = CreateFxAccountsProfile(fxa);
|
||||
|
||||
profile._fetchAndCacheProfile = function() {
|
||||
return Promise.resolve({ avatar: fetchedUrl });
|
||||
return Promise.resolve({ uid: ACCOUNT_UID, avatar: fetchedUrl });
|
||||
};
|
||||
|
||||
return profile.getProfile()
|
||||
@ -418,11 +420,11 @@ add_test(function getProfile_has_cached_fetch_deleted() {
|
||||
let fxa = mockFxa();
|
||||
let client = mockClient(fxa);
|
||||
client.fetchProfile = function() {
|
||||
return Promise.resolve({ body: { avatar: null } });
|
||||
return Promise.resolve({ body: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: null } });
|
||||
};
|
||||
|
||||
let profile = CreateFxAccountsProfile(fxa, client);
|
||||
fxa.profileCache = { profile: { avatar: cachedUrl } };
|
||||
fxa.profileCache = { profile: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: cachedUrl } };
|
||||
|
||||
// instead of checking this in a mocked "save" function, just check after the
|
||||
// observer
|
||||
@ -442,7 +444,7 @@ add_test(function getProfile_has_cached_fetch_deleted() {
|
||||
|
||||
add_test(function getProfile_fetchAndCacheProfile_throws() {
|
||||
let fxa = mockFxa();
|
||||
fxa.profileCache = { profile: { avatar: "myimg" } };
|
||||
fxa.profileCache = { profile: { uid: ACCOUNT_UID, email: ACCOUNT_EMAIL, avatar: "myimg" } };
|
||||
let profile = CreateFxAccountsProfile(fxa);
|
||||
|
||||
profile._fetchAndCacheProfile = () => Promise.reject(new Error());
|
||||
@ -454,6 +456,21 @@ add_test(function getProfile_fetchAndCacheProfile_throws() {
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function getProfile_email_changed() {
|
||||
let fxa = mockFxa();
|
||||
let client = mockClient(fxa);
|
||||
client.fetchProfile = function() {
|
||||
return Promise.resolve({ body: { uid: ACCOUNT_UID, email: "newemail@bar.com" } });
|
||||
};
|
||||
fxa.handleEmailUpdated = email => {
|
||||
do_check_eq(email, "newemail@bar.com");
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
let profile = CreateFxAccountsProfile(fxa, client);
|
||||
return profile._fetchAndCacheProfile();
|
||||
});
|
||||
|
||||
function makeObserver(aObserveTopic, aObserveFunc) {
|
||||
let callback = function(aSubject, aTopic, aData) {
|
||||
log.debug("observed " + aTopic + " " + aData);
|
||||
|
@ -4,6 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||
Cu.import("resource://services-crypto/utils.js");
|
||||
const { FxAccountsWebChannel, FxAccountsWebChannelHelpers } =
|
||||
Cu.import("resource://gre/modules/FxAccountsWebChannel.jsm", {});
|
||||
|
||||
@ -338,7 +339,8 @@ add_task(async function test_helpers_login_without_customize_sync() {
|
||||
do_check_false("verifiedCanLinkAccount" in accountData);
|
||||
|
||||
// previously signed in user preference is updated.
|
||||
do_check_eq(helpers.getPreviousAccountNameHashPref(), helpers.sha256("testuser@testuser.com"));
|
||||
do_check_eq(helpers.getPreviousAccountNameHashPref(),
|
||||
CryptoUtils.sha256Base64("testuser@testuser.com"));
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
@ -84,7 +84,7 @@
|
||||
"fxa_utils.js": ["initializeIdentityWithTokenServerResponse"],
|
||||
"fxaccounts.jsm": ["Authentication"],
|
||||
"FxAccounts.jsm": ["fxAccounts", "FxAccounts"],
|
||||
"FxAccountsCommon.js": ["log", "logPII", "FXACCOUNTS_PERMISSION", "DATA_FORMAT_VERSION", "DEFAULT_STORAGE_FILENAME", "ASSERTION_LIFETIME", "ASSERTION_USE_PERIOD", "CERT_LIFETIME", "KEY_LIFETIME", "POLL_SESSION", "ONLOGIN_NOTIFICATION", "ONVERIFIED_NOTIFICATION", "ONLOGOUT_NOTIFICATION", "ON_FXA_UPDATE_NOTIFICATION", "ON_DEVICE_CONNECTED_NOTIFICATION", "ON_DEVICE_DISCONNECTED_NOTIFICATION", "ON_PROFILE_UPDATED_NOTIFICATION", "ON_PASSWORD_CHANGED_NOTIFICATION", "ON_PASSWORD_RESET_NOTIFICATION", "ON_VERIFY_LOGIN_NOTIFICATION", "ON_ACCOUNT_DESTROYED_NOTIFICATION", "ON_COLLECTION_CHANGED_NOTIFICATION", "FXA_PUSH_SCOPE_ACCOUNT_UPDATE", "ON_PROFILE_CHANGE_NOTIFICATION", "ON_ACCOUNT_STATE_CHANGE_NOTIFICATION", "UI_REQUEST_SIGN_IN_FLOW", "UI_REQUEST_REFRESH_AUTH", "FX_OAUTH_CLIENT_ID", "WEBCHANNEL_ID", "ERRNO_ACCOUNT_ALREADY_EXISTS", "ERRNO_ACCOUNT_DOES_NOT_EXIST", "ERRNO_INCORRECT_PASSWORD", "ERRNO_UNVERIFIED_ACCOUNT", "ERRNO_INVALID_VERIFICATION_CODE", "ERRNO_NOT_VALID_JSON_BODY", "ERRNO_INVALID_BODY_PARAMETERS", "ERRNO_MISSING_BODY_PARAMETERS", "ERRNO_INVALID_REQUEST_SIGNATURE", "ERRNO_INVALID_AUTH_TOKEN", "ERRNO_INVALID_AUTH_TIMESTAMP", "ERRNO_MISSING_CONTENT_LENGTH", "ERRNO_REQUEST_BODY_TOO_LARGE", "ERRNO_TOO_MANY_CLIENT_REQUESTS", "ERRNO_INVALID_AUTH_NONCE", "ERRNO_ENDPOINT_NO_LONGER_SUPPORTED", "ERRNO_INCORRECT_LOGIN_METHOD", "ERRNO_INCORRECT_KEY_RETRIEVAL_METHOD", "ERRNO_INCORRECT_API_VERSION", "ERRNO_INCORRECT_EMAIL_CASE", "ERRNO_ACCOUNT_LOCKED", "ERRNO_ACCOUNT_UNLOCKED", "ERRNO_UNKNOWN_DEVICE", "ERRNO_DEVICE_SESSION_CONFLICT", "ERRNO_SERVICE_TEMP_UNAVAILABLE", "ERRNO_PARSE", "ERRNO_NETWORK", "ERRNO_UNKNOWN_ERROR", "OAUTH_SERVER_ERRNO_OFFSET", "ERRNO_UNKNOWN_CLIENT_ID", "ERRNO_INCORRECT_CLIENT_SECRET", "ERRNO_INCORRECT_REDIRECT_URI", "ERRNO_INVALID_FXA_ASSERTION", "ERRNO_UNKNOWN_CODE", "ERRNO_INCORRECT_CODE", "ERRNO_EXPIRED_CODE", "ERRNO_OAUTH_INVALID_TOKEN", "ERRNO_INVALID_REQUEST_PARAM", "ERRNO_INVALID_RESPONSE_TYPE", "ERRNO_UNAUTHORIZED", "ERRNO_FORBIDDEN", "ERRNO_INVALID_CONTENT_TYPE", "ERROR_ACCOUNT_ALREADY_EXISTS", "ERROR_ACCOUNT_DOES_NOT_EXIST", "ERROR_ACCOUNT_LOCKED", "ERROR_ACCOUNT_UNLOCKED", "ERROR_ALREADY_SIGNED_IN_USER", "ERROR_DEVICE_SESSION_CONFLICT", "ERROR_ENDPOINT_NO_LONGER_SUPPORTED", "ERROR_INCORRECT_API_VERSION", "ERROR_INCORRECT_EMAIL_CASE", "ERROR_INCORRECT_KEY_RETRIEVAL_METHOD", "ERROR_INCORRECT_LOGIN_METHOD", "ERROR_INVALID_EMAIL", "ERROR_INVALID_AUDIENCE", "ERROR_INVALID_AUTH_TOKEN", "ERROR_INVALID_AUTH_TIMESTAMP", "ERROR_INVALID_AUTH_NONCE", "ERROR_INVALID_BODY_PARAMETERS", "ERROR_INVALID_PASSWORD", "ERROR_INVALID_VERIFICATION_CODE", "ERROR_INVALID_REFRESH_AUTH_VALUE", "ERROR_INVALID_REQUEST_SIGNATURE", "ERROR_INTERNAL_INVALID_USER", "ERROR_MISSING_BODY_PARAMETERS", "ERROR_MISSING_CONTENT_LENGTH", "ERROR_NO_TOKEN_SESSION", "ERROR_NO_SILENT_REFRESH_AUTH", "ERROR_NOT_VALID_JSON_BODY", "ERROR_OFFLINE", "ERROR_PERMISSION_DENIED", "ERROR_REQUEST_BODY_TOO_LARGE", "ERROR_SERVER_ERROR", "ERROR_SYNC_DISABLED", "ERROR_TOO_MANY_CLIENT_REQUESTS", "ERROR_SERVICE_TEMP_UNAVAILABLE", "ERROR_UI_ERROR", "ERROR_UI_REQUEST", "ERROR_PARSE", "ERROR_NETWORK", "ERROR_UNKNOWN", "ERROR_UNKNOWN_DEVICE", "ERROR_UNVERIFIED_ACCOUNT", "ERROR_UNKNOWN_CLIENT_ID", "ERROR_INCORRECT_CLIENT_SECRET", "ERROR_INCORRECT_REDIRECT_URI", "ERROR_INVALID_FXA_ASSERTION", "ERROR_UNKNOWN_CODE", "ERROR_INCORRECT_CODE", "ERROR_EXPIRED_CODE", "ERROR_OAUTH_INVALID_TOKEN", "ERROR_INVALID_REQUEST_PARAM", "ERROR_INVALID_RESPONSE_TYPE", "ERROR_UNAUTHORIZED", "ERROR_FORBIDDEN", "ERROR_INVALID_CONTENT_TYPE", "ERROR_NO_ACCOUNT", "ERROR_AUTH_ERROR", "ERROR_INVALID_PARAMETER", "ERROR_CODE_METHOD_NOT_ALLOWED", "ERROR_MSG_METHOD_NOT_ALLOWED", "FXA_PWDMGR_PLAINTEXT_FIELDS", "FXA_PWDMGR_SECURE_FIELDS", "FXA_PWDMGR_MEMORY_FIELDS", "FXA_PWDMGR_REAUTH_WHITELIST", "FXA_PWDMGR_HOST", "FXA_PWDMGR_REALM", "SERVER_ERRNO_TO_ERROR", "ERROR_TO_GENERAL_ERROR_CLASS"],
|
||||
"FxAccountsCommon.js": ["log", "logPII", "FXACCOUNTS_PERMISSION", "DATA_FORMAT_VERSION", "DEFAULT_STORAGE_FILENAME", "ASSERTION_LIFETIME", "ASSERTION_USE_PERIOD", "CERT_LIFETIME", "KEY_LIFETIME", "POLL_SESSION", "ONLOGIN_NOTIFICATION", "ONVERIFIED_NOTIFICATION", "ONLOGOUT_NOTIFICATION", "ON_FXA_UPDATE_NOTIFICATION", "ON_DEVICE_CONNECTED_NOTIFICATION", "ON_DEVICE_DISCONNECTED_NOTIFICATION", "ON_PROFILE_UPDATED_NOTIFICATION", "ON_PASSWORD_CHANGED_NOTIFICATION", "ON_PASSWORD_RESET_NOTIFICATION", "ON_VERIFY_LOGIN_NOTIFICATION", "ON_ACCOUNT_DESTROYED_NOTIFICATION", "ON_COLLECTION_CHANGED_NOTIFICATION", "FXA_PUSH_SCOPE_ACCOUNT_UPDATE", "ON_PROFILE_CHANGE_NOTIFICATION", "ON_ACCOUNT_STATE_CHANGE_NOTIFICATION", "UI_REQUEST_SIGN_IN_FLOW", "UI_REQUEST_REFRESH_AUTH", "FX_OAUTH_CLIENT_ID", "WEBCHANNEL_ID", "PREF_LAST_FXA_USER", "ERRNO_ACCOUNT_ALREADY_EXISTS", "ERRNO_ACCOUNT_DOES_NOT_EXIST", "ERRNO_INCORRECT_PASSWORD", "ERRNO_UNVERIFIED_ACCOUNT", "ERRNO_INVALID_VERIFICATION_CODE", "ERRNO_NOT_VALID_JSON_BODY", "ERRNO_INVALID_BODY_PARAMETERS", "ERRNO_MISSING_BODY_PARAMETERS", "ERRNO_INVALID_REQUEST_SIGNATURE", "ERRNO_INVALID_AUTH_TOKEN", "ERRNO_INVALID_AUTH_TIMESTAMP", "ERRNO_MISSING_CONTENT_LENGTH", "ERRNO_REQUEST_BODY_TOO_LARGE", "ERRNO_TOO_MANY_CLIENT_REQUESTS", "ERRNO_INVALID_AUTH_NONCE", "ERRNO_ENDPOINT_NO_LONGER_SUPPORTED", "ERRNO_INCORRECT_LOGIN_METHOD", "ERRNO_INCORRECT_KEY_RETRIEVAL_METHOD", "ERRNO_INCORRECT_API_VERSION", "ERRNO_INCORRECT_EMAIL_CASE", "ERRNO_ACCOUNT_LOCKED", "ERRNO_ACCOUNT_UNLOCKED", "ERRNO_UNKNOWN_DEVICE", "ERRNO_DEVICE_SESSION_CONFLICT", "ERRNO_SERVICE_TEMP_UNAVAILABLE", "ERRNO_PARSE", "ERRNO_NETWORK", "ERRNO_UNKNOWN_ERROR", "OAUTH_SERVER_ERRNO_OFFSET", "ERRNO_UNKNOWN_CLIENT_ID", "ERRNO_INCORRECT_CLIENT_SECRET", "ERRNO_INCORRECT_REDIRECT_URI", "ERRNO_INVALID_FXA_ASSERTION", "ERRNO_UNKNOWN_CODE", "ERRNO_INCORRECT_CODE", "ERRNO_EXPIRED_CODE", "ERRNO_OAUTH_INVALID_TOKEN", "ERRNO_INVALID_REQUEST_PARAM", "ERRNO_INVALID_RESPONSE_TYPE", "ERRNO_UNAUTHORIZED", "ERRNO_FORBIDDEN", "ERRNO_INVALID_CONTENT_TYPE", "ERROR_ACCOUNT_ALREADY_EXISTS", "ERROR_ACCOUNT_DOES_NOT_EXIST", "ERROR_ACCOUNT_LOCKED", "ERROR_ACCOUNT_UNLOCKED", "ERROR_ALREADY_SIGNED_IN_USER", "ERROR_DEVICE_SESSION_CONFLICT", "ERROR_ENDPOINT_NO_LONGER_SUPPORTED", "ERROR_INCORRECT_API_VERSION", "ERROR_INCORRECT_EMAIL_CASE", "ERROR_INCORRECT_KEY_RETRIEVAL_METHOD", "ERROR_INCORRECT_LOGIN_METHOD", "ERROR_INVALID_EMAIL", "ERROR_INVALID_AUDIENCE", "ERROR_INVALID_AUTH_TOKEN", "ERROR_INVALID_AUTH_TIMESTAMP", "ERROR_INVALID_AUTH_NONCE", "ERROR_INVALID_BODY_PARAMETERS", "ERROR_INVALID_PASSWORD", "ERROR_INVALID_VERIFICATION_CODE", "ERROR_INVALID_REFRESH_AUTH_VALUE", "ERROR_INVALID_REQUEST_SIGNATURE", "ERROR_INTERNAL_INVALID_USER", "ERROR_MISSING_BODY_PARAMETERS", "ERROR_MISSING_CONTENT_LENGTH", "ERROR_NO_TOKEN_SESSION", "ERROR_NO_SILENT_REFRESH_AUTH", "ERROR_NOT_VALID_JSON_BODY", "ERROR_OFFLINE", "ERROR_PERMISSION_DENIED", "ERROR_REQUEST_BODY_TOO_LARGE", "ERROR_SERVER_ERROR", "ERROR_SYNC_DISABLED", "ERROR_TOO_MANY_CLIENT_REQUESTS", "ERROR_SERVICE_TEMP_UNAVAILABLE", "ERROR_UI_ERROR", "ERROR_UI_REQUEST", "ERROR_PARSE", "ERROR_NETWORK", "ERROR_UNKNOWN", "ERROR_UNKNOWN_DEVICE", "ERROR_UNVERIFIED_ACCOUNT", "ERROR_UNKNOWN_CLIENT_ID", "ERROR_INCORRECT_CLIENT_SECRET", "ERROR_INCORRECT_REDIRECT_URI", "ERROR_INVALID_FXA_ASSERTION", "ERROR_UNKNOWN_CODE", "ERROR_INCORRECT_CODE", "ERROR_EXPIRED_CODE", "ERROR_OAUTH_INVALID_TOKEN", "ERROR_INVALID_REQUEST_PARAM", "ERROR_INVALID_RESPONSE_TYPE", "ERROR_UNAUTHORIZED", "ERROR_FORBIDDEN", "ERROR_INVALID_CONTENT_TYPE", "ERROR_NO_ACCOUNT", "ERROR_AUTH_ERROR", "ERROR_INVALID_PARAMETER", "ERROR_CODE_METHOD_NOT_ALLOWED", "ERROR_MSG_METHOD_NOT_ALLOWED", "FXA_PWDMGR_PLAINTEXT_FIELDS", "FXA_PWDMGR_SECURE_FIELDS", "FXA_PWDMGR_MEMORY_FIELDS", "FXA_PWDMGR_REAUTH_WHITELIST", "FXA_PWDMGR_HOST", "FXA_PWDMGR_REALM", "SERVER_ERRNO_TO_ERROR", "ERROR_TO_GENERAL_ERROR_CLASS"],
|
||||
"FxAccountsOAuthGrantClient.jsm": ["FxAccountsOAuthGrantClient", "FxAccountsOAuthGrantClientError"],
|
||||
"FxAccountsProfileClient.jsm": ["FxAccountsProfileClient", "FxAccountsProfileClientError"],
|
||||
"FxAccountsPush.js": ["FxAccountsPushService"],
|
||||
|
Loading…
x
Reference in New Issue
Block a user