'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; // backwards compat for something or other 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(""); }); }); // 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/walnut@daplie.com/init', getConfig); app.get('/api/com.daplie.walnut.init', getConfig); // deprecated app.post('/api/walnut@daplie.com/init', setConfig); app.post('/api/com.daplie.walnut.init', setConfig); // deprecated // TODO use package loader //app.use('/', express.static(path.join(__dirname, '..', '..', 'packages', 'pages', 'walnut@daplie.com', 'init'))); app.use('/', express.static(path.join(__dirname, 'walnut@daplie.com', 'init'))); app.use('/', function (req, res, next) { res.statusCode = 404; res.end('Walnut Bootstrap Not Found. Mising walnut@daplie.com/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()) } }); }); }); };