Node js: Bluebird Promisify in Mongoose middleware - node.js

I have a User model that looked like this:
var Promise = require("bluebird")
var mongoose = require("mongoose");
var mongooseAlias = require('mongoose-aliasfield');
var bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'));
var Schema = mongoose.Schema;
var userSchema = new Schema({
u: { type: String, required: true, trim: true, index: { unique: true }, 'alias': 'userId' },
fb: { type: String, required: true, 'alias': 'fbAccessToken' },
ap: { type: String, required: true, 'alias': 'apiAccessToken' },
f: { type: String, required: true, 'alias': 'firstName' },
l: { type: String, required: true, 'alias': 'lastName' },
e: { type: String, required: true, 'alias': 'email' }
});
// Execute before each user.save() call
userSchema.pre('save', function(callback) {
var user = this;
// return if token hasn't changed
if (!user.isModified('fb') && !user.isModified('ap'))
return callback();
// token changed so we need to hash it
bcrypt.genSalt(5, function(err, salt) {
if (err) return callback(err);
bcrypt.hash(user.fb, salt, null, function(err, hash) {
if (err) return callback(err);
user.fb = hash;
bcrypt.genSalt(5, function(err, salt) {
if (err) return callback(err);
bcrypt.hash(user.ap, salt, null, function(err, hash) {
if (err) return callback(err);
user.ap = hash;
callback();
});
});
});
});
});
userSchema.plugin(mongooseAlias);
module.exports = mongoose.model('User', userSchema);
I'm trying to learn Bluebird at the moment so I cleaned up the bcrypt code like this:
userSchema.pre('save', function(callback) {
var user = this;
// return if token hasn't changed
if (!user.isModified('fb') && !user.isModified('ap'))
return callback();
var p1 = bcrypt.genSaltAsync(5).then(function (salt) {
return bcrypt.hash(user.fb, salt, null);
}).then(function (hash) {
user.fb = hash;
});
var p2 = bcrypt.genSaltAsync(5).then(function (salt) {
return bcrypt.hash(user.ap, salt, null);
}).then(function (hash) {
user.ap = hash;
});
Promise.all(p1, p2).then(function () {
callback();
}).catch(function (err) {
callback(err);
});
});
Can I "promisify" it any further? Or rather, am I missing something here that would make it more elegant? Do I need to promisify the userSchema.pre call somehow?
Cheers

