Connect/Express per request middleware is failing somewhere - node.js

I'm trying to do a very simple Basic Auth middleware for Express on Node.js as demonstrated here: http://node-js.ru/3-writing-express-middleware
I have my middleware function:
var basicAuth = function(request, response, next) {
if (request.headers.authorization && request.headers.authorization.search('Basic ') === 0) {
// Get the username and password
var requestHeader = new Buffer(
request.headers.authorization.split(' ')[1], 'base64').toString();
requestHeader = requestHeader.split(":");
var username = requestHeader[0];
var password = requestHeader[1];
// This is an async that queries the database for the correct credentials
authenticateUser(username, password, function(authenticated) {
if (authenticated) {
next();
} else {
response.send('Authentication required', 401);
}
});
} else {
response.send('Authentication required', 401);
}
};
And I have my route:
app.get('/user/', basicAuth, function(request, response) {
response.writeHead(200);
response.end('Okay');
});
If I try to curl this request I get:
curl -X GET http://localhost/user/ --user user:password
Cannot GET /user/
This works totally cool when I add the middleware while calling createServer(), but when I do it per-request like I am in this route, it just dies quietly server-side. Unfortunately, since not all requests require authentication, I can't make this a global middleware.
I've tried flipping off Express and just using Connect and I get the same result, so I assume it's something in there. Has anybody experienced this before?
Edit: I should also mention that I've logged the relevant code exhaustively and next is being called, but it just appears to go nowhere.
Edit 2: For the record, an "empty" middleware also fails silently:
var func = function(request, response, next) {
next();
};
app.get('/user', func, function(request, response) {
response.writeHead(200);
response.end('Okay');
});
This also has the same result.

