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/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