mirror of
https://github.com/sudoxnym/habitica-self-host.git
synced 2026-07-13 17:52:22 +00:00
[#1446] add password-reset (still need change password for this to be useful)
This commit is contained in:
parent
883d63aaaf
commit
c12de954a4
6 changed files with 97 additions and 7 deletions
|
|
@ -82,5 +82,15 @@ habitrpg.controller("AuthCtrl", ['$scope', '$rootScope', 'User', '$http', '$loca
|
|||
$('#login-modal').modal('show');
|
||||
}
|
||||
}
|
||||
|
||||
$scope.passwordReset = function(email){
|
||||
$http.post(API_URL + '/api/v1/user/reset-password', {email:email})
|
||||
.success(function(){
|
||||
alert('New password sent.');
|
||||
})
|
||||
.error(function(data){
|
||||
alert(data.err);
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@
|
|||
"nib": "~1.0.1",
|
||||
"jade": "~0.35.0",
|
||||
"passport": "~0.1.17",
|
||||
"validator": "~1.5.1"
|
||||
"validator": "~1.5.1",
|
||||
"nodemailer": "~0.5.2"
|
||||
},
|
||||
"private": true,
|
||||
"subdomain": "habitrpg",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ var sanitize = validator.sanitize;
|
|||
var passport = require('passport');
|
||||
var helpers = require('habitrpg-shared/script/helpers');
|
||||
var async = require('async');
|
||||
var derbyAuthUtil = require('derby-auth/utils');
|
||||
var utils = require('../utils');
|
||||
var nconf = require('nconf');
|
||||
var User = require('../models/user').model;
|
||||
|
||||
var api = module.exports;
|
||||
|
|
@ -73,7 +74,7 @@ api.registerUser = function(req, res, next) {
|
|||
return cb("Username already taken");
|
||||
}
|
||||
newUser = helpers.newUser(true);
|
||||
salt = derbyAuthUtil.makeSalt();
|
||||
salt = utils.makeSalt();
|
||||
newUser.auth = {
|
||||
local: {
|
||||
username: username,
|
||||
|
|
@ -82,7 +83,7 @@ api.registerUser = function(req, res, next) {
|
|||
},
|
||||
timestamps: {created: +new Date(), loggedIn: +new Date()}
|
||||
};
|
||||
newUser.auth.local.hashed_password = derbyAuthUtil.encryptPassword(password, salt);
|
||||
newUser.auth.local.hashed_password = utils.encryptPassword(password, salt);
|
||||
user = new User(newUser);
|
||||
user.save(cb);
|
||||
}
|
||||
|
|
@ -111,7 +112,7 @@ api.loginLocal = function(req, res, next) {
|
|||
// We needed the whole user object first so we can get his salt to encrypt password comparison
|
||||
User.findOne({
|
||||
'auth.local.username': username,
|
||||
'auth.local.hashed_password': derbyAuthUtil.encryptPassword(password, user.auth.local.salt)
|
||||
'auth.local.hashed_password': utils.encryptPassword(password, user.auth.local.salt)
|
||||
}, cb);
|
||||
}
|
||||
], function(err, user) {
|
||||
|
|
@ -160,6 +161,29 @@ api.loginFacebook = function(req, res, next) {
|
|||
});
|
||||
};
|
||||
|
||||
api.resetPassword = function(req, res, next){
|
||||
var email = req.body.email,
|
||||
salt = utils.makeSalt(),
|
||||
newPassword = utils.makeSalt(), // use a salt as the new password too (they'll change it later)
|
||||
hashed_password = utils.encryptPassword(newPassword, salt);
|
||||
|
||||
User.findOne({'auth.local.email':email}, function(err, user){
|
||||
if (err) return res.json(500,{err:err});
|
||||
if (!user) return res.send(500, {err:"Couldn't find a user registered for email " + email});
|
||||
user.auth.local.salt = salt;
|
||||
user.auth.local.hashed_password = hashed_password;
|
||||
utils.sendEmail({
|
||||
from: "HabitRPG <admin@habitrpg.com>",
|
||||
to: email,
|
||||
subject: "Password Reset for HabitRPG",
|
||||
text: "Password for " + user.auth.local.username + " has been reset to " + newPassword + ". Log in at " + nconf.get('BASE_URL'),
|
||||
html: "Password for <strong>" + user.auth.local.username + "</strong> has been reset to <strong>" + newPassword + "</strong>. Log in at" + nconf.get('BASE_URL')
|
||||
});
|
||||
user.save();
|
||||
return res.send('New password sent to '+ email);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Registers a new user. Only accepting username/password registrations, no Facebook
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ auth.setupPassport(router); //FIXME make this consistent with the others
|
|||
router.post('/api/v1/register', auth.registerUser);
|
||||
router.post('/api/v1/user/auth/local', auth.loginLocal);
|
||||
router.post('/api/v1/user/auth/facebook', auth.loginFacebook);
|
||||
router.post('/api/v1/user/reset-password', auth.resetPassword);
|
||||
|
||||
module.exports = router;
|
||||
34
src/utils.js
Normal file
34
src/utils.js
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
var nodemailer = require('nodemailer');
|
||||
var nconf = require('nconf');
|
||||
var crypto = require('crypto');
|
||||
|
||||
module.exports.sendEmail = function(mailData) {
|
||||
var smtpTransport = nodemailer.createTransport("SMTP",{
|
||||
service: nconf.get('SMTP_SERVICE'),
|
||||
auth: {
|
||||
user: nconf.get('SMTP_USER'),
|
||||
pass: nconf.get('SMTP_PASS')
|
||||
}
|
||||
});
|
||||
smtpTransport.sendMail(mailData, function(error, response){
|
||||
if(error){
|
||||
console.log(error);
|
||||
}else{
|
||||
console.log("Message sent: " + response.message);
|
||||
}
|
||||
smtpTransport.close(); // shut down the connection pool, no more messages
|
||||
});
|
||||
}
|
||||
|
||||
// Encryption using http://dailyjs.com/2010/12/06/node-tutorial-5/
|
||||
// Note: would use [password-hash](https://github.com/davidwood/node-password-hash), but we need to run
|
||||
// model.query().equals(), so it's a PITA to work in their verify() function
|
||||
|
||||
module.exports.encryptPassword = function(password, salt) {
|
||||
return crypto.createHmac('sha1', salt).update(password).digest('hex');
|
||||
}
|
||||
|
||||
module.exports.makeSalt = function() {
|
||||
var len = 10;
|
||||
return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').substring(0, len);
|
||||
}
|
||||
|
|
@ -41,14 +41,34 @@ block content
|
|||
input(type='text', ng-model='loginUsername', placeholder='{{useUUID ? "UUID" : "Username"}}')
|
||||
.control-group
|
||||
input(type='{{useUUID ? "text" : "password"}}', ng-model='loginPassword', placeholder='{{useUUID ? "API Token" : "Password"}}')
|
||||
.control-group
|
||||
//-.control-group
|
||||
label.checkbox
|
||||
input(type='checkbox', ng-click='useUUID = !useUUID')
|
||||
| Use UUID / API Token (For Facebook Users)
|
||||
.control-group
|
||||
input.btn.btn-primary(type='submit', value='Login')
|
||||
|
||||
.tab-pane#register-tab
|
||||
// good god accordions have html ceremony
|
||||
#forgot-password-accordion.accordion
|
||||
.accordion-group
|
||||
.accordion-heading
|
||||
a.accordion-toggle(data-toggle='collapse', data-parent='#forgot-password-accordion', href='#forgot-password-group')
|
||||
| Forgot Password
|
||||
#forgot-password-group.accordion-body.collapse
|
||||
.accordion-inner
|
||||
form#derby-auth-password-reset(ng-submit='passwordReset(passwordResetEmail)')
|
||||
h3 Email New Password
|
||||
//.alert.alert-success {.success.passwordReset}
|
||||
//.control-group.{#if..errors.passwordReset}error{/}
|
||||
.control-group
|
||||
input(type='text', name='email', placeholder='Email', ng-model='passwordResetEmail')
|
||||
//span.help-inline {.errors.passwordReset}
|
||||
input.btn(type='submit', value='Submit')
|
||||
|
||||
|
||||
|
||||
|
||||
.tab-pane#register-tab
|
||||
form(ng-submit='register()', name='registrationForm')
|
||||
.control-group
|
||||
input(type='text', ng-model='registerVals.username', placeholder='Username', required)
|
||||
|
|
|
|||
Loading…
Reference in a new issue