'use strict'; var defaults = { baseUrl: 'https://api.digitalocean.com/v2/domains' }; module.exports.create = function(config) { // config = { baseUrl, token } var baseUrl = (config.baseUrl || defaults.baseUrl).replace(/\/$/, ''); var authtoken = config.token; var request; function api(method, path, form) { var req = { method: method, url: baseUrl + path, headers: { Authorization: 'Bearer ' + authtoken, 'Content-Type': 'application/json' }, json: true, form: form }; return request(req).then(function(resp) { if (2 !== Math.floor(resp.statusCode / 100)) { console.error(resp.statusCode, req.url); console.error(); console.error('Request:'); console.error(req); console.error(); console.error('Response:'); console.error(resp.body); console.error(); throw new Error('Error response. Check token, baseUrl, domains, etc.'); } return resp; }); } var helpers = { getZonenames: function(/*opts*/) { // { dnsHosts: [ xxxx.foo.example.com ] } return api('GET', '/').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; // 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 api('GET', '/' + data.zone + '/records').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 { init: function(opts) { request = opts.request; return null; }, zones: function(data) { //console.info('Get zones'); return helpers.getZonenames(data); }, set: function(data) { var ch = data.challenge; var txt = ch.dnsAuthorization; // console.info('Adding TXT', data); return api('POST', '/' + ch.dnsZone + '/records', { type: 'TXT', name: ch.dnsPrefix, data: txt, 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 + '/' + ch.dnsZone + '/records/' + txtRecord.id; return api( 'DELETE', '/' + ch.dnsZone + '/records/' + txtRecord.id ).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; } }); } }; };