diff --git a/LICENSE b/LICENSE index a7782bc..b66df9b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,41 @@ +Copyright 2016-2019 AJ ONeal + +This is open source software; you can redistribute it and/or modify it under the +terms of either: + + a) the "MIT License" + b) the "Apache-2.0 License" + MIT License -Copyright (c) 2016 Daplie, Inc + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Apache-2.0 License Summary + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index f247140..0ae9ac8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -le-challenge-dns -================ +# le-challenge-dns | A [Root](https://rootprojects.org) Project | [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js) (library) @@ -21,19 +20,19 @@ press [enter] to continue the process. _acme-challenge.example.com TXT xxxxxxxxxxxxxxxx TTL 60 ``` -Install -------- +## Install ```bash -npm install --save le-challenge-dns@2.x +npm install --save le-challenge-dns@3.x ``` -Usage ------ +If you have `greenlock@v2.6` or lower, you'll need the old `le-challenge-dns@3.x` instead. + +## Usage The challenge can be set globally like this: -```bash +```js var leChallengeDns = require('le-challenge-dns').create({ debug: false }); @@ -41,21 +40,37 @@ var leChallengeDns = require('le-challenge-dns').create({ var Greenlock = require('greenlock'); Greenlock.create({ - server: LE.stagingServerUrl // Change to LE.productionServerUrl in production -, challengeType: 'dns-01' + ... , challenges: { 'dns-01': leChallengeDns } -, approveDomains: [ 'example.com' ] +, approveDomains: [ 'example.com', '*.example.com' ] }); ``` In can also be set in the `approveDomains` callback instead, like this: -``` +```js function approveDomains(opts, certs, cb) { - opts.challenges = { 'dns-01': leChallengeDns }; ... + opts.subject = 'example.com' + opts.domains = [ 'example.com', '*.example.com' ]; + + cb(null, { options: opts, certs: certs }); +} +``` + +If you didn't make the dns challenge globally available in the main greenlock config, +you can make it locally available here: + +```js +function approveDomains(opts, certs, cb) { + ... + + if (!opts.challenges) { opts.challenges = {}; } + opts.challenges['dns-01'] = leChallengeDns; + opts.challenges['http-01'] = ... + cb(null, { options: opts, certs: certs }); } ``` @@ -63,19 +78,33 @@ function approveDomains(opts, certs, cb) { NOTE: If you request a certificate with 6 domains listed, it will require 6 individual challenges. -Exposed Methods ---------------- +## Exposed Methods For ACME Challenge: -* `set(opts, domain, challange, keyAuthorization, done)` -* `get(defaults, domain, challenge, done)` -* `remove(defaults, domain, challenge, done)` +* `set(opts, done)` +* `remove(opts, done)` -Note: `get()` is a no-op for `dns-01`. +The options object has whatever options were set in `approveDomains()` as well as the `challenge`: + +```js +{ challenge: { + identifier: { type: 'dns', value: 'example.com' + , wildcard: true + , altname: '*.example.com' + , type: 'dns-01' + , token: 'xxxxxx' + , keyAuthorization: 'xxxxxx.abc123' + , dnsHost: '_acme-challenge.example.com' + , dnsAuthorization: 'abc123' + , expires: '1970-01-01T00:00:00Z' + } +} +``` + +Note: There's no `get()` because it's the DNS server, not the Greenlock server, that answers the requests. +(though I suppose you could implement it if you happen to run your DNS and webserver together... kinda weird though) For greenlock.js internals: -* `getOptions()` returns the internal defaults merged with the user-supplied options -* `loopback(defaults, domain, challange, done)` performs a dns lookup of the txt record -* `test(opts, domain, challange, keyAuthorization, done)` runs set, loopback, remove, loopback +* `options` stores the internal defaults merged with the user-supplied options diff --git a/index.js b/index.js index 8a734c6..fff1222 100644 --- a/index.js +++ b/index.js @@ -4,48 +4,44 @@ var Challenge = module.exports; Challenge.create = function (defaults) { return { - getOptions: function () { - return defaults || {}; - } + options: defaults , set: Challenge.set , get: Challenge.get , remove: Challenge.remove - , loopback: Challenge.loopback - , test: Challenge.test }; }; // Show the user the token and key and wait for them to be ready to continue -Challenge.set = function (args, domain, challenge, keyAuthorization, cb) { - var keyAuthDigest = require('crypto').createHash('sha256').update(keyAuthorization||'').digest('base64') - .replace(/\+/g, '-') - .replace(/\//g, '_') - .replace(/=+$/g, '') - ; - var challengeDomain = domain; +Challenge.set = function (args, cb) { + if (!args.challenge) { + console.error("please update to greenlock v2.7+"); + process.exit(); + } + var opts = args.challenge; if (this.leDnsResponse) { - this.leDnsResponse(challenge, keyAuthorization, keyAuthDigest, challengeDomain, domain) + this.leDnsResponse(opts.token, opts.keyAuthorization, opts.dnsAuthorization, opts.dnsHost, opts.altname) .then(function (/*successMessage*/) { cb(null); }); } else { console.info(""); - console.info("Challenge for '" + domain + "'"); + console.info("Challenge for '" + opts.altname + "'"); console.info(""); console.info("We now present (for you copy-and-paste pleasure) your ACME Challenge"); - console.info("public Challenge and secret KeyAuthorization and Digest, in that order, respectively:"); - console.info(challenge); - console.info(keyAuthorization); - console.info(keyAuthDigest); console.info(""); - console.info(challengeDomain + "\tTXT " + keyAuthDigest + "\tTTL 60"); + console.info(opts.dnsHost + "\tTXT " + opts.dnsAuthorization + "\tTTL 60"); console.info(""); console.info(JSON.stringify({ - domain: domain - , challenge: challenge - , keyAuthorization: keyAuthorization - , keyAuthDigest: keyAuthDigest + identifier: opts.identifier + , wildcard: opts.wildcard + , altname: opts.altname + , type: opts.type + , token: opts.token + , keyAuthorization: opts.keyAuthorization + , dnsHost: opts.dnsHost + , dnsAuthorization: opts.dnsAuthorization + , expires: opts.expires }, null, ' ').replace(/^/gm, '\t')); console.info(""); console.info("hit enter to continue..."); @@ -58,13 +54,14 @@ Challenge.set = function (args, domain, challenge, keyAuthorization, cb) { }; // nothing to do here, that's why it's manual -Challenge.get = function (defaults, domain, challenge, cb) { +Challenge.get = function (defaults, cb) { + // defaults.challenge cb(null); }; // might as well tell the user that whatever they were setting up has been checked -Challenge.remove = function (args, domain, challenge, cb) { - console.info("Challenge for '" + domain + "' complete. You may remove it."); - cb(null); - //}); +Challenge.remove = function (args, cb) { + console.info("Challenge complete. You may remove the DNS-01 challenge record:"); + console.info("\t" + args.challenge.altname + "\tTXT\t" + args.challenge.dnsAuthorization); + cb(null); }; diff --git a/package.json b/package.json index 5801f9b..42c0548 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "le-challenge-dns", - "version": "2.3.2", - "description": "A manual (interactive CLI) dns-based strategy for node-letsencrypt for setting, retrieving, and clearing ACME DNS-01 challenges issued by the ACME server", + "version": "3.0.0", + "description": "A manual (interactive CLI) dns-based strategy for Greenlock / Let's Encrypt / ACME DNS-01 challenges", "main": "index.js", "scripts": { "test": "node test.js" @@ -11,21 +11,18 @@ "url": "git+https://git.coolaj86.com/coolaj86/le-challenge-dns.js.git" }, "keywords": [ - "le", + "Let's Encrypt", + "Greenlock", + "ACME", + "dns-01", + "wildcard", + "wildcards", "letsencrypt", - "le-challenge", - "le-challenge-", - "le-challenge-dns", "manual", "interactive", "cli", - "acme", - "Let's Encrypt v2", - "LetsEncrypt", - "challenge", "dns", - "cluster", - "ephemeral" + "challenge" ], "author": "AJ ONeal (https://coolaj86.com/)", "license": "(MIT OR Apache-2.0)",