I have a problem with this code. I would appreciate it very much if someone could help me with this. If you have any missing information feel free to ask. Note: Iam using mysql2.
router.get('/restaurants/:name/:location/dashboard', userContoller.isLoggedInAdmin, async (req, res) => {
const restaurantName = req.params.name;
const restaurantLocation = req.params.location;
console.log(`restaurantName: ${restaurantName}`);
console.log(`restaurantLocation: ${restaurantLocation}`);
try {
// Query the database to retrieve the owner's information and the information for the specific restaurant
const [ownerRows] = await db.promise().query(
'SELECT * FROM owner WHERE id = (SELECT owner_id FROM restaurant WHERE name = ? AND location = ?)',
[restaurantName, restaurantLocation]
);
const [restaurantRows] = await db.promise().query(
'SELECT * FROM restaurant WHERE name = ? AND location = ?',
[restaurantName, restaurantLocation]
);
console.log(`ownerRows: ${JSON.stringify(ownerRows)}`);
console.log(`restaurantRows: ${JSON.stringify(restaurantRows)}`);
const owner = ownerRows[0];
const restaurant = restaurantRows[0];
console.log(`owner: ${JSON.stringify(owner)}`);
console.log(`restaurant: ${JSON.stringify(restaurant)}`);
// Check if the owner is logged in and has permission to access the dashboard
if (req.owner && req.owner.id === restaurant.owner_id) {
// Render the dashboard template and pass the owner's information and information for the specific restaurant to it
res.render('role/admin/index', { owner: owner, restaurant: restaurant });
} else {
console.log('Owner not granted access to dashboard');
// Redirect the owner to the login page
res.render('errors/no permission');
}
} catch (error) {
console.error(error);
res.sendStatus(500);
}
});
So I have this route and I want it to work. I have a user, owner and a restaurant table. In the owner table is the owner id and the user id as a foreign key referencing to the primary key in the user table. In the restaurant table there is a column called owner_id which is a foreign key referencing to the primary key in the owner table. What this basically means is that the user is the owner/admin of one or more restaurants. The problem is that somehow the owner does not have access to the restaurant even though he is connected with it.
Here is the middleware:
exports.isLoggedInAdmin = async (req, res, next) => {
console.log('isLoggedInAdmin middleware called');
if (req.cookies.one) {
try {
const decode = await jwt.verify(req.cookies.one, process.env.JWT_SECRET);
const [user] = await db.promise().query("SELECT * FROM user WHERE id = ?", [decode.id]);
if (!user) {
return res.status(401).json({ message: "Unauthorized" });
}
const [owner] = await db.promise().query("SELECT * FROM owner WHERE user_id = ?", [decode.id]);
if (!owner) {
return res.status(401).json({ message: "Unauthorized" });
}
if (user.id !== owner.user_id) {
return res.status(401).json({ message: "Unauthorized" });
}
console.log('Owner found:', owner);
req.owner = {
id: owner.id,
user_id: owner.user_id,
};
next();
} catch (error) {
console.error(error);
return res.status(401).json({ message: "Unauthorized" });
}
} else {
console.log('No owner found');
next();
}
};
Here is the login system (focus on the cookie for the owner):
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).render("login", {
msg: "Please Enter Your Email and Password",
msg_type: "error",
});
}
db.query(
"select * from user where email=?",
[email],
async (error, result) => {
console.log(result);
if (result.length <= 0) {
return res.status(401).render("login", {
msg: "Please Enter Your Email and Password",
msg_type: "error",
});
} else {
if (!(await bcrypt.compare(password, result[0].password))) {
return res.status(401).render("login", {
msg: "Please Enter Your Email and Password",
msg_type: "error",
});
} else {
const id = result[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,
};
// Check if the user is in the owner table
db.query("SELECT * FROM owner WHERE user_id=?", [id], (error, result) => {
if (result.length > 0) {
// Set the cookie for owner
res.cookie("one", token, cookieOptions);
res.status(200).redirect("/restaurants/:name/:location/dashboard");
} else {
// Check if the user is in the manager table
db.query("SELECT * FROM manager WHERE user_id=?", [id], (error, result) => {
if (result.length > 0) {
// Set the cookie for manager
res.cookie("two", token, cookieOptions);
res.status(200).redirect("/manager/dashboard");
} else {
// Check if the user is in the cook table
db.query("SELECT * FROM cook WHERE user_id=?", [id], (error, result) => {
if (result.length > 0) {
// Set the cookie for cook
res.cookie("three", token, cookieOptions);
res.status(200).redirect("/cook/dashboard");
} else {
// Check if the user is in the waiter table
db.query("SELECT * FROM waiter WHERE user_id=?", [id], (error, result) => {
if (result.length > 0) {
// Set the cookie for waiter
res.cookie("four", token, cookieOptions);
res.status(200).redirect("/waiter/dashboard");
}
});
}
});
}
});
}
});
}
}
}
);
} catch (error) {
console.log(error);
}
};
Here is the log:
isLoggedInAdmin middleware called
Owner found: [ { id: 7, user_id: 42 } ]
restaurantName: BLOCKHOUSE
restaurantLocation: Pakistan
ownerRows: [{"id":7,"user_id":42}]
restaurantRows: [{"id":40,"name":"BLOCKHOUSE","location":"Pakistan","email":"2021erik.mettner#gmail.com","phonenumber":"012386763618","owner_id":7}]
owner: {"id":7,"user_id":42}
restaurant: {"id":40,"name":"BLOCKHOUSE","location":"Pakistan","email":"2021erik.mettner#gmail.com","phonenumber":"012386763618","owner_id":7}
Owner not granted access to dashboard
I know where the problem is. It is here:
// Check if the owner is logged in and has permission to access the dashboard
if (req.owner && req.owner.id === restaurant.owner_id)
My Problem is that I dont know how to fix it. I want that the owner can access his restaurants. Only he, not any other owner.
Related
When I try to use an invalid email address in the login form, the app crashes saying: Cannot read properties of undefined (reading 'password').
You can see my auth.js's login part below:
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);
}
}
It should show the same line that I can see when I use an incorrect password (That part works just fine).
message: 'Email or password is incorrect.'
If the email is invalid, the query will return an empty array, not an undefined, meaning that your check is wrong - you should check the length of the array.
Of course, you can always leave the check that result is defined just to be on the safe side:
if( !results || !results.length || !(await bcrypt.compare(password, results[0].password) ) ) {
res.status(401).render('login', {
message: 'Email or password is incorrect.'
});
} else {
Below is the code snippet of a system which is asking email and password to Login into the system. The below code is always showing error that "email or password is incorrect" even if they are correct. I am using NodeJS and MySQL database, Please help!
exports.afterLogin = async (req, res) => {
try {
const { email, password } = req.body;
db.query('Select * FROM patient WHERE email= ?', [email], async (error, results) => {
const verified = bcrypt.compareSync(password,results[0].password);
if(error){
console.log(error);
}
//console.log(results);
else if (!results || !verified) {
res.status(400).render('patientLogin', {
message: 'Email or password is incorrect!',
messageClass:'alert-warning'
});
}
else {
//creating session
db.query('select * from patient where email=?',[email],(err,result)=>{
if(err)
{
console.log(err);
}else{
sess=req.session;
sess.patient={};
sess.patient.city=result[0].city;
sess.patient.name=result[0].first_name;
sess.patient.ids=result[0].patient_id;
// console.log(sess.patient);
patientSess=Object.assign(sess.patient);
// console.log(patientSess);
}
});
const id = results[0].id;
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("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("/searchDoctor");
}
})
} catch (error) {
console.log(error);
}
}
router.get('/profilePage/:userid', function(req, res) {
var userid = req.session.user
console.log(userid)
if (!userid) {
//No user id provided
} else {
pool.query('SELECT * from users where id = ?',
[userid],
(error, results, feilds)=> {
if (error) {
console.log("error ocurred while getting user details of " + userid, error);
res.send({
"code": 400,
"failed": "error ocurred"
});
} else {
if (results.length > 0) {
const profile = results[0]
//You can then access the user id with
console.log(profile.fullname)
res.render("profilePage",{profile});
} else {
console.log('unable to retrieve a profile')
}
}
});
}
});
how can I make the userid = logged-in user? I tried many ways such as sessions (var userid = req.session.user) but all did not work what is the correct way to make the userid = to logged-in user id?
I'm having a hard time with integrating bcrypt to try to make my login system safe.
I basically get the username, password the user inputs and try to compare it from the hashed password in my db. here's what I have.
const inputUsername = req.body.inputUsername;
const inputPassword = req.body.inputPassword;
var userLogin = "select * from login where USERNAME = ?"
ibmdb.open(ibmdbconnMaster, function(err, conn) {
if (err) return console.log(err);
conn.query(userLogin, [inputUsername], function(err, rows) {
if (err) {
console.log(err)
}
if (rows.length > 0) {
var pass = ""
for (var i = 0; i < rows.length; i++) {
pass = rows[i]['PASSWORD'];
console.log(pass)
bcrypt.compare(inputPassword, hash, function(err, result) {
if (pass == result) {
console.log("this works")
userAuth = true;
res.redirect('/index')
}
})
}
console.log("does not work")
} else {
userAuth = "false";
res.render('login.ejs')
alert('Incorrect username or password. Please try again')
}
conn.close(function() {
console.log('closed the function /login');
});
})
})
what happens right now is I get the error ReferenceError: hash is not defined
not sure how to fix this. thanks in advance
Where have you defined hash? I don't see it in your code.
Here's an example of auth routes that I've used with bcrypt/node/express:
const Users = require("../users/users-model.js");
router.post("/register", (req, res) => {
// Pull the user's credentials from the body of the request.
const user = req.body;
// Hash the user's password, and set the hashed password as the
// user's password in the request.
const hash = bcrypt.hashSync(user.password, 10);
user.password = hash;
Users.add(user)
.then((newUser) => {
const token = generateToken(newUser);
res
.status(201)
.json({ created_user: newUser, token: token, user_id: newUser.id });
})
.catch((err) => {
res.status(500).json({
message: "There was an error adding a user to the database",
err,
});
});
});
router.post("/login", (req, res) => {
const { username, password } = req.body;
Users.findBy({ username })
.first()
.then((user) => {
if (user && bcrypt.compareSync(password, user.password)) {
const token = generateToken(user);
res
.status(200)
.json({
username: user.username,
first_name: user.first_name,
last_name: user.last_name,
email: user.email,
token: token,
user_id: user.id,
});
} else {
res.status(401).json({ message: "Invalid Credentials" });
}
})
.catch((err) => {
res.status(500).json(err);
});
});
function generateToken(user) {
const payload = {
userid: user.id,
username: user.username,
};
const options = {
expiresIn: "1h",
};
const token = jwt.sign(payload, secrets.jwtSecret, options);
return token;
}
module.exports = router;
I'm new in making API. I use Node.js and MySQL.
The fact is I have two GET function to get all users and one to get user by ID.
Both function are working when they are alone implemented. If both of them are implemented the function to get all user try to enter in the function to get user by ID so the API crash.
So here is my model users.js
var connection = require("../connection");
function Users()
{
//GET ALL USERS
this.get = function(res)
{
console.log('Request without id');
connection.acquire(function(err, con)
{
con.query('SELECT * FROM users', function(err, result)
{
con.release();
if (err)
res.send({status: 1, message: 'Failed to get users'})
else
res.send(result);
});
});
}
//GET USER BY ID
this.get = function(id, res)
{
console.log('Request with ID');
connection.acquire(function(err, con)
{
if (id != null)
{
con.query('SELECT * FROM users WHERE id = ?', id, function(err, result)
{
con.release();
if (err)
res.send({status: 1, message: 'Failed to find user: ' + id});
else if (result == "")
res.send({status: 1, message: 'Failed to find user: ' + id});
else
res.send(result);
});
}
});
}
And here is the routes.js
var users = require('./models/users');
module.exports = {
configure: function(app) {
app.get('/users/', function(req, res) {
users.get(res);
});
app.get('/users/:id/', function(req, res) {
users.get(req.params.id, res);
});
Do you have any idea why ?
Thanks for help :)
You can't have two functions with the same name in the same scope.
You have to rename your functions
/**
* Get all users
*/
this.get = function(res) {...}
/**
* Get user by id
*/
this.getById = function(id, res) {...}
Or you can have one function and check if an id is provided
this.get = function(id, res) {
if ( Number.isInteger(id) ) {
// return the user
} else {
res = id;
// return all users
}
}