passport bookshelf is not inserting user into database - postgresql

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);
});

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!

Is there an easier way to post an element in the html-post method?

const express = require("express");
const cors = require("cors");
const dotenv = require("dotenv");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const app = express();
dotenv.config();
app.use(cors());
app.use(bodyParser.json());
const { Schema } = mongoose;
const userSchema = Schema({
imageUrl: { type: String },
description: { type: String },
title: { type: String },
price: { type: Number },
});
const Users = mongoose.model("users", userSchema);
app.get("/", (req, res) => {
res.send("started");
});
`get metod`
app.get("/users", (req, res) => {
Users.find({}, (err, docs) => {
if (!err) {
res.send(docs);
} else {
res.status(404).json({ message: err });
}
});
});
app.get("/users/:id", (req, res) => {
const { id } = req.params;
Users.findById(id, (err, doc) => {
if (!err) {
if (doc) {
res.send(doc);
}
} else {
res.status(404).json({ message: err });
}
});
});
`delete metod`
app.delete("/users/:id", (req, res) => {
const { id } = req.params;
Users.findByIdAndDelete(id, (err, doc) => {
if (!err) {
res.send("Succesfully deleted");
} else {
res.status(404).json({ message: err });
}
});
});
`post metod`
app.post("/users", (req, res) => {
const obj = {
imageUrl: req.body.imageUrl,
description: req.body.description,
title: req.body.title,
price: req.body.price,
};
console.log(obj);
let user = new Users(obj);
user.save();
res.send({ message: " Succesfully added" });
});
const PORT = process.env.PORT;
const url = process.env.URL.replace("<password>", process.env.PASSWORD);
mongoose.set("strictQuery", true);
mongoose.connect(url, (err) => {
if (!err) {
console.log("DB connected");
app.listen(PORT, () => {
console.log("Server start");
});
}
});
I'm trying to learn how exactly get post delete queries work
I'm trying to reduce the code here, but no matter what I do, small errors appear in the end. I have a json string, I want to pass it to POST method. But the 'execute', and 'executeMethod ' are throwing error as below:
"The method execute(HttpUriRequest) in the type HttpClient is not applicable for the arguments (PostMethod)". i have included the depencencies.

why is this not returning the access token from JWT?

