one step closer to the edge, but without the break
This commit is contained in:
		
							parent
							
								
									d3022c246e
								
							
						
					
					
						commit
						7db2f0f703
					
				@ -36,7 +36,7 @@ for convenience.
 | 
			
		||||
You can customize the installation:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
export NODEJS_VER=v8.11.1
 | 
			
		||||
export NODEJS_VER=v8.11.2
 | 
			
		||||
export TELEBITD_PATH=/opt/telebitd
 | 
			
		||||
curl -fsS https://get.telebit.cloud/ | bash
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										130
									
								
								bin/telebitd.js
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								bin/telebitd.js
									
									
									
									
									
								
							@ -6,7 +6,7 @@ var pkg = require('../package.json');
 | 
			
		||||
 | 
			
		||||
var argv = process.argv.slice(2);
 | 
			
		||||
var telebitd = require('../telebitd.js');
 | 
			
		||||
var greenlock = require('greenlock');
 | 
			
		||||
var Greenlock = require('greenlock');
 | 
			
		||||
 | 
			
		||||
var confIndex = argv.indexOf('--config');
 | 
			
		||||
var confpath;
 | 
			
		||||
@ -55,6 +55,80 @@ function applyConfig(config) {
 | 
			
		||||
    console.info("");
 | 
			
		||||
    console.info("");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function approveDomains(opts, certs, cb) {
 | 
			
		||||
    console.log('[debug] approveDomains', opts.domains);
 | 
			
		||||
    // This is where you check your database and associated
 | 
			
		||||
    // email addresses with domains and agreements and such
 | 
			
		||||
 | 
			
		||||
    // The domains being approved for the first time are listed in opts.domains
 | 
			
		||||
    // Certs being renewed are listed in certs.altnames
 | 
			
		||||
    if (certs) {
 | 
			
		||||
      opts.domains = certs.altnames;
 | 
			
		||||
      cb(null, { options: opts, certs: certs });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (state.config.vhost) {
 | 
			
		||||
      console.log('[sni] vhost checking is turned on');
 | 
			
		||||
      var vhost = state.config.vhost.replace(/:hostname/, opts.domains[0]);
 | 
			
		||||
      require('fs').readdir(vhost, function (err, nodes) {
 | 
			
		||||
        console.log('[sni] checking fs vhost');
 | 
			
		||||
        if (err) { check(); return; } 
 | 
			
		||||
        if (nodes) { approve(); }
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function approve() {
 | 
			
		||||
      opts.email = state.config.email;
 | 
			
		||||
      opts.agreeTos = state.config.agreeTos;
 | 
			
		||||
      opts.challenges = {
 | 
			
		||||
        // TODO dns-01
 | 
			
		||||
        'http-01': require('le-challenge-fs').create({ webrootPath: '/tmp/acme-challenges' })
 | 
			
		||||
      };
 | 
			
		||||
      opts.communityMember = state.config.communityMember;
 | 
			
		||||
      cb(null, { options: opts, certs: certs });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function check() {
 | 
			
		||||
      console.log('[sni] checking servername');
 | 
			
		||||
      if (-1 !== state.servernames.indexOf(opts.domain) || -1 !== (state._servernames||[]).indexOf(opts.domain)) {
 | 
			
		||||
        approve();
 | 
			
		||||
      } else {
 | 
			
		||||
        cb(new Error("failed the approval chain '" + opts.domains[0] + "'"));
 | 
			
		||||
      }
 | 
			
		||||
      console.log('Approve Domains cb');
 | 
			
		||||
    }
 | 
			
		||||
    check();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  if (!config.email || !config.agreeTos) {
 | 
			
		||||
    console.error("You didn't specify --email <EMAIL> and --agree-tos");
 | 
			
		||||
    console.error("(required for ACME / Let's Encrypt / Greenlock TLS/SSL certs)");
 | 
			
		||||
    console.error("");
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
  }
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
  state.greenlock = Greenlock.create({
 | 
			
		||||
 | 
			
		||||
    version: 'draft-11'
 | 
			
		||||
  , server: 'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
  //, server: 'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
			
		||||
 | 
			
		||||
  , store: require('le-store-certbot').create({ debug: true, webrootPath: '/tmp/acme-challenges' })
 | 
			
		||||
 | 
			
		||||
  , approveDomains: approveDomains
 | 
			
		||||
 | 
			
		||||
  , configDir: '/root/acme'
 | 
			
		||||
  , debug: true
 | 
			
		||||
 | 
			
		||||
  //, approvedDomains: program.servernames
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  require('../handlers').create(state); // adds directly to config for now...
 | 
			
		||||
 | 
			
		||||
  //require('cluster-store').create().then(function (store) {
 | 
			
		||||
@ -77,60 +151,6 @@ function applyConfig(config) {
 | 
			
		||||
      state.tcp[port].on('connection', netConnHandlers.tcp);
 | 
			
		||||
    });
 | 
			
		||||
  //});
 | 
			
		||||
 | 
			
		||||
  function approveDomains(opts, certs, cb) {
 | 
			
		||||
    console.log('Approve Domains', opts.domains);
 | 
			
		||||
    // This is where you check your database and associated
 | 
			
		||||
    // email addresses with domains and agreements and such
 | 
			
		||||
 | 
			
		||||
    // The domains being approved for the first time are listed in opts.domains
 | 
			
		||||
    // Certs being renewed are listed in certs.altnames
 | 
			
		||||
    if (certs) {
 | 
			
		||||
      opts.domains = certs.altnames;
 | 
			
		||||
    } else {
 | 
			
		||||
      if (-1 !== state.servernames.indexOf(opts.domain) || -1 !== (state._servernames||[]).indexOf(opts.domain)) {
 | 
			
		||||
        opts.email = state.config.email;
 | 
			
		||||
        opts.agreeTos = state.config.agreeTos;
 | 
			
		||||
        opts.challenges = {
 | 
			
		||||
          // TODO dns-01
 | 
			
		||||
          'http-01': require('le-challenge-fs').create({ webrootPath: '/tmp/acme-challenges' })
 | 
			
		||||
        };
 | 
			
		||||
        opts.communityMember = state.config.communityMember;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // NOTE: you can also change other options such as `challengeType` and `challenge`
 | 
			
		||||
    // opts.challengeType = 'http-01';
 | 
			
		||||
    // opts.challenge = require('le-challenge-fs').create({});
 | 
			
		||||
 | 
			
		||||
    console.log('Approve Domains cb');
 | 
			
		||||
    cb(null, { options: opts, certs: certs });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  if (!config.email || !config.agreeTos) {
 | 
			
		||||
    console.error("You didn't specify --email <EMAIL> and --agree-tos");
 | 
			
		||||
    console.error("(required for ACME / Let's Encrypt / Greenlock TLS/SSL certs)");
 | 
			
		||||
    console.error("");
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
  }
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
  state.greenlock = greenlock.create({
 | 
			
		||||
 | 
			
		||||
    version: 'draft-11'
 | 
			
		||||
  , server: 'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
			
		||||
 | 
			
		||||
  , store: require('le-store-certbot').create({ debug: true, webrootPath: '/tmp/acme-challenges' })
 | 
			
		||||
 | 
			
		||||
  , approveDomains: approveDomains
 | 
			
		||||
 | 
			
		||||
  , configDir: '/root/acme'
 | 
			
		||||
  , debug: true
 | 
			
		||||
 | 
			
		||||
  //, approvedDomains: program.servernames
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require('fs').readFile(confpath, 'utf8', function (err, text) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										80
									
								
								handlers.js
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								handlers.js
									
									
									
									
									
								
							@ -5,6 +5,14 @@ var tls = require('tls');
 | 
			
		||||
var wrapSocket = require('tunnel-packer').wrapSocket;
 | 
			
		||||
var redirectHttps = require('redirect-https')();
 | 
			
		||||
 | 
			
		||||
function noSniCallback(tag) {
 | 
			
		||||
  return function _noSniCallback(servername, cb) {
 | 
			
		||||
    var err = new Error("[noSniCallback] no handler set for '" + tag + "':'" + servername + "'");
 | 
			
		||||
    console.error(err.message);
 | 
			
		||||
    cb(new Error(err));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.create = function (state) {
 | 
			
		||||
  var tunnelAdminTlsOpts = {};
 | 
			
		||||
  var setupSniCallback;
 | 
			
		||||
@ -62,6 +70,9 @@ module.exports.create = function (state) {
 | 
			
		||||
    // things get a little messed up here
 | 
			
		||||
    state.httpInvalidSniServer.emit('connection', tlsSocket);
 | 
			
		||||
  });
 | 
			
		||||
  state.tlsInvalidSniServer.on('tlsClientError', function () {
 | 
			
		||||
    console.error('tlsClientError InvalidSniServer');
 | 
			
		||||
  });
 | 
			
		||||
  state.httpsInvalid = function (servername, socket) {
 | 
			
		||||
    // none of these methods work:
 | 
			
		||||
    // httpsServer.emit('connection', socket);  // this didn't work
 | 
			
		||||
@ -95,6 +106,9 @@ module.exports.create = function (state) {
 | 
			
		||||
      });
 | 
			
		||||
      httpInvalidSniServer.emit('connection', tlsSocket);
 | 
			
		||||
    });
 | 
			
		||||
    tlsInvalidSniServer.on('tlsClientError', function () {
 | 
			
		||||
      console.error('tlsClientError InvalidSniServer httpsInvalid');
 | 
			
		||||
    });
 | 
			
		||||
    tlsInvalidSniServer.emit('connection', wrapSocket(socket));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
@ -110,15 +124,24 @@ module.exports.create = function (state) {
 | 
			
		||||
  Object.keys(state.tlsOptions).forEach(function (key) {
 | 
			
		||||
    tunnelAdminTlsOpts[key] = state.tlsOptions[key];
 | 
			
		||||
  });
 | 
			
		||||
  tunnelAdminTlsOpts.SNICallback = (state.greenlock && state.greenlock.tlsOptions && function (servername, cb) {
 | 
			
		||||
    console.log("time to handle '" + servername + "'");
 | 
			
		||||
    state.greenlock.tlsOptions.SNICallback(servername, cb);
 | 
			
		||||
  }) || tunnelAdminTlsOpts.SNICallback;
 | 
			
		||||
  if (state.greenlock && state.greenlock.tlsOptions) {
 | 
			
		||||
    console.log('greenlock tlsOptions for SNICallback');
 | 
			
		||||
    tunnelAdminTlsOpts.SNICallback = function (servername, cb) {
 | 
			
		||||
      console.log("time to handle '" + servername + "'");
 | 
			
		||||
      state.greenlock.tlsOptions.SNICallback(servername, cb);
 | 
			
		||||
    };
 | 
			
		||||
  } else {
 | 
			
		||||
    console.log('custom or null tlsOptions for SNICallback');
 | 
			
		||||
    tunnelAdminTlsOpts.SNICallback = tunnelAdminTlsOpts.SNICallback || noSniCallback('admin');
 | 
			
		||||
  }
 | 
			
		||||
  state.tlsTunnelServer = tls.createServer(tunnelAdminTlsOpts, function (tlsSocket) {
 | 
			
		||||
    console.log('tls connection');
 | 
			
		||||
    console.log('(Admin) tls connection');
 | 
			
		||||
    // things get a little messed up here
 | 
			
		||||
    (state.httpTunnelServer || state.httpServer).emit('connection', tlsSocket);
 | 
			
		||||
  });
 | 
			
		||||
  state.tlsTunnelServer.on('tlsClientError', function () {
 | 
			
		||||
    console.error('tlsClientError TunnelServer client error');
 | 
			
		||||
  });
 | 
			
		||||
  state.httpsTunnel = function (servername, socket) {
 | 
			
		||||
    // none of these methods work:
 | 
			
		||||
    // httpsServer.emit('connection', socket);  // this didn't work
 | 
			
		||||
@ -152,11 +175,54 @@ module.exports.create = function (state) {
 | 
			
		||||
    // things get a little messed up here
 | 
			
		||||
    state.httpSetupServer.emit('connection', tlsSocket);
 | 
			
		||||
  });
 | 
			
		||||
  state.tlsSetupServer.on('tlsClientError', function () {
 | 
			
		||||
    console.error('tlsClientError SetupServer');
 | 
			
		||||
  });
 | 
			
		||||
  state.httpsSetupServer = function (servername, socket) {
 | 
			
		||||
    console.log('httpsTunnel (Admin) servername', servername);
 | 
			
		||||
    console.log('httpsTunnel (Setup) servername', servername);
 | 
			
		||||
    state._servernames = [servername];
 | 
			
		||||
    state.config.agreeTos = true; // TODO: BUG XXX BAD, make user accept
 | 
			
		||||
    setupSniCallback = state.greenlock.tlsOptions.SNICallback;
 | 
			
		||||
    setupSniCallback = state.greenlock.tlsOptions.SNICallback || noSniCallback('setup');
 | 
			
		||||
    state.tlsSetupServer.emit('connection', wrapSocket(socket));
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // vhost
 | 
			
		||||
  //
 | 
			
		||||
  state.httpVhost = http.createServer(function (req, res) {
 | 
			
		||||
    console.log('httpVhost (local)');
 | 
			
		||||
    console.log('req.socket.encrypted', req.socket.encrypted);
 | 
			
		||||
 | 
			
		||||
    var finalhandler = require('finalhandler');
 | 
			
		||||
    // TODO compare SNI to hostname?
 | 
			
		||||
    var host = (req.headers.host||'').toLowerCase().trim();
 | 
			
		||||
    var serveSetup = require('serve-static')(state.config.vhost.replace(/:hostname/g, host), { redirect: true });
 | 
			
		||||
 | 
			
		||||
    if (req.socket.encrypted) { serveSetup(req, res, finalhandler(req, res)); return; }
 | 
			
		||||
 | 
			
		||||
    console.log('try greenlock middleware for vhost');
 | 
			
		||||
    (state.greenlock && state.greenlock.middleware(redirectHttpsAndClose)
 | 
			
		||||
      || redirectHttpsAndClose)(req, res, function () {
 | 
			
		||||
      console.log('fallthrough to vhost serving???');
 | 
			
		||||
      serveSetup(req, res, finalhandler(req, res));
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  state.tlsVhost = tls.createServer(
 | 
			
		||||
    { SNICallback: function (servername, cb) {
 | 
			
		||||
        console.log('tlsVhost debug SNICallback', servername);
 | 
			
		||||
        tunnelAdminTlsOpts.SNICallback(servername, cb);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  , function (tlsSocket) {
 | 
			
		||||
      console.log('tlsVhost (local)');
 | 
			
		||||
      state.httpVhost.emit('connection', tlsSocket);
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
  state.tlsVhost.on('tlsClientError', function () {
 | 
			
		||||
    console.error('tlsClientError Vhost');
 | 
			
		||||
  });
 | 
			
		||||
  state.httpsVhost = function (servername, socket) {
 | 
			
		||||
    console.log('httpsVhost (local)', servername);
 | 
			
		||||
    state.tlsVhost.emit('connection', wrapSocket(socket));
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -80,6 +80,10 @@ module.exports.createTcpConnectionHandler = function (copts) {
 | 
			
		||||
      var m;
 | 
			
		||||
 | 
			
		||||
      function tryTls() {
 | 
			
		||||
        var vhost;
 | 
			
		||||
 | 
			
		||||
        console.log("");
 | 
			
		||||
 | 
			
		||||
        if (!copts.servernames.length) {
 | 
			
		||||
          console.log("https => admin => setup => (needs bogus tls certs to start?)");
 | 
			
		||||
          copts.httpsSetupServer(servername, conn);
 | 
			
		||||
@ -92,21 +96,44 @@ module.exports.createTcpConnectionHandler = function (copts) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!servername) {
 | 
			
		||||
          console.log("No SNI was given, so there's nothing we can do here");
 | 
			
		||||
          copts.httpsInvalid(servername, conn);
 | 
			
		||||
        if (copts.config.nowww && /^www\./i.test(servername)) {
 | 
			
		||||
          console.log("TODO: use www bare redirect");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function run() {
 | 
			
		||||
          if (!servername) {
 | 
			
		||||
            console.log("No SNI was given, so there's nothing we can do here");
 | 
			
		||||
            copts.httpsInvalid(servername, conn);
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          var nextDevice = Devices.next(copts.deviceLists, servername);
 | 
			
		||||
          if (!nextDevice) {
 | 
			
		||||
            console.log("No devices match the given servername");
 | 
			
		||||
            copts.httpsInvalid(servername, conn);
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          console.log("pipeWs(servername, service, socket, deviceLists['" + servername + "'])");
 | 
			
		||||
          pipeWs(servername, service, conn, nextDevice);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (copts.config.vhost) {
 | 
			
		||||
          console.log("VHOST path", copts.config.vhost);
 | 
			
		||||
          vhost = copts.config.vhost.replace(/:hostname/, (servername||''));
 | 
			
		||||
          console.log("VHOST name", vhost);
 | 
			
		||||
          conn.pause();
 | 
			
		||||
          //copts.httpsVhost(servername, conn); 
 | 
			
		||||
          //return;
 | 
			
		||||
          require('fs').readdir(vhost, function (err, nodes) {
 | 
			
		||||
            console.log("VHOST error?", err);
 | 
			
		||||
            if (err) { run(); return; } 
 | 
			
		||||
            if (nodes) { copts.httpsVhost(servername, conn); }
 | 
			
		||||
          });
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var nextDevice = Devices.next(copts.deviceLists, servername);
 | 
			
		||||
        if (!nextDevice) {
 | 
			
		||||
          console.log("No devices match the given servername");
 | 
			
		||||
          copts.httpsInvalid(servername, conn);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        console.log("pipeWs(servername, service, socket, deviceLists['" + servername + "'])");
 | 
			
		||||
        pipeWs(servername, service, conn, nextDevice);
 | 
			
		||||
        run();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // https://github.com/mscdex/httpolyglot/issues/3#issuecomment-173680155
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user