Why does bcrypt always return false? - javascript

I've been trying to figure out why bcrypt always return false. I've pretty much tried everything and it's pretty much the same results. I've also tried using third party websites to check if the hash and plain password matches but it also returns false. I'm thinking there's an issue with what I HATCHED but I can't seem to figure it out.
Stack: Express, mongoose, mongodb atlas
api calls
login = (req, res, next) => {
let userData = req.body;
User.findOne({
email: userData.email
},function(error,user){
if(error){
console.log(error)
} else {
if(!user){
res.status(401).send('email not found')
} else if(user){
bcrypt.compare(userData.password, user.password).then(function(resp) {
if(resp === false){
res.status(401).send('Invalid password')
} else {
let payload = {
subject: user._id
}
let token = jwt.sign(payload,"secretKey")
res.status(200).send({user,token})
}});
}
}
})
}
register = async (req, res) => {
let userData = req.body;
User.find({
email: userData.email
},function(err,result){
if(err){
console.log(err)
} else if(under._.isEmpty(result)){
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(userData.password, salt, function(err, hash) {
userData.password = hash;
let user = new User(userData)
user.save((error,registerUser)=>{
if(error){
console.log(error)
} else {
let payload = {
subject: registerUser._id
}
let token = jwt.sign(payload,"secretKey")
res.status(200).send({registerUser,token})
}
})
});
})
} else {
res.status(401).send('Email is already in use')
}
})
};
My schema
import mongoose from 'mongoose';
import {
saveUser,
toAuthJSON,
validatePassword,
} from '../helpers/model.helpers';
import { generateAccessToken } from '../helpers/auth.helpers';
const { Schema } = mongoose;
const userSchema = new Schema({
firstName: {
type: String,
required: [true, 'first name is required'],
},
lastName: {
type: String,
required: [true, 'last name is required'],
},
phoneNumber: {
type: String,
required: [true, 'Phone number is required'],
min: [10, 'A phone number can have at-least 10 digits'],
max: [13, 'Please enter a valid phone number, this is too long'],
},
email: {
type: String,
required: [true, 'An Email is required'],
},
password: {
type: String,
required: [true, 'A password is required'],
},
profileImage: {
type: String,
required: false,
},
title: {
type: String,
required: false,
},
companyName: {
type: String,
required: [false, 'Company name is required'],
},
companyAddress: {
type: String,
required: false,
},
companyPhoneNumber: {
type: String,
required: [false, 'Company phone number is required'],
},
companyLogo: {
type: String,
required: false,
},
},{
versionKey: false
});
userSchema.pre('save', saveUser);
userSchema.methods.validatePassword = validatePassword;
userSchema.methods.generateAccessToken = generateAccessToken;
userSchema.methods.toAuthJSON = toAuthJSON;
export default mongoose.model('User', userSchema);
my helper
import bcrypt from 'bcrypt';
export async function saveUser(next) {
const SALT_WORK_FACTOR = 10;
if (!this.isModified('password')) return next();
try {
const salt = await bcrypt.genSalt(SALT_WORK_FACTOR);
this.password = await bcrypt.hash(this.password, salt);
return next();
} catch (error) {
return next(error);
}
}
export function validatePassword(password) {
return bcrypt.compare(password, this.password);
}
export function toAuthJSON() {
const profile = this.toJSON();
delete profile.password;
// eslint-disable-next-line no-underscore-dangle
delete profile.__v;
return {
profile,
token: this.generateAccessToken(this.id),
};
}

Related

Cannot read properties of null (reading 'experience'). after all this i should get profile with all experience .but all time i end up with server err

