allow for partial manager
This commit is contained in:
parent
af3a2f621c
commit
7313167ca0
|
@ -1,3 +1,4 @@
|
||||||
|
greenlock.json*
|
||||||
TODO.txt
|
TODO.txt
|
||||||
link.sh
|
link.sh
|
||||||
.env
|
.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 pkgpath = path.join(process.cwd(), 'package.json');
|
||||||
var pkgdir = path.dirname(pkgpath);
|
var pkgdir = path.dirname(pkgpath);
|
||||||
//var rcpath = path.join(pkgpath, '.greenlockrc');
|
//var rcpath = path.join(pkgpath, '.greenlockrc');
|
||||||
var configFile = path.join(pkgdir, 'greenlock.d/manager.json');
|
|
||||||
var manager = flags.manager;
|
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)) {
|
if (['fs', 'cloud'].includes(manager)) {
|
||||||
// TODO publish the 1st party modules under a secure namespace
|
manager = '@greenlock/manager';
|
||||||
flags.manager = '@greenlock/manager-' + flags.manager;
|
|
||||||
}
|
}
|
||||||
|
if (['cloud'].includes(manager)) {
|
||||||
|
flags.managerOpts.cloud = true;
|
||||||
|
}
|
||||||
|
|
||||||
flags.manager = flags.managerOpts;
|
flags.manager = flags.managerOpts;
|
||||||
delete flags.managerOpts;
|
delete flags.managerOpts;
|
||||||
flags.manager.manager = manager;
|
flags.manager.manager = manager;
|
||||||
|
@ -57,6 +52,7 @@ cli.main(async function(argList, flags) {
|
||||||
var GreenlockRc = require('./lib/greenlockrc.js');
|
var GreenlockRc = require('./lib/greenlockrc.js');
|
||||||
//var rc = await GreenlockRc(pkgpath, manager, flags.manager);
|
//var rc = await GreenlockRc(pkgpath, manager, flags.manager);
|
||||||
await GreenlockRc(pkgpath, manager, flags.manager);
|
await GreenlockRc(pkgpath, manager, flags.manager);
|
||||||
|
writeGreenlockJs(pkgdir, flags);
|
||||||
writeServerJs(pkgdir, flags);
|
writeServerJs(pkgdir, flags);
|
||||||
writeAppJs(pkgdir);
|
writeAppJs(pkgdir);
|
||||||
|
|
||||||
|
@ -70,9 +66,41 @@ cli.main(async function(argList, flags) {
|
||||||
*/
|
*/
|
||||||
}, args);
|
}, 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) {
|
function writeServerJs(pkgdir, flags) {
|
||||||
var serverJs = 'server.js';
|
var serverJs = 'server.js';
|
||||||
var bakTmpl = 'server-greenlock-tmpl.js';
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var tmpl = fs.readFileSync(
|
var tmpl = fs.readFileSync(
|
||||||
|
@ -82,13 +110,8 @@ function writeServerJs(pkgdir, flags) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.accessSync(path.join(pkgdir, serverJs));
|
fs.accessSync(path.join(pkgdir, serverJs));
|
||||||
console.warn(
|
console.warn("[skip] '%s' exists", serverJs);
|
||||||
JSON.stringify(serverJs),
|
return;
|
||||||
' exists, writing to ',
|
|
||||||
JSON.stringify(bakTmpl),
|
|
||||||
'instead'
|
|
||||||
);
|
|
||||||
serverJs = bakTmpl;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// continue
|
// continue
|
||||||
}
|
}
|
||||||
|
@ -106,10 +129,10 @@ function writeServerJs(pkgdir, flags) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fs.writeFileSync(path.join(pkgdir, serverJs), tmpl);
|
fs.writeFileSync(path.join(pkgdir, serverJs), tmpl);
|
||||||
|
console.info("created '%s'", serverJs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeAppJs(pkgdir) {
|
function writeAppJs(pkgdir) {
|
||||||
var bakTmpl = 'app-greenlock-tmpl.js';
|
|
||||||
var appJs = 'app.js';
|
var appJs = 'app.js';
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
@ -120,16 +143,10 @@ function writeAppJs(pkgdir) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.accessSync(path.join(pkgdir, appJs));
|
fs.accessSync(path.join(pkgdir, appJs));
|
||||||
console.warn(
|
console.warn("[skip] '%s' exists", appJs);
|
||||||
JSON.stringify(appJs),
|
return;
|
||||||
' exists, writing to ',
|
|
||||||
JSON.stringify(bakTmpl),
|
|
||||||
'instead'
|
|
||||||
);
|
|
||||||
appJs = bakTmpl;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(path.join(pkgdir, appJs), tmpl);
|
fs.writeFileSync(path.join(pkgdir, appJs), tmpl);
|
||||||
|
console.info("created '%s'", appJs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,10 +93,11 @@ module.exports = async function(pkgpath, manager, rc) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_rc.manager) {
|
if (['@greenlock/manager', 'greenlock-manager-fs'].includes(_rc.manager)) {
|
||||||
|
if (!_rc.configFile) {
|
||||||
changed = true;
|
changed = true;
|
||||||
_rc.manager = 'greenlock-manager-fs';
|
_rc.configFile = path.join(pkgdir, 'greenlock.json');
|
||||||
console.info('Using default manager ' + _rc.manager);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changed) {
|
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 path = require('path');
|
||||||
var rcPath = path.join(__dirname, '.greenlockrc');
|
var rcPath = path.join(__dirname, '.greenlockrc');
|
||||||
var rc = fs.readFileSync(rcPath, 'utf8');
|
var rc = fs.readFileSync(rcPath, 'utf8');
|
||||||
return JSON.parse(rc);
|
rc = JSON.parse(rc);
|
||||||
|
rc.packageRoot = __dirname;
|
||||||
}
|
}
|
||||||
|
|
137
greenlock.js
137
greenlock.js
|
@ -23,7 +23,6 @@ G.create = function(gconf) {
|
||||||
if (!gconf) {
|
if (!gconf) {
|
||||||
gconf = {};
|
gconf = {};
|
||||||
}
|
}
|
||||||
var manager;
|
|
||||||
|
|
||||||
greenlock._create = function() {
|
greenlock._create = function() {
|
||||||
if (!gconf._bin_mode) {
|
if (!gconf._bin_mode) {
|
||||||
|
@ -65,15 +64,14 @@ G.create = function(gconf) {
|
||||||
}
|
}
|
||||||
console.info('ACME Directory URL:', gdefaults.directoryUrl);
|
console.info('ACME Directory URL:', gdefaults.directoryUrl);
|
||||||
|
|
||||||
manager = normalizeManager(gconf);
|
|
||||||
|
|
||||||
// Wraps each of the following with appropriate error checking
|
// Wraps each of the following with appropriate error checking
|
||||||
// greenlock.manager.defaults
|
// greenlock.manager.defaults
|
||||||
// greenlock.manager.add
|
// greenlock.sites.add
|
||||||
// greenlock.manager.update
|
// greenlock.sites.update
|
||||||
// greenlock.manager.remove
|
// greenlock.sites.remove
|
||||||
// greenlock.manager.find
|
// greenlock.sites.find
|
||||||
require('./manager-underlay.js').wrap(greenlock, manager, gconf);
|
// greenlock.sites.get
|
||||||
|
require('./manager-underlay.js').wrap(greenlock, gconf);
|
||||||
// The goal here is to reduce boilerplate, such as error checking
|
// The goal here is to reduce boilerplate, such as error checking
|
||||||
// and duration parsing, that a manager must implement
|
// and duration parsing, that a manager must implement
|
||||||
greenlock.sites.add = greenlock.add = greenlock.manager.add;
|
greenlock.sites.add = greenlock.add = greenlock.manager.add;
|
||||||
|
@ -83,7 +81,7 @@ G.create = function(gconf) {
|
||||||
// Exports challenges.get for Greenlock Express HTTP-01,
|
// Exports challenges.get for Greenlock Express HTTP-01,
|
||||||
// and whatever odd use case pops up, I suppose
|
// and whatever odd use case pops up, I suppose
|
||||||
// greenlock.challenges.get
|
// greenlock.challenges.get
|
||||||
require('./challenges-underlay.js').wrap(greenlock, manager, gconf);
|
require('./challenges-underlay.js').wrap(greenlock);
|
||||||
|
|
||||||
greenlock._defaults = gdefaults;
|
greenlock._defaults = gdefaults;
|
||||||
greenlock._defaults.debug = gconf.debug;
|
greenlock._defaults.debug = gconf.debug;
|
||||||
|
@ -108,25 +106,20 @@ G.create = function(gconf) {
|
||||||
return p;
|
return p;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (manager.init) {
|
p = greenlock.manager
|
||||||
// TODO punycode?
|
.init({
|
||||||
p = manager.init({
|
|
||||||
request: request
|
request: request
|
||||||
//punycode: require('punycode')
|
//punycode: require('punycode')
|
||||||
});
|
})
|
||||||
} else {
|
|
||||||
p = Promise.resolve();
|
|
||||||
}
|
|
||||||
p = p
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return manager.defaults().then(function(MCONF) {
|
return greenlock.manager._defaults().then(function(MCONF) {
|
||||||
mergeDefaults(MCONF, gconf);
|
mergeDefaults(MCONF, gconf);
|
||||||
if (true === MCONF.agreeToTerms) {
|
if (true === MCONF.agreeToTerms) {
|
||||||
gdefaults.agreeToTerms = function(tos) {
|
gdefaults.agreeToTerms = function(tos) {
|
||||||
return Promise.resolve(tos);
|
return Promise.resolve(tos);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return manager.defaults(MCONF);
|
return greenlock.manager._defaults(MCONF);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
|
@ -289,7 +282,7 @@ G.create = function(gconf) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
sites = JSON.parse(JSON.stringify(sites));
|
sites = JSON.parse(JSON.stringify(sites));
|
||||||
return manager.defaults().then(function(mconf) {
|
return greenlock.manager._defaults().then(function(mconf) {
|
||||||
return sites.map(function(site) {
|
return sites.map(function(site) {
|
||||||
if (site.store && site.challenges) {
|
if (site.store && site.challenges) {
|
||||||
return site;
|
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
|
// needs to get info about the renewal, such as which store and challenge(s) to use
|
||||||
greenlock.renew = function(args) {
|
greenlock.renew = function(args) {
|
||||||
return greenlock._init().then(function() {
|
return greenlock._init().then(function() {
|
||||||
return manager.defaults().then(function(mconf) {
|
return greenlock.manager._defaults().then(function(mconf) {
|
||||||
return greenlock._renew(mconf, args);
|
return greenlock._renew(mconf, args);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -418,7 +411,7 @@ G.create = function(gconf) {
|
||||||
|
|
||||||
greenlock.order = function(args) {
|
greenlock.order = function(args) {
|
||||||
return greenlock._init().then(function() {
|
return greenlock._init().then(function() {
|
||||||
return manager.defaults().then(function(mconf) {
|
return greenlock.manager._defaults().then(function(mconf) {
|
||||||
return greenlock._order(mconf, args);
|
return greenlock._order(mconf, args);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -485,106 +478,6 @@ function errorToJSON(e) {
|
||||||
return error;
|
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) {
|
function mergeDefaults(MCONF, gconf) {
|
||||||
if (
|
if (
|
||||||
gconf.agreeToTerms === true ||
|
gconf.agreeToTerms === true ||
|
||||||
|
|
|
@ -5,7 +5,15 @@ var E = require('./errors.js');
|
||||||
|
|
||||||
var warned = {};
|
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.manager = {};
|
||||||
greenlock.sites = {};
|
greenlock.sites = {};
|
||||||
//greenlock.accounts = {};
|
//greenlock.accounts = {};
|
||||||
|
@ -31,7 +39,7 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
||||||
greenlock.manager.defaults = function(conf) {
|
greenlock.manager.defaults = function(conf) {
|
||||||
return greenlock._init().then(function() {
|
return greenlock._init().then(function() {
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return manager.defaults();
|
return mega.defaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conf.sites) {
|
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) {
|
greenlock.manager.add = function(args) {
|
||||||
if (!args || !Array.isArray(args.altnames) || !args.altnames.length) {
|
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);
|
args.renewStagger = U._parseDuration(args.renewStagger);
|
||||||
}
|
}
|
||||||
|
|
||||||
return manager.set(args).then(function(result) {
|
return mega.set(args).then(function(result) {
|
||||||
if (!gconf._bin_mode) {
|
if (!gconf._bin_mode) {
|
||||||
greenlock.renew({}).catch(function(err) {
|
greenlock.renew({}).catch(function(err) {
|
||||||
if (!err.context) {
|
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) {
|
greenlock.manager.remove = function(args) {
|
||||||
return Promise.resolve().then(function() {
|
return Promise.resolve().then(function() {
|
||||||
args.subject = checkSubject(args);
|
args.subject = checkSubject(args);
|
||||||
|
@ -171,7 +196,7 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// TODO check no altnames
|
// TODO check no altnames
|
||||||
return manager.remove(args);
|
return mega.remove(args);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,37 +216,117 @@ module.exports.wrap = function(greenlock, manager, gconf) {
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
greenlock._find = function(args) {
|
// no transaction promise here because it calls set
|
||||||
var servernames = (args.servernames || [])
|
greenlock._find = async function(args) {
|
||||||
.concat(args.altnames || [])
|
args = _mangleFindArgs(args);
|
||||||
.filter(Boolean)
|
var ours = await mega.find(args);
|
||||||
.slice(0);
|
if (!myFind) {
|
||||||
var modified = servernames.slice(0);
|
return ours;
|
||||||
|
}
|
||||||
|
|
||||||
// servername, wildname, and altnames are all the same
|
// if the user has an overlay find function we'll do a diff
|
||||||
['wildname', 'servername'].forEach(function(k) {
|
// between the managed state and the overlay, and choose
|
||||||
var altname = args[k] || '';
|
// what was found.
|
||||||
if (altname && !modified.includes(altname)) {
|
var theirs = await myFind(args);
|
||||||
modified.push(altname);
|
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) {
|
// delete the things that are gone
|
||||||
servernames = modified;
|
ours.forEach(function(_older) {
|
||||||
servernames = servernames.altnames.map(U._encodeName);
|
if (!_older._exists) {
|
||||||
args.altnames = servernames;
|
_older.deletedAt = Date.now();
|
||||||
args.servernames = args.altnames = checkAltnames(false, args);
|
toUpdate.push(_older);
|
||||||
|
}
|
||||||
|
_older._exists = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// documented as args.servernames
|
greenlock.manager.init = mega.init;
|
||||||
// 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);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function checkSubject(args) {
|
function checkSubject(args) {
|
||||||
|
@ -284,3 +389,185 @@ function checkAltnames(subject, args) {
|
||||||
|
|
||||||
return altnames;
|
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,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"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": {
|
"@root/acme": {
|
||||||
"version": "3.0.8",
|
"version": "3.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz",
|
||||||
|
@ -90,9 +109,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"greenlock-manager-fs": {
|
"greenlock-manager-fs": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.5.tgz",
|
||||||
"integrity": "sha512-Jwo60nHd10PNUA9M6cylD9YB4x4hzlfO2LRIGI0X+V+zA0x3KVbNW14yj8frdfHrtsWC1JQe7oFnHVdoRbAU2A==",
|
"integrity": "sha512-r/q+tEFuDwklfzPfiGhcIrHuJxMrppC+EseESpu5f0DMokh+1iZVm9nGC/VE7/7GETdOYfEYhhQkmspsi8Gr/A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@root/mkdirp": "^1.0.0",
|
"@root/mkdirp": "^1.0.0",
|
||||||
"safe-replace": "^1.1.0"
|
"safe-replace": "^1.1.0"
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@greenlock/manager": "^3.0.0",
|
||||||
"@root/acme": "^3.0.8",
|
"@root/acme": "^3.0.8",
|
||||||
"@root/csr": "^0.8.1",
|
"@root/csr": "^0.8.1",
|
||||||
"@root/keypairs": "^0.9.0",
|
"@root/keypairs": "^0.9.0",
|
||||||
|
@ -45,7 +46,7 @@
|
||||||
"@root/request": "^1.3.10",
|
"@root/request": "^1.3.10",
|
||||||
"acme-http-01-standalone": "^3.0.5",
|
"acme-http-01-standalone": "^3.0.5",
|
||||||
"cert-info": "^1.5.1",
|
"cert-info": "^1.5.1",
|
||||||
"greenlock-manager-fs": "^3.0.3",
|
"greenlock-manager-fs": "^3.0.5",
|
||||||
"greenlock-store-fs": "^3.2.0",
|
"greenlock-store-fs": "^3.2.0",
|
||||||
"safe-replace": "^1.1.0"
|
"safe-replace": "^1.1.0"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue