Node.js password reset - javascript

I have been working on password reset in Node.js and Express.js
So far, my code is working for emailing to the user for changing their password. Also, user can change their password and receives an email after changing the password.
Now, the problem is, I cannot show success message after submitting the password. After pressing the submit button, it redirect to reset.ejs page.
Below is my code,
reset.ejs
<html>
<body style="margin-left:0px;">
<div class="custom-header">
<div class="custom-header-left">
</div>
<div class="custom-header-button">
</div>
<div class="custom-header-right">
<a class="navbar-brand">
<img alt="AGD" src="agdlogo.png" style="width:70%; margin-top:-22%;">
</a>
<a class="navbar-brand" href="/"> XXX </a>
<a class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
</div>
</div>
<!-- Top Bar-->
<div id="fullpage">
<div class="">
<div class="col-md-12 custom-margin-top">
<div class="panel panel-primary text-left">
<div class="panel-heading">Reset your Password</div>
<div class="panel-body">
<div class="col-md-10 ">
<form id="resetpass" role="form" class="form">
<div>
<div class="form-group">
<label for="InputEmail">New Password</label>
<input type="password" class="form-control" id="password" class="password" name="password" placeholder="Enter Email" required>
<label for="InputEmail">Confirm Password</label>
<input type="password" class="form-control" id="repass" class="repass" name="repass" placeholder="Enter Email" required>
<!-- <input type="hidden" name="token" id="token">-->
<button type="submit">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
var params = location.href;
var paramsplit = params.split('/');
//console.log(paramsplit);
$("#resetpass").submit(function (e) {
var resetData = {
password: $("#password").val(),
repass: $("#repass").val(),
token: paramsplit[4]
}
console.log(resetData);
// console.log(resetData);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: '/reset/:token',
data: JSON.stringify(resetData),
success: function (data) {
//console.log(data); // show response from the php script.
}
});
// e.preventDefault(); // avoid to execute the actual submit of the form.
});
</script>
<style CSS>
#import url("https://bootswatch.com/flatly/bootstrap.min.css");
</style>
</html>
I have a mail.controller.js file for controlling the view and model
exports.resetpassword = function(req, res) {
var data = req.body;
async.waterfall([
function(done) {
User.findOne({
resetPasswordToken: req.body.token,
resetPasswordExpires: {
$gt: Date.now()
}
}, function(err, user) {
if (!user) {
res.render('tinypage/regnotify', {
title: "Something is wrong",
alerttype: "alert-danger",
message: "Something wrong with your password change."
});
} else {
user.password = req.body.password;
user.resetPasswordToken = '';
user.resetPasswordExpires = '';
user.save(function(err, user) {
done(err, user);
});
}
});
},
function(user, done) {
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'Mailgun',
auth: {
user: 'sdfa',
pass: 'afdafsa'
}
});
var mailOptions = {
to: user.email,
from: 'agdtrack#s.com',
subject: 'Your password has been changed',
text: 'Hello,\n\n' +
'This is a confirmation that the password for your account ' + req.body.token + ' has just been changed.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
if (err) {
res.render('tinypage/regnotify', {
title: "Wrong",
alerttype: "alert-danger",
message: "Something wrong"
});
} else {
return res.render('tinypage/regnotify', {
title: "Success",
alerttype: "alert-success",
message: "Success! Your password has been changed."
});
done(err);
}
});
}
], function(err) {
res.redirect('/');
});
};
exports.renderresetpage = function(req, res) {
res.render('reset');
};
And my mail.route.js is :
app.route('/reset/:token').get(mail.renderresetpage);
app.route('/reset/:token').post(mail.resetpassword);
All are working fine. Only does not show the success message after pressing submit button.
Your contribution would be a great help.

Submitting a from will navigate to the form's action. You can add an 'onclick' to the button instead to keep you in the same page, and send the ajax request from it. So you can be able to handle the ajax success.

Related

Submitting Braintree form after getting payment nonce using hosted fields

