From e7a0b288414864f2bfc9769466c6236902619068 Mon Sep 17 00:00:00 2001
From: Lloyd Hilaiel <lloyd@hilaiel.com>
Date: Tue, 15 May 2012 16:53:45 -0600
Subject: [PATCH] partial update of loadgen for jwcrypto and wsapi changes -
 issue #1596

---
 bin/load_gen                      | 83 +++++++++++++++++--------------
 lib/load_gen/activities/signup.js |  4 +-
 lib/load_gen/common.js            | 34 +++++++------
 lib/load_gen/crypto.js            | 80 ++++++++++++++++++-----------
 4 files changed, 118 insertions(+), 83 deletions(-)

diff --git a/bin/load_gen b/bin/load_gen
index 479504930..07c1081c6 100755
--- a/bin/load_gen
+++ b/bin/load_gen
@@ -329,44 +329,53 @@ if (args.m) outputActiveUserSummary(args.m);
 
 const userdb = require("../lib/load_gen/user_db.js");
 
-if (args.u) {
-  // parse args.u
-  var start, end;
-  try {
-    var r = args.u.split('/');
-    if (r.length != 2) throw "expected format ##/##";
-    start = parseInt(r[0], 10);
-    end = parseInt(r[1], 10);
-    if (start >= end) throw "first number must be smaller than the second";
-  } catch(e) {
-    console.log("your -u argument is poorly formated: " + e.toString());
+const lg_crypto = require("../lib/load_gen/crypto.js");
+
+lg_crypto.init(function(err) {
+  if (err) {
+    process.stderr.write('error initializing crypto module: ' + err);
     process.exit(1);
   }
 
-  // now create all them users!
-  console.log("Runing with", (end - start + 1), "pre-created users (XXX@loadtest.domain)");
-  for (var i = start; i < end; i++) {
-    userdb.addNewUser(userdb.getNewUser(i + "@loadtest.domain", "THE PASSWORD"));
-  }
-  console.log("users created!  applying load...");
-  poll();
-} else {
-  console.log("To start, let's create " + NUM_INITIAL_USERS + " users via the API.  One moment please...");
-
-  var createUser = require("../lib/load_gen/activities/signup.js").startFunc;
-  var created = 0;
-  for (var i = 0; i < NUM_INITIAL_USERS; i++) {
-    createUser(configuration, function(err) {
-      if (err) {
-        console.log("failed to create initial users! tragedy!  run away!:", err);
-        process.exit(1);
-      }
-      process.stdout.write(".");
-      if (++created == NUM_INITIAL_USERS) {
-        process.stdout.write("\n\n");
-        console.log("Average active users simulated over the last 1s/5s/60s:");
-        poll();
-      }
-    });
+  if (args.u) {
+    // parse args.u
+    var start, end;
+    try {
+      var r = args.u.split('/');
+      if (r.length != 2) throw "expected format ##/##";
+      start = parseInt(r[0], 10);
+      end = parseInt(r[1], 10);
+      if (start >= end) throw "first number must be smaller than the second";
+    } catch(e) {
+      console.log("your -u argument is poorly formated: " + e.toString());
+      process.exit(1);
+    }
+
+    // now create all them users!
+    console.log("Runing with", (end - start + 1), "pre-created users (XXX@loadtest.domain)");
+    for (var i = start; i < end; i++) {
+      userdb.addNewUser(userdb.getNewUser(i + "@loadtest.domain", "THE PASSWORD"));
+    }
+    console.log("users created!  applying load...");
+    poll();
+  } else {
+    console.log("To start, let's create " + NUM_INITIAL_USERS + " users via the API.  One moment please...");
+
+    var createUser = require("../lib/load_gen/activities/signup.js").startFunc;
+    var created = 0;
+    for (var i = 0; i < NUM_INITIAL_USERS; i++) {
+      createUser(configuration, function(err) {
+        if (err) {
+          console.log("failed to create initial users! tragedy!  run away!:", err);
+          process.exit(1);
+        }
+        process.stdout.write(".");
+        if (++created == NUM_INITIAL_USERS) {
+          process.stdout.write("\n\n");
+          console.log("Average active users simulated over the last 1s/5s/60s:");
+          poll();
+        }
+      });
+    }
   }
-}
+});
diff --git a/lib/load_gen/activities/signup.js b/lib/load_gen/activities/signup.js
index 60b4edb51..d62875666 100644
--- a/lib/load_gen/activities/signup.js
+++ b/lib/load_gen/activities/signup.js
@@ -61,7 +61,8 @@ exports.startFunc = function(cfg, cb) {
   // stage them
   wcli.post(cfg, '/wsapi/stage_user', context, {
     email: email,
-    site: userdb.any(user.sites)
+    site: userdb.any(user.sites),
+    pass: user.password
   }, function (err, r) {
     if (err) return cb(err);
     if (r.code !== 200) return cb("can't stage user, non-200 response: " + r.code);
@@ -74,7 +75,6 @@ exports.startFunc = function(cfg, cb) {
       // and simulate clickthrough
       wcli.post(cfg, '/wsapi/complete_user_creation', context, {
         token: r.body,
-        pass: user.password,
         ephemeral: false
       }, function (err, r) {
         try {
diff --git a/lib/load_gen/common.js b/lib/load_gen/common.js
index 1808e76f3..59758e21e 100644
--- a/lib/load_gen/common.js
+++ b/lib/load_gen/common.js
@@ -80,27 +80,31 @@ exports.genAssertionAndVerify = function(cfg, user, ctx, email, audience, cb) {
       return cb(e.toString() + (r ? (" - " + r.body) : ""));
     }
 
-    var assertion = crypto.getAssertion({
+    crypto.getAssertion({
       now: t,
       secretKey: ctx.keys[email].keyPair.secretKey,
       cert: ctx.keys[email].cert,
       audience: audience,
       email: email
-    });
-
-    wcli.post(cfg, '/verify', {}, {
-      audience: assertion.audience,
-      assertion: assertion.assertion
-    }, function (err, r) {
-      try {
-        if (err) throw err;
-        if (r.code !== 200) throw "non-200 status: " + resp.code;
-        if (!JSON.parse(r.body).status === 'okay') throw "verification failed with: " + r.reason;
-        cb(undefined);
-      } catch(e) {
-        return cb("can't verify: " + e.toString());
+    }, function(err, assertion) {
+      if (err) {
+        return cb("error getting assertion: " + err);
       }
+
+      wcli.post(cfg, '/verify', {}, {
+        audience: assertion.audience,
+        assertion: assertion.assertion
+      }, function (err, r) {
+        try {
+          if (err) throw err;
+          if (r.code !== 200) throw "non-200 status: " + resp.code;
+          if (!JSON.parse(r.body).status === 'okay') throw "verification failed with: " + r.reason;
+          cb(undefined);
+        } catch(e) {
+          return cb("can't verify: " + e.toString());
+        }
+      });
     });
   });
-}
+};
 
diff --git a/lib/load_gen/crypto.js b/lib/load_gen/crypto.js
index 85c00a77a..8f4e220b8 100644
--- a/lib/load_gen/crypto.js
+++ b/lib/load_gen/crypto.js
@@ -7,25 +7,36 @@
 
 const
 userDB = require('./user_db.js'),
-jwk = require('jwcrypto/jwk.js'),
-jwt = require('jwcrypto/jwt.js'),
-vep = require('jwcrypto/vep.js');
+jwcrypto = require('jwcrypto');
 
-const NUM_KEYPAIRS = 5;
+// load algorithms
+require("jwcrypto/lib/algs/rs");
+require("jwcrypto/lib/algs/ds");
 
-process.stdout.write("generating " + NUM_KEYPAIRS +
-                     " keypairs to be (re)used during load generation: ");
+const NUM_KEYPAIRS = 5;
 
 var keyPairs = [];
 
-while (keyPairs.length < NUM_KEYPAIRS)
-{
-  keyPairs.push(jwk.KeyPair.generate("DS", 256));
-  process.stdout.write(".");
-}
-
-process.stdout.write("\n");
-
+exports.init = function(cb) {
+  process.stdout.write("generating " + NUM_KEYPAIRS +
+                       " keypairs to be (re)used during load generation: ");
+  function next() {
+    if (keyPairs.length < NUM_KEYPAIRS) {
+      jwcrypto.generateKeypair(
+        {algorithm: "DS", keysize: 256},
+        function(err, kp) {
+          if (err) return cb(err);
+          keyPairs.push(kp);
+          process.stdout.write(".");
+          next();
+        });
+    } else {
+      process.stdout.write("\n");
+      cb(null);
+    }
+  }
+  next();
+};
 
 exports.getKeyPair = function() {
   return userDB.any(keyPairs);
@@ -33,7 +44,7 @@ exports.getKeyPair = function() {
 
 var assertions = [];
 
-exports.getAssertion = function(obj) {
+exports.getAssertion = function(obj, cb) {
   // we can memoize here, returning existing assertions to reduce
   // compute cost of loadgen client, to simulate more load on servers
 
@@ -41,16 +52,23 @@ exports.getAssertion = function(obj) {
   // what email or RP is associated with the assertion, just that
   // it applies load.
 
-  function genAssertion() {
+  function genAssertion(cb) {
     var expirationDate = new Date(obj.now.getTime() + (2 * 60 * 1000));
-    var tok = new jwt.JWT(null, expirationDate, obj.audience);
-    var assertion = vep.bundleCertsAndAssertion([obj.cert], tok.sign(obj.secretKey));
-
-    return {
-      audience: obj.audience,
-      assertion: assertion,
-      expirationDate: expirationDate
-    };
+    jwcrypto.assertion.sign(
+      {},
+      {
+        audience: obj.audience,
+        expiresAt: expirationDate
+      }, obj.secretKey, function(err, assertion) {
+        if (err) cb(err);
+        else {
+          cb(null, {
+            audience: obj.audience,
+            assertion: assertion,
+            expirationDate: expirationDate
+          });
+        }
+      });
   }
 
   if (assertions.length >= 30) {
@@ -58,12 +76,16 @@ exports.getAssertion = function(obj) {
     var assertion = assertions[which];
     // consider assertions which expire in the next minute stale
     if ((assertion.expirationDate - new Date()) < (60 * 1000)) {
-      assertion = assertions[which] = genAssertion();
+      assertions.splice(which, 1);
+    } else {
+      return process.nextTick(function() {
+        return cb(null, assertions[which]);
+      });
     }
-    return assertions[which];
   }
 
-  var a = genAssertion();
-  assertions.push(a);
-  return a;
+  genAssertion(function(err, a) {
+    assertions.push(a);
+    cb(err, a);
+  });
 };
-- 
GitLab