2015-11-04 09:22:00 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
console.log('\n\n\n[MASTER] Welcome to WALNUT!');
|
|
|
|
|
|
|
|
var PromiseA = require('bluebird');
|
2015-11-06 01:00:22 +00:00
|
|
|
var fs = PromiseA.promisifyAll(require('fs'));
|
2015-11-04 09:22:00 +00:00
|
|
|
var cluster = require('cluster');
|
2015-11-06 01:00:22 +00:00
|
|
|
var numForks = 0;
|
|
|
|
var numCores = Math.min(2, require('os').cpus().length);
|
|
|
|
var securePort = process.argv[2] || 443; // 443
|
|
|
|
var insecurePort = process.argv[3] || 80; // 80
|
|
|
|
var localPort = securePort;
|
|
|
|
var caddy;
|
|
|
|
var masterServer;
|
2015-11-04 09:22:00 +00:00
|
|
|
var rootMasterKey;
|
|
|
|
|
|
|
|
var redirects = require('./redirects.json');
|
|
|
|
var path = require('path');
|
|
|
|
|
|
|
|
// force SSL upgrade server
|
|
|
|
var certPaths = [path.join(__dirname, 'certs', 'live')];
|
|
|
|
var promiseServer;
|
|
|
|
var masterApp;
|
2015-11-06 01:00:22 +00:00
|
|
|
var caddyConf = { localPort: 4080, locked: true };
|
2015-11-04 09:22:00 +00:00
|
|
|
|
|
|
|
//console.log('\n.');
|
|
|
|
|
2015-11-06 01:00:22 +00:00
|
|
|
function fork() {
|
|
|
|
if (numForks < numCores) {
|
|
|
|
numForks += 1;
|
|
|
|
cluster.fork();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-04 09:22:00 +00:00
|
|
|
// Note that this function will be called async, after promiseServer is returned
|
|
|
|
// it seems like a circular dependency, but it isn't... not exactly anyway
|
|
|
|
function promiseApps() {
|
|
|
|
if (masterApp) {
|
|
|
|
return PromiseA.resolve(masterApp);
|
|
|
|
}
|
|
|
|
|
2015-11-06 01:00:22 +00:00
|
|
|
masterApp = promiseServer.then(function (_masterServer) {
|
|
|
|
masterServer = _masterServer;
|
|
|
|
console.log("[MASTER] Listening on https://localhost:" + masterServer.address().port, '\n');
|
2015-11-04 09:22:00 +00:00
|
|
|
|
|
|
|
return require('./lib/unlock-device').create().then(function (result) {
|
|
|
|
result.promise.then(function (_rootMasterKey) {
|
|
|
|
var i;
|
2015-11-06 01:00:22 +00:00
|
|
|
caddyConf.locked = false;
|
|
|
|
if (caddy) {
|
|
|
|
caddy.update(caddyConf);
|
|
|
|
}
|
2015-11-04 09:22:00 +00:00
|
|
|
rootMasterKey = _rootMasterKey;
|
|
|
|
|
2015-11-06 01:00:22 +00:00
|
|
|
if (numCores <= 2) {
|
|
|
|
// we're on one core, stagger the remaning
|
|
|
|
fork();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-04 09:22:00 +00:00
|
|
|
for (i = 0; i < numCores; i += 1) {
|
2015-11-06 01:00:22 +00:00
|
|
|
fork();
|
2015-11-04 09:22:00 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
masterApp = result.app;
|
|
|
|
return result.app;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return masterApp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO have a fallback server than can download and apply an update?
|
|
|
|
require('./lib/insecure-server').create(securePort, insecurePort, redirects);
|
|
|
|
//console.log('\n.');
|
2015-11-06 01:00:22 +00:00
|
|
|
promiseServer = fs.existsAsync('/usr/local/bin/caddy').then(function () {
|
|
|
|
console.log("Caddy is not present");
|
|
|
|
// Caddy DOES NOT exist, use our node sni-server
|
|
|
|
return require('./lib/sni-server').create(certPaths, localPort, promiseApps);
|
|
|
|
}, function () {
|
|
|
|
console.log("Caddy is present (assumed running)");
|
|
|
|
// Caddy DOES exist, use our http server without sni
|
|
|
|
localPort = caddyConf.localPort;
|
|
|
|
caddy = require('./lib/spawn-caddy').create();
|
|
|
|
|
|
|
|
return caddy.spawn(caddyConf).then(function () {
|
|
|
|
console.log("caddy has spawned");
|
|
|
|
//return caddy.update(caddyConf).then(function () {
|
|
|
|
// console.log("caddy is updating");
|
|
|
|
|
|
|
|
setInterval(function () {
|
|
|
|
console.log('SIGUSR1 to caddy');
|
|
|
|
return caddy.update(caddyConf);
|
|
|
|
}, 60 * 1000);
|
|
|
|
|
|
|
|
return require('./lib/local-server').create(localPort, promiseApps);
|
|
|
|
//});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-11-04 09:22:00 +00:00
|
|
|
//console.log('\n.');
|
|
|
|
|
|
|
|
cluster.on('online', function (worker) {
|
|
|
|
console.log('[MASTER] Worker ' + worker.process.pid + ' is online');
|
2015-11-06 01:00:22 +00:00
|
|
|
fork();
|
|
|
|
|
|
|
|
if (masterServer) {
|
2015-11-04 09:22:00 +00:00
|
|
|
// NOTE: it's possible that this could survive idle for a while through keep-alive
|
|
|
|
// should default to connection: close
|
2015-11-06 01:00:22 +00:00
|
|
|
masterServer.close();
|
|
|
|
masterServer = null;
|
2015-11-04 09:22:00 +00:00
|
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
// TODO use `id' to find user's uid / gid and set to file
|
|
|
|
// TODO set immediately?
|
2015-11-06 01:00:22 +00:00
|
|
|
if (!caddy) {
|
|
|
|
// TODO what about caddy
|
|
|
|
process.setgid(1000);
|
|
|
|
process.setuid(1000);
|
|
|
|
}
|
2015-11-04 09:22:00 +00:00
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
|
2015-11-06 01:00:22 +00:00
|
|
|
console.log("securePort", securePort);
|
2015-11-04 09:22:00 +00:00
|
|
|
worker.send({
|
|
|
|
type: 'init'
|
2015-11-06 01:00:22 +00:00
|
|
|
, securePort: localPort
|
|
|
|
, certPaths: caddy ? null : certPaths
|
2015-11-04 09:22:00 +00:00
|
|
|
});
|
2015-11-06 01:00:22 +00:00
|
|
|
|
2015-11-04 09:22:00 +00:00
|
|
|
worker.on('message', function (msg) {
|
|
|
|
console.log('message from worker');
|
|
|
|
console.log(msg);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
cluster.on('exit', function (worker, code, signal) {
|
2015-11-06 01:00:22 +00:00
|
|
|
numForks -= 1;
|
2015-11-04 09:22:00 +00:00
|
|
|
console.log('[MASTER] Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal);
|
2015-11-06 01:00:22 +00:00
|
|
|
fork();
|
2015-11-04 09:22:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// TODO delegate to workers
|
|
|
|
function updateIps() {
|
|
|
|
console.log('[UPDATE IP]');
|
|
|
|
require('./lib/ddns-updater').update().then(function (results) {
|
|
|
|
results.forEach(function (result) {
|
|
|
|
if (result.error) {
|
|
|
|
console.error(result);
|
|
|
|
} else {
|
|
|
|
console.log('[SUCCESS]', result.service.hostname);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}).error(function (err) {
|
|
|
|
console.error('[UPDATE IP] ERROR');
|
|
|
|
console.error(err);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// TODO check the IP every 5 minutes and update it every hour
|
|
|
|
setInterval(updateIps, 60 * 60 * 1000);
|
|
|
|
// we don't want this to load right away (extra procesing time)
|
|
|
|
setTimeout(updateIps, 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
worker.send({
|
|
|
|
insecurePort: insecurePort
|
|
|
|
});
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
var fs = require('fs');
|
|
|
|
var daplieReadFile = fs.readFileSync;
|
|
|
|
var time = 0;
|
|
|
|
|
|
|
|
fs.readFileSync = function (filename) {
|
|
|
|
var now = Date.now();
|
|
|
|
var data = daplieReadFile.apply(fs, arguments);
|
|
|
|
var t;
|
|
|
|
|
|
|
|
t = (Date.now() - now);
|
|
|
|
time += t;
|
|
|
|
console.log('loaded "' + filename + '" in ' + t + 'ms (total ' + time + 'ms)');
|
|
|
|
|
|
|
|
return data;
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
|
|
|
//var config = require('./device.json');
|
|
|
|
|
|
|
|
// require('ssl-root-cas').inject();
|
|
|
|
|
|
|
|
/*
|
|
|
|
function phoneHome() {
|
|
|
|
var holepunch = require('./holepunch/beacon');
|
|
|
|
var ports;
|
|
|
|
|
|
|
|
ports = [
|
|
|
|
{ private: 65022
|
|
|
|
, public: 65022
|
|
|
|
, protocol: 'tcp'
|
|
|
|
, ttl: 0
|
|
|
|
, test: { service: 'ssh' }
|
|
|
|
, testable: false
|
|
|
|
}
|
|
|
|
, { private: 650443
|
|
|
|
, public: 650443
|
|
|
|
, protocol: 'tcp'
|
|
|
|
, ttl: 0
|
|
|
|
, test: { service: 'https' }
|
|
|
|
}
|
|
|
|
, { private: 65080
|
|
|
|
, public: 65080
|
|
|
|
, protocol: 'tcp'
|
|
|
|
, ttl: 0
|
|
|
|
, test: { service: 'http' }
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
// TODO return a middleware
|
|
|
|
holepunch.run(require('./redirects.json').reduce(function (all, redirect) {
|
|
|
|
if (!all[redirect.from.hostname]) {
|
|
|
|
all[redirect.from.hostname] = true;
|
|
|
|
all.push(redirect.from.hostname);
|
|
|
|
}
|
|
|
|
if (!all[redirect.to.hostname]) {
|
|
|
|
all[redirect.to.hostname] = true;
|
|
|
|
all.push(redirect.to.hostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
return all;
|
|
|
|
}, []), ports).catch(function () {
|
|
|
|
console.error("Couldn't phone home. Oh well");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
*/
|