Change Express static path dynamically - express

In Express you setup a static folder to serve your files through a middleware. From what I have understood this is then set throughout the applications lifecycle.
Is this possible to set somewhere in server.js for each request instead? For instance some requests uses "clientNew" folder while other requests uses "client". I want to be able to see the difference through a session-id, not through the URL.

So while this is not a recommended approach for a an "open" application with lots of users due to optimization with caching and response time I solved it by doing a pointer to the static handler.
exports.createDynamicPath = function(app, path) {
var static = app.loopback.static(path, { etag: false});
var dynamicPath = function (req, res, next) {
return static(req, res, next);
}
dynamicPath.setPath = function (newPath) {
static = app.loopback.static(newPath, { etag: false})
}
return dynamicPath;
}
exports.determineClient = function(app, dynamicPath){
return function(req, res, next) {
if(req.cookies && req.cookies.version != "client2"){
dynamicPath.setPath("client");
}else{
dynamicPath.setPath("client2");
}
next();
}
}
Based upon the variable in cookies it then switches path. Something worth noting is the disabling of etag, this is critical due to browsers storing previous client and determining if their file is still viable to keep.
This code is used early by the app, in this case Loopback (which by core uses Express).

Related

getInitialProps is called on front end in nextjs

I have code for user fetch from the session in _app.tsx.
MyApp.getInitialProps = async ({ ctx }: any) => {
const { req, res } = ctx;
const session = auth0.getSession(req, res)
return { user: session?.user }
}
Problem is, that getInitialProps is sometimes called on client-side. I don`t understand why? Documentation says:
`getInitialProps enables server-side rendering in a page and allows you to do initial data population, which means sending the page with the data already populated from the server. This is especially useful for SEO.
https://nextjs.org/docs/api-reference/data-fetching/getInitialProps
What is wrong? Why is my function called on client-side?
In case I am wrong, how can I fetch user session data from server on server side?
The link you shared explains you need to use getServerSideProps instead of getInitialProps for Next.js version > 9.3.
Since getInitialProps called on client and server, you have to write authentication logic for both cases. To get the session on client use useUser hook, on server use getSession
import { useUser } from '#auth0/nextjs-auth0';
let user;
if (typeof window === 'undefined'){
const session=auth0.getSession(req,res)
console.log("check session to get user",session)
user=session.user
} else {
const data = useUser()
user=data.user
}

what prevents someone from exploiting route guarding vue js application

So I'm building my application to be protected by the vue-router library, but with simple getting started logic to protect the route, what actually prevents someone from making a fake "jwt" local storage key,value?
Sample:
function route_guard(to, from, next)
{
var isAuthenticated = false;
if(localStorage.getItem('jwt'))
isAuthenticated = true;
else
isAuthenticated = false;
if(isAuthenticated)
{
next();
}
else
{
next('/login');
}
}
So when I add a fake "jwt" under localstorage, I am shown the application. What are some practices to properly authenticate with the route guard which would not allow this type of exploit, or if there is a better way please share.

Serving public and private ports using Nestjs

