From 4a389606b058ce1bc447550f42033883bb38fc30 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 4 Aug 2016 14:26:49 -0400 Subject: [PATCH] remove cruft --- README.md | 24 +-------- index.js | 136 ++++++++++-------------------------------------- lib/core.js | 145 +++++++++++++++++++++------------------------------- 3 files changed, 86 insertions(+), 219 deletions(-) diff --git a/README.md b/README.md index ab99848..222264b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Join the chat at https://gitter.im/Daplie/letsencrypt-express](https://badges.gitter.im/Daplie/letsencrypt-express.svg)](https://gitter.im/Daplie/letsencrypt-express?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | **letsencrypt** (library) -| [letsencrypt-cli](https://github.com/Daplie/letsencrypt-cli) +| [letsencrypt-cli](https://github.com/Daplie/letsencrypt-cli) | [letsencrypt-express](https://github.com/Daplie/letsencrypt-express) | [letsencrypt-koa](https://github.com/Daplie/letsencrypt-koa) | [letsencrypt-hapi](https://github.com/Daplie/letsencrypt-hapi) @@ -144,7 +144,6 @@ le.middleware() // middleware for serv le.sniCallback(hostname, function (err, tlsContext) {}) // uses fetch (below) and formats for https.SNICallback le.register({ domains, email, agreeTos, ... }, cb) // registers or renews certs for a domain le.fetch({domains, email, agreeTos, ... }, cb) // fetches certs from in-memory cache, occasionally refreshes from disk -le.validate(domains, cb) // do some sanity checks before attempting to register le.registrationFailureCallback(err, args, certInfo, cb) // called when registration fails (not implemented yet) ``` @@ -189,16 +188,6 @@ registration will take very little time. This will not be called while another registration is already in progress. -**SECURITY WARNING**: If you use this option with a custom `h.validate()`, make sure that `args.domains` -refers to domains you expect, otherwise an attacker will spoof SNI and cause your server to rate-limit -letsencrypt.org and get blocked. Note that `le.validate()` will check A records before attempting to -register to help prevent such possible attacks. - -`h.validate(domains, cb)` - -When specified this will override `le.validate()`. You will need to do this if the ip address of this -server is not one specified in the A records for your domain. - ### `le.middleware()` An express handler for `/.well-known/acme-challenge/`. @@ -252,17 +241,6 @@ returns `true` if `hostname` is a valid ascii or punycode domain name. (also exposed on the main exported module as `LetsEncrypt.isValidDomain()`) -### `le.validate(args, cb)` - -Used internally, but exposed for convenience. Checks `LetsEncrypt.isValidDomain()` -and then checks to see that the current server - -Called before `backend.register()` to validate the following: - - * the hostnames don't use any illegal characters - * the server's actual public ip (via api.apiify.org) - * the A records for said hostnames - ### `le.fetch(args, cb)` Used internally, but exposed for convenience. diff --git a/index.js b/index.js index f5914ae..f7233db 100644 --- a/index.js +++ b/index.js @@ -42,12 +42,6 @@ LE.tplConfigDir = require('./lib/common').tplConfigDir; // backend, defaults, handlers LE.create = function (defaults, handlers, backend) { - var d, b, h; - // backwards compat for <= v1.0.2 - if (defaults.registerAsync || defaults.create) { - b = defaults; d = handlers; h = backend; - defaults = d; handlers = h; backend = b; - } if (!backend) { backend = require('./lib/core'); } if (!handlers) { handlers = {}; } if (!handlers.lifetime) { handlers.lifetime = 90 * 24 * 60 * 60 * 1000; } @@ -148,63 +142,49 @@ LE.create = function (defaults, handlers, backend) { return jsobj; } - , validate: function (hostnames, cb) { - // TODO check dns, etc - if ((!hostnames.length && hostnames.every(le.isValidDomain))) { - cb(new Error("node-letsencrypt: invalid hostnames: " + hostnames.join(','))); + , register: function (args, cb) { + if (defaults.debug || args.debug) { + console.log('[LE] register'); + } + if (!Array.isArray(args.domains)) { + cb(new Error('args.domains should be an array of domains')); return; } - // - // IMPORTANT - // - // Before attempting a dynamic registration you need to validate that - // - // * these are hostnames that you expected to exist on the system - // * their A records currently point to this ip - // * this system's ip hasn't changed - // - // If you do not check these things, then someone could attack you - // and cause you, in return, to have your ip be rate-limit blocked - // - //console.warn("\n[TODO]: node-letsencrypt: `validate(hostnames, cb)` needs to be implemented"); - //console.warn("(it'll work fine without it, but for security - and convenience - it should be implemented\n"); - // UPDATE: - // it's actually probably better that we don't do this here and instead - // take care of it in the approveRegistrationCallback in letsencrypt-express - cb(null, true); - } - , _registerHelper: function (args, cb) { var copy = LE.merge(defaults, args); var err; if (!utils.isValidDomain(args.domains[0])) { - err = new Error("invalid domain"); + err = new Error("invalid domain name: '" + args.domains + "'"); err.code = "INVALID_DOMAIN"; cb(err); return; } - le.validate(args.domains, function (err) { - if (err) { - cb(err); - return; - } + if ((!args.domains.length && args.domains.every(le.isValidDomain))) { + // NOTE: this library can't assume to handle the http loopback + // (or dns-01 validation may be used) + // so we do not check dns records or attempt a loopback here + cb(new Error("node-letsencrypt: invalid hostnames: " + args.domains.join(','))); + return; + } + if (defaults.debug || args.debug) { + console.log("[NLE]: begin registration"); + } + + return backend.registerAsync(copy).then(function (pems) { if (defaults.debug || args.debug) { - console.log("[NLE]: begin registration"); + console.log("[NLE]: end registration"); } - - return backend.registerAsync(copy).then(function (pems) { - if (defaults.debug || args.debug) { - console.log("[NLE]: end registration"); - } - cb(null, pems); - //return le.fetch(args, cb); - }, cb); - }); + cb(null, pems); + //return le.fetch(args, cb); + }, cb); } - , _fetchHelper: function (args, cb) { + , fetch: function (args, cb) { + if (defaults.debug || args.debug) { + console.log('[LE] fetch'); + } return backend.fetchAsync(args).then(function (certInfo) { if (args.debug) { console.log('[LE] raw fetch certs', certInfo && Object.keys(certInfo)); @@ -224,19 +204,6 @@ LE.create = function (defaults, handlers, backend) { cb(null, certInfo); }, cb); } - , fetch: function (args, cb) { - if (defaults.debug || args.debug) { - console.log('[LE] fetch'); - } - le._fetchHelper(args, cb); - } - , renew: function (args, cb) { - if (defaults.debug || args.debug) { - console.log('[LE] renew'); - } - args.duplicate = false; - le.register(args, cb); - } , getConfig: function (args, cb) { if (defaults.debug || args.debug) { console.log('[LE] getConfig'); @@ -273,55 +240,6 @@ LE.create = function (defaults, handlers, backend) { cb(null, le.pyToJson(pyobj)); }); } - , register: function (args, cb) { - if (defaults.debug || args.debug) { - console.log('[LE] register'); - } - if (!Array.isArray(args.domains)) { - cb(new Error('args.domains should be an array of domains')); - return; - } - // this may be run in a cluster environment - // in that case it should NOT check the cache - // but ensure that it has the most fresh copy - // before attempting a renew - le._fetchHelper(args, function (err, hit) { - var now = Date.now(); - - if (err) { - // had a bad day - cb(err); - return; - } - else if (hit) { - if (!args.duplicate && (now - hit.issuedAt) < ((hit.lifetime || handlers.lifetime) * 0.65)) { - console.warn("\ntried to renew a certificate with over 1/3 of its lifetime left, ignoring"); - console.warn("(use --duplicate or opts.duplicate to override\n"); - cb(null, hit); - return; - } - } - - le._registerHelper(args, function (err/*, pems*/) { - if (err) { - cb(err); - return; - } - - // Sanity Check - le._fetchHelper(args, function (err, pems) { - if (pems) { - cb(null, pems); - return; - } - - // still couldn't read the certs after success... that's weird - console.error("still couldn't read certs after success... that's weird"); - cb(err, null); - }); - }); - }); - } }; return le; diff --git a/lib/core.js b/lib/core.js index 969d094..75f7dcd 100644 --- a/lib/core.js +++ b/lib/core.js @@ -45,8 +45,12 @@ function readRenewalConfig(args) { } function writeRenewalConfig(args) { - //console.log('args'); - //console.log(args); + function log() { + if (args.debug) { + console.log.apply(console, arguments); + } + } + var pyobj = args.pyobj; pyobj.checkpoints = parseInt(pyobj.checkpoints, 10) || 0; @@ -61,10 +65,7 @@ function writeRenewalConfig(args) { //|| args.domainPrivateKeyPath || args.domainKeyPath || pyobj.keyPath || path.join(liveDir, 'privkey.pem'); - if (args.debug) { - console.log('################ privkeyPath ################'); - console.log(privkeyPath); - } + log('[le/core.js] privkeyPath', privkeyPath); var updates = { account: args.account.id @@ -159,10 +160,14 @@ function getOrCreateRenewal(args) { } function writeCertificateAsync(args, defaults, handlers) { - if (args.debug) { - console.log("got certificate!"); + function log() { + if (args.debug) { + console.log.apply(console, arguments); + } } + log("[le/core.js] got certificate!"); + var obj = args.pyobj; var result = args.pems; @@ -178,9 +183,7 @@ function writeCertificateAsync(args, defaults, handlers) { //|| args.domainPrivateKeyPath || args.domainKeyPath || obj.keyPath || path.join(liveDir, 'privkey.pem'); - if (args.debug) { - console.log('[LE] privkeyPath', privkeyPath); - } + log('[le/core.js] privkeyPath', privkeyPath); var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]); @@ -252,39 +255,32 @@ function writeCertificateAsync(args, defaults, handlers) { } function getCertificateAsync(args, defaults, handlers) { + function log() { + if (args.debug || defaults.debug) { + console.log.apply(console, arguments); + } + } + var account = args.account; var promise; var keypairOpts = { public: true, pem: true }; - if (!args.domainKeyPath) { - // TODO use default path ??? - if (args.debug) { - console.log('[domainKeyPath]: none'); - } - promise = RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts); - } + log('[le/core.js] domainKeyPath:', args.domainKeyPath); - if (args.domainKeyPath) { - if (args.debug) { - console.log('[domainKeyPath]:', args.domainKeyPath); - } - promise = fs.readFileAsync(args.domainKeyPath, 'ascii').then(function (pem) { - return RSA.import({ privateKeyPem: pem }); - }, function (/*err*/) { - return RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts).then(function (keypair) { - return mkdirpAsync(path.dirname(args.domainKeyPath)).then(function () { - return fs.writeFileAsync(args.domainKeyPath, keypair.privateKeyPem, 'ascii').then(function () { - return keypair; - }); + promise = fs.readFileAsync(args.domainKeyPath, 'ascii').then(function (pem) { + return RSA.import({ privateKeyPem: pem }); + }, function (/*err*/) { + return RSA.generateKeypairAsync(args.rsaKeySize, 65537, keypairOpts).then(function (keypair) { + return mkdirpAsync(path.dirname(args.domainKeyPath)).then(function () { + return fs.writeFileAsync(args.domainKeyPath, keypair.privateKeyPem, 'ascii').then(function () { + return keypair; }); }); }); - } + }); return promise.then(function (domainKeypair) { - if (args.debug) { - console.log("[letsencrypt/lib/core.js] get certificate"); - } + log("[le/core.js] get certificate"); args.domainKeypair = domainKeypair; //args.registration = domainKey; @@ -346,35 +342,37 @@ function getCertificateAsync(args, defaults, handlers) { } function getOrCreateDomainCertificate(args, defaults, handlers) { + if (args.duplicate) { + // we're forcing a refresh via 'dupliate: true' + return getCertificateAsync(args, defaults, handlers); + } + return fetchFromConfigLiveDir(args).then(function (certs) { - // if nothing, register and save - // if something, check date (don't register unless 30+ days) - // if good, don't bother registering - // (but if we get to the point that we're actually calling - // this function, that shouldn't be the case, right?) - //console.log(certs); - if (!certs) { - // no certs, seems like a good time to get some + var halfLife = (certs.expiresAt - certs.issuedAt) / 2; + + if (!certs || (Date.now() - certs.issuedAt) > halfLife) { + // There is no cert available + // Or the cert is more than half-expired return getCertificateAsync(args, defaults, handlers); } - else if ((Date.now() - certs.issuedAt) > (27 * 24 * 60 * 60 * 1000)) { - // cert is at least 27 days old we can renew that - return getCertificateAsync(args, defaults, handlers); - } - else if (args.duplicate) { - // YOLO! I be gettin' fresh certs 'erday! Yo! - return getCertificateAsync(args, defaults, handlers); - } - else { - console.warn('[WARN] Ignoring renewal attempt for certificate less than 27 days old. Use args.duplicate to force.'); - // We're happy with what we have - return certs; - } + + return PromiseA.reject(new Error( + "[ERROR] Certificate issued at '" + + new Date(certs.issuedAt).toISOString() + "' and expires at '" + + new Date(certs.expiresAt).toISOString() + "'. Ignoring renewal attempt until half-life at '" + + new Date(certs.issuedA + halfLife).toISOString() + "'. Set { duplicate: true } to force." + )); }); } // returns 'account' from lib/accounts { meta, regr, keypair, accountId (id) } function getOrCreateAcmeAccount(args, defaults, handlers) { + function log() { + if (args.debug) { + console.log.apply(console, arguments); + } + } + var pyconf = PromiseA.promisifyAll(require('pyconf')); return pyconf.readFileAsync(args.renewalPath).then(function (renewal) { @@ -384,9 +382,7 @@ function getOrCreateAcmeAccount(args, defaults, handlers) { return accountId; }, function (err) { if ("ENOENT" === err.code) { - if (args.debug) { - console.log("[LE] try email"); - } + log("[le/core.js] try email"); return Accounts.getAccountIdByEmail(args, handlers); } @@ -398,15 +394,12 @@ function getOrCreateAcmeAccount(args, defaults, handlers) { args._acmeUrls = urls; if (accountId) { - if (args.debug) { - console.log('[LE] use account'); - } + log('[le/core.js] use account'); + args.accountId = accountId; return Accounts.getAccount(args, handlers); } else { - if (args.debug) { - console.log('[LE] create account'); - } + log('[le/core.js] create account'); return Accounts.createAccount(args, handlers); } }); @@ -417,9 +410,7 @@ function getOrCreateAcmeAccount(args, defaults, handlers) { return; } */ - if (args.debug) { - console.log('[LE] created account'); - } + log('[le/core.js] created account'); return account; }); /* @@ -448,10 +439,6 @@ module.exports.create = function (defaults, handlers) { copy = merge(args, defaults); tplCopy(copy); - if (copy.debug) { - console.log('[LE DEBUG] reg domains', args.domains); - } - var url = require('url'); var acmeLocation = url.parse(copy.server); var acmeHostpath = path.join(acmeLocation.hostname, acmeLocation.pathname); @@ -469,8 +456,6 @@ module.exports.create = function (defaults, handlers) { }).then(function (result) { return result; }, function (err) { - console.error('[DEBUG le/lib/core.js] registeryAsync err'); - console.error(err && err.stack || err); return PromiseA.reject(err); }); } @@ -478,9 +463,6 @@ module.exports.create = function (defaults, handlers) { var copy = merge(args, defaults); tplCopy(copy); - if (args.debug) { - console.log('[LE DEBUG] fetch domains', copy); - } return fetchFromConfigLiveDir(copy, defaults); } , configureAsync: function (hargs) { @@ -488,9 +470,6 @@ module.exports.create = function (defaults, handlers) { var copy = merge(hargs, defaults); tplCopy(copy); - //console.log('[LE] configureAsync copy'); - //console.log(hargs); - //console.log(copy); return getOrCreateAcmeAccount(copy, defaults, handlers).then(function (account) { copy.account = account; return getOrCreateRenewal(copy); @@ -503,10 +482,6 @@ module.exports.create = function (defaults, handlers) { var copy = merge(hargs, defaults); tplCopy(copy); - if (copy.debug) { - console.log('[LE DEBUG] get configs', copy); - } - return readRenewalConfig(copy).then(function (pyobj) { var exists = pyobj.checkpoints >= 0; if (!exists) { @@ -524,10 +499,6 @@ module.exports.create = function (defaults, handlers) { var copy = merge(hargs, defaults); tplCopy(copy); - if (copy.debug) { - console.log('[LE DEBUG] get configs', copy); - } - return fs.readdirAsync(copy.renewalDir).then(function (nodes) { nodes = nodes.filter(function (node) { return /^[a-z0-9]+.*\.conf$/.test(node);