Passport js, get user input using Handlebars - node.js

I'm starting to learn node.js using passport, handlebars and mysql.
I want to create a signup page that will take email address, password, first name and last name. But on passport, it only takes the username and password.
passport.use('local-signup', new passportlocal.Strategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done){
connection.query("select * from userInfo where email = '"+email+"'", function(err, res){
if(err){
console.error('error');
// done(null, null);
return done(null, false, { message: req.flash('error', 'Please fill your data correctly') });
// return;
}
if (res.length) {
console.log('user exist');
return done(null, false, { message: req.flash('error', 'That email is already registered.') });
}
else{
// create the user
var newUserMysql = new Object();
newUserMysql.email = email;
newUserMysql.password = password;
newUserMysql.firstName = req.firstName;
console.log(newUserMysql.firstName);
var insertQuery = "INSERT INTO userInfo ( email, password, firstName ) values ('" + email +"','"+ password +"','"+ firstName +"')";
connection.query(insertQuery,function(err,rows){
newUserMysql.id = rows.insertId;
// send mail with defined transport object
app.locals.mailer.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
return done(null, newUserMysql);
});
}
})
}));
and following is the code for my handlebars
<div class="ui vertical stripe segment">
<div class="ui text container">
<form action="" method="post">
{{#if message}}
<div class="ui red message">{{message}}</div>
{{/if}}
<div class="content">
<div class="field required">
<label>Email Address</label>
<div class="ui fluid input">
<input type="text" name="email" placeholder="Email Address">
</div>
</div>
</div>
<p></p>
<div class="content">
<div class="field required">
<label>Password</label>
<div class="ui fluid input">
<input type="password" name="password" placeholder="Password">
</div>
</div>
</div>
<p></p>
<div class="content">
<div class="field required">
<label>Repeat Password</label>
<div class="ui fluid input">
<input type="password" name="repeatPassword" placeholder="Repeat Password">
</div>
</div>
</div>
<p></p>
<div class="content">
<div class="field required">
<label>First Name</label>
<div class="ui fluid input">
<input type="text" name="firstName" placeholder="First Name">
</div>
</div>
</div>
<p></p>
<div class="content">
<div class="field required">
<label>Last Name</label>
<div class="ui fluid input">
<input type="text" name="lastName" placeholder="Last Name">
</div>
</div>
</div>
<p></p>
<div class="content">
<div class="field required">
<label>Phone Number</label>
<div class="ui fluid input">
<input type="text" name="phoneNum" placeholder="Phone Number">
</div>
</div>
</div>
<p></p>
<button class="ui yellow button">Sign Up</button>
<div class="ui horizontal divider">
OR
</div>
Already have an account? Please Login here!
</form>
</div>
</div>
I have tried the following solution, but it is not working for me.
I presume that my way of getting the input data from the handlebars to the passport is wrong, but I can't figure it out.
Thank you.

Figure it out with help from Jose, both statements should be added a (req.body.firstName)
else{
// create the user
var newUserMysql = new Object();
newUserMysql.email = email;
newUserMysql.password = password;
newUserMysql.firstName = req.body.firstName;
console.log(newUserMysql.firstName);
var insertQuery = "INSERT INTO userInfo ( email, password, firstName ) values ('" + email +"','"+ password +"','"+ req.body.firstName +"')";

Related

Render updated document to ejs page mongoose node js

I have an app where users can create an account and update their information after creation. I am able to save the updated document to the database when users input new information on the edit page, however, when I redirect them to the user panel, the old information is still being displayed. I believe that it has something to do with the session that gets created on login because the updated information only shows once the user logs out and logs back in.
This is my edit page:
<%- include('partials/header') %>
<% if(user.firstName.endsWith("s")) { %>
<h1 class="dashboard-title"><%=user.firstName + "' Account"%></h1>
<% } else { %>
<h1 class="dashboard-title"><%=user.firstName + "'s Account"%></h1>
<% } %>
<!-- Action Buttons -->
<div class="container">
<div class="row justify-content-center">
<div class="col-md-3">
<a href="/logout" class="dashboard-btn">
<h5>Logout <i class="fas fa-door-open"></i></h5>
</a>
</div>
<div class="col-md-3">
<a href="/edit" class="dashboard-btn">
<h5>Edit <i class="fas fa-edit"></i></h5>
</a>
</div>
</div>
</div>
<br>
<!-- Information -->
<div class="container">
<form class="" action="/edit" method="post">
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="firstName">First Name:</label>
<div class="form-group col-md-7">
<input name="firstName" class="form-control" type="text" value="<%=user.firstName%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="lastName">Last Name:</label>
<div class="form-group col-md-7">
<input name="lastName" class="form-control" type="text" value="<%=user.lastName%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="email">Email:</label>
<div class="form-group col-md-7">
<input name="email" class="form-control" type="text" value="<%=user.username%>" readonly>
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="phone">Phone:</label>
<div class="form-group col-md-7">
<input name="phone" class="form-control" type="text" value="<%=user.phoneNumber%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="address">Address:</label>
<div class="form-group col-md-7">
<input name="address" class="form-control" type="text" value="<%=user.personalInfo.address%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="coverage">Coverage:</label>
<div class="form-group col-md-7">
<input name="coverage" class="form-control" type="text" value="<%=user.coverage%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="paymentPlan">Payment:</label>
<div class="form-group col-md-7">
<input name="paymentPlan" class="form-control" type="text" value="<%=user.paymentPlan%>">
</div>
</div>
<br>
<button class="btn register-btn" type="submit">Submit Changes</button>
</form>
</div>
<%- include('partials/footer') %>
And app.js to handle the post requests to edit route:
app.get("/user-panel", function(req, res) {
if(req.isAuthenticated()) {
res.render("user-panel", {
user: req.user
});
} else {
res.redirect('/login');
}
});
app.get("/edit", function(req, res) {
if(req.isAuthenticated()) {
res.render("edit", {
user: req.user
});
} else {
res.redirect("/login");
}
});
app.post("/edit", function(req, res) {
const email = req.user.username;
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const phone = req.body.phone;
User.findOne({username: email}, function(err, foundUser) {
if(err) {
console.log(err);
} else {
if (foundUser) {
foundUser.firstName = firstName;
foundUser.save();
res.redirect("/user-panel");
}
}
});
});
Any ideas on how I can get the server to respond with the updated info without having to log out the user?
I want to touch on a few things.
to answer your question, you need to query the database again upon redirect. like so:
you need to pass the email value back to the original user-panel function:
res.redirect("/user-panel?username=" + email);
then, you have to query the database again, like so:
app.get("/user-panel", authCheck, function(req, res) {
let email = req.query.email
User.findOne({username: email}, function(err, foundUser) {
if(err) {
console.log(err);
} else {
if (foundUser) {
foundUser.firstName = firstName;
foundUser.save();
res.render("user-panel", {
user: req.user
});
}
}
});
});
You should try not to use authentication logic within each function, rather have it as a seperate function and import it as middleware. Makes it cleaner. I've rewritten it for you.
function authCheck(req, res, next) {
if(req.isAuthenticated()) {
next()
} else {
res.redirect('/login');
}
}
now within any new function you create (within this file), you can just use the function authCheck() as middleware:
app.get('/', authCheck, (req, res) => {

How to use endpoint inside another endpoint in express node js

I am just stuck in a problem and also don't know whether the question is correct or not.
I am working on a node express js, using ejs templating engine.
I have created certain endpoints (say login(POST) endpoint) which are generic endpoints.
Now I want to create a new application which uses should use these endpoints and render the view according to the result of these endpoints.
Lets say I have a generic endpoint for login
router.post('/user/login', function (req, res) {
var userLoginId = req.body.username;
var currentPassword = req.body.password;
UserLogin.findOne({userLoginId: userLoginId, currentPassword: currentPassword}, function (err, usr) {
if (err) {
console.log('Error in User login');
console.log(err);
res.status(500).type('application/problem+json').send();
} else {
if (!usr) {
console.log('Please enter valid username and password');
res.status(404).type('application/problem+json').send();
} else {
res.type('application/json').status(200).send(usr);
}
}
});
});
And I am using this login.ejs file
<div class="container panel panel-primary">
<h2 class="h2 text-center">Login</h2>
<form class="form-horizontal" name="loginForm" method="post" action="/user/login">
<div class="form-group">
<label for="username" class="col-sm-offset-2 col-sm-2 control-label">UserName</label>
<div class="col-sm-4">
<input type="text" name="username" class="form-control" id="username" placeholder="username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-offset-2 col-sm-2 control-label">Password</label>
<div class="col-sm-4">
<input type="password" name="password" class="form-control" id="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-4">
<button type="submit" class="btn btn-primary btn-">Sign in</button>
</div>
</div>
</form>
</div>
Now I want to use this code and want to login to the system.
If the user login is successful I want to redirect to dashboard page else same login page.
On executing this code the api returns me the JSON response and from this response how can I decide to whether to redirect on dashboard page or login page.
Please help if more input is needed please put a comment.
I would instead of doing a form request to login, do a AJAX request to login and then use something like jQuery to do the AJAX request and response. Alternatively you could do something like the following.
router.get('/login', function(req, res){
res.render('login', {});
})
router.post('/login', function (req, res) {
var userLoginId = req.body.username;
var currentPassword = req.body.password;
UserLogin.findOne({userLoginId: userLoginId, currentPassword: currentPassword}, function (err, usr) {
if (err) {
console.log('Error in User login');
console.log(err);
// res.status(500).type('application/problem+json').send();
res.status(500).render('login', { error : 'Error finding password'})
} else {
if (!usr) {
console.log('Please enter valid username and password');
// res.status(404).type('application/problem+json').send();
res.status(404).render('login', { error : 'Please enter valid username and password'})
} else {
res.redirect('/dashboard');
}
}
});
});
For the login.ejs file i would conditionally render the error.
<!DOCTYPE html>
<html>
<body>
<div class="container panel panel-primary">
<h2 class="h2 text-center">Login</h2>
<%if (locals.error) { %>
<%= error %>
<% } %>
<form class="form-horizontal" name="loginForm" method="post" action="/user/login">
<div class="form-group">
<label for="username" class="col-sm-offset-2 col-sm-2 control-label">UserName</label>
<div class="col-sm-4">
<input type="text" name="username" class="form-control" id="username" placeholder="username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-offset-2 col-sm-2 control-label">Password</label>
<div class="col-sm-4">
<input type="password" name="password" class="form-control" id="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-4">
<button type="submit" class="btn btn-primary btn-">Sign in</button>
</div>
</div>
</form>
</div>
</body>
</html>

google recaptcha nodejs app

Ok so I am trying to implement Google Recaptcha into my register page for my app. Everything on the front end seems to work as far as it loads the page and when I click "I am not a robot" it asks me to verify images and then... when I click submit, It tells me to "Please select captcha" and it redirects me back to the register page. Thats how I have the code setup if someone doesn't select the captcha checkmark but I cannot figure out why it won't continue and create the user. Here is the code...
// handle signup logic
router.post("/register", function(req, res) {
if(req.body.captcha === undefined || req.body.captcha === "" || req.body.captcha === null){
req.flash("error", "Please select captcha");
return res.redirect("/register");
}
// secret key
var secretKey = process.env.CAPTCHA;
// Verify URL
var verifyURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${req.body.captcha}&remoteip=${req.connection.remoteAddress}`;
// Make request to Verify URL
request(verifyURL, (err, response, body) => {
// if not successful
if(body.success !== undefined && !body.success){
req.flash("error", "Captcha Failed");
return res.redirect("/register");
}
// if successful
upload(req, res, function(err) {
if(err){
console.log(err.message);
req.flash("error", err.message);
return res.redirect("/register");
}
var newUser = new User({
username: req.body.username,
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
bio: req.body.bio
});
if(typeof req.file !== "undefined") {
newUser.avatar = '/uploads/userImg/' + req.file.filename;
} else {
newUser.avatar = '/uploads/userImg/no-image.png';
}
console.log(newUser);
if(req.body.adminCode === process.env.ADMINCODE) {
newUser.isAdmin = true;
}
if(req.body.answer !== process.env.SECRET){
req.flash("error", "answer the question");
return res.redirect("back");
} else {
User.register(newUser, req.body.password, function(err, user){
if(err){
console.log(err.message);
return res.render("register", {error: err.message});
}
passport.authenticate("local")(req, res, function(){
req.flash("success", "Welcome to Let's Camp " + user.username);
res.redirect("/campgrounds");
});
});
}
});
});
});
<% include ./partials/header %>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form id="register" action="/register" method="post" enctype="multipart/form-data">
<h1 class="text-center">Sign Up</h1>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="firstName">First Name</label>
<input id="firstName" class="form-control" type="text" id="firstName" name="firstName" placeholder="First Name*" required>
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="lastName">Last Name</label>
<input id="lastName" class="form-control" type="text" id="lastName" name="lastName" placeholder="Last Name*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="email">Email</label>
<input id="email" class="form-control" type="email" id="email" name="email" placeholder="Email*" required>
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="avatar">Avatar Image URL</label>
<input id="avatar" class="form-control" type="file" name="avatar">
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="username">Username</label>
<input id="username" class="form-control" type="text" id="username" name="username" placeholder="Username*" required>
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="password">Password</label>
<input id="password" class="form-control" type="password" id="password" name="password" placeholder="Password*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="bio">Bio</label>
<textarea id="bio" class="form-control" type="bio" name="bio" rows="5" placeholder="Write a short description of yourself and what you enjoy about camping."></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="adminCode">Admin Code</label>
<input id="adminCode" class="form-control" type="text" name="adminCode" placeholder="Admin Code">
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="number">Enter: Answer</label>
<input id="number" class="form-control" type="text" id="answer" name="answer" placeholder="Answer*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="g-recaptcha form-group" data-sitekey="6LduxzsUAAAAAAoten8FA_zg12PjA3QfSjF5vFvY"></div>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Sign Up!</button>
</div>
Go Back
</form>
</div>
</div>
<div class="row">
<div class="col-md-12 col-xs-8 col-xs-offset-2">
<p class="text-center"><strong>*</strong> indicates a required field.</p>
</div>
</div>
</div>
<% include ./partials/footer %>
It's not req.body.captcha
Seems like You've not read tutorial correctly.
From this tutorial is see such example:
app.post('/submit',function(req,res){
// g-recaptcha-response is the key that browser will generate upon form submit.
// if its blank or null means user has not selected the captcha, so return the error.
if(req.body['g-recaptcha-response'] === undefined || req.body['g-recaptcha-response'] === '' || req.body['g-recaptcha-response'] === null) {
// not passed validation
}
And from this file is see such code at line 52 :
if(req.body && req.body['g-recaptcha-response']) response = req.body['g-recaptcha-response'];
Both of them proves that "invisible" field is accessible under req.body['g-recaptcha-response']
HERE IS THE FIX:
this:
const captcha = req.body['g-recaptcha-response'];
if(!captcha){
req.flash("error", "Please select captcha");
return res.redirect("/register");
}
and this:
// Verify URL
var verifyURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${captcha}&remoteip=${req.connection.remoteAddress}`;
or just create simple middleware catchReCaptcha and attach to router:
// middleware that catches g-recaptcha-response and puts in req.body.captcha
const catchReCaptcha = (req, res, next) => {
if(req.body && req.body['g-recaptcha-response']) {
req.body.captcha = req.body['g-recaptcha-response'];
}
next();
};
// attached middleware to register route
router.post("/register", catchReCaptcha, (req, res) => {
but keep in mind You'll have conflicts of parsing multipart/form-data since upload method responsible also for parsing body of request for that content-type.

Logic doesn't work after .then

I have a Login end point that respond me a json.
I'm using vue-router to do a POST and then Store a token in localStorage, but after the POST, the json shows on the screen:
{"success":false,"message":"Login ou senha inválidos!"}
It should return on the page login, with the message
This is the code:
var vmLogin = new Vue({
el: '#login',
data: {
email: '',
msg: '',
password: ''
},
beforeCreate: function () {
if(localStorage.getItem("timeTaskToken") !== null) {
window.location.href = '/'
}
},
methods: {
getLogin: function (e) {
this.$http.post('/login', {email: this.email, password: this.password}).then((response) => {
alert('teste!');
if(response.body.success === true) {
localStorage.setItem("timeTaskToken", response.body.token);
window.location.href = '/'
} else {
this.msg = response.body.message
}
}, (response) => {
// error callback
});
e.preventDefault();
}
}
});
login page
<form id="login" class="form-horizontal" method="post">
<h3>{{ msg }}</h3>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email" v-model="email" class="form-control" name="email" placeholder="Email">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<input type="password" v-model="password" class="form-control" name="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default" #click="getLogin">Sign
in</button>
</div>
</div>
</form>
It's like nothing after .then works...
The returned JSON just appear in the screen.
I expect the problem is that the Sign In button is a submit button and you just want it to be a button button.
Change
<button type="submit" class="btn btn-default" #click="getLogin">Sign in</button>
To
<button type="button" class="btn btn-default" #click="getLogin">Sign in</button>
Note the type="button".
If you leave it as type submit then the form is is actually posted and code execution will stop. This also explains why you see a page that has just the JSON result; that is just the response from posting that form.
Alternatively, move e.preventDefault() to the top of the method.
You could also use #click.prevent="getLogin".
Just add a console.error in you error callback
}, (response) => {
console.error(response);
});
This is the first step because maybe you just enter here ..

nodemailer doesn't stop sending mails

I have a simple nodemailer setup that sends emails without a problem. The only thing I can't figure out is how to stop it from sending once it started. I click send, it sends an email but the page keeps loading and soon I receive another email etc. Surely it should only send one email and close the process.
Can anybody see something I'm doing wrong here?
var smtpTransport = nodemailer.createTransport('SMTP', {
host: 'mail.francotanzarella.com',
secureConnection: false,
port: 587,
auth: {
user: 'contact#francotanzarella.com',
pass: '***'
}
});
app.post('/contact', function(req, res) {
var htmlTpl = '<h4>Message from' + ' ' + req.body.name + '</h4><p><span>' + req.body.email + '</span</p><p>' + req.body.message + '</p>';
mailOptions = {
from: 'noreply#francotanzarella.com',
to: 'contact#francotanzarella.com',
subject: 'New message from francotanzarella.com',
html: htmlTpl,
debug: true
}
smtpTransport.sendMail(mailOptions, function(error, response) {
if(error) {
console.log(error)
} else {
console.log(response.message);
}
smtpTransport.close();
});
});
contact.ejs
<form id="contact-form" method="POST" name="userForm" action="/contact" ng-submit="submitForm(userForm.$valid)" novalidate>
<div class="row">
<div class="small-12 column">
<div class="row" ng-class="{ 'error' : userForm.name.$invalid && !userForm.name.$pristine && submitted }">
<div class="small-12 column">
<label for="name" class="inline">Name</label>
</div>
<div class="small-12 column">
<input type="text" id="name" name="name" placeholder="Your name" ng-model="name" required />
<small class="error" ng-show="userForm.name.$invalid && !userForm.name.$pristine">Please enter your name</small>
</div>
</div>
<div class="row" ng-class="{ 'error' : userForm.email.$invalid && !userForm.email.$pristine && submitted }">
<div class="small-12 column">
<label for="email" class="inline">Email</label>
</div>
<div class="small-12 column">
<input type="email" id="email" name="email" placeholder="Your email" ng-model="email" required />
<small class="error" ng-show="userForm.email.$invalid && !userForm.email.$pristine">I need a valid email please</small>
</div>
</div>
<div class="row" ng-class="{ 'error' : userForm.message.$invalid && !userForm.message.$pristine && submitted }">
<div class="small-12 column">
<label for="message" class="inline">Message</label>
</div>
<div class="small-12 column">
<textarea id="message" name="message" placeholder="Send me a message" ng-model="message" required></textarea>
<small class="error" ng-show="userForm.message.$invalid && !userForm.message.$pristine">What? No message?</small>
</div>
</div>
<div class="row">
<div class="small-12 column">
<button type="submit" class="button" ng-disabled="userForm.$invalid">send</button>
</div>
</div>
</div>
</div>
<div id="form-response-container">
<div id="for-response-inner">
<h3 id="form-response"></h3>
</div>
</div>
</form>
Okay I fixed this. Not sure if it's the correct method but it works. I basically pass the browser a ok (200) when the email was sent successfully.
if(error) {
res.send(500);
} else {
res.send(200);
}

Resources