I thing your solution is correct. I prefere to do it a little differently (but I'm not saying that this is better):
bcrypt.genSaltAsync(5)
.then(function (salt) {
return bcrypt.hash(user.fb, salt, null);
})
.then(function (hash) {
user.fb = hash;
})
.then(function (){
return bcrypt.genSaltAsync(5);
})
.then(function (salt) {
return bcrypt.hash(user.ap, salt, null);
})
.then(function (hash) {
user.ap = hash;
})
.then(function () {
callback();
})
.catch(function (err) {
callback(err);
});
I like my solution because everything is in one flow and at first glance you know what is going on. In my solution second salt function is resolving after first. In your solution each one is resolving parallel (I dont check performance of each solution)

Related

Migrating from a Mongoose Model to Postgres NodeJS

I have a node project which I use twillo to verify Phone number and it works with MongoDB, now I want to transfer the same logic to an old project which uses Posgres and Bookshelf to create tables, I have tried adding the necessary fields and but it does not reflect in the database as I would want it to, and How to effectively write methods with the Bookshelf model. Below is my postgres code and my Mongo model that works which I want to replicate with postgres
const UserSchemax = new mongoose.Schema({
fullName: {
type: String,
required: true,
},
countryCode: {
type: String,
required: true,
},
phone: {
type: String,
required: true,
},
verified: {
type: Boolean,
default: false,
},
authyId: String,
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
});
// Middleware executed before save - hash the user's password
UserSchemax.pre('save', function (next) {
const self = this;
// only hash the password if it has been modified (or is new)
if (!self.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(self.password, salt, function (err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
self.password = hash;
next();
});
});
});
// Test candidate password
UserSchemax.methods.comparePassword = function (candidatePassword, cb) {
const self = this;
bcrypt.compare(candidatePassword, self.password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
// Send a verification token to this user
UserSchemax.methods.sendAuthyToken = function (cb) {
var self = this;
if (!self.authyId) {
// Register this user if it's a new user
authy.register_user(self.email, self.phone, self.countryCode,
function (err, response) {
if (err || !response.user) return cb.call(self, err);
self.authyId = response.user.id;
self.save(function (err, doc) {
if (err || !doc) return cb.call(self, err);
self = doc;
sendToken();
});
});
} else {
// Otherwise send token to a known user
sendToken();
}
// With a valid Authy ID, send the 2FA token for this user
function sendToken() {
authy.request_sms(self.authyId, true, function (err, response) {
cb.call(self, err);
});
}
};
// Test a 2FA token
UserSchemax.methods.verifyAuthyToken = function (otp, cb) {
const self = this;
authy.verify(self.authyId, otp, function (err, response) {
cb.call(self, err, response);
});
};
here is my current Postgres model
const User = models.Model.extend({
tableName: 'users',
uuid: true,
schema: [
fields.StringField('first_name'),
fields.StringField('last_name'),
fields.StringField('photo'),
fields.StringField('phone'),
fields.EmailField('email'),
fields.BooleanField('verified')
fields.StringField('authyId')
fields.EncryptedStringField('password', {
min_length: {
value: 8,
message: '{{label}} must be at least 8 characters long!'
}
}),
fields.BooleanField('old_account')
]}
I just added the authyId and verified fields and still, they do not reflect in my postgres table. further code would be supplied on request, I am equally new to NodeJS

access the user._id in nodejs

I'm pretty new with node.js and I'm trying to implement simple user registration and login form using Node.js, Express, bcrypt, express-session and mongoose.
Whenever the user log in, I want to set the value of req.session.userID to user's id. When I trace the code I can't find the problem. I followed up the tutorial in this link and everything seems to be similar.
Schema:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt');
var userSchema = new Schema({
teamName: {
type: String,
unique: true,
trim: true,
required: true
},
faculty: {
type: String,
required: true
},
email: {
required: true,
unique: true,
trim: true,
type: String
},
password: {
required: true,
type: String
},
score: {
type: Number,
default: 0
}
});
userSchema.pre('save', function(next) {
var user = this;
bcrypt.hash(user.password, 10, function(err, hash) {
if (err) return next(err)
user.password = hash;
next();
});
});
userSchema.statics.authenticate = (email, password, callback) => {
userModel.findOne({email: email}, (err, user) => {
if (err) return callback(err);
else if (!user) {
console.log('User not found!')
}
else {
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
callback(null, true)
}
else {
return callback()
}
})
}
})
}
var userModel = mongoose.model('User', userSchema);
module.exports = userModel;
server:
var userModel = require('./../models/users');
router.post('/login', (req, res) => {
var email = req.body.email;
var password = req.body.password;
userModel.authenticate(email, password, (err, user) => {
console.log(user)
if (err) {
console.log(err)
}
else if (!user) {
console.log('Wrong Password')
}
else {
req.session.userId = user._id;
console.log(req.session.userId);
}
})
});
Where I have logged the value of req.session.userId it returns undefined! Where is the problem?
The problem is that the callback is returning TRUE. the callback should be returning the user data. callback(null, user)
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
callback(null, true)
}
Should be
bcrypt.compare(password, user.password, (err, result) => {
if (result) {
callback(null, user)
}

Bcrypt node.js returns false on compare

i got a problem with bcrypt on node.js -> the bcrypt compare method returns false while comparing the passwords from a mongoDB and a user entry. I have no idea why and i tried to debug it since 3 days but i really need some extern help...
UserShema:
var userSchema = new Schema({
name: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
hash and salt:
userSchema.pre('save', function (next) {
var user = this;
if (this.isModified('password') || this.isNew) {
bcrypt.genSalt(10, function (err, salt) {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
return next();
}
});
and finally: the compare method:
userSchema.methods.comparePassword = function (passw, cb) {
bcrypt.compare(passw, this.password, function (err, isMatch) {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', userSchema);
Thx alot!

Why is my node js code able to POST a login form to be matched from mongodb?

I am using node.js I already can post from a signup html page. However the code below
exports.login = function (req, res, next) {
if (req.body && req.body.email && req.body.password) {
var userLogin = new User ({
email: req.body.email,
password: req.body.password
});
userLogin.findOne(function(err) {
if (!err) {
res.redirect('/about.html');
} else {
res.redirect('http://google.com');
next(err);
}
});
} else {
next(new Error('Incorrect POST'));
}
};
The problem I am having is that the userLogin.findOne is not working as it says findOne is undefined.
The model.js file that this is linking to is:
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt-nodejs'),
SALT_WORK_FACTOR = 10;
// these values can be whatever you want - we're defaulting to a
// max of 5 attempts, resulting in a 2 hour lock
MAX_LOGIN_ATTEMPTS = 5,
LOCK_TIME = 2 * 60 * 60 * 1000;
var UserSchema = new Schema({
email: { type: String, required: true, lowercase:true, index: { unique: true } },
password: { type: String, required: true },
firstName: {type: String, required: true},
lastName: {type: String, required: true},
phone: {type: Number, required: true},
birthday: {type: Date, required: true},
loginAttempts: { type: Number, required: true, default: 0 },
lockUntil: { type: Number }
});
UserSchema.virtual('isLocked').get(function() {
// check for a future lockUntil timestamp
return !!(this.lockUntil && this.lockUntil > Date.now());
});
//password hashing middleware
UserSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password along with our new salt
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
//password verification
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
UserSchema.methods.incLoginAttempts = function(cb) {
// if we have a previous lock that has expired, restart at 1
if (this.lockUntil && this.lockUntil < Date.now()) {
return this.update({
$set: { loginAttempts: 1 },
$unset: { lockUntil: 1 }
}, cb);
}
// otherwise we're incrementing
var updates = { $inc: { loginAttempts: 1 } };
// lock the account if we've reached max attempts and it's not locked already
if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked) {
updates.$set = { lockUntil: Date.now() + LOCK_TIME };
}
return this.update(updates, cb);
};
// expose enum on the model, and provide an internal convenience reference
var reasons = UserSchema.statics.failedLogin = {
NOT_FOUND: 0,
PASSWORD_INCORRECT: 1,
MAX_ATTEMPTS: 2
};
UserSchema.statics.getAuthenticated = function(email, password, cb) {
this.findOne({ email: email }, function(err, user) {
if (err) return cb(err);
// make sure the user exists
if (!user) {
return cb(null, null, reasons.NOT_FOUND);
}
// check if the account is currently locked
if (user.isLocked) {
// just increment login attempts if account is already locked
return user.incLoginAttempts(function(err) {
if (err) return cb(err);
return cb(null, null, reasons.MAX_ATTEMPTS);
});
}
// test for a matching password
user.comparePassword(password, function(err, isMatch) {
if (err) return cb(err);
// check if the password was a match
if (isMatch) {
// if there's no lock or failed attempts, just return the user
if (!user.loginAttempts && !user.lockUntil) return cb(null, user);
// reset attempts and lock info
var updates = {
$set: { loginAttempts: 0 },
$unset: { lockUntil: 1 }
};
return user.update(updates, function(err) {
if (err) return cb(err);
return cb(null, user);
});
}
// password is incorrect, so increment login attempts before responding
user.incLoginAttempts(function(err) {
if (err) return cb(err);
return cb(null, null, reasons.PASSWORD_INCORRECT);
});
});
});
};
module.exports = mongoose.model('User', UserSchema);
In your code, userLogin is an instance of the User model which means you've created a document. As documentation for mongoose queries states, queries are handled using 'static helper methods' which means they aren't available on an instance of a model (i.e. on a document).
I think you'd probably want your code to look more like this where userLogin is an object that holds your conditions for the query and then you could use the User model's .findOne method to execute the query.
var userLogin = {
email: req.body.email,
password: req.body.password
};
User.findOne(userLogin, function(err) {
if (!err) {
res.redirect('/about.html');
} else {
res.redirect('http://google.com');
next(err);
}
});
Edit: OK, so the above answered the question about why findOne was undefined.
The second question asked is "why doesn't this authenticate the user?"
The reason the code is redirecting to (I assume) the '/about.html' page is because that's exactly what the code does...as written.
To authenticate (and we're technically starting a new answer to an originally unasked question): you need to call the UserSchema.statics.getAuthenticated method that is defined in modules.js. That would need code like this (slightly modified from the tutorial where most of this code originated):
User.getAuthenticated('<valid_email>', '<valid_password>', function(err, user, reason) {
if (err) throw err;
if (user) {
// handle login success
// note, handling success is more than a res.redirect call
// if you need to deal with session, state, cookies, etc...
return;
}
// otherwise we can determine why we failed
var reasons = User.failedLogin;
switch (reason) {
case reasons.NOT_FOUND:
case reasons.PASSWORD_INCORRECT:
// note: these cases are usually treated the same - don't tell
// the user *why* the login failed, only that it did
break;
case reasons.MAX_ATTEMPTS:
// send email or otherwise notify user that account is
// temporarily locked
break;
}
});
As a side-node, I'd suggest you look into everyauth or passport.js as modules that can do much of this for you. At that point, your main concern will be writing code for user CRUD while the modules handle sessions, cookies, serialization/deserialization and so on for you. This is doubly true if you have any plans to include OAUTH logins via google, facebook, et al.

Mongoose password hashing

I am looking for a good way to save an Account to MongoDB using mongoose.
My problem is: The password is hashed asynchronously. A setter wont work here because it only works synchronous.
I thought about 2 ways:
Create an instance of the model and save it in the callback of the
hash function.
Creating a pre hook on 'save'
Is there any good solution on this problem?
The mongodb blog has an excellent post detailing how to implement user authentication.
http://blog.mongodb.org/post/32866457221/password-authentication-with-mongoose-part-1
The following is copied directly from the link above:
User Model
var mongoose = require('mongoose'),
Schema = mongoose.Schema,
bcrypt = require('bcrypt'),
SALT_WORK_FACTOR = 10;
var UserSchema = new Schema({
username: { type: String, required: true, index: { unique: true } },
password: { type: String, required: true }
});
UserSchema.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
UserSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', UserSchema);
Usage
var mongoose = require(mongoose),
User = require('./user-model');
var connStr = 'mongodb://localhost:27017/mongoose-bcrypt-test';
mongoose.connect(connStr, function(err) {
if (err) throw err;
console.log('Successfully connected to MongoDB');
});
// create a user a new user
var testUser = new User({
username: 'jmar777',
password: 'Password123'
});
// save the user to database
testUser.save(function(err) {
if (err) throw err;
});
// fetch the user and test password verification
User.findOne({ username: 'jmar777' }, function(err, user) {
if (err) throw err;
// test a matching password
user.comparePassword('Password123', function(err, isMatch) {
if (err) throw err;
console.log('Password123:', isMatch); // -> Password123: true
});
// test a failing password
user.comparePassword('123Password', function(err, isMatch) {
if (err) throw err;
console.log('123Password:', isMatch); // -> 123Password: false
});
});
For those who are willing to use ES6+ syntax can use this -
const bcrypt = require('bcryptjs');
const mongoose = require('mongoose');
const { isEmail } = require('validator');
const { Schema } = mongoose;
const SALT_WORK_FACTOR = 10;
const schema = new Schema({
email: {
type: String,
required: true,
validate: [isEmail, 'invalid email'],
createIndexes: { unique: true },
},
password: { type: String, required: true },
});
schema.pre('save', async function save(next) {
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 (err) {
return next(err);
}
});
schema.methods.validatePassword = async function validatePassword(data) {
return bcrypt.compare(data, this.password);
};
const Model = mongoose.model('User', schema);
module.exports = Model;
TL;DR - Typescript solution
I have arrived here when I was looking for the same solution but using typescript. So for anyone interested in TS solution to the above problem, here is an example of what I ended up using.
imports && contants:
import mongoose, { Document, Schema, HookNextFunction } from 'mongoose';
import bcrypt from 'bcryptjs';
const HASH_ROUNDS = 10;
simple user interface and schema definition:
export interface IUser extends Document {
name: string;
email: string;
password: string;
validatePassword(password: string): boolean;
}
const userSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
user schema pre-save hook implementation
userSchema.pre('save', async function (next: HookNextFunction) {
// here we need to retype 'this' because by default it is
// of type Document from which the 'IUser' interface is inheriting
// but the Document does not know about our password property
const thisObj = this as IUser;
if (!this.isModified('password')) {
return next();
}
try {
const salt = await bcrypt.genSalt(HASH_ROUNDS);
thisObj.password = await bcrypt.hash(thisObj.password, salt);
return next();
} catch (e) {
return next(e);
}
});
password validation method
userSchema.methods.validatePassword = async function (pass: string) {
return bcrypt.compare(pass, this.password);
};
and the default export
export default mongoose.model<IUser>('User', userSchema);
note: don't forget to install type packages (#types/mongoose, #types/bcryptjs)
I think this is a good way by user Mongoose and bcrypt!
User Model
/**
* Module dependences
*/
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt');
const SALT_WORK_FACTOR = 10;
// define User Schema
const UserSchema = new Schema({
username: {
type: String,
unique: true,
index: {
unique: true
}
},
hashed_password: {
type: String,
default: ''
}
});
// Virtuals
UserSchema
.virtual('password')
// set methods
.set(function (password) {
this._password = password;
});
UserSchema.pre("save", function (next) {
// store reference
const user = this;
if (user._password === undefined) {
return next();
}
bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) {
if (err) console.log(err);
// hash the password using our new salt
bcrypt.hash(user._password, salt, function (err, hash) {
if (err) console.log(err);
user.hashed_password = hash;
next();
});
});
});
/**
* Methods
*/
UserSchema.methods = {
comparePassword: function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
}
module.exports = mongoose.model('User', UserSchema);
Usage
signup: (req, res) => {
let newUser = new User({
username: req.body.username,
password: req.body.password
});
// save user
newUser.save((err, user) => {
if (err) throw err;
res.json(user);
});
}
Result
Result
The Mongoose official solution requires the model to be saved before using the verifyPass method, which can cause confusion. Would the following work for you? (I am using scrypt instead of bcrypt).
userSchema.virtual('pass').set(function(password) {
this._password = password;
});
userSchema.pre('save', function(next) {
if (this._password === undefined)
return next();
var pwBuf = new Buffer(this._password);
var params = scrypt.params(0.1);
scrypt.hash(pwBuf, params, function(err, hash) {
if (err)
return next(err);
this.pwHash = hash;
next();
});
});
userSchema.methods.verifyPass = function(password, cb) {
if (this._password !== undefined)
return cb(null, this._password === password);
var pwBuf = new Buffer(password);
scrypt.verify(this.pwHash, pwBuf, function(err, isMatch) {
return cb(null, !err && isMatch);
});
};
Another way to do this using virtuals and instance methods:
/**
* Virtuals
*/
schema.virtual('clean_password')
.set(function(clean_password) {
this._password = clean_password;
this.password = this.encryptPassword(clean_password);
})
.get(function() {
return this._password;
});
schema.methods = {
/**
* Authenticate - check if the passwords are the same
*
* #param {String} plainText
* #return {Boolean}
* #api public
*/
authenticate: function(plainPassword) {
return bcrypt.compareSync(plainPassword, this.password);
},
/**
* Encrypt password
*
* #param {String} password
* #return {String}
* #api public
*/
encryptPassword: function(password) {
if (!password)
return '';
return bcrypt.hashSync(password, 10);
}
};
Just save your model like, the virtual will do its job.
var user = {
username: "admin",
clean_password: "qwerty"
}
User.create(user, function(err,doc){});
const bcrypt = require('bcrypt');
const saltRounds = 5;
const salt = bcrypt.genSaltSync(saltRounds);
module.exports = (password) => {
return bcrypt.hashSync(password, salt);
}
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const hashPassword = require('../helpers/hashPassword')
const userSchema = new Schema({
name: String,
email: {
type: String,
match: [/^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, `Please fill valid email address`],
validate: {
validator: function() {
return new Promise((res, rej) =>{
User.findOne({email: this.email, _id: {$ne: this._id}})
.then(data => {
if(data) {
res(false)
} else {
res(true)
}
})
.catch(err => {
res(false)
})
})
}, message: 'Email Already Taken'
}
},
password: {
type: String,
required: [true, 'Password required']
}
});
userSchema.pre('save', function (next) {
if (this.password) {
this.password = hashPassword(this.password)
}
next()
})
const User = mongoose.model('User', userSchema)
module.exports = User
const mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
SALT_WORK_FACTOR = 10;
const userDataModal = mongoose.Schema({
username: {
type: String,
required : true,
unique:true
},
password: {
type: String,
required : true
}
});
userDataModal.pre('save', function(next) {
var user = this;
// only hash the password if it has been modified (or is new)
if (!user.isModified('password')) return next();
// generate a salt
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if (err) return next(err);
// hash the password using our new salt
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
// override the cleartext password with the hashed one
user.password = hash;
next();
});
});
});
userDataModal.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
// Users.index({ emaiId: "emaiId", fname : "fname", lname: "lname" });
const userDatamodal = module.exports = mongoose.model("usertemplates" , userDataModal)
//inserting document
userDataModel.findOne({ username: reqData.username }).then(doc => {
console.log(doc)
if (doc == null) {
let userDataMode = new userDataModel(reqData);
// userDataMode.password = userDataMode.generateHash(reqData.password);
userDataMode.save({new:true}).then(data=>{
let obj={
success:true,
message: "New user registered successfully",
data:data
}
resolve(obj)
}).catch(err=>{
reject(err)
})
}
else {
resolve({
success: true,
docExists: true,
message: "already user registered",
data: doc
}
)
}
}).catch(err => {
console.log(err)
reject(err)
})
//retriving and checking
// test a matching password
user.comparePassword(requestData.password, function(err, isMatch) {
if (err){
reject({
'status': 'Error',
'data': err
});
throw err;
} else {
if(isMatch){
resolve({
'status': true,
'data': user,
'loginStatus' : "successfully Login"
});
console.log('Password123:', isMatch); // -> Password123: true
}
I guess it would be better to use the hook, after some research i found
http://mongoosejs.com/docs/middleware.html
where it says:
Use Cases:
asynchronous defaults
I prefer this solution because i can encapsulate this and ensure that an account can only be saved with a password.
I used .find({email}) instead of .findOne({email}).
Make sure to use .findOne(...) to get a user.
Example:
const user = await <user>.findOne({ email });

Resources