I need to have node.js ran on all my web pages - node.js

So I have created a node server to run a website and am running into an issue with how to have it run node on the rest of the site. currently it just runs on the login page. After logging in it goes to my homepage (homepage.html). The homepage is running off nginx. How can I have everything running off node?
here is my js file (auth.js)
const mysql=require("mysql");
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password:process.env.DATABASE_PASSWORD,
database:process.env.DATABASE
});
exports.login = async (req, res) => {
try {
const{email, password} = req.body;
if(!email || !password){
return res.status(400).render('login', {
message:'Please provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ?', [email], async(error, results) =>{
console.log(results);
if(!results || !(await bcrypt.compare(password, results[0].password) ) ) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
} else{
const id = results[0].id;
const token=jwt.sign({id:id}, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("The token is: "+token);
const cookieOptions= {
expires: new Date(
Date.now + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.cookie('jwt', token, cookieOptions);
res.status(200).redirect("http://zrgarri.it.pointpark.edu/CMPS480/homepage.html");
}
})
} catch (error) {
console.log(error);
}
}
exports.register = (req, res) => {
console.log(req.body);
const name = req.body.name;
const email = req.body.email;
const password = req.body.password;
const passwordConfirm = req.body.passwordConfirm;
db.query('SELECT email FROM users WHERE email=?', [email], async (error, results) => {
if(error){
console.log(error);
}
if(results.length > 0) {
return res.render('register', {
message: 'Email already in use.'
})
} else if(password !== passwordConfirm){
return res.render('register', {
message: 'Passwords do not match.'
});
}
let hashedPassword= await bcrypt.hash(password, 8);
console.log(hashedPassword);
db.query('INSERT INTO users SET ? ', {name: name, email: email, password: hashedPassword}, (error, results)=> {
if(error) {
console.log(error);
} else {
console.log(results);
return res.render('register', {
message: 'User Registered Successfully'
});
}
});
});
}
© 2020 GitHub, Inc.

Related

Login Form Error nodejs express, how do i fix it?

this login form have some problem in it whenever I register and then login with credentials, it always show that my credentials are wrong.
this is auth.js code from controller
const mysql = require("mysql");
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { promisify } = require('util');
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
if( !email || !password ) {
return res.status(400).render('login', {
message: 'Please provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ?', [email], async (error, results) => {
console.log(results);
if( !results || !(await bcrypt.compare(password, results[0].password)) ) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
} else {
const id = results[0].id;
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("The token is: " + token);
const cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.cookie('jwt', token, cookieOptions );
res.status(200).redirect("/");
}
})
} catch (error) {
console.log(error);
}
}
exports.register = (req, res) => {
console.log(req.body);
const { name, email, password, passwordConfirm } = req.body;
db.query('SELECT email FROM users WHERE email = ?', [email], async (error, results) => {
if(error) {
console.log(error);
}
if( results.length > 0 ) {
return res.render('register', {
message: 'That email is already in use'
})
} else if( password !== passwordConfirm ) {
return res.render('register', {
message: 'Passwords do not match'
});
}
let hashedPassword = await bcrypt.hash(password, 8);
console.log(hashedPassword);
db.query('INSERT INTO users SET ?', {name: name, email: email, password: hashedPassword }, (error, results) => {
if(error) {
console.log(error);
} else {
console.log(results);
return res.render('register', {
message: 'User registered'
});
}
})
});
}
exports.isLoggedIn = async (req, res, next) => {
// console.log(req.cookies);
if( req.cookies.jwt) {
try {
//1) verify the token
const decoded = await promisify(jwt.verify)(req.cookies.jwt,
process.env.JWT_SECRET
);
console.log(decoded);
//2) Check if the user still exists
db.query('SELECT * FROM users WHERE id = ?', [decoded.id], (error, result) => {
console.log(result);
if(!result) {
return next();
}
req.user = result[0];
console.log("user is")
console.log(req.user);
return next();
});
} catch (error) {
console.log(error);
return next();
}
} else {
next();
}
}
exports.logout = async (req, res) => {
res.cookie('jwt', 'logout', {
expires: new Date(Date.now() + 2*1000),
httpOnly: true
});
res.status(200).redirect('/');
}
and this is app.js
const express = require("express");
const path = require('path');
const mysql = require("mysql");
const dotenv = require('dotenv');
const cookieParser = require('cookie-parser');
dotenv.config({ path: './.env'});
const app = express();
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
const publicDirectory = path.join(__dirname, './public');
app.use(express.static(publicDirectory));
// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded({ extended: false }));
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.use(cookieParser());
app.set('view engine', 'hbs');
db.connect( (error) => {
if(error) {
console.log(error)
} else {
console.log("MYSQL Connected...")
}
})
//Define Routes
app.use('/', require('./routes/pages'));
app.use('/auth', require('./routes/auth'));
app.listen(5001, () => {
console.log("Server started on Port 5001");
})
When entered right credentials
enter image description here
whenever i enter credential whether right or wrong it shows this only.
please help me, i am stuck here
I am not sure but I think the problem is in controller/auth.js code and i tried to change the login code in that
Replace question mark with ${email}
'SELECT * FROM users WHERE email =${email}'

How to implement Node.JS model using Sequelize

I have a project with the below Model, Controller, and Route File for user. I am wanting to implement sequelize, which I have managed to partially achieve using the account files below, however, I am struggling to work out how to implement logging in and ensuring a request has a valid token usijng user.ensureToken which would become account.ensureToken.
I'm fairly new to Node.Js so I'm not even sure where to start
user.model.js
const bcrypt = require('bcrypt');
const sql = require("./db.js");
const HashBits = require("../config/auth.config.js");
const faker = require('faker');
// constructor
const User = function(user) {
this.first_name = user.first_name;
this.last_name = user.last_name;
this.mob_no = user.mob_no;
this.user_name = user.user_name;
this.password = user.password;
};
User.create = (newUser, result) => {
bcrypt.hash(newUser.password, HashBits.saltRounds, (err, hash) => {
newUser.password = hash;
sql.query("INSERT INTO users SET ?", newUser, (err, res) => {
if (err) {
// console.log("error: ", err);
result(err, null);
return;
}
newID = res.insertId;
// console.log("created user: ", { id: res.insertId, ...newUser });
result(null, { id: res.insertId, ...newUser });
});
});
};
User.authenticate = (user,result) => {
// sql.query(`SELECT * FROM customers WHERE id = ${customerId}`, (err, res) => {
sql.query(`SELECT * FROM users WHERE user_name = '${user.user_name}'`, (err, res) => {
// sql.query("SELECT * FROM users ", (err, res) => {
if (err) {
// console.log("error: ", err);
result(err, null);
return;
}
if(res.length !== 1){
// console.log("error: found multiple users");
result("error: found multiple users", null);
return;
}
// console.log("Found user: ",res[0]);
bcrypt.compare(user.password, res[0].password, function(err, res2) {
if(res2){
// console.log("Yes");
result(null,res[0]);
}else{
// console.log("On ya bike");
result("ERROR",null);
// return;
}
});
});
};
module.exports = User;
user.controller.js
const User = require("../models/user.model.js");
var jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
// Create and Save a new User
exports.create = (req, res) => {
// Validate request
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!"
});
}
// Create a User
const user = new User({
first_name: req.body.first_name,
last_name: req.body.last_name,
mob_no: req.body.mob_no,
user_name: req.body.user_name,
password: req.body.password
});
// Save User in the database
User.create(user, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while creating the User."
});
else res.send(data);
});
};
exports.authenticate = (req,res) => {
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!"
});
}
const user = new User({
user_name: req.body.user_name,
password: req.body.password
});
User.authenticate(user, (err,data) => {
if(err)
res.status(500).send({
message:
err.message || "Some error occurred while authenticating the User."
});
else {
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400 // 24 hours
});
// res.send(data);
res.status(200).send({
id: data.id,
username: data.user_name,
accessToken: token
});
}
});
};
exports.ensureToken = (req, res, next) => {
let token = req.headers["x-access-token"];
if (!token) {
return res.status(403).send({
message: "No token provided!"
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!"
});
}
req.userId = decoded.id;
next();
});
}
user.routes.js
module.exports = app => {
const users = require("../controllers/user.controller.js");
// Create a new User
app.post("/User", users.create);
// Login
app.post("/User/Login", users.authenticate);
};
account.model.js
const bcrypt = require("bcrypt");
module.exports = (sequelize, Sequelize) => {
const Account = sequelize.define("account", {
firstName: {
type: Sequelize.STRING
},
username: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING,
set(value){
const hash = bcrypt.hashSync(value, 10);
this.setDataValue('password', hash);
}
}
});
return Account;
};
account.controller.js
const db = require("../models");
const Account = db.accounts;
const Op = db.Sequelize.Op;
var jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
// Create and Save a new New
exports.create = (req, res) => {
// Validate request
if (!req.body.username) {
res.status(400).send({
message: "Content can not be empty!"
});
return;
}
// Create a Site
const account = {
firstName: req.body.firstName,
username: req.body.username,
password: req.body.password
};
Account.create(account)
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while creating the Account."
});
});
};
exports.authenticate = (req,res) => {
if (!req.body) {
res.status(400).send({
message: "Content can not be empty!"
});
}
const account = new Account({
username: req.body.username,
password: req.body.password
});
};
account.routes.js
module.exports = app => {
const accounts = require("../controllers/account.controller.js");
var router = require("express").Router();
app.post("/account", accounts.create);
app.post("/account/Login", accounts.authenticate);
};
you need to use jwt token for access token as you said and you are bcrypt password in model file which will be security issue you have to bcrypt password as soon as it comes in request I have implemented it in my answer remove code of password bcrypt from your model file
you have to import in your account.controller.js
const db = require("../models");
const User = db.user;
require('dotenv').config();
const Op = db.Sequelize.Op;
const errors = require('../config/errors');
const error = errors.errors;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
module.exports = {
signup: async (req, res) => {
if (!req.body.first_name|| !req.body.lastt_name || !req.body.password) {
return res.status(200).send(error.MANDATORY_FIELDS);
}
try {
// Save User to Database
User.create({
name: req.body.name,
email: req.body.email,
mo_no: req.body.mo_no,
city: req.body.city,
password: bcrypt.hashSync(req.body.password, 8),
user_type: "admin"
}).then(function (user) {
return res.status(200).send(error.OK)
})
.catch(function (err) {
console.log(err);
return res.status(500).send(error.SERVER_ERROR)
});
} catch (e) {
console.log(e);
return res.status(500).send(error.SERVER_ERROR)
}
},
signin: async (req, res) => {
if (!req.body.email || !req.body.password) {
return res.status(200).send(error.MANDATORY_FIELDS);
}
User.findOne({
where: {
email: req.body.email
}
}).then(function (user) {
if (!user) {
return res.status(404).send(error.USER_NOT_PRESENT);
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(422).send(error.PASSWORD_MISSMATCH, {
accessToken: null
});
}
const token = jwt.sign({ id: user.id, first_name: user.first_name },
process.env.secret, {
expiresIn: 86400 // 24 hours
});
const authorities = [];
return res.status(200).send({
id: user.id,
name: user.name,
email: user.email,
accessToken: token
});
});
})
.catch(function (err) {
console.log(err)
return res.status(500).send(error.SERVER_ERROR);
});
}
}
than you have to create a separate folder for authorization like authorize.js or authJwt.js where you have to check is token is valid or not put this code in authorize.js
at decoding time secret token or password also needed which you have in .env file
const jwt = require("jsonwebtoken");
verifyToken = (req, res, next) => {
let token = req.headers["x-access-token"];
if (!token) {
return res.status(403).send(error.TOKEN_NOT_PROVIDED);
}
jwt.verify(token, process.env.secret, (err, decoded) => {
if (err) {
return res.status(401).send(error.UNAUTHORIZED);
}
req.first_name= decoded.first_name;
req.id = decoded.user_id
next();
});
};
const authJwt = {
verifyToken: verifyToken
};
module.exports = authJwt;
than you have to import authorize.js file in your routes whenever you want like this
const authorize = require('../authorize.js');
module.exports = app => {
const accounts = require("../controllers/account.controller.js");
var router = require("express").Router();
app.post("/account", accounts.create);
app.post("/account/Login",
authorize.verifyToken,accounts.authenticate);
};
it will be more effective if you genreate access token at signin time