I am trying to customize the layout of my Braintree payment form using hosted fields.
I had been using the JS v2 SDK but was having other issues: Braintree - Hosted Fields - Uncaught TypeError: FormNapper requires an HTMLFormElement element or the id string of one
I've tried changing to the v3 SDK.
Here is the stripped down version of my payment form and the braintree.js file that I am using with it:
$.ajax({
url:'web/token.php',
type:'get',
dataType:'json',
success:function(token){
var payment_form = document.querySelector('#payment_form');
var submit_button = document.querySelector('#payment_button');
braintree.client.create({
authorization: token
}, function(err, clientInstance) {
if (err) {
console.error(err);
return;
}
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {'font-size': '14px'},
'input.invalid': {'color': 'red'},
'input.valid': {'color': 'green'}
},
fields: {
number: {selector: '#card-number',placeholder: '4111 1111 1111 1111'},
cvv: {selector: '#cvv',placeholder: '123'},
expirationDate: {selector: '#expiration-date',placeholder: 'MM/YY'}
}
}, function(err, hostedFieldsInstance) {
if (err) {
console.error(err);
return;
}
submit_button.removeAttribute('disabled');
payment_form.addEventListener('submit', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (tokenizeErr, payload) {
if (tokenizeErr) {
console.error(tokenizeErr);
return;
}
console.log('Got a nonce: ' + payload.nonce);
$('#payment-method-nonce').val(payload.nonce);
// payment_form.submit();
// $('#payment_form').submit();
document.getElementById('payment_form').submit();
});
});
});
});
}
});
<form action="process_order.php" method="POST" class="form" id="payment_form">
<div id="payment_container">
<div class="form-group">
<label for="card-number">Card Number</label>
<div id="card-number" name="card-number"></div>
</div>
<div class="form-group">
<label for="cvv">CVV</label>
<div id="cvv" name="cvv"></div>
</div>
<div class="form-group">
<label for="expiration-date">Expiration Date</label>
<div id="expiration-date" name="expiration-date"></div>
</div>
<input type="hidden" id="payment-method-nonce" name="payment-method-nonce">
<input type="submit" class="btn btn-default mx-auto" value="Complete Order ยป" id="payment_button">
</div>
</form>
<script src="https://js.braintreegateway.com/web/3.50.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.50.0/js/hosted-fields.min.js"></script>
<script src="web/braintree.js"></script>
At this point I can get the nonce and it is added to the value of the hidden input but the form won't submit.
When I use the variable name or use document.getElementById() I get TypeError: document.getElementById(...).submit is not a function but when I do it the jQuery way ($) nothing happens.

Passport JS does not give error but, does not seem to work

