125 lines
3.6 KiB
JavaScript
125 lines
3.6 KiB
JavaScript
'use strict';
|
|
|
|
var https = require('https');
|
|
var path = require('path');
|
|
var fs = require('fs');
|
|
var PromiseA = global.Promise || require('bluebird').Promise;
|
|
|
|
exports.create = function (ip, localPort, externalPort) {
|
|
return new PromiseA(function (resolve, reject) {
|
|
var token = Math.random().toString(16).split('.')[1];
|
|
var tokenPath = Math.random().toString(16).split('.')[1];
|
|
var options;
|
|
var server;
|
|
var options;
|
|
var certsPath = path.join(__dirname, 'certs', 'server');
|
|
var caCertsPath = path.join(__dirname, 'certs', 'ca');
|
|
|
|
|
|
function testConnection() {
|
|
var awesome = false;
|
|
var timetok;
|
|
var webreq;
|
|
var options = {
|
|
// not hostname because we set headers.host on our own
|
|
host: ip
|
|
, headers: {
|
|
// whatever's on the fake cert
|
|
'Host': 'redirect-www.org'
|
|
}
|
|
, port: externalPort
|
|
, path: '/' + tokenPath
|
|
, ca: fs.readFileSync(path.join(caCertsPath, 'my-root-ca.crt.pem'))
|
|
};
|
|
options.agent = new https.Agent(options);
|
|
|
|
timetok = setTimeout(function () {
|
|
reject(new Error("timed out while testing NAT loopback for port " + externalPort));
|
|
}, 2000);
|
|
|
|
function finishHim(err) {
|
|
clearTimeout(timetok);
|
|
server.close(function () {
|
|
if (!err && awesome) {
|
|
resolve();
|
|
}
|
|
});
|
|
|
|
if (err || !awesome) {
|
|
if (err) {
|
|
reject(err);
|
|
}
|
|
else if (!awesome) {
|
|
reject(new Error("loopback failed. Why? here's my best guess: "
|
|
+ "the ssl cert matched, so you've probably got two boxes and this isn't the right one"));
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
webreq = https.request(options, function(res) {
|
|
res.on('data', function (resToken) {
|
|
if (resToken.toString() === token) {
|
|
awesome = true;
|
|
return;
|
|
}
|
|
});
|
|
res.on('error', function (err) {
|
|
console.error('[ERROR] https.request.response');
|
|
console.error(err);
|
|
finishHim(new Error("loopback failed. Why? here's my best guess: "
|
|
+ "the connection was interrupted"));
|
|
});
|
|
res.on('end', function () {
|
|
finishHim();
|
|
});
|
|
});
|
|
|
|
webreq.on('error', function (err) {
|
|
console.error('[ERROR] https.request');
|
|
console.error(err);
|
|
if (/ssl|cert|chain/i.test(err.message || err.toString())) {
|
|
finishHim(new Error("loopback failed. Why? here's my best guess: "
|
|
+ "the ssl cert validation may have failed (might port-forward to the wrong box)"));
|
|
} else {
|
|
finishHim(new Error("loopback failed. Why? here's my best guess: "
|
|
+ "port forwarding isn't configured for " + ip + ":" + externalPort + " to " + localPort));
|
|
}
|
|
});
|
|
webreq.end();
|
|
}
|
|
|
|
//
|
|
// SSL Certificates
|
|
//
|
|
options = {
|
|
key: fs.readFileSync(path.join(certsPath, 'my-server.key.pem'))
|
|
, ca: [ fs.readFileSync(path.join(caCertsPath, 'my-root-ca.crt.pem')) ]
|
|
, cert: fs.readFileSync(path.join(certsPath, 'my-server.crt.pem'))
|
|
, requestCert: false
|
|
, rejectUnauthorized: false
|
|
};
|
|
|
|
//
|
|
// Serve an Express App securely with HTTPS
|
|
//
|
|
server = https.createServer(options);
|
|
function listen(app) {
|
|
server.on('request', app);
|
|
server.listen(localPort, function () {
|
|
localPort = server.address().port;
|
|
setTimeout(testConnection, 2000);
|
|
});
|
|
}
|
|
|
|
listen(function (req, res) {
|
|
if (('/' + tokenPath) === req.url) {
|
|
res.end(token);
|
|
return;
|
|
}
|
|
|
|
res.end('loopback failure');
|
|
});
|
|
});
|
|
};
|