NodeJS: misconfigured csrf - node.js

I am trying to run a nodejs app. The problem that I have however is every time I try to run the app, it throws an error as stated in the title: misconfigured csrf.
Here is my code:
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const csrf = require('csurf');
const flash = require('connect-flash');
const errorController = require('./controllers/error');
const User = require('./models/user');
const MONGODB_PASS = 'PASSWORD_HERE';
const MONGODB_URI = `mongodb+srv://USER_HERE:${MONGODB_PASS}#DB_HOST_HERE/shop?retryWrites=true&w=majority`;
const app = express();
const store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions'
});
const csrfProtection = csrf({cookie: true});
app.set('view engine', 'ejs');
app.set('views', 'views');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: 'my secret',
resave: false,
saveUninitialized: false,
store
}));
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
if (!req.session.user) return next();
User.findById(req.session.user._id).then(user => {
req.user = user;
next();
}).catch(err => {throw err});
});
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
req.locals.csrfToken = req.csrfToken();
next();
});
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.use(errorController.get404);
mongoose.connect(MONGODB_URI)
.then(result => app.listen(3000)).catch(err => { throw err });
I expect the app to run successfully but instead, it throws an error saying: misconfigured csrf. What am I doing wrong?
Note: I seriously don't know what to write anymore and SO keeps complaining that i need to add some more details. I believe i've provided enough explanation with the description, the title, and the code.

You are using the cookie option:
const csrfProtection = csrf({cookie: true});
It requires the cookie-parser package as documented here: If you are setting the "cookie" option to a non-false value, then you must use cookie-parser before this module.

Related

Cannot authenticate user with Passport Local Strategy

I am using passport to implement a login function on my application. However, every time I try to authenticate the user, I cannot get passed the authentication and am redirected to the failure URL. I have confirmed that there is a user in the MongoDB database and the user supplied password is correct. However, I cannot get past the passport authentication. Can anyone please help me out ?
This is my index.js
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const path = require('path');
const ejsMate = require('ejs-mate');
const loginRoutes = require("./routes/login");
const User = require('./models/users');
const session = require('express-session');
const userRoutes = require('./routes/user');
const passport = require('passport');
const localStrategy = require('passport-local');
sessionConfig = {
name: "session",
secret: 'BetterSecret',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
expires: Date.now() + 604800000, //Date.NOW + No. of Miliseconds in the week
maxAge: 604800000
}
};
//Connection strings only beyond this line
mongoose.connect('mongodb://localhost:27017/myLoc').then(console.log("DB connected")).catch(error => handleError(error));
app.listen(5500, (req, res, next) => {
console.log("Connected");
});
//app.uses
app.use(express.urlencoded({ extended: true }));
app.use("/", loginRoutes);
app.use("/business", userRoutes);
app.engine('ejs', ejsMate);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views')); //setting up the views directory
app.use(express.static(path.join(__dirname, 'public'))); //public directory to serve static content
app.use(session(sessionConfig));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
This is the router for the login:
const express = require('express');
const router = express.Router();
const users = require('../controllers/users');
const passport = require('passport');
router.route('/login')
.get(users.renderLoginForm)
.post(passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }), users.login);
router.route('/register')
.get(users.renderRegisterForm)
.post(users.createNewUser);
module.exports = router;
and for the controller I just have a console.log for now
module.exports.login = (req, res, next) => {
console.log("I am here");
};

Why is node.js not passing my session to a segment it calls