I have a basic register and login app. After the user registers, and stores their information into my sequelize model, I redirect the page to the login page. When I try to login with the username and password I just made, it doesn't throw any errors, but the page goes into an endless loading phase where it eventually says The localhost page isnt working localhost didn't send any data'ERR_EMPTY_RESPONSE`
//Routes
var express = require('express');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var router = express.Router();
var db = require('../models');
router.get('/', function(req, res){
res.redirect('/friend-book');
});
router.get('/friend-book', function(req, res){
res.render('home');
});
router.get('/friend-book/profile', function(req, res){
res.render('profile');
});
router.get('/friend-book/login', function(req, res){
res.render('login');
});
router.get('/friend-book/register', function(req, res){
res.render('register');
});
router.post('/friend-book/search/user', function(req, res){
db.users.findAll({
where: {
name: req.body.name
}
}).then(function(data){
var userResults = {
people: data
}
res.render('searchedUser', userResults);
})
});
router.post('/friend-book/register', function(req, res){
console.log(req.body);
var name = req.body.name;
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var password2 = req.body.password2;
var description = req.body.description
req.checkBody('name', 'Must type in name.').notEmpty();
req.checkBody('username', 'Must type in Username.').notEmpty();
req.checkBody('email', 'Must type in email.').notEmpty();
req.checkBody('email', 'Invalid Email').isEmail();
req.checkBody('password', 'Must type in password.').notEmpty();
req.checkBody('password2', 'Passwords do not match.').equals(req.body.password);
req.checkBody('description', 'Must type in something about yourself.').notEmpty();
var errors = req.validationErrors();
//If there are errors, render the errors
if(errors){
res.render('register', {
errors: errors
});
}else{
db.users.create(req.body).then(function(data){
console.log("register data", data);
console.log("poop", data.id);
req.session.user = {
id: data.id,
name: data.name,
username: data.username,
email: data.email,
description: data.description
};
req.flash('success_msg', 'Success! Welcome to Book Face!');
// res.render("profile", req.session.user);
res.redirect('/friend-book/login')
});
}
//***************************************************************************************************
});
passport.use(new LocalStrategy(
function(username, password, done) {
db.users.findOne({
where: {
username: username
}
}, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
db.users.findById(id, function(err, user) {
done(err, user);
});
});
router.post('/friend-book/login',
passport.authenticate('local',
{
successRedirect: '/',
failureRedirect: '/friend-book/login',
failureFlash: true
}),function(req, res){
res.redirect('/friend-book/profile' + req.user.username);
}
);
module.exports = router;
//My model
var bcrypt = require('bcryptjs')
module.exports = function(sequelize, DataTypes){
var users = sequelize.define('users', {
name: DataTypes.STRING,
username: DataTypes.STRING,
password: DataTypes.STRING,
email: DataTypes.STRING,
description: DataTypes.STRING
}, {
hooks: {
beforeCreate: function(user, options){
return new Promise(function(resolve, reject){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {reject(err)}
user.password = hash;
console.log(user.password);
resolve();
});
});
})
}
}
});
return users;
}
//login handlebars
<div class="container">
<form action="/friend-book/login" method="POST" class="form-signin">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputUsername" class="sr-only">Username</label>
<input type="text" name="username" id="inputUsername" class="form-control" placeholder="Username" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div> <!-- /container -->
//Registration handlebars
<div class="container">
<h2 class="form-register-heading">Book Face Registration</h2>
{{#if errors}}
{{#each errors}}
<div class="alert alert-warning">{{msg}}</div>
{{/each}}
{{/if}}
<form action="/friend-book/register" method="POST" class="form-signin">
<div class="form-group">
<label for="inputName" class="sr-only">Name</label>
<input type="text" name="name" id="inputName" class="form-control" placeholder="Name">
</div>
<div class="form-group">
<label for="inputUsername" class="sr-only">Username</label>
<input type="text" name="username" id="inputUsername" class="form-control" placeholder="Username">
</div>
<div class="form-group">
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password">
</div>
<div class="form-group">
<label for="inputPassword2" class="sr-only">Password</label>
<input type="password" name="password2" id="inputPassword2" class="form-control" placeholder="Password">
</div>
<div class="form-group">
<label for="inputEmail" class="sr-only">Email</label>
<input type="email" name="email" id="inputEmail" class="form-control" placeholder="Email">
</div>
<div class="form-group">
<label for="inputDescription" class="sr-only">Description</label>
<input type="text" name="description" id="inputDescription" class="form-control" placeholder="Type something">
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Register</button>
</form>
</div> <!-- /container -->
You only handle POST requests to /friend-book/login.
When you use res.redirect('/friend-book/login'), it'll redirect the user using GET method to that URL.
router.get('/friend-book/login', function (req, res) {
res.render('login');
});

Submit form without redirect with node.js

I need to display some loading gif while form submission
but, upon form submit do not refresh the page,
just display a Thank You! message:
Currently, it's refresh the page by submit, and I don't wanted to refresh only display a message after submit.
Here's the code:
/* form hbs */
<form id="myForm" style="display:block" method="POST" role="form" class="form col-md-4 col-md-offset-4 col-xs-12">
<div class="form-group">
<input type="text" class="form-control" id="name" name="name" placeholder="Your Name...">
</div>
<div class="form-group">
<input type="email" class="form-control" id="email" name="email" placeholder="Email...">
</div>
<div class="form-group">
<input type="text" class="form-control" id="companyName" name="companyName" placeholder="Your Company Name...">
</div>
<div class="form-group">
<input type="text" class="form-control" id="message" name="message" placeholder="Your Message Here...">
</div>
{{!--onClick="hide();"--}}
<button type="submit" class="btn btn-primary" id="hide">Submit</button>
</form>
//in route index.js
/* GET Add Contact Us page. */
router.get('/ContactUs', function (req, res, next) {
res.render('ContactUs', {
title: 'Contact Us'
});
});
router.post('/ContactUs', function (req, res) {
var name = req.body.name;
var email = req.body.email;
var companyName = req.body.companyName;
var message = req.body.message;
var SQL = "INSERT INTO Contacts(name, email, companyName, message) VALUES($1, $2, $3, $4)";
//send the message to email
handleSayHello(req, res);
query(SQL, [name, email, companyName,message], res, function (json) {
res.render('ContactUs', {
title: 'Success!'
});
});
});
function query(sql, arr, hbsResponse, listener) {
pg.connect(process.env.DATABASE_URL, function (err, client, done) {
if (err) {
return hbsResponse.render('error', {
error: err,
message: err.message
});
}
client.query(sql, arr, function (err, result) {
done(); //close the connection
if (err) {
return hbsResponse.render('error', {
error: err,
message: err.message
});
}
listener(result);
});
});
}
How do I implement it via ajax that post the request without refresh the page and hide form (instead form after submit display another div?
Thank you in advance who that can helping me I will be very grateful!

Sending data to a modal without redirecting in nodejs

I am using passport and flash to manage authentication. I want to send flash messages back to the UI per the documentation. In my scenario in the UI I am using a modal so doing a
res.render('login.ejs', { message: req.flash('loginMessage') });
won't work because you can only render on a page refresh. Therefore how can I send flash dataor any other kind of data to my page when fails to log in for some reason. Regardless of flash data in particular I cannot figure out how to render data to a modal with express.
routes.js
below the res.render never happens on a authentication failure.
//Home Page ===================================
app.get('/', function(req, res) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
//Login Modal =================================
app.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureFlash : true
}));
index.ejs (where my modal is)
<div id="openModal" class="modalDialog">
<div>
X
<h2 id="logintitle">Log In</h2>
<% if (message.length>0) { %>
<div class="alert alert-danger">
<%= message %>
</div>
<% } %>
<form class="form-horizontal" action="/login" method="post" id="loginform">
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_email">Email</label>
<i class="glyphicon glyphicon-user"></i>
<input type="email" class="form-control" name="email" placeholder="Email Address" />
</div>
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_pass">Password</label>
<i class="glyphicon glyphicon-star-empty"></i>
<input type="password" class="form-control" name="password" placeholder="Password" />
</div>
<div id="forgotpass">
Forgot Password?
</div>
<div class="form-group">
<button type="submit" class="btn form-login-button">Log In</button>
</div>
</form>
<div class="strike">
<span>Log in with</span>
</div>
<div id="test" class="test">
<span class="fa fa-facebook"></span> Facebook
<span class="fa fa-google-plus"></span> Google
</div>
</div>
</div>
My understanding is I need to use javascript/ajax to prevent the post for being the redirect but I cannot figure out how to get the flash data to this point:
index.ejs (javascript)
$(function () {
$("#loginform").on("submit", function(e) {
e.preventDefault();
$.ajax({
url: $(this).attr("action"),
type: 'POST',
data: $(this).serialize(),
beforeSend: function () {
},
success: function (data) {
}
});
});
});
EDIT added some code from passport.js
function passport_login(req, email, password, done) {
//doing some validate and found bad password
return done(null, false, req.flash('loginMessage', 'Invalid Password'));
})
So after quite a bit of digging I have found the solution. The key was in recognizing jquery not express is the answer, letting the client handle the redirects and posts/gets. I have only include updates for a local login strategy but they would apply for your signup/social other social profiles as well.
Changes to passport.js (minor)
function passport_login(req, email, password, done) {
//doing some validate and found bad password
return done(null, false, 'Bad Password');
})
Changes to my route (the part I struggled with)
The key things to note here is I am deciding what data I sent through res.send. I could send anything, in this case info is what comes from passport.js ('Bad Password'). If i am happy and able to log in I send a simple little valid:true json.
//Login Modal =================================
app.get('/localLogin', function(req, res, next) {
passport.authenticate('local-login', function(err, user, info) {
if (err) { return next(err); }
//if there is no user in the response send the info back to modal
if (!user) {
return res.send(info);
}
//user was able to login, send true and redirect
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.send({ valid: true });
});
})(req, res, next);
});
Changes to my index.js
Added a div on top the my modal to display messages, remove old <%= message > piece and delete the action and method from the form jQuery will do that for us. (included full modal code to be transparent)
<div id="openModal" class="modalDialog">
<div>
X
<h2 id="logintitle">Log In</h2>
<div id="loginPopup"></div>
<form class="form-horizontal" id="loginform">
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_email">Email</label>
<i class="glyphicon glyphicon-user"></i>
<input type="email" class="form-control" name="email" placeholder="Email Address" />
</div>
<div class="form-group inner-addon left-addon">
<label class="sr-only" for="login_pass">Password</label>
<i class="glyphicon glyphicon-star-empty"></i>
<input type="password" class="form-control" name="password" placeholder="Password" />
</div>
<div id="forgotpass">
Forgot Password?
</div>
<div class="form-group">
<button type="submit" class="btn form-login-button">Log In</button>
</div>
</form>
<div class="strike">
<span>Log in with</span>
</div>
<div id="test" class="test">
<span class="fa fa-facebook"></span> Facebook
<span class="fa fa-google-plus"></span> Google
</div>
</div>
</div>
Then I added the following Jquery code the last piece to the puzzle:
$(function(){
$('#loginform').on('submit', function(e) {
e.preventDefault();
var data = $(this).serialize();
$.get('/localLogin', data, function(result) {
if(result.valid == true)
{
window.location.href = '/profile';
}
else
{
$('#loginPopup').html(result);
}
});
});
});
Hope this helps someone, the information for a full end to end solution on how to do this is sparse.