ExpressJS - Unhandled rejection Error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am able to register and login to the application but I receive the following server error:
"Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client" upon registration. I came across similar questions here but none of them resolved my problem.
authController.js:
const User = require("../models/User");
const jwt = require("jsonwebtoken");
const simplecrypt = require("simplecrypt");
const sc = simplecrypt();
process.env.SECRET_KEY = "secret";
exports.postLogin = (req, res, next) => {
const { username, password } = req.body;
let validationMessages = [];
if (!username || !password) {
validationMessages.push({ message: "Please fill in all fields" });
}
if (password.length < 6) {
validationMessages.push({
message: "Password should be at least 6 characters"
});
}
if (validationMessages.length > 0) {
res.sendStatus(403).json(validationMessages);
} else {
User.findOne({ where: { username: username } })
.then(user => {
if (!user) {
res.sendStatus(400).json({
message: "Invalid username or password"
});
} else if (password == sc.decrypt(user.password)) {
const token = jwt.sign(user.dataValues, process.env.SECRET_KEY, {
expiresIn: 1440 // expires in 24 hours
});
res.send(token);
}
})
.catch(err => {
res.send("Error: " + err);
});
}
};
exports.postRegister = (req, res, next) => {
const { username, password, password2 } = req.body;
let validationMessages = [];
//Check required fields
if (!username || !password || !password2) {
validationMessages.push({ message: "Please fill in all fields" });
}
if (password.length < 6 || password2.length < 6) {
validationMessages.push({
message: "Password should be at least 6 characters"
});
}
if (password !== password2) {
validationMessages.push({
message: "Passwords do not match"
});
}
if (validationMessages.length > 0) {
return res.sendStatus(400).json(validationMessages);
} else {
User.findOne({ where: { username: username } })
.then(user => {
if (user) {
return res.sendStatus(403).json("User already exists");
}
const hashedPassword = sc.encrypt(password);
User.create({ username: username, password: hashedPassword })
.then(user => {
return res.sendStatus(200).send(user);
})
.catch(err => {
throw new Error(err);
});
})
.catch(err => {
throw new Error(err);
});
}
};
exports.getProfile = (req, res, next) => {
const decoded = jwt.verify(
req.headers["authorization"],
process.env.SECRET_KEY
);
User.findOne({
where: {
id: decoded.id
}
})
.then(user => {
if (user) {
res.statusCode(200).json(user);
} else {
throw new Error("User does not exist");
}
})
.catch(err => {
throw new Error(err);
});
};
I am using Node.JS v12.14.0 and Express.JS v4.17.1.
I resolved it myself. My problem was using res.sendStatus which sets the given response HTTP status code and sends its string representation as the response body. res.json will set the content-type response header, but at time time the response will already have been sent to the client. So simply res.send() should replace res.sendStatus().