I'm building a that aims to serve a mobile application. Besides serving the client, it will have several back-office functionalities.
We are using swagger and we do want to be able to access the swagger docs of our back-office endpoints. However, we do not want to expose all of our endpoints publicly.
Assuming that having all endpoints public is a bad option one solutions we are thinking of is letting our server serve two ports, and then only exposing one port to the public. We have created a small sample repo that that serves a client module and a back-office module on two different ports.
The main.ts looks like the following:
import { NestFactory } from '#nestjs/core';
import { ClientModule } from './modules/client/client.module';
import * as express from 'express';
import * as http from 'http';
import {ExpressAdapter} from '#nestjs/platform-express';
import { BackOfficeModule } from './modules/backoffice/backoffice.module';
import { SwaggerModule, DocumentBuilder } from '#nestjs/swagger';
async function bootstrap() {
const clientServer = express();
const clientApp = await NestFactory.create(
ClientModule,
new ExpressAdapter(clientServer),
);
const clientOptions = new DocumentBuilder()
.setTitle('ClientServer')
.setDescription('The client server API description')
.setVersion('1.0')
.addTag('client')
.build();
const clientDocument = SwaggerModule.createDocument(clientApp, clientOptions);
SwaggerModule.setup('api', clientApp, clientDocument);
await clientApp.init();
const backOfficeServer = express();
const backOfficeApp = await NestFactory.create(
BackOfficeModule,
new ExpressAdapter(backOfficeServer),
);
const backOfficeOptions = new DocumentBuilder()
.setTitle('BackOffice')
.setDescription('The back office API description')
.setVersion('1.0')
.addTag('backOffice')
.build();
const backOfficeDocument = SwaggerModule.createDocument(backOfficeApp, backOfficeOptions);
SwaggerModule.setup('api', backOfficeApp, backOfficeDocument);
await backOfficeApp.init();
http.createServer(clientServer).listen(3000); // The public port (Load balancer will route traffic to this port)
http.createServer(backOfficeServer).listen(4000); // The private port (Will be accessed through a bastian host or similar)
}
bootstrap();
Another option would be to create a bigger separation of the codebase and infrastructure, however as this is a very early stage we feel that is unnecessary.
Our question to the Nest community is thus, has anyone done this? If so, what is are your experience? What are the drawbacks to separating our backend code like this?
Disclaimer: this solution is for express+REST combination.
Routing
Even thought nestjs can't separate controller's based on port, it can separate them based on host. Using that, you can add a reverse proxy in front of your application, that modifies the host header based on the port. Or, you can do that in an express middleware, to make things even more simpe. This is what I did:
async function bootstrap() {
const publicPort = 3000
const privatePort = 4000
const server = express()
server.use((req, res, next) => {
// act as a proper reverse proxy and set X-Forwarded-Host header if it hasn't been set
req.headers['x-forwarded-host'] ??= req.headers.host
switch (req.socket.localPort) {
case publicPort:
req.headers.host = 'public'
break
case privatePort:
req.headers.host = 'private'
break
default:
// this shouldn't be possible
res.sendStatus(500)
return
}
next()
})
const app = await NestFactory.create(AppModule, new ExpressAdapter(server))
http.createServer(server).listen(publicPort)
http.createServer(server).listen(privatePort)
}
Controllers:
#Controller({ path: 'cats', host: 'public' })
export class CatsController {...}
#Controller({ path: 'internal' host: 'private' })
export class InternalController {...}
Alternatively, you can simplify by creating your own PublicController and PrivateController decorators:
// decorator for public controllers, also sets guard
export const PublicController = (path?: string): ClassDecorator => {
return applyDecorators(Controller({ path, host: 'public' }), UseGuards(JwtAuthGuard))
}
// decorator for private controllers
export const PrivateController = (path?: string): ClassDecorator => {
return applyDecorators(Controller({ path, host: 'private' }))
}
#PublicController('cats')
export class CatsController {...}
#PrivateController('internal')
export class InternalController {...}
Swagger
For swagger, SwaggerModule.createDocument has an option "include", which accepts a list of modules to include in the swagger docs. With a bit of effort we can also turn the swagger serving part into an express Router, so both the private and public swagger can be served on the same path, for the different ports:
async function bootstrap() {
const publicPort = 3000
const privatePort = 4000
const server = express()
server.use((req, res, next) => {
// act as a proper reverse proxy and set X-Forwarded-Host header if it hasn't been set
req.headers['x-forwarded-host'] ??= req.headers.host
switch (req.socket.localPort) {
case publicPort:
req.headers.host = 'public'
break
case privatePort:
req.headers.host = 'private'
break
default:
// this shouldn't be possible
res.sendStatus(500)
return
}
next()
})
const app = await NestFactory.create(AppModule, new ExpressAdapter(server))
// setup swagger
let publicSwaggerRouter = await createSwaggerRouter(app, [CatsModule])
let privateSwaggerRouter: await createSwaggerRouter(app, [InternalModule])
server.use('/api', (req: Request, res: Response, next: NextFunction) => {
switch (req.headers.host) {
case 'public':
publicSwaggerRouter(req, res, next)
return
case 'private':
privateSwaggerRouter(req, res, next)
return
default:
// this shouldn't be possible
res.sendStatus(500)
return
}
})
http.createServer(server).listen(publicPort)
http.createServer(server).listen(privatePort)
}
async function createSwaggerRouter(app: INestApplication, modules: Function[]): Promise<Router> {
const swaggerConfig = new DocumentBuilder().setTitle('MyApp').setVersion('1.0').build()
const document = SwaggerModule.createDocument(app, swaggerConfig, { include: modules })
const swaggerUi = loadPackage('swagger-ui-express', 'SwaggerModule', () => require('swagger-ui-express'))
const swaggerHtml = swaggerUi.generateHTML(document)
const router = Router()
.use(swaggerUi.serveFiles(document))
.get('/', (req: Request, res: Response, next: NextFunction) => {
res.send(swaggerHtml)
})
return router
}
That's ok, but if you want to run two servers on 1 host, I would recommend to create two files like main-client.ts and main-back-office.ts and run them in different processes, because in that case failures of one server would not affect work of another.
Also if you are not run this in Docker I would suggest tools like forever, pm2, supervisor or my own very small library workers-cluster
If you run it in Docker and don't want big refactoring, I would recommend to create
single Dockerfile with running different CMD or ENTRYPOINT commands
The NestJS docs cover how to let one server serve multiple ports:
https://docs.nestjs.com/faq/multiple-servers#multiple-simultaneous-servers
The following recipe shows how to instantiate a Nest application that listens on multiple ports (for example, on a non-HTTPS port and an HTTPS port) simultaneously.
const httpsOptions = {
key: fs.readFileSync('./secrets/private-key.pem'),
cert: fs.readFileSync('./secrets/public-certificate.pem'),
};
const server = express();
const app = await NestFactory.create(
ApplicationModule,
new ExpressAdapter(server),
);
await app.init();
http.createServer(server).listen(3000);
https.createServer(httpsOptions, server).listen(443);

