UNABLE_TO_VERIFY_LEAF_SIGNATURE while using http-proxy in Node - node.js

All,
I am trying to create a simple proxy which forwards all requests verbatum to another server. To do this I'm using the "http-proxy" npm. I am trying to go from local to a cloud server. At first when I setup the http-proxy I saw an error "unable to verify the first certificate". After some research online I found it's probably related to the fact that I have a self-signed certificate. Because it's self-signed it's not in the certificate store and so can't be validated. But, beacause I don't need this during development, I added "secure: false" to ignore certificate verification. I know that's unsafe from production, but I'm just trying to get around this for now. This update actually got around this error.
Now, I am getting another error "UNABLE_TO_VERIFY_LEAF_SIGNATURE".
Can any one help me figure out how to get rid of this error? I've tried adding this:
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
But that still shows the error. I see the error in the event emitted by the http-proxy (See code below for this event). If I drill down itno the 'proxyRes' I can see this error in the proxyRes -> connection -> authorizationError -> UNABLE_TO_VERIFY_LEAF_SIGNATURE
Here is my code below:
'use strict'
require('dotenv').config({silent: true})
var util = require('util');
const loggerFactory = require('./utils/logger')
const express = require('express')
const defaultRouter = require('./routes/default')
var logger = loggerFactory.consoleLogger
const proxy = require('http-proxy');
module.exports = (config) => {
const app = express()
// app.use(loggerFactory.requestLogger())
app.set('json spaces', 2)
app.set('port', config.express.port)
app.use('', defaultRouter)
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
var apiProxy = proxy.createProxyServer({});
var proxyUrl = process.env.HOMEINSPECTIONSERVER_URL;
app.use((req,res,next) => {
apiProxy.web(req, res,
{
target: proxyUrl,
secure: false,
}
);
apiProxy.on('error', function(e) {
logger.error("Error during proxy call!")
logger.error("This is the error : " + e)
next('route')
});
apiProxy.on('proxyReq', function(proxyReq, req, res, options) {
logger.info("---REQUEST---")
console.log("---REQUEST---")
// logger.info(util.inspect(proxyReq))
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
});
apiProxy.on('proxyRes', function (proxyRes, req, res) {
// logger.info("---RESPONSE---")
// logger.info(util.inspect(proxyRes))
// logger.info("---RESPONSEEND---")
logger.info('RAW Response from the target',
JSON.stringify(proxyRes.headers, true, 2));
});
apiProxy.on('open', function (proxySocket) {
proxySocket.on('data', hybiParseAndLogMessage);
});
apiProxy.on('close', function (res, socket, head) {
console.log('Client disconnected');
});
apiProxy.on('start', function (req, res, target) {
// console.log('Started Request!');
});
})
app.use((req, res) => {
// logger.info('starting request...')
res.json(res.locals.standardResponse)
})
app.use((err, req, res, next) => {
var statusCode = 500
if (res.locals.standardResponse) {
res.locals.standardResponse.error = err
statusCode = err.statusCode || 600
logger.error(err)
res.status(statusCode).json(res.locals.standardResponse)
}
if (err.error !== undefined && err.error.httpStatus !== undefined) {
statusCode = err.error.httpStatus
} else {
statusCode = err.statusCode || 600
}
logger.error(err)
res.status(statusCode).json(res.body)
})
return app
}

I had the same problem using http-proxy-middleware the problem is solved by adding secure: false like this
const {createProxyMiddleware} = require('http-proxy-middleware');
app.use('/firmware-images/:firmwareImageId/files/:fileId/download', createProxyMiddleware({ target: `${FILES_URL}`, changeOrigin: true, secure: false }));
I know is not the same package, but it is the same problem, so I hope it helps someone.

For any one also having this problem above. I solved it by using the npm package called express-http-proxy. You can get it here:
enter link description here
So my code now looks like this:
'use strict'
require('dotenv').config({silent: true})
const loggerFactory = require('./utils/logger')
const express = require('express')
const defaultRouter = require('./routes/default')
var logger = loggerFactory.consoleLogger
module.exports = (config) => {
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
const app = express()
app.set('json spaces', 2)
app.set('port', config.express.port)
app.use('', defaultRouter)
var proxy = require('express-http-proxy');
app.use(proxy(process.env.HOMEINSPECTIONSERVER_URL))
return app
}
Note the important piece of code here:
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
Hope that helps anyone who is stuck!

