From bd907f2004b3031b98b21efdd4509a0b7a6fc634 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sat, 6 Apr 2019 01:43:39 -0600 Subject: [PATCH] v3.0.2: include other reference implementations, typo fixes --- README.md | 15 +++-- index.js | 165 +++++++++------------------------------------- package-lock.json | 17 ++++- package.json | 6 +- 4 files changed, 58 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index d4a3275..a934c49 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [le-challenge-manual](https://git.coolaj86.com/coolaj86/le-challenge-manual.js.git) +# [le-challenge-manual](https://git.coolaj86.com/coolaj86/le-challenge-manual.js) | A [Root](https://rootprojects.org) Project | @@ -6,15 +6,16 @@ An extremely simple reference implementation of an ACME (Let's Encrypt) challenge strategy for [Greenlock](https://git.coolaj86.com/coolaj86/greenlock-express.js) v2.7+ (and v3). -* Prints the ACME challenge details to the terminal (and waits for you to hit enter before continuing) -* Asks you to enter the change response. -* Let's you know it's safeto remove the challenge. +* Prints the ACME challenge details to the terminal + * (waits for you to hit enter before continuing) +* Asks you to enter the challenge response. +* Let's you know it's safe to remove the challenge. Other ACME Challenge Reference Implementations: -* [le-challenge-manual](https://git.coolaj86.com/coolaj86/le-challenge-manual.js.git) -* [le-challenge-http](https://git.coolaj86.com/coolaj86/le-challenge-http.js.git) -* [le-challenge-dns](https://git.coolaj86.com/coolaj86/le-challenge-dns.js.git) +* [**le-challenge-manual**](https://git.coolaj86.com/coolaj86/le-challenge-manual.js) +* [le-challenge-http](https://git.coolaj86.com/coolaj86/le-challenge-http.js) +* [le-challenge-dns](https://git.coolaj86.com/coolaj86/le-challenge-dns.js) Install ------- diff --git a/index.js b/index.js index 9fc133c..b136e33 100644 --- a/index.js +++ b/index.js @@ -3,17 +3,12 @@ var Challenge = module.exports; -// IMPORTANT -// -// These are all PROMISIFIED by Greenlock in such a way that -// it doesn't matter whether you return synchronously, asynchronously, -// or even node-style callback thunk. -// -// Typically you should be using a promise or async function, -// but choose whichever makes sense for you. Challenge.create = function (config) { // If your implementation needs config options, set them. Otherwise, don't bother (duh). + var http01 = require('le-challenge-http').create(config); + var dns01 = require('le-challenge-dns').create(config); + var challenger = {}; // Note: normally you'd implement these right here, but for the sake of @@ -21,11 +16,13 @@ Challenge.create = function (config) { // call out to set the challenge, wherever challenger.set = function (opts, cb) { + // Note: this can be defined as a thunk (like this) or a Promise + var ch = opts.challenge; if ('http-01' === ch.type) { - return Challenge._setHttp(opts, cb); + return http01.set(opts, cb); } else if ('dns-01' === ch.type) { - return Challenge._setDns(opts, cb); + return dns01.set(opts, cb); } else { return Challenge._setAny(opts, cb); } @@ -33,25 +30,28 @@ Challenge.create = function (config) { // call out to remove the challenge, wherever challenger.remove = function (opts) { + // Note: this can be defined synchronously (like this) or as a Promise, or a thunk + var ch = opts.challenge; if ('http-01' === ch.type) { - return Challenge._removeHttp(opts); + return http01.remove(opts); } else if ('dns-01' === ch.type) { - return Challenge._removeDns(opts); + return dns01.remove(opts); } else { return Challenge._removeAny(opts); } }; - // only really useful for http, - // but probably not so much in this context... - // (though you can test it and it'll work) + // only really useful for http + // (and tls-alpn-01, which isn't implemented yet) challenger.get = function (opts) { + // Note: this can be defined as a Promise (like this) or synchronously, or a thunk + var ch = opts.challenge; if ('http-01' === ch.type) { - return Challenge._get(opts); + return http01.get(opts); } else if ('dns-01' === ch.type) { - return Challenge._get(opts); + return dns01.get(opts); } else { return Challenge._get(opts); } @@ -64,71 +64,16 @@ Challenge.create = function (config) { return challenger; }; -// Show the user the token and key and wait for them to be ready to continue -Challenge._setHttp = function (args, cb) { - // Using a node-style callback "thunk" in this example, because that makes - - var ch = args.challenge; - console.info("[ACME http-01 '" + ch.altname + "' CHALLENGE]"); - console.info("Your mission (since you chose to accept it):"); - console.info("First, you must create a file with the following name and contents."); - console.info("Then, by any means necessary, you cause that file to appear at the specified URL."); - console.info(""); - console.info("\tFilename: " + ch.token); - console.info("\tContents: " + ch.keyAuthorization); - // TODO let acme-v2 handle generating this url - console.info('\tURL: http://' + ch.altname + '/.well-known/acme-challenge/' + ch.token); - console.info(""); - if (args.debug) { - console.info("And, if you need additional information for debugging:"); - console.info(""); - console.info(JSON.stringify(httpChallengeToJson(ch), null, 2).replace(/^/gm, '\t')); - console.info(""); - } - console.info("This message won't self-destruct, but you may press hit the any as soon as you're ready to continue..."); - console.info("[Press the ANY key to continue...]"); - - process.stdin.resume(); - process.stdin.once('data', function () { - process.stdin.pause(); - cb(null, null); - }); -}; - -Challenge._setDns = function (args, cb) { - // Using a node-style callback "thunk" in this example, because that makes - - var ch = args.challenge; - console.info("[ACME dns-01 '" + ch.altname + "' CHALLENGE]"); - console.info("Your mission (since you chose to accept it):"); - console.info("First, you must create a DNS record with the following parameters:"); - console.info(""); - console.info(ch.dnsHost + "\tTXT\t" + ch.dnsKeyAuthorization + "\tTTL 60"); - console.info(""); - console.info("Next, wait, no... there is no next."); - if (args.debug) { - console.log("Oh, did you want this?"); - console.info(""); - console.info(JSON.stringify(dnsChallengeToJson(ch), null, 2).replace(/^/gm, '\t')); - console.info(""); - } - console.info("[Press the ANY key to continue...]"); - - process.stdin.resume(); - process.stdin.once('data', function () { - process.stdin.pause(); - cb(null, null); - }); -}; - Challenge._setAny = function (args, cb) { var ch = args.challenge; console.info("[ACME " + ch.type + " '" + ch.altname + "' CHALLENGE]"); - console.info("There's no quippy pre-programmed response for this type of challenge."); - console.info("I have no idea what you intend to do, but I'll tell you everything I know:"); + console.info("Your mission (since you chose to accept it):"); + console.info("You must, by whatever means necessary, use the following information" + + " to make a device or service ready to respond to a '" + ch.type + "' request."); console.info(""); console.info(JSON.stringify(ch, null, 2).replace(/^/gm, '\t')); console.info(""); + console.info("Press the any key once the response is ready to continue with the '" + ch.type + "' challenge process"); console.info("[Press the ANY key to continue...]"); process.stdin.resume(); @@ -138,54 +83,32 @@ Challenge._setAny = function (args, cb) { }); }; -// might as well tell the user that whatever they were setting up has been checked -Challenge._removeHttp = function (args) { - var ch = args.challenge; - console.info(""); - console.info("Challenge for '" + ch.altname + "' complete. You can delete this file now:"); - console.info('\thttp://' + ch.altname + '/.well-known/acme-challenge/' + ch.token); - console.info(""); - - // this can return null or a Promise null - // (or callback null, just like the set() above) - return null; -}; -Challenge._removeDns = function (args) { - var ch = args.challenge; - console.info(""); - console.info("Challenge for '" + ch.altname + "' complete. You can remove this record now:"); - console.info("\t" + ch.dnsHost + "\tTXT\t" + ch.dnsKeyAuthorization + "\tTTL 60"); - console.info(""); - - // this can return null or a Promise null - // (or callback null, just like the set() above) - return null; -}; Challenge._removeAny = function (args) { var ch = args.challenge; console.info(""); - console.info("Challenge for '" + ch.altname + "' complete. You can now undo what you did."); + console.info("[ACME " + ch.type + " '" + ch.altname + "' COMPLETE]: " + ch.status); + console.info("You may now undo whatever you did to create and ready the response."); console.info(""); - // this can return null or a Promise null - // (or callback null, just like set() above) return null; }; -// nothing to do here, that's why it's manual +// This can be used for http-01 and tls-alpn-01 (when it's available), but not dns-01. +// And not all http-01 or tls-alpn-01 strategies will need to implement this. Challenge._get = function (args) { var ch = args.challenge; if (!Challenge._getCache[ch.altname + ':' + ch.token]) { Challenge._getCache[ch.altname + ':' + ch.token] = true; console.info(""); - console.info('GET http://' + ch.altname + '/.well-known/acme-challenge/' + ch.token); - console.info("It's time to painstakingly type out the ACME challenge response with your bear hands. Yes. Your bear hands."); + console.info("[ACME " + ch.type + " '" + ch.altname + "' REQUEST]: " + ch.status); + console.info("The '" + ch.type + "' challenge request has arrived!"); + console.info("It's now time to painstakingly type out the expected response object with your bear hands."); + console.log("Yes. Your bear hands."); + console.log('ex: { "keyAuthorization": "xxxxxxxx.yyyyyyyy" }'); process.stdout.write("> "); } - // Using a promise here just to show that Promises are support - // (in fact, they're the default) return new Promise(function (resolve, reject) { process.stdin.resume(); process.stdin.once('error', reject); @@ -204,31 +127,3 @@ Challenge._get = function (args) { }; // Because the ACME server will hammer us with requests, and that's confusing during a manual test: Challenge._getCache = {}; - -function httpChallengeToJson(ch) { - return { - type: ch.type - , altname: ch.altname - , identifier: ch.identifier - , wildcard: false - , expires: ch.expires - , token: ch.token - , thumbprint: ch.thumbprint - , keyAuthorization: ch.keyAuthorization - }; -} - -function dnsChallengeToJson(ch) { - return { - type: ch.type - , altname: '*.example.com' - , identifier: ch.identifier - , wildcard: ch.wildcard - , expires: ch.expires - , token: ch.token - , thumbprint: ch.thumbprint - , keyAuthorization: ch.keyAuthorization - , dnsHost: ch.dnsHost - , dnsAuthorization: ch.dnsAuthorization - }; -} diff --git a/package-lock.json b/package-lock.json index 93bb092..d0fd293 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,18 @@ { "name": "le-challenge-manual", - "version": "2.1.1", - "lockfileVersion": 1 + "version": "3.0.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "le-challenge-dns": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/le-challenge-dns/-/le-challenge-dns-3.0.2.tgz", + "integrity": "sha512-cmg26G2VdcRL9Ja8JegsES3B2jBTZ/LkkaqzrUAMRl2UQQiS/+kursn3J761ht58/sXOpYVp5V6rQwIXSknDbg==" + }, + "le-challenge-http": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/le-challenge-http/-/le-challenge-http-3.0.0.tgz", + "integrity": "sha512-kQb2j/lftI6mRjHy5AqueOkqjlcyfLlAF3Nk468xjloG0JGadjK4iT23mlXTaBIg84OIpPlhRuS+XNs5uhn8Xw==" + } + } } diff --git a/package.json b/package.json index cb5f2a7..58be4ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "le-challenge-manual", - "version": "3.0.1", + "version": "3.0.2", "description": "A cli-based strategy for node-letsencrypt. Prints the ACME challenge Token and Key and then waits for you to hit enter before continuing.", "main": "index.js", "homepage": "https://git.coolaj86.com/coolaj86/le-challenge-manual.js", @@ -25,5 +25,9 @@ "license": "MPL-2.0", "bugs": { "url": "https://git.coolaj86.com/coolaj86/le-challenge-manual.js/issues" + }, + "dependencies": { + "le-challenge-dns": "^3.0.2", + "le-challenge-http": "^3.0.0" } }