Nodejs basic auth with https - node.js

I have a nodjs app running that uses basic auth with the password details in a file generated by htpasswd. This is working fine.
What I'd like to do is run it over https. I can get it working with https fine, but can't seem to work out how to get the two working together, https + basic auth.
This is for a browser going to the server and sending a variable in the url. I've found a few solutions but many seem to focus on the server doing a outbound call to something else with basic auth.
This is the basic auth one.
// Authentication module.
const auth = require('http-auth');
const basic = auth.basic({
realm: "REALM.",
file: __dirname + "/users.htpasswd"
});
const http = require('http');
const fs = require('fs');
var url = require('url');
const hostname = '0.0.0.0';
const port = 80;
const server = http.createServer(basic, (req, res) => {
var url_parts = url.parse(req.url, true);
var key = url_parts.query["name"];
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
fs.readFile(__dirname + '/basic.json', function (err, data) {
if (err) {
throw err;
}
table = JSON.parse(data.toString());
var value = table[key];
res.end(JSON.stringify({"group" : value}));
});
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
And this is the https bit without the basic auth.
const https = require('https');
const fs = require('fs');
var url = require('url');
const hostname = '0.0.0.0';
const port = 443;
const options = {
key: fs.readFileSync('star.pkey'),
cert: fs.readFileSync('star.pem'),
};
const server = https.createServer(options, (req, res) => {
var url_parts = url.parse(req.url, true);
var key = url_parts.query["name"];
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
fs.readFile(__dirname + '/basic.json', function (err, data) {
if (err) {
throw err;
}
table = JSON.parse(data.toString());
var value = table[key];
res.end(JSON.stringify({"group" : value}));
});
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Any help appreciated.

Related

Why did I get Error Cannot Get/ Node.js (in browser)

This is what I have, the filename "pages" actually exists
The code is:
var cors = require('cors');
var express = require('express');
var url = require('url');
var fs = require('fs');
var app = express();
var server = app.listen(3000, function () { console.log('Listening to port 3000') });
app.use(cors());
app.use(express.static('pages'));
app.post('/storeData', storeData);
function storeData(req, res) {
var input = url.parse(req.url, true).query;
var to_save = input.email + ',' + input.password + '\n';
fs.appendFile('./loginDetails.txt', to_save, (err) => {
if (err) console.log('Error occured while storing data!');
res.send('Data stored successfully');
});
}
The Error (in browser):
Cannot GET /
You haven't defined a get route for /. If you try to access a file under pages instead of just the root service, it should work.

Https proxy decode encoded data node js

I am trying to setup a proxy for http and https. Here is my code,
const http = require('http');
var https = require('https');
const fs = require('fs');
var url = require('url');
var net = require('net');
const config = require('./config');
let proxify = function (req, res) {
var urlObj = url.parse(req.url);
var target = urlObj.protocol + '//' + urlObj.host;
if (!req.headers['x-target']) req.headers['x-target'] = target;
req.headers['x-proxy-username'] = config.username;
req.headers['x-proxy-password'] = config.password;
console.log(target);
console.log('Proxy HTTP request for:', target);
var proxy = httpProxy.createProxyServer({});
proxy.on('error', function (err, req, res) {
console.log('proxy error', err);
res.end();
});
proxy.web(req, res, { target: config.server, changeOrigin: true });
};
var httpserver = http.createServer(proxify).listen(2890); //this is the port your clients will connect to
const httpsserver = https
.createServer(
{
cert: fs.readFileSync('./ssl_cert/cert.pem'),
key: fs.readFileSync('./ssl_cert/key.pem'),
},
proxify
)
.listen(2891);
var regex_hostport = /^([^:]+)(:([0-9]+))?$/;
var getHostPortFromString = function (hostString, defaultPort) {
var host = hostString;
var port = defaultPort;
var result = regex_hostport.exec(hostString);
if (result != null) {
host = result[1];
if (result[2] != null) {
port = result[3];
}
}
return [host, port];
};
httpserver.addListener('connect', function (req, socket, bodyhead) {
var hostPort = getHostPortFromString(req.url, 443);
var hostDomain = hostPort[0];
var port = parseInt(hostPort[1]);
console.log('Proxying HTTPS request for:', hostDomain, port);
req.headers['x-target'] = 'http://' + hostDomain + ':' + port;
req.headers['x-proxy-username'] = config.username;
req.headers['x-proxy-password'] = config.password;
var proxyHost = new URL(config.server);
var proxySocket = new net.Socket();
proxySocket.connect(
{ port: proxyHost.port, host: proxyHost.hostname },
function () {
console.log('bodyhead', bodyhead.toString()); //debug
proxySocket.write(bodyhead);
socket.write(
'HTTP/' + req.httpVersion + ' 200 Connection established\r\n\r\n'
);
}
);
proxySocket.on('data', function (chunk) {
console.log('proxy data chunk', chunk.toString()); // debug
socket.write(chunk);
});
proxySocket.on('end', function () {
socket.end();
});
proxySocket.on('error', function () {
socket.write('HTTP/' + req.httpVersion + ' 500 Connection error\r\n\r\n');
socket.end();
});
socket.on('data', function (chunk) {
console.log('data chunk', chunk.toString('utf8')); // debug
proxySocket.write(chunk);
});
socket.on('end', function () {
proxySocket.end();
});
socket.on('error', function () {
proxySocket.end();
});
});
Don't judge me too hard, just trying to get it working first.
When proxying http with windows 10 proxy settings, it works fine. But when I am trying to proxy https, it logs encoded data like `↕►♦♦♦☺♣♣♣♠♠☺↕3+)/1.1♣♣☺
☺↔ \s☻�t�DQ��g}T�c\‼sO��♦��U��ޝ∟-☻☺☺+♂
→→♥♦♥♥♥☻♥☺♥☻☻j☺§�` and gives a 400 bad request.I don't know if its the encoding of https response or something else, I have no idea what i am doing at this point and need help.
it is because https uses tls/ssl to encrypt the data.

resource is not passed - node js

I'm trying to forward created resource (http) by callback to print result on web page using it
var http = require('http');
var net = require('net');
var fs = require ('fs');
var Path = require('path');
function LookDirs(server,port,callback){
http.createServer(function (req, res) {
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.write('<html><head><title>Simple Server</title></head>');
res.write('<body> Test1');
callback('..', res);
res.end('\n</body</html>');
}).listen(port);
};
function ViewContent(dirPath){
fs.readdir(dirPath, function(err, entries){
for (var idx in entries){
var fullPath = Path.join(dirPath, entries[idx]);
(function(fullPath){
console.log(fullPath,idx);
res.write('abc');
})(fullPath);
}
})
}
LookDirs("Test 234", "1337", ViewContent);
And I keep getting
res.write('abc');
^
ReferenceError: res is not defined
I was sure that I have passed that resource during callback..
You can not access res from ViewContent.
This (req, res) responses from createServer stand for request and response. Here you can see more about it: https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/
const server = http.createServer((request, response) => {
// magic happens here!
});
Also you can not run callbacks on createServer prototype, but you can run on the listen method though.
var http = require('http');
var net = require('net');
var fs = require('fs');
var Path = require('path');
function LookDirs(server, port, callback) {
http.createServer(function (req, res) {
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.write('<html><head><title>Simple Server</title></head>');
res.write('<body> Test1');
res.end('\n</body</html>');
}).listen(port, callback("./"));
};
function ViewContent(dirPath) {
fs.readdir(dirPath, function (err, entries) {
for (var idx in entries) {
var fullPath = Path.join(dirPath, entries[idx]);
// I can not access res from here, it has sent already.
console.log(fullPath)
}
})
}
LookDirs("Test 234", "1337", ViewContent);

Node: letsencrypt-express module not working while using http and https node server

I am trying to use Letsencrypt without using a reverse proxy like Nginx, I found a module called letsencrypt-express (greenlock-express) on npm. But I cant get it working.
Working Example:
var express = require('express')
var letsencript = require('greenlock-express')
var leclg = require('le-challenge-fs')
var lestore = require('le-store-certbot')
var http = require('http');
var https = require('https');
var redHttps = require('redirect-https')
var app = express();
app.get('/', (req, res) => {
res.send('Ok Working');
})
var lex = letsencript.create({
server: 'staging',
// agreeTos: true,
approveDomains: (opts, certs, cb) => {
if (certs) {
// change domain list here
opts.domains = ['10hd.in']
} else {
// change default email to accept agreement
opts.email = 'test#gmail.com',
opts.agreeTos = true;
}
cb(null, { options: opts, certs: certs });
},
// app: app,
// challenges: { 'http-01': leclg.create({ webrootPath: '/tmp/acme-challenges' }) },
// store: lestore.create({ webrootPath: '/tmp/acme-challenges' })
}).listen(80, 443);
The Upper Example is working as expected. Redirects http to https and issues a certificate from the Letsencript stagging server. and stores them in ~/letsencript folder.
And Here is what I Want but not working.
var express = require('express')
var letsencript = require('greenlock-express')
var leclg = require('le-challenge-fs')
var lestore = require('le-store-certbot')
var http = require('http');
var https = require('https');
var redHttps = require('redirect-https')
var app = express();
app.get('/', (req, res) => {
res.send('Ok Working');
})
var lex = letsencript.create({
server: 'staging',
// agreeTos: true,
approveDomains: (opts, certs, cb) => {
if (certs) {
// change domain list here
opts.domains = ['10hd.in']
} else {
// change default email to accept agreement
opts.email = 'test#gmail.com',
opts.agreeTos = true;
}
cb(null, { options: opts, certs: certs });
},
// app: app,
// challenges: { 'http-01': leclg.create({ webrootPath: '/tmp/acme-challenges' }) },
// store: lestore.create({ webrootPath: '/tmp/acme-challenges' })
})
// .listen(80, 443);
const middlewareWrapper = lex.middleware;
// redHttps()
http.createServer(lex.middleware(redHttps())).listen(80, ()=> {
console.log("Listening for ACME http-01 challenges");
});
//
https.createServer(
lex.httpsOptions,
lex.middleware(app)
).listen(433, () => {
console.log("Listening for ACME tls-sni-01 challenges and serve app");
});
I Want to serve the server through https node module. and wanna do something in the callback provided in .listen() function.
But It does not even create let's encrypt the folder in home dir.
Console Output:
bubundas17#instance-2:~/test$ sudo node app.js
le.challenges[tls-sni-01].loopback should be defined as function (opts, domain, token, cb) { ... } and should prove (by external means) that the ACME server challenge 'tls-sni-01' will succeed
Listening for ACME http-01 challenges
Listening for ACME tls-sni-01 challenges and serve app
I solved the problem myself. the "greenlock-express" is just an interceptor of "greenlock" module.
Here is a working Code.
const http = require('http');
const https = require('https');
const redirectHttps = require('redirect-https')
var app = require('express')();
app.get('/', (req, res) => {
res.send("Test Server")
})
var le = require('greenlock').create({
server: 'staging',
configDir: 'certs/etc',
approveDomains: (opts, certs, cb) => {
if (certs) {
opts.domains = ['10hd.in']
} else {
opts.email = 'test#gmail.com',
opts.agreeTos = true;
}
cb(null, {
options: opts,
certs: certs
});
},
});
http.createServer(le.middleware(redirectHttps())).listen(80, function() {
console.log("Server Running On http" + 80);
})
https.createServer(le.httpsOptions, le.middleware(app)).listen(443, function() {
console.log("Server Running On https" + 443);
})
I don't Know Why this code is working and why the previous code is not! But the code is working, that's enough!

Nodejs websocket communication with external system

I'm new to nodejs and I'm trying to solve communication issue with external system.
There is a gateway to external system which can handle websocket requests on port 5000. In the example below, when you request homepage, the nodejs opens websocket connection, then on websocket open event it sends request and waits for response which is used for the HTTP response.
Do you know how to open websocket to external system only once and handle requests based on request id?
var ws = require('ws');
var express = require('express');
var async = require('async');
var uuid = require('node-uuid');
app = express();
app.get('/', function (req, res) {
var webSocket = new ws('ws://localhost:5000/');
async.series([
function (callback) {
webSocket.on('open', function () {
webSocket.send(JSON.stringify({query:'data query', requestid: uuid.v4()}));
callback(null, 'data query');
});
},
function (callback) {
webSocket.on('message', function (data, flags) {
callback(null, data);
})
}
], function (err, results) {
res.setHeader('content-type', 'text/javascript');
res.send(results[1]);
webSocket.terminate();
});
});
var server = app.listen(3000, function () {
var port = server.address().port
console.log('Listening at %s', port)
});
Thanks for the hints. I ended with the following solution which does what I expect:
var ws = require('ws');
var express = require('express');
var uuid = require('node-uuid');
var requests = {};
app = express();
var webSocket = new ws('ws://localhost:5000/');
webSocket.on('open', function () {
console.log('Connected!');
});
webSocket.on('message', function (data, flags) {
var json = JSON.parse(data);
console.log(json.requestId);
var res = requests[json.requestId];
res.setHeader('content-type', 'text/javascript');
res.send(json.data);
delete requests[json.requestId];
});
app.get('/', function (req, res) {
var rid = uuid.v4();
requests[rid] = res;
webSocket.send(JSON.stringify({query:'data query', requestId: rid}));
});
var server = app.listen(3000, function () {
var port = server.address().port
console.log('Listening at %s', port)
});

Resources