'use strict'; var request = require('@root/request'); request = require('util').promisify(request); var defaults = { baseUrl: 'https://api.digitalocean.com' }; module.exports.create = function(config) { // config = { baseUrl, token } var baseUrl = config.baseUrl || defaults.baseUrl; var authtoken = config.token; var helpers = { getZonenames: function(/*opts*/) { // { dnsHosts: [ xxxx.foo.example.com ] } var url = baseUrl + '/v2/domains/'; return request({ method: 'GET', url: url, headers: { Authorization: 'Bearer ' + authtoken, 'Content-Type': 'application/json' }, json: true }).then(function(resp) { return resp.body.domains.map(function(x) { return x.name; }); }); }, getTXTRecord: function(data) { // data:{dnsPrefix:"_88-acme-challenge-0e.foo",zone:"example.com",txt:"_cdZWaclIbkP1qYpMkZIURTK--ydQIK6d9axFmftWz0"} var dnsPrefix = data.dnsPrefix; var txt = data.txt; var url = baseUrl + '/v2/domains/' + data.zone + '/records'; // 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, json: true, headers: { Authorization: 'Bearer ' + authtoken, 'Content-Type': 'application/json' } }).then(function(resp) { resp = resp.body; var entries = resp && resp.domain_records && resp.domain_records.filter(function(x) { return x.type === 'TXT' && x.name === dnsPrefix && x.data === txt; }); return entries && entries[0]; }); } }; return { zones: function(data) { //console.info('Get zones'); return helpers.getZonenames(data); }, set: function(data) { var ch = data.challenge; var txt = ch.dnsAuthorization; var url = baseUrl + '/v2/domains/' + ch.dnsZone + '/records'; // console.info('Adding TXT', data); return request({ method: 'POST', url: url, headers: { Authorization: 'Bearer ' + authtoken, 'Content-Type': 'application/json' }, json: { type: 'TXT', // Note: dnsPrefix != dnsHost.split('.')[0] // _greenlock-dryrun-2277.bar.foo.example.com => _greenlock-dryrun-2277.bar.foo name: ch.dnsPrefix, data: txt, // Note: set a LOW ttl so that responses are not cached so long ttl: 300 } }).then(function(resp) { resp = resp.body; if (resp && resp.domain_record && resp.domain_record.data === txt) { return true; } throw new Error('record did not set. check subdomain, api key, etc'); }); }, remove: function(data) { var ch = data.challenge; // Digital ocean provides the api to remove records by ID. So we first get the recordId and use it to remove the domain record // console.info('Removing TXT', data); var payload = { dnsPrefix: ch.dnsPrefix, zone: ch.dnsZone, txt: ch.dnsAuthorization }; return helpers.getTXTRecord(payload).then(function(txtRecord) { if (txtRecord) { var url = baseUrl + '/v2/domains/' + ch.dnsZone + '/records/' + txtRecord.id; return request({ method: 'DELETE', url: url, headers: { Authorization: 'Bearer ' + authtoken, 'Content-Type': 'application/json' } }).then(function(resp) { resp = resp.body; return true; }); } else { throw new Error('Txt Record not found for removal'); } }); }, get: function(data) { var ch = data.challenge; // console.info('Fetching TXT', data); var payload = { dnsPrefix: ch.dnsPrefix, zone: ch.dnsZone, txt: ch.dnsAuthorization }; return helpers.getTXTRecord(payload).then(function(txtRecord) { if (txtRecord) { return { dnsAuthorization: txtRecord.data }; } else { return null; } }); } }; };