From f937b1ef696721eb3ceef778322cbc30fd1642dd Mon Sep 17 00:00:00 2001
From: Lloyd Hilaiel <lloyd@hilaiel.com>
Date: Tue, 1 Nov 2011 18:38:14 -0600
Subject: [PATCH] break 'checkParams' feature out into a separate file so it
 can be shared by multiple processes - issue #460

---
 lib/browserid/wsapi.js | 42 ++++++------------------
 lib/validate.js        | 72 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+), 32 deletions(-)
 create mode 100644 lib/validate.js

diff --git a/lib/browserid/wsapi.js b/lib/browserid/wsapi.js
index c46c514b1..410c8e285 100644
--- a/lib/browserid/wsapi.js
+++ b/lib/browserid/wsapi.js
@@ -47,30 +47,8 @@ bcrypt = require('bcrypt'),
 crypto = require('crypto'),
 logger = require('logging.js').logger,
 ca = require('./ca.js'),
-config = require('configuration.js');
-
-function checkParams(params) {
-  return function(req, resp, next) {
-    var params_in_request=null;
-    if (req.method === "POST") {
-      params_in_request = req.body;
-    } else {
-      params_in_request = req.query;
-    }
-
-    try {
-      params.forEach(function(k) {
-        if (!params_in_request.hasOwnProperty(k) || typeof params_in_request[k] !== 'string') {
-          throw k;
-        }
-      });
-    } catch(e) {
-      logger.error(e.toString());
-      return httputils.badRequest(resp, "missing '" + e + "' argument");
-    }
-    next();
-  };
-}
+config = require('configuration.js'),
+validate = require('validate');
 
 // log a user out, clearing everything from their session except the csrf token
 function clearAuthenticatedUser(session) {
@@ -172,7 +150,7 @@ function setup(app) {
    * user via their claimed email address.  Upon timeout expiry OR clickthrough
    * the staged user account transitions to a valid user account
    */
-  app.post('/wsapi/stage_user', checkParams([ "email", "site" ]), function(req, resp) {
+  app.post('/wsapi/stage_user', validate([ "email", "site" ]), function(req, resp) {
     // staging a user logs you out.
     clearAuthenticatedUser(req.session);
 
@@ -259,7 +237,7 @@ function setup(app) {
     });
   };
 
-  app.post('/wsapi/complete_user_creation', checkParams(["token", "pass"]), function(req, resp) {
+  app.post('/wsapi/complete_user_creation', validate(["token", "pass"]), function(req, resp) {
     // issue #155, valid password length is between 8 and 80 chars.
     if (req.body.pass.length < 8 || req.body.pass.length > 80) {
       httputils.badRequest(resp, "valid passwords are between 8 and 80 chars");
@@ -299,7 +277,7 @@ function setup(app) {
     });
   });
 
-  app.post('/wsapi/stage_email', checkAuthed, checkParams(["email", "site"]), function (req, resp) {
+  app.post('/wsapi/stage_email', checkAuthed, validate(["email", "site"]), function (req, resp) {
     db.lastStaged(req.body.email, function (last) {
       if (last && (new Date() - last) < config.get('min_time_between_emails_ms')) {
         logger.warn('throttling request to stage email address ' + req.body.email + ', only ' +
@@ -326,7 +304,7 @@ function setup(app) {
     });
   });
 
-  app.get('/wsapi/email_for_token', checkParams(["token"]), function(req,resp) {
+  app.get('/wsapi/email_for_token', validate(["token"]), function(req,resp) {
     db.emailForVerificationSecret(req.query.token, function(email) {
       resp.json({ email: email });
     });
@@ -372,7 +350,7 @@ function setup(app) {
       });
   });
 
-  app.post('/wsapi/complete_email_addition', checkParams(["token"]), function(req, resp) {
+  app.post('/wsapi/complete_email_addition', validate(["token"]), function(req, resp) {
     db.gotVerificationSecret(req.body.token, undefined, function(e) {
       if (e) {
         logger.warn("couldn't complete email verification: " + e);
@@ -383,7 +361,7 @@ function setup(app) {
     });
   });
 
-  app.post('/wsapi/authenticate_user', checkParams(["email", "pass"]), function(req, resp) {
+  app.post('/wsapi/authenticate_user', validate(["email", "pass"]), function(req, resp) {
     db.checkAuth(req.body.email, function(hash) {
       if (typeof hash !== 'string' ||
           typeof req.body.pass !== 'string')
@@ -418,7 +396,7 @@ function setup(app) {
     });
   });
 
-  app.post('/wsapi/remove_email', checkAuthed, checkParams(["email"]), function(req, resp) {
+  app.post('/wsapi/remove_email', checkAuthed, validate(["email"]), function(req, resp) {
     var email = req.body.email;
 
     db.removeEmail(req.session.authenticatedUser, email, function(error) {
@@ -440,7 +418,7 @@ function setup(app) {
       }});
   });
 
-  app.post('/wsapi/cert_key', checkAuthed, checkParams(["email", "pubkey"]), function(req, resp) {
+  app.post('/wsapi/cert_key', checkAuthed, validate(["email", "pubkey"]), function(req, resp) {
     db.emailsBelongToSameAccount(req.session.authenticatedUser, req.body.email, function(sameAccount) {
       // not same account? big fat error
       if (!sameAccount) return httputils.badRequest(resp, "that email does not belong to you");
diff --git a/lib/validate.js b/lib/validate.js
new file mode 100644
index 000000000..281b57691
--- /dev/null
+++ b/lib/validate.js
@@ -0,0 +1,72 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla BrowserID.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Lloyd Hilaiel <lloyd@hilaiel.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// a teensy tinsy module to do parameter validation.  A good candiate for future
+// librification.
+//
+// usage:
+//
+//   const validate = require('validate.js');
+//
+//   app.post('/wsapi/foo', validate([ "email", "site" ]), function(req, resp) {
+//   });
+
+const
+logger = require('./logging.js').logger,
+httputils = require('httputils.js');
+
+module.exports = function (params) {
+  return function(req, resp, next) {
+    var params_in_request=null;
+    if (req.method === "POST") {
+      params_in_request = req.body;
+    } else {
+      params_in_request = req.query;
+    }
+
+    try {
+      params.forEach(function(k) {
+        if (!params_in_request.hasOwnProperty(k) || typeof params_in_request[k] !== 'string') {
+          throw k;
+        }
+      });
+    } catch(e) {
+      logger.error(e.toString());
+      return httputils.badRequest(resp, "missing '" + e + "' argument");
+    }
+    next();
+  };
+};
-- 
GitLab