v3.0.4: ACME dns-01 challenge reference implementation for Greenlock v2.7+ (and v3)

This commit is contained in:
AJ ONeal 2019-04-07 17:35:26 -06:00
parent e98e53e0a7
commit 8a12a86761
4 changed files with 36 additions and 52 deletions

View File

@ -1,4 +1,4 @@
# [le-challenge-dns](https://git.coolaj86.com/coolaj86/le-challenge-dns.js) # [greenlock-challenge-dns](https://git.coolaj86.com/coolaj86/greenlock-challenge-dns.js)
| A [Root](https://rootprojects.org) Project | | A [Root](https://rootprojects.org) Project |
@ -16,17 +16,17 @@ _acme-challenge.example.com TXT xxxxxxxxxxxxxxxx TTL 60
Other ACME Challenge Reference Implementations: Other ACME Challenge Reference Implementations:
* [le-challenge-manual](https://git.coolaj86.com/coolaj86/le-challenge-manual.js.git) * [greenlock-challenge-manual](https://git.coolaj86.com/coolaj86/greenlock-challenge-manual.js.git)
* [le-challenge-http](https://git.coolaj86.com/coolaj86/le-challenge-http.js.git) * [greenlock-challenge-http](https://git.coolaj86.com/coolaj86/greenlock-challenge-http.js.git)
* [**le-challenge-dns**](https://git.coolaj86.com/coolaj86/le-challenge-dns.js.git) * [**greenlock-challenge-dns**](https://git.coolaj86.com/coolaj86/greenlock-challenge-dns.js.git)
## Install ## Install
```bash ```bash
npm install --save le-challenge-dns@3.x npm install --save greenlock-challenge-dns@3.x
``` ```
If you have `greenlock@v2.6` or lower, you'll need the old `le-challenge-dns@3.x` instead. If you have `greenlock@v2.6` or lower, you'll need the old `greenlock-challenge-dns@3.x` instead.
## Usage ## Usage
@ -35,9 +35,9 @@ var Greenlock = require('greenlock');
Greenlock.create({ Greenlock.create({
... ...
, challenges: { 'http-01': require('le-challenge-http') , challenges: { 'http-01': require('greenlock-challenge-http')
, 'dns-01': require('le-challenge-dns').create({ debug: true }) , 'dns-01': require('greenlock-challenge-dns').create({ debug: true })
, 'tls-alpn-01': require('le-challenge-manual') , 'tls-alpn-01': require('greenlock-challenge-manual')
} }
... ...
}); });

View File

@ -24,7 +24,7 @@ Challenge.create = function (config) {
return Challenge._removeDns(opts); return Challenge._removeDns(opts);
}; };
// Optional (only really useful for http) // Optional (only really useful for http and testing)
// Called when the challenge needs to be retrieved // Called when the challenge needs to be retrieved
challenger.get = function (opts) { challenger.get = function (opts) {
return Challenge._getDns(opts); return Challenge._getDns(opts);
@ -43,7 +43,7 @@ Challenge.create = function (config) {
Challenge._setDns = function (args, cb) { 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 you need per-run / per-domain options set them in approveDomains() and they'll be on 'args' here.
if (!args.challenge) { if (!args.challenge) {
console.error("You must be using Greenlock v2.7+ to use le-challenge-dns v3+"); console.error("You must be using Greenlock v2.7+ to use greenlock-challenge-dns v3+");
process.exit(); process.exit();
} }
var ch = args.challenge; var ch = args.challenge;
@ -65,7 +65,7 @@ Challenge._setDns = function (args, cb) {
process.stdin.resume(); process.stdin.resume();
process.stdin.once('data', function () { process.stdin.once('data', function () {
process.stdin.pause(); process.stdin.pause();
cb(null); cb(null, null);
}); });
}; };
@ -73,10 +73,10 @@ Challenge._setDns = function (args, cb) {
Challenge._removeDns = function (args) { Challenge._removeDns = function (args) {
var ch = args.challenge; var ch = args.challenge;
console.info(""); console.info("");
console.info("[ACME http-01 '" + ch.altname + "' COMPLETE]: " + ch.status); console.info("[ACME dns-01 '" + ch.altname + "' COMPLETE]: " + ch.status);
console.info("Challenge complete. You may now remove the DNS-01 challenge record:"); console.info("Challenge complete. You may now remove the DNS-01 challenge record:");
console.info(""); console.info("");
console.info("\tTXT\t" + args.challenge.altname + "\t" + args.challenge.dnsAuthorization); console.info("\tTXT\t" + ch.altname + "\t" + ch.dnsAuthorization);
console.info(""); console.info("");
return null; return null;
@ -86,13 +86,16 @@ Challenge._removeDns = function (args) {
// but it's not something you would implement because the Greenlock server isn't the NameServer. // but it's not something you would implement because the Greenlock server isn't the NameServer.
Challenge._getDns = function (args) { Challenge._getDns = function (args) {
var ch = args.challenge; var ch = args.challenge;
// because the way to mock a DNS challenge is weird
var altname = (ch.altname || ch.dnsHost || ch.identifier.value);
var dnsHost = (ch.dnsHost || ch.identifier.value);
if (!Challenge._getCache[ch.altname + ':' + ch.token]) { if (ch._test || !Challenge._getCache[ch.token]) {
Challenge._getCache[ch.altname + ':' + ch.token] = true; Challenge._getCache[ch.token] = true;
console.info(""); console.info("");
console.info("[ACME " + ch.type + " '" + ch.altname + "' REQUEST]: " + ch.status); console.info("[ACME " + ch.type + " '" + altname + "' REQUEST]: " + ch.status);
console.info("The '" + ch.type + "' challenge request has arrived!"); console.info("The '" + ch.type + "' challenge request has arrived!");
console.info('dig TXT ' + ch.dnsHost); console.info('dig TXT ' + dnsHost);
console.info("(paste in the \"DNS Authorization\" you received a moment ago to respond)"); console.info("(paste in the \"DNS Authorization\" you received a moment ago to respond)");
process.stdout.write("> "); process.stdout.write("> ");
} }
@ -103,7 +106,7 @@ Challenge._getDns = function (args) {
process.stdin.once('data', function (chunk) { process.stdin.once('data', function (chunk) {
process.stdin.pause(); process.stdin.pause();
var result = chunk.toString('utf8'); var result = chunk.toString('utf8').trim();
try { try {
result = JSON.parse(result); result = JSON.parse(result);
} catch(e) { } catch(e) {
@ -120,6 +123,7 @@ Challenge._getDns = function (args) {
}); });
}); });
}; };
Challenge._getCache = {};
function dnsChallengeToJson(ch) { function dnsChallengeToJson(ch) {
return { return {

View File

@ -1,6 +1,6 @@
{ {
"name": "le-challenge-dns", "name": "greenlock-challenge-dns",
"version": "3.0.3", "version": "3.0.4",
"description": "A manual (interactive CLI) dns-based strategy for Greenlock / Let's Encrypt / ACME DNS-01 challenges", "description": "A manual (interactive CLI) dns-based strategy for Greenlock / Let's Encrypt / ACME DNS-01 challenges",
"main": "index.js", "main": "index.js",
"files": [], "files": [],
@ -9,7 +9,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://git.coolaj86.com/coolaj86/le-challenge-dns.js.git" "url": "git+https://git.coolaj86.com/coolaj86/greenlock-challenge-dns.js.git"
}, },
"keywords": [ "keywords": [
"Let's Encrypt", "Let's Encrypt",
@ -18,9 +18,7 @@
"dns-01", "dns-01",
"wildcard", "wildcard",
"wildcards", "wildcards",
"letsencrypt",
"manual", "manual",
"interactive",
"cli", "cli",
"dns", "dns",
"challenge" "challenge"
@ -28,8 +26,8 @@
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
"license": "(MIT OR Apache-2.0)", "license": "(MIT OR Apache-2.0)",
"bugs": { "bugs": {
"url": "https://git.coolaj86.com/coolaj86/le-challenge-dns.js/issues" "url": "https://git.coolaj86.com/coolaj86/greenlock-challenge-dns.js/issues"
}, },
"homepage": "https://git.coolaj86.com/coolaj86/le-challenge-dns.js", "homepage": "https://git.coolaj86.com/coolaj86/greenlock-challenge-dns.js",
"dependencies": {} "dependencies": {}
} }

34
test.js
View File

@ -1,36 +1,18 @@
'use strict'; 'use strict';
/*global Promise*/
var challenge = require('./').create({}); var tester = require('greenlock-challenge-test');
var opts = challenge.getOptions && challenge.getOptions() || challenge.options; var type = 'dns-01';
var challenger = require('greenlock-challenge-dns').create({});
function run() { // The dry-run tests can pass on, literally, 'example.com'
// this will cause the prompt to appear // but the integration tests require that you have control over the domain
return new Promise(function (resolve, reject) { var domain = '*.example.com';
challenge.set(opts, function () {
// this will cause the final completion message to appear
return Promise.resolve(challenge.remove(opts)).then(resolve).catch(reject);
});
});
}
opts.challenge = { tester.test(type, domain, challenger).then(function () {
type: 'http-01'
, identifier: { type: 'dns', value: 'example.com' }
, wildcard: false
, expires: '2012-01-01T12:00:00.000Z'
, token: 'abc123'
, thumbprint: '<<account key thumbprint>>'
, keyAuthorization: 'abc123.xxxx'
, dnsHost: '_acme-challenge.example.com'
, dnsAuthorization: 'yyyy'
, altname: 'example.com'
};
run(opts).then(function () {
console.info("PASS"); console.info("PASS");
}).catch(function (err) { }).catch(function (err) {
console.error("FAIL"); console.error("FAIL");
console.error(err); console.error(err);
process.exit(18); process.exit(20);
}); });