Update a property in document in an Express route (Mongoose, MongoDB, Express)

I've successfully set up the registration and login functionality using Express, MongoDB and Mongoose.
I would like to log when the user last visited the site once the user's credential is accepted in a lastConnection property of the user document,
I tried but "lastConnection" is null (see the line below where I add a comment)
router.post("/login", async function(req, res) {
const { errors, isValid } = validateLoginInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
const user = await User.findOne({ email }).then(user => {
if (!user) {
errors.email = "Email already exists";
}
console.log("user ", user); <-- returns an object with the datas of user
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
const payload = {
id: user.id,
name: user.name
};
user.lastConnection = new Date(); <-- doesn't work
jwt.sign(
payload,
keys.secretOrKey,
{
expiresIn: 7200
},
(err, token) => {
res.json({
success: true,
token: "Bearer " + token
});
}
);
} else {
errors.password = "Password is not correct";
// return res
// .status(400)
// .json({ passwordincorrect: "Password incorrect" });
}
});
});
return {
errors,
isValid: isEmpty(errors)
};
});
Any ideas? I think I have to do an update but I don't know where to put it
Try replacing user.lastConnection = new Date(); with
user.update({ lastConnection: new Date() })
.then( updatedUser => {
console.log(updatedUser)
// put jwt.sign code here
})

