diff --git a/bin/load_gen b/bin/load_gen index 3250fa4b347dd5b03f0dd4e0495489b0109ca17c..f7584e5b98c3d2cf344eec3732eb632c15606bb5 100755 --- a/bin/load_gen +++ b/bin/load_gen @@ -102,12 +102,10 @@ var activity = { // new user signup probability: (1.0 / (40 * 28 * .2)) }, -/* "reset_pass": { // users forget their password once every 4 weeks probability: (1.0 / (40 * 28.0)) }, -*/ "add_email": { // users add a new email address once every 2 weeks probability: (1.0 / (40 * 14.0)) @@ -128,6 +126,10 @@ var activity = { // inclusion. The strict probability is 100% - sum of above // probabilities. We round to 31 / 40. probability: (31 / 40.0) + }, + "change_pass": { + // users change their passwords once every two months + probability: (1.0 / (40 * 56)) } }; diff --git a/lib/load_gen/activities/change_pass.js b/lib/load_gen/activities/change_pass.js new file mode 100644 index 0000000000000000000000000000000000000000..bc0f402387ca2789ddcd9e0fee5e6460bfd0f21c --- /dev/null +++ b/lib/load_gen/activities/change_pass.js @@ -0,0 +1,87 @@ +/* ***** 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 ***** */ + +/* this file is the "signin" activity, which simulates the process of a user + * with an existing browserid account and existing authentication material + * signin into a site. */ + +const +wcli = require("../../wsapi_client.js"), +userdb = require("../user_db.js"), +winston = require('winston'), +crypto = require('../crypto'), +common = require('../common'); + +exports.startFunc = function(cfg, cb) { + var user = userdb.getExistingUser(); + + if (!user) { + winston.warn("can't achieve desired concurrency! not enough users!"); + return cb("not enough users"); + } + + // unlock the user when we're done with them + cb = (function() { + var _cb = cb; + return function(x) { + userdb.releaseUser(user); + _cb(x); + }; + })(); + + // pick one of the user's emails that we'll use + var email = userdb.any(user.emails); + + // pick one of the user's devices that we'll use + var context = userdb.any(user.ctxs); + + var origin = userdb.any(user.sites); + + // establish session context and authenticate if needed + common.auth(cfg, user, context, email, function(err) { + if (err) return cb(err); + wcli.post(cfg, '/wsapi/update_password', context, { + oldpass: user.password, + newpass: user.password + }, function (r) { + try { + cb(JSON.parse(r.body).success === true ? undefined : "password update failed"); + } catch(e) { + cb("password update failed: " + e.toString()); + } + }); + }); +}; diff --git a/lib/load_gen/activities/reset_pass.js b/lib/load_gen/activities/reset_pass.js index 8bb6ca856c4457d18255fcc99d8feea7f606611c..4f4d02a5869a1c14431fddafe8287aa6265cfda4 100644 --- a/lib/load_gen/activities/reset_pass.js +++ b/lib/load_gen/activities/reset_pass.js @@ -37,11 +37,72 @@ /* this file is the "reset_pass" activity, which simulates the process of a * user resetting their password. */ +const +wcli = require("../../wsapi_client.js"), +userdb = require("../user_db.js"), +winston = require('winston'), +common = require('../common'); + exports.startFunc = function(cfg, cb) { - // At present, this process is exactly the same as signup, with the difference - // being that the email used is one that has already been verified. we can - // reuse code here for now. - // XXX: write me - setTimeout(function() { cb(true); }, 10); + var user = userdb.getExistingUser(); + + if (!user) { + winston.warn("can't achieve desired concurrency! not enough users!"); + return cb("not enough users"); + } + + // unlock the user when we're done with them + cb = (function() { + var _cb = cb; + return function(x) { + userdb.releaseUser(user); + _cb(x); + }; + })(); + + // to "reset" a password, we'll break a single email of of the selected existing user + // into a new user. + user = userdb.splitUser(user); + + // now everything is identical to the signup flow + // pick a device context at random + var context = userdb.any(user.ctxs); + + // pick an email address to operate on (there should really be + // only one at this point + var email = userdb.any(user.emails); + + var origin = userdb.any(user.sites); + + // stage them + wcli.post(cfg, '/wsapi/stage_user', context, { + email: email, + site: userdb.any(user.sites) + }, function (r) { + if (r.code !== 200) return cb(false); + // now get the verification secret + wcli.get(cfg, '/wsapi/fake_verification', context, { + email: email + }, function (r) { + if (r.code !== 200) return cb(false); + // and simulate clickthrough + wcli.post(cfg, '/wsapi/complete_user_creation', context, { + token: r.body, + pass: user.password + }, function (r) { + r.body = JSON.parse(r.body); + if (r.code !== 200 || r.body.success !== true) { + return cb("failed to complete user creation"); + } + // and now let's log in with this email address + common.authAndKey(cfg, user, context, email, function(err) { + if (err) return cb(err); + common.genAssertionAndVerify(cfg, user, context, email, origin, function(err) { + cb(err); + }); + }); + }); + }); + }); }; diff --git a/lib/load_gen/activities/signup.js b/lib/load_gen/activities/signup.js index 56e9adda7e2ad7dfa9e00fc54127adefe09a7422..cd62201a22edef67b4f3d05ff14e669465b915e9 100644 --- a/lib/load_gen/activities/signup.js +++ b/lib/load_gen/activities/signup.js @@ -88,6 +88,8 @@ exports.startFunc = function(cfg, cb) { // only one at this point var email = userdb.any(user.emails); + var origin = userdb.any(user.sites); + // stage them wcli.post(cfg, '/wsapi/stage_user', context, { email: email, @@ -108,10 +110,12 @@ exports.startFunc = function(cfg, cb) { if (r.code !== 200 || r.body.success !== true) { return cb("failed to complete user creation"); } - // and now let's prepare this idenity in this context (get a keypair - // and certify it) + // and now let's log in with this email address common.authAndKey(cfg, user, context, email, function(err) { - cb(err); + if (err) return cb(err); + common.genAssertionAndVerify(cfg, user, context, email, origin, function(err) { + cb(err); + }); }); }); }); diff --git a/lib/load_gen/user_db.js b/lib/load_gen/user_db.js index 799e8a2435419e12ba4ceef7d8f45b853a6a9a90..46062907b32fab68e67cc6410a355914eedbf4d1 100644 --- a/lib/load_gen/user_db.js +++ b/lib/load_gen/user_db.js @@ -35,8 +35,7 @@ * ***** END LICENSE BLOCK ***** */ /* the "user database". a little in-memory collection of users for the - * purposes of performance testing. - */ + * purposes of performance testing. */ const secrets = require('../secrets.js'), @@ -112,6 +111,18 @@ exports.getExistingUser = function() { } }; +exports.splitUser = function(user) { + if (!user.locked) throw "you can't split a user that's not in use!"; + if (user.emails.length == 1) { + return user; + } else { + var newuser = exports.getNewUser(); + newuser.emails[0] = user.emails.shift(); + exports.releaseUser(user); + return newuser; + } +}; + exports.releaseUser = function(user) { if (!user.locked) throw "you can't release a user that's not in use!"; delete user.locked;