template improvements

This commit is contained in:
AJ ONeal 2019-11-05 02:50:27 -07:00
parent 4dc324f26f
commit 8f3872e82e
11 changed files with 286 additions and 211 deletions

View File

@ -464,7 +464,7 @@ This is what keeps the mapping of domains <-> certificates.
In many cases it will interact with the same database as the Key & Cert Store, and probably the code as well. In many cases it will interact with the same database as the Key & Cert Store, and probably the code as well.
- set({ subject, altnames, renewAt }) - set({ subject, altnames, renewAt })
- find({ altnames, renewBefore }) - find({ servernames, renewBefore })
```js ```js
// should return a list of site configs: // should return a list of site configs:
[ [

View File

@ -117,7 +117,7 @@ A._newAccount = function(gnlck, mconf, db, acme, args, email, fullAccount) {
/^https?:\/\//i, /^https?:\/\//i,
'' ''
); );
*/ */
keyP = db.setKeypair(query, keypair); keyP = db.setKeypair(query, keypair);
} }
@ -145,7 +145,7 @@ A._newAccount = function(gnlck, mconf, db, acme, args, email, fullAccount) {
/^https?:\/\//i, /^https?:\/\//i,
'' ''
) )
*/ */
}, },
reg reg
); );

View File

@ -49,7 +49,7 @@ cli.main(async function(argList, flags) {
} }
} }
var GreenlockRc = require('./lib/greenlockrc.js'); var GreenlockRc = require('../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); writeGreenlockJs(pkgdir, flags);

View File

@ -5,7 +5,7 @@ var Flags = module.exports;
var path = require('path'); var path = require('path');
//var pkgpath = path.join(__dirname, '..', 'package.json'); //var pkgpath = path.join(__dirname, '..', 'package.json');
var pkgpath = path.join(process.cwd(), 'package.json'); var pkgpath = path.join(process.cwd(), 'package.json');
var GreenlockRc = require('./greenlockrc.js'); var GreenlockRc = require('../../greenlockrc.js');
// These are ALL options // These are ALL options
// The individual CLI files each select a subset of them // The individual CLI files each select a subset of them
@ -168,21 +168,21 @@ Flags.flags = function(mconf, myOpts) {
}; };
}; };
Flags.init = function(myOpts) { Flags.init = async function(myOpts) {
return GreenlockRc(pkgpath).then(async function(rc) { var rc = await GreenlockRc(pkgpath);
rc._bin_mode = true; rc._bin_mode = true;
var Greenlock = require('../../'); var Greenlock = require('../../');
// this is a copy, so it's safe to modify // this is a copy, so it's safe to modify
var greenlock = Greenlock.create(rc); rc.packageRoot = path.dirname(pkgpath);
var mconf = await greenlock.manager.defaults(); var greenlock = Greenlock.create(rc);
var flagOptions = Flags.flags(mconf, myOpts); var mconf = await greenlock.manager.defaults();
return { var flagOptions = Flags.flags(mconf, myOpts);
flagOptions, return {
rc, flagOptions,
greenlock, rc,
mconf greenlock,
}; mconf
}); };
}; };
Flags.mangleFlags = function(flags, mconf, sconf, extras) { Flags.mangleFlags = function(flags, mconf, sconf, extras) {

View File

@ -1,114 +0,0 @@
'use strict';
// TODO how to handle path differences when run from npx vs when required by greenlock?
var promisify = require('util').promisify;
var fs = require('fs');
var readFile = promisify(fs.readFile);
var writeFile = promisify(fs.writeFile);
var chmodFile = promisify(fs.chmod);
var path = require('path');
function saveFile(rcpath, data, enc) {
// because this may have a database url or some such
return writeFile(rcpath, data, enc).then(function() {
return chmodFile(rcpath, parseInt('0600', 8));
});
}
module.exports = async function(pkgpath, manager, rc) {
// TODO when run from package
// Run from the package root (assumed) or exit
var pkgdir = path.dirname(pkgpath);
var rcpath = path.join(pkgdir, '.greenlockrc');
var created = false;
try {
require(pkgpath);
} catch (e) {
console.error(
'npx greenlock must be run from the package root (where package.json is)'
);
process.exit(1);
}
if (manager) {
if ('.' === manager[0]) {
manager = path.resolve(pkgdir, manager);
}
try {
require(manager);
} catch (e) {
console.error('npx greenlock must be run from the package root');
process.exit(1);
}
}
var _data = await readFile(rcpath, 'utf8').catch(function(err) {
if ('ENOENT' !== err.code) {
throw err;
}
console.info('Creating ' + rcpath);
created = true;
var data = '{}';
return saveFile(rcpath, data, 'utf8').then(function() {
return data;
});
});
var changed;
var _rc;
try {
_rc = JSON.parse(_data);
} catch (e) {
console.error("couldn't parse " + rcpath, _data);
console.error('(perhaps you should just delete it and try again?)');
process.exit(1);
}
if (manager) {
if (!_rc.manager) {
_rc.manager = manager;
}
if (_rc.manager !== manager) {
console.info('Switching manager:');
var older = _rc.manager;
var newer = manager;
if ('/' === older[0]) {
older = path.relative(pkgdir, older);
}
if ('/' === newer[0]) {
newer = path.relative(pkgdir, newer);
}
console.info('\told: ' + older);
console.info('\tnew: ' + newer);
changed = true;
}
}
if (rc) {
changed = true;
Object.keys(rc).forEach(function(k) {
_rc[k] = rc[k];
});
}
if (['@greenlock/manager', 'greenlock-manager-fs'].includes(_rc.manager)) {
if (!_rc.configFile) {
changed = true;
_rc.configFile = path.join(pkgdir, 'greenlock.json');
}
}
if (!changed) {
return _rc;
}
var data = JSON.stringify(_rc, null, 2);
if (created) {
console.info('Wrote ' + rcpath);
}
return saveFile(rcpath, data, 'utf8').then(function() {
return _rc;
});
};

View File

@ -1,29 +1,13 @@
'use strict'; 'use strict';
module.exports = require('greenlock').create(init()); var pkg = require('./package.json');
module.exports = require('@root/greenlock').create({
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 // name & version for ACME client user agent
var pkg = require('./package.json'); packageAgent: pkg.name + '/' + pkg.version,
options.packageAgent = pkg.name + '/' + pkg.version;
// contact for security and critical bug notices // contact for security and critical bug notices
options.maintainerEmail = pkg.author; maintainerEmail: pkg.author,
return options; // where to find .greenlockrc and set default paths
} packageRoot: __dirname
});
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;
}

