making it work standalone again
This commit is contained in:
		
							parent
							
								
									5ce28e5f90
								
							
						
					
					
						commit
						9d2e89a1c7
					
				
							
								
								
									
										144
									
								
								lib/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										144
									
								
								lib/bootstrap.js
									
									
									
									
										vendored
									
									
								
							@ -12,18 +12,17 @@ module.exports.create = function (app, xconfx, models) {
 | 
			
		||||
  var fs = PromiseA.promisifyAll(require('fs'));
 | 
			
		||||
  var dns = PromiseA.promisifyAll(require('dns'));
 | 
			
		||||
 | 
			
		||||
  function isInitialized() {
 | 
			
		||||
  function isInitialized () {
 | 
			
		||||
    // TODO read from file only, not db
 | 
			
		||||
    return models.ComDaplieWalnutConfig.get('config').then(function (conf) {
 | 
			
		||||
      if (!conf || !conf.primaryDomain || !conf.primaryEmail) {
 | 
			
		||||
      if (!conf || !conf.primaryDomain/* || !conf.primaryEmail*/) {
 | 
			
		||||
        console.log('DEBUG incomplete conf', conf);
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      xconfx.primaryDomain = xconfx.primaryDomain || conf.primaryDomain;
 | 
			
		||||
 | 
			
		||||
      var configname = conf.primaryDomain + '.json';
 | 
			
		||||
      var configpath = path.join(__dirname, '..', '..', 'config', configname);
 | 
			
		||||
      var configpath = path.join(__dirname, '..', '..', 'config', conf.primaryDomain + '.json');
 | 
			
		||||
 | 
			
		||||
      return fs.readFileAsync(configpath, 'utf8').then(function (text) {
 | 
			
		||||
        return JSON.parse(text);
 | 
			
		||||
@ -31,11 +30,6 @@ module.exports.create = function (app, xconfx, models) {
 | 
			
		||||
        console.log('DEBUG not exists leconf', configpath);
 | 
			
		||||
        return false;
 | 
			
		||||
      }).then(function (data) {
 | 
			
		||||
        if (!data || !data.email || !data.agreeTos) {
 | 
			
		||||
          console.log('DEBUG incomplete leconf', data);
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
@ -44,7 +38,7 @@ module.exports.create = function (app, xconfx, models) {
 | 
			
		||||
  function initialize() {
 | 
			
		||||
    var express = require('express');
 | 
			
		||||
    var getIpAddresses = require('./ip-checker').getExternalAddresses;
 | 
			
		||||
    var resolve;
 | 
			
		||||
    var resolveInit;
 | 
			
		||||
 | 
			
		||||
    function errorIfNotApi(req, res, next) {
 | 
			
		||||
      var hostname = req.hostname || req.headers.host;
 | 
			
		||||
@ -142,106 +136,35 @@ module.exports.create = function (app, xconfx, models) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setConfig(req, res) {
 | 
			
		||||
      var config = req.body;
 | 
			
		||||
      var results = {};
 | 
			
		||||
 | 
			
		||||
      return PromiseA.resolve().then(function () {
 | 
			
		||||
        if (!config.agreeTos && !config.tls) {
 | 
			
		||||
          return PromiseA.reject(new Error("To enable encryption you must agree to the LetsEncrypt terms of service"));
 | 
			
		||||
        // TODO expect authenticated oauth3 user
 | 
			
		||||
        var config = req.body;
 | 
			
		||||
        var safeConfig = {};
 | 
			
		||||
 | 
			
		||||
        if ('string' !== typeof config.domain) {
 | 
			
		||||
          return PromiseA.reject(new Error("'domain' should be a string specifying a valid domain name"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!config.domain) {
 | 
			
		||||
          return PromiseA.reject(new Error("You must specify a valid domain name"));
 | 
			
		||||
        }
 | 
			
		||||
        config.domain = config.domain.replace(/^www\./, '');
 | 
			
		||||
        config.domain = (config.domain||'').replace(/^www\./, '');
 | 
			
		||||
 | 
			
		||||
        return getIpAddresses().then(function (inet) {
 | 
			
		||||
          if (!inet.addresses.length) {
 | 
			
		||||
            return PromiseA.reject(new Error("no ip addresses"));
 | 
			
		||||
        // TODO url-testing lib
 | 
			
		||||
        if (!/\w+\.\w+/.test(config.domain)) {
 | 
			
		||||
          return PromiseA.reject(new Error("'domain' should be a string specifying a valid domain name"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
          results.inets = inet.addresses.map(function (a) {
 | 
			
		||||
            a.time = undefined;
 | 
			
		||||
            return a;
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          results.resolutions = [];
 | 
			
		||||
          return PromiseA.all([
 | 
			
		||||
            // for static content
 | 
			
		||||
            verifyIps(inet.addresses, config.domain).then(function (ips) {
 | 
			
		||||
              results.resolutions.push({ hostname: config.domain, ips: ips });
 | 
			
		||||
            })
 | 
			
		||||
            // for redirects
 | 
			
		||||
          , verifyIps(inet.addresses, 'www.' + config.domain).then(function (ips) {
 | 
			
		||||
              results.resolutions.push({ hostname: 'www.' + config.domain, ips: ips });
 | 
			
		||||
            })
 | 
			
		||||
            // for api
 | 
			
		||||
          , verifyIps(inet.addresses, 'api.' + config.domain).then(function (ips) {
 | 
			
		||||
              results.resolutions.push({ hostname: 'api.' + config.domain, ips: ips });
 | 
			
		||||
            })
 | 
			
		||||
            // for protected assets
 | 
			
		||||
          , verifyIps(inet.addresses, 'assets.' + config.domain).then(function (ips) {
 | 
			
		||||
              results.resolutions.push({ hostname: 'assets.' + config.domain, ips: ips });
 | 
			
		||||
            })
 | 
			
		||||
            // for the cloud management
 | 
			
		||||
          , verifyIps(inet.addresses, 'cloud.' + config.domain).then(function (ips) {
 | 
			
		||||
              results.resolutions.push({ hostname: 'cloud.' + config.domain, ips: ips });
 | 
			
		||||
            })
 | 
			
		||||
          , verifyIps(inet.addresses, 'api.cloud.' + config.domain).then(function (ips) {
 | 
			
		||||
              results.resolutions.push({ hostname: 'api.cloud.' + config.domain, ips: ips });
 | 
			
		||||
            })
 | 
			
		||||
          ]).then(function () {
 | 
			
		||||
            if (!results.resolutions[0].ips.length) {
 | 
			
		||||
              results.error = { message: "bare domain could not be resolved to this device" };
 | 
			
		||||
            }
 | 
			
		||||
            else if (!results.resolutions[2].ips.length) {
 | 
			
		||||
              results.error = { message: "api subdomain could not be resolved to this device" };
 | 
			
		||||
            }
 | 
			
		||||
            /*
 | 
			
		||||
            else if (!results.resolutions[1].ips.length) {
 | 
			
		||||
              results.error = { message: "" }
 | 
			
		||||
            }
 | 
			
		||||
            else if (!results.resolutions[3].ips.length) {
 | 
			
		||||
              results.error = { message: "" }
 | 
			
		||||
            }
 | 
			
		||||
            else if (!results.resolutions[4].ips.length || !results.resolutions[4].ips.length) {
 | 
			
		||||
              results.error = { message: "cloud and api.cloud subdomains should be set up" };
 | 
			
		||||
            }
 | 
			
		||||
            */
 | 
			
		||||
          });
 | 
			
		||||
        var configpath = path.join(__dirname, '..', '..', 'config', config.domain + '.json');
 | 
			
		||||
        safeConfig = { primaryDomain: config.domain };
 | 
			
		||||
        return fs.writeFileAsync(configpath, JSON.stringify(safeConfig, null, '  '), 'utf8').then(function () {
 | 
			
		||||
          // TODO nix SQL
 | 
			
		||||
          return models.ComDaplieWalnutConfig.upsert('config', safeConfig);
 | 
			
		||||
        });
 | 
			
		||||
      }).then(function () {
 | 
			
		||||
        if (results.error) {
 | 
			
		||||
          return;
 | 
			
		||||
        if (resolveInit) {
 | 
			
		||||
          resolveInit();
 | 
			
		||||
          resolveInit = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var configname = config.domain + '.json';
 | 
			
		||||
        var configpath = path.join(__dirname, '..', '..', 'config', configname);
 | 
			
		||||
        var leAuth = {
 | 
			
		||||
          agreeTos: true
 | 
			
		||||
        , email: config.email // TODO check email
 | 
			
		||||
        , domain: config.domain
 | 
			
		||||
        , createdAt: Date.now()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return dns.resolveMxAsync(config.email.replace(/.*@/, '')).then(function (/*addrs*/) {
 | 
			
		||||
          // TODO allow private key to be uploaded
 | 
			
		||||
          return fs.writeFileAsync(configpath, JSON.stringify(leAuth, null, '  '), 'utf8').then(function () {
 | 
			
		||||
            return models.ComDaplieWalnutConfig.upsert('config', {
 | 
			
		||||
              letsencrypt: leAuth
 | 
			
		||||
            , primaryDomain: config.domain
 | 
			
		||||
            , primaryEmail: config.email
 | 
			
		||||
            });
 | 
			
		||||
          });
 | 
			
		||||
        }, function () {
 | 
			
		||||
          return PromiseA.reject(new Error("invalid email address (MX record lookup failed)"));
 | 
			
		||||
        });
 | 
			
		||||
      }).then(function () {
 | 
			
		||||
        if (!results.error && results.inets && resolve) {
 | 
			
		||||
          resolve();
 | 
			
		||||
          resolve = null;
 | 
			
		||||
        }
 | 
			
		||||
        res.send(results);
 | 
			
		||||
        res.send({ success: true });
 | 
			
		||||
      }, function (err) {
 | 
			
		||||
        console.error('Error lib/bootstrap.js');
 | 
			
		||||
        console.error(err.stack || err);
 | 
			
		||||
@ -259,19 +182,21 @@ module.exports.create = function (app, xconfx, models) {
 | 
			
		||||
    ], methods: [ "GET", "POST", "PATCH", "PUT", "DELETE" ] });
 | 
			
		||||
 | 
			
		||||
    app.use('/', function (req, res, next) {
 | 
			
		||||
      console.log('[lib/bootstrap.js] req.url', req.url);
 | 
			
		||||
 | 
			
		||||
      return isInitialized().then(function (initialized) {
 | 
			
		||||
        if (!initialized) {
 | 
			
		||||
          next();
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        resolve(true);
 | 
			
		||||
        // init is always considered to be 
 | 
			
		||||
        resolveInit(true);
 | 
			
		||||
 | 
			
		||||
        // force page refresh
 | 
			
		||||
        // TODO goto top of routes?
 | 
			
		||||
        // TODO feed this request back through the route stack from the top to avoid forced refresh?
 | 
			
		||||
        res.statusCode = 302;
 | 
			
		||||
        res.setHeader('Location', req.url);
 | 
			
		||||
        res.end();
 | 
			
		||||
        res.end("<!-- App bootstraping complete, but you got here somehow anyway. Let's redirect you so you get to the main app. -->");
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    app.use('/api', errorIfNotApi);
 | 
			
		||||
@ -283,10 +208,17 @@ module.exports.create = function (app, xconfx, models) {
 | 
			
		||||
    app.get('/api/com.daplie.walnut.init', getConfig);
 | 
			
		||||
    app.post('/api/com.daplie.walnut.init', setConfig);
 | 
			
		||||
    app.use('/', errorIfApi);
 | 
			
		||||
    app.use('/', express.static(path.join(__dirname, '..', '..', 'packages', 'pages', 'com.daplie.walnut.init')));
 | 
			
		||||
 | 
			
		||||
    // TODO use package loader
 | 
			
		||||
    //app.use('/', express.static(path.join(__dirname, '..', '..', 'packages', 'pages', 'com.daplie.walnut.init')));
 | 
			
		||||
    app.use('/', express.static(path.join(__dirname, 'com.daplie.walnut.init')));
 | 
			
		||||
    app.use('/', function (req, res, next) {
 | 
			
		||||
      res.statusCode = 404;
 | 
			
		||||
      res.end('Walnut Bootstrap Not Found. Mising com.daplie.walnut.init');
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return new PromiseA(function (_resolve) {
 | 
			
		||||
      resolve = _resolve;
 | 
			
		||||
      resolveInit = _resolve;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -157,15 +157,23 @@ module.exports.create = function (webserver, xconfx, state) {
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          var hostsmap = {};
 | 
			
		||||
 | 
			
		||||
          function log(req, res, next) {
 | 
			
		||||
            var hostname = (req.hostname || req.headers.host || '').split(':').shift();
 | 
			
		||||
 | 
			
		||||
            // Printing all incoming requests for debugging
 | 
			
		||||
            console.log('[worker/log]', req.method, hostname, req.url);
 | 
			
		||||
 | 
			
		||||
	    // logging all the invalid hostnames that come here out of curiousity
 | 
			
		||||
            if (hostname && !hostsmap[hostname]) {
 | 
			
		||||
              hostsmap[hostname] = true;
 | 
			
		||||
              require('fs').writeFile(
 | 
			
		||||
                require('path').join(__dirname, '..', '..', 'var', 'hostnames', hostname)
 | 
			
		||||
              , hostname, function () {});
 | 
			
		||||
              , hostname
 | 
			
		||||
              , function () {}
 | 
			
		||||
              );
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            next();
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
@ -217,6 +225,7 @@ module.exports.create = function (webserver, xconfx, state) {
 | 
			
		||||
                require('./unbrick-appcache').unbrick(req, res);
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
              console.log('[lib/worker] unencrypted:', req.headers);
 | 
			
		||||
              res.end("Connection is not encrypted. That's no bueno or, as we say in Hungarian, nem szabad!");
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user