In node.js, my entrypoint segment (app.js) calls another segment after the express session has been set up. The segment called is expecting a session field in the request ('req') object but it isn't there.
This is app.js in full:
const express = require('express');
const path = require('path');
const nunjucks = require('nunjucks');
const helmet = require('helmet');
const csp = require('helmet-csp');
const uuid = require('uuid/v4');
const fs = require('fs');
const https = require('https');
const cookieMiddleware = require('./app/middleware/cookie-message.js');
const cookieDetailsGet = require('./app/routes/cookies/cookie-details.get.js');
const cookiePolicyPost = require('./app/routes/cookies/cookie-policy.post.js');
const cookiePolicyGet = require('./app/routes/cookies/cookie-policy.get.js');
const nonceMiddleware = require('./app/middleware/nonce.js');
const cookieParser = require('cookie-parser');
let app = express();
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const bodyParser = require('body-parser');
const i18next = require('i18next');
const i18nextMiddleware = require('i18next-express-middleware');
const i18nextFsBackend = require('i18next-node-fs-backend');
const config = require('./app/config/config');
const i18nextOptions = require('./app/config/i18nextOptions');
const { getRedisClient } = require('./app/services/redis-client');
const router = express.Router;
/* Generate nonce. */
const nonce = Buffer.from(uuid().toString('base64'));
app.use((req, res, next) => {
res.locals.nonce = nonce;
next();
});
// configure Nunjucks templating
nunjucks.configure(['views',
path.join(__dirname, 'node_modules/morris-frontend/'),
path.join(__dirname, 'node_modules/morris-frontend/morris/components/'),
path.join(__dirname, 'app/views/')
], {
autoescape: true,
express: app
});
// secure apps by setting various HTTP headers
app.use(helmet());
app.use(csp({
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'"],
scriptSrc: [
"'self'",
`'nonce-${nonce}'`, // Pass the nonce value along.
"'sha256-+6WnXIl4mbFTCARd8N3COQmT3bJJmo32N8q8ZSQAIcU='",
],
imgSrc: ["'self'"],
fontSrc: ["'self'"]
}
}));
// referrerPolicy
app.use(helmet.referrerPolicy({ policy: 'no-referrer-when-downgrade' }));
// view engine setup
app.set('views', path.join(__dirname, 'app/views'));
app.set('view engine', 'html');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());
cookieMiddleware(
app,
config.CONSENT_COOKIE_NAME,
config.COOKIE_POLICY,
config.COOKIE_CONSENT,
'/decision/',
config.GOOGLE_TAG_MANAGER_DOMAIN
);
// Language support
i18next.use(i18nextFsBackend)
.use(i18nextMiddleware.LanguageDetector)
.init(i18nextOptions);
app.use(i18nextMiddleware.handle(i18next, {
removeLngFromUrl: false
}));
// Redis session
const sessionStore = new RedisStore({
client: getRedisClient(),
prefix: 'bl:',
ttl: parseInt(config.sessionTTL, 10),
logErrors: (err) => {
log.error('Redis session error', {
err_message: err.message,
err_stack: err.stack
});
}
});
app.use(session({
secret: config.sessionSecret,
store: sessionStore,
resave: false,
saveUninitialized: false
}));
app.use(bodyParser.json());
app.use('/decision', express.static(path.join(__dirname, 'node_modules/morris-frontend/morris')));
app.use('/decision', express.static(path.join(__dirname, 'app/public/grants')));
// Cookie policy pages
app.get(`/${config.COOKIE_DETAILS}`, cookieDetailsGet(
config.COOKIE_POLICY,
config.CONSENT_COOKIE_NAME,
config.SESSION_COOKIE_NAME,
config.COOKIE_CONSENT,
config.sessionsTTL
));
app.get(`/${config.COOKIE_POLICY}`, cookiePolicyGet(config.COOKIE_DETAILS));
app.post(`/${config.COOKIE_POLICY}`, cookiePolicyPost(
config.CONSENT_COOKIE_NAME,
'/',
config.GOOGLE_TAG_MANAGER_DOMAIN
));
// Defining the Router
//app.use(require('./app/routes/routes'));
require('./app/routes/monitoring')(app);
if (process.env.HTTPS_ON === 'true') {
const httpsKeys = {
key: fs.readFileSync(process.env.HTTPS_KEY, 'utf-8'),
cert: fs.readFileSync(process.env.HTTPS_CRT, 'utf-8')
};
app = https.createServer(httpsKeys, app);
}
app.listen(process.env.PORT || 3001, () => {
const protocol = process.env.HTTPS_ON ? 'https' : 'http';
const port = process.env.PORT || 3001;
console.log(`Server running on ${protocol}://localhost:${port}`); // eslint-disable-line no-console
});
module.exports = { app, router };
The call that's messing up is this bit:
cookieMiddleware(
app,
config.CONSENT_COOKIE_NAME,
config.COOKIE_POLICY,
config.COOKIE_CONSENT,
'/decision/',
config.GOOGLE_TAG_MANAGER_DOMAIN
);
Here's the top part of cookie-message.js (the segment being called:
const qs = require('querystring');
const setConsentCookie = require('../utils/set-consent-cookie.js');
const removeGTMCookies = require('../utils/remove-gtm-cookies.js');
module.exports = (app, consentCookieName, cookiePolicy, cookieConsent, mountUrl, proxyMountUrl = mountUrl, gtmDomain, useTLS = false) => {
const reProxyMountUrl = new RegExp(`^${proxyMountUrl}`);
const sanitiseUrl = (url) => url.replace(reProxyMountUrl, mountUrl).replace(/\/+/g, '/');
// URL to cookie policy page
const cookiePolicyUrl = `${mountUrl}${cookiePolicy}`;
// Set template options for cookie consent banner
app.use((req, res, next) => {
console.log('inside cookie-message.js');
console.log('req.session=', req.session);
The console.log call shows req.session as being undefined.
Any suggestions?
If you want to use the session inside of the cookieMiddleware(), then you have to move the session middleware to be BEFORE cookieMiddleware() is called. Right now, you have the session middleware after so req.session has not yet been configured when cookieMiddleware() gets called.
Middleware is run in the order it is registered so to use req.session, the session middleware has to have already run before the middleware where you're trying to use req.session. So, you can either move cookieMiddleware() to be later (after session middleware) or move your session middleware earlier before cookieMiddleware() is called.

Node js Express Error: ERR_TOO_MANY_REDIRECTS

Everything worked just fine until all of a sudden this error occurred: ERR_TOO_MANY_REDIRECTS. I had no luck in figuring it out on my own so please help me if you can.
I use express-handlebars and express to route my pages and I thing I saw where the problem occurres. In my bookController file when I use res.render('something') no matter from what route it always redirects me to '/' and when I use res.send('something') It redirects to where it defined.
This is my app.js file:
const express = require("express");
const mongoose = require("mongoose");
const passport = require("passport");
const path = require("path");
const bodyParser = require("body-parser");
const hbs = require("express-handlebars");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const MongoStore = require("connect-mongo")(session);
const flash = require("connect-flash");
const routes = require("./routes/index");
const expressValidator = require("express-validator");
const errorHandlers = require("./handlers/errorHandlers");
const app = express();
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const compiler = webpack(webpackConfig);
const webpackDevMiddleware = require("webpack-dev-middleware")(
compiler,
webpackConfig.devServer
);
app.use(webpackDevMiddleware);
app.use(require("webpack-hot-middleware")(compiler));
app.use(express.static(path.join(__dirname, "public")));
app.engine(
"hbs",
hbs({
extname: "hbs",
defaultLayout: "main",
layoutsDir: __dirname + "/views/layouts",
partialsDir: __dirname + "/views/partials"
})
);
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(flash());
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.SECRET
})
);
app.use(cookieParser());
app.use(expressValidator());
app.use((req, res, next) => {
res.locals.flashes = req.flash();
next();
});
app.use("/", routes);
app.use(errorHandlers.flashValidationErrors);
module.exports = app;
This is my index.js file
const router = require("express").Router();
const bookController = require("../controllers/bookController");
const { catchErrors } = require("../handlers/errorHandlers");
router.get("/", bookController.home);
router.post("/contact", catchErrors(bookController.contactForm));
router.post("/productPage", catchErrors(bookController.productForm));
module.exports = router;
This is my bookController file:
const mail = require("../handlers/mail");
exports.home = async (req, res) => {
res.render("index");
};
exports.contactForm = async (req, res) => {
const email = req.body.email;
const subject = req.body.subject;
const text = req.body.text;
await mail.send({ email, subject, text });
res.redirect("/");
};
exports.productForm = async (req, res) => {
console.log(req.body);
res.redirect("/");
};
I will very appreciate any help.
Thank you.
Answer which solved the question.
If res.render() does not stop the request (Same way as res.send(html)), usually means there is error in the render function. As the behaviour of res.render() is that if it errors, it will trigger next(err).
https://expressjs.com/en/api.html#res.render
When an error occurs, the method invokes next(err) internally.
Errors are quite simple to be tracked in the function, by passing an callback into the render;
res.render('index', function(err, html) {
if (err) console.error(err);
res.send(html);
});
Once you can trace the error and fix it, problem should be solved.