i was following brad traversy's one of his udemy course. after working on adding experience in profile in profile routes. i all time get server error. but it should end up with full profile details like in brad course. this is my github link for that project
https://github.com/arshad007hossain/findDevs
profile.js
const express = require("express");
const router = express.Router();
const auth = require("../../middleware/authmiddleware");
const { check, validationResult } = require("express-validator");
const Profile = require("../../models/Profile");
const User = require("../../models/User");
// #route GET api/profile/me
// #desc Get current users profile
// #access Private
router.get("/me", auth, async (req, res) => {
try {
const profile = await Profile.findOne({
user: req.user.id,
}).populate("user", ["name", "avatar"]);
if (!profile) {
return res.status(400).json({ msg: "There is no profile for this user" });
}
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
// #route POST api/profile/me
// #desc create or update users profile
// #access Private
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubusername,
facebook,
linkedin,
twitter,
instagram,
youtube,
skills,
} = req.body;
//build user profile
const profileFields = {};
profileFields.user = req.user.id;
if (company) profileFields.company = company;
if (website) profileFields.website = website;
if (location) profileFields.location = location;
if (bio) profileFields.bio = bio;
if (status) profileFields.status = company;
if (githubusername) profileFields.githubusername = githubusername;
if (skills) {
profileFields.skills = skills.split(",").map((skill) => skill.trim());
}
//build social objects
profileFields.social = {};
if (youtube) profileFields.social.youtube = youtube;
if (twitter) profileFields.social.twitter = twitter;
if (linkedin) profileFields.social.linkedin = linkedin;
if (instagram) profileFields.social.instagram = instagram;
if (facebook) profileFields.social.facebook = facebook;
//console.log(profileFields.skills);
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//Update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
);
return res.json(profile);
}
//create
profile = new Profile(profileFields);
await profile.save();
res.json(profile);
} catch (err) {
console.errora(err.message);
res.status(500).json("server error");
}
}
);
// #route GET api/profile
// #desc Get all profile
// #access Public
router.get("/", async (req, res) => {
try {
let profiles = await Profile.find().populate("user", ["name", "avatar"]);
res.json(profiles);
} catch (err) {
console.error(err.message);
res.status(500).json("server error");
}
});
// #route GET api/profile/user/user_id
// #desc Get single profile
// #access Public
router.get("/user/:user_id", async (req, res) => {
try {
const profile = await Profile.findOne({
user: req.params.user_id,
}).populate("user", ["name", "avatar"]);
if (!profile) return res.status(400).json({ msg: "Profile not found" });
res.json(profile);
} catch (err) {
if (err.kind == "ObjectId") {
return res.status(400).json({ msg: "Profile not found" });
}
console.error(err.message);
res.status(500).json("server error");
}
});
// #route DELETE api/profile
// #desc Delete profile, user
// #access Private
router.delete("/", auth, async (req, res) => {
try {
// Remove profile
await Profile.findOneAndRemove({ user: req.user.id });
// Remove user
await User.findOneAndRemove({ _id: req.user.id });
res.json({ msg: "User deleted" });
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
// #route PUT api/profile/experience
// #desc Add profile experience
// #access Private
router.put(
'/experience',
[
auth,
[
check('title', 'Title is required field').not().isEmpty(),
check('company', 'Company is required field').not().isEmpty(),
check('from', 'From date is required field').not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
title,
company,
location,
from,
to,
current,
description,
} = req.body;
const newExp = {
title,
company,
location,
from,
to,
current,
description,
};
try {
const profile = await Profile.findOne({ user: req.user.id });
profile.experience.unshift(newExp);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
User.js
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
avatar: {
type: String,
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = User = mongoose.model("user", UserSchema);
Profile.js Model
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'user'
},
company: {
type: String
},
website: {
type: String
},
location: {
type: String
},
status: {
type: String,
required: true
},
skills: {
type: [String],
required: true
},
bio: {
type: String
},
githubusername: {
type: String
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
},
from: {
type: Date,
required: true
},
to: {
type: Date
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
fieldofstudy: {
type: String,
required: true
},
from: {
type: Date,
required: true
},
to: {
type: Date
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
social: {
youtube: {
type: String
},
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},
instagram: {
type: String
}
},
date: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('profile', ProfileSchema);

._doc in Mongoose

I have this js code
app.post('/auth', async (req, res) => {
try {
const user = UserModel.findOne({email: req.body.email}).exec()
if (!user) return res.status(404).json({
message: 'Not find user'
})
const isValidPassword = bcrypt.compare(req.body.password,user._doc.passwordHash)
if (!isValidPassword) return res.status(404).json({
message: 'Incorrect password'
})
}
catch (err) {
console.log(err)
res.status(500).json({
message: 'error'
})
}
})
And I have this Schema
import mongoose from 'mongoose'
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
surname: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
passwordHash: {
type: String,
required: true
},
telegramUrl: {
type: String,
required: true
},
avatarUrl: String
},
{
timestamps: true
}
)
export default mongoose.model('User', userSchema)
In this line
const isValidPassword = bcrypt.compare(req.body.password,user._doc.passwordHash)
I have error: Cannot read properties of undefined (reading 'passwordHash'). Why am I getting an error? He writes to me that ._doc undefined but why? Help me please
use these two methods in your schema
const bcrypt = require("bcrypt");
// Create Hash Salt Password ..
userSchema.pre("save", async function (next) {
if (!this.isModified("passwordHash")) return next();
this.passwordHash = await bcrypt.hash(this.passwordHash, 12);
next();
});
// Compare Password ...
userSchema.methods.comparePassword = function (passwordHash) {
return bcrypt.compareSync(passwordHash, this.passwordHash);
};
And in your auth code
app.post('/auth', async (req, res) => {
try {
const user = await UserModel.findOne({email: req.body.email}).exec()
if (user) {
res.status(400).json(
{ message: 'User already register'})
}
else{
const newuser = New User({
name: req.body.name,
// also write other schema fields
}
const res = await newuser.save();
console.log(res)
catch (err) {
console.log(err)
res.status(500).json({
message: 'error'
})
}
})
I hope this should resolve your problem

bcrypt compare method is returning false even if I used the same string when I hashed it

When I use the same password I hashed and stored in database as a parameter in compare method I get false. Really don't know whats the problem here:
router:
router.post("/users/login", async (req, res) => {
try {
const user = await User.findByCredentials(
req.body.email,
req.body.password
);
const token = await user.generateAuthToken();
console.log("Route token -->", token);
res.send({ user, token });
} catch (e) {
res.status(400).send(errors.e400);
}
});
Method for email and password validation ( calling compare method here):
userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email });
if (!user) throw new Error("User does not exist.");
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) throw new Error("Invalid password.");
return user;
};
password hashing:
userSchema.pre("save", async function () {
try {
this.password = await bcrypt.hash(this.password, 8);
} catch (e) {
console.log(e);
}
});
user schema:
const userSchema = new mongoose.Schema({
username: {
type: String,
trim: true,
required: true,
unique: true,
},
email: {
type: String,
trim: true,
required: true,
unique: true,
validate(value) {
if (!validator.isEmail(value))
throw new Error("Email address is not valid.");
},
},
password: {
type: String,
trim: true,
required: true,
minLength: 7,
},
tokens: [
{
token: {
type: String,
required: true,
},
},
],
});

user.save() is not a function when i am trying to save the model

const user = User.findOne({email:req.body.email});
if(!user){
return next(new ErrorHander("User not found",404));
}
const resetToken = user.getResetPasswordToken
await user.save({ validateBeforeSave: false });
I dont know why user.save is not working in mern mongodb i have same peice of code working for other person but not for me
What i did is that i get the user by fireing the query in the line one after having that user i should be able to use user.save() function here but sadly it is giving error
//here is my model schema
const mongoose = require("mongoose");
const validator = require("validator");
const bcrypt = require("bcryptjs");
const crypto = require("crypto")
const jwt = require("jsonwebtoken");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "please Ente the your name"],
},
email: {
type: String,
required: [true, "Please Enter the email"],
unique: [true],
validate: [validator.isEmail, "Please Enter a valid email"],
},
password: {
type: String,
required: true,
minlength: [8, "Passwaord must be more that 8 characters"],
select: false,
},
avatar: {
public_id: {
type: String,
required: true,
},
url: {
type: String,
required: true,
},
},
role: {
type: String,
default: "user",
},
resetPasswordToken: String,
resetPasswordTokenExpire: Date,
createdAt: {
type: Date,
default: Date.now,
},
});
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
this.password = await bcrypt.hash(this.password, 10);
});
userSchema.methods.comparePassword = async function (password) {
return await bcrypt.compare(password, this.password);
};
userSchema.methods.getJWTToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRE,
});
};
// compare password
// userSchema.methods.comparePassword = async function(enterPass){
// return await bcyrypt.compare(enterPass,this.password)
// }
// Reset Password
userSchema.methods.getResetPasswordToken = function(){
const resetToken = crypto.randomBytes(20).toString("hex");
this.resetPasswordToken = crypto.createHash("sha256").update(resetToken).digest("hex");
this.resetPasswordTokenExpire = Date.now +15*60*1000;
return resetToken;
}
module.exports = mongoose.model("User", userSchema);
User.findOne will return a Promise. So you need to add await keyword.
const user = await User.findOne({email:req.body.email});
if(!user){
return next(new ErrorHander("User not found",404));
}
const resetToken = user.getResetPasswordToken
await user.save({ validateBeforeSave: false });