I'm trying to generate a JWT access token to verify the user through the header and avoid that after each page reload the user gets logged out. But whenever I try to try this it doesn't logs the user in.
Here is where I log the user in and create a jwt session:
router.route('/login').post((req, res, next) => {
passport.authenticate("local" , {session: false}, (err, user, info) => {
if (err) throw err;
if (!user) res.status(400).send("No user exists");
else {
req.logIn(user, {session: false}, err => {
if (err) throw error;
const token = jwt.sign(user, 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMTAwOTUiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlcyI6WyJ3cml0ZXIiLCJtb2RlcmF0b3IiXSwiaWF0IjoxNTIzODE3OTk5LCJleHAiOjE1MjQ0MjI3OTl9.rrpyIW0ftJGna1c_SHH6Hus8hBd2-CUqofaSIUHj0C0');
res.json({user, token});
})
}
})(req, res, next)
})
Here is where I set the callback for jwt:
module.exports = function (passport) {
passport.use(
new localStrategy((username, password, done) => {
Users.findOne({username: username}, (err, user) => {
if (err) throw err
if (!user) return done(null, false);
bcrypt.compare(password, user.password, (err, result) => {
if (err) throw err;
if(result === true) {
return done(null, user)
} else {
return done(null, false)
}
})
})
})
)
passport.use(new JWTStrategy({
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey : 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMTAwOTUiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlcyI6WyJ3cml0ZXIiLCJtb2RlcmF0b3IiXSwiaWF0IjoxNTIzODE3OTk5LCJleHAiOjE1MjQ0MjI3OTl9.rrpyIW0ftJGna1c_SHH6Hus8hBd2-CUqofaSIUHj0C0'
},
function (jwtPayload, cb) {
//find the user in db if needed. This functionality may be omitted if you store everything you'll need in JWT payload.
return Users.findOneById(jwtPayload.id)
.then(user => {
return cb(null, user);
})
.catch(err => {
return cb(err);
});
}
));

why an empty array when I do an app.get()?

So I have a mongodb database to which I have imported some json data to its collection.
When I do a db.posts.find(), the data imported successfully, but when I attempt a get request, I get an empty array [].
Here is my server.js file:
'use strict';
const express = require('express');
const morgan = require('morgan');
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const { DATABASE_URL, PORT } = require('./config');
const { BlogPost } = require('./models');
const app = express();
app.use(morgan('common'));
app.use(express.json());
app.get('/posts', (req, res) => {
BlogPost
.find()
.then(posts => {
res.json(posts.map(post => post.serialize()));
})
.catch(err => {
console.error(err);
res.status(500).json({ error: 'something went terribly wrong' });
});
});
app.get('/posts/:id', (req, res) => {
BlogPost
.findById(req.params.id)
.then(post => res.json(post.serialize()))
.catch(err => {
console.error(err);
res.status(500).json({ error: 'something went horribly awry' });
});
});
app.post('/posts', (req, res) => {
const requiredFields = ['title', 'content', 'author'];
for (let i = 0; i < requiredFields.length; i++) {
const field = requiredFields[i];
if (!(field in req.body)) {
const message = `Missing \`${field}\` in request body`;
console.error(message);
return res.status(400).send(message);
}
}
BlogPost
.create({
title: req.body.title,
content: req.body.content,
author: req.body.author
})
.then(blogPost => res.status(201).json(blogPost.serialize()))
.catch(err => {
console.error(err);
res.status(500).json({ error: 'Something went wrong' });
});
});
app.delete('/posts/:id', (req, res) => {
BlogPost
.findByIdAndRemove(req.params.id)
.then(() => {
res.status(204).json({ message: 'success' });
})
.catch(err => {
console.error(err);
res.status(500).json({ error: 'something went terribly wrong' });
});
});
app.put('/posts/:id', (req, res) => {
if (!(req.params.id && req.body.id && req.params.id === req.body.id)) {
res.status(400).json({
error: 'Request path id and request body id values must match'
});
}
const updated = {};
const updateableFields = ['title', 'content', 'author'];
updateableFields.forEach(field => {
if (field in req.body) {
updated[field] = req.body[field];
}
});
BlogPost
.findByIdAndUpdate(req.params.id, { $set: updated }, { new: true })
.then(updatedPost => res.status(204).end())
.catch(err => res.status(500).json({ message: 'Something went wrong' }));
});
app.delete('/:id', (req, res) => {
BlogPost
.findByIdAndRemove(req.params.id)
.then(() => {
console.log(`Deleted blog post with id \`${req.params.id}\``);
res.status(204).end();
});
});
app.use('*', function (req, res) {
res.status(404).json({ message: 'Yo stupido, Not Found' });
});
// closeServer needs access to a server object, but that only
// gets created when `runServer` runs, so we declare `server` here
// and then assign a value to it in run
let server;
// this function connects to our database, then starts the server
function runServer(databaseUrl, port = PORT) {
return new Promise((resolve, reject) => {
mongoose.connect(databaseUrl, err => {
if (err) {
return reject(err);
}
server = app.listen(port, () => {
console.log(`Your app is listening on port ${port}`);
resolve();
})
.on('error', err => {
mongoose.disconnect();
reject(err);
});
});
});
}
// this function closes the server, and returns a promise. we'll
// use it in our integration tests later.
function closeServer() {
return mongoose.disconnect().then(() => {
return new Promise((resolve, reject) => {
console.log('Closing server');
server.close(err => {
if (err) {
return reject(err);
}
resolve();
});
});
});
}
// if server.js is called directly (aka, with `node server.js`), this block
// runs. but we also export the runServer command so other code (for instance, test code) can start the server as needed.
if (require.main === module) {
runServer(DATABASE_URL).catch(err => console.error(err));
}
module.exports = { runServer, app, closeServer };
and here is my config.js file:
'use strict';
exports.DATABASE_URL =
process.env.DATABASE_URL || 'mongodb://localhost/seed_data';
exports.PORT = process.env.PORT || 8080;
In my models.js file, this is what my mongoose model looks like:
'use strict';
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const blogPostSchema = mongoose.Schema({
author: {
firstName: String,
lastName: String
},
title: {type: String, required: true},
content: {type: String},
created: {type: Date, default: Date.now}
});
blogPostSchema.virtual('authorName').get(function() {
return `${this.author.firstName} ${this.author.lastName}`.trim();
});
blogPostSchema.methods.serialize = function() {
return {
id: this._id,
author: this.authorName,
content: this.content,
title: this.title,
created: this.created
};
};
const BlogPost = mongoose.model('BlogPost', blogPostSchema);
module.exports = {BlogPost};
The issue is with your first parameter in your mongoose.model(). Since you shared that the collection name is posts, that should be the name of your first parameter as a string 'posts'.
Checkout this documentation on how to declare collection name and model name:
How to declare collection name and model name in mongoose
So your mongoose.model() should look like this:
const BlogPost = mongoose.model('posts', blogPostSchema);
Give that a try.

I have an error with passport.js implementation in 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.