'use strict'; /*global Promise*/ var Challenge = module.exports; // If your implementation needs config options, set them. Otherwise, don't bother (duh). Challenge.create = function (config) { var challenger = {}; // Note: normally you'd these right in the method body, but for the sake of // "Table of Contents"-style documentation, I've pulled them out. // Note: All of these methods can be synchronous, async, Promise, and callback-style // (the calling functions check function.length and then Promisify accordingly) // Called when it's tiem to set the challenge challenger.set = function (opts, cb) { return Challenge._setDns(opts, cb); }; // Called when it's time to remove the challenge challenger.remove = function (opts) { return Challenge._removeDns(opts); }; // Optional (only really useful for http) // Called when the challenge needs to be retrieved challenger.get = function (opts) { return Challenge._getDns(opts); }; // Whatever you assign to 'options' will be merged into the incoming 'opts' beforehand // (for convenience, so you don't have to do the if (!x) { x = y; } dance) // (also, some defaults are layered, so it's good to set it any that you have) challenger.options = { debug: config.debug }; return challenger; }; // Show the user the token and key and wait for them to be ready to continue Challenge._setDns = function (args, cb) { // if you need per-run / per-domain options set them in approveDomains() and they'll be on 'args' here. if (!args.challenge) { console.error("You must be using Greenlock v2.7+ to use le-challenge-dns v3+"); process.exit(); } var ch = args.challenge; console.info(""); console.info("[ACME dns-01 '" + ch.altname + "' CHALLENGE]"); console.info("You're about to receive the following DNS query:"); console.info(""); console.info("\tTXT\t" + ch.dnsHost + "\t" + ch.dnsAuthorization + "\tTTL 60"); console.info(""); if (ch.debug) { console.info("Debug Info:"); console.info(""); console.info(JSON.stringify(dnsChallengeToJson(ch), null, ' ').replace(/^/gm, '\t')); console.info(""); } console.info("Go set that DNS record, wait a few seconds for it to propagate, and then continue when ready"); console.info("[Press the ANY key to continue...]"); process.stdin.resume(); process.stdin.once('data', function () { process.stdin.pause(); cb(null); }); }; // might as well tell the user that whatever they were setting up has been checked Challenge._removeDns = function (args) { var ch = args.challenge; console.info(""); console.info("[ACME http-01 '" + ch.altname + "' COMPLETE]: " + ch.status); console.info("Challenge complete. You may now remove the DNS-01 challenge record:"); console.info(""); console.info("\tTXT\t" + args.challenge.altname + "\t" + args.challenge.dnsAuthorization); console.info(""); return null; }; // This is implemented here for completeness (and perhaps some possible use in testing), // but it's not something you would implement because the Greenlock server isn't the NameServer. Challenge._getDns = function (args) { var ch = args.challenge; if (!Challenge._getCache[ch.altname + ':' + ch.token]) { Challenge._getCache[ch.altname + ':' + ch.token] = true; console.info(""); console.info("[ACME " + ch.type + " '" + ch.altname + "' REQUEST]: " + ch.status); console.info("The '" + ch.type + "' challenge request has arrived!"); console.info('dig TXT ' + ch.dnsHost); console.info("(paste in the \"DNS Authorization\" you received a moment ago to respond)"); process.stdout.write("> "); } return new Promise(function (resolve, reject) { process.stdin.resume(); process.stdin.once('error', reject); process.stdin.once('data', function (chunk) { process.stdin.pause(); var result = chunk.toString('utf8'); try { result = JSON.parse(result); } catch(e) { args.challenge.dnsAuthorization = result; result = args.challenge; } if (result.dnsAuthorization) { resolve(result); return; } // The return value will checked. It must not be 'undefined'. resolve(null); }); }); }; function dnsChallengeToJson(ch) { return { type: ch.type , altname: ch.altname , identifier: ch.identifier , wildcard: ch.wildcard , expires: ch.expires , token: ch.token , thumbprint: ch.thumbprint , keyAuthorization: ch.keyAuthorization , dnsHost: ch.dnsHost , dnsAuthorization: ch.dnsAuthorization }; }