Requiring sequilize modules returns undefined in some express app files - javascript

Goal - creating middleware-like callback in userHandler in util.js util.js for some express routes in express app, generated with express-generator and sequlize-cli.
Expected - user model successfully used in routes and userHandler in util.js.
Result - user model successfully works in login route, but is undefined in userHandler in util.js. When requiring models fully getting {}. Require seems correct.
console error
[nodemon] starting `node ./bin/www`
{}
Fri, 15 Jan 2021 14:54:42 GMT server:server Listening on port 8000
here
Fri, 15 Jan 2021 15:53:33 GMT server:server TypeError: Cannot read property 'findByPk' of undefined
at C:\Users\bpali\Desktop\authorization1\server\utils.js:40:27
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async C:\Users\bpali\Desktop\authorization1\server\utils.js:12:5
GET /users/my-info 500 23.306 ms - 2
File structure
util.js
const jwt = require('jsonwebtoken');
var debug = require('debug')('server:server');
const secret = process.env.SECRET || SgxLbntQGfukf1yEAYZyzLBJKvop8Z2k6q1YG0wOHXZMgbVNhhsLaSIOB8Rkw9Pe4anRpTAE8h95RCwDYLjSsbJhpdZruVKzpzGgw1bnqCLLS1gAU1R1uChtRYDkSBOoZkFdnG3sRVLtJz63gqEQkq7owtaACYOXAd1fPOFkUgwgxammROY1NgpmUJR9YOwhVtcq5mTu;
const { User } = require('./models');
const models = require('./models');
console.log(models); // {} - ???
const verifyToken = async (token) => new Promise((resolve, reject) => jwt.verify(token, secret, (err, decoded) => err ? reject(err) : resolve(decoded)));
const signToken = async (payload, options = { expiresIn: '365d' }) => new Promise((resolve, reject) => jwt.sign(payload, secret, options, (err, token) => err ? reject(err) : resolve(token)));
const asyncErrorHandler = (asyncFn, ...args) => async (req, res, next) => {
try {
await asyncFn(req, res, next, ...args);
next();
} catch (e) {
debug(e);
res.status(500).send(e);
}
}
const userHandler = (allowedTypes) => asyncErrorHandler(async (req, res, next) => {
const autHeader = req.get('Authorization');
if (!autHeader) {
res.status(401).send('Unauthorized');
next('route');
}
const autSplit = autHeader.split && autHeader.split(' ');
if (!autSplit || autSplit.length !== 2 || !(autSplit[0] === 'Token' || autSplit[0] === 'Bearer')) {
res.status(401).send('Wrong format of authorisation');
next('route');
}
const token = autSplit[1];
console.log('here');
let decodedToken;
try {
decodedToken = await verifyToken(token);
} catch (e) {
res.status(403).send(`Wrong token! ${e.name + ': ' + e.message}`);
next('route');
}
const { login } = decodedToken;
const user = await User.findByPk(login);
if (!user) {
res.status(403).send('Wrong user');
next('route');
}
req.user = user;
if (allowedTypes && allowedTypes.indexOf && allowedTypes.indexOf(user.role) === -1) {
res.status(403).send('Not allowed role');
next('route');
}
next();
});
module.exports = { verifyToken, signToken, asyncErrorHandler, userHandler }
routes/users.js
var express = require('express');
var router = express.Router();
const { QueryTypes } = require('sequelize');
const { User, sequelize } = require('../models');
const { asyncErrorHandler, userHandler } = require('../utils');
/* GET users listing. */
// router.get('/', function(req, res, next) {
// res.send('respond with a resource');
// });
router.post('/login', asyncErrorHandler(async function (req, res, next) {
const { login, password } = req.body;
if (!login || !password || typeof login !== 'string' || typeof password !== 'string'){
res.status(400).send('Not empty login and password strings needed in json body');
next();
}
const user = await User.findByPk(login);
if (!user){
res.status(400).send('Absent login');
next('route');
}
if (!(await user.checkPassword(password))){
res.status(400).send('Wrong password');
next('route');
};
const { type } = user
res.json({
token: await user.makeToken(),
user: { login, type },
});
// next();
}));
router.post('/register', asyncErrorHandler(async function (req, res, next) {
const { login, password } = req.body;
if (!login || !password || typeof login !== 'string' || typeof password !== 'string'){
res.status(400).send('Not empty login and password strings needed in json body');
next('route');
}
if (await User.findByPk(login)) {
res.status(403).send('Busy login');
next('route');
}
const user = User.build({ login, type: 'user' });
await user.setPassword(password);
await user.save();
const { type } = user
res.json({ login, type });
// next();
}));
router.get('/my-info', userHandler(), function (req, res, next) {
const { login, type } = req.user;
res.json({ login, type });
});
router.get('/user-info/:login', userHandler(['admin']), asyncErrorHandler(async function (req, res, next) {
const user = await (User.findByPk(req.params.login));
if (!user) {
res.status(404).send('Login not found');
next('route');
}
const { login, type } = user;
req.json({ login, type });
// next();
}));
router.get('/list-users', userHandler(['admin']), asyncErrorHandler(async function (req, res, next) {
const users = await sequelize.query("SELECT * FROM `users`", { type: QueryTypes.SELECT });
console.log(users);
res.json(users);
}));
module.exports = router;
models/index.js
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
models/user.js
'use strict';
const {
Model
} = require('sequelize');
const bcrypt = require('bcrypt');
const { signToken } = require('../utils');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
async setPassword (password) {
this.password = await bcrypt.hash(password, 10);
}
async checkPassword (password) {
return await bcrypt.compare(password, this.password);
}
async makeToken() {
const { login } = this;
return await signToken({ login });
}
};
User.init({
login: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
type: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
sequelize,
modelName: 'User',
});
return User;
};
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
bin/www
#!/usr/bin/env node
require('dotenv').config()
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('server:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
package.json
{
"name": "server",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon ./bin/www"
},
"dependencies": {
"bcrypt": "^5.0.0",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"dotenv": "^8.2.0",
"express": "~4.16.1",
"hbs": "~4.0.4",
"http-errors": "~1.6.3",
"jsonwebtoken": "^8.5.1",
"morgan": "~1.9.1",
"pg": "^8.5.1",
"pg-hstore": "^2.3.3",
"sequelize": "^6.3.5"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
.env
DEBUG=server:*
PORT=8000
SECRET=SgxLbntQGfukf1yEAYZyzLBJKvop8Z2k6q1YG0wOHXZMgbVNhhsLaSIOB8Rkw9Pe4anRpTAE8h95RCwDYLjSsbJhpdZruVKzpzGgw1bnqCLLS1gAU1R1uChtRYDkSBOoZkFdnG3sRVLtJz63gqEQkq7owtaACYOXAd1fPOFkUgwgxammROY1NgpmUJR9YOwhVtcq5mTu

Problem found - unclear circular dependency
utils.js requires models/index.js
models/index.js not directly requires models/user.js
models/user.js requires utils.js, more exactly - signToken function from it
What was done - renamed utils.js in routeUtils.js, put signToken and verifyToken functions to new file tokenUtils.js, updated imports in other files, so this circular dependency will not happen, after this, it imported correctly.
Main updates:
File structure
routeUtils.js
// const jwt = require('jsonwebtoken');
var debug = require('debug')('server:server');
// const secret = process.env.SECRET || SgxLbntQGfukf1yEAYZyzLBJKvop8Z2k6q1YG0wOHXZMgbVNhhsLaSIOB8Rkw9Pe4anRpTAE8h95RCwDYLjSsbJhpdZruVKzpzGgw1bnqCLLS1gAU1R1uChtRYDkSBOoZkFdnG3sRVLtJz63gqEQkq7owtaACYOXAd1fPOFkUgwgxammROY1NgpmUJR9YOwhVtcq5mTu;
const { User } = require('./models');
const { verifyToken } = require('./tokenUtils');
// const models = require('./models');
// console.log(models); // {} - ???
// const verifyToken = async (token) => new Promise((resolve, reject) => jwt.verify(token, secret, (err, decoded) => err ? reject(err) : resolve(decoded)));
// const signToken = async (payload, options = { expiresIn: '365d' }) => new Promise((resolve, reject) => jwt.sign(payload, secret, options, (err, token) => err ? reject(err) : resolve(token)));
const asyncErrorHandler = (asyncFn, ...args) => async (req, res, next) => {
try {
await asyncFn(req, res, next, ...args);
// next();
} catch (e) {
debug(e);
res.status(500).send(e);
}
}
const userHandler = (allowedTypes) => asyncErrorHandler(async (req, res, next) => {
const autHeader = req.get('Authorization');
if (!autHeader) {
res.status(401).send('Unauthorized');
next('route');
}
const autSplit = autHeader.split && autHeader.split(' ');
if (!autSplit || autSplit.length !== 2 || !(autSplit[0] === 'Token' || autSplit[0] === 'Bearer')) {
res.status(401).send('Wrong format of authorisation');
next('route');
}
const token = autSplit[1];
// console.log('here');
let decodedToken;
try {
decodedToken = await verifyToken(token);
} catch (e) {
debug(e);
res.status(403).send(`Wrong token! ${e.name + ': ' + e.message}`);
next('route');
}
const { login } = decodedToken;
const user = await User.findByPk(login);
if (!user) {
res.status(403).send('Wrong user');
next('route');
}
req.user = user;
if (allowedTypes && allowedTypes.indexOf && allowedTypes.indexOf(user.type) === -1) {
// console.log('here');
res.status(403).send('Not allowed user type');
next('route');
}
next();
});
module.exports = { /* verifyToken, signToken, */ asyncErrorHandler, userHandler }
tokenUtils.js
const jwt = require('jsonwebtoken');
const secret = process.env.SECRET || SgxLbntQGfukf1yEAYZyzLBJKvop8Z2k6q1YG0wOHXZMgbVNhhsLaSIOB8Rkw9Pe4anRpTAE8h95RCwDYLjSsbJhpdZruVKzpzGgw1bnqCLLS1gAU1R1uChtRYDkSBOoZkFdnG3sRVLtJz63gqEQkq7owtaACYOXAd1fPOFkUgwgxammROY1NgpmUJR9YOwhVtcq5mTu;
const verifyToken = async (token) => new Promise((resolve, reject) => jwt.verify(token, secret, (err, decoded) => err ? reject(err) : resolve(decoded)));
const signToken = async (payload, options = { expiresIn: '365d' }) => new Promise((resolve, reject) => jwt.sign(payload, secret, options, (err, token) => err ? reject(err) : resolve(token)));
module.exports = { verifyToken, signToken };
models/user.js
'use strict';
const {
Model
} = require('sequelize');
const bcrypt = require('bcrypt');
const { signToken } = require('../tokenUtils');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
async setPassword (password) {
this.password = await bcrypt.hash(password, 10);
}
async checkPassword (password) {
return await bcrypt.compare(password, this.password);
}
async makeToken() {
const { login } = this;
return await signToken({ login });
}
};
User.init({
login: {
type: DataTypes.STRING,
primaryKey: true,
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
type: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
sequelize,
modelName: 'User',
});
return User;
};

Related

Fetching csrf token using csurf from function not api route

I created a api route named "/add" that renders a file named "additional-user-info" with crsf token and it works fine
app.js
const express = require("express");
require("dotenv").config();
const mongoose = require("mongoose");
const authRoutes = require("./routes/authRoutes");
const cookieParser = require("cookie-parser");
var csrf = require("csurf");
var csrfProtection = csrf({ cookie: true });
const {
requireAuth,
checkUser,
displayallusers,
deleteUser,
searchuser,
isAdmin,
} = require("./middleware/authMiddleware");
const mongoSantize = require("express-mongo-sanitize");
const xss = require("xss-clean");
const app = express();
// middleware
app.disable("x-powered-by");
app.use(express.static("public"));
app.use(mongoSantize());
app.use(xss());
app.use(express.json());
app.use(cookieParser());
//handling wrong invlid json syntax
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err.status === 400 && "body" in err) {
//console.error(err);
return res.status(400).send("Invalid Json formatting"); // Bad request
}
});
// view engine
app.set("view engine", "ejs");
// database connection
const mongoUsername = process.env.MONGO_USERNAME;
const mongoPassword = process.env.MONGO_PASSWORD;
const dbURI =
"mongodb+srv://" +
mongoUsername +
":" +
mongoPassword +
"#boioboi/real-auth?retryWrites=true&w=majority";
mongoose
.connect(dbURI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then((result) => app.listen(3000))
.catch((err) => console.log(err));
// routes
app.get("*", checkUser);
app.get("/add", csrfProtection, (req, res) => {
console.log("zeeeeeeeee");
console.log(req.csrfToken());
res.render("additional-user-info", { csrfToken: req.csrfToken() });
});
app.get("/", (req, res) => res.render("home"));
app.get("/smoothies", requireAuth, (req, res) => res.render("smoothies"));
app.use(authRoutes);
Website has a functionality that if a user creates an account or logins into his account and has certian database fields empty website would render same "additional-user-info" page to get his info
This is a function that checks if a user is valid or not and renders "additional-user-info" page if certain fields are empty
authMiddleware
const checkUser = (req, res, next) => {
const token = req.cookies.jwt;
if (token) {
jwt.verify(token, jwt_secret, async (err, decodedtoken) => {
if (err) {
console.log(err.message);
res.locals.user = null;
next();
} else {
console.log(decodedtoken);
let user = await User.findById(decodedtoken.id);
res.locals.user = user;
if (
(user.additionalinfo.fullname == "") |
(user.additionalinfo.address == "") |
(user.additionalinfo.city == "") |
(user.additionalinfo.district == "") |
(user.additionalinfo.propertytype == "") |
(user.additionalinfo.adharcard == "") |
(user.additionalinfo.pancard == "")
) {
return res.render("additional-user-info"); //crsf-token is not defined error here
}
next();
}
});
} else {
res.locals.user = null;
next();
}
};
But when it renders "additional-user-info" page from checkUser() function it gives error saying "csrfToken is not defined". How should i fix this issue?

Node.js, Express: next is not defined,

I am getting Error: next is not defined. I don't know in which file I am getting this error.
Code:
server.js
require("dotenv").config({
path: "C:/Users/dogra/Documents/Web Development/Portfolio/FullStack/AdvanceAuth/.env",
});
const express = require("express");
const connectDB = require("./config/db");
const errorHandler = require("./middleware/errorHandler");
connectDB();
const app = express();
app.use(express.json());
app.use("/api/auth", require("./routes/authRoutes"));
app.use("/api/private", require("./routes/privateRoutes"));
app.use(errorHandler);
const PORT = process.env.PORT || 5000;
const server = app.listen(PORT, () => {
console.log(`Server running on PORT: ${PORT}`);
});
process.on("unhandledRejection", (err, promise) => {
console.log(`Logged Error: ${err.message}`);
server.close(() => process.exit(1));
});
controllers
authController.js
const User = require("../models/userModel");
const ErrorResponse = require("../utils/errorResponse");
exports.register = async (req, res, next) => {
const { username, email, password } = req.body;
try {
const user = await User.create({
username,
email,
password,
});
sendToken(user, 201, res);
} catch (error) {
next(error);
}
};
exports.login = async (req, res, next) => {
const { email, password } = req.body;
if (!email || !password) {
return next(new ErrorResponse("Please enter credentials properly", 400));
}
try {
const user = await User.findOne({ email }).select("+password");
if (!user) {
return next(new ErrorResponse("Email not registered", 401));
}
const isMatch = await user.matchPasswords(password);
if (!isMatch) {
return next(new ErrorResponse("Invalid Password", 401));
}
sendToken(user, 200, res);
} catch (error) {
next();
}
};
exports.forgotPassword = (req, res, next) => {
res.send("ForgotPassword Route");
};
exports.resetPassword = (req, res, next) => {
res.send("ResetPassword Route");
};
const sendToken = (user, statusCode, res) => {
const token = user.getSignedJwtToken();
res.status(statusCode).json({ success: true, token });
};
privateController.js
exports.private = (req, res, next) => {
res.status(200).json({
success: true,
data: "You got access to the private data in this route",
});
};
routes
authRoutes.js
const express = require("express");
const router = express.Router();
// controllers
const {
register,
login,
forgotPassword,
resetPassword,
} = require("../controllers/authControllers");
router.route("/register").post(register);
router.route("/login").post(login);
router.route("/forgotPassword").post(forgotPassword);
router.route("/resetPassword/:resetToken").put(resetPassword);
module.exports = router;
privateRoutes.js
const express = require("express");
const router = express.Router();
const { private } = require("../controllers/privateControllers");
const { protect } = require("../middleware/authMiddleware");
router.route("/").get(protect, private);
module.exports = router;
middlewre
authMiddleware.js
const jwt = require("jsonwebtoken");
const User = require("../models/userModel");
const ErrorResponse = require("../utils/errorResponse");
exports.protect = async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
token = req.headers.authorization.split(" ")[1];
}
if (!token) {
return next(
new ErrorResponse("Not authorized to access to this route", 401)
);
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findById(decoded.id);
if (!user) {
return next(new ErrorResponse("No User found with this id", 404));
}
req.user = user;
next();
} catch (error) {
return next(new ErrorResponse("Not Authorized to access this route", 401));
}
};
errorHandler.js
const ErrorResponse = require("../utils/errorResponse");
const errorHandler = (err, req, res, next) => {
let error = { ...err };
error.message = err.message;
if (err.code === 11000) {
const message = `Duplicate Field value entered`;
error = new ErrorResponse(message, 400);
}
if (err.name === "ValidationError") {
const message = Object.values(err.errors).map((val) => val.message);
error = new ErrorResponse(message, 400);
}
console.log(error.message);
res.status(error.statusCode || 500).json({
success: false,
error: error.message || "Server Error",
});
};
module.exports = errorHandler;
utils
errorResponse.js
class ErrorResponse extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
module.exports = ErrorResponse;
models
userModel.js
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: [true, "Please enter your username"],
},
email: {
type: String,
required: [true, "Please enter your email"],
unique: true,
lowercase: true,
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 provide a valid email",
],
},
password: {
type: String,
required: [true, "Please enter a valid password"],
minlength: 8,
select: false,
},
resetPasswordToken: String,
resetPasswordExpired: Date,
});
// Hashing Password
UserSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
// Checking if password entered is correct or not
UserSchema.methods.matchPasswords = async function (password) {
return await bcrypt.compare(password, this.password);
};
// Converting user data into JSON WEB TOKEN
UserSchema.methods.getSignedJwtToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRE,
});
};
const User = mongoose.model("User", UserSchema);
module.exports = User;
Sorry, for the long question but I really don't know where is the problem. I googled, & found we get next is not defined error when you don't define it source. But, I have defined it inside my all controllers & middleware's.
The problem was in my dotenv path in server.js Since I cloned my project from GitHub in my new laptop the path was different & I forgot to update the path.

