commit ed4a83d78833e7df49b14c084396a433f763d6ce Author: AJ ONeal Date: Thu Jun 6 23:32:22 2019 -0600 initial commit diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..420e082 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "bracketSpacing": true, + "printWidth": 80, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": true +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..778ea37 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# [acme-dns-01-duckdns](https://git.rootprojects.org/root/acme-dns-01-duckdns) | a [Root](https://rootrpojects.org) project + +DuckDNS for Let's Encrypt / ACME dns-01 challenges with ACME.js and Greenlock.js (Node.js). + +# Tests + +``` +# node ./test.js domain-zone api-token +node ./test.js example.com xxxxxx +``` diff --git a/index.js b/index.js new file mode 100644 index 0000000..647221a --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('./lib/index.js'); diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..6b4bd4d --- /dev/null +++ b/lib/index.js @@ -0,0 +1,87 @@ +'use strict'; + +var request = require('@root/request'); +request = require('util').promisify(request); + +var dns = require('dns'); + +module.exports.create = function(config) { + // config = { baseUrl, token, apiTimeout } + var baseUrl = config.baseUrl || 'https://www.duckdns.org'; + var authtoken = config.token; + var apiTimeout = config.apiTimeout || 5000; + // return object containing get/set/remove functions + return { + set: function(data) { + var domain_name = data.challenge.identifier.value; + var txt = data.challenge.dnsAuthorization; + var url = + baseUrl + + '/update?domains=' + + domain_name + + '&token=' + + authtoken + + '&txt=' + + txt; + + // console.log("adding txt", data); + return request({ + method: 'GET', + url: url + }).then(function(resp) { + if (resp === 'OK') { + return true; + } + throw new Error('record did not set. check subdomain, api key, etc'); + }); + }, + remove: function(data) { + var domain_name = data.challenge.identifier.value; + var txt = data.challenge.dnsAuthorization; + var url = + baseUrl + + '/update?domains=' + + domain_name + + '&token=' + + authtoken + + '&txt=' + + txt + + '&clear=true'; + + // console.log("removing txt"); + return request({ + method: 'GET', + url: url + }).then(function(resp) { + if (resp === 'OK') { + return true; + } + throw new Error('Couldnt remove record. check subdomain, api key, etc'); + }); + }, + get: function(data) { + // the duckdns doesnt provide an API to fetch DNS records so we are using Node DNS library to get TXT record. + // We need to add manual delay as the DNS records do not get updated instantly. + var domain_name = data.challenge.identifier.value; + return delay(apiTimeout).then(function() { + console.log('fetching txt', data); + return new Promise(function(resolve, reject) { + dns.resolveTxt(domain_name, (err, txt) => { + if (err) { + console.error(err); + reject(null); + } + // console.log(txt); + if (txt && txt[0] && txt[0][0]) + resolve({ dnsAuthorization: txt[0][0] }); + else resolve(null); + }); + }); + }); + } + }; +}; + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..2a81dc0 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "acme-dns-01-duckdns", + "version": "3.0.0", + "description": "DuckDNS for Let's Encrypt / ACME dns-01 challenges with ACME.js and Greenlock.js", + "main": "index.js", + "scripts": { + "test": "node ./test.js" + }, + "repository": { + "type": "git", + "url": "https://git.rootprojects.org/root/acme-dns-01-duckdns.git" + }, + "keywords": [ + "duckdns", + "duck", + "dns", + "dns-01", + "letsencrypt", + "acme", + "greenlock" + ], + "author": "AJ ONeal (https://coolaj86.com/)", + "license": "MPL-2.0", + "dependencies": { + "@root/request": "^1.3.11" + }, + "devDependencies": { + "acme-challenge-test": "^3.1.0" + } +} diff --git a/test.js b/test.js new file mode 100755 index 0000000..8674fce --- /dev/null +++ b/test.js @@ -0,0 +1,23 @@ +#!/usr/bin/env node +'use strict'; + +// See https://git.coolaj86.com/coolaj86/acme-challenge-test.js +var tester = require('acme-challenge-test'); + +// Usage: node ./test.js example.com xxxxxxxxx +var zone = process.argv[2]; +var challenger = require('./index.js').create({ + token: process.argv[3] +}); + +// The dry-run tests can pass on, literally, 'example.com' +// but the integration tests require that you have control over the domain +tester + .testZone('dns-01', zone, challenger) + .then(function() { + console.info('PASS', zone); + }) + .catch(function(e) { + console.error(e.message); + console.error(e.stack); + });