'app.use() requires a middleware function' - javascript

I was making a registration and Login page for user in Node using express. When i try to run my app.js file it gives this "app.use()" error. Below is my app.js code
const express= require("express");
const app= express();
const path= require("path");
const hbs= require("hbs");
var session= require("express-session");
const { urlencoded } = require("express");
const port= process.env.PORT || 3000;
require("dotenv").config;
const static_path= (path.join(__dirname,"../public"));
const template_path= (path.join(__dirname,"../templates/views"));
const partials_path= (path.join(__dirname,"../templates/partials"));
const db= require("./db/db.js");
const cookieParser= require("cookie-parser");
const e = require("express");
hbs.registerPartials(partials_path);
var regisRouter= require("../src/routes/regis");
var loginRouter= require("../src/routes/login");
var dashbRouter= require("../src/routes/dashboard");
var logoutRouter= require("../src/routes/logout");
app.use('/regis',regisRouter);
app.use('/login',loginRouter);
app.use('/dashboard',dashbRouter);
app.use('/logout',logoutRouter);
// 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');
});
app.use(express.static(static_path));
app.use(express.json());
app.use(express.urlencoded({extended:false}));
app.use("cookieParser()");
app.set("view engine", "hbs");
app.set("views",template_path);
const oneDay = 1000 * 60 * 60 * 24;
app.use(session({
secret: "secret123",
resave: false,
saveUninitialized: true,
cookie: {maxAge: oneDay}
}));
app.get("/",(req,res) =>{
session= req.session;
if(session.id)
{
res.send("Welcome User <a href=\'/logout'>click to logout</a>");
}
else
res.render("index");
});
// app.post("/register", async(req,res) =>{
// try {
// const password= req.body.password;
// const cpassword= req.body.confirmpassword;
// if(password===cpassword)
// {
// }
// else
// {
// res.send("invalid login credentials");
// }
// } catch (error) {
// res.status(400).send(error);
// }
// });
app.listen(port,() =>{
console.log(`this is port no. ${port}`);
});
I think probably this part has an error, but i am not so sure about it
app.use('/regis',regisRouter);
app.use('/login',loginRouter);
app.use('/dashboard',dashbRouter);
app.use('/logout',logoutRouter);
Below is the folder structure if it is of any help
I am not able to understand this error. If someone could tell me it would be of great help , thankyou!

The problem is you have to pass a function as a parameter to app.use(), but you are giving a string into it "cookieParser()".
Change
app.use("cookieParser()");
To
app.use(cookieParser());

Related

How to debug EJS

