From 597dd6372d512dea7b24aad36b3bffff4e0a16de Mon Sep 17 00:00:00 2001
From: Lloyd Hilaiel <lloyd@hilaiel.com>
Date: Tue, 10 Jul 2012 13:34:15 -0700
Subject: [PATCH] collapse add email and reverification into a single wsapi and
 corresponding db call.

---
 lib/db.js                                 |  3 +--
 lib/db/json.js                            | 28 +++-----------------
 lib/db/mysql.js                           | 31 ++++-------------------
 lib/load_gen/activities/add_email.js      |  4 +--
 lib/wsapi/complete_email_confirmation.js  | 11 +++++---
 tests/db-test.js                          |  2 +-
 tests/email-throttling-test.js            |  2 +-
 tests/forgotten-pass-test.js              |  4 +--
 tests/primary-then-secondary-test.js      |  4 +--
 tests/stalled-mysql-test.js               |  4 +--
 tests/verify-in-different-browser-test.js |  8 +++---
 11 files changed, 31 insertions(+), 70 deletions(-)

diff --git a/lib/db.js b/lib/db.js
index ed0b46ad0..0dca5d2f9 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -103,9 +103,8 @@ exports.onReady = function(f) {
   'stageUser',
   'stageEmail',
   'completeCreateUser',
-  'completeAddEmail',
+  'completeConfirmEmail',
   'completePasswordReset',
-  'completeReverify',
   'removeEmail',
   'cancelAccount',
   'updatePassword',
diff --git a/lib/db/json.js b/lib/db/json.js
index 0998f8803..a1d8623e4 100644
--- a/lib/db/json.js
+++ b/lib/db/json.js
@@ -292,7 +292,9 @@ function getAndDeleteRowForSecret(secret, cb) {
   process.nextTick(function() { cb(null, o); });
 }
 
-exports.completeAddEmail = function(secret, cb) {
+// either a email re-verification, or an email addition - we treat these things
+// the same
+exports.completeConfirmEmail = function(secret, cb) {
   getAndDeleteRowForSecret(secret, function(err, o) {
     exports.emailKnown(o.email, function(err, known) {
       function addIt() {
@@ -322,30 +324,6 @@ exports.completeAddEmail = function(secret, cb) {
   });
 }
 
-exports.completeReverify = function(secret, cb) {
-  getAndDeleteRowForSecret(secret, function(err, o) {
-    exports.emailToUID(o.email, function(err, uid) {
-      if (err) return cb(err);
-
-      // if for some reason the email is associated with a different user now than when
-      // the action was initiated, error out.
-      if (uid !== o.existing_user) {
-        return cb("cannot update password, data inconsistency");
-      }
-
-      sync();
-      // flip the verification bit on all emails for the user other than the one just verified
-      var email = jsel.match(":has(.id:expr(x=?)) > .emails > .?", [ uid, o.email ], db.users);
-      if (!email.length) return cb("cannot find email");
-      email = email[0];
-      email.verified = true;
-      flush();
-
-      cb(err, o.email, uid);
-    });
-  });
-};
-
 exports.completeCreateUser = function(secret, cb) {
   getAndDeleteRowForSecret(secret, function(err, o) {
     exports.emailKnown(o.email, function(err, known) {
diff --git a/lib/db/mysql.js b/lib/db/mysql.js
index 185d1664e..4b3cc13a2 100644
--- a/lib/db/mysql.js
+++ b/lib/db/mysql.js
@@ -378,7 +378,9 @@ exports.completeCreateUser = function(secret, cb) {
   });
 };
 
-exports.completeAddEmail = function(secret, cb) {
+// either a email re-verification, or an email addition - we treat these things
+// the same
+exports.completeConfirmEmail = function(secret, cb) {
   getAndDeleteRowForSecret(secret, function(err, o) {
     if (err) return cb(err);
     
@@ -390,8 +392,8 @@ exports.completeAddEmail = function(secret, cb) {
       return cb("data inconsistency, no numeric existing user associated with staged email address");
     }
 
-    // we're adding an email address to an existing user account.  add appropriate entries into
-    // email table
+    // we're adding or reverifying an email address to an existing user account.  add appropriate
+    // entries into email table.
     if (o.passwd) {
       exports.updatePassword(o.existing_user, o.passwd, function(err) {
         if (err) return cb('could not set user\'s password');
@@ -403,29 +405,6 @@ exports.completeAddEmail = function(secret, cb) {
   });
 };
 
-exports.completeReverify = function(secret, cb) {
-  getAndDeleteRowForSecret(secret, function(err, o) {
-    if (err) return cb(err);
-    
-    if (o.new_acct) return cb("this verification link is not for an re-verification");
-
-    // ensure the expected existing_user field is populated, which it must always be when
-    // new_acct is false
-    if (typeof o.existing_user !== 'number') {
-      return cb("data inconsistency, no numeric existing user associated with staged email address");
-    }
-
-    // simply flip a bit
-    client.query(
-      'UPDATE email SET verified = TRUE WHERE user = ? AND type = ? AND address = ?',
-      [ o.existing_user, 'secondary', o.email ],
-      function(err, rez) {
-        if (!rez || rez.affectedRows !== 1) cb("couldn't update email address");
-        else cb(err, o.email, o.existing_user);
-      });
-  });
-};
-
 exports.completePasswordReset = function(secret, cb) {
   getAndDeleteRowForSecret(secret, function(err, o) {
     if (err) return cb(err);
diff --git a/lib/load_gen/activities/add_email.js b/lib/load_gen/activities/add_email.js
index a79fc564d..9e240d8f6 100644
--- a/lib/load_gen/activities/add_email.js
+++ b/lib/load_gen/activities/add_email.js
@@ -19,7 +19,7 @@ exports.startFunc = function(cfg, cb) {
   // 5. email_addition_status is invoked some number of times while the dialog polls
   // 6. landing page is loaded:
   //   6a. session_context
-  //   6b. complete_email_addition
+  //   6b. complete_email_confirmation
   // 7. email_addition_status returns 'complete'
   // 8. a key is generated and added
 
@@ -76,7 +76,7 @@ exports.startFunc = function(cfg, cb) {
         var token = r.body;
 
         // and simulate clickthrough
-        wcli.post(cfg, '/wsapi/complete_email_addition', context, {
+        wcli.post(cfg, '/wsapi/complete_email_confirmation', context, {
           token: token
         }, function (err, r) {
           try {
diff --git a/lib/wsapi/complete_email_confirmation.js b/lib/wsapi/complete_email_confirmation.js
index f903a28ad..fefdd1fc3 100644
--- a/lib/wsapi/complete_email_confirmation.js
+++ b/lib/wsapi/complete_email_confirmation.js
@@ -2,6 +2,12 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+/* This api is hit in two cases:
+ *  + the final step in adding a new email to your account
+ *  + the final step in re-verifying an email in your account after
+ *    password reset
+ */
+
 const
 db = require('../db.js'),
 logger = require('../logging.js').logger,
@@ -18,11 +24,10 @@ exports.args = ['token'];
 exports.i18n = false;
 
 exports.process = function(req, res) {
-  // in order to complete an email addition, one of the following must be true:
+  // in order to complete an email confirmation, one of the following must be true:
   //
   // 1. you must already be authenticated as the user who initiated the verification
   // 2. you must provide the password of the initiator.
-
   db.authForVerificationSecret(req.body.token, function(err, initiator_hash, initiator_uid) {
     if (err) {
       logger.info("unknown verification secret: " + err);
@@ -47,7 +52,7 @@ exports.process = function(req, res) {
     }
 
     function postAuthentication() {
-      db.completeAddEmail(req.body.token, function(e, email, uid) {
+      db.completeConfirmEmail(req.body.token, function(e, email, uid) {
         if (e) {
           logger.warn("couldn't complete email verification: " + e);
           wsapi.databaseDown(res, e);
diff --git a/tests/db-test.js b/tests/db-test.js
index 4ec5ceece..811f5cfb6 100755
--- a/tests/db-test.js
+++ b/tests/db-test.js
@@ -218,7 +218,7 @@ suite.addBatch({
         "makes it visible via isStaged": function(sekret, r) { assert.isTrue(r); },
         "lets you verify it": {
           topic: function(secret, r) {
-            db.completeAddEmail(secret, this.callback);
+            db.completeConfirmEmail(secret, this.callback);
           },
           "successfully": function(err, r) {
             assert.isNull(err);
diff --git a/tests/email-throttling-test.js b/tests/email-throttling-test.js
index 9b7e4560c..5b7611572 100755
--- a/tests/email-throttling-test.js
+++ b/tests/email-throttling-test.js
@@ -112,7 +112,7 @@ suite.addBatch({
 suite.addBatch({
   "and when we attempt to finish adding the email address": {
     topic: function() {
-      wsapi.post('/wsapi/complete_email_addition', { token: token }).call(this);
+      wsapi.post('/wsapi/complete_email_confirmation', { token: token }).call(this);
     },
     "it works swimmingly": function(err, r) {
       assert.equal(r.code, 200);
diff --git a/tests/forgotten-pass-test.js b/tests/forgotten-pass-test.js
index 958fe071a..7e9aae487 100755
--- a/tests/forgotten-pass-test.js
+++ b/tests/forgotten-pass-test.js
@@ -105,7 +105,7 @@ suite.addBatch({
 suite.addBatch({
   "create second account": {
     topic: function() {
-      wsapi.post('/wsapi/complete_email_addition', { token: token }).call(this);
+      wsapi.post('/wsapi/complete_email_confirmation', { token: token }).call(this);
     },
     "account created": function(err, r) {
       assert.equal(r.code, 200);
@@ -423,7 +423,7 @@ suite.addBatch({
 suite.addBatch({
   "complete reverify": {
     topic: function() {
-      wsapi.post('/wsapi/complete_reverify', { token: token }).call(this);
+      wsapi.post('/wsapi/complete_email_confirmation', { token: token }).call(this);
     },
     "works": function(err, r) {
       assert.equal(r.code, 200);
diff --git a/tests/primary-then-secondary-test.js b/tests/primary-then-secondary-test.js
index 2112b3e2a..1eb6aaeda 100755
--- a/tests/primary-then-secondary-test.js
+++ b/tests/primary-then-secondary-test.js
@@ -122,7 +122,7 @@ suite.addBatch({
           },
           "which then": {
             topic: function() {
-              wsapi.post('/wsapi/complete_email_addition', {
+              wsapi.post('/wsapi/complete_email_confirmation', {
                 token: this._token
               }).call(this);
             },
@@ -200,7 +200,7 @@ suite.addBatch({
           },
           "with a token": {
             topic: function() {
-              wsapi.post('/wsapi/complete_email_addition', {
+              wsapi.post('/wsapi/complete_email_confirmation', {
                 token: this._token
               }).call(this);
             },
diff --git a/tests/stalled-mysql-test.js b/tests/stalled-mysql-test.js
index 5bf27ce97..5337ad295 100755
--- a/tests/stalled-mysql-test.js
+++ b/tests/stalled-mysql-test.js
@@ -119,8 +119,8 @@ suite.addBatch({
       assert.strictEqual(r.code, 503);
     }
   },
-  "complete_email_addition": {
-    topic: wsapi.post('/wsapi/complete_email_addition', {
+  "complete_email_confirmation": {
+    topic: wsapi.post('/wsapi/complete_email_confirmation', {
       token: 'bogus'
     }),
     "fails with 503": function(err, r) {
diff --git a/tests/verify-in-different-browser-test.js b/tests/verify-in-different-browser-test.js
index b221322a8..9cd451b6c 100755
--- a/tests/verify-in-different-browser-test.js
+++ b/tests/verify-in-different-browser-test.js
@@ -100,7 +100,7 @@ suite.addBatch({
       "then clearing cookies and completing": {
         topic: function() {
           wsapi.clearCookies();
-          wsapi.post('/wsapi/complete_email_addition', {
+          wsapi.post('/wsapi/complete_email_confirmation', {
             token: this._token
           }).call(this);
         },
@@ -109,7 +109,7 @@ suite.addBatch({
         },
         "but succeeds": {
           topic: function() {
-            wsapi.post('/wsapi/complete_email_addition', {
+            wsapi.post('/wsapi/complete_email_confirmation', {
               token: this._token,
               pass: TEST_PASS
             }).call(this);
@@ -171,7 +171,7 @@ suite.addBatch({
       "then clearing cookies and completing": {
         topic: function() {
           wsapi.clearCookies();
-          wsapi.post('/wsapi/complete_email_addition', {
+          wsapi.post('/wsapi/complete_email_confirmation', {
             token: this._token
           }).call(this);
         },
@@ -180,7 +180,7 @@ suite.addBatch({
         },
         "but succeeds": {
           topic: function() {
-            wsapi.post('/wsapi/complete_email_addition', {
+            wsapi.post('/wsapi/complete_email_confirmation', {
               token: this._token,
               pass: TEST_PASS
             }).call(this);
-- 
GitLab