SQL Parse Error Using JavaScript with Express and MySQL - javascript

I am trying to make a log in system. Right now I am working on allowing the user to register. I am trying to make it so you can't create an account that has the same username or email as another. However, it is giving me a parse error.
Here is the code:
app.post("/create", (req, res) => {
const email = req.body.email;
const username = req.body.username;
const password = req.body.password;
db.query("SELECT email, username FROM users WHERE email = ? AND username = ?"),
[email, username],
(err, result) => {
if (err) {
console.log(err);
} else if (result) {
res.send("Username or Email is already in use.")
} else {
db.query(
"INSERT INTO users (email, username, password) VALUES (?,?,?)",
[email, username, password],
(err, result) => {
if (err) {
console.log(err);
} else {
res.send("Values Inserted");
}
}
);
}
};
});
Here is the error I am getting:
{
code: 'ER_PARSE_ERROR',
errno: 1064,
sqlMessage: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? AND username = ?' at line 1",
sqlState: '42000',
index: 0,
sql: 'SELECT email, username FROM users WHERE email = ? AND username = ?'
}

Related

Cannot read properties of undefined (reading 'id')

I have a auth.js file And a middleware named as fetchuser code given beolow
Can anyone please tell me why am i getting this error.
I am using express js and mongoose but this error is occured during sending token to the user and verify the user whether is user logged in or not.
auth.js
const express = require('express');
const User = require('../models/User');
const router = express.Router();
const { body, validationResult } = require('express-validator');
const bcrypt = require('bcryptjs'); // it is used for password hashing
const jwt = require('jsonwebtoken');
const fetchuser=require('../middleware/fetchuser');
// Route:1 - Create a User using :POST. "/api/auth/createuser". NO Login Required.
router.post('/createuser', [
body('email', 'Enter valid email').isEmail(),
body('name', 'Enter valid email').isLength({ min: 3 }),
body('password').isLength({ min: 5 })
], async (req, res) => {
// Check fo vaidation whether is any rule(defined in User model) breaked or not
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Check Whether user with same email id exist or not
try {
let user = await User.findOne({ email: req.body.email });
if (user) {
return res.status(400).json({ error: "Sorry user with same email id already exist" });
}
// hashing of password
const salt = await bcrypt.genSalt(10);
const securePassword = await bcrypt.hash(req.body.password, salt);
// create A new User
user = await User.create({
name: req.body.name,
email: req.body.email,
password: securePassword
})
// returning user id in Token
const JWT_secret = "Rishiisa#boy";
const data = { user:{id: user.id} };
const auth_token = jwt.sign(data, JWT_secret);
res.json({ auth_token });
}
catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
// Route:2 - Login a User using credential. "/api/auth/login". NO Login Required.
router.post('/login', [
body('email', 'Enter valid email').isEmail(),
body('password', 'password can not be blank').exists(),
], async (req, res) => {
// Check for vaidation according to the rule defined at line no. 53, 54;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// destructure the email and password from body request
const { email, password } = req.body;
try {
// Checking whether email is exist or not
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ error: "Please try to login using correct credentials" });
}
// Now Comparing password with help of bcryptjs
const comparepassword = await bcrypt.compare(password, user.password);
if (!comparepassword) {
return res.status(400).json({ error: "Please try to login using correct credentials" });
}
// Now if user enter coorect password and login then user got logged in;
// And We will send authtoken to user;
// returning user id in Token
const JWT_secret = "Rishiisa#boy";
const data = { user:{id: user.id} };
const auth_token = jwt.sign(data, JWT_secret);
res.json({ auth_token });
}
catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
// Route:3 - Get Loggedin User details using:POST "/api/auth/getuser" Login required
router.post('/getuser', fetchuser, async (req, res) => {
try {
const userid = req.user.id;
const user = await User.findById(userid).select("-password");
res.send(user);
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error");
}
})
module.exports = router
middleware:
fetchuser.js
const jwt = require('jsonwebtoken');
const JWT_secret = "Rishiisa#boy";
const fetchuser = (req, res, next) => {
// Get the user from jwt token and add user id to req object
const token = req.header('auth_token');
if (!token) {
res.status(401).send({ error: "Please authenticate using a valid token" });
}
try {
const data = jwt.verify(token, JWT_secret);
req.user = data.user;
next();
} catch (error) {
res.status(401).send({ error: "Please authenticate using a valid token" });
}
}
module.exports = fetchuser;
In auth.js, where you wrote: "const data = { user:{id: user.id} };" Try changing user.id to user._id, since in MongoDB the user id is referred to as '_id'.
Let me know if that works.
I've had problems sending jwt token back and even verifying it, but all is good on my side now.
Also, below is my (inspired) method of going about this:
router.post('/register', (req, res)=>{
const { username, password } = req.body;
const user = new User({
username,
password
});
bcrypt.genSalt(10, (err, salt)=>{
bcrypt.hash(user.password, salt, (err, hash)=>{
if(err) throw err;
user.password = hash;
user.save()
.then(user=>{
jwt.sign(
{ id: user._id },
process.env.jwtSecret,
{ expiresIn: 3600 },
(err, token) =>{
if(err) throw err;
res.status(200)
}
)
})
})
})
})

login with email or phone or username in node js

How can I login email or phone or username with password in node js and mongodb?
user can login with email and password, username and password, phone and password.
this is like Instagram login module.
here is my script:
const login = catchAsync(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user || !(await user.isPasswordMatch(password))) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Incorrect email or password');
}
const tokens = await tokenService.generateAuthTokens(user.id);
const response = { user: user.transform(), tokens };
res.send(response);
});
What you can try is that don't restrict your code to accept the email only make it general and find the user based on the input like this
const login = catchAsync(async(req, res) => {
const {
userEmailPhone,
password
} = req.body;
//suppose in your DB you have email, phone and username fields
const user = await User.findOne({
$or: [{
"email": userEmailPhone
}, {
"phone": userEmailPhone
}, {
"userName": userEmailPhone
}]
});
if (!user || !(await user.isPasswordMatch(password))) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Incorrect email or password');
}
const tokens = await tokenService.generateAuthTokens(user.id);
const response = {
user: user.transform(),
tokens
};
res.send(response);
});
NOTE: Make sure Email, Phone and Username is unique for every user
Hope this helps
I needed same then I created this simple functionality to allow login with username and password, email and password or phone and password.
There should be a better way or algorithm, but I couldn't find it.
I hope it meets your need.
// authRoutes.js//
// Login route
router.post("/login", loginController);
// authController.js
// Login Controller
export const loginController = async (req, res) => {
if (req.body.userDetail == "" || req.body.password == "")
res.status(400).json("All Fields Are Required!");
try {
let user;
try {
user = await User.findOne({ username: req.body.userDetail });
if (!user) user = await User.findOne({ email: req.body.userDetail });
if (!user) user = await User.findOne({ phone: req.body.userDetail });
const validatedUser = await bcrypt.compare(
req.body.password,
user.password
);
!validatedUser && res.status(403).json("Wrong credentials!");
const { password, ...others } = user._doc;
res.status(200).json(others);
} catch (error) {
res.status(404).json("User Not Found!");
}
} catch (error) {
res.status(500).json("Something Else Went Wrong!");
}
};
First, you need to check if the email and password exist and then you need check if email and password combination is true.
in your case, You can also add a field like a mobile with an email.
const login = catchAsync(async (Request, Response, next) => {
const { email, password } = Request.body;
//check if email and password exists
if (!email || !password) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Please provide email and password');
}
//check if user exist and password correct
const user = await User.findOne({ email }).select('+password');
if (!user || !(await user.isPasswordMatch(password, user.password))) {
throw new ApiError(httpStatus.UNAUTHORIZED, 'Incorrect email or password');
}
//if everything ok, send token to the client
const tokens = await tokenService.generateAuthTokens(user.id);
const response = { user: user.transform(), tokens };
res.send(response);
});
P.S: It is not good practice to throw an error directly. Use a different approach.

