208 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
 | 
						|
//
 | 
						|
// IMPORTANT !!!
 | 
						|
//
 | 
						|
// None of this is authenticated or encrypted
 | 
						|
//
 | 
						|
 | 
						|
module.exports.create = function (app, xconfx, models) {
 | 
						|
  var PromiseA = require('bluebird');
 | 
						|
  var path = require('path');
 | 
						|
  var fs = PromiseA.promisifyAll(require('fs'));
 | 
						|
  var dns = PromiseA.promisifyAll(require('dns'));
 | 
						|
 | 
						|
  function isInitialized () {
 | 
						|
    // TODO read from file only, not db
 | 
						|
    return models.ComDaplieWalnutConfig.get('config').then(function (conf) {
 | 
						|
      if (!conf || !conf.primaryDomain/* || !conf.primaryEmail*/) {
 | 
						|
        console.log('[DEBUG] uninitialized or incomplete config:', JSON.stringify(conf));
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      xconfx.primaryDomain = xconfx.primaryDomain || conf.primaryDomain;
 | 
						|
 | 
						|
      var configpath = path.join(__dirname, '..', '..', 'config', conf.primaryDomain + '.json');
 | 
						|
 | 
						|
      return fs.readFileAsync(configpath, 'utf8').then(function (text) {
 | 
						|
        return JSON.parse(text);
 | 
						|
      }, function (/*err*/) {
 | 
						|
        console.log('DEBUG not exists leconf', configpath);
 | 
						|
        return false;
 | 
						|
      }).then(function (data) {
 | 
						|
        return true;
 | 
						|
      });
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  function initialize() {
 | 
						|
    var express = require('express');
 | 
						|
    var getIpAddresses = require('./ip-checker').getExternalAddresses;
 | 
						|
    var resolveInit;
 | 
						|
 | 
						|
    function getConfig(req, res) {
 | 
						|
      getIpAddresses().then(function (inets) {
 | 
						|
        var results = {
 | 
						|
          hostname: require('os').hostname()
 | 
						|
        , inets: inets.addresses.map(function (a) {
 | 
						|
            a.time = undefined;
 | 
						|
            return a;
 | 
						|
          })
 | 
						|
        };
 | 
						|
        //res.send({ inets: require('os').networkInterfaces() });
 | 
						|
        res.send(results);
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    function verifyIps(inets, hostname) {
 | 
						|
      var map = {};
 | 
						|
      var arr = [];
 | 
						|
 | 
						|
      inets.forEach(function (addr) {
 | 
						|
        if (!map[addr.family]) {
 | 
						|
          map[addr.family] = true;
 | 
						|
          if (4 === addr.family) {
 | 
						|
            arr.push(dns.resolve4Async(hostname).then(function (arr) {
 | 
						|
              return arr;
 | 
						|
            }, function (/*err*/) {
 | 
						|
              return [];
 | 
						|
            }));
 | 
						|
          }
 | 
						|
          if (6 === addr.family) {
 | 
						|
            arr.push(dns.resolve6Async(hostname).then(function (arr) {
 | 
						|
              return arr;
 | 
						|
            }, function (/*err*/) {
 | 
						|
              return [];
 | 
						|
            }));
 | 
						|
          }
 | 
						|
        }
 | 
						|
      });
 | 
						|
 | 
						|
      return PromiseA.all(arr).then(function (fams) {
 | 
						|
        console.log('DEBUG hostname', hostname);
 | 
						|
        var ips = [];
 | 
						|
 | 
						|
        fams.forEach(function (addrs) {
 | 
						|
          console.log('DEBUG ipv46');
 | 
						|
          console.log(addrs);
 | 
						|
          addrs.forEach(function (addr) {
 | 
						|
            inets.forEach(function (a) {
 | 
						|
              if (a.address === addr) {
 | 
						|
                a.time = undefined;
 | 
						|
                ips.push(a);
 | 
						|
              }
 | 
						|
            });
 | 
						|
          });
 | 
						|
          console.log('');
 | 
						|
        });
 | 
						|
 | 
						|
        return ips;
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    function setConfig(req, res) {
 | 
						|
      return PromiseA.resolve().then(function () {
 | 
						|
        // 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"));
 | 
						|
        }
 | 
						|
 | 
						|
        config.domain = (config.domain||'').replace(/^www\./, '');
 | 
						|
 | 
						|
        // 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"));
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        var configpath = path.join(__dirname, '..', '..', 'config', config.domain + '.json');
 | 
						|
        safeConfig = { primaryDomain: config.domain };
 | 
						|
        xconfx.primaryDomain = safeConfig.primaryDomain;
 | 
						|
        return fs.writeFileAsync(configpath, JSON.stringify(safeConfig, null, '  '), 'utf8').then(function () {
 | 
						|
          // TODO nix SQL
 | 
						|
          return models.ComDaplieWalnutConfig.upsert('config', safeConfig);
 | 
						|
        });
 | 
						|
      }).then(function () {
 | 
						|
        if (resolveInit) {
 | 
						|
          resolveInit();
 | 
						|
          resolveInit = null;
 | 
						|
        }
 | 
						|
        res.send({ success: true });
 | 
						|
      }, function (err) {
 | 
						|
        console.error('Error lib/bootstrap.js');
 | 
						|
        console.error(err.stack || err);
 | 
						|
        res.send({ error: { message: err.message || err.toString() } });
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    var CORS = require('connect-cors');
 | 
						|
    var cors = CORS({ credentials: true, headers: [
 | 
						|
      'X-Requested-With'
 | 
						|
    , 'X-HTTP-Method-Override'
 | 
						|
    , 'Content-Type'
 | 
						|
    , 'Accept'
 | 
						|
    , 'Authorization'
 | 
						|
    ], 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;
 | 
						|
        }
 | 
						|
 | 
						|
        // init is always considered to be
 | 
						|
        resolveInit(true);
 | 
						|
 | 
						|
        // 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("<!-- App bootstraping complete, but you got here somehow anyway. Let's redirect you so you get to the main app. -->");
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    // NOTE Allows CORS access to API with ?access_token=
 | 
						|
    // TODO Access-Control-Max-Age: 600
 | 
						|
    // TODO How can we help apps handle this? token?
 | 
						|
    // TODO allow apps to configure trustedDomains, auth, etc
 | 
						|
    app.use('/api', cors);
 | 
						|
    app.get('/api/com.daplie.walnut.init', getConfig);
 | 
						|
    app.post('/api/com.daplie.walnut.init', setConfig);
 | 
						|
 | 
						|
    // 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) {
 | 
						|
      resolveInit = _resolve;
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  return isInitialized().then(function (initialized) {
 | 
						|
    if (initialized) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return initialize();
 | 
						|
  }, function (err) {
 | 
						|
    console.error('FATAL ERROR:');
 | 
						|
    console.error(err.stack || err);
 | 
						|
    app.use('/', function (req, res) {
 | 
						|
      res.send({
 | 
						|
        error: {
 | 
						|
          message: "Unrecoverable Error Requires manual server update: " + (err.message || err.toString())
 | 
						|
        }
 | 
						|
      });
 | 
						|
    });
 | 
						|
  });
 | 
						|
};
 |