I tried to build a simple web with express.
I use postman to post some data in mysql.
But when I tried to use sql query the data showed undefined.
Here's my code.
login.js
const db = require('./connection_db');
module.exports = function memberLogin(memberData) {
let result = {};
return new Promise((resolve, reject) => {
db.query('SELECT * FROM member_info WHERE email = ? AND password = ?', [memberData.email, memberData.password], function (err, rows) {
if (err) {
result.status = "fail to login"
result.err = "please try again later"
reject(result);
return;
}
resolve(rows);
});
});
}
part of controller.js
const memberData = {
name: req.body.name,
email: req.body.email,
password: req.body.password,
birthday: req.body.birthday
}
loginAction(memberData).then(rows => {
if (check.checkNull(rows) === true) {
res.json({
result: {
status: "fail to login",
err: "please try again"
}
})
} else if (check.checkNull(rows) === false) {
res.json({
result: {
status: "success",
loginMember: "welcome " + rows[0].name + " login!",
}
})
}
})
Related
I've been struggling with Bcrypt on my MERN project I'm trying to create an authentication system I'm trying to run tests on Postman and I'm not sure why do I keep getting the error: "Illegal arguments: undefined, string at Object.bcrypt.hashSync"
this is my postman request:
this is the Controller Code:
const config = require("../config/auth.config");
const db = require("../models");
const User = db.user;
const Role = db.role;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
exports.signup = (req, res) => {
const user = new User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
user.save((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (req.body.roles) {
Role.find(
{
name: { $in: req.body.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = roles.map((role) => role._id);
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
}
);
} else {
Role.findOne({ name: "user" }, (err, role) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = [role._id];
user.save((err) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({ message: "User was registered successfully!" });
});
});
}
});
};
exports.signin = (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password!" });
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
email: user.email,
roles: authorities,
});
});
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({ message: "You've been signed out!" });
} catch (err) {
this.next(err);
}
};
The error message:
Illegal arguments: undefined, string at Object.bcrypt.hashSync wants to say that you're passing undefined as an argument to the hashSync function. We need to fix this error.
Take a closer look at this line where the error occurs:
password: bcrypt.hashSync(req.body.password, 8),
req.body.password is undefined, you can verify it by console.log(req.body.password). What's wrong is that you are sending data as URL parameters. So req.body is an empty object and req.body.password is undefined.
In Postman, select the Body tab, choose JSON format, then type your data as a JSON object. Then, in your code, use express.json() middleware to parse requests in JSON format. You'll have the desired output.
You can see my example request in Postman below:
I am very new to both nodeJS and React, and am currently trying to get my head around user authentication. I am able to register new users and login to my backend via postman/rapid api, but cannot login correctly via my react front end. Code below:
Front End Requests
import axios from 'axios'
import {AuthModel, UserModel} from './_models'
const API_URL = process.env.REACT_APP_API_URL
export const GET_USER_BY_ACCESSTOKEN_URL = `${API_URL}/auth/signin`
export const LOGIN_URL = `${API_URL}/auth/signin`
export const REGISTER_URL = `${API_URL}/auth/signup`
export const REQUEST_PASSWORD_URL = `${API_URL}/forgot_password`
// Server should return AuthModel
export function login(email: string, password: string) {
return axios.post<AuthModel>(LOGIN_URL, {
email,
password,
})
}
// Server should return AuthModel
export function register(
email: string,
firstname: string,
lastname: string,
password: string,
password_confirmation: string
) {
return axios.post(REGISTER_URL, {
email,
firstname: firstname,
lastname: lastname,
password,
password_confirmation,
})
}
// Server should return object => { result: boolean } (Is Email in DB)
export function requestPassword(email: string) {
return axios.post<{result: boolean}>(REQUEST_PASSWORD_URL, {
email,
})
}
export function getUserByToken(token: string) {
return axios.post<UserModel>(GET_USER_BY_ACCESSTOKEN_URL, {
api_token: token,
})
}
Backend:
const jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
const db = require("../models");
const User = db.user;
const Role = db.role;
verifyToken = (req, res, next) => {
let token = req.session.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();
});
};
isAdmin = (req, res, next) => {
User.findById(req.userId).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
Role.find(
{
_id: { $in: user.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "admin") {
next();
return;
}
}
res.status(403).send({ message: "Require Admin Role!" });
return;
}
);
});
};
isModerator = (req, res, next) => {
User.findById(req.userId).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
Role.find(
{
_id: { $in: user.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "moderator") {
next();
return;
}
}
res.status(403).send({ message: "Require Moderator Role!" });
return;
}
);
});
};
const authJwt = {
verifyToken,
isAdmin,
isModerator,
};
module.exports = authJwt;
const config = require("../config/auth.config");
const db = require("../models");
const User = db.user;
const Role = db.role;
var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");
exports.signup = (req, res) => {
const user = new User({
username: req.body.email,
firstname: req.body.firstname,
lastname: req.body.lastname,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
user.save((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (req.body.roles) {
Role.find(
{
name: { $in: req.body.roles },
},
(err, roles) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = roles.map((role) => role._id);
user.save((err,data) => {
if (err) {
res.status(500).send({ message: err });
return;
}
res.send({message: "User registered successfully?"});
});
}
);
} else {
Role.findOne({ name: "user" }, (err, role) => {
if (err) {
res.status(500).send({ message: err });
return;
}
user.roles = [role._id];
user.save((err,data) => {
if (err) {
res.status(500).send({ message: err });
return;
}
var token = jwt.sign({ id: data._id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
// This is what I mean
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
});
//res.send({message: "User registered successfully? No 2"});
});
});
}
});
};
exports.signin = (req, res) => {
User.findOne({
username: req.body.email,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({ message: "Invalid Password!" });
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
req.session.token = token;
res.status(200).send({
id: user._id,
username: user.username,
firstname: user.firstname,
lastname: user.lastname,
email: user.email,
roles: authorities,
});
});
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({ message: "You've been signed out!" });
} catch (err) {
this.next(err);
}
};
exports.allAccess = (req, res) => {
res.status(200).send("Public Content.");
};
exports.userBoard = (req, res) => {
res.status(200).send("User Content.");
};
exports.adminBoard = (req, res) => {
res.status(200).send("Admin Content.");
};
exports.moderatorBoard = (req, res) => {
res.status(200).send("Moderator Content.");
};
Any guidance would be greatly appreciated!
I am writing an Express endpoint in Typescript to update a user's password in the database, but having some trouble with multiple queries/synchronous code.
My problem is right now I am trying to await the return of a function but it doesn't seem to be awaiting.
My route looks like this:
router.put("/:userId", validateUser, async (req: any, res: Response) => {
const result: any = await updatePassword(req.body.password, req.body.confirmPassword, req.params.userId);
console.log(result) //LOGS UNDEFINED????
if (result.status !== 200) res.status(result.status).send({ message: result.message, code: result.code });
res.send("Success!");
});
and that updatePassword function looks like this:
const updatePassword = async (password: string, confirmPassword: string, userId: string) => {
if (password !== confirmPassword) {
return { status: 409, message: Errors.mismatchingPasswordMessage, code: Errors.mismatchingPasswordCode };
}
const hashedPassword = bcrypt.hashSync(password, 10);
//update the password in the DB
pool.query("UPDATE users SET password = ? WHERE userId = ?", [hashedPassword, userId], (err: MysqlError, result: any) => {
if (err) {
console.log(err);
return { status: 500, message: err.message, code: err.code };
}
if (result.changedRows !== 1) {
return { status: 500, message: "Password could not be updated!" };
}
return { status: 200 };
});
}
Why is this the route not correctly awaiting the result of updatePassword??
Thanks in advance for any help.
The problem is, you're mixing async/await and callback style in this part
pool.query("UPDATE users SET password = ? WHERE userId = ?", [hashedPassword, userId], (err: MysqlError, result: any) => {
if (err) {
console.log(err);
return { status: 500, message: err.message, code: err.code };
}
if (result.changedRows !== 1) {
return { status: 500, message: "Password could not be updated!" };
}
return { status: 200 };
});
The function updatePassword jumps directly to the next line after this block, which is nothing. So it returns undefined.
You need to replace this block with async/await code. Something like :
try {
const result = await pool.query("UPDATE users SET password = ? WHERE userId = ?", [hashedPassword, userId]);
if (result.changedRows !== 1) {
return { status: 500, message: "Password could not be updated!" };
}
return { status: 200 };
}
catch (err){
console.log(err);
return { status: 500, message: err.message, code: err.code };
}
I'm trying to upload files to my database but I'm having trouble.
When I try to upload a file to my database I got this error :
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
And the data from my file is not save to my database (see the image) :
I think my problem is here :
const fileData = {
type: req.body.type,
name: req.body.name,
data: req.body.data
};
I tried to copy the function I use for create a user when he register but for a file when someone upload it.
Register (it works) :
users.post("/register", (req, res) => {
const today = new Date();
const userData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
phone: req.body.phone,
deliveryAddress: req.body.deliveryAddress,
created: today
};
User.findOne({
where: {
email: req.body.email
}
})
//TODO bcrypt
.then(user => {
if (!user) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
userData.password = hash;
User.create(userData)
.then(user => {
res.json({ status: user.email + " registered!" });
})
.catch(err => {
res.send("error: " + err);
});
});
} else {
res.status(400).json({ error: "Email already taken" });
console.log("Email already taken !");
}
})
.catch(err => {
res.status(400).json("Error : " + err);
});
});
File upload (not working) :
app.post("/files", (req, res) => {
const uploadFile = req.files.file;
const fileName = req.files.file.name;
const fileData = {
type: req.body.type,
name: req.body.name,
data: req.body.data
};
uploadFile.mv(`./uploads/${fileName}`, function(err) {
if (err) {
return res.status(500).send(err);
}
res.json({
file: `uploads/${fileName}`
});
});
Upload.findOne({
where: {
name: req.body.name
}
})
.then(file => {
if (!file) {
Upload.create(fileData)
.then(file => {
res.json({ status: file.name + " created !" });
})
.catch(err => {
res.send("error: " + err);
});
} else {
res.status(400).json({ error: "File already uploaded" });
console.log("File already uploaded");
}
})
.catch(err => {
res.status(400).json("Error : " + err);
});
});
I'm not very familiar with backend so...
I tried to change :
const fileData = {
type: req.body.type,
name: req.body.name,
data: req.body.data
};
with
const fileData = {
type: req.files.file.type,
name: req.files.file.name,
data: req.files.file.data
};
But I got an infinite loop and the file is not uploaded to my database (nothing is created).
The upload to the backend (uploads folder) works.
EDIT
When I use req.files.file.something for the fileData it works sometimes, the file is correctly uploaded to database but I got the error again (I think it works when the file is very tiny).
For a 1 Ko file :
Executing (default): INSERT INTO `files` (`id`,`name`,`data`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'a suprimer.html',X'3c21444f43545950452068746d6c3e0d0a0d0a3c21444f43545950452068746d6c3e0d0a3c68746d6c3e0d0a3c686561643e200d0a093c6d65746120636861727365743d227574662d38223e0d0a093c7469746c653e20466169726520756e6520696d6167653c2f7469746c653e0d0a3c2f686561643e0d0a3c626f64793e0d0a0d0a093c703e746573743c2f703e0d0a0d0a093c696d67207372633d2268642e696d6167652e736e6f772e6a706567223e0d0a090d0a0d0a3c2f626f64793e0d0a3c2f68746d6c3e','2020-01-29 10:07:28','2020-01-29 10:07:28');
And in the database :
Why the type is not set up ?
How can I reduce the time of the upload for a bigger file ?
You can try this code below:
app.post("/files", (req, res) => {
const uploadFile = req.files.file;
const fileName = req.files.file.name;
const fileData = {
type: req.body.type,
name: req.body.name,
data: req.body.data
};
Upload.findOne({
where: {
name: req.body.name
}
}).then(file => {
if (!file) {
// upload file to directory
uploadFile.mv(`./uploads/${fileName}`);
// save file to database
Upload.create(fileData)
.then(file => {
return res.json({ status: file.name + " created !" });
}).catch(err => {
return res.send("error: " + err);
});
} else {
return res.status(400).json({ error: "File already uploaded" });
}
})
.catch(err => {
return res.status(400).json("Error : " + err);
});
});
I hope it can help you to upload your file.
I believe this is because you are trying to send two responses in the same call handler. Once in uploadfile.mv then again in Upload.findOne. You cannot return two res.X to the same request.
This thread might be useful: Error: Can't set headers after they are sent to the client
app.post('/sign-up', function (req, res) {
let emailValid = validator.validate(req.body.email);
let consent = req.body.consent ? true:false
if(emailValid && consent) {
const user = new UserModel({
name: req.body.firstName,
surname: req.body.surname,
email: req.body.email
})
UserModel.find({'email': req.body.email}, function(notFound, found) {
if(notFound) {
user.save().then(item => {
console.log('Saved successfully!');
res.render('submitSuccess', {data: req.body});
}).catch(err => {
res.status(400).render('404');
})
} else if(found) {
console.log('Exists');
res.status(404).render('submitSuccess', {data:req.body});
}
else {
res.status(404).render('404');
}
});
}
});
The intended functionality here is that if someone submits an email to the database that already exists, it does not then save a duplicate. However, it seems that found is returning true everytime, therefore nothing is getting saved.
Run this code:
app.post('/sign-up', function (req, res) {
let emailValid = validator.validate(req.body.email);
let consent = req.body.consent ? true : false
if (emailValid && consent) {
const user = new UserModel({
name: req.body.firstName,
surname: req.body.surname,
email: req.body.email
})
UserModel.find({ 'email': req.body.email }, function (err, found) {
if (err) {
console.error(err);
res.status(500).end();
return;
}
if (found.length == 0) {
user.save().then(item => {
console.log('Saved successfully!');
res.render('submitSuccess', { data: req.body });
}).catch(err => {
res.status(400).render('404');
})
} else {
console.log('Exists');
res.status(404).render('submitSuccess', { data: req.body });
}
});
}
});
What's in the err?