Skip to content

Commit

Permalink
Backed out 3 changesets (bug 1383663) for timeouts in browser_aboutAc…
Browse files Browse the repository at this point in the history
…counts.js and failures in test_web_channel.js

Backed out changeset f384a524cac6 (bug 1383663)
Backed out changeset 9d26a627e2f8 (bug 1383663)
Backed out changeset c7d46e2e8ddc (bug 1383663)

MozReview-Commit-ID: 88xbdeVJtK2
  • Loading branch information
philor committed Sep 16, 2017
1 parent 238bfde commit db689b2
Show file tree
Hide file tree
Showing 13 changed files with 348 additions and 124 deletions.
190 changes: 189 additions & 1 deletion browser/base/content/aboutaccounts/aboutaccounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Cu.import("resource://gre/modules/FxAccountsCommon.js", fxAccountsCommon);
// for master-password utilities
Cu.import("resource://services-sync/util.js");

const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";

const ACTION_URL_PARAM = "action";

const OBSERVER_TOPICS = [
Expand All @@ -27,6 +29,65 @@ function log(msg) {
// dump("FXA: " + msg + "\n");
}

function getPreviousAccountNameHash() {
try {
return Services.prefs.getStringPref(PREF_LAST_FXA_USER);
} catch (_) {
return "";
}
}

function setPreviousAccountNameHash(acctName) {
Services.prefs.setStringPref(PREF_LAST_FXA_USER, sha256(acctName));
}

function needRelinkWarning(acctName) {
let prevAcctHash = getPreviousAccountNameHash();
return prevAcctHash && prevAcctHash != sha256(acctName);
}

// Given a string, returns the SHA265 hash in base64
function 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);
}

function promptForRelink(acctName) {
let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
let continueLabel = sb.GetStringFromName("continue.label");
let title = sb.GetStringFromName("relinkVerify.title");
let description = sb.formatStringFromName("relinkVerify.description",
[acctName], 1);
let body = sb.GetStringFromName("relinkVerify.heading") +
"\n\n" + description;
let ps = Services.prompt;
let buttonFlags = (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING) +
(ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL) +
ps.BUTTON_POS_1_DEFAULT;
let pressed = Services.prompt.confirmEx(window, title, body, buttonFlags,
continueLabel, null, null, null,
{});
return pressed == 0; // 0 is the "continue" button
}

// If the last fxa account used for sync isn't this account, we display
// a modal dialog checking they really really want to do this...
// (This is sync-specific, so ideally would be in sync's identity module,
// but it's a little more seamless to do here, and sync is currently the
// only fxa consumer, so...
function shouldAllowRelink(acctName) {
return !needRelinkWarning(acctName) || promptForRelink(acctName);
}

function updateDisplayedEmail(user) {
let emailDiv = document.getElementById("email");
if (emailDiv && user) {
Expand All @@ -51,6 +112,7 @@ var wrapper = {
docShell.addProgressListener(this.iframeListener,
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT |
Ci.nsIWebProgress.NOTIFY_LOCATION);
iframe.addEventListener("load", this);

// Ideally we'd just merge urlParams with new URL(url).searchParams, but our
// URLSearchParams implementation doesn't support iteration (bug 1085284).
Expand Down Expand Up @@ -106,7 +168,133 @@ var wrapper = {
setErrorPage("networkError");
}
},
}
},

handleEvent(evt) {
switch (evt.type) {
case "load":
this.iframe.contentWindow.addEventListener("FirefoxAccountsCommand", this);
this.iframe.removeEventListener("load", this);
break;
case "FirefoxAccountsCommand":
this.handleRemoteCommand(evt);
break;
}
},

