miroir de
				https://github.com/therootcompany/greenlock.js.git
				synchronisé 2024-11-16 17:29:00 +00:00 
			
		
		
		
	CLI: implement init and bugfix .greenlockrc
Cette révision appartient à :
		
							Parent
							
								
									5b38fe7fcd
								
							
						
					
					
						révision
						341347ba3e
					
				| @ -5,7 +5,7 @@ var args = process.argv.slice(2); | ||||
| var arg0 = args[0]; | ||||
| //console.log(args);
 | ||||
| 
 | ||||
| var found = ['certonly', 'add', 'update', 'config', 'defaults', 'remove'].some( | ||||
| var found = ['certonly', 'add', 'update', 'config', 'defaults', 'remove', 'init'].some( | ||||
|     function(k) { | ||||
|         if (k === arg0) { | ||||
|             require('./' + k); | ||||
|  | ||||
							
								
								
									
										135
									
								
								bin/init.js
									
									
									
									
									
										Fichier normal
									
								
							
							
						
						
									
										135
									
								
								bin/init.js
									
									
									
									
									
										Fichier normal
									
								
							| @ -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); | ||||
| } | ||||
| @ -14,7 +14,7 @@ CLI.parse = function(conf) { | ||||
|         var v = conf[k]; | ||||
|         if (!v) { | ||||
|             console.error( | ||||
|                 'Developer Error: missing config value for', | ||||
|                 'Developer Error: missing cli flag definition for', | ||||
|                 JSON.stringify(k) | ||||
|             ); | ||||
|             process.exit(1); | ||||
|  | ||||
							
								
								
									
										278
									
								
								bin/lib/flags.js
									
									
									
									
									
								
							
							
						
						
									
										278
									
								
								bin/lib/flags.js
									
									
									
									
									
								
							| @ -7,142 +7,170 @@ var path = require('path'); | ||||
| var pkgpath = path.join(process.cwd(), 'package.json'); | ||||
| 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) { | ||||
|         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 = { | ||||
|             subject: [ | ||||
|                 false, | ||||
|                 'the "subject" (primary domain) of the certificate', | ||||
|                 'string' | ||||
|             ], | ||||
|             altnames: [ | ||||
|                 false, | ||||
|                 'the "subject alternative names" (additional domains) on the certificate, the first of which MUST be the subject', | ||||
|                 'string' | ||||
|             ], | ||||
|             servername: [ | ||||
|                 false, | ||||
|                 'a name that matches a subject or altname', | ||||
|                 'string' | ||||
|             ], | ||||
|             servernames: [ | ||||
|                 false, | ||||
|                 'a list of names that matches a subject or altname', | ||||
|                 'string' | ||||
|             ], | ||||
|             'renew-offset': [ | ||||
|                 false, | ||||
|                 "time to wait until renewing the cert such as '45d' (45 days after being issued) or '-3w' (3 weeks before expiration date)", | ||||
|                 'string', | ||||
|                 mconf.renewOffset | ||||
|             ], | ||||
|             'customer-email': [ | ||||
|                 false, | ||||
|                 "the email address of the owner of the domain or site (not necessarily the Let's Encrypt or ACME subscriber)", | ||||
|                 'string' | ||||
|             ], | ||||
|             'subscriber-email': [ | ||||
|                 false, | ||||
|                 "the email address of the Let's Encrypt or ACME Account subscriber (not necessarily the domain owner)", | ||||
|                 'string' | ||||
|             ], | ||||
|             'account-key-type': [ | ||||
|                 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)", | ||||
|                 'string', | ||||
|                 mconf.accountKeyType | ||||
|             ], | ||||
|             'server-key-type': [ | ||||
|                 false, | ||||
|                 "either 'RSA-2048' or 'P-256' (ECDSA) - although other values are technically supported, they don't make sense and won't work with many services (More bits != More security)", | ||||
|                 'string', | ||||
|                 mconf.serverKeyType | ||||
|             ], | ||||
|             store: [ | ||||
|                 false, | ||||
|                 'the module name or file path of the store module to use', | ||||
|                 'string' | ||||
|                 //mconf.store.module
 | ||||
|             ], | ||||
|             'store-xxxx': [ | ||||
|                 false, | ||||
|                 'an option for the chosen store module, such as --store-apikey or --store-bucket', | ||||
|                 'bag' | ||||
|             ], | ||||
|             challenge: [ | ||||
|                 false, | ||||
|                 'the module name or file path of the HTTP-01, DNS-01, or TLS-ALPN-01 challenge module to use', | ||||
|                 'string', | ||||
|                 '' | ||||
|                 /* | ||||
|     return { | ||||
|         subject: [ | ||||
|             false, | ||||
|             'the "subject" (primary domain) of the certificate', | ||||
|             'string' | ||||
|         ], | ||||
|         altnames: [ | ||||
|             false, | ||||
|             'the "subject alternative names" (additional domains) on the certificate, the first of which MUST be the subject', | ||||
|             'string' | ||||
|         ], | ||||
|         servername: [ | ||||
|             false, | ||||
|             'a name that matches a subject or altname', | ||||
|             'string' | ||||
|         ], | ||||
|         servernames: [ | ||||
|             false, | ||||
|             'a list of names that matches a subject or altname', | ||||
|             'string' | ||||
|         ], | ||||
|         cluster: [false, 'initialize with cluster mode on', 'boolean', false], | ||||
|         'renew-offset': [ | ||||
|             false, | ||||
|             "time to wait until renewing the cert such as '45d' (45 days after being issued) or '-3w' (3 weeks before expiration date)", | ||||
|             'string', | ||||
|             mconf.renewOffset | ||||
|         ], | ||||
|         'customer-email': [ | ||||
|             false, | ||||
|             "the email address of the owner of the domain or site (not necessarily the Let's Encrypt or ACME subscriber)", | ||||
|             'string' | ||||
|         ], | ||||
|         'subscriber-email': [ | ||||
|             false, | ||||
|             "the email address of the Let's Encrypt or ACME Account subscriber (not necessarily the domain owner)", | ||||
|             'string' | ||||
|         ], | ||||
|         'maintainer-email': [ | ||||
|             false, | ||||
|             'the maintainance contact for security and critical bug notices', | ||||
|             'string' | ||||
|         ], | ||||
|         'account-key-type': [ | ||||
|             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)", | ||||
|             'string', | ||||
|             mconf.accountKeyType | ||||
|         ], | ||||
|         'server-key-type': [ | ||||
|             false, | ||||
|             "either 'RSA-2048' or 'P-256' (ECDSA) - although other values are technically supported, they don't make sense and won't work with many services (More bits != More security)", | ||||
|             'string', | ||||
|             mconf.serverKeyType | ||||
|         ], | ||||
|         store: [ | ||||
|             false, | ||||
|             'the module name or file path of the store module to use', | ||||
|             'string' | ||||
|             //mconf.store.module
 | ||||
|         ], | ||||
|         'store-xxxx': [ | ||||
|             false, | ||||
|             'an option for the chosen store module, such as --store-apikey or --store-bucket', | ||||
|             '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: [ | ||||
|             false, | ||||
|             'the module name or file path of the HTTP-01, DNS-01, or TLS-ALPN-01 challenge module to use', | ||||
|             'string', | ||||
|             '' | ||||
|             /* | ||||
|                 Object.keys(mconf.challenges) | ||||
|                     .map(function(typ) { | ||||
|                         return mconf.challenges[typ].module; | ||||
|                     }) | ||||
|                     .join(',') | ||||
|                 */ | ||||
|             ], | ||||
|             'challenge-xxxx': [ | ||||
|                 false, | ||||
|                 'an option for the chosen challenge module, such as --challenge-apikey or --challenge-bucket', | ||||
|                 'bag' | ||||
|             ], | ||||
|             'challenge-json': [ | ||||
|                 false, | ||||
|                 'a JSON string containing all option for the chosen challenge module (instead of --challenge-xxxx)', | ||||
|                 'json', | ||||
|                 '{}' | ||||
|             ], | ||||
|             'challenge-http-01': [ | ||||
|                 false, | ||||
|                 'the module name or file path of the HTTP-01 to add', | ||||
|                 'string' | ||||
|                 //(mconf.challenges['http-01'] || {}).module
 | ||||
|             ], | ||||
|             'challenge-http-01-xxxx': [ | ||||
|                 false, | ||||
|                 'an option for the chosen challenge module, such as --challenge-http-01-apikey or --challenge-http-01-bucket', | ||||
|                 'bag' | ||||
|             ], | ||||
|             'challenge-dns-01': [ | ||||
|                 false, | ||||
|                 'the module name or file path of the DNS-01 to add', | ||||
|                 'string' | ||||
|                 //(mconf.challenges['dns-01'] || {}).module
 | ||||
|             ], | ||||
|             'challenge-dns-01-xxxx': [ | ||||
|                 false, | ||||
|                 'an option for the chosen challenge module, such as --challenge-dns-01-apikey or --challenge-dns-01-bucket', | ||||
|                 'bag' | ||||
|             ], | ||||
|             'challenge-tls-alpn-01': [ | ||||
|                 false, | ||||
|                 'the module name or file path of the DNS-01 to add', | ||||
|                 'string' | ||||
|                 //(mconf.challenges['tls-alpn-01'] || {}).module
 | ||||
|             ], | ||||
|             'challenge-tls-alpn-01-xxxx': [ | ||||
|                 false, | ||||
|                 'an option for the chosen challenge module, such as --challenge-tls-alpn-01-apikey or --challenge-tls-alpn-01-bucket', | ||||
|                 'bag' | ||||
|             ], | ||||
|             'force-save': [ | ||||
|                 false, | ||||
|                 "save all options for this site, even if it's the same as the defaults", | ||||
|                 'boolean', | ||||
|                 myOpts.forceSave || false | ||||
|             ] | ||||
|         }; | ||||
|         ], | ||||
|         'challenge-xxxx': [ | ||||
|             false, | ||||
|             'an option for the chosen challenge module, such as --challenge-apikey or --challenge-bucket', | ||||
|             'bag' | ||||
|         ], | ||||
|         'challenge-json': [ | ||||
|             false, | ||||
|             'a JSON string containing all option for the chosen challenge module (instead of --challenge-xxxx)', | ||||
|             'json', | ||||
|             '{}' | ||||
|         ], | ||||
|         'challenge-http-01': [ | ||||
|             false, | ||||
|             'the module name or file path of the HTTP-01 to add', | ||||
|             'string' | ||||
|             //(mconf.challenges['http-01'] || {}).module
 | ||||
|         ], | ||||
|         'challenge-http-01-xxxx': [ | ||||
|             false, | ||||
|             'an option for the chosen challenge module, such as --challenge-http-01-apikey or --challenge-http-01-bucket', | ||||
|             'bag' | ||||
|         ], | ||||
|         'challenge-dns-01': [ | ||||
|             false, | ||||
|             'the module name or file path of the DNS-01 to add', | ||||
|             'string' | ||||
|             //(mconf.challenges['dns-01'] || {}).module
 | ||||
|         ], | ||||
|         'challenge-dns-01-xxxx': [ | ||||
|             false, | ||||
|             'an option for the chosen challenge module, such as --challenge-dns-01-apikey or --challenge-dns-01-bucket', | ||||
|             'bag' | ||||
|         ], | ||||
|         'challenge-tls-alpn-01': [ | ||||
|             false, | ||||
|             'the module name or file path of the DNS-01 to add', | ||||
|             'string' | ||||
|             //(mconf.challenges['tls-alpn-01'] || {}).module
 | ||||
|         ], | ||||
|         'challenge-tls-alpn-01-xxxx': [ | ||||
|             false, | ||||
|             'an option for the chosen challenge module, such as --challenge-tls-alpn-01-apikey or --challenge-tls-alpn-01-bucket', | ||||
|             'bag' | ||||
|         ], | ||||
|         'force-save': [ | ||||
|             false, | ||||
|             "save all options for this site, even if it's the same as the defaults", | ||||
|             'boolean', | ||||
|             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 { | ||||
|             flagOptions, | ||||
|             rc, | ||||
|  | ||||
| @ -89,7 +89,7 @@ module.exports = async function(pkgpath, manager, rc) { | ||||
|     if (rc) { | ||||
|         changed = true; | ||||
|         Object.keys(rc).forEach(function(k) { | ||||
|             _rc[k] = rc; | ||||
|             _rc[k] = rc[k]; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										9
									
								
								bin/tmpl/app.tmpl.js
									
									
									
									
									
										Fichier normal
									
								
							
							
						
						
									
										9
									
								
								bin/tmpl/app.tmpl.js
									
									
									
									
									
										Fichier normal
									
								
							| @ -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
									
									
									
									
									
										Fichier normal
									
								
							
							
						
						
									
										36
									
								
								bin/tmpl/server.tmpl.js
									
									
									
									
									
										Fichier normal
									
								
							| @ -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); | ||||
| } | ||||
| @ -208,6 +208,11 @@ P._loadSync = function(modname) { | ||||
| }; | ||||
| 
 | ||||
| P._installSync = function(moduleName) { | ||||
|     try { | ||||
|         return require(moduleName); | ||||
|     } catch (e) { | ||||
|         // continue
 | ||||
|     } | ||||
|     var npm = 'npm'; | ||||
|     var args = ['install', '--save', moduleName]; | ||||
|     var out = ''; | ||||
|  | ||||
| @ -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 | ||||
| # using --challenge is exclusive (will delete things not mentioned) | ||||
| 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 | ||||
| node bin/greenlock.js update --subject example.com --challenge bar-http-01-baz | ||||
| # 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 | ||||
| # 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 remove --subject example.com | ||||
| 
 | ||||
| # TODO test for failure | ||||
| # node bin/greenlock.js add --subject example.com | ||||
|  | ||||
		Chargement…
	
	
			
			x
			
			
		
	
		Référencer dans un nouveau ticket
	
	Bloquer un utilisateur