Mongoose-encryption Failure, Page keeps rolling - node.js

I am having a problem with an npm package called 'mongoose-encryption'. Here is my code.
main().catch((err) => console.log(err));
async function main() {
await mongoose.connect('mongodb://localhost:27017/userEncryptedDB', { useNewUrlParser: true });
}
const userSchema = new mongoose.Schema({
email: String,
password: String
});
const secret = 'xxs4Ox4nSKSVnJzIxzy+es6ouOmoMcqcarAnEVRP26Q=';
userSchema.plugin(encrypt, {secret: secret, encryptedFields: ['password']});
const User = mongoose.model('User', userSchema);
Now, if I don't use the package, registration and logging in to the website works properly but if I use the plug in, it says "You are never registered!" even though I register for the email and password...
app.post('/login', (req, res) => {
const email = req.body.username;
const password = req.body.password;
User.findOne({email: email, password: password}, (err, user) => {
if(err) {
console.error(err);
} else {
if(user){
console.log('You are already registered!');
res.render('secrets');
} else {
console.error('You are never registered!');
}
}
});
});
What am I doing wrong here? I started computer stopped database, restarted it. Registration is successfully done but when I try to login page keeps rolling... If I dont use mongoose-encryption, login page works fine once I enter password.
I can clearly see that the new username gets added to the database like so:
{ "_id" : ObjectId("616a4aa45dfbf877d9f92468"), "email" : "aras#aras.com", "_ct" : BinData(0,"YbVYW9Pi6dz1yqRD7XgcEyEp48lLGVjp3J40ZgxGt/YuA8+eyiyebMaO9AGdygBj6A=="), "_ac" : BinData(0,"YQiV2QvS9AyrE1hjm81x5U8K6+0lT8h1ruxtCEZv/iwZWyJfaWQiLCJfY3QiXQ=="), "__v" : 0 }
But then when I try to login, it fails to retrieve password. Password I use here in this case is "1".

Try dropping the collection (first save it somewhere for later use) and try again. It will work!

Related

How to use node.js fetch data from mongodb and push retrieved data into an array?

How to use node.js fetch data from mongodb and push retrieved data into an array ? I have user collection in mongodb and I can fetch the user and its USER_SECRET and PAS_SECRET information by email without problem to display them in a form, but I was failed to push USER_SECRET and PASS_SECRET of user into a users [] array . I Got error 500.
//-----login ui form-----
router.get("/user/login", function (req, res) {
res.render("users/login.ejs");
});
//------ Post ---
router.post("/user_secret", async (req, res) => {
const email = req.body.username;
console.log(email);
users = [];
try {
const user = await User.findOne({ USER_SECRET: email });
if (!user) {
return res.status(404).send("Inputs are Incorrect Information");
}
// res.render("users/addOrEdit", { user });// this works
res.users.push({
username: user.USER_SECRET,
password: user.PASS_SECRET,
});
} catch (e) {
res.status(500).send();
}
});
I could not find the reason of failure. Should I use map method ?
How to check if the users [] has data or not ? Please help.
I think res.users is undefined...so after getting the user, you can write:
res.status(200).send([{
username: user.USER_SECRET,
password: user.PASS_SECRET
}])
Instead of:
res.users.push({ ... })

Error with async await ( at least in my opinion ) - ExpressJS, MongoDB, NodeJS, multer

