Browse Source

CLI: implement init and bugfix .greenlockrc

v4
AJ ONeal 5 years ago
parent
commit
341347ba3e
  1. 2
      bin/greenlock.js
  2. 135
      bin/init.js
  3. 2
      bin/lib/cli.js
  4. 44
      bin/lib/flags.js
  5. 2
      bin/lib/greenlockrc.js
  6. 9
      bin/tmpl/app.tmpl.js
  7. 36
      bin/tmpl/server.tmpl.js
  8. 5
      plugins.js
  9. 2
      tests/cli.sh

2
bin/greenlock.js

@ -5,7 +5,7 @@ var args = process.argv.slice(2);
var arg0 = args[0]; var arg0 = args[0];
//console.log(args); //console.log(args);
var found = ['certonly', 'add', 'update', 'config', 'defaults', 'remove'].some( var found = ['certonly', 'add', 'update', 'config', 'defaults', 'remove', 'init'].some(
function(k) { function(k) {
if (k === arg0) { if (k === arg0) {
require('./' + k); require('./' + k);

135
bin/init.js

@ -0,0 +1,135 @@
'use strict';
var P = require('../plugins.js');
var args = process.argv.slice(3);
var cli = require('./lib/cli.js');
//var path = require('path');
//var pkgpath = path.join(__dirname, '..', 'package.json');
//var pkgpath = path.join(process.cwd(), 'package.json');
var Flags = require('./lib/flags.js');
var flagOptions = Flags.flags();
var myFlags = {};
['maintainer-email', 'cluster', 'manager', 'manager-xxxx'].forEach(function(k) {
myFlags[k] = flagOptions[k];
});
cli.parse(myFlags);
cli.main(async function(argList, flags) {
var path = require('path');
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;
}
flags.manager = flags.managerOpts;
delete flags.managerOpts;
flags.manager.manager = manager;
try {
P._loadSync(manager);
} catch (e) {
try {
P._installSync(manager);
} catch (e) {
console.error(
'error:',
JSON.stringify(manager),
'could not be loaded, and could not be installed.'
);
process.exit(1);
}
}
var GreenlockRc = require('./lib/greenlockrc.js');
//var rc = await GreenlockRc(pkgpath, manager, flags.manager);
await GreenlockRc(pkgpath, manager, flags.manager);
writeServerJs(pkgdir, flags);
writeAppJs(pkgdir);
/*
rc._bin_mode = true;
var Greenlock = require('../');
// this is a copy, so it's safe to modify
var greenlock = Greenlock.create(rc);
var mconf = await greenlock.manager.defaults();
var flagOptions = Flags.flags(mconf, myOpts);
*/
}, args);
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(
path.join(__dirname, 'tmpl/server.tmpl.js'),
'utf8'
);
try {
fs.accessSync(path.join(pkgdir, serverJs));
console.warn(
JSON.stringify(serverJs),
' exists, writing to ',
JSON.stringify(bakTmpl),
'instead'
);
serverJs = bakTmpl;
} 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, serverJs), tmpl);
}
function writeAppJs(pkgdir) {
var bakTmpl = 'app-greenlock-tmpl.js';
var appJs = 'app.js';
var fs = require('fs');
var path = require('path');
var tmpl = fs.readFileSync(
path.join(__dirname, 'tmpl/app.tmpl.js'),
'utf8'
);
try {
fs.accessSync(path.join(pkgdir, appJs));
console.warn(
JSON.stringify(appJs),
' exists, writing to ',
JSON.stringify(bakTmpl),
'instead'
);
appJs = bakTmpl;
} catch (e) {
// continue
}
fs.writeFileSync(path.join(pkgdir, appJs), tmpl);
}

2
bin/lib/cli.js

@ -14,7 +14,7 @@ CLI.parse = function(conf) {
var v = conf[k]; var v = conf[k];
if (!v) { if (!v) {
console.error( console.error(
'Developer Error: missing config value for', 'Developer Error: missing cli flag definition for',
JSON.stringify(k) JSON.stringify(k)
); );
process.exit(1); process.exit(1);

44
bin/lib/flags.js

@ -7,18 +7,20 @@ var path = require('path');
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');
Flags.init = function(myOpts) { // These are ALL options
// The individual CLI files each select a subset of them
Flags.flags = function(mconf, myOpts) {
// Current Manager Config
if (!mconf) {
mconf = {};
}
// Extra Override Options
if (!myOpts) { if (!myOpts) {
myOpts = {}; myOpts = {};
} }
return GreenlockRc(pkgpath).then(async function(rc) {
var Greenlock = require('../../');
// this is a copy, so it's safe to modify
rc._bin_mode = true;
var greenlock = Greenlock.create(rc);
var mconf = await greenlock.manager.defaults();
var flagOptions = { return {
subject: [ subject: [
false, false,
'the "subject" (primary domain) of the certificate', 'the "subject" (primary domain) of the certificate',
@ -39,6 +41,7 @@ Flags.init = function(myOpts) {
'a list of names that matches a subject or altname', 'a list of names that matches a subject or altname',
'string' 'string'
], ],
cluster: [false, 'initialize with cluster mode on', 'boolean', false],
'renew-offset': [ 'renew-offset': [
false, false,
"time to wait until renewing the cert such as '45d' (45 days after being issued) or '-3w' (3 weeks before expiration date)", "time to wait until renewing the cert such as '45d' (45 days after being issued) or '-3w' (3 weeks before expiration date)",
@ -55,6 +58,11 @@ Flags.init = function(myOpts) {
"the email address of the Let's Encrypt or ACME Account subscriber (not necessarily the domain owner)", "the email address of the Let's Encrypt or ACME Account subscriber (not necessarily the domain owner)",
'string' 'string'
], ],
'maintainer-email': [
false,
'the maintainance contact for security and critical bug notices',
'string'
],
'account-key-type': [ 'account-key-type': [
false, false,
"either 'P-256' (ECDSA) or 'RSA-2048' - although other values are technically supported, they don't make sense and won't work with many services (More bits != More security)", "either 'P-256' (ECDSA) or 'RSA-2048' - although other values are technically supported, they don't make sense and won't work with many services (More bits != More security)",
@ -78,6 +86,17 @@ Flags.init = function(myOpts) {
'an option for the chosen store module, such as --store-apikey or --store-bucket', 'an option for the chosen store module, such as --store-apikey or --store-bucket',
'bag' 'bag'
], ],
manager: [
false,
'the module name or file path of the manager module to use',
'string',
'greenlock-manager-fs'
],
'manager-xxxx': [
false,
'an option for the chosen manager module, such as --manager-apikey or --manager-dburl',
'bag'
],
challenge: [ challenge: [
false, false,
'the module name or file path of the HTTP-01, DNS-01, or TLS-ALPN-01 challenge module to use', 'the module name or file path of the HTTP-01, DNS-01, or TLS-ALPN-01 challenge module to use',
@ -142,7 +161,16 @@ Flags.init = function(myOpts) {
myOpts.forceSave || false myOpts.forceSave || false
] ]
}; };
};
Flags.init = function(myOpts) {
return GreenlockRc(pkgpath).then(async function(rc) {
rc._bin_mode = true;
var Greenlock = require('../../');
// this is a copy, so it's safe to modify
var greenlock = Greenlock.create(rc);
var mconf = await greenlock.manager.defaults();
var flagOptions = Flags.flags(mconf, myOpts);
return { return {
flagOptions, flagOptions,
rc, rc,

2
bin/lib/greenlockrc.js

@ -89,7 +89,7 @@ module.exports = async function(pkgpath, manager, rc) {
if (rc) { if (rc) {
changed = true; changed = true;
Object.keys(rc).forEach(function(k) { Object.keys(rc).forEach(function(k) {
_rc[k] = rc; _rc[k] = rc[k];
}); });
} }

9
bin/tmpl/app.tmpl.js

@ -0,0 +1,9 @@
'use strict';
// Here's a vanilla HTTP app to start,
// but feel free to replace it with Express, Koa, etc
var app = function(req, res) {
res.end('Hello, Encrypted World!');
};
module.exports = app;

36
bin/tmpl/server.tmpl.js

@ -0,0 +1,36 @@
'use strict';
require('greenlock-express')
.init(function() {
// .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;
// whether or not to run at cloudscale
options.cluster = false;
return options;
})
.ready(function(glx) {
var app = require('./app.js');
// Serves on 80 and 443
// Get's SSL certificates magically!
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 rcPath = '.greenlockrc';
var rc = fs.readFileSync(rcPath, 'utf8');
return JSON.parse(rc);
}

5
plugins.js

@ -208,6 +208,11 @@ P._loadSync = function(modname) {
}; };
P._installSync = function(moduleName) { P._installSync = function(moduleName) {
try {
return require(moduleName);
} catch (e) {
// continue
}
var npm = 'npm'; var npm = 'npm';
var args = ['install', '--save', moduleName]; var args = ['install', '--save', moduleName];
var out = ''; var out = '';

2
tests/cli.sh

@ -14,13 +14,13 @@ node bin/greenlock.js defaults
node bin/greenlock.js defaults --challenge-dns-01 foo-http-01-bar --challenge-dns-01-token BIG_TOKEN node bin/greenlock.js defaults --challenge-dns-01 foo-http-01-bar --challenge-dns-01-token BIG_TOKEN
# using --challenge is exclusive (will delete things not mentioned) # using --challenge is exclusive (will delete things not mentioned)
node bin/greenlock.js defaults --challenge acme-http-01-standalone node bin/greenlock.js defaults --challenge acme-http-01-standalone
node bin/greenlock.js remove --subject example.com
# should delete all and add just this one anew # should delete all and add just this one anew
node bin/greenlock.js update --subject example.com --challenge bar-http-01-baz node bin/greenlock.js update --subject example.com --challenge bar-http-01-baz
# should add, leaving the existing # should add, leaving the existing
node bin/greenlock.js update --subject example.com --challenge-dns-01 baz-dns-01-qux --challenge-dns-01-token BIG_TOKEN node bin/greenlock.js update --subject example.com --challenge-dns-01 baz-dns-01-qux --challenge-dns-01-token BIG_TOKEN
# should delete all and add just this one anew # should delete all and add just this one anew
node bin/greenlock.js update --subject example.com --challenge bar-http-01-baz node bin/greenlock.js update --subject example.com --challenge bar-http-01-baz
node bin/greenlock.js remove --subject example.com
# TODO test for failure # TODO test for failure
# node bin/greenlock.js add --subject example.com # node bin/greenlock.js add --subject example.com

Loading…
Cancel
Save