Unexpected identifier Syntax Error when using mysql and bcryptjs

I'm using Mysql in my Express app
i hashed users pass using bcryptjs in mysql db and its fine.
using this code :
// register
router.post("/register", async (req, res) => {
const hashed = await bcrypt.hash(req.body.pass, 10);
const user = {
uname: req.body.uname,
phone: req.body.phone,
pass: hashed
};
let sql = "INSERT INTO user SET ? ";
db.query(sql, user, (err, result) => {
if (err) throw err;
console.log(`${user.uname} INSERTED INTO users`);
});
});
// GET USERS
router.get("/users", (req, res) => {
db.query("SELECT * FROM user", (err, results) => {
if (err) {
return res.send(err);
} else {
return res.json({
data: results
});
}
});
});
but when i want to log in users and let bcrypt compare requested pass with user pass it will give me this err :
SyntaxError: Unexpected identifier
And this is what i tried :
// loggin
router.post("/login", async (req, res) => {
var username = req.body.uname;
var password = req.body.pass;
db.query(
"SELECT pass FROM user WHERE uname = ?",
[username],
(err, result, fields) => {
try {
if (await bcrypt.compare(password, result)) {
console.log('Success')
}
} catch {
console.log('catched')
}
}
);
});
💡 The only one reason why you got some error, it's because you're using await in a function without async
👨🏻‍🏫 You can use this code below 👇:
router.post("/login", async (req, res) => {
var username = req.body.uname;
var password = req.body.pass;
db.query(
"SELECT pass FROM user WHERE uname = ?",
[username],
async (err, result, fields) => {
try {
// if you're using mysql2, don't forget to change `result` with `result[0].pass`.
// you can console.log(result) to see where is the field of your password plain text
const isPassword = await bcrypt.compare(password, result);
console.log(isPassword); // true
} catch(ex) {
console.log(ex); // false
}
}
);
});
I hope it's can help you 🙏.