TypeError: Cannot read property 'method' of undefined express

Im making a dashboard for a Discord Bot, but i keep getting the error TypeError: Cannot read property 'method' of undefined. The code of my app is:
const http = require('http');
const path = require('path');
const client = require("./Client");
const express = require('express');
const reqip = require('request-ip');
const passport = require('passport');
const Discord = require('discord.js');
const session = require('express-session');
const getFilesSync = require("..//Utils/fileWalk");
const SQLiteStore = require("connect-sqlite3")(session);
const { Strategy } = require('passport-discord').Strategy;
const port = process.env.port || 80;
class App {
constructor(locals = {}) {
this.express = express();
this.express.set("view engine", "ejs");
this.express.set("port", port);
this.express.set("json spaces", 2);
this.express.locals = locals;
/ * MiddleWare Functions * /;
this.express.use(express.json());
this.express.use(express.urlencoded({
extended: false
}))
this.express.use(reqip.mw());
this.express.use('/assets', express.static(__dirname + "/../Assets"));
bindAuth(this.express, client);
this.express.use(passport.initialize());
this.express.use(passport.session());
this.express.use(async (req, res, next) => {
req.bot = client;
next();
});
this.loadRoutes().loadErrorHandler();
}
listen(port) {
return new Promise((resolve) => this.express.listen(port, resolve));
}
loadRoutes() {
const routesPath = path.join(__dirname, "../routes");
const routes = getFilesSync(routesPath);
if (!routes.length) return this;
routes.forEach((filename) => {
const route = require(path.join(routesPath, filename));
const routePath =
filename === "index.js" ? "/" : `/${filename.slice(0, -3)}`;
try {
this.express.use(routePath, route);
} catch (error) {
console.error(`Error occured with the route "${filename}"\n\n${error}`);
}
});
return this;
}
loadErrorHandler() {
this.express.use((req, res) => {
res.status(404);
if (req.accepts("html")) return res.render("404", {req});
if (req.accepts("json"))
return res.send({
status: 404,
error: "Not found",
});
res.type("txt").send("404 - Not found");
});
return this;
}
}
function bindAuth(app, client) {
app.use(session({store: new SQLiteStore(), secret: "nosecretlol", resave: false, saveUninitialized: false}))
passport.serializeUser(function(user, done) {
done(null, user);
})
passport.deserializeUser(function(obj, done) {
done(null, obj);
})
passport.use(
new Strategy(
{
clientID: process.env.bot_id,
clientSecret: process.env.bot_secret,
callbackURL: process.env.bot_redirect,
scope: ["identify", "guilds"]
},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function() {
profile.tokens = { accessToken }
return done(null, profile)
})
})
)
}
module.exports = App;
And in my index i make my app like this:
const App = require("myfile");
(async () => {
await new App().listen(process.env.port || 80)
})()
The error says is in: node_modules\express\lib\router\index.js:139:34)
I tried with all and i cannot solve this, i asked many persons but no ones give me a answer that can solve my question.
Like i said this is for a Discord Bot Dashboard

