diff --git a/lib/wsapi/email_for_token.js b/lib/wsapi/email_for_token.js index 3aed92174cf1c5b138638959cffea8a223355803..66f9a63989c9faafae23af4871e72b410be3c82e 100644 --- a/lib/wsapi/email_for_token.js +++ b/lib/wsapi/email_for_token.js @@ -42,20 +42,20 @@ exports.process = function(req, res) { function checkMustAuth() { // must the user authenticate? This is true if they are not authenticated - // as the uid who initiated the verification, and they are not on the same + // as the uid who initiated the verification, or they are not on the same // browser as the initiator var must_auth = true; - if (uid && req.session.userid === uid) { + if (uid && req.session.userid === uid && + typeof req.session.pendingReset === 'string' && + req.params.token === req.session.pendingReset) { must_auth = false; } else if (!uid && typeof req.session.pendingCreation === 'string' && req.params.token === req.session.pendingCreation) { must_auth = false; } - else if (typeof req.session.pendingReset === 'string' && - req.params.token === req.session.pendingReset) - { + else if (typeof req.session.pendingReverification === 'string') { must_auth = false; } // NOTE: for reverification, we require you're authenticated. it's not enough diff --git a/tests/forgotten-pass-test.js b/tests/forgotten-pass-test.js index 7e9aae487b38946332a3096323207edc3ad5e329..fff015c37f92b741aa4297313e331a88ac96ed19 100755 --- a/tests/forgotten-pass-test.js +++ b/tests/forgotten-pass-test.js @@ -286,6 +286,68 @@ suite.addBatch({ }, }); +// Test issue #2104: when using a second browser to initiate password reset, first +// browser should be prompted to authenticate + +// New context for a second client +var oldContext; +suite.addBatch({ + "change context": function () { + oldContext = wsapi.getContext(); + wsapi.setContext({}); + } +}); + +// Run the "forgot_email" flow with first address. +suite.addBatch({ + "reset password on first account": { + topic: wsapi.post('/wsapi/stage_reset', { + email: 'first@fakeemail.com', + pass: 'secondfakepass', + site:'https://otherfakesite.com' + }), + "works": function(err, r) { + assert.strictEqual(r.code, 200); + } + } +}); + +// wait for the token +suite.addBatch({ + "a token": { + topic: function() { + start_stop.waitForToken(this.callback); + }, + "is obtained": function (t) { + assert.strictEqual(typeof t, 'string'); + token = t; + } + } +}); + +// restore context of first client +suite.addBatch({ + "restore context": function () { + wsapi.setContext(oldContext); + } +}); + +suite.addBatch({ + "given a token, getting an email": { + topic: function() { + wsapi.get('/wsapi/email_for_token', { token: token }).call(this); + }, + "account created": function(err, r) { + assert.equal(r.code, 200); + var body = JSON.parse(r.body); + assert.strictEqual(body.success, true); + assert.strictEqual(body.email, 'first@fakeemail.com'); + assert.strictEqual(body.must_auth, true); + } + } +}); + + // test list emails suite.addBatch({ "list emails API": { diff --git a/tests/lib/wsapi.js b/tests/lib/wsapi.js index 868c86d02756fd53ed624cbe543b403355cb510e..cd35cb64be9a49c0865901ad410e1e9b434c9a32 100644 --- a/tests/lib/wsapi.js +++ b/tests/lib/wsapi.js @@ -42,4 +42,13 @@ exports.getCSRF = function() { return context.session.csrf_token; } return null; -}; \ No newline at end of file +}; + +// allows for multiple clients +exports.setContext = function (cxt) { + context = cxt; +}; + +exports.getContext = function () { + return context; +};