If I disable NODE_TLS_REJECT_UNAUTHORIZED, my request is still denied - node.js

I am disabling Node from rejecting self signed certificates and making a request.
const { USER, PW } = process.env;
const b64 = new Buffer(`${VP_API_USER}:${VP_API_PW}`).toString("base64");
const Authorization = `Basic ${b64}`;
const doFind = async url => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
const results = await fetch(url, { headers: { Authorization } })
.then(r => (r.ok ? r.json() : Promise.reject(r)))
.catch(err => {
return Promise.reject(err);
});
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
return results;
};
I am still being rejected.
{ FetchError: request to https://<url>:55544/contracts failed, reason: connect ECONNREFUSED <url>:55544
at ClientRequest.<anonymous> (/Users/mjhamm75/Developer/sedd-monorepo/node_modules/node-fetch/index.js:133:11)
at emitOne (events.js:116:13)
at ClientRequest.emit (events.js:211:7)
at TLSSocket.socketErrorListener (_http_client.js:387:9)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at emitErrorNT (internal/streams/destroy.js:64:8)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
name: 'FetchError',
message: 'request to https://<url>:55544/contracts failed, reason: connect ECONNREFUSED <url>:55544',
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED' }
What am I doing wrong?

process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
line should go inside the callback (your then or catch before the return. because a promise gets resolved in the callback, but your line
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
is written outside of it, even though it appears after the statement, it runs immediately without waiting for the callback. so, your tls is effectively never disabled.
I hope this helps:)

Previous answer looks incorrect - await postpones execution of next line until promise will be resolved.
According to the documentation the NODE_TLS_REJECT_UNAUTHORIZED value should be string '0' to disable TLS validation.

This is how I would approach it, if I had to reset the env var afterwards.
Using .finally() the statement will execute regardless of the outcome of the fetch.
const doFind = async url => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
const results = await fetch(url, { headers: { Authorization } })
.then(r => (r.ok ? r.json() : Promise.reject(r)))
.catch(err => {
return Promise.reject(err);
})
.finally(() => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = 1;
});
return results;
};

Related

Nodejs - ERR_TLS_CERT_ALTNAME_INVALID

I have called this function below:
export async function getStaticProps() {
const res = await fetch("https://links.papareact.com/pyp");
const exploreData = await res.json();
return {
props: {
exploreData,
},
};
}
And it is showing the error below. How do I solve this issue?
Server Error
FetchError: request to https://jsonkeeper.com/b/4G1G failed, reason: Hostname/IP does not match certificate's altnames: Host: jsonkeeper.com. is not in the cert's altnames: DNS:www.jsonkeeper.com
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Call Stack
ClientRequest.
file:///P:/Work/Web%20Development/airbnb-clone/node_modules/next/dist/compiled/node-fetch/index.js (1:65756)
ClientRequest.emit
node:events (527:28)
TLSSocket.socketErrorListener
node:_http_client (454:9)
TLSSocket.emit
node:events (527:28)
emitErrorNT
node:internal/streams/destroy (157:8)
emitErrorCloseNT
node:internal/streams/destroy (122:3)
processTicksAndRejections
node:internal/process/task_queues (83:21)your text
I was trying to call an api but its showing
type: 'system',
errno: 'ERR_TLS_CERT_ALTNAME_INVALID',
code: 'ERR_TLS_CERT_ALTNAME_INVALID',
I have installed mkcert but the problem was not solved.
You just need to add www to the jsonkeeper link
export async function getStaticProps() {
const res = await fetch('https://www.jsonkeeper.com/b/4G1G');
const exploreData = await res.json();
return {
props: {
exploreData,
},
};
}

Dropbox API integration on AWS Lambda gets FetchError (ETIMEDOUT)