Related

Not able to understand working of Cors in my Node js serverside code

The below is my server.js code of my React app's backend.
I am not able to understand the working of the below line
app.use(cors(options));
The full code is as below:
const express = require("express");
const app = express();
const cors = require("cors");
let allowed = ["http://localhost:3000", "http://localhost:4000"];
function options(req, res) {
let tmp;
let origin = req.header("Origin");
if (allowed.indexOf(origin) > -1) {
tmp = {
origin: true,
optionSuccessStatus: 200,
};
} else {
tmp = {
origin: false,
};
}
res(null, tmp);
}
app.use(cors(options));
app.listen(8000, () => {
console.log("Server running at 8000");
});
app.get("/", (req, res) => {
res.send("Hi From server hello super");
});
My doubt
The "options" is a function which has arguments . But in the line app.use(cors(options)), how the arguments are passed
res(null,tmp) -> what does it do. Is it equivalent to res.send(tmp)?
This is using the Express-CORS middleware which has some documentation describing what it means to have options be a function.
Specifically, the options function is called by the middleware as the request is being processed to determine the impact on the specified fields like origin, method, optionsSuccessStatus (by the way, your code has a typo for this field—its missing an s), etc.
As the documentation shows, res is just a callback that lets the rest of the middleware and other middlewares continue normal execution.

Do not understand the function with Express and CORS [duplicate]

This question already has an answer here:
NodeJS callback with null as first argument
(1 answer)
Closed 9 months ago.
This is a code I found in the internet using Express and CORS:
const express = require('express');
const app = express();
const cors = require('cors');
var corsOptionsDelegate = async (req, callback) => {
var corsOptions = { origin: false };
try {
...
corsOptions.origin = true;
} catch (err) {
console.log(err);
}
callback(null, corsOptions)
}
app.use(cors(corsOptionsDelegate));
I don't know how this function callback(null, corsOptions) process in this code.
This is just a standard callback design pattern. Here's an article you can read but also you should learn more about what design patterns are and how Node.js works. This is a very basic question you're asking here.
You actually do not need any function callback for simple servers.
There is a much simpler way.
const whiteList = [ "https://myRealBackendUrl-1", "https://myRealBackendUrl-2" ];
// you can also pass a string here instead here instead of array
const corsOptions = {
credentials: true,
origin: process.env.NODE_ENV !== production ? "http://localhost:3000" : whiteList
// if you are in a dev environment, you probably want something like localhost
// if you are in a production environment, for example heroku then your backend
// url will be something like http://example.herokuapp.com
// in that case `const whiteList = [ "http://example.herokuapp.com" ];`
};
app.use(cors(corsOptions));
The above code should be enough for the normal use case.
As for the callback function, it is if you want to run some function of your own.
var corsOptionsDelegate = async (req, callback) => {
var corsOptions = { origin: false };
try {
// you can do some dynamic check here
// For example: check database for some conditions then allow access
if( myDatabaseSays == true ) corsOptions.origin = true;
else corsOptions.origin = false;
} catch (err) {
console.log(err);
// corsOptions.origin = false;
}
callback(null, corsOptions) // chain it
}
Anyway read the docs properly for more info
[1]: https://expressjs.com/en/resources/middleware/cors.html

node + Swagger behind nginx proxy_pass