This is my code in backend (ExpressJs, multer)
Note: I used cors in server.js file and it working as I expected in previous route, but in this Register Admin route, the other error occurs
const multer = require('multer');
const upload = multer({ dest: './public/uploads/' });
const User = require('../models/user.model'); // User model
router.post('/admin/register', upload.single('avatar'),
async (req, res) => {
const avatar = req.file.path.slice(7);
const user = {
...JSON.parse(req.body.user),
avatar
};
// hapi/joi validate => 1
const { error } = Validation.adminRegisterValidation(user);
if (error) {
return res.json({ error: error.details[0].message });
}
// validate from database => 2
const emailExist = await User.findOne({ email: user.email });
if (emailExist) {
return res.json({ error: 'Email already exist!' });
}
// hash the password => 3
const hashedPassword = await bcrypt.hash(user.password, 10);
const newUser = new User({
...user,
admin: false,
password: hashedPassword,
sub_admin: true
});
try {
await newUser.save();
return res.json("Add user success!");
} catch (err) {
return res.json({ error: err });
}
}
);
If i turn 1,2,3 to comment, the user is added as I expected
This project in my Github Github
- Front-end in file: src -> components -> dashboard -> user-dashboard -> CreateUser.js
- Backend in file: backend -> routes -> user.route.js
THIS IS MY ERROR IMAGE
Well I found two errors that might be causing your issue, not really sure if it will totally fix your issue, but will definitely get you close.
1) Remove Max length property from user schema
Right now you have max length of 30 for password in your user Schema but once you hash the password, hashed password can go beyond 30 characters.
You can click here to see what I'm talking about.
2) You need to remove old password in order to store the new hashed password
In this line of code you are using Spread Syntax to include all the fields in NewUser object from user object, which already includes password that comes from your frontend
const newUser = new User({
...user,
admin: false,
password: hashedPassword,
sub_admin: true
});
This what causes newUser to have 2 password fields, to delete the old password after hashing do this
// hash the password => 3
const hashedPassword = await bcrypt.hash(user.password, 10);
delete user.password
const newUser = new User({
...user,
admin: false,
password: hashedPassword,
sub_admin: true
});
This way you can set password to new Hashed one.
AS your error is very Generic It's almost impossible to DEBUG it, these are the few things I found very odd.
As I said not really sure if it will fix your error but it might get you close

How to decode and verify password in feathers js