ExpressJS: Can't set headers after they are sent

I have an API in ExpressJS. Within that API I have a login endpoint, when posting to that endpoint however I keep getting the exception that headers cannot be set after they have been sent.
I understand this is normally a callback that is being called twice or not properly returning from something that has set headers, causing the app to attempt to set them again, however in my /login endpoint I am not doing this.
I cannot understand why this happening, I would love some input as to why as I am close to pulling my hair out reading the same replies and answers. I hope it is something obvious I am missing.
import User from '../../models/user';
import { Router } from 'express';
import jwt from 'jsonwebtoken';
export default () => {
const route = Router();
route.post('/create', async (req, res, next) => {
if (!req.body.email || !req.body.password) {
return res
.status(400)
.json({ message: 'username or password is missing' });
}
const { email, password } = req.body;
const count = await User.count({ email });
if (count > 0) {
return res.status(409).json({ message: 'email must be unique' });
}
const newUser = await new User({ email, password });
const doc = await newUser.save();
return res.status(201).json({ type: 'account', attributes: doc });
});
route.post('/login', async (req, res, next) => {
if (req.body.email && req.body.password) {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user) {
user.comparePassword(password, isMatch => {
if (isMatch) {
const token = jwt.sign(
{ sub: user.id, roles: [], email: user.email },
process.env.SECRET_KEY,
{ expiresIn: '12h' },
);
return res
.status(200)
.json({ type: 'account', attributes: { token } });
}
});
}
}
res.sendStatus(401);
});
return route;
};
import User from '../../models/user';
import { Router } from 'express';
import jwt from 'jsonwebtoken';
export default () => {
const route = Router();
route.post('/create', async (req, res, next) => {
if (!req.body.email || !req.body.password) {
return res
.status(400)
.json({ message: 'username or password is missing' });
}
const { email, password } = req.body;
const count = await User.count({ email });
if (count > 0) {
return res.status(409).json({ message: 'email must be unique' });
}
const newUser = await new User({ email, password });
const doc = await newUser.save();
return res.status(201).json({ type: 'account', attributes: doc });
});
route.post('/login', async (req, res, next) => {
if (req.body.email && req.body.password) {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user) {
return user.comparePassword(password, isMatch => {
if (isMatch) {
const token = jwt.sign(
{ sub: user.id, roles: [], email: user.email },
process.env.SECRET_KEY,
{ expiresIn: '12h' },
);
return res
.status(200)
.json({ type: 'account', attributes: { token } });
} else {
return res.status(400)
.json({ message: 'username or password is invalid' });
}
});
}
}
res.sendStatus(401);
});
return route;
};
Have a look at the updated code return was missing at
return user.comparePassword(password, isMatch => {
Hope it'll fix your issue.
The problem in here. Your callback in comparePassword return only inside that callback. So the code still run to res.sendStatus(401) and after the callback is done it will run res.status(200).json...
user.comparePassword(password, isMatch => {
if (isMatch) {
const token = jwt.sign(
{ sub: user.id, roles: [], email: user.email },
process.env.SECRET_KEY,
{ expiresIn: '12h' },
);
return res
.status(200)
.json({ type: 'account', attributes: { token } });
}
});
Try to promisify comparePassword method in the user model:
userSchema.methods.comparePassword = function (password) {
return new Promise( function(resolve, reject) {
resolve(password === this.password);
});
}
Now you can use await syntax to get the promise result:
route.post('/login', async (req, res, next) => {
if (req.body.email && req.body.password) {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user) {
const isMatch = await user.comparePassword(password);
if (isMatch) {
const token = jwt.sign(
{ sub: user.id, roles: [], email: user.email },
process.env.SECRET_KEY,
{ expiresIn: '12h' },
);
return res
.status(200)
.json({ type: 'account', attributes: { token } });
}
}
}
res.sendStatus(401);
});

Resources