I'm trying to get node and swagger to work with nginx dynamically
server_name ~^backend(?<PORTSERVER>[^.]+)\.domain\.com$;
location /swagger
{
proxy_pass http://127.0.0.1:$PORTSERVER/swagger/;
}
location /api
{
proxy_pass http://127.0.0.1:$PORTSERVER/api;
}
this is an example of virtual host the PORTSERVER variable is taking from gitlab-ci it takes id number of merge request + 2000
when i put the port directly in place of $PORTSEVER every thing is working swagger and api
any advice is appreciated thank you
this is index.js file
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
const typeorm_1 = require("typeorm");
const express = require("express");
// var router = express.Router();
const fileUpload = require("express-fileupload");
const bodyParser = require("body-parser");
const routes_1 = require("./routes");
const cors = require("cors");
const typeorm_pagination_1 = require("typeorm-pagination");
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('../../swagger.json');
var path = require('path');
typeorm_1.createConnection()
.then((connection) => __awaiter(void 0, void 0, void 0, function* () {
// create express app
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(fileUpload());
app.use(express.static(path.join(__dirname, '..', 'public')));
console.log(path.join(__dirname, '..', 'public'));
// register express routes from defined application routes
routes_1.Routes.forEach((route) => {
app[route.method]('/api' + route.route, (req, res, next) => {
const result = new route.controller()[route.action](req, res, next);
res.header('Access-Control-Allow-Origin', '*');
if (result instanceof Promise) {
result.then((result) => (result !== null && result !== undefined ? res.send(result) : undefined));
}
else if (result !== null && result !== undefined) {
res.json(result);
}
});
});
// setup express app here
// ...
app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.use(express.json());
app.use(cors());
app.use(typeorm_pagination_1.pagination); // Register the pagination middleware
// start express server
// app.listen(process.env.SERVER_Port);
app.listen(process.env.PORTSERVER);
console.log('Express server has started on port ' + process.env.PORTSERVER);
}))
.catch((error) => console.log(error));
//# sourceMappingURL=index.js.map
The key is his sentence is "when i put the port directly in place of $PORTSEVER every thing is working swagger and api"
Based on the description you gave, I think that gitlabci is miss generating the port number, or miss understanding the syntax.. Both gitlabci and nginx uses $VAR syntax.. Can be a miss interpretation of the 1st line regex too..
Also, I think you need to check the content of process.env.PORTSERVERa used in the js file.. It can have different port than nginx..
For this, I would approach the issue by preventing the the job from restarting nginx to not cause down time for other vhosts.. Deploy a broken config then from the server I run nginx -t and/or diff -u a working config and a broken one..
The 1st source of truth would be nginx -t and nginx logs.. If, ever, nginx manage the starts, the HTTP code it's returning can reveal more paths to pursuit.
One thing you forgot to share is the content of your gitlabci YML.. That can help identify the issue too.

Backend API calls not rerouting in node express [duplicate]

