Added password reset

This commit is contained in:
Ben Hardill
2017-03-23 14:07:42 +00:00
parent 2ed3d82602
commit 25058f087d
10 changed files with 278 additions and 1 deletions

View File

@@ -117,6 +117,8 @@ var Account = require('./models/account');
var oauthModels = require('./models/oauth');
var Devices = require('./models/devices');
var Topics = require('./models/topics');
var LostPassword = require('./models/lostPassword');
Account.findOne({username: mqtt_user}, function(error, account){
if (!error && !account) {
@@ -331,6 +333,84 @@ app.post('/newuser', function(req,res){
});
app.get('/changePassword/:key',function(req, res, next){
var uuid = req.params.key;
LostPassword.findOne({uuid: uuid}).populate('user').exec(function(error, lostPassword){
if (!error && lostPassword) {
req.login(lostPassword.user, function(err){
if (!err){
lostPassword.remove();
res.redirect('/changePassword');
} else {
console.log(err);
res.redirect('/');
}
})
} else {
res.redirect('/');
}
});
});
app.get('/changePassword', ensureAuthenticated, function(req, res, next){
res.render('pages/changePassword', {user: req.user});
});
app.post('/changePassword', ensureAuthenticated, function(req, res, next){
Account.findOne({username: req.user.username}, function (err, user){
if (!err && user) {
user.setPassword(req.body.password, function(e,u){
// var s = Buffer.from(account.salt, 'hex').toString('base64');
// var h = Buffer.from(account.hash, 'hex').toString(('base64'));
var mqttPass = "PBKDF2$sha256$901$" + user.salt + "$" + user.hash;
u.mqttPass = mqttPass;
u.save(function(error){
if (!error) {
console.log("Chagned %s's password", u.username);
res.status(200).send();
} else {
console.log(error);
res.status(400).send("Problem setting new password");
}
});
});
} else {
console.log(err);
res.status(400).send("Problem setting new password");
}
});
});
app.get('/lostPassword', function(req, res, next){
res.render('pages/lostPassword', { user: req.user});
});
var sendemail = require('./sendemail');
var mailer = new sendemail();
app.post('/lostPassword', function(req, res, next){
var email = req.body.email;
Account.findOne({email: email}, function(error, user){
if (!error){
if (user){
var lostPassword = new LostPassword({user: user});
console.log(lostPassword);
lostPassword.save(function(err){
if (!err) {
res.status(200).send();
}
console.log(lostPassword.uuid);
console.log(lostPassword.user.username);
var body = mailer.buildLostPasswordBody(lostPassword.uuid, lostPassword.user.username);
mailer.send(email, 'alexa-node-red@hardill.me.uk', 'Password Reset for Alexa Node-RED', body.text, body.html);
});
} else {
res.status(404).send("No user found with that email address");
}
}
});
});
app.get('/auth/start',oauthServer.authorize(function(applicationID, redirectURI,done){
oauthModels.Application.findOne({ oauth_id: applicationID }, function(error, application) {
if (application) {

15
models/lostPassword.js Normal file
View File

@@ -0,0 +1,15 @@
var uid = require('uid2');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var LostPassword = new Schema({
uuid: { type: String, unique: true, required: true, default: function() {
return uid(42);
}},
user: { type: Schema.Types.ObjectId, ref: 'Account' },
createdDate: { type: Date, expires: 86400 , default: function(){
return new Date();
}}
});
module.exports = mongoose.model('LostPassword', LostPassword);

View File

@@ -1,6 +1,6 @@
{
"name": "home-skill-web",
"version": "0.0.1",
"version": "0.0.2",
"description": "",
"main": "index.js",
"scripts": {
@@ -25,6 +25,7 @@
"mongoose-sequence": "^3.1.0",
"morgan": "^1.7.0",
"mqtt": "^2.0.1",
"nodemailer": "^1.11.0",
"oauth2orize": "^1.5.1",
"passport": "^0.3.2",
"passport-http": "^0.3.0",

59
sendemail.js Normal file
View File

@@ -0,0 +1,59 @@
var fs = require("fs");
var ejs = require('ejs');
var path = require('path');
var nodemailer = require('nodemailer');
var smtpOptions = {
host: process.env.MAIL_SERVER,
port: 587,
secure: false,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD
}
}
var lostPasswordTxtTemplate;
var lostPasswordHTMLTemplate;
fs.readFile(
path.join(__dirname, 'views', 'email', 'resetPasswordText.ejs'),
"utf-8",
function(err, file){
lostPasswordTxtTemplate = file;
});
fs.readFile(
path.join(__dirname, 'views', 'email', 'resetPasswordHTML.ejs'),
"utf-8",
function(err, file){
lostPasswordHTMLTemplate = file;
});
var transporter = nodemailer.createTransport(smtpOptions);
var Mailer = function() {
};
Mailer.prototype.send = function send(to, from, subject, text, html){
var message = {
to: to,
from: from,
subject: subject,
text: text,
html: html
};
transporter.sendMail(message);
}
Mailer.prototype.buildLostPasswordBody = function buildLostBody(uuid, userid){
var body = ejs.render(lostPasswordTxtTemplate, {uuid: uuid, username: userid});
var htmlBody = ejs.render(lostPasswordHTMLTemplate, {uuid: uuid, username: userid});
return {text: body, html: htmlBody };
}
module.exports = Mailer;

View File

@@ -0,0 +1,16 @@
<html>
<head></head>
<body>
<p>Hello</p>
<p>A request was recently made to reset the password for your Node-RED Alexa Home Skill account.</p>
<p>Your username is <%= username %>.<p>
<p>Follow this link to reset your password</p>
<a href="https://alexa-node-red.bm.hardill.me.uk/changePassword/<%= uuid %>">https://alexa-node-red.bm.hardill.me.uk/changePassword/<%= uuid %></a>
<p>This link will only be valid for the next 24hrs and will only work once.</p>
</body>
</html>

View File

@@ -0,0 +1,11 @@
Hello
A request was recently made to reset the password for your Node-RED Alexa Home Skill account.
Your username is <%= username %>.
Follow this link to reset your password
https://alexa-node-red.bm.hardill.me.uk/changePassword/<%= uuid %>
This link will only be valid for the next 24hrs and will only work once.

View File

@@ -0,0 +1,49 @@
<% include ../fragments/header.ejs %>
<div class="container main-content">
<div id="changePassword">
<h3>Enter New Password</h3>
<label style="width: 75px" for="password">Password:</label>
<input type="password" id="password"/>
<br>
<label style="width: 75px" for="password">Password:</label>
<input type="password" id="passwordAgain"/>
<br>
<button id="registerButton">Submit</button>
<script type="application/javascript">
var xhr = new XMLHttpRequest();
var button = document.getElementById('registerButton');
button.onclick = function(){
var password = document.getElementById('password').value;
var passwordAgain = document.getElementById('passwordAgain').value;
if (password !== passwordAgain) {
alert("Passwords don't match");
return;
}
if (password.length < 1) {
alert("Zero length passwords are note really a good idea");
return;
}
var params = "password=" + encodeURIComponent(password);
xhr.open('POST', '/changePassword',true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function () {
if( xhr.readyState == 4 && xhr.status == 200) {
//new user created
window.location = '/';
} else if (xhr.readyState == 4 && xhr.status == 400) {
//show error
alert(xhr.responseText);
}
}
xhr.send(params);
}
</script>
</div>
</div>
<% include ../fragments/footer.ejs %>

View File

@@ -14,5 +14,6 @@
<input type="submit" value="Login">
</form>
</div>
<p>If you have forgetten your password click <a href="/lostPassword">here</a></p>
</div>
<% include ../fragments/footer.ejs %>

View File

@@ -0,0 +1,39 @@
<% include ../fragments/header.ejs %>
<div class="container main-content">
<div id="changePassword">
<h3>Enter email address</h3>
<label style="width: 75px" for="email">Email:</label>
<input type="email" id="email"/>
<br>
<button id="registerButton">Submit</button>
<script type="application/javascript">
var xhr = new XMLHttpRequest();
var button = document.getElementById('registerButton');
button.onclick = function(){
var email = document.getElementById('email').value;
if (email.indexOf('@') == -1) {
alert("That doesn't look like a valid email address");
return;
} else {
var params = 'email=' + encodeURIComponent(email);
xhr.open('POST', '/lostPassword',true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function () {
if( xhr.readyState == 4 && xhr.status == 200) {
//new lostpassword token created
window.location = '/';
} else if (xhr.readyState == 4 && xhr.status == 404) {
//show error
alert(xhr.responseText);
}
}
xhr.send(params);
}
}
</script>
</div>
</div>
<% include ../fragments/footer.ejs %>

View File

@@ -33,6 +33,12 @@
alert("Passwords don't match");
return;
}
if (password.length < 1) {
alert("Zero length passwords are note really a good idea");
return;
}
var email = document.getElementById('email').value;
//need to try validate the email address here:
if (email.indexOf('@') == -1) {