| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 22:38:32 -07:00
										 |  |  | var U = require('../utils.js'); | 
					
						
							|  |  |  | var E = require('../errors.js'); | 
					
						
							| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | var warned = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  | // 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     greenlock.manager = {}; | 
					
						
							|  |  |  |     greenlock.sites = {}; | 
					
						
							|  |  |  |     //greenlock.accounts = {};
 | 
					
						
							|  |  |  |     //greenlock.certs = {};
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var allowed = [ | 
					
						
							|  |  |  |         'accountKeyType', //: ["P-256", "RSA-2048"],
 | 
					
						
							|  |  |  |         'serverKeyType', //: ["RSA-2048", "P-256"],
 | 
					
						
							|  |  |  |         'store', // : { module, specific opts },
 | 
					
						
							|  |  |  |         'challenges', // : { "http-01", "dns-01", "tls-alpn-01" },
 | 
					
						
							|  |  |  |         'subscriberEmail', | 
					
						
							|  |  |  |         'agreeToTerms', | 
					
						
							|  |  |  |         'agreeTos', | 
					
						
							|  |  |  |         'customerEmail', | 
					
						
							|  |  |  |         'renewOffset', | 
					
						
							|  |  |  |         'renewStagger', | 
					
						
							|  |  |  |         'module', // not allowed, just ignored
 | 
					
						
							|  |  |  |         'manager' | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // get / set default site settings such as
 | 
					
						
							|  |  |  |     // subscriberEmail, store, challenges, renewOffset, renewStagger
 | 
					
						
							|  |  |  |     greenlock.manager.defaults = function(conf) { | 
					
						
							|  |  |  |         return greenlock._init().then(function() { | 
					
						
							|  |  |  |             if (!conf) { | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |                 return mega.defaults(); | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (conf.sites) { | 
					
						
							|  |  |  |                 throw new Error('cannot set sites as global config'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (conf.routes) { | 
					
						
							|  |  |  |                 throw new Error('cannot set routes as global config'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // disallow keys we know to be bad
 | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 'subject', | 
					
						
							|  |  |  |                 'deletedAt', | 
					
						
							|  |  |  |                 'altnames', | 
					
						
							|  |  |  |                 'lastAttemptAt', | 
					
						
							|  |  |  |                 'expiresAt', | 
					
						
							|  |  |  |                 'issuedAt', | 
					
						
							|  |  |  |                 'renewAt', | 
					
						
							|  |  |  |                 'sites', | 
					
						
							|  |  |  |                 'routes' | 
					
						
							|  |  |  |             ].some(function(k) { | 
					
						
							|  |  |  |                 if (k in conf) { | 
					
						
							|  |  |  |                     throw new Error( | 
					
						
							|  |  |  |                         '`' + k + '` not allowed as a default setting' | 
					
						
							|  |  |  |                     ); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |             Object.keys(conf).forEach(function(k) { | 
					
						
							|  |  |  |                 if (!allowed.includes(k) && !warned[k]) { | 
					
						
							|  |  |  |                     warned[k] = true; | 
					
						
							|  |  |  |                     console.warn( | 
					
						
							|  |  |  |                         k + | 
					
						
							|  |  |  |                             " isn't a known key. Please open an issue and let us know the use case." | 
					
						
							|  |  |  |                     ); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Object.keys(conf).forEach(function(k) { | 
					
						
							|  |  |  |                 if (-1 !== ['module', 'manager'].indexOf(k)) { | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ('undefined' === typeof k) { | 
					
						
							|  |  |  |                     throw new Error( | 
					
						
							|  |  |  |                         "'" + | 
					
						
							|  |  |  |                             k + | 
					
						
							|  |  |  |                             "' should be set to a value, or `null`, but not left `undefined`" | 
					
						
							|  |  |  |                     ); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |             return mega.defaults(conf); | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |         }); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-11-05 02:50:27 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     greenlock.manager._defaults = function(opts) { | 
					
						
							|  |  |  |         return mega.defaults(opts); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-03 01:58:01 -06:00
										 |  |  |     greenlock.manager.add = function(args) { | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |         if (!args || !Array.isArray(args.altnames) || !args.altnames.length) { | 
					
						
							|  |  |  |             throw new Error( | 
					
						
							|  |  |  |                 'you must specify `altnames` when adding a new site' | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (args.renewAt) { | 
					
						
							|  |  |  |             throw new Error( | 
					
						
							|  |  |  |                 'you cannot specify `renewAt` when adding a new site' | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return greenlock.manager.set(args); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO agreeToTerms should be handled somewhere... maybe?
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Add and update remains because I said I had locked the API
 | 
					
						
							|  |  |  |     greenlock.manager.set = greenlock.manager.update = function(args) { | 
					
						
							|  |  |  |         return greenlock._init().then(function() { | 
					
						
							|  |  |  |             // The goal is to make this decently easy to manage by hand without mistakes
 | 
					
						
							|  |  |  |             // but also reasonably easy to error check and correct
 | 
					
						
							|  |  |  |             // and to make deterministic auto-corrections
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             args.subject = checkSubject(args); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             //var subscriberEmail = args.subscriberEmail;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // TODO shortcut the other array checks when not necessary
 | 
					
						
							|  |  |  |             if (Array.isArray(args.altnames)) { | 
					
						
							|  |  |  |                 args.altnames = checkAltnames(args.subject, args); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // at this point we know that subject is the first of altnames
 | 
					
						
							|  |  |  |             return Promise.all( | 
					
						
							|  |  |  |                 (args.altnames || []).map(function(d) { | 
					
						
							|  |  |  |                     d = d.replace('*.', ''); | 
					
						
							|  |  |  |                     return U._validDomain(d); | 
					
						
							|  |  |  |                 }) | 
					
						
							|  |  |  |             ).then(function() { | 
					
						
							|  |  |  |                 if (!U._uniqueNames(args.altnames || [])) { | 
					
						
							|  |  |  |                     throw E.NOT_UNIQUE( | 
					
						
							|  |  |  |                         'add', | 
					
						
							|  |  |  |                         "'" + args.altnames.join("' '") + "'" | 
					
						
							|  |  |  |                     ); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // durations
 | 
					
						
							|  |  |  |                 if (args.renewOffset) { | 
					
						
							|  |  |  |                     args.renewOffset = U._parseDuration(args.renewOffset); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 if (args.renewStagger) { | 
					
						
							|  |  |  |                     args.renewStagger = U._parseDuration(args.renewStagger); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |                 return mega.set(args).then(function(result) { | 
					
						
							| 
									
										
										
										
											2019-11-01 23:33:11 -06:00
										 |  |  |                     if (!gconf._bin_mode) { | 
					
						
							|  |  |  |                         greenlock.renew({}).catch(function(err) { | 
					
						
							|  |  |  |                             if (!err.context) { | 
					
						
							|  |  |  |                                 err.contxt = 'renew'; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             greenlock._notify('error', err); | 
					
						
							|  |  |  |                         }); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |                     return result; | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |     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); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     greenlock.manager.remove = function(args) { | 
					
						
							| 
									
										
										
										
											2019-11-03 01:58:01 -06:00
										 |  |  |         return Promise.resolve().then(function() { | 
					
						
							|  |  |  |             args.subject = checkSubject(args); | 
					
						
							|  |  |  |             if (args.servername) { | 
					
						
							|  |  |  |                 throw new Error( | 
					
						
							|  |  |  |                     'remove() should be called with `subject` only, if you wish to remove altnames use `update()`' | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (args.altnames) { | 
					
						
							|  |  |  |                 throw new Error( | 
					
						
							|  |  |  |                     'remove() should be called with `subject` only, not `altnames`' | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             // TODO check no altnames
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |             return mega.remove(args); | 
					
						
							| 
									
										
										
										
											2019-11-03 01:58:01 -06:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         subject: site.subject, | 
					
						
							|  |  |  |         altnames: site.altnames, | 
					
						
							|  |  |  |         //issuedAt: site.issuedAt,
 | 
					
						
							|  |  |  |         //expiresAt: site.expiresAt,
 | 
					
						
							|  |  |  |         renewOffset: site.renewOffset, | 
					
						
							|  |  |  |         renewStagger: site.renewStagger, | 
					
						
							|  |  |  |         renewAt: site.renewAt, | 
					
						
							|  |  |  |         subscriberEmail: site.subscriberEmail, | 
					
						
							|  |  |  |         customerEmail: site.customerEmail, | 
					
						
							|  |  |  |         challenges: site.challenges, | 
					
						
							|  |  |  |         store: site.store | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     */ | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |     // no transaction promise here because it calls set
 | 
					
						
							|  |  |  |     greenlock._find = async function(args) { | 
					
						
							|  |  |  |         args = _mangleFindArgs(args); | 
					
						
							|  |  |  |         var ours = await mega.find(args); | 
					
						
							|  |  |  |         if (!myFind) { | 
					
						
							|  |  |  |             return ours; | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |         // if the user has an overlay find function we'll do a diff
 | 
					
						
							|  |  |  |         // between the managed state and the overlay, and choose
 | 
					
						
							|  |  |  |         // what was found.
 | 
					
						
							|  |  |  |         var theirs = await myFind(args); | 
					
						
							|  |  |  |         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); | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // delete the things that are gone
 | 
					
						
							|  |  |  |         ours.forEach(function(_older) { | 
					
						
							|  |  |  |             if (!_older._exists) { | 
					
						
							|  |  |  |                 _older.deletedAt = Date.now(); | 
					
						
							|  |  |  |                 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     greenlock.manager.init = mega.init; | 
					
						
							| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function checkSubject(args) { | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     if (!args || !args.subject) { | 
					
						
							|  |  |  |         throw new Error('you must specify `subject` when configuring a site'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* | 
					
						
							| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | 		if (!args.subject) { | 
					
						
							|  |  |  | 			throw E.NO_SUBJECT('add'); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  |     */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     var subject = (args.subject || '').toLowerCase(); | 
					
						
							|  |  |  |     if (subject !== args.subject) { | 
					
						
							|  |  |  |         console.warn('`subject` must be lowercase', args.subject); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     return U._encodeName(subject); | 
					
						
							| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function checkAltnames(subject, args) { | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     // the things we have to check and get right
 | 
					
						
							|  |  |  |     var altnames = (args.altnames || []).map(function(name) { | 
					
						
							|  |  |  |         return String(name || '').toLowerCase(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-01 23:33:11 -06:00
										 |  |  |     // punycode BEFORE validation
 | 
					
						
							|  |  |  |     // (set, find, remove)
 | 
					
						
							|  |  |  |     if (altnames.join() !== args.altnames.join()) { | 
					
						
							|  |  |  |         console.warn( | 
					
						
							|  |  |  |             'all domains in `altnames` must be lowercase:', | 
					
						
							|  |  |  |             args.altnames | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args.altnames = args.altnames.map(U._encodeName); | 
					
						
							|  |  |  |     if ( | 
					
						
							|  |  |  |         !args.altnames.every(function(d) { | 
					
						
							|  |  |  |             return U._validName(d); | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         throw E.INVALID_HOSTNAME('add', "'" + args.altnames.join("' '") + "'"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-01 23:33:11 -06:00
										 |  |  |     if (subject && subject !== args.altnames[0]) { | 
					
						
							|  |  |  |         throw E.BAD_ORDER( | 
					
						
							|  |  |  |             'add', | 
					
						
							|  |  |  |             '(' + args.subject + ") '" + args.altnames.join("' '") + "'" | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* | 
					
						
							|  |  |  |     if (subject && subject !== altnames[0]) { | 
					
						
							|  |  |  |         throw new Error( | 
					
						
							|  |  |  |             '`subject` must be the first domain in `altnames`', | 
					
						
							|  |  |  |             args.subject, | 
					
						
							|  |  |  |             altnames.join(' ') | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-01 23:33:11 -06:00
										 |  |  |     */ | 
					
						
							| 
									
										
										
										
											2019-10-31 16:26:18 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return altnames; | 
					
						
							| 
									
										
										
										
											2019-10-31 05:49:37 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | function loadManager(gconf) { | 
					
						
							|  |  |  |     var m; | 
					
						
							|  |  |  |     // 1. Get the manager
 | 
					
						
							|  |  |  |     // 2. Figure out if we need to wrap it
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 01:21:31 -07:00
										 |  |  |     /* | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |     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' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-11-18 01:21:31 -07:00
										 |  |  |     */ | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |     try { | 
					
						
							|  |  |  |         // wrap this to be safe for @greenlock/manager
 | 
					
						
							| 
									
										
										
										
											2019-11-18 01:21:31 -07:00
										 |  |  |         m = require(gconf.manager.module).create(gconf.manager); | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |     } 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( | 
					
						
							| 
									
										
										
										
											2019-11-18 01:21:31 -07:00
										 |  |  |             gconf.manager.module + | 
					
						
							|  |  |  |                 ' implements `set()`, but not `get()` or `find()`' | 
					
						
							| 
									
										
										
										
											2019-11-05 00:01:31 -07:00
										 |  |  |         ); | 
					
						
							|  |  |  |     } 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; | 
					
						
							|  |  |  | } |