To avoid same-domain AJAX issues, I want my node.js web server to forward all requests from URL /api/BLABLA to another server, for example other_domain.com:3000/BLABLA, and return to user the same thing that this remote server returned, transparently.
All other URLs (beside /api/*) are to be served directly, no proxying.
How do I achieve this with node.js + express.js? Can you give a simple code example?
(both the web server and the remote 3000 server are under my control, both running node.js with express.js)
So far I found this https://github.com/http-party/node-http-proxy , but reading the documentation there didn't make me any wiser. I ended up with
var proxy = new httpProxy.RoutingProxy();
app.all("/api/*", function(req, res) {
console.log("old request url " + req.url)
req.url = '/' + req.url.split('/').slice(2).join('/'); // remove the '/api' part
console.log("new request url " + req.url)
proxy.proxyRequest(req, res, {
host: "other_domain.com",
port: 3000
});
});
but nothing is returned to the original web server (or to the end user), so no luck.
request has been deprecated as of February 2020, I'll leave the answer below for historical reasons, but please consider moving to an alternative listed in this issue.
Archive
I did something similar but I used request instead:
var request = require('request');
app.get('/', function(req,res) {
//modify the url in any way you want
var newurl = 'http://google.com/';
request(newurl).pipe(res);
});
I found a shorter and very straightforward solution which works seamlessly, and with authentication as well, using express-http-proxy:
const url = require('url');
const proxy = require('express-http-proxy');
// New hostname+path as specified by question:
const apiProxy = proxy('other_domain.com:3000/BLABLA', {
proxyReqPathResolver: req => url.parse(req.baseUrl).path
});
And then simply:
app.use('/api/*', apiProxy);
Note: as mentioned by #MaxPRafferty, use req.originalUrl in place of baseUrl to preserve the querystring:
forwardPath: req => url.parse(req.baseUrl).path
Update: As mentioned by Andrew (thank you!), there's a ready-made solution using the same principle:
npm i --save http-proxy-middleware
And then:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/api', {target: 'http://www.example.org/api'});
app.use(apiProxy)
Documentation: http-proxy-middleware on Github
You want to use http.request to create a similar request to the remote API and return its response.
Something like this:
const http = require('http');
// or use import http from 'http';
/* your app config here */
app.post('/api/BLABLA', (oreq, ores) => {
const options = {
// host to forward to
host: 'www.google.com',
// port to forward to
port: 80,
// path to forward to
path: '/api/BLABLA',
// request method
method: 'POST',
// headers to send
headers: oreq.headers,
};
const creq = http
.request(options, pres => {
// set encoding
pres.setEncoding('utf8');
// set http status code based on proxied response
ores.writeHead(pres.statusCode);
// wait for data
pres.on('data', chunk => {
ores.write(chunk);
});
pres.on('close', () => {
// closed, let's end client request as well
ores.end();
});
pres.on('end', () => {
// finished, let's finish client request as well
ores.end();
});
})
.on('error', e => {
// we got an error
console.log(e.message);
try {
// attempt to set error message and http status
ores.writeHead(500);
ores.write(e.message);
} catch (e) {
// ignore
}
ores.end();
});
creq.end();
});
Notice: I haven't really tried the above, so it might contain parse errors hopefully this will give you a hint as to how to get it to work.
To extend trigoman's answer (full credits to him) to work with POST (could also make work with PUT etc):
app.use('/api', function(req, res) {
var url = 'YOUR_API_BASE_URL'+ req.url;
var r = null;
if(req.method === 'POST') {
r = request.post({uri: url, json: req.body});
} else {
r = request(url);
}
req.pipe(r).pipe(res);
});
I used the following setup to direct everything on /rest to my backend server (on port 8080), and all other requests to the frontend server (a webpack server on port 3001). It supports all HTTP-methods, doesn't lose any request meta-info and supports websockets (which I need for hot reloading)
var express = require('express');
var app = express();
var httpProxy = require('http-proxy');
var apiProxy = httpProxy.createProxyServer();
var backend = 'http://localhost:8080',
frontend = 'http://localhost:3001';
app.all("/rest/*", function(req, res) {
apiProxy.web(req, res, {target: backend});
});
app.all("/*", function(req, res) {
apiProxy.web(req, res, {target: frontend});
});
var server = require('http').createServer(app);
server.on('upgrade', function (req, socket, head) {
apiProxy.ws(req, socket, head, {target: frontend});
});
server.listen(3000);
First install express and http-proxy-middleware
npm install express http-proxy-middleware --save
Then in your server.js
const express = require('express');
const proxy = require('http-proxy-middleware');
const app = express();
app.use(express.static('client'));
// Add middleware for http proxying
const apiProxy = proxy('/api', { target: 'http://localhost:8080' });
app.use('/api', apiProxy);
// Render your site
const renderIndex = (req, res) => {
res.sendFile(path.resolve(__dirname, 'client/index.html'));
}
app.get('/*', renderIndex);
app.listen(3000, () => {
console.log('Listening on: http://localhost:3000');
});
In this example we serve the site on port 3000, but when a request end with /api we redirect it to localhost:8080.
http://localhost:3000/api/login redirect to http://localhost:8080/api/login
Ok, here's a ready-to-copy-paste answer using the require('request') npm module and an environment variable *instead of an hardcoded proxy):
coffeescript
app.use (req, res, next) ->
r = false
method = req.method.toLowerCase().replace(/delete/, 'del')
switch method
when 'get', 'post', 'del', 'put'
r = request[method](
uri: process.env.PROXY_URL + req.url
json: req.body)
else
return res.send('invalid method')
req.pipe(r).pipe res
javascript:
app.use(function(req, res, next) {
var method, r;
method = req.method.toLowerCase().replace(/delete/,"del");
switch (method) {
case "get":
case "post":
case "del":
case "put":
r = request[method]({
uri: process.env.PROXY_URL + req.url,
json: req.body
});
break;
default:
return res.send("invalid method");
}
return req.pipe(r).pipe(res);
});
I found a shorter solution that does exactly what I want https://github.com/http-party/node-http-proxy
After installing http-proxy
npm install http-proxy --save
Use it like below in your server/index/app.js
var proxyServer = require('http-route-proxy');
app.use('/api/BLABLA/', proxyServer.connect({
to: 'other_domain.com:3000/BLABLA',
https: true,
route: ['/']
}));
I really have spent days looking everywhere to avoid this issue, tried plenty of solutions and none of them worked but this one.
Hope it is going to help someone else too :)
I don't have have an express sample, but one with plain http-proxy package. A very strip down version of the proxy I used for my blog.
In short, all nodejs http proxy packages work at the http protocol level, not tcp(socket) level. This is also true for express and all express middleware. None of them can do transparent proxy, nor NAT, which means keeping incoming traffic source IP in the packet sent to backend web server.
However, web server can pickup original IP from http x-forwarded headers and add it into the log.
The xfwd: true in proxyOption enable x-forward header feature for http-proxy.
const url = require('url');
const proxy = require('http-proxy');
proxyConfig = {
httpPort: 8888,
proxyOptions: {
target: {
host: 'example.com',
port: 80
},
xfwd: true // <--- This is what you are looking for.
}
};
function startProxy() {
proxy
.createServer(proxyConfig.proxyOptions)
.listen(proxyConfig.httpPort, '0.0.0.0');
}
startProxy();
Reference for X-Forwarded Header: https://en.wikipedia.org/wiki/X-Forwarded-For
Full version of my proxy: https://github.com/J-Siu/ghost-https-nodejs-proxy
I think you should use cors npm
const app = express();
const cors = require('cors');
var corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions));
https://www.npmjs.com/package/cors

