allow for partial manager
This commit is contained in:
parent
af3a2f621c
commit
7313167ca0
|
@ -1,3 +1,4 @@
|
|||
greenlock.json*
|
||||
TODO.txt
|
||||
link.sh
|
||||
.env
|
||||
|
|
75
bin/init.js
75
bin/init.js
|
@ -21,20 +21,15 @@ cli.main(async function(argList, flags) {
|
|||
var pkgpath = path.join(process.cwd(), 'package.json');
|
||||
var pkgdir = path.dirname(pkgpath);
|
||||
//var rcpath = path.join(pkgpath, '.greenlockrc');
|
||||
var configFile = path.join(pkgdir, 'greenlock.d/manager.json');
|
||||
var manager = flags.manager;
|
||||
|
||||
// TODO move to bin/lib/greenlockrc.js
|
||||
if (!manager) {
|
||||
manager = 'greenlock-cloud-fs';
|
||||
if (!flags.managerOpts.configFile) {
|
||||
flags.managerOpts.configFile = configFile;
|
||||
}
|
||||
}
|
||||
if (['fs', 'cloud'].includes(manager)) {
|
||||
// TODO publish the 1st party modules under a secure namespace
|
||||
flags.manager = '@greenlock/manager-' + flags.manager;
|
||||
manager = '@greenlock/manager';
|
||||
}
|
||||
if (['cloud'].includes(manager)) {
|
||||
flags.managerOpts.cloud = true;
|
||||
}
|
||||
|
||||
flags.manager = flags.managerOpts;
|
||||
delete flags.managerOpts;
|
||||
flags.manager.manager = manager;
|
||||
|
@ -57,6 +52,7 @@ cli.main(async function(argList, flags) {
|
|||
var GreenlockRc = require('./lib/greenlockrc.js');
|
||||
//var rc = await GreenlockRc(pkgpath, manager, flags.manager);
|
||||
await GreenlockRc(pkgpath, manager, flags.manager);
|
||||
writeGreenlockJs(pkgdir, flags);
|
||||
writeServerJs(pkgdir, flags);
|
||||
writeAppJs(pkgdir);
|
||||
|
||||
|
@ -70,9 +66,41 @@ cli.main(async function(argList, flags) {
|
|||
*/
|
||||
}, args);
|
||||
|
||||
function writeGreenlockJs(pkgdir, flags) {
|
||||
var greenlockJs = 'greenlock.js';
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var tmpl = fs.readFileSync(
|
||||
path.join(__dirname, 'tmpl/greenlock.tmpl.js'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
try {
|
||||
fs.accessSync(path.join(pkgdir, greenlockJs));
|
||||
console.warn("[skip] '%s' exists", greenlockJs);
|
||||
return;
|
||||
} catch (e) {
|
||||
// continue
|
||||
}
|
||||
|
||||
if (flags.cluster) {
|
||||
tmpl = tmpl.replace(
|
||||
/options.cluster = false/g,
|
||||
'options.cluster = true'
|
||||
);
|
||||
}
|
||||
if (flags.maintainerEmail) {
|
||||
tmpl = tmpl.replace(
|
||||
/pkg.author/g,
|
||||
JSON.stringify(flags.maintainerEmail)
|
||||
);
|
||||
}
|
||||
fs.writeFileSync(path.join(pkgdir, greenlockJs), tmpl);
|
||||
console.info("created '%s'", greenlockJs);
|
||||
}
|
||||
|
||||
function writeServerJs(pkgdir, flags) {
|
||||
var serverJs = 'server.js';
|
||||
var bakTmpl = 'server-greenlock-tmpl.js';
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var tmpl = fs.readFileSync(
|
||||
|
@ -82,13 +110,8 @@ function writeServerJs(pkgdir, flags) {
|
|||
|
||||
try {
|
||||
fs.accessSync(path.join(pkgdir, serverJs));
|
||||
console.warn(
|
||||
JSON.stringify(serverJs),
|
||||
' exists, writing to ',
|
||||
JSON.stringify(bakTmpl),
|
||||
'instead'
|
||||
);
|
||||
serverJs = bakTmpl;
|
||||
console.warn("[skip] '%s' exists", serverJs);
|
||||
return;
|
||||
} catch (e) {
|
||||
// continue
|
||||
}
|
||||
|
@ -106,10 +129,10 @@ function writeServerJs(pkgdir, flags) {
|
|||
);
|
||||
}
|
||||
fs.writeFileSync(path.join(pkgdir, serverJs), tmpl);
|
||||
console.info("created '%s'", serverJs);
|
||||
}
|
||||
|
||||
function writeAppJs(pkgdir) {
|
||||
var bakTmpl = 'app-greenlock-tmpl.js';
|
||||
var appJs = 'app.js';
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
@ -120,16 +143,10 @@ function writeAppJs(pkgdir) {
|
|||
|
||||
try {
|
||||
fs.accessSync(path.join(pkgdir, appJs));
|
||||
console.warn(
|
||||
JSON.stringify(appJs),
|
||||
' exists, writing to ',
|
||||
JSON.stringify(bakTmpl),
|
||||
'instead'
|
||||
);
|
||||
appJs = bakTmpl;
|
||||
console.warn("[skip] '%s' exists", appJs);
|
||||
return;
|
||||
} catch (e) {
|
||||
// continue
|
||||
fs.writeFileSync(path.join(pkgdir, appJs), tmpl);
|
||||
console.info("created '%s'", appJs);
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(pkgdir, appJs), tmpl);
|
||||
}
|
||||
|
|
|
@ -93,10 +93,11 @@ module.exports = async function(pkgpath, manager, rc) {
|
|||
});
|
||||
}
|
||||
|
||||
if (!_rc.manager) {
|
||||
changed = true;
|
||||
_rc.manager = 'greenlock-manager-fs';
|
||||
console.info('Using default manager ' + _rc.manager);
|
||||
if (['@greenlock/manager', 'greenlock-manager-fs'].includes(_rc.manager)) {
|
||||
if (!_rc.configFile) {
|
||||
changed = true;
|
||||
_rc.configFile = path.join(pkgdir, 'greenlock.json');
|
||||
}
|
||||
}
|
||||
|
||||
if (!changed) {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = require('greenlock').create(init());
|
||||
|
||||
function init() {
|
||||
// .greenlockrc defines which manager to use
|
||||
// (i.e. greenlock-manager-fs or greenlock-manager-cloud)
|
||||
var options = getGreenlockRc() || {};
|
||||
|
||||
// name & version for ACME client user agent
|
||||
var pkg = require('./package.json');
|
||||
options.packageAgent = pkg.name + '/' + pkg.version;
|
||||
|
||||
// contact for security and critical bug notices
|
||||
options.maintainerEmail = pkg.author;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function getGreenlockRc() {
|
||||
// The RC file is also used by the (optional) CLI and (optional) Web GUI.
|
||||
// You are free to forego CLI and GUI support.
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var rcPath = path.join(__dirname, '.greenlockrc');
|
||||
var rc = fs.readFileSync(rcPath, 'utf8');
|
||||
rc = JSON.parse(rc);
|
||||
rc.packageRoot = __dirname;
|
||||
}
|
|
@ -33,5 +33,6 @@ function getGreenlockRc() {
|
|||
var path = require('path');
|
||||
var rcPath = path.join(__dirname, '.greenlockrc');
|
||||
var rc = fs.readFileSync(rcPath, 'utf8');
|
||||
return JSON.parse(rc);
|
||||
rc = JSON.parse(rc);
|
||||
rc.packageRoot = __dirname;
|
||||
}
|
||||
|
|
139
greenlock.js
139
greenlock.js
|
@ -23,7 +23,6 @@ G.create = function(gconf) {
|
|||
if (!gconf) {
|
||||
gconf = {};
|
||||
}
|
||||
var manager;
|
||||
|
||||
greenlock._create = function() {
|
||||
if (!gconf._bin_mode) {
|
||||
|
@ -65,15 +64,14 @@ G.create = function(gconf) {
|
|||
}
|
||||
console.info('ACME Directory URL:', gdefaults.directoryUrl);
|
||||
|
||||
manager = normalizeManager(gconf);
|
||||
|
||||
// Wraps each of the following with appropriate error checking
|
||||
// greenlock.manager.defaults
|
||||
// greenlock.manager.add
|
||||
// greenlock.manager.update
|
||||
// greenlock.manager.remove
|
||||
// greenlock.manager.find
|
||||
require('./manager-underlay.js').wrap(greenlock, manager, gconf);
|
||||
// greenlock.sites.add
|
||||
// greenlock.sites.update
|
||||
// greenlock.sites.remove
|
||||
// greenlock.sites.find
|
||||
// greenlock.sites.get
|
||||
require('./manager-underlay.js').wrap(greenlock, gconf);
|
||||
// The goal here is to reduce boilerplate, such as error checking
|
||||
// and duration parsing, that a manager must implement
|
||||
greenlock.sites.add = greenlock.add = greenlock.manager.add;
|
||||
|
@ -83,7 +81,7 @@ G.create = function(gconf) {
|
|||
// Exports challenges.get for Greenlock Express HTTP-01,
|
||||
// and whatever odd use case pops up, I suppose
|
||||
// greenlock.challenges.get
|
||||
require('./challenges-underlay.js').wrap(greenlock, manager, gconf);
|
||||
require('./challenges-underlay.js').wrap(greenlock);
|
||||
|
||||
greenlock._defaults = gdefaults;
|
||||
greenlock._defaults.debug = gconf.debug;
|
||||
|
@ -108,25 +106,20 @@ G.create = function(gconf) {
|
|||
return p;
|
||||
};
|
||||
|
||||
if (manager.init) {
|
||||
// TODO punycode?
|
||||
p = manager.init({
|
||||
p = greenlock.manager
|
||||
.init({
|
||||
request: request
|
||||
//punycode: require('punycode')
|
||||
});
|
||||
} else {
|
||||
p = Promise.resolve();
|
||||
}
|
||||
p = p
|
||||
})
|
||||
.then(function() {
|
||||
return manager.defaults().then(function(MCONF) {
|
||||
return greenlock.manager._defaults().then(function(MCONF) {
|
||||
mergeDefaults(MCONF, gconf);
|
||||
if (true === MCONF.agreeToTerms) {
|
||||
gdefaults.agreeToTerms = function(tos) {
|
||||
return Promise.resolve(tos);
|
||||
};
|
||||
}
|
||||
return manager.defaults(MCONF);
|
||||
return greenlock.manager._defaults(MCONF);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
|
@ -278,7 +271,7 @@ G.create = function(gconf) {
|
|||
|
||||
greenlock._config = function(args) {
|
||||
return greenlock._single(args).then(function() {
|
||||
return greenlock._configAll(args).then(function (sites) {
|
||||
return greenlock._configAll(args).then(function(sites) {
|
||||
return sites[0];
|
||||
});
|
||||
});
|
||||
|
@ -289,7 +282,7 @@ G.create = function(gconf) {
|
|||
return null;
|
||||
}
|
||||
sites = JSON.parse(JSON.stringify(sites));
|
||||
return manager.defaults().then(function(mconf) {
|
||||
return greenlock.manager._defaults().then(function(mconf) {
|
||||
return sites.map(function(site) {
|
||||
if (site.store && site.challenges) {
|
||||
return site;
|
||||
|
@ -314,7 +307,7 @@ G.create = function(gconf) {
|
|||
// needs to get info about the renewal, such as which store and challenge(s) to use
|
||||
greenlock.renew = function(args) {
|
||||
return greenlock._init().then(function() {
|
||||
return manager.defaults().then(function(mconf) {
|
||||
return greenlock.manager._defaults().then(function(mconf) {
|
||||
return greenlock._renew(mconf, args);
|
||||
});
|
||||
});
|
||||
|
@ -418,7 +411,7 @@ G.create = function(gconf) {
|
|||
|
||||
greenlock.order = function(args) {
|
||||
return greenlock._init().then(function() {
|
||||
return manager.defaults().then(function(mconf) {
|
||||
return greenlock.manager._defaults().then(function(mconf) {
|
||||
return greenlock._order(mconf, args);
|
||||
});
|
||||
});
|
||||
|
@ -485,106 +478,6 @@ function errorToJSON(e) {
|
|||
return error;
|
||||
}
|
||||
|
||||
function normalizeManager(gconf) {
|
||||
var m;
|
||||
// 1. Get the manager
|
||||
// 2. Figure out if we need to wrap it
|
||||
|
||||
if (!gconf.manager) {
|
||||
gconf.manager = 'greenlock-manager-fs';
|
||||
if (gconf.find) {
|
||||
// { manager: 'greenlock-manager-fs', find: function () { } }
|
||||
warpFind(gconf);
|
||||
}
|
||||
}
|
||||
|
||||
if ('string' === typeof gconf.manager) {
|
||||
try {
|
||||
// wrap this to be safe for greenlock-manager-fs
|
||||
m = require(gconf.manager).create(gconf);
|
||||
} catch (e) {
|
||||
console.error('Error loading manager:');
|
||||
console.error(e.code);
|
||||
console.error(e.message);
|
||||
}
|
||||
} else {
|
||||
m = gconf.manager;
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
console.error();
|
||||
console.error(
|
||||
'Failed to load manager plugin ',
|
||||
JSON.stringify(gconf.manager)
|
||||
);
|
||||
console.error();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (
|
||||
['set', 'remove', 'find', 'defaults'].every(function(k) {
|
||||
return 'function' === typeof m[k];
|
||||
})
|
||||
) {
|
||||
return m;
|
||||
}
|
||||
|
||||
// { manager: { find: function () { } } }
|
||||
if (m.find) {
|
||||
warpFind(m);
|
||||
}
|
||||
// m.configFile could also be set
|
||||
m = require('greenlock-manager-fs').create(m);
|
||||
|
||||
if ('function' !== typeof m.find) {
|
||||
console.error();
|
||||
console.error(
|
||||
JSON.stringify(gconf.manager),
|
||||
'must implement `find()` and should implement `set()`, `remove()`, `defaults()`, and `init()`'
|
||||
);
|
||||
console.error();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
function warpFind(gconf) {
|
||||
gconf.__gl_find = gconf.find;
|
||||
gconf.find = function(args) {
|
||||
// the incoming args will be normalized by greenlock
|
||||
return gconf.__gl_find(args).then(function(sites) {
|
||||
// we also need to error check the incoming sites,
|
||||
// as if they were being passed through `add()` or `set()`
|
||||
// (effectively they are) because the manager assumes that
|
||||
// they're not bad
|
||||
sites.forEach(function(s) {
|
||||
if (!s || 'string' !== typeof s.subject) {
|
||||
throw new Error('missing subject');
|
||||
}
|
||||
if (
|
||||
!Array.isArray(s.altnames) ||
|
||||
!s.altnames.length ||
|
||||
!s.altnames[0] ||
|
||||
s.altnames[0] !== s.subject
|
||||
) {
|
||||
throw new Error('missing or malformed altnames');
|
||||
}
|
||||
['renewAt', 'issuedAt', 'expiresAt'].forEach(function(k) {
|
||||
if (s[k]) {
|
||||
throw new Error(
|
||||
'`' +
|
||||
k +
|
||||
'` should be updated by `set()`, not by `find()`'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
return sites;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function mergeDefaults(MCONF, gconf) {
|
||||
if (
|
||||
gconf.agreeToTerms === true ||
|
||||
|
|
|
@ -5,7 +5,15 @@ var E = require('./errors.js');
|
|||
|
||||
var warned = {};
|
||||
|
||||
module.exports.wrap = function(greenlock, manager, gconf) {
|
||||
// The purpose of this file is to try to auto-build
|
||||
// partial managers so that the external API can be smaller.
|
||||
|
||||
module.exports.wrap = function(greenlock, gconf) {
|
||||
var myFind = gconf.find;
|
||||
delete gconf.find;
|
||||
|
||||
var mega = mergeManager(gconf);
|
||||
|
||||
greenlock.manager = {};
|
||||
greenlock.sites = {};
|
||||
//greenlock.accounts = {};
|
||||
|
@ -31,7 +39,7 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
|||
greenlock.manager.defaults = function(conf) {
|
||||
return greenlock._init().then(function() {
|
||||
if (!conf) {
|
||||
return manager.defaults();
|
||||
return mega.defaults();
|
||||
}
|
||||
|
||||
if (conf.sites) {
|
||||
|
@ -83,9 +91,10 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
|||
}
|
||||
});
|
||||
|
||||
return manager.defaults(conf);
|
||||
return mega.defaults(conf);
|
||||
});
|
||||
};
|
||||
greenlock.manager._defaults = mega.defaults;
|
||||
|
||||
greenlock.manager.add = function(args) {
|
||||
if (!args || !Array.isArray(args.altnames) || !args.altnames.length) {
|
||||
|
@ -142,7 +151,7 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
|||
args.renewStagger = U._parseDuration(args.renewStagger);
|
||||
}
|
||||
|
||||
return manager.set(args).then(function(result) {
|
||||
return mega.set(args).then(function(result) {
|
||||
if (!gconf._bin_mode) {
|
||||
greenlock.renew({}).catch(function(err) {
|
||||
if (!err.context) {
|
||||
|
@ -157,6 +166,22 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
|||
});
|
||||
};
|
||||
|
||||
greenlock.manager.get = greenlock.sites.get = function(args) {
|
||||
return Promise.resolve().then(function() {
|
||||
if (args.subject) {
|
||||
throw new Error(
|
||||
'get({ servername }) searches certificates by altnames, not by subject specifically'
|
||||
);
|
||||
}
|
||||
if (args.servernames || args.altnames || args.renewBefore) {
|
||||
throw new Error(
|
||||
'get({ servername }) does not take arguments that could lead to multiple results'
|
||||
);
|
||||
}
|
||||
return mega.get(args);
|
||||
});
|
||||
};
|
||||
|
||||
greenlock.manager.remove = function(args) {
|
||||
return Promise.resolve().then(function() {
|
||||
args.subject = checkSubject(args);
|
||||
|
@ -171,57 +196,137 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
|||
);
|
||||
}
|
||||
// TODO check no altnames
|
||||
return manager.remove(args);
|
||||
return mega.remove(args);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
{
|
||||
subject: site.subject,
|
||||
altnames: site.altnames,
|
||||
//issuedAt: site.issuedAt,
|
||||
//expiresAt: site.expiresAt,
|
||||
renewOffset: site.renewOffset,
|
||||
renewStagger: site.renewStagger,
|
||||
renewAt: site.renewAt,
|
||||
subscriberEmail: site.subscriberEmail,
|
||||
customerEmail: site.customerEmail,
|
||||
challenges: site.challenges,
|
||||
store: site.store
|
||||
};
|
||||
*/
|
||||
{
|
||||
subject: site.subject,
|
||||
altnames: site.altnames,
|
||||
//issuedAt: site.issuedAt,
|
||||
//expiresAt: site.expiresAt,
|
||||
renewOffset: site.renewOffset,
|
||||
renewStagger: site.renewStagger,
|
||||
renewAt: site.renewAt,
|
||||
subscriberEmail: site.subscriberEmail,
|
||||
customerEmail: site.customerEmail,
|
||||
challenges: site.challenges,
|
||||
store: site.store
|
||||
};
|
||||
*/
|
||||
|
||||
greenlock._find = function(args) {
|
||||
var servernames = (args.servernames || [])
|
||||
.concat(args.altnames || [])
|
||||
.filter(Boolean)
|
||||
.slice(0);
|
||||
var modified = servernames.slice(0);
|
||||
// no transaction promise here because it calls set
|
||||
greenlock._find = async function(args) {
|
||||
args = _mangleFindArgs(args);
|
||||
var ours = await mega.find(args);
|
||||
if (!myFind) {
|
||||
return ours;
|
||||
}
|
||||
|
||||
// servername, wildname, and altnames are all the same
|
||||
['wildname', 'servername'].forEach(function(k) {
|
||||
var altname = args[k] || '';
|
||||
if (altname && !modified.includes(altname)) {
|
||||
modified.push(altname);
|
||||
// if the user has an overlay find function we'll do a diff
|
||||
// between the managed state and the overlay, and choose
|
||||
// what was found.
|
||||
var theirs = await myFind(args);
|
||||
theirs = theirs.filter(function(site) {
|
||||
if (!site || 'string' !== typeof site.subject) {
|
||||
throw new Error('found site is missing subject');
|
||||
}
|
||||
if (
|
||||
!Array.isArray(site.altnames) ||
|
||||
!site.altnames.length ||
|
||||
!site.altnames[0] ||
|
||||
site.altnames[0] !== site.subject
|
||||
) {
|
||||
throw new Error('missing or malformed altnames');
|
||||
}
|
||||
['renewAt', 'issuedAt', 'expiresAt'].forEach(function(k) {
|
||||
if (site[k]) {
|
||||
throw new Error(
|
||||
'`' +
|
||||
k +
|
||||
'` should be updated by `set()`, not by `find()`'
|
||||
);
|
||||
}
|
||||
});
|
||||
if (!site) {
|
||||
return;
|
||||
}
|
||||
if (args.subject && site.subject !== args.subject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var servernames = args.servernames || args.altnames;
|
||||
if (
|
||||
servernames &&
|
||||
!site.altnames.some(function(altname) {
|
||||
return servernames.includes(altname);
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return site.renewAt < (args.renewBefore || Infinity);
|
||||
});
|
||||
return _mergeFind(ours, theirs);
|
||||
};
|
||||
|
||||
function _mergeFind(ours, theirs) {
|
||||
var toUpdate = [];
|
||||
theirs.forEach(function(_newer) {
|
||||
var hasCurrent = ours.some(function(_older) {
|
||||
var changed = false;
|
||||
if (_newer.subject !== _older.subject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// BE SURE TO SET THIS UNDEFINED AFTERWARDS
|
||||
_older._exists = true;
|
||||
|
||||
_newer.deletedAt = _newer.deletedAt || 0;
|
||||
Object.keys(_newer).forEach(function(k) {
|
||||
if (_older[k] !== _newer[k]) {
|
||||
changed = true;
|
||||
_older[k] = _newer[k];
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
toUpdate.push(_older);
|
||||
}
|
||||
|
||||
// handled the (only) match
|
||||
return true;
|
||||
});
|
||||
if (!hasCurrent) {
|
||||
toUpdate.push(_newer);
|
||||
}
|
||||
});
|
||||
|
||||
if (modified.length) {
|
||||
servernames = modified;
|
||||
servernames = servernames.altnames.map(U._encodeName);
|
||||
args.altnames = servernames;
|
||||
args.servernames = args.altnames = checkAltnames(false, args);
|
||||
}
|
||||
// delete the things that are gone
|
||||
ours.forEach(function(_older) {
|
||||
if (!_older._exists) {
|
||||
_older.deletedAt = Date.now();
|
||||
toUpdate.push(_older);
|
||||
}
|
||||
_older._exists = undefined;
|
||||
});
|
||||
|
||||
// documented as args.servernames
|
||||
// preserved as args.altnames for v3 beta backwards compat
|
||||
// my only hesitancy in this choice is that a "servername"
|
||||
// may NOT contain '*.', in which case `altnames` is a better choice.
|
||||
// However, `altnames` is ambiguous - as if it means to find a
|
||||
// certificate by that specific collection of altnames.
|
||||
// ... perhaps `domains` could work?
|
||||
return manager.find(args);
|
||||
};
|
||||
Promise.all(
|
||||
toUpdate.map(function(site) {
|
||||
return greenlock.sites.update(site).catch(function(err) {
|
||||
console.error(
|
||||
'Developer Error: cannot update sites from user-supplied `find()`:'
|
||||
);
|
||||
console.error(err);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
// ours is updated from theirs
|
||||
return ours;
|
||||
}
|
||||
|
||||
greenlock.manager.init = mega.init;
|
||||
};
|
||||
|
||||
function checkSubject(args) {
|
||||
|
@ -284,3 +389,185 @@ function checkAltnames(subject, args) {
|
|||
|
||||
return altnames;
|
||||
}
|
||||
|
||||
function loadManager(gconf) {
|
||||
var m;
|
||||
// 1. Get the manager
|
||||
// 2. Figure out if we need to wrap it
|
||||
|
||||
if (!gconf.manager) {
|
||||
gconf.manager = '@greenlock/manager';
|
||||
}
|
||||
|
||||
if ('string' !== typeof gconf.manager) {
|
||||
throw new Error(
|
||||
'`manager` should be a string representing the npm name or file path of the module'
|
||||
);
|
||||
}
|
||||
try {
|
||||
// wrap this to be safe for @greenlock/manager
|
||||
m = require(gconf.manager).create(gconf);
|
||||
} catch (e) {
|
||||
console.error('Error loading manager:');
|
||||
console.error(e.code);
|
||||
console.error(e.message);
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
console.error();
|
||||
console.error(
|
||||
'Failed to load manager plugin ',
|
||||
JSON.stringify(gconf.manager)
|
||||
);
|
||||
console.error();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
function mergeManager(gconf) {
|
||||
var mng;
|
||||
function m() {
|
||||
if (mng) {
|
||||
return mng;
|
||||
}
|
||||
mng = require('@greenlock/manager').create(gconf);
|
||||
return mng;
|
||||
}
|
||||
|
||||
var mini = loadManager(gconf);
|
||||
var mega = {};
|
||||
// optional
|
||||
if (mini.defaults) {
|
||||
mega.defaults = function(opts) {
|
||||
return mini.defaults(opts);
|
||||
};
|
||||
} else {
|
||||
mega.defaults = m().defaults;
|
||||
}
|
||||
|
||||
// optional
|
||||
if (mini.remove) {
|
||||
mega.remove = function(opts) {
|
||||
return mini.remove(opts);
|
||||
};
|
||||
} else {
|
||||
mega.remove = function(opts) {
|
||||
mega.get(opts).then(function(site) {
|
||||
if (!site) {
|
||||
return null;
|
||||
}
|
||||
site.deletedAt = Date.now();
|
||||
return mega.set(site).then(function() {
|
||||
return site;
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (mini.find) {
|
||||
// without this there cannot be fully automatic renewal
|
||||
mega.find = function(opts) {
|
||||
return mini.find(opts);
|
||||
};
|
||||
}
|
||||
|
||||
// set and (find and/or get) should be from the same set
|
||||
if (mini.set) {
|
||||
mega.set = function(opts) {
|
||||
if (!mini.find) {
|
||||
// TODO create the list so that find can be implemented
|
||||
}
|
||||
return mini.set(opts);
|
||||
};
|
||||
} else {
|
||||
mega.set = m().set;
|
||||
mega.get = m().get;
|
||||
}
|
||||
|
||||
if (mini.get) {
|
||||
mega.get = function(opts) {
|
||||
return mini.get(opts);
|
||||
};
|
||||
} else if (mini.find) {
|
||||
mega.get = function(opts) {
|
||||
var servername = opts.servername;
|
||||
delete opts.servername;
|
||||
opts.servernames = (servername && [servername]) || undefined;
|
||||
return mini.find(opts).then(function(sites) {
|
||||
return sites.filter(function(site) {
|
||||
return site.altnames.include(servername);
|
||||
})[0];
|
||||
});
|
||||
};
|
||||
} else if (mini.set) {
|
||||
throw new Error(
|
||||
gconf.manager + ' implements `set()`, but not `get()` or `find()`'
|
||||
);
|
||||
} else {
|
||||
mega.find = m().find;
|
||||
mega.get = m().get;
|
||||
}
|
||||
|
||||
if (!mega.get) {
|
||||
mega.get = function(opts) {
|
||||
var servername = opts.servername;
|
||||
delete opts.servername;
|
||||
opts.servernames = (servername && [servername]) || undefined;
|
||||
return mega.find(opts).then(function(sites) {
|
||||
return sites.filter(function(site) {
|
||||
return site.altnames.include(servername);
|
||||
})[0];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
mega.init = function(deps) {
|
||||
if (mini.init) {
|
||||
return mini.init(deps).then(function() {
|
||||
if (mng) {
|
||||
return mng.init(deps);
|
||||
}
|
||||
});
|
||||
} else if (mng) {
|
||||
return mng.init(deps);
|
||||
} else {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
};
|
||||
|
||||
return mega;
|
||||
}
|
||||
|
||||
function _mangleFindArgs(args) {
|
||||
var servernames = (args.servernames || [])
|
||||
.concat(args.altnames || [])
|
||||
.filter(Boolean)
|
||||
.slice(0);
|
||||
var modified = servernames.slice(0);
|
||||
|
||||
// servername, wildname, and altnames are all the same
|
||||
['wildname', 'servername'].forEach(function(k) {
|
||||
var altname = args[k] || '';
|
||||
if (altname && !modified.includes(altname)) {
|
||||
modified.push(altname);
|
||||
}
|
||||
});
|
||||
|
||||
if (modified.length) {
|
||||
servernames = modified;
|
||||
servernames = servernames.map(U._encodeName);
|
||||
args.altnames = servernames;
|
||||
args.servernames = args.altnames = checkAltnames(false, args);
|
||||
}
|
||||
|
||||
// documented as args.servernames
|
||||
// preserved as args.altnames for v3 beta backwards compat
|
||||
// my only hesitancy in this choice is that a "servername"
|
||||
// may NOT contain '*.', in which case `altnames` is a better choice.
|
||||
// However, `altnames` is ambiguous - as if it means to find a
|
||||
// certificate by that specific collection of altnames.
|
||||
// ... perhaps `domains` could work?
|
||||
return args;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,25 @@
|
|||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@greenlock/manager": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@greenlock/manager/-/manager-3.0.0.tgz",
|
||||
"integrity": "sha512-ijgJrFdzJPmzrDk8aKXYoYR8LNfG3hXd9/s54ZY7IgxTulyPQ/qOPgl7sWgCxxLhZBzSY1xI6eC/6Y5TQ01agg==",
|
||||
"requires": {
|
||||
"greenlock-manager-fs": "^3.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"greenlock-manager-fs": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.5.tgz",
|
||||
"integrity": "sha512-r/q+tEFuDwklfzPfiGhcIrHuJxMrppC+EseESpu5f0DMokh+1iZVm9nGC/VE7/7GETdOYfEYhhQkmspsi8Gr/A==",
|
||||
"requires": {
|
||||
"@root/mkdirp": "^1.0.0",
|
||||
"safe-replace": "^1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@root/acme": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz",
|
||||
|
@ -90,9 +109,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"greenlock-manager-fs": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.3.tgz",
|
||||
"integrity": "sha512-Jwo60nHd10PNUA9M6cylD9YB4x4hzlfO2LRIGI0X+V+zA0x3KVbNW14yj8frdfHrtsWC1JQe7oFnHVdoRbAU2A==",
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.5.tgz",
|
||||
"integrity": "sha512-r/q+tEFuDwklfzPfiGhcIrHuJxMrppC+EseESpu5f0DMokh+1iZVm9nGC/VE7/7GETdOYfEYhhQkmspsi8Gr/A==",
|
||||
"requires": {
|
||||
"@root/mkdirp": "^1.0.0",
|
||||
"safe-replace": "^1.1.0"
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"@greenlock/manager": "^3.0.0",
|
||||
"@root/acme": "^3.0.8",
|
||||
"@root/csr": "^0.8.1",
|
||||
"@root/keypairs": "^0.9.0",
|
||||
|
@ -45,7 +46,7 @@
|
|||
"@root/request": "^1.3.10",
|
||||
"acme-http-01-standalone": "^3.0.5",
|
||||
"cert-info": "^1.5.1",
|
||||
"greenlock-manager-fs": "^3.0.3",
|
||||
"greenlock-manager-fs": "^3.0.5",
|
||||
"greenlock-store-fs": "^3.2.0",
|
||||
"safe-replace": "^1.1.0"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue