662 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			662 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
 | 
						|
var pkg = require('./package.json');
 | 
						|
 | 
						|
var ACME = require('@root/acme');
 | 
						|
var Greenlock = module.exports;
 | 
						|
var request = require('@root/request');
 | 
						|
var process = require('process');
 | 
						|
 | 
						|
var G = Greenlock;
 | 
						|
var U = require('./utils.js');
 | 
						|
var E = require('./errors.js');
 | 
						|
var P = require('./plugins.js');
 | 
						|
var A = require('./accounts.js');
 | 
						|
var C = require('./certificates.js');
 | 
						|
 | 
						|
var DIR = require('./lib/directory-url.js');
 | 
						|
var ChWrapper = require('./lib/challenges-wrapper.js');
 | 
						|
var MngWrapper = require('./lib/manager-wrapper.js');
 | 
						|
 | 
						|
var UserEvents = require('./user-events.js');
 | 
						|
var Init = require('./lib/init.js');
 | 
						|
 | 
						|
var caches = {};
 | 
						|
 | 
						|
// { maintainerEmail, directoryUrl, subscriberEmail, store, challenges  }
 | 
						|
G.create = function(gconf) {
 | 
						|
    var greenlock = {};
 | 
						|
    var gdefaults = {};
 | 
						|
    if (!gconf) {
 | 
						|
        gconf = {};
 | 
						|
    }
 | 
						|
 | 
						|
    greenlock._create = function() {
 | 
						|
        if (!gconf._bin_mode) {
 | 
						|
            if (!gconf.maintainerEmail) {
 | 
						|
                throw E.NO_MAINTAINER('create');
 | 
						|
            }
 | 
						|
 | 
						|
            // TODO send welcome message with benefit info
 | 
						|
            U._validMx(gconf.maintainerEmail).catch(function() {
 | 
						|
                console.error(
 | 
						|
                    'invalid maintainer contact info:',
 | 
						|
                    gconf.maintainerEmail
 | 
						|
                );
 | 
						|
 | 
						|
                // maybe move this to init and don't exit the process, just in case
 | 
						|
                process.exit(1);
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        if ('function' === typeof gconf.notify) {
 | 
						|
            gdefaults.notify = gconf.notify;
 | 
						|
        } else {
 | 
						|
            gdefaults.notify = _notify;
 | 
						|
        }
 | 
						|
 | 
						|
        gconf = Init._init(gconf);
 | 
						|
 | 
						|
        // OK: /path/to/blah
 | 
						|
        // OK: npm-name-blah
 | 
						|
        // NOT OK: ./rel/path/to/blah
 | 
						|
        // Error: .blah
 | 
						|
        if ('.' === (gconf.manager.module || '')[0]) {
 | 
						|
            if (!gconf.packageRoot) {
 | 
						|
                gconf.packageRoot = process.cwd();
 | 
						|
                console.warn(
 | 
						|
                    '`packageRoot` not defined, trying ' + gconf.packageRoot
 | 
						|
                );
 | 
						|
            }
 | 
						|
            gconf.manager.module =
 | 
						|
                gconf.packageRoot + '/' + gconf.manager.module.slice(2);
 | 
						|
        }
 | 
						|
 | 
						|
        // Wraps each of the following with appropriate error checking
 | 
						|
        // greenlock.manager.defaults
 | 
						|
        // greenlock.sites.add
 | 
						|
        // greenlock.sites.update
 | 
						|
        // greenlock.sites.remove
 | 
						|
        // greenlock.sites.find
 | 
						|
        // greenlock.sites.get
 | 
						|
        MngWrapper.wrap(greenlock, gconf);
 | 
						|
        // The goal here is to reduce boilerplate, such as error checking
 | 
						|
        // and duration parsing, that a manager must implement
 | 
						|
        greenlock.sites.add = greenlock.add = greenlock.manager.add;
 | 
						|
        greenlock.sites.update = greenlock.update = greenlock.manager.update;
 | 
						|
        greenlock.sites.remove = greenlock.remove = greenlock.manager.remove;
 | 
						|
 | 
						|
        // Exports challenges.get for Greenlock Express HTTP-01,
 | 
						|
        // and whatever odd use case pops up, I suppose
 | 
						|
        // greenlock.challenges.get
 | 
						|
        ChWrapper.wrap(greenlock);
 | 
						|
 | 
						|
        DIR._getDefaultDirectoryUrl('', gconf.staging, '');
 | 
						|
        if (gconf.directoryUrl) {
 | 
						|
            gdefaults.directoryUrl = gconf.directoryUrl;
 | 
						|
        }
 | 
						|
 | 
						|
        greenlock._defaults = gdefaults;
 | 
						|
        greenlock._defaults.debug = gconf.debug;
 | 
						|
 | 
						|
        if (!gconf._bin_mode && false !== gconf.renew) {
 | 
						|
            // renew every 90-ish minutes (random for staggering)
 | 
						|
            // the weak setTimeout (unref) means that when run as a CLI process this
 | 
						|
            // will still finish as expected, and not wait on the timeout
 | 
						|
            (function renew() {
 | 
						|
                setTimeout(function() {
 | 
						|
                    greenlock.renew({});
 | 
						|
                    renew();
 | 
						|
                }, Math.PI * 30 * 60 * 1000).unref();
 | 
						|
            })();
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // The purpose of init is to make MCONF the source of truth
 | 
						|
    greenlock._init = function() {
 | 
						|
        var p;
 | 
						|
        greenlock._init = function() {
 | 
						|
            return p;
 | 
						|
        };
 | 
						|
 | 
						|
        p = greenlock.manager
 | 
						|
            .init({
 | 
						|
                request: request
 | 
						|
                //punycode: require('punycode')
 | 
						|
            })
 | 
						|
            .then(async function() {
 | 
						|
                var MCONF = await greenlock.manager._defaults();
 | 
						|
                mergeDefaults(MCONF, gconf);
 | 
						|
                if (true === MCONF.agreeToTerms) {
 | 
						|
                    gdefaults.agreeToTerms = function(tos) {
 | 
						|
                        return Promise.resolve(tos);
 | 
						|
                    };
 | 
						|
                }
 | 
						|
 | 
						|
                return greenlock.manager._defaults(MCONF);
 | 
						|
            })
 | 
						|
            .catch(function(err) {
 | 
						|
                if ('load_plugin' !== err.context) {
 | 
						|
                    console.error('Fatal error during greenlock init:');
 | 
						|
                    console.error(err.message);
 | 
						|
                }
 | 
						|
                if (!gconf._bin_mode) {
 | 
						|
                    process.exit(1);
 | 
						|
                }
 | 
						|
            });
 | 
						|
        return p;
 | 
						|
    };
 | 
						|
 | 
						|
    greenlock.notify = greenlock._notify = function(ev, params) {
 | 
						|
        var mng = greenlock.manager;
 | 
						|
 | 
						|
        if ('_' === String(ev)[0]) {
 | 
						|
            if ('_cert_issue' === ev) {
 | 
						|
                try {
 | 
						|
                    mng.update({
 | 
						|
                        subject: params.subject,
 | 
						|
                        renewAt: params.renewAt
 | 
						|
                    }).catch(function(e) {
 | 
						|
                        e.context = '_cert_issue';
 | 
						|
                        greenlock._notify('error', e);
 | 
						|
                    });
 | 
						|
                } catch (e) {
 | 
						|
                    e.context = '_cert_issue';
 | 
						|
                    greenlock._notify('error', e);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            // trap internal events internally
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
            var p = greenlock._defaults.notify(ev, params);
 | 
						|
            if (p && p.catch) {
 | 
						|
                p.catch(function(e) {
 | 
						|
                    console.error("Promise Rejection on event '" + ev + "':");
 | 
						|
                    console.error(e);
 | 
						|
                });
 | 
						|
            }
 | 
						|
        } catch (e) {
 | 
						|
            console.error("Thrown Exception on event '" + ev + "':");
 | 
						|
            console.error(e);
 | 
						|
            console.error(params);
 | 
						|
        }
 | 
						|
 | 
						|
        if (-1 !== ['cert_issue', 'cert_renewal'].indexOf(ev)) {
 | 
						|
            // We will notify all greenlock users of mandatory and security updates
 | 
						|
            // We'll keep track of versions and os so we can make sure things work well
 | 
						|
            // { name, version, email, domains, action, communityMember, telemetry }
 | 
						|
            // TODO look at the other one
 | 
						|
            UserEvents.notify({
 | 
						|
                /*
 | 
						|
        // maintainer should be only on pre-publish, or maybe install, I think
 | 
						|
        maintainerEmail: greenlock._defaults._maintainerEmail,
 | 
						|
        name: greenlock._defaults._packageAgent,
 | 
						|
        version: greenlock._defaults._maintainerPackageVersion,
 | 
						|
        //action: params.pems._type,
 | 
						|
        domains: params.altnames,
 | 
						|
        subscriberEmail: greenlock._defaults._subscriberEmail,
 | 
						|
        // TODO enable for Greenlock Pro
 | 
						|
        //customerEmail: args.customerEmail
 | 
						|
        telemetry: greenlock._defaults.telemetry
 | 
						|
        */
 | 
						|
            });
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // certs.get
 | 
						|
    greenlock.get = async function(args) {
 | 
						|
        greenlock._single(args);
 | 
						|
        args._includePems = true;
 | 
						|
        var results = await greenlock.renew(args);
 | 
						|
        if (!results || !results.length) {
 | 
						|
            // TODO throw an error here?
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
 | 
						|
        // just get the first one
 | 
						|
        var result = results[0];
 | 
						|
 | 
						|
        // (there should be only one, ideally)
 | 
						|
        if (results.length > 1) {
 | 
						|
            var err = new Error(
 | 
						|
                "a search for '" +
 | 
						|
                    args.servername +
 | 
						|
                    "' returned multiple certificates"
 | 
						|
            );
 | 
						|
            err.context = 'duplicate_certs';
 | 
						|
            err.servername = args.servername;
 | 
						|
            err.subjects = results.map(function(r) {
 | 
						|
                return (r.site || {}).subject || 'N/A';
 | 
						|
            });
 | 
						|
 | 
						|
            greenlock._notify('warning', err);
 | 
						|
        }
 | 
						|
 | 
						|
        if (result.error) {
 | 
						|
            return Promise.reject(result.error);
 | 
						|
        }
 | 
						|
 | 
						|
        // site for plugin options, such as http-01 challenge
 | 
						|
        // pems for the obvious reasons
 | 
						|
        return result;
 | 
						|
    };
 | 
						|
 | 
						|
    // TODO remove async here, it doesn't matter
 | 
						|
    greenlock._single = async function(args) {
 | 
						|
        if ('string' !== typeof args.servername) {
 | 
						|
            throw new Error('no `servername` given');
 | 
						|
        }
 | 
						|
        // www.example.com => *.example.com
 | 
						|
        args.wildname =
 | 
						|
            '*.' +
 | 
						|
            args.servername
 | 
						|
                .split('.')
 | 
						|
                .slice(1)
 | 
						|
                .join('.');
 | 
						|
        if (args.wildname.split('.').length < 3) {
 | 
						|
            // No '*.com'
 | 
						|
            args.wildname = '';
 | 
						|
        }
 | 
						|
        if (
 | 
						|
            args.servernames ||
 | 
						|
            //TODO I think we need to block altnames as well, but I don't want to break anything
 | 
						|
            //args.altnames ||
 | 
						|
            args.subject ||
 | 
						|
            args.renewBefore ||
 | 
						|
            args.issueBefore ||
 | 
						|
            args.expiresBefore
 | 
						|
        ) {
 | 
						|
            throw new Error(
 | 
						|
                'bad arguments, did you mean to call greenlock.renew()?'
 | 
						|
            );
 | 
						|
        }
 | 
						|
        // duplicate, force, and others still allowed
 | 
						|
        return args;
 | 
						|
    };
 | 
						|
 | 
						|
    greenlock._config = async function(args) {
 | 
						|
        greenlock._single(args);
 | 
						|
        var sites = await greenlock._configAll(args);
 | 
						|
        return sites[0];
 | 
						|
    };
 | 
						|
    greenlock._configAll = async function(args) {
 | 
						|
        var sites = await greenlock._find(args);
 | 
						|
        if (!sites || !sites.length) {
 | 
						|
            return [];
 | 
						|
        }
 | 
						|
        sites = JSON.parse(JSON.stringify(sites));
 | 
						|
        var mconf = await greenlock.manager._defaults();
 | 
						|
        return sites.map(function(site) {
 | 
						|
            if (site.store && site.challenges) {
 | 
						|
                return site;
 | 
						|
            }
 | 
						|
 | 
						|
            var dconf = site;
 | 
						|
            // TODO make cli and api mode the same
 | 
						|
            if (gconf._bin_mode) {
 | 
						|
                dconf = site.defaults = {};
 | 
						|
            }
 | 
						|
            if (!site.store) {
 | 
						|
                dconf.store = mconf.store;
 | 
						|
            }
 | 
						|
            if (!site.challenges) {
 | 
						|
                dconf.challenges = mconf.challenges;
 | 
						|
            }
 | 
						|
            return site;
 | 
						|
        });
 | 
						|
    };
 | 
						|
 | 
						|
    // needs to get info about the renewal, such as which store and challenge(s) to use
 | 
						|
    greenlock.renew = async function(args) {
 | 
						|
        await greenlock._init();
 | 
						|
        var mconf = await greenlock.manager._defaults();
 | 
						|
        return greenlock._renew(mconf, args);
 | 
						|
    };
 | 
						|
    greenlock._renew = async function(mconf, args) {
 | 
						|
        if (!args) {
 | 
						|
            args = {};
 | 
						|
        }
 | 
						|
 | 
						|
        var renewedOrFailed = [];
 | 
						|
        //console.log('greenlock._renew find', args);
 | 
						|
        var sites = await greenlock._find(args);
 | 
						|
        // Note: the manager must guaranteed that these are mutable copies
 | 
						|
        //console.log('greenlock._renew found', sites);;
 | 
						|
 | 
						|
        if (!Array.isArray(sites)) {
 | 
						|
            throw new Error(
 | 
						|
                'Developer Error: not an array of sites returned from find: ' +
 | 
						|
                    JSON.stringify(sites)
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        await (async function next() {
 | 
						|
            var site = sites.shift();
 | 
						|
            if (!site) {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
 | 
						|
            var order = { site: site };
 | 
						|
            renewedOrFailed.push(order);
 | 
						|
            // TODO merge args + result?
 | 
						|
            return greenlock
 | 
						|
                ._order(mconf, site)
 | 
						|
                .then(function(pems) {
 | 
						|
                    if (args._includePems) {
 | 
						|
                        order.pems = pems;
 | 
						|
                    }
 | 
						|
                })
 | 
						|
                .catch(function(err) {
 | 
						|
                    order.error = err;
 | 
						|
 | 
						|
                    // For greenlock express serialization
 | 
						|
                    err.toJSON = errorToJSON;
 | 
						|
                    err.context = err.context || 'cert_order';
 | 
						|
                    err.subject = site.subject;
 | 
						|
                    if (args.servername) {
 | 
						|
                        err.servername = args.servername;
 | 
						|
                    }
 | 
						|
                    // for debugging, but not to be relied on
 | 
						|
                    err._site = site;
 | 
						|
                    // TODO err.context = err.context || 'renew_certificate'
 | 
						|
                    greenlock._notify('error', err);
 | 
						|
                })
 | 
						|
                .then(function() {
 | 
						|
                    return next();
 | 
						|
                });
 | 
						|
        })();
 | 
						|
 | 
						|
        return renewedOrFailed;
 | 
						|
    };
 | 
						|
 | 
						|
    greenlock._acme = async function(mconf, args, dirUrl) {
 | 
						|
        var packageAgent = gconf.packageAgent || '';
 | 
						|
        // because Greenlock_Express/v3.x Greenlock/v3 is redundant
 | 
						|
        if (!/greenlock/i.test(packageAgent)) {
 | 
						|
            packageAgent = (packageAgent + ' Greenlock/' + pkg.version).trim();
 | 
						|
        }
 | 
						|
        var acme = ACME.create({
 | 
						|
            maintainerEmail: gconf.maintainerEmail,
 | 
						|
            packageAgent: packageAgent,
 | 
						|
            notify: greenlock._notify,
 | 
						|
            debug: greenlock._defaults.debug || args.debug
 | 
						|
        });
 | 
						|
 | 
						|
        var dir = caches[dirUrl];
 | 
						|
        // don't cache more than an hour
 | 
						|
        if (dir && Date.now() - dir.ts < 1 * 60 * 60 * 1000) {
 | 
						|
            return dir.promise;
 | 
						|
        }
 | 
						|
 | 
						|
        await acme.init(dirUrl).catch(function(err) {
 | 
						|
            // TODO this is a special kind of failure mode. What should we do?
 | 
						|
            console.error(
 | 
						|
                "[debug] Let's Encrypt may be down for maintenance or `directoryUrl` may be wrong"
 | 
						|
            );
 | 
						|
            throw err;
 | 
						|
        });
 | 
						|
 | 
						|
        caches[dirUrl] = {
 | 
						|
            promise: Promise.resolve(acme),
 | 
						|
            ts: Date.now()
 | 
						|
        };
 | 
						|
        return acme;
 | 
						|
    };
 | 
						|
 | 
						|
    greenlock.order = async function(siteConf) {
 | 
						|
        await greenlock._init();
 | 
						|
        var mconf = await greenlock.manager._defaults();
 | 
						|
        return greenlock._order(mconf, siteConf);
 | 
						|
    };
 | 
						|
    greenlock._order = async function(mconf, siteConf) {
 | 
						|
        // packageAgent, maintainerEmail
 | 
						|
 | 
						|
        var dirUrl = DIR._getDirectoryUrl(
 | 
						|
            siteConf.directoryUrl || mconf.directoryUrl,
 | 
						|
            siteConf.subject
 | 
						|
        );
 | 
						|
 | 
						|
        var acme = await greenlock._acme(mconf, siteConf, dirUrl);
 | 
						|
        var storeConf = siteConf.store || mconf.store;
 | 
						|
        storeConf = JSON.parse(JSON.stringify(storeConf));
 | 
						|
        storeConf.packageRoot = gconf.packageRoot;
 | 
						|
 | 
						|
        if (!storeConf.basePath) {
 | 
						|
            storeConf.basePath = gconf.configDir;
 | 
						|
        }
 | 
						|
 | 
						|
        if ('.' === (storeConf.basePath || '')[0]) {
 | 
						|
            if (!gconf.packageRoot) {
 | 
						|
                gconf.packageRoot = process.cwd();
 | 
						|
                console.warn(
 | 
						|
                    '`packageRoot` not defined, trying ' + gconf.packageRoot
 | 
						|
                );
 | 
						|
            }
 | 
						|
            storeConf.basePath = require('path').resolve(
 | 
						|
                gconf.packageRoot || '',
 | 
						|
                storeConf.basePath
 | 
						|
            );
 | 
						|
        }
 | 
						|
 | 
						|
        storeConf.directoryUrl = dirUrl;
 | 
						|
        var store = await P._loadStore(storeConf);
 | 
						|
        var account = await A._getOrCreate(
 | 
						|
            greenlock,
 | 
						|
            mconf,
 | 
						|
            store.accounts,
 | 
						|
            acme,
 | 
						|
            siteConf
 | 
						|
        );
 | 
						|
        var challengeConfs = siteConf.challenges || mconf.challenges;
 | 
						|
        var challenges = {};
 | 
						|
        var arr = await Promise.all(
 | 
						|
            Object.keys(challengeConfs).map(function(typ01) {
 | 
						|
                return P._loadChallenge(challengeConfs, typ01);
 | 
						|
            })
 | 
						|
        );
 | 
						|
        arr.forEach(function(el) {
 | 
						|
            challenges[el._type] = el;
 | 
						|
        });
 | 
						|
 | 
						|
        var pems = await C._getOrOrder(
 | 
						|
            greenlock,
 | 
						|
            mconf,
 | 
						|
            store.certificates,
 | 
						|
            acme,
 | 
						|
            challenges,
 | 
						|
            account,
 | 
						|
            siteConf
 | 
						|
        );
 | 
						|
        if (!pems) {
 | 
						|
            throw new Error('no order result');
 | 
						|
        }
 | 
						|
        if (!pems.privkey) {
 | 
						|
            throw new Error('missing private key, which is kinda important');
 | 
						|
        }
 | 
						|
 | 
						|
        return pems;
 | 
						|
    };
 | 
						|
 | 
						|
    greenlock._create();
 | 
						|
 | 
						|
    return greenlock;
 | 
						|
};
 | 
						|
 | 
						|
G._loadChallenge = P._loadChallenge;
 | 
						|
 | 
						|
function errorToJSON(e) {
 | 
						|
    var error = {};
 | 
						|
    Object.getOwnPropertyNames(e).forEach(function(k) {
 | 
						|
        error[k] = e[k];
 | 
						|
    });
 | 
						|
    return error;
 | 
						|
}
 | 
						|
 | 
						|
function mergeDefaults(MCONF, gconf) {
 | 
						|
    if (
 | 
						|
        gconf.agreeToTerms === true ||
 | 
						|
        MCONF.agreeToTerms === true ||
 | 
						|
        // TODO deprecate
 | 
						|
        gconf.agreeTos === true ||
 | 
						|
        MCONF.agreeTos === true
 | 
						|
    ) {
 | 
						|
        MCONF.agreeToTerms = true;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!MCONF.subscriberEmail && gconf.subscriberEmail) {
 | 
						|
        MCONF.subscriberEmail = gconf.subscriberEmail;
 | 
						|
    }
 | 
						|
 | 
						|
    // Load the default store module
 | 
						|
    if (!MCONF.store) {
 | 
						|
        if (gconf.store) {
 | 
						|
            MCONF.store = gconf.store;
 | 
						|
        } else {
 | 
						|
            MCONF.store = {
 | 
						|
                module: 'greenlock-store-fs'
 | 
						|
            };
 | 
						|
            console.info('[default] store.module: ' + MCONF.store.module);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
    if ('greenlock-store-fs' === MCONF.store.module && !MCONF.store.basePath) {
 | 
						|
        //homedir = require('os').homedir();
 | 
						|
        if (gconf.configFile) {
 | 
						|
            MCONF.store.basePath = gconf.configFile.replace(/\.json$/i, '.d');
 | 
						|
        } else {
 | 
						|
            MCONF.store.basePath = './greenlock.d';
 | 
						|
        }
 | 
						|
    }
 | 
						|
    */
 | 
						|
 | 
						|
    // just to test that it loads
 | 
						|
    P._loadSync(MCONF.store.module);
 | 
						|
 | 
						|
    // Load the default challenge modules
 | 
						|
    var challenges = MCONF.challenges || gconf.challenges;
 | 
						|
    if (!challenges) {
 | 
						|
        challenges = {};
 | 
						|
    }
 | 
						|
    if (!challenges['http-01'] && !challenges['dns-01']) {
 | 
						|
        challenges['http-01'] = { module: 'acme-http-01-standalone' };
 | 
						|
        console.info(
 | 
						|
            '[default] challenges.http-01.module: ' +
 | 
						|
                challenges['http-01'].module
 | 
						|
        );
 | 
						|
    }
 | 
						|
    if (challenges['http-01']) {
 | 
						|
        if ('string' !== typeof challenges['http-01'].module) {
 | 
						|
            throw new Error(
 | 
						|
                'bad challenge http-01 module config:' +
 | 
						|
                    JSON.stringify(challenges['http-01'])
 | 
						|
            );
 | 
						|
        }
 | 
						|
        P._loadSync(challenges['http-01'].module);
 | 
						|
    }
 | 
						|
    if (challenges['dns-01']) {
 | 
						|
        if ('string' !== typeof challenges['dns-01'].module) {
 | 
						|
            throw new Error(
 | 
						|
                'bad challenge dns-01 module config' +
 | 
						|
                    JSON.stringify(challenges['dns-01'])
 | 
						|
            );
 | 
						|
        }
 | 
						|
        P._loadSync(challenges['dns-01'].module);
 | 
						|
    }
 | 
						|
    MCONF.challenges = challenges;
 | 
						|
 | 
						|
    if (!MCONF.renewOffset) {
 | 
						|
        MCONF.renewOffset = gconf.renewOffset || '-45d';
 | 
						|
        console.info('[default] renewOffset: ' + MCONF.renewOffset);
 | 
						|
    }
 | 
						|
    if (!MCONF.renewStagger) {
 | 
						|
        MCONF.renewStagger = gconf.renewStagger || '3d';
 | 
						|
        console.info('[default] renewStagger: ' + MCONF.renewStagger);
 | 
						|
    }
 | 
						|
 | 
						|
    var vers = process.versions.node.split('.');
 | 
						|
    var defaultKeyType = 'EC-P256';
 | 
						|
    if (vers[0] < 10 || (vers[0] === '10' && vers[1] < '12')) {
 | 
						|
        defaultKeyType = 'RSA-2048';
 | 
						|
    }
 | 
						|
    if (!MCONF.accountKeyType) {
 | 
						|
        MCONF.accountKeyType = gconf.accountKeyType || defaultKeyType;
 | 
						|
        console.info('[default] accountKeyType: ' + MCONF.accountKeyType);
 | 
						|
    }
 | 
						|
    if (!MCONF.serverKeyType) {
 | 
						|
        MCONF.serverKeyType = gconf.serverKeyType || 'RSA-2048';
 | 
						|
        console.info('[default] serverKeyType: ' + MCONF.serverKeyType);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!MCONF.subscriberEmail && false !== MCONF.subscriberEmail) {
 | 
						|
        MCONF.subscriberEmail =
 | 
						|
            gconf.subscriberEmail || gconf.maintainerEmail || undefined;
 | 
						|
        MCONF.agreeToTerms = gconf.agreeToTerms || undefined;
 | 
						|
        console.info('');
 | 
						|
        console.info('[default] subscriberEmail: ' + MCONF.subscriberEmail);
 | 
						|
        console.info(
 | 
						|
            '[default] agreeToTerms: ' +
 | 
						|
                (MCONF.agreeToTerms ||
 | 
						|
                    gconf.agreeToTerms ||
 | 
						|
                    '(show notice on use)')
 | 
						|
        );
 | 
						|
        console.info('');
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function _notify(ev, args) {
 | 
						|
    if (!args) {
 | 
						|
        args = ev;
 | 
						|
        ev = args.event;
 | 
						|
        delete args.event;
 | 
						|
    }
 | 
						|
 | 
						|
    // TODO define message types
 | 
						|
    if (!_notify._notice) {
 | 
						|
        console.info(
 | 
						|
            'set greenlockOptions.notify to override the default logger'
 | 
						|
        );
 | 
						|
        _notify._notice = true;
 | 
						|
    }
 | 
						|
    var prefix = 'Warning';
 | 
						|
    switch (ev) {
 | 
						|
        case 'error':
 | 
						|
            prefix = 'Error';
 | 
						|
        /* falls through */
 | 
						|
        case 'warning':
 | 
						|
            console.error(
 | 
						|
                prefix + '%s:',
 | 
						|
                (' ' + (args.context || '')).trimRight()
 | 
						|
            );
 | 
						|
            console.error(args.message);
 | 
						|
            if (args.description) {
 | 
						|
                console.error(args.description);
 | 
						|
            }
 | 
						|
            if (args.code) {
 | 
						|
                console.error('code:', args.code);
 | 
						|
            }
 | 
						|
            if (args.stack) {
 | 
						|
                console.error(args.stack);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            if (/status/.test(ev)) {
 | 
						|
                console.info(
 | 
						|
                    ev,
 | 
						|
                    args.altname || args.subject || '',
 | 
						|
                    args.status || ''
 | 
						|
                );
 | 
						|
                if (!args.status) {
 | 
						|
                    console.info(args);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            console.info(
 | 
						|
                ev,
 | 
						|
                '(more info available: ' + Object.keys(args).join(' ') + ')'
 | 
						|
            );
 | 
						|
    }
 | 
						|
}
 |