2019-11-03 07:58:01 +00:00
'use strict' ;
var Flags = module . exports ;
var path = require ( 'path' ) ;
//var pkgpath = path.join(__dirname, '..', 'package.json');
var pkgpath = path . join ( process . cwd ( ) , 'package.json' ) ;
var GreenlockRc = require ( './greenlockrc.js' ) ;
2019-11-03 09:51:32 +00:00
// 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
2019-11-03 07:58:01 +00:00
if ( ! myOpts ) {
myOpts = { } ;
}
2019-11-03 09:51:32 +00:00
return {
2019-11-03 17:01:32 +00:00
all : [
false ,
'search all site configs rather than by --subject or --servernames' ,
'boolean'
] ,
2019-11-03 09:51:32 +00:00
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' ,
''
/ *
2019-11-03 07:58:01 +00:00
Object . keys ( mconf . challenges )
. map ( function ( typ ) {
return mconf . challenges [ typ ] . module ;
} )
. join ( ',' )
* /
2019-11-03 09:51:32 +00:00
] ,
'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
]
} ;
} ;
2019-11-03 07:58:01 +00:00
2019-11-03 09:51:32 +00:00
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 ) ;
2019-11-03 07:58:01 +00:00
return {
flagOptions ,
rc ,
greenlock ,
mconf
} ;
} ) ;
} ;
Flags . mangleFlags = function ( flags , mconf , sconf , extras ) {
if ( extras ) {
if ( extras . forceSave ) {
flags . forceSave = true ;
}
}
//console.log('debug a:', flags);
if ( 'altnames' in flags ) {
flags . altnames = ( flags . altnames || '' ) . split ( /[,\s]+/ ) . filter ( Boolean ) ;
}
if ( 'servernames' in flags ) {
flags . servernames = ( flags . servernames || '' )
. split ( /[,\s]+/ )
. filter ( Boolean ) ;
}
var store ;
if ( flags . store ) {
store = flags . storeOpts ;
store . module = flags . store ;
flags . store = store ;
} else {
delete flags . store ;
}
delete flags . storeOpts ;
// If this is additive, make an object to hold all values
var isAdditive = [
[ 'http-01' , 'Http01' ] ,
[ 'dns-01' , 'Dns01' ] ,
[ 'tls-alpn-01' , 'TlsAlpn01' ]
] . some ( function ( types ) {
var typCamel = types [ 1 ] ;
var modname = 'challenge' + typCamel ;
if ( flags [ modname ] ) {
if ( ! flags . challenges ) {
flags . challenges = { } ;
}
return true ;
}
} ) ;
if ( isAdditive && sconf ) {
// copy over the old
var schallenges = sconf . challenges || { } ;
Object . keys ( schallenges ) . forEach ( function ( k ) {
if ( ! flags . challenges [ k ] ) {
flags . challenges [ k ] = schallenges [ k ] ;
}
} ) ;
}
var typ ;
var challenge ;
if ( flags . challenge ) {
// this varient of the flag is exclusive
flags . challenges = { } ;
isAdditive = false ;
if ( /http-01/ . test ( flags . challenge ) ) {
typ = 'http-01' ;
} else if ( /dns-01/ . test ( flags . challenge ) ) {
typ = 'dns-01' ;
} else if ( /tls-alpn-01/ . test ( flags . challenge ) ) {
typ = 'tls-alpn-01' ;
}
var modname = 'challenge' ;
var optsname = 'challengeOpts' ;
challenge = flags [ optsname ] ;
// JSON may already have module name
if ( challenge . module ) {
if ( flags [ modname ] && challenge . module !== flags [ modname ] ) {
console . error (
'module names do not match:' ,
JSON . stringify ( challenge . module ) ,
JSON . stringify ( flags [ modname ] )
) ;
process . exit ( 1 ) ;
}
} else {
challenge . module = flags [ modname ] ;
}
flags . challenges [ typ ] = challenge ;
var chall = mconf . challenges [ typ ] ;
if ( chall && challenge . module === chall . module ) {
var keys = Object . keys ( challenge ) ;
var same =
! keys . length ||
keys . every ( function ( k ) {
return chall [ k ] === challenge [ k ] ;
} ) ;
if ( same && ! flags . forceSave ) {
delete flags . challenges ;
}
}
}
delete flags . challenge ;
delete flags . challengeOpts ;
// Add each of the values, including the existing
[
[ 'http-01' , 'Http01' ] ,
[ 'dns-01' , 'Dns01' ] ,
[ 'tls-alpn-01' , 'TlsAlpn01' ]
] . forEach ( function ( types ) {
var typ = types [ 0 ] ;
var typCamel = types [ 1 ] ;
var modname = 'challenge' + typCamel ;
var optsname = 'challenge' + typCamel + 'Opts' ;
var chall = mconf . challenges [ typ ] ;
var challenge = flags [ optsname ] ;
// this variant of the flag is additive
if ( isAdditive && chall && flags . forceSave ) {
if ( flags . challenges && ! flags . challenges [ typ ] ) {
flags . challenges [ typ ] = chall ;
}
}
if ( ! flags [ modname ] ) {
delete flags [ modname ] ;
delete flags [ optsname ] ;
return ;
}
// JSON may already have module name
if ( challenge . module ) {
if ( flags [ modname ] && challenge . module !== flags [ modname ] ) {
console . error (
'module names do not match:' ,
JSON . stringify ( challenge . module ) ,
JSON . stringify ( flags [ modname ] )
) ;
process . exit ( 1 ) ;
}
} else {
challenge . module = flags [ modname ] ;
}
if ( flags [ modname ] ) {
if ( ! flags . challenges ) {
flags . challenges = { } ;
}
flags . challenges [ typ ] = challenge ;
}
// Check to see if this is already what's set in the defaults
if ( chall && challenge . module === chall . module ) {
var keys = Object . keys ( challenge ) ;
// Check if all of the options are also the same
var same =
! keys . length ||
keys . every ( function ( k ) {
return chall [ k ] === challenge [ k ] ;
} ) ;
if ( same && ! flags . forceSave ) {
// If it's already the global, don't make it the per-site
delete flags [ modname ] ;
delete flags [ optsname ] ;
}
}
delete flags [ modname ] ;
delete flags [ optsname ] ;
} ) ;
[
[ 'accountKeyType' , [ /256/ , /384/ , /EC/ ] , 'EC-P256' ] ,
[ 'serverKeyType' , [ /RSA/ ] , 'RSA-2048' ]
] . forEach ( function ( k ) {
var key = k [ 0 ] ;
var vals = k [ 1 ] ;
var val = flags [ key ] ;
if ( val ) {
if (
! vals . some ( function ( v ) {
return v . test ( val ) ;
} )
) {
flags [ key ] = k [ 2 ] ;
console . warn (
key ,
"does not allow the value '" ,
val ,
"' using the default '" ,
k [ 2 ] ,
"' instead."
) ;
}
}
} ) ;
Object . keys ( flags ) . forEach ( function ( k ) {
if ( flags [ k ] === mconf [ k ] && ! flags . forceSave ) {
delete flags [ k ] ;
}
} ) ;
//console.log('debug z:', flags);
delete flags . forceSave ;
} ;