From ef5bd3ced28df3964b88ef70ee6ace18faef0ae2 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Thu, 13 Jun 2019 13:51:01 -0600 Subject: [PATCH] minor refactor --- README.md | 75 ++++++++++++++++++++++++-- lib/index.js | 148 +++++++++++++++++++++------------------------------ 2 files changed, 131 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 916d7c0..d2c2e40 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,77 @@ -# [acme-dns-01-vultr](https://git.rootprojects.org/root/acme-dns-01-vultr) | a [Root](https://rootrpojects.org) project +# [acme-dns-01-vultr](https://git.rootprojects.org/root/acme-dns-01-vultr.js) | a [Root](https://rootrpojects.org) project -Vultr DNS for Let's Encrypt / ACME dns-01 challenges with ACME.js and Greenlock.js (Node.js). +Vultr DNS + Let's Encrypt for Node.js + +This handles ACME dns-01 challenges, compatible with ACME.js and Greenlock.js. +Passes [acme-dns-01-test](https://git.rootprojects.org/root/acme-dns-01-test.js). + +# Install + +```bash +npm install --save acme-dns-01-vultr@3.x +``` + +# Usage + +First you create an instance with your credentials: + +```js +var dns01 = require('acme-dns-01-vultr').create({ + baseUrl: 'https://api.vultr.com/v1/dns', // default + apiKey: 'xxxx' +}); +``` + +Then you can use it with any compatible ACME module, +such as Greenlock.js or ACME.js. + +### Greenlock.js + +```js +var Greenlock = require('greenlock-express'); +var greenlock = Greenlock.create({ + challenges: { + 'dns-01': dns01 + // ... + } +}); +``` + +See [Greenlockā„¢ Express](https://git.rootprojects.org/root/greenlock-express.js) +and/or [Greenlock.js](https://git.rootprojects.org/root/greenlock.js) documentation for more details. + +### ACME.js + +```js +// TODO +``` + +See the [ACME.js](https://git.rootprojects.org/root/acme-v2.js) for more details. + +### Build your own + +```js +dns01 + .set({ + identifier: { value: 'foo.example.com' }, + wildcard: false, + dnsHost: '_acme-challenge.foo.example.com' + dnsAuthorization: 'xxx_secret_xxx' + }) + .then(function () { + console.log("TXT record set"); + }) + .catch(function () { + console.log("Failed to set TXT record"); + }); +``` + +See [acme-dns-01-test](https://git.rootprojects.org/root/acme-dns-01-test.js) +for more implementation details. # Tests -``` -# node ./test.js domain-zone api-token +```bash +# node ./test.js domain-zone api-key node ./test.js example.com xxxxxx ``` diff --git a/lib/index.js b/lib/index.js index fff0ba8..3dbe6ca 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,146 +4,118 @@ var request = require('@root/request'); request = require('util').promisify(request); var defaults = { - baseUrl: 'https://api.vultr.com/' + baseUrl: 'https://api.vultr.com/v1/dns' }; module.exports.create = function(config) { - var baseUrl = config.baseUrl || defaults.baseUrl; + var baseUrl = (config.baseUrl || defaults.baseUrl).replace(/\/$/, ''); var apiKey = config.apiKey; + + function api(method, path, form) { + return request({ + method: method, + url: baseUrl + path, + headers: { + 'API-Key': apiKey + }, + json: true, + form: form + }); + } + return { zones: function(data) { - var url = baseUrl + 'v1/dns/list'; - return request({ - method: 'GET', - url: url, - headers: { - 'API-Key': apiKey - }, - json: true - }).then(function(resp) { - if (resp.statusCode == 200) { - return resp.body.map(function(x) { - return x.domain; - }); - } else { + return api('GET', '/list').then(function(resp) { + if (200 !== resp.statusCode) { console.error(resp.statusCode); console.error(resp.body); throw new Error('Could not get list of zones. Check api key, etc'); } + + return resp.body.map(function(x) { + return x.domain; + }); }); }, set: function(data) { var ch = data.challenge; var txt = ch.dnsAuthorization; // If the domain to be verified is - var url = baseUrl + 'v1/dns/create_record'; //console.debug('adding txt', data); - return request({ - method: 'POST', - url: url, - headers: { - 'API-Key': apiKey - }, - form: { - type: 'TXT', - name: ch.dnsPrefix, - data: '"' + txt + '"', // vultr requires the TXT record wraped in quotes - domain: ch.dnsZone, - ttl: 300 - } + return api('POST', '/create_record', { + type: 'TXT', + name: ch.dnsPrefix, + data: '"' + txt + '"', // vultr requires the TXT record wraped in quotes + domain: ch.dnsZone, + ttl: 300 }).then(function(resp) { - if (resp.statusCode == 200) { - return true; - } else { + if (200 !== resp.statusCode) { console.error(resp.statusCode); console.error(resp.body); throw new Error('record did not set. check subdomain, api key, etc'); } + + return true; }); }, remove: function(data) { var ch = data.challenge; - var url = baseUrl + 'v1/dns/records'; - return request({ - method: 'GET', - url: url + '?domain=' + ch.dnsZone, - json: true, - headers: { - 'API-Key': apiKey - } - }) + return api('GET', '/records?domain=' + ch.dnsZone) .then(function(resp) { - if (resp.statusCode == 200) { - resp = resp.body; - //console.debug(resp); - var entries = resp.filter(function(x) { - return x.type === 'TXT'; - }); - - var entry = entries.filter(function(x) { - // vultr wraps the TXT record in double quotes - return ( - x.data.substring(1, x.data.length - 1) === ch.dnsAuthorization - ); - })[0]; - - if (entry) { - return entry['RECORDID']; - } else { - throw new Error( - "Couldn't remove record. check subdomain, api key, etc" - ); - } - } else { + if (200 !== resp.statusCode) { throw new Error( 'record did not set. check subdomain, api key, etc' ); } + + resp = resp.body; + //console.debug(resp); + var entries = resp.filter(function(x) { + return x.type === 'TXT'; + }); + + var entry = entries.filter(function(x) { + // vultr wraps the TXT record in double quotes + return ( + x.data.substring(1, x.data.length - 1) === ch.dnsAuthorization + ); + })[0]; + + if (entry) { + return entry.RECORDID; + } else { + throw new Error( + "Couldn't remove record. check subdomain, api key, etc" + ); + } }) .then(function(recordId) { - var url = baseUrl + 'v1/dns/delete_record'; - - return request({ - method: 'POST', - url: url, - headers: { - 'API-Key': apiKey - }, - form: { - domain: ch.dnsZone, - RECORDID: recordId - } + return api('POST', '/delete_record', { + domain: ch.dnsZone, + RECORDID: recordId }).then(function(resp) { - if (resp.statusCode == 200) { - return true; - } else { + if (200 !== resp.statusCode) { console.error(resp.statusCode); console.error(resp.body); throw new Error( 'record did not remove. check subdomain, api key, etc' ); } + + return true; }); }); }, get: function(data) { var ch = data.challenge; - var url = baseUrl + 'v1/dns/records'; //console.debug('getting txt', data); // Digital ocean provides the api to fetch records by ID. Since we do not have id, we fetch all the records, // filter the required TXT record - return request({ - method: 'GET', - url: url + '?domain=' + ch.dnsZone, - json: true, - headers: { - 'API-Key': apiKey - } - }).then(function(resp) { + return api('GET', '/records?domain=' + ch.dnsZone).then(function(resp) { resp = resp.body; var entries = resp.filter(function(x) {