isAuthenticated() in Passport js always return false

I have been browsing the forum but I am unable to find the error in my code , it always results in false and I am not able to solve it , Please help me...
Is there any other way to authenticate user instead of passport so that I can use it.I am adding more sentences as it is not allowing me to post my query,Sorry..
const http = require("http"),
hostname = "127.0.0.1",
port = 3000,
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
express = require("express"),
passport = require("passport"),
localStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose"),
User = require("./models/user");
app = express();
mongoose.connect("mongodb://localhost/drive", { useNewUrlParser: true });
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(passport.initialize());
app.use(passport.session());
app.use(
require("express-session")({
secret: "Beta tumse na ho payega",
resave: false,
saveUninitialized: false
})
);
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(bodyParser.urlencoded({ extended: true }));
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
});
app.get("/", function(req, res) {
res.render("index");
});
app.get("/register", function(req, res) {
res.send("hello");
});
app.get("/login", function(req, res) {
res.render("login");
});
app.post(
"/login",
passport.authenticate("local", {
successRedirect: "/",
failureRedirect: "/login"
}),
function(req, res) {}
);
app.get("/logout", function(req, res) {
req.logout();
res.redirect("/");
});
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
console.log("Not logged");
res.redirect("/login");
}
}
app.get("/secret", isLoggedIn, function(req, res) {
res.send("You are logged in");
});
app.post("/register", function(req, res) {
if (req.body.password === req.body.cpassword) {
User.register(
new User({ username: req.body.username }),
req.body.password,
function(err, user) {
if (err) console.log(err);
else
passport.authenticate("local")(req, res, function() {
res.send("signed up");
});
}
);
} else res.send("Password Mismatch");
});
//DRIVE SCHEMA
//var driveSchema = mongoose.Schema({
// title: String,
// created: { type: Date, default: Date.now }
//});
app.listen(port, hostname, function() {
console.log("Server is running at " + hostname + "/" + port);
});
//./models/user.js file
const mongoose = require("mongoose"),
passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
I have used passport and jwt library, to authenticate and maintain session for the user. There is no need to maintain user session on server side.
apis/apis.js : This file has all apis end points. /login url will authenticate user using passport and send a token to the client using jwt
const passport = require('passport')
const expRoute = require('express').Router();
let exporter = process.exporter;
expRoute.post('/login', (req, res, next) => {
passport.authenticate(
'local',
{
// successRedirect: '/',
// failureRedirect: '/login',
successFlash: 'Welcome!',
failureFlash: 'Invalid username or password.'
},
(err, user, info) => {
if (err) {
return res.status(500).json(err)
}
else if (user) {
return res.status(200).json({
token: exporter.generateToken(user)
})
}
else {
return res.status(400).json(info)
}
}
)(req, res, next);
})
expRoute.get('/view', exporter.authenticateToken, (req, res) => {
let param = req.finalTokenExtractedData
if (param && exporter.isObjectValid(param, 'tokenId', true, true)) {
let condition = {
_id: param.tokenId
}
let options = {
_id: 0,
password: 0,
__v: 0
}
process.USER.findOne(condition, options) // mongo find
.then((data) => {
res.status(200).json({
result: data,
msg: 'success'
})
})
.catch((mongoErr) => {
exporter.logNow(`USER mongo Error: ${mongoErr}`)
res.status(400).json({
msg: 'user not found'
})
})
}
else {
res.status(404).json({
msg: 'invalid token'
})
}
})
module.exports = expRoute
common/env.js: This file will initialise all connections such mongo, require few files will be used as global
process.CONFIG = require('../configs/config.json')
process.exporter = require("../lib/exporter.js")
process.dbInit = (globalName, mongoUrl, collectionName) => {
require("../models/db-init.js")(mongoUrl, collectionName)
.then((modelObj) => {
process[globalName] = modelObj // will be used as global
})
.catch((dbInitErr) => {
process.exporter.logNow(`dbInit Error: ${dbInitErr}`)
process.exit()
});
}
lib/exporter.js: This file has exporter class which consist of all major functions like mongo connection, authenticateToken, verifyPassword, etc.
const fs = require('fs'),
redis = require("redis"),
path = require("path"),
mongoose = require('mongoose'); mongoose.set('useCreateIndex', true);
const Schema = mongoose.Schema;
var bcrypt = require('bcryptjs')
var jwt = require('jsonwebtoken')
class Exporter {
mongoConnection(mongoURI, schemaObj) {
return new Promise(async (resolve, reject) => {
if (!mongoURI || typeof mongoURI == 'undefined' || mongoURI.length < 1)
return reject('invalid mongo connection url');
return resolve(mongoose.createConnection(mongoURI, { useNewUrlParser: true }))
})
}
createMongoSchema(schemaObj) {
return (new Schema(schemaObj));
}
createMongoModel(mongoDB, collectionName, newSchema) {
if (newSchema)
return mongoDB.model(collectionName, newSchema)
return mongoDB.model(collectionName)
}
authenticateToken(req, res, next) {
const bearerHeader = req.header('authorization')
if (typeof bearerHeader != 'undefined') {
const bearer = bearerHeader.split(' ')
const bearerToken = bearer[1]
jwt.verify(bearerToken, process.CONFIG.jwt.token.activated, (err, data) => {
if (err)
res.status(400).json({
msg: "Invalid token or please try to login again"
})
else {
process.exporter.getSingleHashKeysValuesFromRedis('expired_token', bearerToken)
.then((redisTokendata) => {
if (redisTokendata)
res.status(400).json({
msg: "token expired"
})
else {
req.finalTokenExtractedData = data
// if (req.originalUrl.trim() == process.logoutURL.trim())
req.jwtToken = {
token: bearerToken,
secret: process.CONFIG.jwt.token.activated
}
next()
}
})
.catch((redisTokenError) => {
process.exporter.logNow(`redis token error: ${redisTokenError}`)
res.status(400).json({
msg: "Some went wrong while checking token. Please try later."
})
})
}
})
}
else
res.status(400).json({
msg: "invalid token"
})
}
generateToken(data) {
let expiry = new Date();
// expiry.setDate(expiry.getDate() + 7)
expiry.setMinutes(expiry.getMinutes() + 5)
return jwt.sign({
tokenId: data._id,
exp: parseInt(expiry.getTime() / 1000),
}, process.CONFIG.jwt.token.activated)
}
createPassword(password) {
return new Promise((resolve, reject) => {
if (typeof password == 'undefined' && password == '')
return reject('password empty')
bcrypt.hash(password, 10, async (bErr, hash) => {
if (bErr)
reject(bErr)
else
resolve(hash)
})
})
}
verifyPassword(enteredPassword, savePassword) {
return bcrypt.compareSync(enteredPassword, savePassword)
}
}
module.exports = (new Exporter());
index.js: This is file which you will execute node index.js.
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const passport = require('passport');
require('./common/env')
require('./configs/passport')
const app = express()
const cors = require('cors')
app.use(cors());
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true}))
app.use(passport.initialize())
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
let apis = require('./apis/api')
app.use('/user', apis)
/**
* 404 Handler
*/
app.use((req, res, next)=>{
return res.status(404).send("Endpoint "+req.url +" not found");
})
/**
* if any error or exception occurred then write into a JS file so that app can be restarted
*/
process.on('uncaughtException', (err) => {
console.error(err.stack);
});
app.listen(3000, function(server) {
console.log("App listening at 3000");
});
When index.js file has been executed successfully and listening to a port 3000, then use this URL http://localhost:3000/user/login for authentication, it will accept your username and password, then authenticate using passport and send a token to the client as response. The token can contain user data in encrypted form and have expiry time.
Reference link: https://github.com/arjun-707/login-logout-jwt-nodejs
You need the express-session module.
server.js
// Require a possible config.js file with your configuration variables
const Config = require('./models/config.js');
// If the config module is formed as a class
const config = new Config();
const express = new('express');
const app = express();
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const uuid = require('uuid/v4');
const mongoose = require('mongoose');
// Require your custom passport local strategy file
const passport = require('./models/sessions');
mongoose.connect('mongodb://localhost:27017/your_db_name', {
useNewUrlParser: true
});
// Set the session options
app.use(session({
// Use UUIDs for session IDs
genid: (req) => {
return uuid()
},
// If you want to store the session in MongoDB using mongoose
// Require your personal mon
store: new MongoStore({
mongooseConnection: mongoose.connection
}),
// Define the session secret in env variable or in config file
secret: process.env.SESSION_SECRET || config.sessionSecretKey,
resave: false,
saveUninitialized: true
}));
// Initialize the passport module
app.use(passport.initialize());
// Tell to passport to use session
app.use(passport.session());
./models/session.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt-nodejs');
// Your custom MongoDB connection module
const db = require('./db');
// Configure passport.js to use the local strategy
passport.use(new LocalStrategy({
usernameField: 'username'
},
(username, password, done) => {
db.User.find({
username: username // But it could use email as well
}).then(res => {
const user = JSON.parse(JSON.stringify(res[0]));
if (!user) {
return done(null, false, {
message: 'Invalid credentials.\n'
});
}
if (!bcrypt.compareSync(password, user.password)) {
return done(null, false, {
message: 'Invalid credentials.\n'
});
}
return done(null, user);
}).catch(error => done(error));
}
));
// Tell passport how to serialize the user
passport.serializeUser((user, done) => {
done(null, user._id);
});
// Tell passport how to deserialize the user
passport.deserializeUser((id, done) => {
db.User.find({
_id: id
}).then(res => {
const response = typeof res !== undefined && res.length != 0 ? JSON.parse(JSON.stringify(res[0])) : null;
done(null, response)
}).catch(error => done(error, false))
});
// Export passport for external usage
module.exports = passport;
./models/db.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const uuid = require('uuid/v4');
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/your_db_name', {
useNewUrlParser: true
});
// Define the models container
let models = {};
// Prepare your user schema
const userSchema = Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
// Assign the user schema
models.User = mongoose.model('User', userSchema);
// Export for external usage
module.exports = models;
/*
In that way you can wrap in "models" all schemas:
const newSchema = Schema({
name: String
});
models.Newschema = mongoose.model('Newschema', newSchema);
module.exports = models;
And use it externally like:
const db = require('./models/db');
db.User.find({}).then(docs => {}).catch(err => {});
db.Newschema.find({}).then(docs => {}).catch(err => {});
Etc....
*/
./models/config.js
class Config {
constructor() {
this.sessionSecretKey = "my-awesome-secretkey";
/* And other configurations */
}
}
module.exports = Config;
/*
Externally use like:
const Config = require('./models/config');
const config = new Config();
let sessionSecretKey = config.sessionSecretKey;
*/
Then you can use the req.isAuthenticated() after the login:
// POST the username and password to '/login' router
app.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (info) {
return res.send(info.message)
}
if (err) {
return next(err);
}
if (!user) {
return res.sendStatus(404); // Is a shortcut
// OR -> res.status(404).end();
// OR -> res.status(404).send('Not found'); as you like
}
req.login(user, (err) => {
if (err) return next(err);
// Store the user object retrieved from MongoDB in `req.session`
req.session.user = user;
return res.sendStatus(200); // Is a shortcut
// OR -> res.status(200).end();
// OR -> res.status(200).send('OK'); as you like
})
})(req, res, next);
});
// The logout logic
app.get('/logout', verifySession, function (req, res) {
req.session.destroy(function (err) {
req.logout();
res.redirect('/');
});
});
// Verify the session to protect private routers
function verifySession(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
// Forbidden
res.redirect('/');
// OR -> res.sendStatus(403);
// OR -> res.status(403).end();
// OR -> res.status(403).send('Forbidden'); as you like
}
}
Of course you have to run npm install with all the dependencies required defined in package.json file or manually instal with npm i express-session#latest --s for all the dependencies required: npm i module-name#latest --s.
Don't forget the
const server = app.listen(config.port || 3000, () => {
console.log(`Server running on ${server.address().port} port.`);
});
At the end of server.js file. I hope that it will be useful for you.