Set up reset password token for custom route in meteor

I am building a custom authentication system using accounts-password in meteor. My question is why when i remove the default hash that meteor provides for reset password links i do also lose my resetPasswors token session? So far i have this code but im not able to access the condition in my template to change my password. Seems like something wrong when setting up a custom reset password route.
router.js
Router.route('/reset-password', {name: 'resetPassword'});
Router.route('/reset-password/:token', function () {
this.render('resetPassword');
});
reset_password.html
<template name="resetPassword">
<div class="reset-container">
{{#if resetPassword}}
<form class="reset-password">
<div class="form-group">
<label for="password" class="control-label">New password</label>
<input type="password" name="password" class="form-control"
title="Please enter a new password" id="password" placeholder="Password">
<span class="help-block small"> Your strong password</span>
</div>
<input type="submit" class="btn btn-success btn-block" value="Reset password">
</form>
{{else}}
<form class="forgot-password">
<div class="form-group">
<label for="email" class="control-label">Email</label>
<input type="text" name="email" class="form-control"
title="Please enter your email" id="email" placeholder="example#gmail.com">
<span class="help-block small"> Your unique email address</span>
</div>
<input type="submit" class="btn btn-success btn-block" value="Send instructions!">
</form>
{{/if}}
</div>
</template>
reset_password.js
if (Accounts._resetPasswordToken) {
Session.set('resetPasswordToken', Accounts._resetPasswordToken);
}
Template.resetPassword.helpers({
resetPassword: function() {
return Session.get('resetPasswordToken');
}
});
Template.resetPassword.events({
"submit .forgot-password": function(event) {
// Prevent default browser form submit
event.preventDefault();
// Get value from form element
email = event.target.email.value;
if (email) {
Accounts.forgotPassword({email: email}, function (error) {
if (error) {
if (error.message === 'User not found [403]') {
throwAlert('This email address does not exist.', 'danger');
} else {
throwAlert('We are sorry but something went wrong.', 'danger');
}
} else {
throwAlert('We have sent you an email with basic instructions to reset your password.', 'success');
}
});
} else {
throwAlert('Your email address cannot be empty.', 'danger');
}
},
"submit .reset-password": function (event) {
// Prevent default browser form submit
event.preventDefault();
// Get value from form element
password = event.target.password.value;
// If the password is valid, we can reset it.
if (password) {
Accounts.resetPassword(Session.get('resetPasswordToken'), password, function (error) {
if (error) {
throwAlert('We are sorry but something went wrong.', 'danger');
} else {
throwAlert('Your password has been changed. Welcome back!', 'success');
Session.set('resetPasswordToken', null);
Router.go('postsList');
}
});
} else {
throwAlert('Your password cannot be empty. Create a good one!', 'danger');
}
}
});
server/config.js
Meteor.startup(function() {
Accounts.emailTemplates.resetPassword.text = function(user, url) {
var token = url.substring(url.lastIndexOf('/') + 1, url.length);
var newUrl = Meteor.absoluteUrl('reset-password/' + token);
var str = 'Hello, \n';
str+= 'Click on the following link to reset your password \n';
str+= newUrl;
return str;
};
});
same, i do:
this.route('password.reset', {
path: '/password/reset/:token',
onBeforeAction: function() {
Accounts._resetPasswordToken = this.params.token;
this.next();
},
template: 'resetPassword'
});
and move the if(Accounts._resetPasswordToken) in the onCreated
Template.resetPassword.onCreated(function() {
if(Accounts._resetPasswordToken) {
Session.set(RESET_PASSWORD, Accounts._resetPasswordToken);
}
...

Categories

Resources