updates
This commit is contained in:
parent
3a1efa7cdf
commit
36b15be276
2
app.js
2
app.js
|
@ -21,7 +21,7 @@ module.exports = function (opts) {
|
|||
if (opts.livereload) {
|
||||
livereload = '<script src="//'
|
||||
+ (res.getHeader('Host') || opts.servername).split(':')[0]
|
||||
+ ':35729/livereload.js?snipver=1"></script>';
|
||||
+ ':' + opts.lrPort + '/livereload.js?snipver=1"></script>';
|
||||
addLen = livereload.length;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
'use strict';
|
||||
|
||||
var PromiseA = require('bluebird');
|
||||
|
||||
module.exports.match = function (servername, opts) {
|
||||
return PromiseA.promisify(require('ipify'))().then(function (ip) {
|
||||
var dns = PromiseA.promisifyAll(require('dns'));
|
||||
|
||||
opts.externalIps = [ { address: ip, family: 'IPv4' } ];
|
||||
opts.ifaces = require('./local-ip.js').find({ externals: opts.externalIps });
|
||||
opts.externalIfaces = Object.keys(opts.ifaces).reduce(function (all, iname) {
|
||||
var iface = opts.ifaces[iname];
|
||||
|
||||
iface.ipv4.forEach(function (addr) {
|
||||
if (addr.external) {
|
||||
addr.iface = iname;
|
||||
all.push(addr);
|
||||
}
|
||||
});
|
||||
iface.ipv6.forEach(function (addr) {
|
||||
if (addr.external) {
|
||||
addr.iface = iname;
|
||||
all.push(addr);
|
||||
}
|
||||
});
|
||||
|
||||
return all;
|
||||
}, []).filter(Boolean);
|
||||
|
||||
function resolveIps(hostname) {
|
||||
var allIps = [];
|
||||
|
||||
return PromiseA.all([
|
||||
dns.resolve4Async(hostname).then(function (records) {
|
||||
records.forEach(function (ip) {
|
||||
allIps.push({
|
||||
address: ip
|
||||
, family: 'IPv4'
|
||||
});
|
||||
});
|
||||
}, function () {})
|
||||
, dns.resolve6Async(hostname).then(function (records) {
|
||||
records.forEach(function (ip) {
|
||||
allIps.push({
|
||||
address: ip
|
||||
, family: 'IPv6'
|
||||
});
|
||||
});
|
||||
}, function () {})
|
||||
]).then(function () {
|
||||
return allIps;
|
||||
});
|
||||
}
|
||||
|
||||
function resolveIpsAndCnames(hostname) {
|
||||
return PromiseA.all([
|
||||
resolveIps(hostname)
|
||||
, dns.resolveCnameAsync(hostname).then(function (records) {
|
||||
return PromiseA.all(records.map(function (hostname) {
|
||||
return resolveIps(hostname);
|
||||
})).then(function (allIps) {
|
||||
return allIps.reduce(function (all, ips) {
|
||||
return all.concat(ips);
|
||||
}, []);
|
||||
});
|
||||
}, function () {
|
||||
return [];
|
||||
})
|
||||
]).then(function (ips) {
|
||||
return ips.reduce(function (all, set) {
|
||||
return all.concat(set);
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
return resolveIpsAndCnames(servername).then(function (allIps) {
|
||||
var matchingIps = [];
|
||||
|
||||
if (!allIps.length) {
|
||||
console.warn("Could not resolve '" + servername + "'");
|
||||
}
|
||||
|
||||
// { address, family }
|
||||
allIps.some(function (ip) {
|
||||
function match(addr) {
|
||||
if (ip.address === addr.address) {
|
||||
matchingIps.push(addr);
|
||||
}
|
||||
}
|
||||
|
||||
opts.externalIps.forEach(match);
|
||||
// opts.externalIfaces.forEach(match);
|
||||
|
||||
Object.keys(opts.ifaces).forEach(function (iname) {
|
||||
var iface = opts.ifaces[iname];
|
||||
|
||||
iface.ipv4.forEach(match);
|
||||
iface.ipv6.forEach(match);
|
||||
});
|
||||
|
||||
return matchingIps.length;
|
||||
});
|
||||
|
||||
return matchingIps;
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "serve-https",
|
||||
"version": "1.5.6",
|
||||
"version": "2.0.0",
|
||||
"description": "Serves HTTPS using TLS (SSL) certs for localhost.daplie.com - great for testing and development.",
|
||||
"main": "serve.js",
|
||||
"scripts": {
|
||||
|
@ -38,8 +38,12 @@
|
|||
},
|
||||
"homepage": "https://github.com/Daplie/serve-https#readme",
|
||||
"dependencies": {
|
||||
"bluebird": "^3.4.6",
|
||||
"finalhandler": "^0.4.0",
|
||||
"ipify": "^1.1.0",
|
||||
"le-challenge-dns": "^2.0.1",
|
||||
"le-challenge-fs": "^2.0.5",
|
||||
"letsencrypt-express": "^2.0.2",
|
||||
"livereload": "^0.4.0",
|
||||
"localhost.daplie.com-certificates": "^1.2.0",
|
||||
"minimist": "^1.1.1",
|
||||
|
|
136
serve.js
136
serve.js
|
@ -6,6 +6,7 @@ var https = require('https');
|
|||
var http = require('http');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var DDNS = require('ddns-cli');
|
||||
var portFallback = 8443;
|
||||
var insecurePortFallback = 4080;
|
||||
|
||||
|
@ -49,13 +50,74 @@ function createInsecureServer(port, pubdir, opts) {
|
|||
}
|
||||
|
||||
function createServer(port, pubdir, content, opts) {
|
||||
function approveDomains(params, certs, cb) {
|
||||
// This is where you check your database and associated
|
||||
// email addresses with domains and agreements and such
|
||||
var domains = params.domains;
|
||||
//var p;
|
||||
console.log('approveDomains');
|
||||
console.log(domains);
|
||||
|
||||
|
||||
// The domains being approved for the first time are listed in opts.domains
|
||||
// Certs being renewed are listed in certs.altnames
|
||||
if (certs) {
|
||||
params.domains = certs.altnames;
|
||||
//p = PromiseA.resolve();
|
||||
}
|
||||
else {
|
||||
//params.email = opts.email;
|
||||
if (!opts.agreeTos) {
|
||||
console.error("You have not previously registered '" + domains + "' so you must specify --agree-tos to agree to both the Let's Encrypt and Daplie DNS terms of service.");
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
params.agreeTos = opts.agreeTos;
|
||||
}
|
||||
|
||||
// ddns.token(params.email, domains[0])
|
||||
params.email = opts.email;
|
||||
params.refreshToken = opts.refreshToken;
|
||||
params.challengeType = 'dns-01';
|
||||
params.cli = opts.argv;
|
||||
|
||||
cb(null, { options: params, certs: certs });
|
||||
}
|
||||
|
||||
return new PromiseA(function (resolve) {
|
||||
var server = https.createServer(opts);
|
||||
var app = require('./app');
|
||||
|
||||
var directive = { public: pubdir, content: content, livereload: opts.livereload
|
||||
, servername: opts.servername, expressApp: opts.expressApp };
|
||||
|
||||
// returns an instance of node-letsencrypt with additional helper methods
|
||||
var webrootPath = require('os').tmpdir();
|
||||
var leChallengeFs = require('le-challenge-fs').create({ webrootPath: webrootPath });
|
||||
var leChallengeDns = require('le-challenge-dns').create({ ttl: 1 });
|
||||
var lex = require('letsencrypt-express').create({
|
||||
// set to https://acme-v01.api.letsencrypt.org/directory in production
|
||||
server: opts.debug ? 'staging' : 'https://acme-v01.api.letsencrypt.org/directory'
|
||||
|
||||
// If you wish to replace the default plugins, you may do so here
|
||||
//
|
||||
, challenges: {
|
||||
'http-01': leChallengeFs
|
||||
, 'tls-sni-01': leChallengeFs
|
||||
, 'dns-01': leChallengeDns
|
||||
}
|
||||
, challengeType: 'dns-01'
|
||||
, store: require('le-store-certbot').create({ webrootPath: webrootPath })
|
||||
, webrootPath: webrootPath
|
||||
|
||||
// You probably wouldn't need to replace the default sni handler
|
||||
// See https://github.com/Daplie/le-sni-auto if you think you do
|
||||
//, sni: require('le-sni-auto').create({})
|
||||
|
||||
, approveDomains: approveDomains
|
||||
});
|
||||
opts.httpsOptions.SNICallback = lex.httpsOptions.SNICallback;
|
||||
var server = https.createServer(opts.httpsOptions);
|
||||
|
||||
server.on('error', function (err) {
|
||||
if (opts.errorPort || opts.manualPort) {
|
||||
showError(err, port);
|
||||
|
@ -71,8 +133,9 @@ function createServer(port, pubdir, content, opts) {
|
|||
server.listen(port, function () {
|
||||
opts.port = port;
|
||||
|
||||
opts.lrPort = 35729;
|
||||
var livereload = require('livereload');
|
||||
var server2 = livereload.createServer({ https: opts });
|
||||
var server2 = livereload.createServer({ https: opts.httpsOptions, port: opts.lrPort });
|
||||
|
||||
server2.watch(pubdir);
|
||||
|
||||
|
@ -90,6 +153,8 @@ function createServer(port, pubdir, content, opts) {
|
|||
}
|
||||
|
||||
server.on('request', function (req, res) {
|
||||
console.log('[' + req.method + '] ' + req.url);
|
||||
|
||||
if ('function' === typeof app) {
|
||||
app(req, res);
|
||||
return;
|
||||
|
@ -118,22 +183,23 @@ function run() {
|
|||
var tls = require('tls');
|
||||
|
||||
// letsencrypt
|
||||
var email = argv.email;
|
||||
var agreeTos = argv.agreeTos || argv['agree-tos'];
|
||||
|
||||
var cert = require('localhost.daplie.com-certificates');
|
||||
var opts = {
|
||||
key: cert.key
|
||||
, cert: cert.cert
|
||||
//, ca: cert.ca
|
||||
|
||||
, email: email
|
||||
, agreeTos: agreeTos
|
||||
agreeTos: argv.agreeTos || argv['agree-tos']
|
||||
, debug: argv.debug
|
||||
, email: argv.email
|
||||
, httpsOptions: {
|
||||
key: cert.key
|
||||
, cert: cert.cert
|
||||
//, ca: cert.ca
|
||||
}
|
||||
, argv: argv
|
||||
};
|
||||
var peerCa;
|
||||
var p;
|
||||
|
||||
opts.SNICallback = function (servername, cb) {
|
||||
cb(null, tls.createSecureContext(opts));
|
||||
opts.httpsOptions.SNICallback = function (servername, cb) {
|
||||
cb(null, tls.createSecureContext(opts.httpsOptions));
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -161,8 +227,8 @@ function run() {
|
|||
argv.root = [argv.root];
|
||||
}
|
||||
|
||||
opts.key = fs.readFileSync(argv.key);
|
||||
opts.cert = fs.readFileSync(argv.cert);
|
||||
opts.httpsOptions.key = fs.readFileSync(argv.key);
|
||||
opts.httpsOptions.cert = fs.readFileSync(argv.cert);
|
||||
|
||||
// turn multiple-cert pemfile into array of cert strings
|
||||
peerCa = argv.root.reduce(function (roots, fullpath) {
|
||||
|
@ -181,9 +247,9 @@ function run() {
|
|||
|
||||
// TODO * `--verify /path/to/root.pem` require peers to present certificates from said authority
|
||||
if (argv.verify) {
|
||||
opts.ca = peerCa;
|
||||
opts.requestCert = true;
|
||||
opts.rejectUnauthorized = true;
|
||||
opts.httpsOptions.ca = peerCa;
|
||||
opts.httpsOptions.requestCert = true;
|
||||
opts.httpsOptions.rejectUnauthorized = true;
|
||||
}
|
||||
|
||||
if (argv['serve-root']) {
|
||||
|
@ -208,6 +274,29 @@ function run() {
|
|||
opts.expressApp = require(path.resolve(process.cwd(), argv['express-app']));
|
||||
}
|
||||
|
||||
if (opts.email || opts.servername) {
|
||||
if (!opts.agreeTos) {
|
||||
console.warn("You may need to specify --agree-tos to agree to both the Let's Encrypt and Daplie DNS terms of service.");
|
||||
}
|
||||
if (!opts.email) {
|
||||
// TODO store email in .ddnsrc.json
|
||||
console.warn("You may need to specify --email to register with both the Let's Encrypt and Daplie DNS.");
|
||||
}
|
||||
p = DDNS.refreshToken({
|
||||
email: opts.email
|
||||
, silent: true
|
||||
}, {
|
||||
debug: false
|
||||
, email: opts.argv.email
|
||||
}).then(function (refreshToken) {
|
||||
opts.refreshToken = refreshToken;
|
||||
});
|
||||
}
|
||||
else {
|
||||
p = PromiseA.resolve();
|
||||
}
|
||||
|
||||
return p.then(function () {
|
||||
return createServer(port, pubdir, content, opts).then(function () {
|
||||
var msg;
|
||||
var p;
|
||||
|
@ -252,7 +341,7 @@ function run() {
|
|||
return promise.then(function (matchingIps) {
|
||||
if (matchingIps) {
|
||||
if (!matchingIps.length) {
|
||||
console.log("Neither the attached nor external interfaces match '" + argv.servername + "'");
|
||||
console.info("Neither the attached nor external interfaces match '" + argv.servername + "'");
|
||||
}
|
||||
opts.matchingIps = matchingIps || [];
|
||||
}
|
||||
|
@ -292,11 +381,11 @@ function run() {
|
|||
}
|
||||
console.info('\t' + httpsUrl);
|
||||
|
||||
httpsUrl = 'https://[' + iface.ipv6[0].address + ']';
|
||||
if (443 !== opts.port) {
|
||||
httpsUrl += ':' + opts.port;
|
||||
}
|
||||
if (iface.ipv6.length) {
|
||||
httpsUrl = 'https://[' + iface.ipv6[0].address + ']';
|
||||
if (443 !== opts.port) {
|
||||
httpsUrl += ':' + opts.port;
|
||||
}
|
||||
console.info('\t' + httpsUrl);
|
||||
}
|
||||
}
|
||||
|
@ -305,6 +394,7 @@ function run() {
|
|||
console.info('');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
|
|
Loading…
Reference in New Issue