Securing assets folder in express js node - node.js

I have an assets folder in which i have images and render them with node express js. Is there a way to secure the assets in such a way that the users access only the assets entitled to them?
const app = express();
app.use('/assets', express.static('assets'));
app.listen(port, () => {
console.log(`Server runnning on port ${port}`);
});

Basically you are looking for authorization middleware which will take care of checking the access.
You can use passport js or any other library or create your own.
Since you are using Express to code, this snippet may be useful.
requireLogin = (req, res, next) => {
if (!req.user) {
return res.status(401).send({ error: 'You must login!' });
}
next();
};
app.get('/assets',requireLogin , express.static('assets'));
Express has very good documentation on middleware here .

Related

Api returning 404 on production

I have a next.js app and I'm trying to create an api. When I run it as development, the api's get called, but when I run it using next start I get a 404 error when calling the api's.
Here's the relevant server.js code:
app.prepare().then(() => {
require('./server/startup/routes')(server);
server.get('*', (req, res) => {
return handle(req, res);
});
const PORT = process.env.PORT || 5000;
server.listen(PORT, err => {
if (err) throw err;
console.log(`> Read on http://localhost:${PORT}`);
});
});
Here's the routes file
module.exports = app => {
app.use('/api/something-cool', cool);
};
Cool File:
const express = require('express');
const router = express.Router();
router.post('/', async (req, res) => {
...Code
res.send({ status: 'ok' });
});
module.exports = router;
The api route of /something-cool works when I run nodemon, but when I run next run, it returns a 404 error. What am I doing wrong and how can I fix it?
You are using a custom server (express) on top of Next.js to customize routes. This means that first, you have to build the Next.js App and then you have to run your server.js file in order to serve the App.
Option 1:
Builds the production application first
next build
Then run you server.js file:
NODE_ENV=production node server.js
more info here https://github.com/zeit/next.js/tree/master/examples/custom-server-express
Option 2:
There is also the option to create the API route within the Next.js App without using a custom server.
See https://github.com/zeit/next.js/tree/master/examples/api-routes for more info on how to do it.

Webpack proxy messing up my routing?

So I'm using webpack for a project on 8080 with a backend on 3000. The proxy seems to work fine, as I can send requests to the backend and access it without issue. However. I need to include this middleware that allows me to have a user load the page, and if they've logged in within a certain amount of time, the initial request they send to the server logs them in automatically.
router.use(function (req, res, next) {
//check token for routes beneath vvvv
})
router.post('/preauth', function (req, res) {
//return user account info if req.token is valid
})
When I try to get to prauth, or even any route before that from the page loaded on 8080 I only touch the middleware and nothing else.
When I do npm run build then try it again from the identical page on 3000, it works as expected.
No, CORS is not enabled and the proxy does not rewrite any url.
Does anyone know if something in my Webpack config might be causing this?
You need install Cors in nodejs:npm install cors, you can try the following below or you see: Nodejs + Vuejs
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('This is a CORS-enabled web server listening on port 80')
})

Serving multiple react apps with client-side routing in Express

I have different software products for one single service, which needs to be deployed to a single server. The clients are built with react, with a build setup by create-react-app, while the server runs Node.js and Express.
When I serve a single application from the server it is done the following way:
// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);
if(process.env.NODE_ENV !== 'development') {
app.use(express.static(path.join(__dirname, 'build-client')));
app.get('/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
I want to be able to serve multiple apps from the server. How should I do that?
What I tried is to wire in different static paths for the assets and separate the clients with different names, although it did not work. Like this:
// App.js
// ...
// Entry point for data routes (API)
app.use('/data', indexRoute);
if(process.env.NODE_ENV !== 'development') {
app.use(express.static(path.join(__dirname, 'build-client')));
app.use(express.static(path.join(__dirname, 'build-admin')));
app.get('/client/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
app.get('/admin/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
I have also tried to do it this way, but Express throw Error: No default engine was specified and no extension was provided:
if(process.env.NODE_ENV !== 'development') {
// Admin paths
app.use('/admin', express.static(path.join(__dirname, 'build-admin')));
app.get('/admin/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
});
// Site paths
app.use('/', express.static(path.join(__dirname, 'build-client')));
app.get('/*', function(req, res) {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
}
How could I accomplish this or something similar?
After some tinkering I was able to achieve this without using virtual hosts. I used the first idea you gave in the question, except I left the main app at the root (i.e. /).
// when going to `/app2`, serve the files at app2/build/* as static files
app.use('/app2', express.static(path.join(__dirname, 'app2/build')))
// when going to `/`, serve the files at mainApp/build/* as static files
app.use(express.static(path.join(__dirname, 'mainApp/build')))
// These are necessary for routing within react
app.get('app2/*', (req, res) => {
res.sendFile(path.join(__dirname + '/app2/build/index.html'))
})
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/mainApp/build/index.html'));
});
After this, I went into mainApp/package.json and added
"proxy": "http://localhost:4141"
:4141 is the port that the express server is running on. This line will make calls to fetch('/some/route') go back to the server instead of into your react app itself.
Finally, we go to app2/package.json and add
"proxy": "http://localhost:4141/app2",
"homepage": "/app2"
I believe that the key here is the "homepage" key. The way I understand it, when react starts it searches for some static files at its homepage, and without the "homepage" piece I was only able to get either a blank white screen or the mainApp.
I hope this helps someone out there!
EDIT
I have since changed from serving my create-react-apps through my express server to serving them through netlify. Now I don't need to worry about this express setup, or the homepage key in package.json. The express server lives by itself, and the react apps can still both use the same api, and deployment is much easier. Setup with netlify is trivial.
After struggling for a while with this problem I've found a possible solution without compromising the original setup.
We used Express vhost package to setup handling of requests through virtual domains.
When you create your app instance, you should initialize as many apps with express as you want to expose separately (in our case its three separate apps plus the original app instance)
// Create an express instance
const app = express();
const appAdmin = express();
const appClient = express();
const appVendor = express();
After that you need to install vhost and import it. Then with specifying the static folder for each app you can handle serving the static files separately, while the remaining part deals with handling the request for the given subdomains respectively.
appAdmin.use(express.static(path.join(__dirname, 'build-admin')));
appClient.use(express.static(path.join(__dirname, 'build-client')));
appVendor.use(express.static(path.join(__dirname, 'build-vendor')));
appAdmin.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-admin' , 'index.html'));
});
appClient.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-client' , 'index.html'));
});
appVendor.use((req, res, next) => {
return res.sendFile(path.resolve( __dirname, 'build-vendor' , 'index.html'));
});
app.use(vhost('domain.com', appClient));
app.use(vhost('www.domain.com', appClient));
app.use(vhost('a.domain.com', appAdmin));
app.use(vhost('b.domain.com', appVendor));
Don't forget to add the desired subdomains in your domain's DNS registry. Example:
...records
CNAME vendor #
CNAME admin #

