From f9bcb1fafa783e225e432a27a3a18d324958536f Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Wed, 10 Aug 2016 16:31:25 -0400 Subject: [PATCH] updates --- lib/sni-callback.js | 94 ++++++++++++++++++++++++++++++--------------- master.js | 5 +-- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/lib/sni-callback.js b/lib/sni-callback.js index c226229..d70b879 100644 --- a/lib/sni-callback.js +++ b/lib/sni-callback.js @@ -1,9 +1,27 @@ 'use strict'; -// opts = { renewWithin, renew, register, httpsOptions } +// opts = { notBefore, notAfter, renew, register, httpsOptions } module.exports.create = function (opts) { + + if (!opts.notBefore) { throw new Error("must supply options.notBefore (and options.notAfter)"); } + if (!opts.notAfter) { opts.notAfter = opts.notBefore - (3 * 24 * 60 * 60 * 1000); } + if (!opts.httpsOptions) { opts.httpOptions = {}; } + + + + + //opts.renewWithin = opts.notBefore; // i.e. 15 days + opts.renewWindow = opts.notBefore - opts.notAfter; // i.e. 1 day + //opts.renewRatio = opts.notBefore = opts.renewWindow; // i.e. 1/15 (6.67%) + + + + var tls = require('tls'); + + + var snicb = { @@ -11,10 +29,6 @@ module.exports.create = function (opts) { // in-process cache _ipc: {} - - - - // just to account for clock skew , _fiveMin: 5 * 60 * 1000 @@ -23,22 +37,31 @@ module.exports.create = function (opts) { // cache and format incoming certs , cacheCerts: function (certs) { + var meta = { + certs: certs + , tlsContext: tls.createSecureContext({ + key: certs.privkey + , cert: certs.cert + certs.chain + , rejectUnauthorized: opts.httpsOptions.rejectUnauthorized + + , requestCert: opts.httpsOptions.requestCert // request peer verification + , ca: opts.httpsOptions.ca // this chain is for incoming peer connctions + , crl: opts.httpsOptions.crl // this crl is for incoming peer connections + }) + + , subject: certs.subject + // stagger renewal time by a little bit of randomness + , renewAt: (certs.expiresAt - (opts.notBefore - (opts.renewWindow * Math.random()))) + // err just barely on the side of safety + , expiresNear: certs.expiresAt - snicb._fiveMin + }; + certs.altnames.forEach(function (domain) { snicb._ipc[domain] = { subject: certs.subject }; }); - snicb._ipc[certs.subject] = certs; + snicb._ipc[certs.subject] = meta; - certs.tlsContext = tls.createSecureContext({ - key: certs.privkey - , cert: certs.cert + certs.chain - , rejectUnauthorized: opts.httpsOptions.rejectUnauthorized - - , requestCert: opts.httpsOptions.requestCert // request peer verification - , ca: opts.httpsOptions.ca // this chain is for incoming peer connctions - , crl: opts.httpsOptions.crl // this crl is for incoming peer connections - }); - - return certs; + return meta; } @@ -46,32 +69,39 @@ module.exports.create = function (opts) { // automate certificate registration on request , sniCallback: function (domain, cb) { - var certs = snicb._ipc[domain]; + var certMeta = snicb._ipc[domain]; var promise; var now = Date.now(); - if (certs && certs.subject !== domain) { - certs = snicb._ipc[domain]; + if (certMeta && certMeta.subject !== domain) { + certMeta = snicb._ipc[domain]; } - // err just barely on the side of safety - if (!certs) { + if (!certMeta) { + // we don't have a cert and must get one promise = opts.register(domain); } - else if (now >= (certs.expiresAt - snicb._fiveMin)) { - promise = opts.renew(domain, certs); - } - else { - if (now >= (certs.expiresAt - opts.renewWithin)) { - // in background - opts.renew(domain, certs).then(snicb.cacheCerts); + else if (now >= certMeta.expiresNear) { + // we have a cert, but it's no good for the average user + promise = opts.renew(domain, certMeta.certs); + } else { + + // we could stand to try to renew the cert + if (now >= certMeta.renewAt) { + // give the cert some time to be validated and replaced before trying again + certMeta.renewAt = Date.now() + (2 * 60 * 60 * 1000) + (3 * 60 * 60 * 1000 * Math.random()); + // let the update happen in the background + opts.renew(domain, certMeta.certs).then(snicb.cacheCerts); } - cb(null, certs); + + // return the valid cert right away + cb(null, certMeta.certs); return; } - promise.then(snicb.cacheCerts).then(function (certs) { - cb(null, certs.tlsContext); + // promise the non-existent or expired cert + promise.then(snicb.cacheCerts).then(function (certMeta) { + cb(null, certMeta.tlsContext); }, cb); } diff --git a/master.js b/master.js index d26fe37..5c3c179 100644 --- a/master.js +++ b/master.js @@ -2,8 +2,8 @@ module.exports.create = function (opts) { if (!opts.letsencrypt) { opts.letsencrypt = require('letsencrypt').create({ server: opts.server }); } - if ('function' === typeof opts.approve) { - throw new Error("You must provide opts.approve(options, certs, callback) to approve certificates"); + if ('function' !== typeof opts.approveDomains) { + throw new Error("You must provide opts.approveDomains(options, certs, callback) to approve certificates"); } function log(debug) { @@ -17,7 +17,6 @@ module.exports.create = function (opts) { console.log.apply(console, args); } - opts._pending = {}; opts._le = opts.letsencrypt; opts.addWorker = function (worker) {