/**
* onLogin handler receives user credentials from the jelly after a
* sucessful login and stores it in the fxaccounts service
*
* @param accountData the user's account data and credentials
*/
onLogin(accountData) {
log("Received: 'login'. Data:" + JSON.stringify(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;
// sessionTokenContext is erroneously sent by the content server.
// https://github.com/mozilla/fxa-content-server/issues/2766
// To avoid having the FxA storage manager not knowing what to do with
// it we delete it here.
delete accountData.sessionTokenContext;

// We need to confirm a relink - see shouldAllowRelink for more
let newAccountEmail = accountData.email;
// The hosted code may have already checked for the relink situation
// by sending the can_link_account command. If it did, then
// it will indicate we don't need to ask twice.
if (!accountData.verifiedCanLinkAccount && !shouldAllowRelink(newAccountEmail)) {
// we need to tell the page we successfully received the message, but
// then bail without telling fxAccounts
this.injectData("message", { status: "login" });
// after a successful login we return to preferences
openPrefs();
return;
}
delete accountData.verifiedCanLinkAccount;

// Remember who it was so we can log out next time.
setPreviousAccountNameHash(newAccountEmail);

// A sync-specific hack - we want to ensure sync has been initialized
// before we set the signed-in user.
let xps = Cc["@mozilla.org/weave/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject;
xps.whenLoaded().then(() => {
updateDisplayedEmail(accountData);
return fxAccounts.setSignedInUser(accountData);
}).then(() => {
// If the user data is verified, we want it to immediately look like
// they are signed in without waiting for messages to bounce around.
if (accountData.verified) {
openPrefs();
}
this.injectData("message", { status: "login" });
// until we sort out a better UX, just leave the jelly page in place.
// If the account email is not yet verified, it will tell the user to
// go check their email, but then it will *not* change state after
// the verification completes (the browser will begin syncing, but
// won't notify the user). If the email has already been verified,
// the jelly will say "Welcome! You are successfully signed in as
// EMAIL", but it won't then say "syncing started".
}, (err) => this.injectData("message", { status: "error", error: err })
);
},

onCanLinkAccount(accountData) {
// We need to confirm a relink - see shouldAllowRelink for more
let ok = shouldAllowRelink(accountData.email);
this.injectData("message", { status: "can_link_account", data: { ok } });
},

/**
* onSignOut handler erases the current user's session from the fxaccounts service
*/
onSignOut() {
log("Received: 'sign_out'.");

fxAccounts.signOut().then(
() => this.injectData("message", { status: "sign_out" }),
(err) => this.injectData("message", { status: "error", error: err })
);
},

handleRemoteCommand(evt) {
log("command: " + evt.detail.command);
let data = evt.detail.data;

switch (evt.detail.command) {
case "login":
this.onLogin(data);
break;
case "can_link_account":
this.onCanLinkAccount(data);
break;
case "sign_out":
this.onSignOut(data);
break;
default:
log("Unexpected remote command received: " + evt.detail.command + ". Ignoring command.");
break;
}
},

injectData(type, content) {
return fxAccounts.promiseAccountsSignUpURI().then(authUrl => {
let data = {
type,
content
};
this.iframe.contentWindow.postMessage(data, authUrl);
})
.catch(e => {
console.log("Failed to inject data", e);
setErrorPage("configError");
});
},
};


Expand Down
7 changes: 7 additions & 0 deletions browser/components/preferences/in-content/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,13 @@ var gSyncPane = {
}).then(data => {
let fxaLoginStatus = document.getElementById("fxaLoginStatus");
if (data) {
if (data.email) {
// A hack to handle that the user's email address may have changed.
// This can probably be removed as part of bug 1383663.
fxaEmailAddressLabels.forEach((label) => {
label.value = data.email;
});
}
if (data.displayName) {
fxaLoginStatus.setAttribute("hasName", true);
displayNameLabel.hidden = false;
Expand Down
9 changes: 0 additions & 9 deletions services/crypto/modules/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,6 @@ 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.
*/
Expand Down
19 changes: 7 additions & 12 deletions services/fxaccounts/FxAccounts.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ var publicProperties = [
"getProfileCache",
"getSignedInUser",
"getSignedInUserProfile",
"handleAccountDestroyed",
"handleDeviceDisconnection",
"handleEmailUpdated",
"handleAccountDestroyed",
"hasLocalSession",
"invalidateCertificate",
"loadAndPoll",
Expand Down Expand Up @@ -594,7 +593,7 @@ FxAccountsInternal.prototype = {
*
* @param credentials
* The credentials object containing the fields to be updated.
* This object must contain the |uid| field and it must
* This object must contain |email| and |uid| fields and they must
* match the currently signed in user.
*/
updateUserAccountData(credentials) {
Expand All @@ -604,14 +603,15 @@ FxAccountsInternal.prototype = {
}
let currentAccountState = this.currentAccountState;
return currentAccountState.promiseInitialized.then(() => {
return currentAccountState.getUserAccountData(["uid"]);
return currentAccountState.getUserAccountData(["email", "uid"]);
}).then(existing => {
if (existing.uid != credentials.uid) {
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 uid as storage will complain if we try and
// update it (even when the value is the same)
// 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);
});
Expand Down Expand Up @@ -1607,11 +1607,6 @@ 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;
Expand Down
2 changes: 0 additions & 2 deletions services/fxaccounts/FxAccountsCommon.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ 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;
Expand Down
Loading

0 comments on commit db689b2

Please sign in to comment.