I have a node.js app which runs on AWS Lambda. The Lambda is connected with a VPC. It goes internet with a static IP. I use v10.23.0 dropbox-sdk-js. It always seems to run on my local but it sometimes runs on the lambda, sometimes gets fetch error.
My code is like this:
async function main() {
const Dropbox = require('dropbox').Dropbox;
const dropbox = {
dbx: new Dropbox({
accessToken: process.env.ACCESS_TOKEN,
pathRoot: JSON.stringify({ '.tag': 'namespace_id', 'namespace_id': process.env.NAMESPACE_ID })
})
};
const payload = {
path: '',
recursive: true,
include_media_info: false,
include_deleted: false,
include_has_explicit_shared_members: true,
include_mounted_folders: true,
include_non_downloadable_files: true
};
let hasMore = true;
let entries = [];
let response;
let cursor;
while (hasMore) {
try {
if (cursor) {
response = await dropbox.dbx.filesListFolderContinue({ cursor: cursor });
}
else {
response = await dropbox.dbx.filesListFolderGetLatestCursor(payload);
response = await dropbox.dbx.filesListFolderContinue({ cursor: response.result.cursor });
}
console.info('Entries: ', JSON.stringify(response.result.entries));
cursor = response.result.cursor;
entries = entries.concat(response.result.entries);
hasMore = response.result.has_more;
}
catch (error) {
console.info(error);
return error;
}
}
}
main();
Error log:
2022-01-20T08:22:18.579Z 67caa239-e75c-46ce-be4c-0fcf6c154694 INFO FetchError: request to https://api.dropboxapi.com/2/files/list_folder/continue failed, reason: connect ETIMEDOUT 162.125.4.19:443
at ClientRequest.<anonymous> (/var/task/node_modules/dropbox/node_modules/node-fetch/lib/index.js:1483:11)
at ClientRequest.emit (events.js:400:28)
at TLSSocket.socketErrorListener (_http_client.js:475:9)
at TLSSocket.emit (events.js:400:28)
at emitErrorNT (internal/streams/destroy.js:106:8)
at emitErrorCloseNT (internal/streams/destroy.js:74:3)
at processTicksAndRejections (internal/process/task_queues.js:82:21) {
type: 'system',
errno: 'ETIMEDOUT',
code: 'ETIMEDOUT'
}
I deattached VPC from lambda and it worked. I think AWS blocks fetching while you are using VPC.

Socket Hangup Error In Node JS On Force API Timeout

I am using request module in Node JS (v8.12) to call a third party API. Since the API is not very reliable and due to lack of better option I am timing out the call after 2 seconds in case if there is no response from the API. But in doing so it creates a socket hang up error. Below is the code used and stack trace
const options = {
url: resource_url,
rejectUnauthorized: false,
timeout: 2000,
method: 'GET',
headers: {
'content-Type': 'application/json',
}
};
return new Promise(function (resolve, reject) {
request(options, function (err, res, body) {
if (!err) {
resolve(JSON.parse(body.data));
} else {
if (err.code === 'ETIMEDOUT' || err.code == 'ESOCKETTIMEDOUT') {
resolve(someOldData);
} else {
resolve(someOldData);
}
}
});
});
Error: socket hang up
at createHangUpError (_http_client.js:331:15)
at TLSSocket.socketCloseListener (_http_client.js:363:23)
at scope.activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:54:19)
at Scope._activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/async_hooks.js:51:14)
at Scope.activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:12:19)
at TLSSocket.bound (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:53:20)
at emitOne (events.js:121:20)
at TLSSocket.emit (events.js:211:7)
at _handle.close (net.js:554:12)
at TCP.done [as _onclose] (_tls_wrap.js:356:7)
After doing a bit of reading and research I found this article pointing out a similar issue so I switched to http module as mentioned in one of the solution in the article. But switching to http module also did not resolve the issue. Below is code implementation using http and stack trace.
let responseData;
const requestOptions = {
hostname: resource_host,
path: resource_path,
method: 'GET',
timeout: 2000,
};
return new Promise((resolve, reject) => {
const requestObject = http.request(requestOptions, (responseObj) => {
responseObj.setEncoding('utf8');
responseObj.on('data', (body) => {
responseData = body;
});
responseObj.on('end', () => {
resolve(responseData);
});
});
requestObject.on('error', (err) => {
responseData = someOldData;
resolve(responseData);
});
requestObject.on('timeout', () => {
responseData = someOldData;
requestObject.abort();
});
requestObject.end();
});
Error: socket hang up
at connResetException (internal/errors.js:608:14)
at Socket.socketCloseListener (_http_client.js:400:25)
at <trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:54:19
at Scope._activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/async_hooks.js:51:14)
at Scope.activate (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:12:19)
at Socket.bound (<trace-log-base-path>/dd-trace/packages/dd-trace/src/scope/base.js:53:20)
at Socket.emit (events.js:322:22)
at Socket.EventEmitter.emit (domain.js:482:12)
at TCP.<anonymous> (net.js:672:12)
I went through multiple SO post and various other resources over the web, but I am unable to resolve this issue.
Could it be because of the third party, because I also tried to reproduce the issue by creating a dummy server which sleeps for some time after the request is fired and timing out that request but was unable to reproduce the issue.
I'll be very grateful for any help in this regards.
Removing requestObject.abort() in timeout event block when using http module resolves this issue.

NodeJS axios request self signed works in browser but not in jest supertest case