Why is my Express api register route not POSTing?

I am trying to make a small authentication system for a practice project I have. I am trying to send POST requests via postman to my express server(http://localhost:4000/api/register), and it's replying back "404 not found" I am following the tutorial here.
Here is my server.js:
const newpost = require('./routes/newpost');
const getposts = require('./routes/getposts');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const deleteposts = require('./routes/delete');
const editposts = require('./routes/editposts');
const path = require('path');
const app = express();
const webpack = require('webpack');
const webpackConfig = require('../webpack.config');
const webpackMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const passport = require('passport');
const port = 4000;
const compiler = webpack(webpackConfig);
const config = require('./config/main');
const mongoose = require('mongoose');
const authRouter = require('./routes/authrouter');
const logger = require('morgan');
// db connection
mongoose.connect(config.database);
app.use(passport.initialize());
/*
app.use(webpackMiddleware(compiler, {
noInfo: true, publicPath: webpackConfig.output.publicPath,
}));
app.use(webpackHotMiddleware(compiler, {
log: console.log,
}));
*/
app.use(cors());
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(logger('dev'));
app.use('/newpost', newpost);
app.use('/posts', getposts);
app.use('/delete', deleteposts);
app.use('/edit', editposts);
//auth router to handle auth routes
authRouter(app);
/*
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../public/index.html'));
}); */
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
Here is my authrouter.js. These are the routes I'm exporting into my server.js. :
const AuthenticationController = require('../controllers/authentication');
const express = require('express');
// const passportService = require('../config/passport');
/* eslint-disable */
const passport = require('passport');
// Middleware to require login/auth
// const requireAuth = passport.authenticate('jwt', { session: false });
const requireLogin = passport.authenticate('local', { session: false });
module.exports = function(app){
"use-strict";
// init route groups
const apiRoutes = express.Router();
const authRoutes = express.Router();
// auth routes
// set auth routes as subgroup/middleware to apiRoutes
apiRoutes.use('/auth', authRoutes);
// Registration routes
authRoutes.post('/register', AuthenticationController.register);
// Login route
authRoutes.post('/login', requireLogin, AuthenticationController.login);
// Set url for API group routes
app.use('/api', apiRoutes);
};
Here is my authentication.js
const jwt = require('jsonwebtoken');
// const crypto = require('crypto'); used for pw resets
const User = require('../models/user');
const config = require('../config/main');
function generateToken(user) {
return jwt.sign(user, config.secret, {
expiresIn: 10080, // in seconds
});
}
// set user info from request
function setUserInfo(request) {
return {
_id: request._id,
email: request.email,
role: request.role,
};
}
// Login Route
exports.login = function (req, res, next) {
const userInfo = setUserInfo(req.user);
res.status(200).json({
token: `JWT${generateToken(userInfo)}`,
user: userinfo,
});
};
// registration route
exports.register = function (req, res, next) {
// check for registration errors
const email = req.body.email;
const password = req.body.password;
// Return error if no email provided
if (!email) {
return res.status(422).send({ error: 'You must enter an email address' });
}
// Return error if no pw provided
if (!password) {
return res.status(422).send({ error: 'You must enter a password' });
}
User.findOne({ email }, (err, existingUser) => {
if (err) { return next(err); }
// if user is not unique, return error
if (existingUser) {
return res.status(422).send({ error: 'That email address is already in use' });
}
// if email is unique and pw was provided, create acct
const user = new User({
email,
password,
});
user.save((err, user) => {
if (err) { return next(err); }
// Subscribe member to Mailchimp list
// mailchimp.subscribeToNewsLetter(user.email);
// Respond with JWT if user was created
const userInfo = setUserInfo(user);
res.status(201).json({
token: `JWT ${generateToken(userInfo)}`,
user: userInfo,
});
});
});
};
// Role authorization check
exports.roleAuthorization = function (role) {
return function (req, res, next) {
const user = req.user;
User.findById(user._id, (err, foundUser) => {
if (err) {
res.status(422).json({ error: 'No user was found' });
return next(err);
}
// if user is found, check role
if (foundUser.role == role) {
return next();
}
res.status(401).json({ error: 'You are not authorized to view this content ' });
return next('Unauthorized');
});
};
};
Here is my passport.js :
// Importing Passport; strategies; and config
const passport = require('passport');
const User = require('../models/user');
const config = require('./main');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const LocalStrategy = require('passport-local');
const localOptions = { usernameField: 'email' };
// setting up the local Strategy
const localLogin = new LocalStrategy(localOptions, ((email, password, done) => {
User.findOne({ email }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, { error: 'Your login details could not be verified. Please try again.',
});
}
user.comparePassword(password, (err, isMatch) => {
if (err) { return done(err); }
if (!isMatch) {
return done(null, false, { error: 'Your login details could not be verified. Please try again.',
});
}
return done(null, user);
});
});
}));
const jwtOptions = {
// Telling passport to check auth headers for JWT
jwtFromRequest: ExtractJwt.fromAuthHeader(),
// Telling passport where to find the secret
secretOrKey: config.secret,
};
// setting up JWT login strategy
const jwtLogin = new JwtStrategy(jwtOptions, ((payload, done) => {
User.findById(payload._id, (err, user) => {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
}));
// allow passport to use the strategies we defined
passport.use(jwtLogin);
passport.use(localLogin);
I believe the correct post endpoint would be api/auth/register

Categories

Resources