From 23910ac3a644e4a2cd5c47d527d1f6280de0c405 Mon Sep 17 00:00:00 2001 From: Lloyd Hilaiel <lloyd@hilaiel.com> Date: Tue, 15 May 2012 15:01:16 -0600 Subject: [PATCH] issue #1592 - update complete_user_creation to accept a password in the case that email verification was started on a previous version of code. --- lib/wsapi/complete_user_creation.js | 79 +++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/lib/wsapi/complete_user_creation.js b/lib/wsapi/complete_user_creation.js index e507e0f95..9be9daae5 100644 --- a/lib/wsapi/complete_user_creation.js +++ b/lib/wsapi/complete_user_creation.js @@ -28,6 +28,16 @@ exports.process = function(req, res) { // and then control a browserid account that they can use to prove they own // the email address of the attacked. + // TRANSITIONAL CODE COMMENT + // for issue 1000 we moved initial password selection to the browserid dialog (from + // the verification page). Rolling out this change causes some temporal pain. + // Outstannding verification links sent before the change was deployed will have + // new user requests without passwords. When the verification page is loaded for + // these links, we prompt the user for a password. That password is sent up with + // the request. this code and comment should all be purged after the new code + // has been in production for 2 weeks. + // END TRANSITIONAL CODE COMMENT + // is this the same browser? if (typeof req.session.pendingCreation === 'string' && req.body.token === req.session.pendingCreation) { @@ -36,10 +46,18 @@ exports.process = function(req, res) { // is a password provided? else if (typeof req.body.pass === 'string') { return db.authForVerificationSecret(req.body.token, function(err, hash) { + // TRANSITIONAL CODE + // if hash is null, no password was provided during verification and + // this is an old-style verification. We accept the password and will + // update it after the verification is complete. + if (err == 'no password for user' || !hash) return postAuthentication(); + // END TRANSITIONAL CODE + if (err) { logger.warn("couldn't get password for verification secret: " + err); return wsapi.databaseDown(res, err); } + bcrypt.compare(req.body.pass, hash, function (err, success) { if (err) { logger.warn("max load hit, failing on auth request with 503: " + err); @@ -65,19 +83,58 @@ exports.process = function(req, res) { if (!known) return res.json({ success: false} ); - db.gotVerificationSecret(req.body.token, function(err, email, uid) { - if (err) { - logger.warn("couldn't complete email verification: " + err); - wsapi.databaseDown(res, err); - } else { - // FIXME: not sure if we want to do this (ba) - // at this point the user has set a password associated with an email address - // that they've verified. We create an authenticated session. - wsapi.authenticateSession(req.session, uid, 'password', - config.get('ephemeral_session_duration_ms')); - res.json({ success: true }); + // TRANSITIONAL CODE + // user is authorized (1 or 2 above) OR user has no password set, in which + // case for a short time we'll accept the password provided with the verification + // link, and set it as theirs. + var transitionalPassword = null; + + db.authForVerificationSecret(req.body.token, function(err, hash) { + if (err == 'no password for user' || !hash) { + if (!req.body.pass) return httputils.authRequired(res, "password required"); + var err = wsapi.checkPassword(req.body.pass); + if (err) { + logger.warn("invalid password received: " + err); + return httputils.badRequest(res, err); + } + transitionalPassword = req.body.pass; } + completeCreation(); }); + // END TRANSITIONAL CODE + + function completeCreation() { + db.gotVerificationSecret(req.body.token, function(err, email, uid) { + if (err) { + logger.warn("couldn't complete email verification: " + err); + wsapi.databaseDown(res, err); + } else { + // FIXME: not sure if we want to do this (ba) + // at this point the user has set a password associated with an email address + // that they've verified. We create an authenticated session. + wsapi.authenticateSession(req.session, uid, 'password', + config.get('ephemeral_session_duration_ms')); + res.json({ success: true }); + + // TRANSITIONAL CODE + if (transitionalPassword) { + wsapi.bcryptPassword(transitionalPassword, function(err, hash) { + if (err) { + logger.warn("couldn't bcrypt pass for old verification link: " + err); + return; + } + + db.updatePassword(uid, hash, function(err) { + if (err) { + logger.warn("couldn't bcrypt pass for old verification link: " + err); + } + }); + }); + } + // END TRANSITIONAL CODE + } + }); + } }); } }; -- GitLab