diff --git a/ChangeLog b/ChangeLog index cb72ff6b1ac02c05ffa8702c3f6e487392232287..aa0a2cb677c1d6f9b4c5eaa535e1084f013fcded 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,12 @@ train-2012.04.11: * developers link now points to MDN: #1397 * fix issues that were introduced while implementing the above features: #1349, #1348, #1354, #1357, #1374, #1399, #1400, #1408, #1395, #1406, #1405, #1390, #1391 * (hotfix 2012.04.12) return 400 rather than 500 for invalid params to stage_user or stage_email: #1429 + * (hotfix 2012.04.12) fix broken string, "is this your computer" was broken into two fragments: #1425 + * (hotfix 2012.04.16) fix API regression that would cause javascript error when .get() invoked without second arg: #1442 + * (hotfix 2012.04.16) update load_gen to new server apis that require an `ephemeral` argument: #1436 + * (hotfix 2012.04.17) fix broken reset password flow - button was non-responsive in dialog: #1440 + * (hotfix 2012.04.17) mitigate errors seen when adding a secondary email to an acct with only primary emails: #1445 + * (hotfix 2012.04.18) fix error where under certain conditions user could see an error immediately after authenticating: #1449 train-2012.03.28: * work towards better user messaging for when cookies are disabled: #1167, #1302 diff --git a/lib/wsapi/complete_email_addition.js b/lib/wsapi/complete_email_addition.js index 1359b49c379efab649d942f988f37f8c466c7dfa..6e7dd2a4df4ce2116142fe5603d848ae43f9cccf 100644 --- a/lib/wsapi/complete_email_addition.js +++ b/lib/wsapi/complete_email_addition.js @@ -41,27 +41,32 @@ exports.process = function(req, res) { }); } - db.gotVerificationSecret(req.body.token, req.body.pass, function(e, email, uid) { + // got verification secret's second paramter is a password. That password + // will only be used on new account creation. Because we know this is not + // a new account, we don't provide it. + db.gotVerificationSecret(req.body.token, "", function(e, email, uid) { if (e) { logger.warn("couldn't complete email verification: " + e); wsapi.databaseDown(res, e); } else { // now do we need to set the password? if (r.needs_password && req.body.pass) { + // requiring the client to wait until the bcrypt process is complete here + // exacerbates race conditions in front-end code. We'll return success early, + // here, then update the password after the fact. The worst thing that could + // happen is that password update could fail (due to extreme load), and the + // user will have to reset their password. + wsapi.authenticateSession(req.session, uid, 'password'); + res.json({ success: true }); + wsapi.bcryptPassword(req.body.pass, function(err, hash) { if (err) { logger.warn("couldn't bcrypt password during email verification: " + err); - return res.json({ success: false }); + return; } db.updatePassword(uid, hash, function(err) { if (err) { logger.warn("couldn't update password during email verification: " + err); - wsapi.databaseDown(res, err); - } else { - // XXX: what if our software 503s? User doesn't get a password set and - // cannot change it. - wsapi.authenticateSession(req.session, uid, 'password'); - res.json({ success: !err }); } }); }); diff --git a/resources/static/dialog/controllers/check_registration.js b/resources/static/dialog/controllers/check_registration.js index 7e4e90ab8e5de2856bfc2c87e518ef28cace42c1..3389f3f9e0ca7b47bb22e796e3c8135c91af9ce0 100644 --- a/resources/static/dialog/controllers/check_registration.js +++ b/resources/static/dialog/controllers/check_registration.js @@ -40,7 +40,10 @@ BrowserID.Modules.CheckRegistration = (function() { }); } else if (status === "mustAuth") { - self.close("authenticate", { email: self.email }); + user.addressInfo(self.email, function(info) { + self.close("authenticate", info); + }); + oncomplete && oncomplete(); } }, self.getErrorDialog(errors.registration, oncomplete)); diff --git a/resources/static/dialog/controllers/dialog.js b/resources/static/dialog/controllers/dialog.js index 9d5c2693bbeeacea1e703d51b0403967feff70b3..1d3e57b872a4fc526677fe7189401bfc9a688f71 100644 --- a/resources/static/dialog/controllers/dialog.js +++ b/resources/static/dialog/controllers/dialog.js @@ -86,7 +86,7 @@ BrowserID.Modules.Dialog = (function() { if (/^http/.test(url)) u = URLParse(url); else if (/^\//.test(url)) u = URLParse(origin + url); else throw "relative urls not allowed: (" + url + ")"; - return u.validate().normalize().toString(); + return encodeURI(u.validate().normalize().toString()); } var Dialog = bid.Modules.PageModule.extend({ diff --git a/resources/static/dialog/resources/state.js b/resources/static/dialog/resources/state.js index 1d8bcfdbceb2c2f6124112342c0d0ff39bda75be..126e68878274f2fe717617c23c50be583386544e 100644 --- a/resources/static/dialog/resources/state.js +++ b/resources/static/dialog/resources/state.js @@ -243,6 +243,8 @@ BrowserID.State = (function() { handleState("reset_password", function(msg, info) { // reset password says the password has been reset, now waiting for // confirmation. + info = info || {}; + self.stagedEmail = info.email; startAction(false, "doResetPassword", info); }); diff --git a/resources/static/dialog/views/is_this_your_computer.ejs b/resources/static/dialog/views/is_this_your_computer.ejs index 2ab5bd1789788cf4abb72f2860898db25bd4982c..d592e7714619c878d42a04f96b45c2c55499e40e 100644 --- a/resources/static/dialog/views/is_this_your_computer.ejs +++ b/resources/static/dialog/views/is_this_your_computer.ejs @@ -12,8 +12,7 @@ <p> <button class="this_is_not_my_computer negative" tabindex="3"><%= gettext('no') %></button> - <%= gettext('If you\'re at a public computer such as a library or internet cafe, we\'ll ask you ' + - 'for your password again in an hour.') %> + <%= gettext('If you\'re at a public computer such as a library or internet cafe, we\'ll ask you for your password again in an hour.') %> </p> </div> diff --git a/resources/static/test/cases/controllers/check_registration.js b/resources/static/test/cases/controllers/check_registration.js index 8619cfa0a11c0b392b7cf7529ffdd3d12ac5aea3..03a01bf0a23fed05da0e3de64fab2eb43843e9eb 100644 --- a/resources/static/test/cases/controllers/check_registration.js +++ b/resources/static/test/cases/controllers/check_registration.js @@ -48,10 +48,18 @@ controller.startCheck(); } - asyncTest("user validation with mustAuth result", function() { + asyncTest("user validation with mustAuth result - callback with email, type and known set to true", function() { xhr.useResult("mustAuth"); - - testVerifiedUserEvent("authenticate", "User Must Auth"); + createController("waitForUserValidation"); + register("authenticate", function(msg, info) { + // we want the email, type and known all sent back to the caller so that + // this information does not need to be queried again. + equal(info.email, "registered@testuser.com", "correct email"); + ok(info.type, "type sent with info"); + ok(info.known, "email is known"); + start(); + }); + controller.startCheck(); }); asyncTest("user validation with pending->complete result ~3 seconds", function() { diff --git a/resources/static/test/cases/resources/state.js b/resources/static/test/cases/resources/state.js index 1c32995418eb58c6e2c785a5530d5a8bd791f23b..b620cdf598dbe85f3965123ff82e95e598c1a551 100644 --- a/resources/static/test/cases/resources/state.js +++ b/resources/static/test/cases/resources/state.js @@ -218,6 +218,14 @@ equal(actions.info.doAuthenticate.email, TEST_EMAIL, "authenticate called with the correct email"); }); + test("reset_password through to validation on same browser - call doEmailConfirmed with email address", function() { + mediator.publish("reset_password", { email: TEST_EMAIL }); + mediator.publish("user_confirmed"); + + equal(actions.info.doEmailConfirmed.email, TEST_EMAIL, "doEmailConfirmed called with correct email"); + }); + + asyncTest("assertion_generated with null assertion - redirect to pick_email", function() { mediator.subscribe("pick_email", function() { ok(true, "redirect to pick_email"); diff --git a/resources/static/test/mocks/xhr.js b/resources/static/test/mocks/xhr.js index 14c08098bdb87b1653e03db4ce9e85cc62811596..17aa6c9851933562e057afbd92c26cb68fa1d4af 100644 --- a/resources/static/test/mocks/xhr.js +++ b/resources/static/test/mocks/xhr.js @@ -110,6 +110,7 @@ BrowserID.Mocks.xhr = (function() { "get /wsapi/address_info?email=unregistered%40testuser.com primary": { type: "primary", auth: "https://auth_url", prov: "https://prov_url" }, "get /wsapi/address_info?email=testuser%40testuser.com unknown_secondary": { type: "secondary", known: false }, "get /wsapi/address_info?email=testuser%40testuser.com known_secondary": { type: "secondary", known: true }, + "get /wsapi/address_info?email=registered%40testuser.com mustAuth": { type: "secondary", known: true }, "get /wsapi/address_info?email=testuser%40testuser.com primary": { type: "primary", auth: "https://auth_url", prov: "https://prov_url" }, "get /wsapi/address_info?email=testuser%40testuser.com ajaxError": undefined, "post /wsapi/add_email_with_assertion invalid": { success: false }, diff --git a/scripts/browserid.spec b/scripts/browserid.spec index 1e657bbbdc2c46358c2d12bee05773efcc44520d..d24a0871ee13bd830ca4fd6bd1c6c119859fdc28 100644 --- a/scripts/browserid.spec +++ b/scripts/browserid.spec @@ -1,7 +1,7 @@ %define _rootdir /opt/browserid Name: browserid-server -Version: 0.2012.04.25 +Version: 0.2012.04.27 Release: 1%{?dist}_%{svnrev} Summary: BrowserID server Packager: Pete Fritchman <petef@mozilla.com> diff --git a/tests/primary-then-secondary-test.js b/tests/primary-then-secondary-test.js index bfb72c4b064f3bfd937f25348442d3d07fb11abf..11104396191720812da44e195cb6b2020aea0751 100755 --- a/tests/primary-then-secondary-test.js +++ b/tests/primary-then-secondary-test.js @@ -141,6 +141,24 @@ suite.addBatch({ }); +// after a small delay, we can authenticate with our password +suite.addBatch({ + "after a small delay": { + topic: function() { setTimeout(this.callback, 1500); }, + "authenticating with our newly set password" : { + topic: wsapi.post('/wsapi/authenticate_user', { + email: TEST_EMAIL, + pass: TEST_PASS, + ephemeral: false + }), + "works": function(err, r) { + assert.strictEqual(r.code, 200); + } + } + } +}); + + // adding a second secondary will not let us set the password suite.addBatch({ "add a new email address to our account": { @@ -159,7 +177,7 @@ suite.addBatch({ this._token = t; assert.strictEqual(typeof t, 'string'); }, - "and to complete": { + "and to complete": { topic: function(t) { wsapi.get('/wsapi/email_for_token', { token: t