MissingSchemaError: Schema hasn't been registered for model "Store"

I'm using the Wes Boss Node.js tutorial and have been encountering a number of issues with schema errors.
My database is currently running on mLab and MongoDB Compass. It was fine yesterday when I left for work, and I had just added my first bit of data to the DB successfully. This morning I go to continue where I left off, and everything is suddenly broken.
I've tried deleting the node_modules directory, running npm cache clean, and npm install. I have tried changing the order of the dependencies. I thought it might be that the connection just needed restarted, so I closed the connection, exited Compass, re-opened and re-connected to the DB. I tried deleting the "sessions" table and re-connecting. No such luck.
I've tried plugging the database's server address into my browser's URL bar and I receive a message indicating that the connection was successful.
Error:
MissingSchemaError: Schema hasn't been registered for model "Store". Use mongoose.model(name, schema)
at MissingSchemaError (C:\Users\Misha\Desktop\dang-thats-delicious\node_modules\mongoose\lib\error\missingSchema.js:20:11)
app.js:
const express = require('express');
const session = require('express-session');
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo')(session);
const path = require('path');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const passport = require('passport');
const promisify = require('es6-promisify');
const flash = require('connect-flash');
const expressValidator = require('express-validator');
const routes = require('./routes/index');
const helpers = require('./helpers');
const errorHandlers = require('./handlers/errorHandlers');
const app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.use(cookieParser());
app.use(session({
secret: process.env.SECRET,
key: process.env.KEY,
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
res.locals.h = helpers;
res.locals.flashes = req.flash();
res.locals.user = req.user || null;
res.locals.currentPath = req.path;
next();
});
app.use((req, res, next) => {
req.login = promisify(req.login, req);
next();
});
app.use('/', routes);
app.use(errorHandlers.notFound);
app.use(errorHandlers.flashValidationErrors);
if (app.get('env') === 'development') {
app.use(errorHandlers.developmentErrors);
}
app.use(errorHandlers.productionErrors);
module.exports = app;
index.js:
const express = require('express');
const router = express.Router();
const storeController = require('../controllers/storeController');
const { catchErrors } = require('../handlers/errorHandlers');
router.get('/', storeController.homePage);
router.get('/add', storeController.addStore);
router.post('/add', catchErrors(storeController.createStore));
module.exports = router;
start.js:
require('./models/Store');
const mongoose = require('mongoose');
const Store = mongoose.model('Store');
require('dotenv').config({ path: 'variables.env' });
mongoose.connect(process.env.DATABASE);
mongoose.Promise = global.Promise;
mongoose.connection.on('error', (err) => {
console.error(`${err.message}`);
});
require('./models/Store');
const app = require('./app');
app.set('port', process.env.PORT || 7777);
const server = app.listen(app.get('port'), () => {
console.log(`Express running → PORT ${server.address().port}`);
});
Well, I think I solved my own problem. My storeController.js file needed require('../models/Store'); at the top, right below const mongoose = require('mongoose');
However, now I'm getting another error, and I believe it's related to removing my stored sessions from the DB:
express-session deprecated req.secret; provide secret option at app.js:38:9
Going to attempt to re-create the DB and see what happens.

express-validator error -> TypeError: req.checkBody is not a function

I am using express-validator package to validate requested data.
According to these answer I also did change the order or package declaration and initialization
below is my server.js file
const express = require("express");
const session = require("express-session");
const mongoose = require('mongoose');
const MongoStore = require('connect-mongo')(session);
const path = require('path');
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const passport = require('passport');
const promisify = require('es6-promisify');
const expressValidator = require('express-validator');
const expressJwt = require("express-jwt");
const error_staus = 404;
const morgan = require('morgan');
const logger = require('./helper/logger');
const routes = require('./routes/index');
let server = "";
const bugsnag = require('bugsnag');
// import our configurations from config/tester.js file
const config = require("./config/tester").get(process.env.NODE_ENV);
require('./helper/passport');
require("./helper/translator");
// create our Express app
const app = express();
// view engine setup
app.set("views", `${__dirname}/views`);
app.set("view engine", "ejs");
// serves up static files from the public folder. Anything in app/ will just be served up as the file it is
app.use(express.static(path.join(__dirname, 'app')));
// Takes the raw requests and turns them into usable properties on req.body
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Exposes a bunch of methods for validating data. Used heavily on userController.validateRegister
app.use(expressValidator());
// Sessions allow us to store data on visitors from request to request
app.use(session({
secret: '123456',
key: '99785',
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(session({
"secret": 'secret12345',
"resave": false,
"saveUninitialized": true
}));
// Passport JS is what we use to handle our logins
app.use(passport.initialize());
app.use(passport.session());
// promisify some callback based APIs
app.use((req, res, next) => {
req.login = promisify(req.login, req);
next();
});
// begin logger
app.use(morgan('dev', {
skip: function (req, res) {
return res.statusCode < 400
}, stream: process.stderr
}));
app.use(morgan('dev', {
skip: function (req, res) {
return res.statusCode >= 400
}, stream: process.stdout
}));
app.use('/', routes);
app.use(function(req, res, next){
logger.error('404 page requested');
res.sendStatus(error_staus);
});
// done! we export it so we can start the site in start.js
module.exports = app;
This is the userController.js
const mongoose = require('mongoose');
const User = mongoose.model('User');
const promisify = require('es6-promisify');
exports.loginForm = (req, res) => {
res.render('login', { title: 'Login' });
};
exports.registerForm = (req, res) => {
res.render('register', { title: 'Register' });
};
exports.validateRegister = (req, res, next) => {
req.sanitizeBody('name');
req.checkBody('name', 'You must supply a name!').notEmpty();
req.checkBody('email', 'That Email is not valid!').isEmail();
req.sanitizeBody('email').normalizeEmail({
gmail_remove_dots: false,
remove_extension: false,
gmail_remove_subaddress: false
});
req.checkBody('password', 'Password Cannot be Blank!').notEmpty();
req.checkBody('password-confirm', 'Confirmed Password cannot be blank!').notEmpty();
req.checkBody('password-confirm', 'Oops! Your passwords do not match').equals(req.body.password);
const errors = req.validationErrors();
if (errors) {
req.flash('error', errors.map(err => err.msg));
res.render('register', { title: 'Register', body: req.body, flashes: req.flash() });
return; // stop the fn from running
}
next(); // there were no errors!
};
Note : I am using express-validator version 3.1.2
When I check request object, in that object there is all methods of express-validator too.
But try to use that method I am getting req.checkBody is not a function error.
Can anybody help with these issue ?

Resources