goldilocks.js/lib/tunnel.js

138 lines
3.8 KiB
JavaScript

'use strict';
module.exports.create = function (opts, servers) {
// servers = { plainserver, server }
var Oauth3 = require('oauth3-cli');
var Tunnel = require('daplie-tunnel').create({
Oauth3: Oauth3
, PromiseA: opts.PromiseA
, CLI: {
init: function (/*rs, ws, state, options*/) {
// noop
}
}
}).Tunnel;
var stunnel = require('stunnel');
var killcount = 0;
/*
var Dup = {
write: function (chunk, encoding, cb) {
this.__my_socket.push(chunk, encoding);
cb();
}
, read: function (size) {
var x = this.__my_socket.read(size);
if (x) { this.push(x); }
}
, setTimeout: function () {
console.log('TODO implement setTimeout on Duplex');
}
};
var httpServer = require('http').createServer(function (req, res) {
console.log('req.socket.encrypted', req.socket.encrypted);
res.end('Hello, tunneled World!');
});
var tlsServer = require('tls').createServer(opts.httpsOptions, function (tlsSocket) {
console.log('tls connection');
// things get a little messed up here
httpServer.emit('connection', tlsSocket);
// try again
//servers.server.emit('connection', tlsSocket);
});
*/
process.on('SIGINT', function () {
killcount += 1;
console.log('[quit] closing http and https servers');
if (killcount >= 3) {
process.exit(1);
}
if (servers.server) {
servers.server.close();
}
if (servers.insecureServer) {
servers.insecureServer.close();
}
});
return Tunnel.token({
refreshToken: opts.refreshToken
, email: opts.email
, domains: [ opts.servername ]
, device: { hostname: opts.devicename || opts.device }
}).then(function (result) {
// { jwt, tunnelUrl }
return stunnel.connect({
token: result.jwt
, stunneld: result.tunnelUrl
// XXX TODO BUG // this is just for testing
, insecure: /*opts.insecure*/ true
, locals: [
{ protocol: 'https'
, hostname: opts.servername
, port: opts.port
}
, { protocol: 'http'
, hostname: opts.servername
, port: opts.insecurePort || opts.port
}
]
// a simple passthru is proving to not be so simple
, net: require('net') /*
{
createConnection: function (info, cb) {
// data is the hello packet / first chunk
// info = { data, servername, port, host, remoteAddress: { family, address, port } }
var myDuplex = new (require('stream').Duplex)();
var myDuplex2 = new (require('stream').Duplex)();
// duplex = { write, push, end, events: [ 'readable', 'data', 'error', 'end' ] };
myDuplex2.__my_socket = myDuplex;
myDuplex.__my_socket = myDuplex2;
myDuplex2._write = Dup.write;
myDuplex2._read = Dup.read;
myDuplex._write = Dup.write;
myDuplex._read = Dup.read;
myDuplex.remoteFamily = info.remoteFamily;
myDuplex.remoteAddress = info.remoteAddress;
myDuplex.remotePort = info.remotePort;
// socket.local{Family,Address,Port}
myDuplex.localFamily = 'IPv4';
myDuplex.localAddress = '127.0.01';
myDuplex.localPort = info.port;
myDuplex.setTimeout = Dup.setTimeout;
// this doesn't seem to work so well
//servers.server.emit('connection', myDuplex);
// try a little more manual wrapping / unwrapping
var firstByte = info.data[0];
if (firstByte < 32 || firstByte >= 127) {
tlsServer.emit('connection', myDuplex);
}
else {
httpServer.emit('connection', myDuplex);
}
if (cb) {
process.nextTick(cb);
}
return myDuplex2;
}
}
//*/
});
});
};