function(request, response, callback) {
vs
next();
Your supposed to either change callback to next or vica versa.

I found this link.
Express middleware: Basic HTTP Authentication
The author seems to be doing the same thing as you did, except he has a return after the next().

Related

Not able to redirect as a post request

I am trying to redirect the user with a post request from the home page after checking if their sessions exist.
This is my home controller file:-
const express = require('express');
const router = express.Router();
router.get('/', (req, res, next) => {
if (req.session["Data"] != undefined) {
res.redirect(307, '/Try');
}
else {res.render('home', {pageTitle: "Home"});}
});
module.exports = router;
But it is giving me error- Cannot GET /Try
This is what I'm using in my route file- router.post('/Try', try_controller.Try);
I am using res.redirect(307, '/Try') in another controller file of the same project and it's working. I can't figure out why it's not working here.
I don't think you can redirect a GET as a POST. If you own the /Try route, one option is to add a GET handler for that, then redirect will work.
Otherwise, in your GET route handler for \ you can create a new POST and return the results of that.
const request = require('request')
router.get('/', (req, res, next) => {
if (req.session["Data"] != undefined) {
//res.redirect(307, '/Try');
request.post('/Try', {}, function(err, response, body) {
if (err) return next(err)
return res.status(response.statusCode).send(body);
})
}
else {res.render('home', {pageTitle: "Home"});}
});
The example above an https://github.com/request/request though there are more modern ways of sending POST from express.
This isn't technically "redirecting", so you won't return 307 or 302.
I tried different things but in the end, I added an empty form in my home.pug file and submitted it using js.
JS code -
script.
let ssn = !{JSON.stringify(session)};
data = "Data"
if (ssn[data] != undefined) {document.getElementById('form-id').submit();}

How to have express server make an initial http request before serving static files

I have a basic express server being used for an api server and serving static files for a react app like so:
app.use(express.static('/public'))
app.use('/api', apiRouter)
When a user initially loads the app, I need to retrieve data from a different server that I'll need for the api server before serving up the static files. Is there a way to have express make an initial http request to another server and cache the results on the server before serving up the static files?
Ideally, I want the server to make this request only once (when the user initially loads the app). I've looked into using express middleware, but am having trouble figuring out where to insert the middleware so that it only gets called when the files are served up.
First off, if you really want to only make a request once to some outside server, then you should probably just do it upon server startup. There's really no reason to wait until some request comes in if you're going to cache the result anyway and it doesn't matter what route or what user is making the first request.
But, if you want to trigger it only when a request comes in, then you can use middleware to do so. An outline of the middleware could look something like this:
let cachedResult;
app.use((req, res, next) => {
if (cachedResult) {
next();
} else {
request(..., (err, response, body) => {
if (err) {
next(err);
} else {
cachedResult = ....
next();
}
});
}
});
If you want the middleware to ONLY execute when a static resource is requested, then you need some way of determining which incoming requests are for static resources and which are not.
The code you show:
app.use(express.static('/public'))
checks the public sub-directory for a match for any request which isn't very helpful. If you would prefix all static resources with a prefix such as /static, then you could target only your static files like this:
app.use('/static', express.static('/public'));
And, you could run the middleware only for the static files like this:
app.use('/static', (req, res, next) => { ... });
app.use('/static', express.static('/public'));
Request. Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.
A simple request example could look like:
var request = require('request');
request({
url: "https://some.url.com",
method: "POST",
headers: { "content-type" : "application/json" },
json: payload
},
function (error, response, data) {
if (!error && response.statusCode == 200) {
//handle request
}
else {
callback({ "errorMessage": "There was an error with the request" });
}
}
);
Ok, first: caching. Define a variable or a module that will be accessible to your future middleware:
./cache.js
const cache = {};
module.exports = cache;
This module will hold users' data, like:
{
'id00001': {
email: 'foo#bar.com',
birthday: 1488700668567
},
'id00002': {
email: 'baz#bar.com',
birthday: 1488700668590
},
// etc...
}
Next, use Request and Express middleware:
./app.js
const express = require('express'),
app = express();
const cache = require('./cache'),
request = require('request');
const getUserDataMiddleware = (req, res, next) => {
// assuming you have a mechanism to identify your users already somehow
let user = req.user,
id = user.id;
// if data is not in cache
if (!cache[id]) {
request.get({
url: 'http://getuserdata.com/' + id,
json: true
}, (err, response, body) => {
if (err) {
next(err);
return;
}
// save received data to cache
cache[id] = body;
next();
});
} else {
// you have your user data in cache, do whatever you want now
next();
}
};
app.use('/public', getUserDataMiddleware, express.static('./public'));

express response locals disappear

I would like to send error messages back to the client without adding them to the url. Here is my attempt:
exports.register = function(req, res) {
if (req.body.password != req.body.password_repeat) {
res.locals.err = 'Passwords must match.';
res.locals.action = 'register';
res.redirect('/');
return;
}
...
exports.index = function(req, res) {
req.url = '/';
res.render('index', {
action: res.locals.action,
error: res.locals.error,
redirect: res.locals.redirect
});
};
So the redirect works fine and exports.index executes. The problem is that res.locals are gone by then. Is this because once I redirect it is considered a new req/res cycle? Any way I can pass this information through redirect without doing something like res.redirect('/?error=error')
You can use flash package from expressjs, but you need to have session middleware to use it. Also, you can use express-flash package from RGBboy but you need to have both cookieParser and session middlewares in this case.

Block regular users from Google auth callback Express Route

I have the following program to log in with Google:
app.get('/oauth/google', function(req, res) {
res.redirect(<OAUTH2_URL>);
});
app.get('/oauth/google/callback', function(req, res, next) {
var code = req.query.code;
if(!code || !_.isString(code)) {
return next(new Error(400, 'Invalid code'));
}
.
.
.
// I try the code to see if it is valid.
});
How do I only allow Googles redirect back to the application to have access to the callback route, and block regular users from using it?
If you're using sessions then you could set a flag from your /oauth/google path before you redirect off to Google, and then on your /oauth/google/callback simply check for that flag, and reset.
app.get('/oauth/google', function(req, res) {
req.session.authFlag = true;
res.redirect(<OAUTH2_URL>);
});
app.get('/oauth/google/callback', function(req, res, next) {
if (!req.session.authFlag) return next(new Error(403, 'Forbidden'));
else req.session.authFlag = false;
...
});
If you're not using sessions though, or for some reason sessions aren't available because the client doesn't support cookies (which should be a concern in above mentioned solution as well!), then I guess your best bet is to just check for req.query.code because other than that query string (req.query.code) there's no difference between requests redirected by Google and direct requests made by regular user.
(...req.headers.referer/origin could've worked in theory but they're unreliable and shouldn't be used as a measure)

How to get the remoteUser for a request with express.js

I'm using a basicAuth middleware in my app, and it works.
But then, in my routes functions, I would like to get the login that was used by the user to authenticate. Assuming req is my request variable, this was supposed to be in req.remoteUser (and later in req.user).
But currently both are set to 'true'. I check that the middleware is used before calling app.use(app.router), so the req request should be populated ! I also use a bodyParser on the line right after basicAuth, and it populates the request correctly.
Nothing much on google, only one issue in express github saying that now it works and both req.user and req.remoteUser have the value.
One needs to provide the username to the callback function (even if the calling code obviously has it in it's context) if we want req.user to be set.
So intead of doing this (as the great tutorial I followed said) :
var express = require('express');
var app = express();
// Authenticator
app.use(express.basicAuth(function(user, pass, callback) {
var result = (user === 'testUser' && pass === 'testPass');
callback(null /* error */, result);
}));
app.get('/home', function(req, res) {
res.send('Hello World');
});
app.listen(process.env.PORT || 8080);
One must change the function into :
app.use(express.basicAuth(function(user, pass, callback) {
if (user === 'testUser' && pass === 'testPass') {
callback(null /* error */, user);
} else {
callback(null, null);
}
}));
And for those wondering, yes that means we can't have a user whose name is the empty String (else it will be interpreted as false by express), which seems a shame.

Resources