How to allow user login by either username or email using node.js

I have a node.js login system with passport but I am trying to figure out how to log in a user with either their username or email. I am only able to log in the user with email or username seperately. I don't know how to write the code to cater for both their username and email. So if a user wants to login with username, they can or if the wish to use their email, they also can. Here is my localstrategy code in my users.js file:
passport.use(new LocalStrategy(
function(email, password, done) {
User.getUserByEmail(email, function(err, user, next){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
And here's my module.exports in my user.js:
module.exports.getUserByEmail = function(email, callback){
var query = {email: email};
User.findOne(query, callback);
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
The above code only allows user to login with their email. I want users to have the opportunity to login with either their email or username.
Just got into this situation, and I though I'll share my final code to verify user using either username or email:
userSchema.statics.findByCredentials = async credentials => {
const {
email = undefined,
username = undefined,
password = undefined
} = credentials
if ((!!email && !!username) || (!email && !username)) {
throw new Error('Should provide either email or username.')
}
if (!password) {
throw new Error('Password is required.')
}
const user = await User.findOne(email ? { email } : { username })
if (!user) {
throw new Error('Credentials are invalid!')
}
if (!bcrypt.compare(password, user.password)) {
throw new Error('Credentials are invalid!')
}
return user
}
So I am using this function to verify if the user provided valid credentials, and from my handler, I call the function on the model class.
Expect both username and password within your authentication middleware and then proceed with whatever value you have found as the condition to find the user.
Middleware example:
function authenticateUser(req, res, done) {
let username = req.body.username,
password = req.body.password,
email = req.body.email;
let conditions = !!username ? {username: username} : {email: email};
UserModel.findOne(conditions, (err, user) => {
if (err) return done(err);
if (!user) return done(new Error('Incorrect username or email'));
return user.comparePassword(password, user.password)
.then(match => {
if (match) return done();
else return done(new Error('Incorrect password'));
})
.catch(error => {
if (error) return done(new Error(`Unable to validated password. - ${error}`));
});
});
}
Now, a front-end developer — with the right documentation — can now actually use either the username, email or both (you will need a bit of JavaScript for both) when building login forms using your endpoint. Here is an example of using both:
HTML:
<form id="login-form" method="POST" action="/login">
<input id="username-or-email" type="text" placeholder="Username or Email" required/>
<input type="password" name="password" placeholder="Password" required/>
<input type="submit"/>
</form>
JavaScript:
// select the form element
let loginForm = document.querySelector('#login-form');
// add a form handler on submit
loginForm.addEventListener("submit", formHandler);
// validate and the set name attribute as appropriate
function formHandler() {
/** W3C Email regex: (RFC5322) */
const email_regex = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
/** Must starts with a letter then can include underscores (_) & hyphens (-) */
const username_regex = /^[a-zA-Z][\w-]+$/;
let input = document.querySelector('#username-or-email');
if (email_regex.test(input.value)) {
// it is an email, send the value as an email
input.setAttribute("name", "email");
} else if (username_regex.test(input.value)) {
// it is a username, send the value as a username
input.setAttribute("name", "username");
} else {
// invalid email or username format, return an error message to user
}
}
So you get to validate and set your dynamic input at the same time. Keep in mind that the regular expression should match your username and email data model as much as possible.
You can use getUserById inside the callback of getUserByEmail so that both of the queries run for either email or username. If you specify email, then emailOrUserName will have the email value and then User.getUserByEmail will return the user and next it will proceed with comparePassword.
And if you have username then emailOrUserName will have the username value and then User.getUserByEmail will not return the user so, it executes User.getUserById and if the user is found there then it will proceed with User.comparePassword else it will return Unknown user
passport.use(new LocalStrategy(
function(emailOrUserName, password, done) {
User.getUserByEmail(emailOrUserName, function(err, user, next){
if(err) throw err;
if(!user){
User.getUserById(emailOrUserName, function(err, user, next){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user'});
}
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
Do this in local strategy
function(username, password, done) {
var criteria = (username.indexOf('#') === -1) ? {username: username} : {email: username};
User.findOne(criteria, function (err, user) { //implementation }
The code below can be used to allow your users to log in using either their username or email and password:
if (!req.body.username && !req.body.email) {
res.status(400).send({ message: "All input is required, username/email is missing",
status: false });
return;
}
if (!req.body.password) {
res.status(400).send({ message: "All input is required, password is missing",
status: false });
return;
}
let whereClause = {};
if (req.body.email) {
whereClause.email = req.body.email;
} else if (req.body.username) {
whereClause.username = req.body.username.toLowerCase();
}
const user = await User.findOne({ where: whereClause });
// If user not found
if (!user) {
return res.status(404).send({ message: "User not found", status: false });
}
You can wrap it in a try-catch block for proper error handling.
I add little more on the above answer shared by user7153178: Mine is related to the backend, using context.
Inside your Login component in the frontend, try to have these.
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
then you will be needing this function on your form:
const handleSubmit = () => {
const user = {
email,
password,
};
if (email === "" || password === "") {
setError("Please fill in your credentials");
} else {
loginUser(user, context.dispatch);
}
};
this is one of the input as part of your form
<Input
placeholder={"Email or Phone Number"}
name={"email"}
id={"email"}
value={email}
onChangeText={(text) =>
setEmail(text.toLowerCase())}
/>
In the backend write your post like that:
router.post("/login", async (req, res) => {
const user = await User.findOne(
{ $or: [{ email: req.body.email }, { phone:
req.body.email }] }
);
if (!user) {
return res.status(400).send("The user not found");
}
if (user && bcrypt.compareSync(req.body.password,
user.passwordHash)) {
const token = jwt.sign(
{
userId: user.id,
isAdmin: user.isAdmin,
},
secret,
{ expiresIn: "1d" }
);
res.status(200).send({ user: user.email, token:
token });
} else {
res.status(400).send("password is wrong!");
}
});

string interpolation with sqlite3 and Node

Somewhat new to this, but I'm having an issue inserting a variable into my sqlite3 query. I get the error { [Error: SQLITE_ERROR: no such column: shmee] errno: 1, code: 'SQLITE_ERROR' } where shmee in this case is req.body.username
Not sure what I'm doing wrong here? Any guidance?
app.post('/users/login', function (req, res) {
console.log(req.body)
var query = "SELECT username, password FROM users WHERE username = "+req.body.username+";"
db.all(query, function (err, data) {
if (err) {
console.log(err);
} else if (req.body.password === data.password) {
//set cookie with user info
req.session.user = data;
res.redirect('/users/'+data.username);
} else {
console.log(data)
console.log('password not correct');
res.redirect('/cbt');
}
})
});
Do not concatenate data into query strings; this is a serious source of security vulnerabilities!
Use query parameters; wherever you want to pass data into a query, put a ?, and pass it as an additional argument to run:
db.run("SELECT username, password FROM users WHERE username = ?",
username,
function(err, data) {...});
Also hash your passwords.

Categories

Resources