I am building a NodeJS app that makes calls to an external API. The external API uses a self-signed certificate. I tried setting the environment variable process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'. This works to ignore the certificate verification when using the app normally. However, a request to the same endpoint does NOT work when calling the NodeJS route with the Jest Supertest agent.
There is a certificate verification error when running the Jest Supertest case. Is there a way to accept self-signed certificates when sending requests using the Supertest agent?
npm test
Error: Error: SSL Error: DEPTH_ZERO_SELF_SIGNED_CERT
at Object.dispatchError (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:54:19)
at EventEmitter.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
at EventEmitter.emit (events.js:323:22)
at Request.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:384:47)
at Request.emit (events.js:311:20)
at Request.onRequestResponse (/home/node/app/node_modules/request/request.js:948:10)
at ClientRequest.emit (events.js:311:20)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:603:27)
at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17)
at TLSSocket.socketOnData (_http_client.js:476:22) undefined
NodeJS internal route
Works when accessing route via the browser, but not when running Jest Supertest. The internal route is /internal and that works, but when that code subsequently sends a request to the external API that has a self-signed certificate, the self-signed certificate causes a 500 error message.
router.get('/internal', (req, res, next) => {
// Set request values that are specific to this route
const requestOptionsData = { method: `GET`, endpoint: `/external` };
try {
httpCtrl.makeRequest(requestOptionsData).then(result => {
if (result.error) {
return res.status(result.status).json(result.error.message || result.error);
}
return res.status(result.status).json(result);
}).catch((error) => {
console.error(error);
return res.status(500).send(error);
});
} catch (e) {
console.error(e);
return res.status(500).send(e);
}
});
NodeJS controller
A wrapper function to make axios requests to external API
httpCtrl.makeRequest = async (requestOptionsData) => {
let result = {};
// Set request options
const requestOptions = httpCtrl.setApiRequestOptions(requestOptionsData);
let response;
try {
response = await axios(requestOptions);
} catch(e) {
result.error = e.toJSON() || e;
console.error(result.error);
result.status = 500;
return result;
}
result.status = response && response.status || 500;
result.data = response && response.data || {};
return result;
}
JEST Supertest
Test that causes certificate error
const app = require('../app.js');
const supertest = require('supertest');
describe('API routes', () => {
it('GET internal NodeJS route', async done => {
agent
.get('/internal')
.set('Accept', 'application/json')
.send()
.expect(200)
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).toBe(200);
return done();
});
});
});
UPDATE:
I tried removing NODE_TLS_REJECT_UNAUTHORIZED and setting rejectUnauthorized to false in the axios agent config but still having the same problem. The connection works when using the app via the browser but does work with supertest.
const agent = new https.Agent({
rejectUnauthorized: false
});
const options = {
url: url,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${requestOptionsData.jwt}`,
'Host': process.env.ADMIN_API_BASE_URL
},
method: requestOptionsData.method || `GET`,
httpsAgent: agent
}
Here is the error with this agent configuration:
Error: Error: self signed certificate
at Object.dispatchError (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:54:19)
at EventEmitter.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
at EventEmitter.emit (events.js:323:22)
at Request.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:384:47)
at Request.emit (events.js:311:20)
at Request.onRequestError (/home/node/app/node_modules/request/request.js:877:8)
at ClientRequest.emit (events.js:311:20)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:311:20)
at emitErrorNT (internal/streams/destroy.js:92:8) undefined
console.error controllers/http.ctrl.js:50
I was able to solve this with the solution in this github issue.
I solved it by adding testEnvironment: 'node', to jest.config.js file.
https://github.com/axios/axios/issues/1180

Node.js Error: Max redirects exceeded

how I can ignore pages with cycle redirects?
I use this code to fetching pages:
var libxml = require("libxmljs"),
http = require('follow-redirects').http,
url = require("url");
var request = http.request( { "host": host, "path": URL, "port": 80 }, function( response ) {
var str = '';
response.on( 'data', function( chunk ) {
str += chunk;
});
response.on( 'end', function() {
callback( str, response.statusCode );
}).on( 'error', function ( err ) {
console.log( err );
});
}).end();
It will not go to 'error' block, and I've got an exception:
events.js:85
throw er; // Unhandled 'error' event
^
Error: Max redirects exceeded.
at ClientRequest.cb (/var/parsing/node_modules/follow-redirects/create.js:55:19)
at ClientRequest.g (events.js:199:16)
at ClientRequest.emit (events.js:107:17)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:426:21)
at HTTPParser.parserOnHeadersComplete (_http_common.js:111:23)
at Socket.socketOnData (_http_client.js:317:20)
at Socket.emit (events.js:107:17)
at readableAddChunk (_stream_readable.js:163:16)
at Socket.Readable.push (_stream_readable.js:126:10)
at TCP.onread (net.js:538:20)
The error is being thrown by the request object, not the response object, so you need to add an (additional) error listener to request;
var request = http.request(...).on('error', function(err) {
...
}).end();
Looking at the docs for the package you are using (https://www.npmjs.com/package/follow-redirects), it looks like it just has a maxRedirects option. Directly from the linked page:
require('follow-redirects').maxRedirects = 10; // Has global affect (be careful!)
https.request({
host: 'bitly.com',
path: '/UHfDGO',
maxRedirects: 3 // per request setting
}, function (res) {/* ... */});

Resources