I have an error with passport.js implementation in Sails.js - sails.js

I have a problem with Sails Passport implementation. This error appears in my terminal:
/home/tatico/sinGualichoPassport/config/passport.js:19
if (!user.validPassword(password)) {
^
TypeError: user.validPassword is not a function
at /home/tatico/sinGualichoPassport/config/passport.js:19:17
at returnResults (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:180:9)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/basic.js:86:16
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:83:7
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:52:16
at Object.async.forEachOf.async.eachOf (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:236:30)
at Object.async.forEach.async.each (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:209:22)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:436:11
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:574:5
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:52:16
at Object.async.forEachOf.async.eachOf (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:236:30)
at Object.async.forEach.async.each (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/async/lib/async.js:209:22)
at _buildChildOpts (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:464:9)
at _execChildOpts (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:432:8)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/query/finders/operations.js:81:10
at wrapper (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/lodash/index.js:3592:19)
at applyInOriginalCtx (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:421:80)
at wrappedCallback (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/utils/normalize.js:324:18)
at callback.success (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/switchback/lib/normalize.js:33:31)
at _switch (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/switchback/lib/factory.js:58:28)
at /home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/lib/waterline/adapter/dql.js:166:7
at wrapper (/home/tatico/.npm-global/lib/node_modules/sails/node_modules/waterline/node_modules/lodash/index.js:3592:19)
This is my Files:
config/passport.js:
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy
bcrypt = require('bcrypt');
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
module.exports = {
http: {
customMiddleware: function(app){
console.log('Express midleware for passport');
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(function(req,res,next){
// Set the loggedUser in locals *does it work?
// to get it from the view
res.locals.loggedUser = req.user;
next();
});
}
}
};
UserController.js
module.exports = {
auth: function(req, res) {
return res.view();
},
create: function(req, res, next) {
User.create( req.params.all(), function createdUser(err, user){
if (err) {
return res.negotiate(err);
}
req.session.authenticated = true;
req.session.user = user;
return res.json(user);
});
},
login: function(req, res, next) {
// Use Passport LocalStrategy
require('passport').authenticate('local', function(err, user, info){
if ((err) || (!user)) next(err);
req.login(user, function(err){
if (err) return res.redirect('/user/auth');
// Redirect to the user page.
return res.redirect('/user/' + user.id);
});
})(req, res);
},
logout: function(req, res){
// Call Passport method to destroy the session.
req.logout();
// Redirect to home page.
return res.redirect('/');
}
};
User.js:
module.exports = {
attributes: {
email: {
type: 'string',
required: true,
email: true,
unique: true
},
password: {
type: 'string',
required: true
},
username: {
type: 'string',
required: true,
unique: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
// Lifecycle Callbacks
beforeCreate: function(values, next) {
hashPassword(values, next);
},
beforeUpdate: function(values, next) {
if(values.password) hashPassword(values, next);
else next();
}
}
var bcrypt = require('bcrypt');
function hashPassword(values, next) {
bcrypt.hash(values.password, 10, function(err, hash) {
if (err) return next(err);
values.password = hash;
next();
});
}
Im new in Sails, and I suppose this is a not good implementantion, Anyone can Help me and give a little feed back to improve my understanding of Sails and Passport? Thanks.

ValidPassword is not defined anywhere which is leading to this error.

Related

Mongoose pre save middleware is not triggering/saving hashed passwords to db

I am trying to pre save and hash password with bcrypt in mongoose in my next.js project, but password still unhashed. i tryed every link in stackoverflow and didnt solve it, the password still saved unHashed.
mongoose version: 6.9.1
this is my users.model file:
import {
models,
model,
Schema,
} from 'mongoose';
import bcrypt from 'bcrypt';
const UserSchema: Schema = new Schema({
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
displayName: {
type: String,
required: true,
},
role: {
type: String,
},
});
UserSchema.pre('save', function (next) {
console.log('Pre-Save Hash has fired.');
let user = this;
bcrypt.genSalt(10, (err, salt) => {
if (err) console.error(err);
bcrypt.hash(user.password, salt, (err, hash) => {
user.password = hash;
next();
});
});
});
const UserModel = models.Users || model('Users', UserSchema, 'users');
export default UserModel;
this is my adding function file:
import dbConnect from '#/utils/mongodb';
import UserModel from '#/models/user.model';
import { NextApiRequest, NextApiResponse } from 'next';
import { MongoError } from 'mongodb';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// const { email, password } = req.query;
try {
dbConnect();
const query = req.body;
const newUser = new UserModel(query);
const addedUser= await newUser.save(function (err: MongoError) {
if (err) {
throw err;
}
});
res.status(200).json(addedUser);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
}
i cant see the 'Pre-Save Hash has fired.' in my console also..
// You need to add user.isModified("password")
userSchema.pre("save", function (next) {
var user = this;
if (user.isModified("password")) {
bcrypt.genSalt(SALT_I, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
next();
}
});
userSchema.methods.comparePassword = function (candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
if (err) return cb(err);
cb(null, isMatch);
});
};
// to make register end point
import mongoose from "mongoose";
import User from "../../../models/User";
const dbConnect = async () => {
mongoose
.connect("mongodb://localhost:27017/test")
.then(() => {
console.log("Connected to mongoDb");
})
.catch((error) => {
console.log(error);
});
};
export default async function handler(req, res) {
try {
await dbConnect();
const query = req.body;
const newUser = new User(query);
await newUser.save(function (err, result) {
if (err) {
throw err;
} else {
res.status(200).json(result);
}
});
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
}
thanks to all.
The problem was in my dbconnect file!

Typescript Error in mongoose schemas pre method: Unexpected aliasing of 'this' to local variable

I'm trying to implement authentication based on MongoDB and NestJS for an Ionic application and getting the following error message after making a POST request to the route api/users:
[Nest] 85372 - 03/26/2020, 14:04:49 [ExceptionsHandler] Cannot read property 'password' of undefined +23790ms
Inside my users.schema.ts file a get the errror message:
Unexpected aliasing of 'this' to local variable.eslint(#typescript-eslint/no-this-alias)
My users.schema.ts looks like this (commented the line with the error):
import * as mongoose from 'mongoose';
import * as bcrypt from 'bcryptjs'
export const UserSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
unique: true,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date,
default: Date.now
}
});
UserSchema.pre('save', function (next) {
const user = this; // This is marked as an error in vs code
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(this.user.password, salt, (err, hash) => {
if (err) return next();
this.user.password = hash;
next();
});
});
});
UserSchema.methods.checkPassword = (attempt, callback) => {
bcrypt.compare(attempt, this.user.password, (err, isMatch) => {
if (err) return callback(err);
callback(null, isMatch);
})
}
I tried to implement the same schema with an arrow function, but then I get the following error message after making a POST request to api/users:
[Nest] 85947 - 03/26/2020, 14:09:30 [ExceptionsHandler] Cannot read property 'isModified' of undefined +22567ms
UserSchema.pre('save', (next) => {
if (!this.user.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(this.user.password, salt, (err, hash) => {
if (err) return next();
this.user.password = hash;
next();
});
});
});
What am I doing wrong here?
You cannot use arrow functions, because you loose the track of this. Read the official documentation of arrow functions, there are some very good examples about "what is this in an array function". MDN Arrow function expressions
There are two solutions:
Remove the arrow-function callback for bcrypt
UserSchema.pre('save', function (next) {
if (!this.isModified('password')) return next();
bcrypt.genSalt(10, function (err, salt) {
if (err) return next(err);
bcrypt.hash(this.user.password, salt, (err, hash) => {
if (err) return next();
this.user.password = hash;
next();
});
});
});
Disable eslint rule and always use the user variable
UserSchema.pre('save', function (next) {
const user = this;
if (!this.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) return next();
user.password = hash;
next();
});
});
});