There are several answers for this question, but they're all several years old and no longer relevant/safe to use.
Since EJS is rendered as html in the browser, there's no way to inspect it in the browser dev tools
The EJS.co site says that the errors/logs should show in the terminal just like node errors, but that's not the reality for me, somehow.
I used the command npx express-generator to bootstrap my project, and I'm wondering if there isn't a debugger of some kind in there that is overriding how EJS is supposed to send errors?
I say this because when EJS has an error, the only thing my terminal shows is something like GET /users/dashboard 500 26.5 ms with nothing else. And then of course the browser shows the default message for 500 errors, which isn't helpful.
I'll throw in my app.js in case someone smarter than me can see the issue there:
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const rfs = require('rotating-file-stream')
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
require('mongoose-type-url');
// const serveFavicon = require('serve-favicon');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const expressSession = require('express-session');
const methodOverride = require('method-override');
const expressSanitizer = require('express-sanitizer');
const sgMail = require('#sendgrid/mail');
// create a rotating write stream
const accessLogStream = rfs.createStream('access.log', {
interval: '1d', // rotate daily
path: path.join(__dirname, 'log')
});
const User = require('./models/user');
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
const formsRouter = require('./routes/forms');
const companiesRouter = require('./routes/companies');
const locationsRouter = require('./routes/locations');
const app = express();
if (app.get('env') == 'development'){ require('dotenv').config(); };
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
//connect to database
mongoose.connect(process.env.DATABASE_URL,{
useNewUrlParser:true,
useUnifiedTopology:true,
useFindAndModify: false,
useCreateIndex:true
}).then(() => {
console.log('Connected to Mongo DB')
}).catch(err => {
console.log('error: ',err.message)
});
// view engine setup
//use ejs-locals for all ejs templates
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev', { skip: function (req,res) { return res.statusCode < 400} }));
app.use(logger('common', { stream: accessLogStream }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(methodOverride("_method"));
app.use(expressSanitizer());
var expiryDate = new Date(Date.now() + 60 * 60 * 1000 * 6) // 6 hours
app.use(expressSession({
secret:"surfs up brah",
resave:false,
saveUninitialized:false,
name: 'sessionId',
secure:true,
httpOnly:true,
expires: expiryDate
}));
app.use(passport.initialize());
app.use(passport.session());
app.disable('x-powered-by');
app.use(function(req, res, next){
res.locals.currentUser = req.user;
next();
});
// CHANGE: USE "createStrategy" INSTEAD OF "authenticate"
passport.use(User.createStrategy({usernameField:'personalEmail'}));
// use static authenticate method of model in LocalStrategy
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
//set local variables middleware
app.use(async function (req,res,next) {
if (app.get('env') == 'development'){ req.user = await User.findOne({firstName: 'potato'}); };
res.locals.currentUser = req.user;
//set default page title if one is not specified
res.locals.title='Custom Forms';
//set success flash message
res.locals.success = req.session.success || "";
//delete flash message after sending it to the page so it doesn't show again
delete req.session.success;
//set error flash message
res.locals.error = req.session.error || "";
//delete flash message after sending it to the page so it doesn't show again
delete req.session.error;
//continue on to the next function in the middlware/route chain
next();
});
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/forms', formsRouter);
app.use('/companies', companiesRouter);
app.use('/locations', locationsRouter);
// 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');
});
const { seedDatabase, clearDatabase, seedDefaultQuestions, clearRecentItems} = require('./seeds.js');
async function databaseInit() {
await clearRecentItems();
// await seedDefaultQuestions();
// await clearDatabase();
await User.register({firstName: 'potato', lastName:'head',username:'potatohead', personalEmail:'test#test.com', role:'Owner'},'password');
// await seedDatabase();
}
databaseInit();
let port = process.env.PORT;
if (port == null || port == "") {
port = 8080;
}
app.listen(port, () => {
console.log("server has started, listening on port "+port);
});
module.exports = app;
Here's an example route:
app.get('/dashboard', (req,res) => {
const currentCompany = Company.findById(req.params.id);
res.render('../views/company/profile', {currentCompany});
}
And some sample EJS:
<html>
<body>
<h1><%= currentCompany.name %></h1>
</body>
</html>
Now say I didn't wrap the findById call in a try block and it didn't find a document, then tried to render the page using an undefined or null object. The EJS file wouldn't have anything to which to refer for currentCompany.name (by the way, I do indeed try/catch and handle errors).
This is where the terminal just logs the simple 500 error, and refuses to load anything at all.
Another example of issues I've had with EJS:
<html>
<body>
<&- include('../../partials/header) %>
</body>
</html>
Here, it would throw the exact same 500 error because I went up one too many folders in the path for that partial. Absolutely nothing else shown anywhere.
Thanks to #LawrenceCherone, the issue is the default error handler created when npx express-generator is used.
// 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');
});
Without that, the EJS error information (including line number, etc) gets displayed in the browser.

Error connection MongoDB: Error: Route.get() requires a callback function but got a [object Undefined]