Double request in Chrome with Nodejs

I'm doing a test with Nodejs to increment a global counter, according to the scripts below. Everything works, except that Chrome executes two sequential requests when I refresh it, which causes the counter to increment twice as well (see the image). In Postman and Firefox works fine and only one request occurs on refresh. I've done the tests running the app on Linux and Windows and the problem with Chrome holds. Anyone have any idea what might be happening?
server.js
const http = require('http');
const express = require('express');
const app = express();
const rotas = require("./route-test")(app);
const port = 3000;
const server = app.listen(process.env.PORT || port, function(){
console.log('App listening port: ', port);
});
route-test.js
const myGlobalVars = require("./global-vars");
module.exports = (app) => {
app.use('/', (req, res) => {
res.end('Counter in: ' + myGlobalVars.counter);
});
app.use(function(req, res, next){
//console.log(req.originalUrl);
});
}
global-vars.js
let myCounter = 0;
const _myVars = Object.create(Object.prototype, {
dateInit: {
writable: false,
configurable: false,
value: new Date()
},
counter: {
configurable: false,
get: function() { return myCounter++ },
set: function(_val) {
myCounter = _val;
}
}
});
module.exports = _myVars;
I check all 3 files... so in FireFox and Google Canary(developers version) we have only 1 request(we got 1 request and we increment only once myGlobalVars.counter ). in simple Google Chrome version we have 2 request. one of them is request for favicon.ico. so we just need to add condition to ignore favicon.ico request and dont increment twice our myGlobalVars.counter value...
in route-test.js
const myGlobalVars = require("./global-vars");
module.exports = (app) => {
app.use('/', (req, res) => {
// instead of this code res.end('Counter in: ' + myGlobalVars.counter);
// add this condition
if (req.url === '/') {
res.end( `\n\n\nCounter in: ${myGlobalVars.counter}` );
}
});
}
I think it's the request that the browser makes to the server to get /favicon.ico resource.
You might have faced this bug :
https://bugs.chromium.org/p/chromium/issues/detail?id=64810
Today, it should be fixed in Chrome, but you can still reproduce it in Chromium instrumented by puppeteer for example.

Resources