Can I set authorization headers with RequireJS?

We want to have 2 sets of resources for our AngularJS app (public/private) which uses RequireJS for dependency management. Basically everything on the login page would be public and once logged in, another angularjs app would be loaded (new requirejs config) that would load resources that require authentication to access.
Is there a way to configure requirejs to set an authorization header when loading resources?
It depends on what you mean by "resources" and how your server is configured. But in general - yes, since you are using AngularJS you can use the $httpProvider to inject an interceptor service.
For example, in a service:
var dependencies = ['$rootScope', 'userService'];
var service = function ($rootScope, userService) {
return {
request: function(config) {
var currentUser = userService.getCurrentUser();
var access_token = currentUser ? currentUser.access_token : null;
if(access_token) {
config.headers.authorization = access_token;
}
return config;
},
responseError: function (response) {
if(response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return response;
}
};
};
module.factory(name, dependencies.concat(service));
Then, after you configure your routes, you can use:
$httpProvider.interceptors.push( 'someService');
You can find some more information on interceptors here: https://docs.angularjs.org/api/ng/service/$http#interceptors
UPDATE
You might be able to use the text plugin to try and receive it, but I don't see the point in protecting client side code. Plus, if you want to use optimization the resources will just come in one file anyway...
config: {
text: {
onXhr: function (xhr, url) {
xhr.setRequestHeader('Authorization','Basic ' + token);
}
}
}
Refer to: custom-xhr-hooks
Another UPDATE
You could also use urlArgs (mainly used for cache invalidation) without using the text plugin:
require.config({
urlArgs: 'token='+token,
...
)}

How do I call {express,connect}.bodyParser() from within middleware?

I have some custom middleware. In some of my handlers, I want to use req.body, but that only works if the user did
app.use(express.bodyParser());
I could always tell the user, "you must use express.bodyParser() first," but I prefer to be safe and instantiate it if it has not been loaded yet.
Is there any way to invoke express.bodyParser() or connect.bodyParser() inside middleware?
I'm not sure if this is will work and if it'll always work, but I believe it'll be the "closer" way of doing what you want, without depending on connect/express (thing that you haven't specified in your question).
// Beware that the main module of the node process _must_
// be able to resolve express with this! This will allow to not depend on express.
var express = require.main.require( "express" );
// If you can depend on express, use this instead!
//var express = require( "express" );
function yourMiddleware( req, res, next ) {
var me = function( req, res ) {
// do your things
next();
};
if ( req.body === undefined ) {
express.bodyParser()( req, res, me );
} else {
me( req, res );
}
}