ReactJS - MongoDB - JavaScript: MongoDB is not receiving any data from API - javascript

I am building a boat visualizer using AISHub APIs. After inquiring the APIs I am able to obtain a json file with the vessels I am interested in and inject these vessels inside a table.
the problem I have is that after I receive and filter the data from the API, I would like to send them to MongoDB to store them. As of now MongoDB is not receiving any data and I don't know why?
According to the official documentation of MongoDB here is what I did to create the 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:
app.js
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;
index.js
var express = require('express');
var router = express.Router();
var axios = require('axios');
const NodeCache = require('node-cache');
const myCache = new NodeCache();
let hitCount = 0;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
const mmsiOfInterest = [
'367029520',
'366909730',
'367128570'
];
const shipNamesOfInterest = [
'MICHIGAN',
'JP BOISSEAU',
'DELAWARE BAY
];
router.get('/hello', async function(req, res, next) {
const cData = myCache.get('cData');
if (!cData) {
hitCount++;
console.log(`hit ${hitCount} number of times`);
const { data } = await axios.get(
'http://data.aishub.net/ws.php?username=request'
);
const [ metaData, ships ] = data;
const shipsOfInterest = ships.filter(
(ship) => mmsiOfInterest.includes(ship.MMSI) || shipNamesOfInterest.includes(ship.NAME)
);
myCache.set('cData', shipsOfInterest, 70);
res.send(data);
return;
}
res.send(cData);
});
module.exports = router;
users.js
var express = require('express');
var router = express.Router();
// vessel models
const Vessles = require('../models/Vessels');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post('/vessles/map', function(req, res) {
const { callsign, name, imo, mmsi } = req.body;
let errors = [];
// Check required fields
if (!callsign || !name || !imo || !mmsi) {
errors.push({ msg: 'No data received' });
}
if (
Vessles.findOne({ mmsi: mmsi }).then((vessels) => {
if (vessels) {
// vessel exists
const newVessel = new Vessles({
callsign,
name,
imo,
mmsi
});
}
})
);
});
module.exports = router;
MondoDB Schema organization for Vessels.js
const mongoose = require('mongoose');
const VesselsSchema = new mongoose.Schema({
callsign: {
type: String,
required: true
},
name: {
type: String,
required: true
},
imo: {
type: Number,
required: false
},
mmsi: {
type: Number,
required: false
}
});
const Vessels = mongoose.model('Vessels', VesselsSchema);
module.exports = Vessels;
Posts that I have been reading to help me solve the problem but without success:
1) front end react is not sending data to db
2) connection to mongo db in react
3) This source was very useful but does not quite operate what I am trying to solve as it is more for rendering. Will surely be useful later though.
4) I thought that this source was extremely useful but didn't fully and clearly explain the process, otherwise with more explanation would probably be good.
Thanks for pointing in the right direction for solving this problem.

Related

ReactJS - JavaScript: Failing to dynamically pass API data to MongoDB database

I am building a small boat visualizer using AIS APIs. After inquiring the APIs I am able to obtain a json file with the vessels and filter with only the vessel I am interested in, and inject them into a table on the webpage. The API gives several fileds but I only filter specific ones: [NAME, CALLSIGN, HEADING, SOG, IMO, MMSI, LONGITUDE, LATITUDE, DATE]. I can correctly connect to MongoDB as I sudo npm start.
Please shed light on why information are not being saved. I followed the documentation and a lot of posts but still something is not right.
The problem: I would like to send also the API data to a collection to MongoDB database. I successfully connect to MongoDB but information are not being passed. I don't understand why that is happening despite following official documentation on forming a Schema is followed.
Below is how I try to write to MongoDB:
users.js
var express = require('express');
var router = express.Router();
const LatitudeLongitude = require('../models/LatitudeLongitude');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post('/vessles/map/latlng', function(req, res) {
const { name, callsign, heading, sog, imo, mmsi, longitude, latitude, date } = req.body;
let errors = [];
// Check required fields
if (!name || !callsign || !heading || !sog || !imo || !mmsi || !longitude || !latitude || !date) {
errors.push({ msg: 'No data received' });
console.log('error');
}
// vessel exists
const newVessel = new LatitudeLongitude({
name,
callsign,
heading,
sog,
imo,
mmsi,
longitude,
latitude,
date
});
// Save all vessels info
newVessel.save(function(err, vessel) {
if (err) return console.log(err);
});
res.status(200).end();
});
LatitudeLongitude.js --> forming a Schema
const mongoose = require('mongoose');
const LatitudeLongitudeSchema = new mongoose.Schema(
{
name: {
type: String,
required: true
},
callsign: {
type: String,
required: true
},
heading: {
type: Number,
required: false
},
sog: {
type: Number,
required: true
},
imo: {
type: Number,
required: false
},
mmsi: {
type: Number,
required: false
},
longitude: {
type: Number,
required: false
},
latitude: {
type: Number,
required: false
},
date: {
type: Date,
required: true
}
},
{ collection: 'latitudelongitude' }
);
const LatitudeLongitude = mongoose.model('LatitudeLongitude', LatitudeLongitudeSchema);
module.exports = LatitudeLongitude;
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');
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);
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
const PORT = process.env.PORT || 3000;
app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
app.use(bodyParser.json({ limit: '50mb' }));
app.use(cors());
app.listen(PORT, console.log(`Server started on port ${PORT}`));
module.exports = app;
Also below is my collection for completeness:
what I have done so far:
I tried many different ways to pass data from the API to MongoDB and the best approach I found simple is the one above I posted, but there is an error I can't seem to catch.
I believe that the file users.js should be the one that is probably missing something.
The connection to the database happens on the file app.js and I can confirm that the I can successfully connect to MongoDB.
I consulted this source, and also this one. But none of them was useful to understand what I am doing wrong.

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

