v0.7.0: reduce scope of find()

This commit is contained in:
AJ ONeal 2019-10-30 07:59:41 +00:00
parent 0ebc958305
commit 116b4925e7
4 changed files with 127 additions and 48 deletions

View File

@ -11,15 +11,15 @@ var homedir = require('os').homedir();
var path = require('path'); var path = require('path');
var mkdirp = promisify(require('@root/mkdirp')); var mkdirp = promisify(require('@root/mkdirp'));
Manage.create = function(opts) { Manage.create = function(CONF) {
if (!opts) { if (!CONF) {
opts = {}; CONF = {};
} }
if (!opts.configFile) { if (!CONF.configFile) {
opts.configFile = '~/.config/greenlock/manager.json'; CONF.configFile = '~/.config/greenlock/manager.json';
console.info('Greenlock Manager Config File: ' + opts.configFile); console.info('Greenlock Manager Config File: ' + CONF.configFile);
} }
opts.configFile = opts.configFile.replace('~/', homedir + '/'); CONF.configFile = CONF.configFile.replace('~/', homedir + '/');
var manage = {}; var manage = {};
@ -28,7 +28,7 @@ Manage.create = function(opts) {
manage.defaults = manage.config = function(conf) { manage.defaults = manage.config = function(conf) {
// get / set default site settings such as // get / set default site settings such as
// subscriberEmail, store, challenges, renewOffset, renewStagger // subscriberEmail, store, challenges, renewOffset, renewStagger
return Manage._getLatest(manage, opts).then(function(config) { return Manage._getLatest(manage, CONF).then(function(config) {
if (!conf) { if (!conf) {
conf = JSON.parse(JSON.stringify(config)); conf = JSON.parse(JSON.stringify(config));
delete conf.sites; delete conf.sites;
@ -86,7 +86,7 @@ Manage.create = function(opts) {
manage.add = function(args) { manage.add = function(args) {
manage._txPromise = manage._txPromise.then(function() { manage._txPromise = manage._txPromise.then(function() {
// if the fs has changed since we last wrote, get the lastest from disk // if the fs has changed since we last wrote, get the lastest from disk
return Manage._getLatest(manage, opts).then(function(config) { return Manage._getLatest(manage, CONF).then(function(config) {
// TODO move to Greenlock.add // TODO move to Greenlock.add
var subscriberEmail = args.subscriberEmail; var subscriberEmail = args.subscriberEmail;
var subject = args.subject || args.domain; var subject = args.subject || args.domain;
@ -131,7 +131,11 @@ Manage.create = function(opts) {
altnames altnames
.slice(0) .slice(0)
.sort() .sort()
.join(' ') !== site.altnames.slice(0).sort().join(' ') .join(' ') !==
site.altnames
.slice(0)
.sort()
.join(' ')
) { ) {
// TODO signal to wait for renewal? // TODO signal to wait for renewal?
// it will definitely be renewed on the first request anyway // it will definitely be renewed on the first request anyway
@ -180,11 +184,11 @@ Manage.create = function(opts) {
manage.find = function(args) { manage.find = function(args) {
return _find(args).then(function(existing) { return _find(args).then(function(existing) {
if (!opts.find) { if (!CONF.find) {
return existing; return existing;
} }
return Promise.resolve(opts.find(args)).then(function(results) { return Promise.resolve(CONF.find(args)).then(function(results) {
// TODO also detect and delete stale (just ignoring them for now) // TODO also detect and delete stale (just ignoring them for now)
var changed = []; var changed = [];
var same = []; var same = [];
@ -192,7 +196,7 @@ Manage.create = function(opts) {
// Check lowercase subject names // Check lowercase subject names
var subject = (_newer.subject || '').toLowerCase(); var subject = (_newer.subject || '').toLowerCase();
// Set the default altnames to the subject, just in case // Set the default altnames to the subject, just in case
var altnames = _newer.altnames || []; var altnames = (_newer.altnames || []).slice(0);
if (!altnames.includes(subject)) { if (!altnames.includes(subject)) {
console.warn( console.warn(
"all site configs should include 'subject' and 'altnames': " + "all site configs should include 'subject' and 'altnames': " +
@ -220,7 +224,6 @@ Manage.create = function(opts) {
) { ) {
_older.renewAt = 0; _older.renewAt = 0;
_older.altnames = altnames; _older.altnames = altnames;
// TODO signal waitForRenewal (although it'll update on the first access automatically)
changed.push(_older); changed.push(_older);
} else { } else {
same.push(_older); same.push(_older);
@ -243,7 +246,7 @@ Manage.create = function(opts) {
} }
// kinda redundant to pull again, but whatever... // kinda redundant to pull again, but whatever...
return Manage._getLatest(manage, opts).then(function(config) { return Manage._getLatest(manage, CONF).then(function(config) {
changed.forEach(function(site) { changed.forEach(function(site) {
config.sites[site.subject] = site; config.sites[site.subject] = site;
}); });
@ -259,27 +262,27 @@ Manage.create = function(opts) {
}; };
function _find(args) { function _find(args) {
return Manage._getLatest(manage, opts).then(function(config) { return Manage._getLatest(manage, CONF).then(function(config) {
// i.e. find certs more than 30 days old // i.e. find certs more than 30 days old
//args.issuedBefore = Date.now() - 30 * 24 * 60 * 60 * 1000; //args.issuedBefore = Date.now() - 30 * 24 * 60 * 60 * 1000;
// i.e. find certs more that will expire in less than 45 days // i.e. find certs more that will expire in less than 45 days
//args.expiresBefore = Date.now() + 45 * 24 * 60 * 60 * 1000; //args.expiresBefore = Date.now() + 45 * 24 * 60 * 60 * 1000;
var issuedBefore = args.issuedBefore || Infinity; var issuedBefore = args.issuedBefore || Infinity;
var expiresBefore = args.expiresBefore || Infinity; //Date.now() + 21 * 24 * 60 * 60 * 1000; var expiresBefore = args.expiresBefore || Infinity; //Date.now() + 21 * 24 * 60 * 60 * 1000;
var all = !args.altnames; var nameKeys = ['subject', 'altnames'];
var altnames = (args.altnames || args.domains || []).slice(0); // if there's anything to match, only return matches
if (args.servername && !altnames.includes(args.servername)) { // if there's nothing to match, return everything
altnames.push(args.servername); var matchAll = !nameKeys.some(function(k) {
} return k in args;
if (args.wildname && !altnames.includes(args.wildname)) { });
altnames.push(args.wildname);
} var querynames = (args.altnames || []).slice(0);
// TODO match ANY domain on any cert // TODO match ANY domain on any cert
var sites = Object.keys(config.sites || {}) var sites = Object.keys(config.sites || {})
.filter(function(sub) { .filter(function(subject) {
var site = config.sites[sub]; var site = doctor.site(config.sites, subject);
if (site.deletedAt) { if (site.deletedAt) {
return false; return false;
} }
@ -290,20 +293,20 @@ Manage.create = function(opts) {
return false; return false;
} }
// after attribute filtering, before cert filtering
if (matchAll) {
return true;
}
// if subject is specified, don't return anything else // if subject is specified, don't return anything else
if (args.subject) { if (site.subject === args.subject) {
if (site.subject === args.subject) { return true;
return true;
}
} }
// altnames, servername, and wildname all get rolled into one // altnames, servername, and wildname all get rolled into one
return ( return site.altnames.some(function(altname) {
all || return querynames.includes(altname);
(site.altnames || []).some(function(name) { });
return altnames.includes(name);
})
);
}) })
.map(function(name) { .map(function(name) {
var site = config.sites[name]; var site = config.sites[name];
@ -326,7 +329,7 @@ Manage.create = function(opts) {
}); });
} }
manage.notify = opts.notify || _notify; manage.notify = CONF.notify || _notify;
function _notify(ev, args) { function _notify(ev, args) {
if (!args) { if (!args) {
args = ev; args = ev;
@ -378,7 +381,7 @@ Manage.create = function(opts) {
manage.update = function(args) { manage.update = function(args) {
manage._txPromise = manage._txPromise.then(function() { manage._txPromise = manage._txPromise.then(function() {
return Manage._getLatest(manage, opts).then(function(config) { return Manage._getLatest(manage, CONF).then(function(config) {
var site = config.sites[args.subject]; var site = config.sites[args.subject];
//site.issuedAt = args.issuedAt; //site.issuedAt = args.issuedAt;
//site.expiresAt = args.expiresAt; //site.expiresAt = args.expiresAt;
@ -394,7 +397,7 @@ Manage.create = function(opts) {
throw new Error('should have a subject for sites to remove'); throw new Error('should have a subject for sites to remove');
} }
manage._txPromise = manage._txPromise.then(function() { manage._txPromise = manage._txPromise.then(function() {
return Manage._getLatest(manage, opts).then(function(config) { return Manage._getLatest(manage, CONF).then(function(config) {
var site = config.sites[args.subject]; var site = config.sites[args.subject];
if (!site) { if (!site) {
return {}; return {};
@ -414,22 +417,22 @@ Manage.create = function(opts) {
manage._config = {}; manage._config = {};
manage._save = function(config) { manage._save = function(config) {
return mkdirp(path.dirname(opts.configFile)).then(function() { return mkdirp(path.dirname(CONF.configFile)).then(function() {
return sfs return sfs
.writeFileAsync( .writeFileAsync(
opts.configFile, CONF.configFile,
// pretty-print the config file // pretty-print the config file
JSON.stringify(config, null, 2), JSON.stringify(config, null, 2),
'utf8' 'utf8'
) )
.then(function() { .then(function() {
// this file may contain secrets, so keep it safe // this file may contain secrets, so keep it safe
return chmodFile(opts.configFile, parseInt('0600', 8)) return chmodFile(CONF.configFile, parseInt('0600', 8))
.catch(function() { .catch(function() {
/*ignore for Windows */ /*ignore for Windows */
}) })
.then(function() { .then(function() {
return statFile(opts.configFile).then(function( return statFile(CONF.configFile).then(function(
stat stat
) { ) {
manage._lastStat.size = stat.size; manage._lastStat.size = stat.size;
@ -443,8 +446,8 @@ Manage.create = function(opts) {
return manage; return manage;
}; };
Manage._getLatest = function(mng, opts) { Manage._getLatest = function(mng, CONF) {
return statFile(opts.configFile) return statFile(CONF.configFile)
.catch(function(err) { .catch(function(err) {
if ('ENOENT' === err.code) { if ('ENOENT' === err.code) {
return { return {
@ -462,10 +465,34 @@ Manage._getLatest = function(mng, opts) {
) { ) {
return mng._config; return mng._config;
} }
return readFile(opts.configFile, 'utf8').then(function(data) { return readFile(CONF.configFile, 'utf8').then(function(data) {
mng._lastStat = stat; mng._lastStat = stat;
mng._config = JSON.parse(data); mng._config = JSON.parse(data);
return mng._config; return mng._config;
}); });
}); });
}; };
var doctor = {};
// users muck up config files, so we try to handle it gracefully.
doctor.site = function(sconfs, subject) {
var site = sconfs[subject];
if (!site) {
delete sconfs[subject];
site = {};
}
// TODO notify on any changes
if ('string' !== typeof site.subject) {
delete sconfs[subject];
site.subject = 'greenlock-error.example.com';
}
if (!Array.isArray(site.altnames)) {
site.altnames = [site.subject];
}
if (!site.renewAt) {
site.renewAt = 1;
}
return site;
};

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "greenlock-manager-fs", "name": "greenlock-manager-fs",
"version": "0.6.3", "version": "0.7.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "greenlock-manager-fs", "name": "greenlock-manager-fs",
"version": "0.6.5", "version": "0.7.0",
"description": "A simple file-based management strategy for Greenlock", "description": "A simple file-based management strategy for Greenlock",
"main": "manager.js", "main": "manager.js",
"scripts": { "scripts": {

52
test.js Normal file
View File

@ -0,0 +1,52 @@
'use strict';
var Manager = require('./');
var manager = Manager.create({
configFile: 'greenlock-manager-test.delete-me.json'
});
var domains = ['example.com', 'www.example.com'];
async function run() {
await manager.add({
subject: domains[0],
altnames: domains
});
await manager.find({}).then(function(results) {
if (!results.length) {
console.log(results);
throw new Error('should have found all managed sites');
}
});
await manager.find({ subject: 'www.example.com' }).then(function(results) {
if (results.length) {
console.log(results);
throw new Error(
"shouldn't find what doesn't exist, exactly, by subject"
);
}
});
await manager
.find({ altnames: ['www.example.com'] })
.then(function(results) {
if (!results.length) {
console.log(results);
throw new Error('should have found sites matching altname');
}
});
await manager.find({ altnames: ['*.example.com'] }).then(function(results) {
if (results.length) {
console.log(results);
throw new Error(
'should only find an exact (literal) wildcard match'
);
}
});
console.log("PASS");
}
run();