passport bookshelf is not inserting user into database

I'm using passport with bookshelf, and im having issues inserting a user in the database.
I'm using postman, and it shows that a user has been added to the db, but its not.
There doesn't seem to be much information about bookshelf, passport, and postgres used together. So it makes finding solutions like this hard.
routes/users
router.post('/register', (req, res, next) => {
passport.authenticate('register', (err, user, info) => {
if(err){
console.log(err)
}
if(info !== undefined){
console.log(info.message)
res.status(403).send(info.message)
}else{
req.logIn(user, err => {
const data = {
username: req.body.username.trim(),
password: req.body.password.trim(),
email: req.body.email.trim()
}
console.log(data);
User.forge({
username: data.username
}).fetch().then( (user) => {
console.log('user creatd in db');
res.status(200).send({
message:'user created'
})
})
})
}
})(req, res, next);
});
passport.js
import passport from 'passport';
import LocalStrategy from 'passport-local';
import User from '../models/User';
import bcrypt from 'bcrypt';
import JWTstrag from 'passport-jwt';
import ExtracJWT from 'passport-jwt';
const JWTstrategy = JWTstrag.Strategy
const ExtractJWT = ExtracJWT.ExtractJwt
const Local = LocalStrategy.Strategy
const opts = {
jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('JWT'),
secretOrKey: process.env.JWT_SECRET,
};
passport.use('jwt', new JWTstrategy(opts, (jwt_payload, done) => {
try{
User.forge({username: jwt_payload._id})
.fetch()
.then( (user) => {
if(user){
console.log('user found in db in passport');
done(null, user)
}else{
console.log('user not found in db');
done(null, false)
}
})
} catch(err){
done(err)
}
}))
passport.use(
'register',
new Local(
{
usernameField: 'username',
passwordField: 'password',
// passReqToCallback: true,
session: false,
},
(req, username, password, done) => {
try {
User.forge({username: username}, {email: req.body.email}).fetch().then(user => {
if (user != null) {
console.log('username or email already taken');
return done(null, false, {
message: 'username or email already taken',
});
} else {
bcrypt.hash(password, 12).then(hashedPassword => {
const user = new User({
username: req.body.username,
password: hashedPassword,
email: req.body.email
})
user.save().then( () => {
res.status(200).send('user created')
return done(null, user);
})
});
}
});
} catch (err) {
return done(err);
}
},
),
);
// passport.use(new Local ( (username, password, done) => {
// User.findOne({username: username} , (err, user) =>{
// if(err){
// return done(err)
// }
// if(!user){
// return done(null, false, {message: "Incorrect username."})
// }
// if(!user.validPassword(password)){
// return done(null, false, {message: 'Incorrect password'})
// }
// return done (null, user)
// })
// }))
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(user, done) {
User
.forge({id: user})
.fetch()
.then((usr) => {
done(null, usr);
})
.catch((err) => {
done(err);
});
});
main.js
import 'dotenv/config';
import cors from 'cors';
import express from 'express';
import logger from 'morgan';
import path from 'path';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import userRoute from './routes/users';
import passport from 'passport';
import session from 'express-session';
import './config/passport';
const app = express();
app.use(cors());
app.use(logger('dev'));
// For React Stuff if need be
// app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
app.use(cookieParser());
app.use(bodyParser.json());
// you need body parser urlencoded so passport will not give a Missing Credentials error
app.use(bodyParser.urlencoded({ extended:false}));
app.use(session({
saveUninitialized: false,
resave:false,
cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, // 30 days
secret : process.env.JWT_SECRET,
}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.use('/users', userRoute);
app.use(() => (req, res, next) =>{
res.locals.user = req.user; // This is the important line
// req.session.user = user
console.log(res.locals.user);
next();
});
//build mode
// app.get('*', (req, res) => {
// res.sendFile(path.join(__dirname+'/client/public/index.html'));
// })
// module.parent prevents the
// Node / Express: EADDRINUSE, Address already in use error when unit testing
if(!module.parent){
app.listen(process.env.PORT, () =>
console.log(`Example app listening on port ${process.env.PORT}!`),
);
}
export default app;
Fixed it, there were a number of errors.
One being the
done is not a function
Which will be fixed by uncommenting
passReqToCallback: true,
two being res thats not supposed to be in the passport.js file but route file.
so remove
res.status(200).send('user created')
Now everything should be working.
passport.js
passport.use(
'register',
new Local(
{
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true,
session: false,
},
(req, username, password, done) => {
try {
User.forge({username: username}, {email: req.body.email}).fetch().then(user => {
if (user != null) {
console.log('username or email already taken');
return done(null, false, {
message: 'username or email already taken',
});
} else {
bcrypt.hash(password, 12).then(hashedPassword => {
const user = new User({
username: req.body.username,
password: hashedPassword,
email: req.body.email
})
user.save().then( () => {
return done(null, user);
})
});
}
});
} catch (err) {
return done(err);
}
},
),
);
routes/users
router.post('/register', (req, res, next) => {
passport.authenticate('register', (err, user, info) => {
if(err){
console.log(err)
}
if(info !== undefined){
console.log(info.message)
res.status(403).send(info.message)
}else{
req.logIn(user, err => {
const data = {
username: req.body.username.trim(),
password: req.body.password.trim(),
email: req.body.email.trim()
}
console.log(data);
User.forge({
username: data.username
}).fetch().then( (user) => {
console.log('user creatd in db');
res.status(200).send({
message:'user created'
})
})
})
}
})(req, res, next);
});

unable hash the password in mean stack

This is the code from routes file.
router.put('/reset/:token', function(req, res, next) {
console.log('reseting the password');
User.findOne({resetPasswordToken:req.params.token}, function(err, user) {
if(err) {
return next(err);
}
if (!user) {
return res.status(422).json({errors: [{msg: 'invalid reset token'}]});
}
user.resetPasswordToken ='';
user.resetPasswordExpires = '';
user.password = req.body.password;
User.addUser(user, (err, user) => {
if(err){
res.json({success: false, msg:'password has not changed'});
} else {
res.json({success: true, msg:'password has changed'});
}
});
});
});
This part of the code is from my schema file.
const UserSchema = mongoose.Schema({
password: {
type: String,
required: true
},
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
const User = module.exports = mongoose.model('User', UserSchema);
module.exports.addUser = function(newUser, callback){
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) throw err;
newUser.password = hash;
newUser.save(callback);
});
});
}
When I try to rest the password it is storing as I've given the input. It is not hashing the password. For example, I have given the password as "zp12345", in the database it is storing as "password" : "zp12345".
For solve the problem you need to fix your addUser method:
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
module.exports.addUser = function(newUser, callback){
bcrypt.hash(newUser.password, bcrypt.genSaltSync(10), null, (err, hash) => {
if (err) {
return next(err);
}
newUser.password = hash;
newUser.save(callback);
})
};
Here there is another example: Mongoose Pre Save Changing Password
And this is the library documentation: Bcrypt Nodejs