Express / Passport SAML Authentication Redirects Leading to Infinite Loop

Trying to use passport-saml connecting to ADFS.
The SAML Response is coming back with Successful status codes.
We get the following success code back:
"<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status>"
But our Passport IsAuthenicated is always generating a false.
I have listed out all of our files used for this below and would appreciate any help.
server.js file:
const express = require('express');
const http = require('http');
const path = require('path');
const passport = require('passport');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require('express-session');
const errorhandler = require('errorhandler');
var env = process.env.NODE_ENV || 'development';
const config = require('./config/config')[env];
console.log('Using configuration', config);
require('./config/passport')(passport, config);
var app = express();
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(cookieParser());
app.enable('trust proxy'); // add this line
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(session(
{
resave: true,
saveUninitialized: true,
secret: 'default',
proxy: true // add this line
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(morgan('combined'));
function ensureAuthenticated(req, res, next) {
if (//req.isAuthenticated()
true
) {
console.log('req.isAuthenticated = ' + req.isAuthenticated());
return next(); }
else{
console.log('req.isAuthenticated = ' + req.isAuthenticated());
res.redirect('/login');
}
}
app.set('port', config.app.port);
require('./config/routes')(app, config, passport);
//ensure that ensureAuthenticated is in the get function call before master build
//ie app.get('/*', ensureAuthenticated, (req, res)
app.use(express.static(path.join(__dirname, 'public')));
app.get('/*', ensureAuthenticated, (req, res) => {
res.sendFile(path.join(__dirname, 'public/index.html'));
});
app.listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
routes.js
module.exports = function (app, config, passport) {
app.get('/', function (req, res) {
res.redirect('/home')
});
app.get('/login',
passport.authenticate(config.passport.strategy,
{
successRedirect: '/',
failureRedirect: '/login'
})
);
app.post('/',
passport.authenticate(config.passport.strategy,
{
failureRedirect: '/',
failureFlash: true
}),
function (req, res) {
res.redirect('/');
}
);
app.get('/logout', function (req, res) {
req.logout();
// TODO: invalidate session on IP
res.redirect('https://redrectsite.com/?wa=signout1.0');
});
};
config.js
module.exports = {
development: {
app: {
name: 'Passport SAML strategy example',
port: process.env.PORT || 80
},
passport: {
strategy: 'saml',
saml: {
callbackUrl: process.env.SAML_CALLBACK_URL || 'https://oursite.com',
entryPoint: process.env.SAML_ENTRY_POINT || 'https://oursite.com/adfs/ls/idpinitiatedsignon',
issuer: process.env.SAML_ISSUER || 'https://oursite.com',
identifierFormat: null,
signatureAlgorithm: 'sha256',
authnContext: 'http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows',
disableRequestedAuthnContext: true
//cert: process.env.SAML_CERT || null
}
}
}
};
passport.js
const SamlStrategy = require('passport-saml').Strategy;
module.exports = function (passport, config) {
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
passport.use(new SamlStrategy(
{
callbackUrl: config.passport.saml.callbackUrl,
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
cert: config.passport.saml.cert,
identifierFormat: config.passport.saml.identifierFormat,
signatureAlgorithm: config.passport.saml.signatureAlgorithm,
authnContext: config.passport.saml.authnContext,
disableRequestedAuthnContext: config.passport.saml.disableRequestedAuthnContext
},
function (profile, done) {
return done(null,
{
id: profile.uid,
email: profile.email,
displayName: profile.cn,
firstName: profile.givenName,
lastName: profile.sn
});
})
);
};
I had a similar issue. If you look at what isAuthenticated() does, it's actually just checking a property within the request.session object.
https://github.com/jaredhanson/passport/blob/2327a36e7c005ccc7134ad157b2f258b57aa0912/lib/http/request.js#L86
req.isAuthenticated = function() {
var property = 'user';
if (this._passport && this._passport.instance) {
property = this._passport.instance._userProperty || 'user';
}
return (this[property]) ? true : false;
};
I'm not sure if it's passport or express-session, but once you get to the authentication method, the user object is stored at request.session.passport.user so if you like, you can directly verify that it's non-null instead of using the packaged isAuthenticated() method, which seems to check the wrong path.
My code started working after changing it to the following.
if (_.get(req, 'session.passport.user', null)) {
return next();
}
(lodash _.get for easier null-checking of the nested properties)

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.

Categories

Resources