I have been trying to connect my application to MongoDB using express but without success. Below the most important part of the code:
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 cors = require('cors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var mongoose = require('mongoose');
const bodyParser = require('body-parser');
const vesselController = require('./controllers/VesselController');
require('./config/keys');
var app = express();
app.use(cors());
app.options('*', cors());
// DB Config
const db = require('./config/keys').MongoURI;
const options = {
useNewUrlParser: true,
reconnectTries: Number.MAX_VALUE,
poolSize: 10
};
mongoose
.connect(db, options)
.then(() => console.log('MongoDB Connection established'))
.catch((err) => console.log('Error connecting MongoDB database due to: ', err));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// Bodyparser
app.use(express.urlencoded({ extended: false }));
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));
});
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
// 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');
});
const PORT = process.env.PORT || 3000;
app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
app.use(bodyParser.json({ limit: '50mb' }));
app.use(cors());
app.route('/vessels/all').get(vesselController.getBaseAll);
app.route('vessels/:id/track').get(vesselController.getCurrent);
app.route('/vessels').get(vesselController.getHistory);
app.listen(PORT, console.log(`Server started on port ${PORT}`));
module.exports = app;
VesselController.js
const Vessels = require('../models/Vessels');
const Positions = require('../models/Positions');
const Compnanies = require('../models/Companies');
exports.getBaseAll = (req, res) => {
Promise.all([
Compnanies.find(),
Vessels.find(),
Positions.aggregate([
{
$sort: {
date: -1
}
},
{
$group: {
_id: '$callsign',
details: {
$push: '$$ROOT'
}
}
},
{
$replaceRoot: {
newRoot: {
$arrayElemAt: [ '$details', 0 ]
}
}
}
])
])
.then(([ companies, vessels, positions ]) => {
// apply vessels detail table as join:
positions.forEach((pos) => {
vessels.forEach((ves) => {
if (pos.callsign == ves.callsign) {
p._detail = ves;
}
});
companies.forEach((com) => {
if (p._detail.company == com.number) {
p._detail = com;
}
});
});
res.status(200).json(positions);
})
.catch((err) => {
return res.status(500).send(err);
});
};
exports.getHistory = (req, res) => {
var id = req.param.id;
Positions.find(
{
callsign: id,
date: {
$gte: new Date(Date.now() - 1000 * 60 * 60 * 24)
}
},
(err, task) => {
if (err) {
return res.status(500).send(err);
}
res.status(200).json(task);
}
);
};
exports.getCurrent = (req, res) => {
var currentPos = Positions.find({
date: {
$gte: new Date(Date.now() - 1000 * 60 * 60)
}
});
currentPos.exec((err, task) => {
if (err) {
return res.status(500).send(err);
}
res.status(200).json(task);
});
};
I am not sure if the problem is due to the fact that I am trying to connect to a specific database. After hitting connect to my application as shown below and copy/paste the key:
mongodb+srv://<username>:<password>#vessel-tracker-cluster-x2lpw.mongodb.net/test?retryWrites=true&w=majority
Below is how my cluser is organized:
And after accessing the collections you can see how the database is structured:
What I have done to solve the problem:
Posts that I came across and analyzed to solve the problem were:
1) This was useful but I could not solve the problem.
2) I used this other source but problem still stays.
3) This one was also useful but my problem still stay and MongoDB is not properly connecting
Thanks for pointing in the right direction for solving this problem.
As I see from the stack trace there's an error in app.js:77:27:
app.route('/vessels/all').get(vesselController.getBaseAll);
Though I've executed your code and it worked fine I would like to propose you the following:
1) Try to substitute exports with module.exports in your VesselController.js;
2) Try to debug app.js and see what vesselController.getBaseAll / vesselController.getCurrent / vesselController.getHistory returns:
console.log(vesselController.getBaseAll); // should be [Function]

Problem with nodejs static route and files