Calling Express by hand

In a node.js/express/socket.io application, how does one "call" express by hand to load/render the home page without saying app.use(blah). In other words, if I wanted to tell express to load index.html by hand instead of automatically.
var express = require('express'),
app = express(),
...
//app.use magically loads index.html when the browser hits 8080
app.use(express.static(path.join(__dirname, '../client/www'))); //index.html is in www
var port = process.env.PORT || 8080; //select your port or let it pull from your .env file
//===============PORT=================
http.listen(port, function () {
console.log('listening on: ' + port);
}
Where index.html is in www ? This doesn't work:
app.get('/', function(req, res){
res.sendfile('index.html', { root: __dirname + "/relative_path_of_file" } );
});
Nor this:
app.get('/', function(req, res){
res.render('/home/idf/Documents/js/react-trader/client/www/index.html', {user: req.user});
});
I was able to resolve the problem that is the cause of this question. I am using Passport to authenticate Express. I needed to protect the home page (index.html), so I added a route and ensured that the user had to be authenticated to view that page. So I said:
app.get('/index.html', ensureAuthenticated, function(req, res){
...
}
The problem is that if I do this, when the user authenticates, I couldn't figure out how to pass control to Express. I either could authenticate (and prevent accessing the home page) through Passport routing, or I could do Express. But I couldn't do both.
It turns out the answer is really simple (or at least in my very limited understanding at this point) I got to work by simply rewriting to
app.get('/index.html', ensureAuthenticated, function(req, res, next){
return next();
}
In essence, the way to break out of Passport routes and pass control to Express [or "call it by hand" - hence my question] is to return next();
This is not obvious at all, and it took quite a bit of experimentation to get it to work.

Capture all http requests with node/express

I am looking to capture all of the data from any request (images, fonts, css, js, etc) on my website so that I can capture the file details, specifically the file name and file size. I have found almost an identical question/solution:
Node.js : How to do something on all HTTP requests in Express?
But the solution appears to be deprecated with Express v4. Is there a simple solution to do this? As another approach I have tried the below solution with no luck:
var express = require("express");
var path = require("path");
var port = process.env.PORT || 3000;
var app = express();
var publicPath = path.resolve(__dirname, "public");
app.use(express.static(publicPath));
app.get("/", function(req, res){
// I want to listen to all requests coming from index.html
res.send("index.html");
});
app.all("*", function(){
// can't get requests
})
app.listen(port, function(){
console.log(`server listening on port ${port}`);
});
Also I am not looking to do this from Fiddler/Charles because I am looking to display this data on my site.
Express routes are predicated on order. Notice the answer that you linked in your question has the middleware defined, and used before all other routes.
Secondly you're trying to implement something that requires middleware, not a wildcard route. The pattern in link you provided in your question is not deprecated according to their docs.
app.use(function (req, res, next) {
// do something with the request
req.foo = 'testing'
next(); // MUST call this or the routes will not be hit
});
app.get('/', function(req, res){
if (req.foo === 'testing') {
console.log('works');
}
res.send("index.html");
});

Resources