Permalink
Browse files

added examples; started work on issue #4

  • Loading branch information...
1 parent fbf0bcc commit 1626972faafc3ed5b4ac85d2c32a5f3ee835d04c @kbjr kbjr committed Nov 12, 2012
@@ -0,0 +1,29 @@
+
+var passreset = require('pass-reset');
+
+app.post('/password/reset',
+ passreset.requestResetToken({
+ callbackURL: 'http://www.example.com/password/reset/{token}'
+ });
+);
+
+app.get('/password/reset/:token', function() {
+ //
+ // Render a form here that takes the token (which should be auto-generated in the form)
+ // and a new password/confirmation, something like the following would work:
+ //
+ // <form action="/password/reset">
+ // <input type="hidden" name="token" value="{{ token }}" />
+ // <input type="password" name="password" value="" placeholder="Password" />
+ // <input type="password" name="confirm" value="" placeholder="Confirm Password" />
+ // </form>
+ //
+ // In this example the form would have to be submitted with AJAX because the reset route
+ // below takes a PUT. If you want the form to work with HTML only you can use a POST with
+ // a different route URI or some kind of method override.
+ //
+});
+
+app.put('/password/reset',
+ passreset.resetPassword()
+);
@@ -0,0 +1,62 @@
+
+var passreset = require('pass-reset');
+var handlebars = require('handlebars');
+
+//
+// Custom storage models would be initilaized here, but we
+// will just use the default memory store
+//
+
+//
+// Configure the user lookup routine
+//
+passreset.lookupUsers(function(login, callback) {
+ User.find({ username: login }, function(err, users) {
+ if (err) {return callback(err);}
+ if (! users.length) {return callback(null, false);}
+ var user = users[0];
+ callback(null, {
+ email: user.email,
+ users: [{
+ id: user.id,
+ name: user.username
+ }]
+ });
+ });
+});
+
+//
+// Configure the set password routine
+//
+passreset.setPassword(function(id, password, callback) {
+ if (password.length < 8) {
+ return callback(null, false, 'Password must be at least 8 characters');
+ }
+ var hash = doHash(password);
+ var update = { $set: { password: hash } };
+ User.update({ id: id }, update, { }, function(err) {
+ if (err) {return callback(err);}
+ callback(null, true);
+ });
+});
+
+//
+// Configure the send email routine
+//
+passReset.sendEmail(function(email, resets, callback) {
+ var template = handlebars.compile([
+ '<p>You requested a password reset for the following account(s).</p>',
+ '<ul>',
+ '{{#each resets}}',
+ '<li>{{name}}: <a href="{{url}}">{{url}}</a></li>',
+ '{{/each}}',
+ '</ul>'
+ ].join('\n'));
+ mailer.send({
+ to: email,
+ from: 'noreply@example.com',
+ subject: 'password reset',
+ body: template({ resets: resets })
+ });
+ callback(null, true);
+});
@@ -0,0 +1,58 @@
+
+var passreset = require('pass-reset');
+var mongoose = require('mongoose');
+
+function MongooseStore(host, db) {
+ this.client = mongoose.createConnection(host, db);
+ this.client.once('open', this.init.bind(this));
+}
+
+MongooseStore.prototype.init = function() {
+ // Build the schema/model for token storage
+ var schema = new mongoose.Schema({
+ key: String,
+ token: String,
+ expires: {
+ type: Date,
+ default: function() {
+ return new Date(Date.now() + passreset.expireTimeout());
+ }
+ }
+ });
+ this.PassResetToken = db.model('PassResetToken', schema);
+
+ // Check for expired tokens periodically and remove them
+ setInterval(function() {
+ var expired = {expires: {'$lte': new Date}};
+ this.PassResetToken.remove(expired).exec();
+ }.bind(this));
+};
+
+MongooseStore.prototype.create = function(id, token, callback) {
+ (new this.PassResetToken({key: id, token: token})).save(callback);
+};
+
+MongooseStore.prototype.lookup = function(token, callback) {
+ this.PassResetToken.findOne({token: token}, function(err, token) {
+ if (err) {
+ return callback(err);
+ }
+ // Not found
+ if (! token) {
+ return callback(null, false);
+ }
+ // Expired
+ if (Date.now() > token.expired) {
+ token.remove();
+ return callback(null, false);
+ }
+ // Good token found
+ callback(null, token.key);
+ });
+};
+
+MongooseStore.prototype.destroy = function(token, callback) {
+ this.PassResetToken.remove({token: token}, callback);
+};
+
+passreset.setStore(new MongooseStore('localhost', 'test'));
@@ -0,0 +1,22 @@
+
+var passreset = require('pass-reset');
+var redis = require('redis-url');
+
+function RedisStore(url) {
+ this.client = reqis.connect(url);
+}
+
+RedisStore.prototype.create = function(id, token, callback) {
+ this.client.set(token, id, callback);
+ this.client.expire(token, Math.round(passReset.expireTimeout() / 1000));
+};
+
+RedisStore.prototype.lookup = function(token, callback) {
+ this.client.get(token, callback);
+};
+
+RedisStore.prototype.destroy = function(token, callback) {
+ this.client.del(token, callback);
+};
+
+passreset.setStore(new RedisStore('redis://...'));
View
@@ -95,6 +95,7 @@ exports.sendEmail = function(func) {
exports.requestResetToken = function(opts) {
opts = merge({
next: null,
+ error: 'json',
loginParam: 'login',
callbackURL: '/password/reset/{token}'
}, opts);
@@ -144,6 +145,15 @@ exports.requestResetToken = function(opts) {
}
});
});
+
+ function error(err, status) {
+ if (opts.error === 'json') {
+ sendJson.error(err, status);
+ }
+ if (typeof opts.error === 'function') {
+ opts.error(req, res)
+ }
+ }
});
};
func._opts = opts;

0 comments on commit 1626972

Please sign in to comment.