Can't push items into mongodb arrays

I'm trying to make a simple social media app using react, express and mongodb.
This is the user model:
const UserSchema = new mongoose.Schema(
{
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: { type: String, required: true, unique: true},
followers: { type: Array, required: false },
following: { type: Array, required: false },
likes: { type: Array, required: false},
},
{ collection: 'users' }
)
This is the express server:
app.post('/api/follow', async (req, res) => {
const {token, username} = req.body
if (token === null)
{
return res.json({status: 'error'})
}
const user = await User.findOne({username}).lean()
const _visitor = jwt.verify(token, JWT_SECRET)
const visitor = await User.findOne({username: _visitor.username})
if (!user)
{
return res.json({status: 'error', error: 'User not found.'})
}
if (!visitor)
{
return res.json({status: 'error', error: 'User not found.'})
}
visitor.following.push(user._id)
user.followers.push(me._id)
return res.json({status: 'ok'})
})
But when I check the mongodb compass the following and followers arrays are empty.
The best way is to use findOneAndUpdate() method to update a value.
Also, if you are updating from two different collections you can use transactions. This is optional but can be useful to avoid inconsitences in your DB.
So your code can be something similar to this:
const updateVisitor = await User.findOneAndUpdate(
{
username: _visitor.username
},
{
$push:{
following: user._id
}
})
Example here
An the same code for user:
const updateUser = await User.findOneAndUpdate(
{
username: username
},
{
$push:{
followers: me._id
}
})

Categories

Resources