In my project I have a report hat is reachable with index.html
But this is private and I want to protect / limit access with my node app. for this I use
app.use('/allure', express.static(path.join(__alluredir , 'allure-report/')));
Then I use for bugging purpose
app.all('/allure/*', function(req, res, next) {
console.log("catched allure query");
next(); // allow the next route to run
});
But the index.html is still reachable with localhost:8080/allure/index.hmtl and also just with localhost:8080/allure/ without an console output. This confuse a lot. Anybody has an idea how to hinder access the index.html without logged in? (Is use passport)
my whole app.js file is:
const express = require('express');
const app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
var bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
var favicon = require('serve-favicon')
const { allureGenerator } = require('./ops/copyalluredata');
app.set('socketio', io);
//app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ type: 'application/json' }));
app.use(bodyParser.urlencoded({
parameterLimit: 100000,
limit: '50mb',
extended: true
}));
var appDir = path.dirname(require.main.filename);
global.__basedir = appDir;
global.__alluredir = process.env.REPORT_DIR_ENV;
fs.readFile(path.join(appDir, '/config.xml'), (err, data) => {
if (err) throw err;
myConfigData = JSON.parse(data);
process.env.BROWSERSTACK_USERNAME = myConfigData.browserstackid;
process.env.BROWSERSTACK_ACCESS_KEY = myConfigData.browserstackkey;
process.env.BROWSERSTACK_DISPLAY_RESOLUTION="1600x1200";
console.log('config gelesen');
});
//Diese Funktion schreibt die benötigten Dateien in den allure Modul Ordner damit das Logo verwendet wird.
allureGenerator();
// Passport Config
require(path.join(appDir, '/config/passport'))(passport);
// DB Config
var db = '';
if (process.env.NODE_ENV == 'home') {
db = require(path.join(appDir, '/config/keys')).mongoURI;
console.log('keys');
}else{
db = require(path.join(appDir, '/config/keys_local')).mongoURI;
console.log('keys_local');
}
// Connect to MongoDB
mongoose
.connect(
db,
{ useNewUrlParser: true }
)
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
app.use('/allure', express.static(path.join(__alluredir , 'allure-report/')));
app.use(express.static(appDir));
// EJS
app.use(expressLayouts);
app.set('view engine', 'ejs');
app.set('views', path.join(appDir, '/views'));
app.use(
session({
secret: 'secret',
resave: true,
saveUninitialized: true
})
);
app.use(favicon(path.join(__dirname, 'css', 'fvicon.ico')))
app.use(passport.initialize());
app.use(passport.session());
// Connect flash
app.use(flash());
// Global variables
app.use(function(req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index.js'));
app.use('/users', require('./routes/users.js'));
app.use('/cases', require('./routes/cases.js'));
app.use('/tcafe', require('./routes/tcafe.js'));
app.use('/imgtest', require('./routes/imgtest.js'));
app.use('/rapitest', require('./routes/restapitest.js'));
io.on('connection', function(socket){
console.log('a user connected');
});
app.all('/allure/*', function(req, res, next) {
console.log("catched allure query");
next(); // allow the next route to run
});
app.use((req, res, next) => {
next({
status: 404,
message: 'Not Found',
});
});
app.use((err, req, res, next) => {
if (err.status === 404) {
return res.status(400).render('404',{ layout: 'system.ejs' });
}
if (err.status === 500) {
return res.status(500).render('500');
}
next();
});
const PORT = process.env.PORT || 8080;
http.listen(PORT, console.log(`Server started on port ${PORT}`));
You can use something like this Or just use somemiddleware-
app.use('/allure', function(req,res,next){
if(<authenticate check>){ // some kind of authenticate check
return express.static(path.join(__dirname, 'allure'));
} else {
<Any error you want to show>
}
});
OR
app.use('/allure',<Auth Middlewarae> , express.static(path.join(__dirname, 'allure')));

Random redirection

i have a Problem with my project. I want to make a little download system for pictures, so i made a router for /download/:filename. I have the pictures in /userdata/${userId}/ and if i request /download/ with a param like test it logs in my console, but if i use a param wich exists in the userdata folder like Download.jpg it redirects me back to the homepath of the user: /file/${userId} here is my code:
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
const admin = require("./routes/admin");
import file from "./routes/file";
import download from "./routes/download";
const session = require("express-session");
var app = express();
app.set("trust proxy", 1);
app.use(session({
secret: "bla",
resave: false,
cookie: {
maxAge: 120000000
},
saveUninitialized: false
}));
function checkIfLoggedin(req,res,next){
if(!(req.originalUrl === "/") && !req.session.loggedIn){
res.redirect('/');
return;
}
next();
};
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(checkIfLoggedin);
app.use('/', index);
app.use("/admin", admin);
app.use("/file", file);
app.use("/download", download);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// 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;
index.js router
var express = require('express');
var router = express.Router();
const bcrypt = require('bcrypt-nodejs');
var dbPassword;
import mysql from "mysql";
//
/* GET home page. */
router.get('/', function(req, res, next) {
if (req.session.user != undefined) {
res.redirect("/file/"+req.session.user.userId);
}
else{
res.render('index', {});
}
});
router.post('/', function(req,res,next) {
console.log("1");
const enteredUsername = req.body.username;
const enteredPassword = req.body.password;
const con = mysql.createConnection({
host: "localhost",
user: "user",
password: "pass",
database: "db"
});
con.query('SELECT * FROM users WHERE username = ?;', [`${enteredUsername}`], (error, results, fields) => {
if (results.length > 0) {
console.log("2");
console.log(error);
let dbPassword = results[0].password;
bcrypt.compare(enteredPassword, dbPassword, (err,response) => {
console.log(err);
console.log(response);
console.log("3");
if (response == true) {
req.session.user = {
userId: results[0].userId,
username: results[0].username,
isAdmin: results[0].isAdmin,
};
req.session.loggedIn = true;
console.log("file");
if (req.session.user.isAdmin) {
res.redirect("/admin");
}
else{
res.redirect("/file/" + req.session.user.userId);
}
}
else{
req.session.loggedIn = false;
console.log("false");
res.send("Falsches Passwort");
}
});
}
else{
res.send("Falsche Daten");
}
});
});
router.get("/logout", (req,res,next) => {
if (req.session.user.userId) {
req.session.destroy();
res.redirect("/");
}
});
module.exports = router;
file.js
import express from "express";
import fs from "fs";
const router = express.Router();
const userDataPath = "/srv/www/www.precode.tech/www/userdata/";
router.get("/:userId", (req,res,next) => {
//console.log(req.params.userId == req.session.user.userId);
if (req.params.userId == req.session.user.userId) {
const userDataFiles = fs.readdirSync(userDataPath+req.session.user.userId);
res.render("file", {files : userDataFiles, user: req.session.user});
}
else{
res.status(403).render("unauthorized");
}
//res.send(`${req.params.userId} ${req.session.user.userId}`);
});
/*router.get("/:userId/download/:filename", (req,res,next) => {
console.log(req.params.filename);
if (req.params.userId == req.session.user.userId) {
let filePath = `${__dirname}/../userdata/${req.session.user.userId}/`;
res.download(filePath, req.params.filename);
next();
};
});*/
export default router;
download.js
import express from "express";
const router = express.Router();
/*router.get("/", (req,res,next) => {
res.send("download");
});*/
router.get("/:filename", (req,res,next) =>{
console.log(req.params.filename);
});
export default router;
It would be very nice, if you have ideas or see the problem.
Thank you :)
EDIT: It should not redirect to the base path of the user, the get request on download should allways console.log the item
I did not find the flaw, but let's cleanup the code and fix middleware attaching sequence (at least I saw cookie parser attached after session middleware, I suspect only that part) and check.
But let's check my code review / cleanup.
Really hope it helps.
app.js:
const express = require('express');
const path = require('path');
//const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require("express-session");
const mysql = require('mysql');
const db = mysql.createConnection({
host: "localhost",
user: "user",
password: "pass",
database: "db"
});
const app = express();
app.set("trust proxy", 1);
// set view engine and renderer
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// serve static files
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); // no need for it since express static will serve all static files in public folder
app.use(express.static(path.join(__dirname, 'public')));
// connect morgan to profile requests
app.use(logger('dev'));
// parse cookies first
app.use(cookieParser());
// then handle session
app.use(session({
secret: "bla",
resave: false,
cookie: {
maxAge: 120000000
},
saveUninitialized: true
}));
// handle requests data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use((req, res, next) => {
req.db = db; // attach db connection to request context
next();
});
// public routes that does not need auth check
app.use('/', require('./routes/index'));
const checkIfLoggedin = (req, res, next) => {
if (!req.session.loggedIn) {
return res.redirect('/');
}
res.locals.user = req.session.user;
next();
};
// internal routes that needs auth check
app.use(
'/admin',
checkIfLoggedin,
require('./routes/admin'));
app.use(
'/files',
checkIfLoggedin,
require('./routes/files'));
/* no need for this route, it's covered in files.js
app.use(
'/download',
checkIfLoggedin,
download);
*/
// catch 404 and forward to error handler
app.use((error, req, res, next) => {
if (error) return next(error);
const err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use((error, req, res, next) => {
// set locals, only providing error in development
res
.status(error.status || 500)
.render('error', {
message: error.message,
error: req.app.get('env') === 'development' ? error : {}
});
});
module.exports = app;
routes/index.js:
const express = require('express');
const router = express.Router();
const logger = require('winston');
const bcrypt = require('bcrypt-nodejs');
const _ = require('lodash'); // install it: npm i --save lodash
/* GET home page. */
router.get('/', (req, res) => {
if (_.get(req, 'session.user.userId')) {
return res.redirect("/files/" + req.session.user.userId);
}
res.render('index', {});
});
router.post('/auth', (req, res, next) => {
const {username, password} = req.body;
const db = req.db;
const query = 'SELECT * FROM users WHERE username = ? LIMIT 1';
const fields = [username];
db.query(
query,
fields,
(err, result) => {
if (err) {
logger.error(err);
const error = new Error('System fehler');
return next(error);
}
const user = _.get(result, '0');
if (!user) {
req.session.loggedIn = false;
const error = new Error('Benutzer nicht gefunden');
error.status = 403;
return next(error);
}
bcrypt.compare(password, user.password,
(err, isEqual) => {
if(err || !isEqual) {
if (err) logger.error('Error in password compare:', err);
const error = new Error('Passwort ungültig');
error.status = 403;
return next(error);
}
req.session.user = _.pick(user, ['id', 'userId', 'username', 'isAdmin']);
req.session.loggedIn = true;
if (user.isAdmin) {
return res.redirect("/admin");
}
res.redirect("/files/" + user.userId);
});
});
});
router.get("/logout", (req, res) => {
// simply destroy session and redirect,
// no need for session check
req.session.destroy();
res.redirect("/");
});
module.exports = router;
routes/files.js:
const express = require('express');
const router = express.Router();
const logger = require('winston');
const fs = require('fs');
const path = require('path');
const async = require('async');
const userDataPath = path.join(__dirname, '..', 'userdata');
// no need to check userId with session.user.userId
// since middleware attached in app.js will guard this route
// and redirect user to '/'
router.get('/:userId', (req, res, next) => {
if(req.params.userId != req.session.user.userId) {
const error = new Error("You cannot access other user's files");
error.status = 403;
return next(error);
}
const directory = path.join(userDataPath, req.params.userId);
logger.info('Reading directory:', directory);
fs.readdir(
directory,
(err, entries) => {
if (err) {
logger.error(err);
const error = new Error('System error');
return next(error);
}
const directories = [];
const files = [];
async.eachLimit(
entries, 10,
(entry, done) => {
fs.stat(path.join(dir, entry), (error, stat) => {
if (stat.isFile()) files.push(entry);
if (stat.isDirectory()) directories.push(entry);
done();
});
},
() => {
res.render("files", {
directories,
files
});
});
});
});
router.get('/:userId/download/:filename', (req, res, next) => {
if(req.params.userId != req.session.user.userId) {
const error = new Error("You cannot access other user's files");
error.status = 403;
return next(error);
}
res.download(path.join(userDataPath, req.params.userId, req.params.filename));
});
module.exports = router;
P.S. If it works behind nginx, apache and etc make sure userdata folder is not accessible publicly.

Session Node.js + Passport.js + Redis, Store session by user.id

When a user logs in a session is created for him, but if he were to go to another computer and login a 2nd session would be created for his account. I would like to make it so that a user could not have more then one valid session. Is there anyway to store sessions in redis by user.steamId so that his first session becomes invalid?
Any help would be great thanks!
app.js
var express = require('express'),
http = require('http');
var app = express();
var cookie = require('cookie');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var redis = require('redis');
var client = redis.createClient();
var session = require('express-session');
var redisStore = require('connect-redis')(session);
io.set('transports', ['websocket']);
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
const fs = require('fs');
require('./config/passport')(passport);
var sessionMiddleware = session({
store:new redisStore({host:'localhost',port:6379,client:client}),
secret:'secretTextchange',
saveUninitialized:false,
resave:false
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(sessionMiddleware);
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
require('./routes/routes')(app,passport,client);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
io.use(function(socket, next) {
sessionMiddleware(socket.request, {}, next);
});
io.sockets.on('connection', function (socket) {
console.log("verified");
socket.on('message',function(msg){
io.sockets.emit('rmessage', {
name:socket.request.session.passport.user.name,
avatarUrl:socket.request.session.passport.user.avatarUrl,
message:msg
});
});
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
server.listen(3000);
module.exports = app;
passport.js
var OpenIDStrategy = require('passport-openid').Strategy;
var auth = require('./auth');
var steam = require('./steam');
var s = new steam({
apiKey: auth.Steam.apiKey,
format:'json'
})
module.exports = function(passport){
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null,user);
});
var SteamStrategy = new OpenIDStrategy({
// OpenID provider configuration
providerURL: auth.Steam.providerUrl,
stateless: auth.Steam.stateless,
// How the OpenID provider should return the client to us
returnURL: auth.Steam.returnUrl,
realm: auth.Steam.realm,
},
function(identifier, done) {
process.nextTick(function () {
console.log("passport-"+identifier);
s.getPlayerSummaries({
steamids:identifier.match(/\d+$/)[0],
callback:function(err,data){
var user = {
steamid:identifier.match(/\d+$/)[0],
avatarUrl: data.response.players[0].avatar,
name:data.response.players[0].personaname
};
return done(null, user);
}
});
// In case of an error, we invoke done(err).
// If we cannot find or don't like the login attempt, we invoke
// done(null, false).
// If everything went fine, we invoke done(null, user).
});
});
passport.use(SteamStrategy);
}
routes.js
module.exports = function(app,passport,client){
app.get('/', function (req,res) {
res.render('index.ejs',{
user: req.user,
title:"yo"});
});
app.get('/auth',passport.authenticate('openid'));
app.get('/auth/return',passport.authenticate('openid'),function(req,res){
if (req.user) {
res.redirect('/');
} else {
res.redirect('/');
}
});
}
Could you use this: https://www.npmjs.com/package/redis-sessions ?
There's a method called soid which gets all sessions of a single id. You could query user's id as they log in. Then get all the sessions from that id. If soid returns empty you can safely assume the user had no sessions. If it returns with things inside it, then the user has sessions.
This is my best attempt right now.
Good luck.

Categories

Resources