I am new to feathersJs and trying to learn how to perform authentication using hooks and services. I am using Couchdb database and cradle.
This is the post method to encrypt password in hashPassword using "users" hooks service. The post method is as below:
app.post('/dev',function(req,res,next){
var username = req.body.username;
var password = req.body.password;
app.service('database').create({username,password}).then(user => {
db.save(user, function (err, docs) {
// Handle response
res.json(docs);
});
console.log('User Created Successfully.', user);
}).catch(console.error);
})
and service is:
app.service('authentication').hooks({
before: {
create: [
// You can chain multiple strategies
auth.hooks.authenticate(['jwt', 'local'])
],
remove: [
auth.hooks.authenticate('jwt')
]
}
});
app.service('database').hooks({
before: {
find: [
auth.hooks.authenticate('jwt')
],
create: [
local.hooks.hashPassword({ passwordField: 'password' })
]
}
});
now i am using this to retrive data :
app.post('/devget',function(req,res,next){
var User = {
username: req.body.username,
password: req.body.password
};
app.service('dataget').find(User).then(user => {
db.view('byuser/user',{key: User.username}, function (err, docs) {
// Handle response
res.json(docs);
});
console.log('User Get Successfully.', user);
}).catch(console.error);
})
this will give me data in response as:
Response [
{ id: '060ab48a4826da7125d8ae45350037ee',
key: 'w',
value:
{ _id: '060ab48a4826da7125d8ae45350037ee',
_rev: '1-ea9a18d3724ce4542019dc5752c1fd4d',
username: 'w',
password: '$2a$10$yBJVJTmVXfTk0V4CCiWkd.GvAZZB9dF2pckKJ9wb/lJcAK8Ou.v06',
id: 0 } } ]
this works fine and password is encrypted but i am not getting how to decrypt password and authenticate user.
Note: i just want o do it with hooks and services or custom service or class but not using passport.
You do not decrypt the password; you compare the encrypted password to a function that will encrypt the password (after you've found the user to make a password comparison to).
const bcrypt = require('bcryptjs');
var hash = bcrypt.hashSync("bacon");
bcrypt.compareSync("bacon", hash); // true
bcrypt.compareSync("veggies", hash); // false
I would use the comparePassword function in this file
https://github.com/feathersjs/feathers/blob/be5d8df3b7afa39852ff1b5643676d9140ba8203/packages/authentication-local/src/strategy.ts#L94
Based on that you could write a hook and consider contributing it to the feathersJS project.

Bcrypt error: illegal arguments String unidentified

here is my complete code
var express = require('express'),
app = express(),
mongoose = require('mongoose'),
bodyParser = require('body-parser'),
morgan = require('morgan'),
webToken = require('jsonwebtoken'),
bcrypt = require('bcryptjs'),
assert = require('assert');
Schema = mongoose.Schema,
secretKey = "omjdiuwkslxmshsoepdukslsj";
//User Schema
var userSchema = new Schema({
username: {type: String, required: true, index: {unique:true}},
password: {type: String, required: true, select: false}
})
userSchema.pre('save', function(next){
var user = this;
if(!user.isModified('password')) return next();
bcrypt.hash(user.password, null, null, function(err, hash){
if(err) return next(err);
user.password = hash;
next();
})
});
userSchema.methods.comparePassword = function(password){
var user = this;
bcrypt.compare(password, user.password, function(err, result){
if(err){
console.log(err);
}
else {
console.log("passwords match!");
return;
}
})
}
var userModel = mongoose.model('users', userSchema);
//Connecting to Mongo
mongoose.connect("mongodb://localhost/userstories", function(err){
if(err) {
console.log(err);
}
else {
console.log("Connected to database!");
}
});
//Creating Token
function createToken(user){
var token = webToken.sign({
_id: user.id,
username: user.username
}, secretKey,{
expiresIn: 30 * 60 * 1000
})
return token;
}
//Middlewares
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(morgan('dev'));
//Api's
app.post('/signup', function(req, res){
var user = new userModel({
username: req.body.username,
password: req.body.password
})
user.save(function(err){
if(err){
console.log(err);
}
else{
res.json({message: "User created!"});
}
})
})
app.post('/login', function(req, res){
userModel.findOne({username: req.body.username}, function(err, user){
if(err) console.log(err);
if(!user){
res.send("User not found!");
}
else if(user){
var validPassword = user.comparePassword(req.body.password);
if(validPassword){
var tokens = createToken(user);
res.json({
success: true,
message: "Successfully logged In",
token: tokens
});
}
else {
res.send("Invalid password");
}
}
})
});
//Running the server
app.listen(3000, function(err){
if(err) console.log("port not working");
else{
console.log("Everything went just fine");
}
})
I've tried every approaches and saw all the answers here. But no one seem to come across this illegal argument error. Please figure this one out for me Im sure there is a bug I cant see
In your User Schema, you are setting select to false for the password field. This means that anytime you look for a user in the schema as you're trying to do in the login request, you won't get the value of the password field or any other field that has select false defined in the schema.
What you need to do is to specify you need the password when the user is found:
app.post('/login', function(req, res){
userModel.findOne({username: req.body.username}, 'password', function(err, user){
// continue
}
This will return only the _id and the password from the DB. If you want to return other fields, you'd have to add them in:
app.post('/login', function(req, res){
userModel.findOne({username: req.body.username}, 'password firstName lastName email', function(err, user){
// continue
}
I have tried the same code for authentication once and got the same error Error: Illegal arguments: string, function.
But I did not see any issue with the code. The thing is, I had registered two users with the same user name and a different password. Then, when I tried to log in with the user name and one password this error occurred and stopped the server.
So it seems that you are also facing the same problem. Make sure there are no errors with this stuff if you do not want to have a bug in your code.
Check the value of user.password before sending it to bcrypt.compare().
Chances are, you've fetched the user without including the password property, resulting in a value of undefined. This can happen in Sequelize if you set custom attributes or if you're using a scope that excludes props.
Your code is wrong in this place. You may see it.
var validPassword = user.comparePassword(req.body.password);
If you use bcryptjs thrid party plugins, like that
let validPassword = bcrypt.compare(req.body.password, user.password);
bcrypt.compare(password, hashedPassword);
In my particular case, I was dealing with this error, checking out all the code up and down unsuccessfully for almost two days.
Finally, realized that the column PASSWORD in MariaDB was in uppercase. Theoretically that shouldn't affect at all, but I decided to rename it to lowercase and bum! problem solved.
For those using async/await for database calls, make sure you don't forget the await keyword on the User.findOne() call.
In my case, I had forgotten the await keyword while fetching the user. This as a result, was giving me a Promise object instead of User object and hence the password property on it was undefined.
I also encountered the same error when I was using
bcrypt.compareSync("input to be compared with the hash", hash).
Later on I discovered that I was supposed to pass the actual value in the first input parameter i.e (The actual value from which the hash was generated) and the hash in the second input parameter, but I was passing hashed values in both the input parameters.
After correcting the same it was giving me the desired output as true or false.
You can also run and check your code here.
Do like this:
UserSchema.pre('save', async function (next) {
const hash = await bcrypt.hash(this.password, 10);
this.password = hash;
next()
})
You need to specify that you also want the password because you have set the select property to false on password.
So when you are fetching the user, just make sure to explicitly specify that you also want the password. Add .select('+password') on the user object when you are querying a user.
In my case it was a simple spelling mistake before sending to bcrypt.hash :
If you're testing this with Postman, I just found an issue where the default Content-Type header is set to text/plain. If you untick the default header (as it doesn't allow you to change it) and add another Content-Type header with a value of application/json, it works.

Why is my Node validation failing in this POST?

I'm following along in the MEAN machine Node authentication tutorial.
Here is their source code: https://github.com/scotch-io/mean-machine-code/blob/master/10-node-authentication/server.js I basically have everything except for the apiRouter.post('/authenticate', part
The Express APIs are working:
http://localhost:8615/api/users will return a list of users from scotch.io's MongoDB
The following is the API for /api/users:
apiRouter.route('/users')
// create a user (accessed at POST http://localhost:8615/api/users)
.post(function(req, res) {
// create a new instance of the User model
var user = new User();
// set the users information (comes from the request)
user.name = req.body.name;
user.username = req.body.username;
user.password = req.body.password;
// save the user and check for errors
user.save(function(err) {
if (err) {
// duplicate entry
if (err.code == 11000)
return res.json({ success: false, message: 'A user with that username already exists. '});
else
return res.send(err);
}
// return a message
res.json({ message: 'User created!' });
});
})
// get all users (access at GET http://localhost:8615/api/users)
.get(function(req, res) {
User.find(function(err, users) {
if (err) return res.send(err);
// return the users
res.json(users);
})
});
Here is my user.js User Schema
// SCHEMAS ------------------------------------
// user schema
var UserSchema = new Schema({
name: String,
username: { type: String, required: true, index: { unique: true }},
password: { type: String, required: true, select: false }
// ^ select false will not return passwords
});
// hash the password before the user is saved
UserSchema.pre('save', function(next) {
var user = this;
// PUT username
if (!user.isModified('username')) return next();
// PUT name
if (!user.isModified('name')) return next();
// hash the password only if the password has been changed or user is new
if (!user.isModifited('password')) return next();
// generate the salt
bcrypt.hash(user.password, null, null, function(err, hash) {
if (err) return next(err);
// change the password to the hashed version
user.password = hash;
next();
});
});
FROM THE BOOK:
Create a Sample User
First, we need to make sure that we even have a user to authenticate
since towards the end of last chapter, we deleted everyone. Let’s
create the user using the POST http://localhost:8080/api/users route
we created in our API to add a user to our database.
We will send a POST request with the following information: Name Chris
Username chris Password supersecret
I'm using Postman to add a new user, as you can see I have put in key/value pairs for username and password, however getting an error saying "Validation failed" "username is required" "password is required":
UPDATE, I just tried x-www-form-urlencoded and got the following error
GET /api/users 200 66.141 ms - 655
••• API CRUD hit •••
/Users/leongaban/NodeDallas/projects/awesome-test/app/models/user.js:27
if (!user.isModifited('password')) return next();
^
TypeError: Object { password: 'supersecret',
username: 'Chris',
name: 'chris',
_id: 54c001dc4ee4028c18e61334 } has no method 'isModifited'
at model.UserSchema.methods.comparePassword.user (/Users/leongaban/NodeDallas/projects/awesome-test/app/models/user.js:27:12)
Screenshot of error in Postman: https://s3.amazonaws.com/f.cl.ly/items/1M0M392M0E3b2i430I1n/Image%202015-01-21%20at%201.45.51%20PM.png
try x-www-form-urlencoded in postman, that would do.
You want to push a json to your server. Select raw and set the data type to JSON.
Then you just have to write your user in JSON format with all his fields here.
{
"name": "Chris",
"username": "chris",
"password": "supersecret"
}

Resources