Merge branch 'master' of bitbucket.org:coolaj86/walnut

This commit is contained in:
AJ ONeal 2015-10-09 03:48:46 +00:00
commit c1b550f219
12 changed files with 526 additions and 91 deletions

View File

@ -14,6 +14,7 @@ cli.parse({
, insecure: [ false, '(deprecated) allow insecure non-https connections', 'boolean' ]
, cacert: [ false, '(not implemented) specify a CA for "self-signed" https certificates', 'string' ]
, answer: [ 'a', 'The answer', 'string' ]
, token: [ false, 'Token (TODO or filepath to token)', 'string' ]
});
cli.main(function (args, options) {
@ -22,8 +23,9 @@ cli.main(function (args, options) {
options.answer = options.answer || args[1]
if (options.insecure) {
console.error('--insecure is not supported. You must use secure connections.');
return;
//console.error('--insecure is not supported. You must use secure connections.');
//return;
options.cacert = false;
}
if (!options.hostname) {
@ -41,20 +43,26 @@ cli.main(function (args, options) {
updater: options.service
, port: options.port
, cacert: options.cacert
, token: options.token
, ddns: [
{ "name": options.hostname
, "value": options.answer
, "type": options.type
, "priority": options.priority
, "token": options.token
}
]
}).then(function (data) {
if ('string') {
data = JSON.parse(data);
try {
data = JSON.parse(data);
} catch(e) {
console.error(data);
}
}
console.log(JSON.stringify(data, null, ' '));
console.log('Test with');
console.log('dig ' + options.hostname + ' ' + options.type);
})
});
});

View File

@ -1,38 +1,52 @@
#!/usr/bin/env node
'use strict';
// dig -p 53 @redirect-www.org pi.nadal.daplie.com A
var updateIp = require('./holepunch/helpers/update-ip.js').update;
// TODO have a quick timeout
require('ipify')(function (err, ip) {
console.log('ip', ip);
var redirects = require('./redirects');
var ddns = [];
var ddnsMap = {};
var path = require('path');
// dig -p 53 @redirect-www.org pi.nadal.daplie.com A
var updateIp = require('./holepunch/helpers/update-ip.js').update;
function add(hostname) {
ddns.push({
"name": hostname
var redirects = require('./redirects');
var ddns = [];
var ddnsMap = {};
function add(hostname) {
ddns.push({
"name": hostname
, "answer": ip
});
}
redirects.forEach(function (r) {
if (!ddnsMap[r.from.hostname.toLowerCase()]) {
add(r.from.hostname);
}
if (!ddnsMap[r.to.hostname.toLowerCase()]) {
add(r.to.hostname);
}
});
}
redirects.forEach(function (r) {
if (!ddnsMap[r.from.hostname.toLowerCase()]) {
add(r.from.hostname);
}
if (!ddnsMap[r.to.hostname.toLowerCase()]) {
add(r.to.hostname);
}
});
return updateIp({
updater: 'redirect-www.org'
, port: 65443
, cacert: null
, ddns: ddns
}).then(function (data) {
if ('string') {
data = JSON.parse(data);
}
return updateIp({
updater: 'ns1.redirect-www.org'
, port: 65443
, cacert: path.join(__dirname, 'certs/ca/ns1-test.root.crt.pem')
, ddns: ddns
, token: require('./dyndns-token').token
}).then(function (data) {
if ('string' === typeof data) {
try {
data = JSON.parse(data);
} catch(e) {
console.error('[ERROR] bad json response');
console.error(data);
}
}
console.log(JSON.stringify(data, null, ' '));
console.log('Test with');
console.log('dig <<hostname>> A');
console.log(JSON.stringify(data, null, ' '));
console.log('Test with');
console.log('dig <<hostname>> A');
});
});

1
dyndns-token.sample.js Normal file
View File

@ -0,0 +1 @@
module.exports = { token: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" };

View File

@ -1,14 +1,13 @@
'use strict';
var PromiseA = require('bluebird').Promise
, updateIp = require('./helpers/update-ip.js').update
, request = PromiseA.promisifyAll(require('request'))
, requestAsync = PromiseA.promisify(require('request'))
, upnpForward = require('./helpers/upnp-forward').upnpForward
, pmpForward = require('./helpers/pmp-forward').pmpForward
, loopbackHttps = require('./loopback-https')
//, checkip = require('check-ip-address')
;
var PromiseA = require('bluebird').Promise;
var updateIp = require('./helpers/update-ip.js').update;
var request = PromiseA.promisifyAll(require('request'));
var requestAsync = PromiseA.promisify(require('request'));
var upnpForward = require('./helpers/upnp-forward').upnpForward;
var pmpForward = require('./helpers/pmp-forward').pmpForward;
var loopbackHttps = require('./loopback-https');
//var checkip = require('check-ip-address');
function openPort(ip, port) {
if (!/tcp|https|http/.test(port.protocol || 'tcp')) {
@ -52,7 +51,7 @@ function beacon(hostnames, ports) {
console.log("Updated DynDNS");
console.log(data);
ports.forEach(function (port) {
promises.push(openPort(JSON.parse(data)[0].answers[0] || hostname, port));
});

View File

@ -1,18 +1,16 @@
'use strict';
var PromiseA = require('bluebird').Promise
, natpmp = require('nat-pmp')
, exec = require('child_process').exec
;
var PromiseA = require('bluebird').Promise;
var natpmp = require('nat-pmp');
var exec = require('child_process').exec;
exports.pmpForward = function (port) {
return new PromiseA(function (resolve, reject) {
exec('ip route show default', function (err, stdout, stderr) {
var gw
;
var gw;
if (err || stderr) { reject(err || stderr); return; }
// default via 192.168.1.1 dev eth0
gw = stdout.replace(/^default via (\d+\.\d+\.\d+\.\d+) dev[\s\S]+/m, '$1');
console.log('Possible PMP gateway is', gw);
@ -55,3 +53,29 @@ exports.pmpForward = function (port) {
});
});
};
function usage() {
console.warn("");
console.warn("node helpers/pmp-forward [public port] [private port] [ttl]");
console.warn("");
}
function run() {
var pubPort = parseInt(process.argv[2], 10) || 0;
var privPort = parseInt(process.argv[3], 10) || pubPort;
var ttl = parseInt(process.argv[4], 10) || 0;
var options = { public: pubPort, private: privPort, ttl: ttl };
if (!pubPort) {
usage();
return;
}
exports.pmpForward(options).then(function () {
console.log('done');
});
}
if (require.main === module) {
run();
}

View File

@ -1,18 +1,17 @@
#!/usr/bin/env node
'use strict';
var PromiseA = require('bluebird').Promise
, https = require('https')
, fs = require('fs')
, path = require('path')
;
var PromiseA = require('bluebird').Promise;
var https = require('https');
var fs = require('fs');
var path = require('path');
module.exports.update = function (opts) {
return new PromiseA(function (resolve, reject) {
var options
, hostname = opts.updater || 'redirect-www.org'
, port = opts.port || 65443
;
var options;
var hostname = opts.updater || 'redirect-www.org';
var port = opts.port || 65443;
var req;
options = {
host: hostname
@ -22,12 +21,36 @@ module.exports.update = function (opts) {
'Content-Type': 'application/json'
}
, path: '/api/ddns'
, auth: opts.auth || 'admin:secret'
, ca: [ fs.readFileSync(path.join(__dirname, '..', 'certs', 'ca', 'my-root-ca.crt.pem')) ]
//, auth: opts.auth || 'admin:secret'
};
if (opts.cacert) {
if (!Array.isArray(opts.cacert)) {
opts.cacert = [opts.cacert];
}
options.ca = opts.cacert;
} else {
options.ca = [path.join(__dirname, '..', 'certs', 'ca', 'my-root-ca.crt.pem')]
}
options.ca = options.ca.map(function (str) {
if ('string' === typeof str && str.length < 1000) {
str = fs.readFileSync(str);
}
return str;
});
if (opts.token || opts.jwt) {
options.headers['Authorization'] = 'Bearer ' + (opts.token || opts.jwt);
}
if (false === opts.cacert) {
options.rejectUnauthorized = false;
}
options.agent = new https.Agent(options);
https.request(options, function(res) {
req = https.request(options, function(res) {
var textData = '';
res.on('error', function (err) {
@ -38,8 +61,22 @@ module.exports.update = function (opts) {
// console.log(chunk.toString());
});
res.on('end', function () {
resolve(textData);
var err;
try {
resolve(JSON.parse(textData));
} catch(e) {
err = new Error("Unparsable Server Response");
err.code = 'E_INVALID_SERVER_RESPONSE';
err.data = textData;
reject(err);
}
});
}).end(JSON.stringify(opts.ddns, null, ' '));
});
req.on('error', function () {
reject(err);
});
req.end(JSON.stringify(opts.ddns, null, ' '));
});
};

View File

@ -19,7 +19,7 @@ exports.upnpForward = function (port) {
console.log('mappings');
console.log(mappings);
});
return promitter;
})*/;
});
@ -49,8 +49,24 @@ client.externalIp(function(err, ip) {
});
*/
if (require.main === module) {
exports.upnpForward({ public: 65080, private: 65080, ttl: 0 }).then(function () {
function usage() {
console.warn("");
console.warn("node helpers/upnp-forward [public port] [private port] [ttl]");
console.warn("");
}
function run() {
var pubPort = parseInt(process.argv[2], 10) || 0;
var privPort = parseInt(process.argv[3], 10) || pubPort;
var ttl = parseInt(process.argv[4], 10) || 0;
var options = { public: pubPort, private: privPort, ttl: ttl };
if (!pubPort) {
usage();
return;
}
exports.upnpForward(options).then(function () {
console.log('done');
}).catch(function (err) {
console.error('ERROR');
@ -58,3 +74,8 @@ if (require.main === module) {
throw err;
});
}
if (require.main === module) {
run();
return;
}

101
lib/ddns-updater.js Normal file
View File

@ -0,0 +1,101 @@
'use strict';
var updateIp = require('../holepunch/helpers/update-ip.js').update;
// TODO XXX use API + storage
var token = require('../dyndns-token.js').token;
/*
* @param {string[]} hostnames - A list of hostnames
* @param {Object[]} addresses - A list of { address: <ip-address>, family: <4|6> }
*/
function update(hostnames, addresses) {
// TODO use not-yet-built API to get and store tokens
// TODO use API to add and remove nameservers
var services = [
// TODO XXX don't disable cacert checking
{ hostname: 'ns1.redirect-www.org', port: 65443, cacert: false }
, { hostname: 'ns2.redirect-www.org', port: 65443, cacert: false }
];
var answers = [];
var promises;
var results = [];
var PromiseA;
hostnames.forEach(function (hostname) {
addresses.forEach(function (address) {
var answer = {
"name": hostname
, "value": address.address
, "type": null
, "priority": null
, "token": token
};
if (4 === address.family) {
answer.type = 'A';
}
else if (6 === address.family) {
answer.type = 'AAAA';
}
else {
console.error('[ERROR] unspported address:');
console.error(address);
return;
}
answers.push(answer);
});
});
promises = services.map(function (service, i) {
return updateIp({
updater: service.hostname
, port: service.port
, cacert: service.cacert
, token: token
, ddns: answers
}).then(function (data) {
results[i] = { service: service, data: data };
return data;
}).error(function (err) {
results[i] = { service: service, error: err };
});
});
PromiseA = require('bluebird').Promise;
return PromiseA.all(promises).then(function () {
return results;
});
}
module.exports.update = function () {
var allMap = {};
var hostnames = require('../redirects.json').reduce(function (all, redirect) {
if (!allMap[redirect.from.hostname]) {
allMap[redirect.from.hostname] = true;
all.push(redirect.from.hostname);
}
if (!all[redirect.to.hostname]) {
allMap[redirect.to.hostname] = true;
all.push(redirect.to.hostname);
}
return all;
}, []);
return require('./ip-checker').getExternalAddresses().then(function (result) {
//console.log(Object.keys(allMap), result);
//console.log(hostnames)
//console.log(result.addresses);
console.log('[IP CHECKER] hostnames.length', hostnames.length);
console.log('[IP CHECKER] result.addresses.length', result.addresses.length);
return update(hostnames, result.addresses);
});
};
if (require.main === module) {
module.exports.update().then(function (results) {
console.log('results');
console.log(results);
});
}

View File

@ -6,6 +6,8 @@ module.exports.create = function (securePort, insecurePort, redirects) {
var escapeRe;
function redirectHttps(req, res) {
res.setHeader('Strict-Transport-Security', 'max-age=10886400; includeSubDomains; preload');
var insecureRedirects;
var host = req.headers.host || '';
var url = req.url;
@ -40,19 +42,21 @@ module.exports.create = function (securePort, insecurePort, redirects) {
);
});
var escapeHtml = require('escape-html');
var newLocation = 'https://'
+ host.replace(/:\d+/, ':' + securePort) + url
;
var safeLocation = escapeHtml(newLocation);
var metaRedirect = ''
+ '<html>\n'
+ '<head>\n'
+ ' <style>* { background-color: white; color: white; text-decoration: none; }</style>\n'
+ ' <META http-equiv="refresh" content="0;URL=' + newLocation + '">\n'
+ ' <META http-equiv="refresh" content="0;URL=' + safeLocation + '">\n'
+ '</head>\n'
+ '<body style="display: none;">\n'
+ ' <p>You requested an insecure resource. Please use this instead: \n'
+ ' <a href="' + newLocation + '">' + newLocation + '</a></p>\n'
+ ' <a href="' + safeLocation + '">' + safeLocation + '</a></p>\n'
+ '</body>\n'
+ '</html>\n'
;
@ -72,7 +76,7 @@ module.exports.create = function (securePort, insecurePort, redirects) {
// To minimize this, we give browser users a mostly optimal experience,
// but people experimenting with the API get a message letting them know
// that they're doing it wrong and thus forces them to ensure they encrypt.
res.setHeader('Content-Type', 'text/html');
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(metaRedirect);
}

126
lib/ip-checker.js Normal file
View File

@ -0,0 +1,126 @@
"use strict";
var PromiseA = require('bluebird').Promise;
var ifaces = require('os').networkInterfaces();
var dns = PromiseA.promisifyAll(require('dns'));
var https = require('https');
function getExternalAddresses() {
var iftypes = {};
Object.keys(ifaces).forEach(function (ifname) {
ifaces[ifname].forEach(function (iface) {
if (iface.internal) {
return;
}
/*
if (/^(::|f[cde])/.test(iface.address)) {
console.log('non-public ipv6');
return;
}
*/
iftypes[iface.family] = true;
});
});
var now = Date.now();
return PromiseA.all([
dns.lookupAsync('api.ipify.org', { family: 4/*, all: true*/ }).then(function (ans) {
iftypes.IPv4 = { address: ans[0], family: ans[1], time: Date.now() - now };
}).error(function () {
//console.log('no ipv4', Date.now() - now);
iftypes.IPv4 = false;
})
, dns.lookupAsync('api.ipify.org', { family: 6/*, all: true*/ }).then(function (ans) {
iftypes.IPv6 = { address: ans[0], family: ans[1], time: Date.now() - now };
}).error(function () {
//console.log('no ipv6', Date.now() - now);
iftypes.IPv6 = false;
})
]).then(function () {
var requests = [];
if (iftypes.IPv4) {
requests.push(new PromiseA(function (resolve) {
var req = https.request({
method: 'GET'
, hostname: iftypes.IPv4.address
, port: 443
, headers: {
Host: 'api.ipify.org'
}
, path: '/'
//, family: 4
// TODO , localAddress: <<external_ipv4>>
}, function (res) {
var result = '';
res.on('error', function (/*err*/) {
resolve(null);
});
res.on('data', function (chunk) {
result += chunk.toString('utf8');
});
res.on('end', function () {
resolve({ address: result, family: 4/*, wan: result === iftypes.IPv4.localAddress*/, time: iftypes.IPv4.time });
});
});
req.on('error', function () {
resolve(null);
});
req.end();
}));
}
if (iftypes.IPv6) {
requests.push(new PromiseA(function (resolve) {
var req = https.request({
method: 'GET'
, hostname: iftypes.IPv6.address
, port: 443
, headers: {
Host: 'api.ipify.org'
}
, path: '/'
//, family: 6
// TODO , localAddress: <<external_ipv6>>
}, function (res) {
var result = '';
res.on('error', function (/*err*/) {
resolve(null);
});
res.on('data', function (chunk) {
result += chunk.toString('utf8');
});
res.on('end', function () {
resolve({ address: result, family: 6/*, wan: result === iftypes.IPv6.localAaddress*/, time: iftypes.IPv4.time });
});
});
req.on('error', function () {
resolve(null);
});
req.end();
}));
}
return PromiseA.all(requests).then(function (ips) {
ips = ips.filter(function (ip) {
return ip;
});
return {
addresses: ips
, time: Date.now() - now
};
});
});
}
exports.getExternalAddresses = getExternalAddresses;

View File

@ -8,7 +8,9 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
var path = require('path');
var dummyCerts;
var serveFavicon;
var secureContexts = {};
var secureContexts = {};
var loopbackApp;
var loopbackToken = require('crypto').randomBytes(32).toString('hex');
function loadDummyCerts() {
if (dummyCerts) {
@ -132,6 +134,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
console.log('[log] [once] Preparing mount for', domaininfo.hostname + '/' + domaininfo.dirpathname);
domainMergeMap[domaininfo.hostname].mountsMap['/' + domaininfo.dirpathname] = function (req, res, next) {
res.setHeader('Strict-Transport-Security', 'max-age=10886400; includeSubDomains; preload');
function loadThatApp() {
var time = Date.now();
@ -206,6 +209,13 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
});
}
function suckItDubDubDub(req, res) {
var newLoc = 'https://' + (req.headers.host||'').replace(/^www\./) + req.url;
res.statusCode = 301;
res.setHeader('Location', newLoc);
res.end("<html><head><title></title></head><body><!-- redirecting nowww --></body><html>");
}
function nextify() {
if (!appContext) {
appContext = loadThatApp();
@ -230,17 +240,27 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
connectContext.static = serveStatic(path.join(vhostsdir, domaininfo.dirname, 'public'));
}
if (/^\/api\//.test(req.url)) {
nextify();
if (/^www\./.test(req.headers.host)) {
if (/\.appcache\b/.test(req.url)) {
res.setHeader('Content-Type', 'text/cache-manifest');
res.end('CACHE MANIFEST\n\n# v0__DELETE__CACHE__MANIFEST__\n\nNETWORK:\n*');
return;
}
suckItDubDubDub(req, res);
return;
}
connectContext.static(req, res, nextify);
if (/^\/api\//.test(req.url)) {
nextify();
return;
}
connectContext.static(req, res, nextify);
};
domainMergeMap[domaininfo.hostname].apps.use(
'/' + domaininfo.pathname
, domainMergeMap[domaininfo.hostname].mountsMap['/' + domaininfo.dirpathname]
);
'/' + domaininfo.pathname
, domainMergeMap[domaininfo.hostname].mountsMap['/' + domaininfo.dirpathname]
);
return PromiseA.resolve();
}
@ -276,9 +296,20 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
};
}
function getLoopbackApp() {
return function (req, res) {
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.end(JSON.stringify({ "success": true, "token": loopbackToken }));
};
}
function getAppContext(domaininfo) {
var localApp;
if ('loopback.daplie.invalid' === domaininfo.dirname) {
return getLoopbackApp();
}
try {
// TODO live reload required modules
localApp = require(path.join(vhostsdir, domaininfo.dirname, 'app.js'));
@ -287,9 +318,9 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
// TODO pass in websocket
localApp = localApp.create(secureServer, {
dummyCerts: dummyCerts
, hostname: domaininfo.hostname
, port: securePort
, url: domaininfo.pathname
, hostname: domaininfo.hostname
, port: securePort
, url: domaininfo.pathname
});
if (!localApp) {
@ -324,7 +355,38 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
console.log('[log] [once] Loading all mounts for ' + domainApp.hostname);
domainApp._loaded = true;
app.use(vhost(domainApp.hostname, domainApp.apps));
app.use(vhost('www.' + domainApp.hostname, domainApp.apps));
app.use(vhost('www.' + domainApp.hostname, function (req, res, next) {
if (/\.appcache\b/.test(req.url)) {
res.setHeader('Content-Type', 'text/cache-manifest');
res.end('CACHE MANIFEST\n\n# v0__DELETE__CACHE__MANIFEST__\n\nNETWORK:\n*');
//domainApp.apps(req, res, next);
return;
}
// TODO XXX this is in the api section, so it should hard break
//res.statusCode = 301;
//res.setHeader('Location', newLoc);
// TODO port number for non-443
var escapeHtml = require('escape-html');
var newLocation = 'https://' + domainApp.hostname + req.url;
var safeLocation = escapeHtml(newLocation);
var metaRedirect = ''
+ '<html>\n'
+ '<head>\n'
+ ' <style>* { background-color: white; color: white; text-decoration: none; }</style>\n'
+ ' <META http-equiv="refresh" content="0;URL=' + safeLocation + '">\n'
+ '</head>\n'
+ '<body style="display: none;">\n'
+ ' <p>You requested an old resource. Please use this instead: \n'
+ ' <a href="' + safeLocation + '">' + safeLocation + '</a></p>\n'
+ '</body>\n'
+ '</html>\n'
;
// 301 redirects will not work for appcache
res.end(metaRedirect);
}));
});
}
@ -400,14 +462,28 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
var secOpts;
try {
var nodes = fs.readdirSync(path.join(certsPath, 'server'));
var keyNode = nodes.filter(function (node) { return /\.key\.pem$/.test(node); })[0];
var crtNode = nodes.filter(function (node) { return /\.crt\.pem$/.test(node); })[0];
var nodes = fs.readdirSync(certsPath);
var keyNode = nodes.filter(function (node) { return 'privkey.pem' === node; })[0];
var crtNode = nodes.filter(function (node) { return 'fullchain.pem' === node; })[0];
if (keyNode && crtNode) {
keyNode = path.join(certsPath, keyNode);
crtNode = path.join(certsPath, crtNode);
} else {
nodes = fs.readdirSync(path.join(certsPath, 'server'));
keyNode = nodes.filter(function (node) { return /^privkey(\.key)?\.pem$/.test(node) || /\.key\.pem$/.test(node); })[0];
crtNode = nodes.filter(function (node) { return /^fullchain(\.crt)?\.pem$/.test(node) || /\.crt\.pem$/.test(node); })[0];
keyNode = path.join(certsPath, 'server', keyNode);
crtNode = path.join(certsPath, 'server', crtNode);
}
secOpts = {
key: fs.readFileSync(path.join(certsPath, 'server', keyNode))
, cert: fs.readFileSync(path.join(certsPath, 'server', crtNode))
key: fs.readFileSync(keyNode)
, cert: fs.readFileSync(crtNode)
};
// I misunderstood what the ca option was for
/*
if (fs.existsSync(path.join(certsPath, 'ca'))) {
secOpts.ca = fs.readdirSync(path.join(certsPath, 'ca')).filter(function (node) {
console.log('[log ca]', node);
@ -416,6 +492,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
return fs.readFileSync(path.join(certsPath, 'ca', node));
});
}
*/
} catch(err) {
// TODO Let's Encrypt / ACME HTTPS
console.error("[ERROR] Couldn't READ HTTPS certs from '" + certsPath + "':");
@ -446,14 +523,18 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
// fallback / default dummy certs
key: localDummyCerts.key
, cert: localDummyCerts.cert
, ca: localDummyCerts.ca
// changes from default: disallow RC4
, ciphers: "ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:!RC4:HIGH:!MD5:!aNULL"
//, ca: localDummyCerts.ca
// io.js defaults have disallowed insecure algorithms as of 2015-06-29
// https://iojs.org/api/tls.html
// previous version could use something like this
//, ciphers: "ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:!RC4:HIGH:!MD5:!aNULL"
};
function addSniWorkaroundCallback() {
//SNICallback is passed the domain name, see NodeJS docs on TLS
secureOpts.SNICallback = function (domainname, cb) {
domainname = domainname.replace(/^www\./, '')
if (/(^|\.)proxyable\./.test(domainname)) {
// device-id-12345678.proxyable.myapp.mydomain.com => myapp.mydomain.com
// proxyable.myapp.mydomain.com => myapp.mydomain.com
@ -521,5 +602,23 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
});
}
function updateIps() {
console.log('[UPDATE IP]');
require('./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);
updateIps();
return runServer();
};

View File

@ -63,7 +63,7 @@
"ee-first": "^1.1.0",
"errorhandler": "1.x",
"es6-promise": "2.x",
"escape-html": "^1.0.1",
"escape-html": "^1.0.2",
"escape-string-regexp": "1.x",
"etag": "^1.5.1",
"express": "4.x",
@ -74,6 +74,7 @@
"fresh": "^0.2.4",
"human-readable-ids": "1.x",
"inherits": "^2.0.1",
"ipify": "^1.0.5",
"jarson": "1.x",
"json-storage": "2.x",
"knex": "^0.6.23",
@ -87,7 +88,7 @@
"negotiator": "^0.5.1",
"node-pre-gyp": "^0.6.4",
"node-uuid": "1.x",
"nodemailer": "1.x",
"nodemailer": "^1.4.0",
"nodemailer-mailgun-transport": "1.x",
"oauth": "0.9.x",
"oauth2orize": "git://github.com/coolaj86/oauth2orize.git#v1.0.1+scope.1",