View File

@ -2,21 +2,12 @@
require('greenlock-express') require('greenlock-express')
.init(function() { .init(function() {
// .greenlockrc defines which manager to use return {
// (i.e. greenlock-manager-fs or greenlock-manager-cloud) greenlock: require('./greenlock.js'),
var options = getGreenlockRc() || {};
// name & version for ACME client user agent // whether or not to run at cloudscale
var pkg = require('./package.json'); cluster: false
options.packageAgent = pkg.name + '/' + pkg.version; };
// contact for security and critical bug notices
options.maintainerEmail = pkg.author;
// whether or not to run at cloudscale
options.cluster = false;
return options;
}) })
.ready(function(glx) { .ready(function(glx) {
var app = require('./app.js'); var app = require('./app.js');
@ -25,14 +16,3 @@ require('greenlock-express')
// Get's SSL certificates magically! // Get's SSL certificates magically!
glx.serveApp(app); glx.serveApp(app);
}); });
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;
}

View File

@ -127,7 +127,10 @@ C._rawOrder = function(gnlck, mconf, db, acme, chs, acc, email, args) {
var query = { var query = {
subject: args.subject, subject: args.subject,
certificate: args.certificate || {}, certificate: args.certificate || {},
directoryUrl: args.directoryUrl || gnlck._defaults.directoryUrl directoryUrl:
args.directoryUrl ||
mconf.directoryUrl ||
gnlck._defaults.directoryUrl
}; };
rawPending[id] = U._getOrCreateKeypair(db, args.subject, query, keyType) rawPending[id] = U._getOrCreateKeypair(db, args.subject, query, keyType)
.then(function(kresult) { .then(function(kresult) {
@ -208,7 +211,10 @@ C._check = function(gnlck, mconf, db, args) {
subject: args.subject, subject: args.subject,
// may contain certificate.id // may contain certificate.id
certificate: args.certificate, certificate: args.certificate,
directoryUrl: args.directoryUrl || gnlck._defaults.directoryUrl directoryUrl:
args.directoryUrl ||
mconf.directoryUrl ||
gnlck._defaults.directoryUrl
}; };
return db.check(query).then(function(pems) { return db.check(query).then(function(pems) {
if (!pems) { if (!pems) {

View File

@ -13,6 +13,7 @@ var P = require('./plugins.js');
var A = require('./accounts.js'); var A = require('./accounts.js');
var C = require('./certificates.js'); var C = require('./certificates.js');
var UserEvents = require('./user-events.js'); var UserEvents = require('./user-events.js');
var GreenlockRc = require('./greenlockrc.js');
var caches = {}; var caches = {};
@ -42,27 +43,21 @@ G.create = function(gconf) {
}); });
} }
if (!gconf.packageRoot) {
gconf.packageRoot = process.cwd();
console.warn(
'`packageRoot` not defined, trying ' + gconf.packageRoot
);
}
if ('function' === typeof gconf.notify) { if ('function' === typeof gconf.notify) {
gdefaults.notify = gconf.notify; gdefaults.notify = gconf.notify;
} else { } else {
gdefaults.notify = _notify; gdefaults.notify = _notify;
} }
if (gconf.directoryUrl) { var rc = GreenlockRc.resolve(gconf);
gdefaults = gconf.directoryUrl; gconf = Object.assign(rc, gconf);
if (gconf.staging) {
throw new Error(
'supply `directoryUrl` or `staging`, but not both'
);
}
} else if (gconf.staging) {
gdefaults.directoryUrl =
'https://acme-staging-v02.api.letsencrypt.org/directory';
} else {
gdefaults.directoryUrl =
'https://acme-v02.api.letsencrypt.org/directory';
}
console.info('ACME Directory URL:', gdefaults.directoryUrl);
// Wraps each of the following with appropriate error checking // Wraps each of the following with appropriate error checking
// greenlock.manager.defaults // greenlock.manager.defaults
@ -83,10 +78,31 @@ G.create = function(gconf) {
// greenlock.challenges.get // greenlock.challenges.get
require('./challenges-underlay.js').wrap(greenlock); require('./challenges-underlay.js').wrap(greenlock);
if (gconf.directoryUrl) {
gdefaults.directoryUrl = gconf.directoryUrl;
if (gconf.staging) {
throw new Error(
'supply `directoryUrl` or `staging`, but not both'
);
}
} else if (
gconf.staging ||
process.argv.includes('--staging') ||
/DEV|STAG/i.test(process.env.ENV)
) {
greenlock.staging = true;
gdefaults.directoryUrl =
'https://acme-staging-v02.api.letsencrypt.org/directory';
} else {
greenlock.live = true;
gdefaults.directoryUrl =
'https://acme-v02.api.letsencrypt.org/directory';
}
greenlock._defaults = gdefaults; greenlock._defaults = gdefaults;
greenlock._defaults.debug = gconf.debug; greenlock._defaults.debug = gconf.debug;
if (!gconf._bin_mode) { if (!gconf._bin_mode && false !== gconf.renew) {
// renew every 90-ish minutes (random for staggering) // renew every 90-ish minutes (random for staggering)
// the weak setTimeout (unref) means that when run as a CLI process this // the weak setTimeout (unref) means that when run as a CLI process this
// will still finish as expected, and not wait on the timeout // will still finish as expected, and not wait on the timeout
@ -371,7 +387,7 @@ G.create = function(gconf) {
}); });
}; };
greenlock._acme = function(args) { greenlock._acme = function(mconf, args) {
var packageAgent = gconf.packageAgent || ''; var packageAgent = gconf.packageAgent || '';
// because Greenlock_Express/v3.x Greenlock/v3 is redundant // because Greenlock_Express/v3.x Greenlock/v3 is redundant
if (!/greenlock/i.test(packageAgent)) { if (!/greenlock/i.test(packageAgent)) {
@ -383,7 +399,15 @@ G.create = function(gconf) {
notify: greenlock._notify, notify: greenlock._notify,
debug: greenlock._defaults.debug || args.debug debug: greenlock._defaults.debug || args.debug
}); });
var dirUrl = args.directoryUrl || greenlock._defaults.directoryUrl; var dirUrl = args.directoryUrl || mconf.directoryUrl;
var showDir = false;
if (!dirUrl) {
showDir = true;
dirUrl = greenlock._defaults.directoryUrl;
}
if (showDir || /staging/.test(dirUrl)) {
console.info('ACME Directory URL:', gdefaults.directoryUrl);
}
var dir = caches[dirUrl]; var dir = caches[dirUrl];
@ -409,17 +433,17 @@ G.create = function(gconf) {
}); });
}; };
greenlock.order = function(args) { greenlock.order = function(siteConf) {
return greenlock._init().then(function() { return greenlock._init().then(function() {
return greenlock.manager._defaults().then(function(mconf) { return greenlock.manager._defaults().then(function(mconf) {
return greenlock._order(mconf, args); return greenlock._order(mconf, siteConf);
}); });
}); });
}; };
greenlock._order = function(mconf, args) { greenlock._order = function(mconf, siteConf) {
// packageAgent, maintainerEmail // packageAgent, maintainerEmail
return greenlock._acme(args).then(function(acme) { return greenlock._acme(mconf, siteConf).then(function(acme) {
var storeConf = args.store || mconf.store; var storeConf = siteConf.store || mconf.store;
storeConf = JSON.parse(JSON.stringify(storeConf)); storeConf = JSON.parse(JSON.stringify(storeConf));
storeConf.packageRoot = gconf.packageRoot; storeConf.packageRoot = gconf.packageRoot;
if (storeConf.basePath) { if (storeConf.basePath) {
@ -435,9 +459,10 @@ G.create = function(gconf) {
mconf, mconf,
store.accounts, store.accounts,
acme, acme,
args siteConf
).then(function(account) { ).then(function(account) {
var challengeConfs = args.challenges || mconf.challenges; var challengeConfs =
siteConf.challenges || mconf.challenges;
return Promise.all( return Promise.all(
Object.keys(challengeConfs).map(function(typ01) { Object.keys(challengeConfs).map(function(typ01) {
return P._loadChallenge(challengeConfs, typ01); return P._loadChallenge(challengeConfs, typ01);
@ -454,7 +479,7 @@ G.create = function(gconf) {
acme, acme,
challenges, challenges,
account, account,
args siteConf
).then(function(pems) { ).then(function(pems) {
if (!pems) { if (!pems) {
throw new Error('no order result'); throw new Error('no order result');

191
greenlockrc.js Normal file
View File

@ -0,0 +1,191 @@
'use strict';
// TODO how to handle path differences when run from npx vs when required by greenlock?
var fs = require('fs');
var path = require('path');
function saveFile(rcpath, data, enc) {
// because this may have a database url or some such
fs.writeFileSync(rcpath, data, enc);
return fs.chmodSync(rcpath, parseInt('0600', 8));
}
var GRC = (module.exports = function(pkgpath, manager, rc) {
// TODO when run from package
// Run from the package root (assumed) or exit
var pkgdir = path.dirname(pkgpath);
try {
require(pkgpath);
} catch (e) {
console.error(
'npx greenlock must be run from the package root (where package.json is)'
);
process.exit(1);
}
try {
return module.exports._defaults(pkgdir, manager, rc);
} catch (e) {
if ('package.json' === e.context) {
console.error(e.desc);
process.exit(1);
}
console.error(e.message);
process.exit(1);
}
});
// Figure out what to do between what's hard-coded,
// what's in the config file, and what's left unset
module.exports.resolve = function(gconf) {
var rc = GRC.read(gconf.packageRoot);
if (gconf.configFile) {
rc = { configFile: gconf.configFile };
}
var manager;
var updates;
if (rc.manager) {
if (gconf.manager && rc.manager !== gconf.manager) {
console.warn(
'warn: ignoring hard-coded ' +
gconf.manager +
' in favor of ' +
rc.manager
);
}
gconf.manager = rc.manager;
} else if (gconf.manager) {
manager = gconf.manager;
}
if (rc.configFile) {
if (gconf.configFile && rc.configFile !== gconf.configFile) {
console.warn(
'warn: ignoring hard-coded ' +
gconf.configFile +
' in favor of ' +
rc.configFile
);
}
gconf.configFile = rc.configFile;
} else if (gconf.manager) {
updates = { configFile: gconf.configFile };
}
return GRC._defaults(gconf.packageRoot, manager, rc);
};
module.exports._defaults = function(pkgdir, manager, rc) {
var rcpath = path.join(pkgdir, '.greenlockrc');
var _rc;
var created = false;
if (manager) {
if ('.' === manager[0]) {
manager = path.resolve(pkgdir, manager);
}
try {
require(manager);
} catch (e) {
console.error('could not load ' + manager + ' from ' + pkgdir);
throw e;
}
}
var stuff = module.exports._read(pkgdir);
_rc = stuff.rc;
created = stuff.created;
var changed;
if (manager) {
if (!_rc.manager) {
_rc.manager = manager;
}
if (_rc.manager !== manager) {
console.info('Switching manager:');
var older = _rc.manager;
var newer = manager;
if ('/' === older[0]) {
older = path.relative(pkgdir, older);
}
if ('/' === newer[0]) {
newer = path.relative(pkgdir, newer);
}
console.info('\told: ' + older);
console.info('\tnew: ' + newer);
changed = true;
}
}
if (rc) {
changed = true;
Object.keys(rc).forEach(function(k) {
_rc[k] = rc[k];
});
}
if (['@greenlock/manager', 'greenlock-manager-fs'].includes(_rc.manager)) {
if (!_rc.configFile) {
changed = true;
_rc.configFile = path.join(pkgdir, 'greenlock.json');
}
}
if (!changed) {
return _rc;
}
var data = JSON.stringify(_rc, null, 2);
if (created) {
console.info('Wrote ' + rcpath);
}
saveFile(rcpath, data, 'utf8');
return _rc;
};
module.exports.read = function(pkgdir) {
return module.exports._read(pkgdir).rc;
};
module.exports._read = function(pkgdir) {
var created;
var rcpath = path.join(pkgdir, '.greenlockrc');
var _data;
try {
_data = fs.readFileSync(rcpath, 'utf8');
} catch (err) {
if ('ENOENT' !== err.code) {
throw err;
}
try {
require(path.join(pkgdir, 'package.json'));
} catch (e) {
e.context = 'package.json';
e.desc =
'run `greenlock` from the same directory as `package.json`, or specify `packageRoot` of `.greenlockrc`';
throw e;
}
console.info('Creating ' + rcpath);
created = true;
_data = '{}';
saveFile(rcpath, _data, 'utf8');
}
var rc;
try {
rc = JSON.parse(_data);
} catch (e) {
console.error("couldn't parse " + rcpath, _data);
console.error('(perhaps you should just delete it and try again?)');
process.exit(1);
}
return {
created: created,
rc: rc
};
};

View File

@ -94,7 +94,10 @@ module.exports.wrap = function(greenlock, gconf) {
return mega.defaults(conf); return mega.defaults(conf);
}); });
}; };
greenlock.manager._defaults = mega.defaults;
greenlock.manager._defaults = function(opts) {
return mega.defaults(opts);
};
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) {