Is there a documentation or a tutorial for integrating passport.js into sails.js? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed last month.
Improve this question
Every tutorial or unfinished documentation out there doensn't work. This is why I ask here: Is there a simple tutorial, which really works, for passport and sails?
follow this steps two integrate passport with sails js
first :-
List these dependencies inside application_directory/package.json under dependencies
//application_directory/package.json
{
...
"dependencies": {
...
"passport": "~0.1.16",
"passport-local": "~0.1.6",
"bcrypt": "~0.7.6"
}
...
}
2-
To create user model run the following command:
sails generate model user
3- model user.js will look like the following
var bcrypt = require('bcrypt');
module.exports = {
attributes: {
username: {
type: 'string',
required: true,
unique: true
},
password: {
type: 'string',
required: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
beforeCreate: function(user, cb) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
console.log(err);
cb(err);
}else{
user.password = hash;
cb(null, user);
}
});
});
}
};
4- To create a controller in sails type the command
sails generate controller
AuthController will look like the following:
var passport = require('passport');
module.exports = {
login: function (req, res) {
res.view();
},
process: function(req, res){
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: 'login failed'
});
res.send(err);
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message: 'login successful'
});
});
})(req, res);
},
logout: function (req,res){
req.logout();
res.send('logout successful');
}
};
module.exports.blueprints = {
actions: true,
rest: true,
shortcuts: true
};
5- add the following code to application_directory/config/routes.js
module.exports.routes = {
// (This would also work if you had a file at: `/views/home.ejs`)
'/': {
view: 'home/index'
},
'/login': {
controller: 'AuthController',
action: 'login'
},
'/logout': {
controller: 'AuthController',
action: 'logout'
}
......
}
6- Inside application_directory/config create a file passport.js and add the following code to that
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
module.exports = {
express: {
customMiddleware: function(app){
console.log('Express midleware for passport');
app.use(passport.initialize());
app.use(passport.session());
}
}
};
7- Inside /api/services/ create a file passport.js and add the following code to that
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
bcrypt = require('bcrypt'); < /code>
//helper functions
function findById(id, fn) {
User.findOne(id).done(function (err, user) {
if (err) {
return fn(null, null);
} else {
return fn(null, user);
}
});
}
function findByUsername(u, fn) {
User.findOne({
username: u
}).done(function (err, user) {
// Error handling
if (err) {
return fn(null, null);
// The User was found successfully!
} else {
return fn(null, user);
}
});
}
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(
function (username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
findByUsername(username, function (err, user) {
if (err)
return done(null, err);
if (!user) {
return done(null, false, {
message: 'Unknown user ' + username
});
}
bcrypt.compare(password, user.password, function (err, res) {
if (!res)
return done(null, false, {
message: 'Invalid Password'
});
var returnUser = {
username: user.username,
createdAt: user.createdAt,
id: user.id
};
return done(null, returnUser, {
message: 'Logged In Successfully'
});
});
})
});
}
));
8- Modify the authenticated.js file present inside /api/policies/
/**
* Allow any authenticated user.
*/
module.exports = function (req, res, ok) {
// User is allowed, proceed to controller
var is_auth = req.isAuthenticated()
if (is_auth) return next();
// User is not allowed
else return res.redirect("/login");
};