From ff37329a6ee77b1f4cd2700003643d6d150cdf90 Mon Sep 17 00:00:00 2001
From: Zachary Carter <zack.carter@gmail.com>
Date: Thu, 19 Jul 2012 16:31:49 -0700
Subject: [PATCH] Ensure that when a user verifies in a different browser than
 what they reset their password with, they must authenticate to complete the
 verification

---
 lib/wsapi/email_for_token.js | 10 +++---
 tests/forgotten-pass-test.js | 62 ++++++++++++++++++++++++++++++++++++
 tests/lib/wsapi.js           | 11 ++++++-
 3 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/lib/wsapi/email_for_token.js b/lib/wsapi/email_for_token.js
index 3aed92174..66f9a6398 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 7e9aae487..fff015c37 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 868c86d02..cd35cb64b 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;
+};
-- 
GitLab