diff --git a/src/apps.js b/src/apps.js index db7768906..2d76dfccc 100644 --- a/src/apps.js +++ b/src/apps.js @@ -397,8 +397,8 @@ function get(appId, callback) { for (let d of domainObjects) { domainObjectMap[d.domain] = d; } app.iconUrl = getIconUrlSync(app); - app.fqdn = domains.fqdn(app.location, app.domain, domainObjectMap[app.domain].config); - app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, ad.domain, domainObjectMap[ad.domain].config); }); + app.fqdn = domains.fqdn(app.location, domainObjectMap[app.domain]); + app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, domainObjectMap[ad.domain]); }); callback(null, app); }); @@ -431,8 +431,8 @@ function getByIpAddress(ip, callback) { for (let d of domainObjects) { domainObjectMap[d.domain] = d; } app.iconUrl = getIconUrlSync(app); - app.fqdn = domains.fqdn(app.location, app.domain, domainObjectMap[app.domain].config); - app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, ad.domain, domainObjectMap[ad.domain].config); }); + app.fqdn = domains.fqdn(app.location, domainObjectMap[app.domain]); + app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, domainObjectMap[ad.domain]); }); callback(null, app); }); @@ -457,8 +457,8 @@ function getAll(callback) { async.eachSeries(apps, function (app, iteratorDone) { app.iconUrl = getIconUrlSync(app); - app.fqdn = domains.fqdn(app.location, app.domain, domainObjectMap[app.domain].config); - app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, ad.domain, domainObjectMap[ad.domain].config); }); + app.fqdn = domains.fqdn(app.location, domainObjectMap[app.domain]); + app.alternateDomains.forEach(function (ad) { ad.fqdn = domains.fqdn(ad.subdomain, domainObjectMap[ad.domain]); }); iteratorDone(null, app); }, function (error) { diff --git a/src/cloudron.js b/src/cloudron.js index 6747a86a3..025b2fe0f 100644 --- a/src/cloudron.js +++ b/src/cloudron.js @@ -292,7 +292,7 @@ function setDashboardDomain(domain, callback) { if (error && error.reason === DomainsError.NOT_FOUND) return callback(new CloudronError(CloudronError.BAD_FIELD, 'No such domain')); if (error) return callback(new CloudronError(CloudronError.INTERNAL_ERROR, error)); - const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config); + const fqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); config.setAdminDomain(domain); config.setAdminLocation(constants.ADMIN_LOCATION); diff --git a/src/dns/caas.js b/src/dns/caas.js index 50a9a0874..25b5ccc0c 100644 --- a/src/dns/caas.js +++ b/src/dns/caas.js @@ -4,35 +4,38 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), config = require('../config.js'), debug = require('debug')('box:dns/caas'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, superagent = require('superagent'), - util = require('util'); + util = require('util'), + waitForDns = require('./waitfordns.js'); -function getFqdn(subdomain, domain) { - assert.strictEqual(typeof subdomain, 'string'); +function getFqdn(location, domain) { + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); - return (subdomain === '') ? domain : subdomain + '-' + domain; + return (location === '') ? domain : location + '-' + domain; } -function add(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - var fqdn = subdomain !== '' && type === 'TXT' ? subdomain + '.' + dnsConfig.fqdn : getFqdn(subdomain, dnsConfig.fqdn); + const dnsConfig = domainObject.config; - debug('add: %s for zone %s of type %s with values %j', subdomain, dnsConfig.fqdn, type, values); + let fqdn = location !== '' && type === 'TXT' ? location + '.' + domainObject.domain : getFqdn(location, domainObject.domain); + + debug('add: %s for zone %s of type %s with values %j', location, domainObject.domain, type, values); var data = { type: type, @@ -54,16 +57,16 @@ function add(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - var fqdn = subdomain !== '' && type === 'TXT' ? subdomain + '.' + dnsConfig.fqdn : getFqdn(subdomain, dnsConfig.fqdn); + const dnsConfig = domainObject.config; + const fqdn = location !== '' && type === 'TXT' ? location + '.' + domainObject.domain : getFqdn(location, domainObject.domain); - debug('get: zoneName: %s subdomain: %s type: %s fqdn: %s', dnsConfig.fqdn, subdomain, type, fqdn); + debug('get: zoneName: %s subdomain: %s type: %s fqdn: %s', domainObject.domain, location, type, fqdn); superagent .get(config.apiServerOrigin() + '/api/v1/domains/' + fqdn) @@ -77,26 +80,15 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - add(dnsConfig, zoneName, subdomain, type, values, callback); -} - -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); - assert.strictEqual(typeof type, 'string'); - assert(util.isArray(values)); - assert.strictEqual(typeof callback, 'function'); - - debug('del: %s for zone %s of type %s with values %j', subdomain, dnsConfig.fqdn, type, values); + const dnsConfig = domainObject.config; + debug('del: %s for zone %s of type %s with values %j', location, domainObject.domain, type, values); var data = { type: type, @@ -104,7 +96,7 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }; superagent - .del(config.apiServerOrigin() + '/api/v1/domains/' + getFqdn(subdomain, dnsConfig.fqdn)) + .del(config.apiServerOrigin() + '/api/v1/domains/' + getFqdn(location, domainObject.domain)) .query({ token: dnsConfig.token }) .send(data) .timeout(30 * 1000) @@ -119,29 +111,42 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, domain, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config; + if (!dnsConfig.token || typeof dnsConfig.token !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'token must be a non-empty string')); + const ip = '127.0.0.1'; + var credentials = { token: dnsConfig.token, - fqdn: domain, hyphenatedSubdomains: true // this will ensure we always use them, regardless of passed-in configs }; - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/cloudflare.js b/src/dns/cloudflare.js index b31f1acfc..0058e9f87 100644 --- a/src/dns/cloudflare.js +++ b/src/dns/cloudflare.js @@ -4,7 +4,7 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; @@ -12,9 +12,11 @@ var assert = require('assert'), async = require('async'), debug = require('debug')('box:dns/cloudflare'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, superagent = require('superagent'), util = require('util'), + waitForDns = require('./waitfordns.js'), _ = require('underscore'); // we are using latest v4 stable API https://api.cloudflare.com/#getting-started-endpoints @@ -54,16 +56,13 @@ function getZoneByName(dnsConfig, zoneName, callback) { } // gets records filtered by zone, type and fqdn -function getDnsRecords(dnsConfig, zoneId, zoneName, subdomain, type, callback) { +function getDnsRecords(dnsConfig, zoneId, fqdn, type, callback) { assert.strictEqual(typeof dnsConfig, 'object'); assert.strictEqual(typeof zoneId, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); + assert.strictEqual(typeof fqdn, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - var fqdn = subdomain === '' ? zoneName : subdomain + '.' + zoneName; - superagent.get(CLOUDFLARE_ENDPOINT + '/zones/' + zoneId + '/dns_records') .set('X-Auth-Key',dnsConfig.token) .set('X-Auth-Email',dnsConfig.email) @@ -79,24 +78,25 @@ function getDnsRecords(dnsConfig, zoneId, zoneName, subdomain, type, callback) { }); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - var fqdn = subdomain === '' ? zoneName : subdomain + '.' + zoneName; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); - debug('upsert: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + debug('upsert: %s for zone %s of type %s with values %j', fqdn, zoneName, type, values); getZoneByName(dnsConfig, zoneName, function(error, result) { if (error) return callback(error); let zoneId = result.id; - getDnsRecords(dnsConfig, zoneId, zoneName, subdomain, type, function (error, dnsRecords) { + getDnsRecords(dnsConfig, zoneId, fqdn, type, function (error, dnsRecords) { if (error) return callback(error); let i = 0; // // used to track available records to update instead of create @@ -119,7 +119,7 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { }; if (i >= dnsRecords.length) { // create a new record - debug(`upsert: Adding new record subdomain: ${subdomain}, zoneName: ${zoneName} proxied: false`); + debug(`upsert: Adding new record fqdn: ${fqdn}, zoneName: ${zoneName} proxied: false`); superagent.post(CLOUDFLARE_ENDPOINT + '/zones/' + zoneId + '/dns_records') .set('X-Auth-Key', dnsConfig.token) @@ -135,7 +135,7 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { } else { // replace existing record data.proxied = dnsRecords[i].proxied; // preserve proxied parameter - debug(`upsert: Updating existing record subdomain: ${subdomain}, zoneName: ${zoneName} proxied: ${data.proxied}`); + debug(`upsert: Updating existing record fqdn: ${fqdn}, zoneName: ${zoneName} proxied: ${data.proxied}`); superagent.put(CLOUDFLARE_ENDPOINT + '/zones/' + zoneId + '/dns_records/' + dnsRecords[i].id) .set('X-Auth-Key', dnsConfig.token) @@ -156,17 +156,20 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - getZoneByName(dnsConfig, zoneName, function(error, result){ + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + + getZoneByName(dnsConfig, zoneName, function(error, zone) { if (error) return callback(error); - getDnsRecords(dnsConfig, result.id, zoneName, subdomain, type, function(error, result) { + getDnsRecords(dnsConfig, zone.id, fqdn, type, function (error, result) { if (error) return callback(error); var tmp = result.map(function (record) { return record.content; }); @@ -177,18 +180,21 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - getZoneByName(dnsConfig, zoneName, function(error, result){ + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + + getZoneByName(dnsConfig, zoneName, function(error, zone) { if (error) return callback(error); - getDnsRecords(dnsConfig, result.id, zoneName, subdomain, type, function(error, result) { + getDnsRecords(dnsConfig, zone.id, fqdn, type, function(error, result) { if (error) return callback(error); if (result.length === 0) return callback(null); @@ -221,16 +227,31 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (!dnsConfig.token || typeof dnsConfig.token !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'token must be a non-empty string')); if (!dnsConfig.email || typeof dnsConfig.email !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'email must be a non-empty string')); + const ip = '127.0.0.1'; + var credentials = { token: dnsConfig.token, email: dnsConfig.email @@ -242,22 +263,22 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { if (error && error.code === 'ENOTFOUND') return callback(new DomainsError(DomainsError.BAD_FIELD, 'Unable to resolve nameservers for this domain')); if (error || !nameservers) return callback(new DomainsError(DomainsError.BAD_FIELD, error ? error.message : 'Unable to get nameservers')); - getZoneByName(dnsConfig, zoneName, function(error, result) { + getZoneByName(dnsConfig, zoneName, function(error, zone) { if (error) return callback(error); - if (!_.isEqual(result.name_servers.sort(), nameservers.sort())) { - debug('verifyDnsConfig: %j and %j do not match', nameservers, result.name_servers); + if (!_.isEqual(zone.name_servers.sort(), nameservers.sort())) { + debug('verifyDnsConfig: %j and %j do not match', nameservers, zone.name_servers); return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to Cloudflare')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(dnsConfig, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/digitalocean.js b/src/dns/digitalocean.js index 0949a5d50..d41795da3 100644 --- a/src/dns/digitalocean.js +++ b/src/dns/digitalocean.js @@ -4,7 +4,7 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; @@ -12,10 +12,12 @@ var assert = require('assert'), async = require('async'), debug = require('debug')('box:dns/digitalocean'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, safe = require('safetydance'), superagent = require('superagent'), - util = require('util'); + util = require('util'), + waitForDns = require('./waitfordns.js'); var DIGITALOCEAN_ENDPOINT = 'https://api.digitalocean.com'; @@ -23,10 +25,10 @@ function formatError(response) { return util.format('DigitalOcean DNS error [%s] %j', response.statusCode, response.body); } -function getInternal(dnsConfig, zoneName, subdomain, type, callback) { +function getInternal(dnsConfig, zoneName, name, type, callback) { assert.strictEqual(typeof dnsConfig, 'object'); assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); + assert.strictEqual(typeof name, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); @@ -45,7 +47,7 @@ function getInternal(dnsConfig, zoneName, subdomain, type, callback) { if (result.statusCode !== 200) return callback(new DomainsError(DomainsError.EXTERNAL_ERROR, formatError(result))); matchingRecords = matchingRecords.concat(result.body.domain_records.filter(function (record) { - return (record.type === type && record.name === subdomain); + return (record.type === type && record.name === name); })); nextPage = (result.body.links && result.body.links.pages) ? result.body.links.pages.next : null; @@ -61,19 +63,20 @@ function getInternal(dnsConfig, zoneName, subdomain, type, callback) { }); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug('upsert: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + debug('upsert: %s for zone %s of type %s with values %j', name, zoneName, type, values); - getInternal(dnsConfig, zoneName, subdomain, type, function (error, result) { + getInternal(dnsConfig, zoneName, name, type, function (error, result) { if (error) return callback(error); // used to track available records to update instead of create @@ -89,7 +92,7 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { var data = { type: type, - name: subdomain, + name: name, data: value, priority: priority, ttl: 1 @@ -133,16 +136,17 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - getInternal(dnsConfig, zoneName, subdomain, type, function (error, result) { + getInternal(dnsConfig, zoneName, name, type, function (error, result) { if (error) return callback(error); // We only return the value string @@ -154,17 +158,18 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - getInternal(dnsConfig, zoneName, subdomain, type, function (error, result) { + getInternal(dnsConfig, zoneName, name, type, function (error, result) { if (error) return callback(error); if (result.length === 0) return callback(null); @@ -193,15 +198,30 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (!dnsConfig.token || typeof dnsConfig.token !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'token must be a non-empty string')); + const ip = '127.0.0.1'; + var credentials = { token: dnsConfig.token }; @@ -217,14 +237,14 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to Digital Ocean')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(dnsConfig, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/gandi.js b/src/dns/gandi.js index 420f2ee65..096449849 100644 --- a/src/dns/gandi.js +++ b/src/dns/gandi.js @@ -4,16 +4,18 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), debug = require('debug')('box:dns/gandi'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, superagent = require('superagent'), - util = require('util'); + util = require('util'), + waitForDns = require('./waitfordns.js'); var GANDI_API = 'https://dns.api.gandi.net/api/v5'; @@ -21,24 +23,25 @@ function formatError(response) { return util.format(`Gandi DNS error [${response.statusCode}] ${response.body.message}`); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`upsert: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`upsert: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); var data = { 'rrset_ttl': 300, // this is the minimum allowed 'rrset_values': values // for mx records, value is already of the ' ' format }; - superagent.put(`${GANDI_API}/domains/${zoneName}/records/${subdomain}/${type}`) + superagent.put(`${GANDI_API}/domains/${zoneName}/records/${name}/${type}`) .set('X-Api-Key', dnsConfig.token) .timeout(30 * 1000) .send(data) @@ -52,18 +55,19 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`get: ${subdomain} in zone ${zoneName} of type ${type}`); + debug(`get: ${name} in zone ${zoneName} of type ${type}`); - superagent.get(`${GANDI_API}/domains/${zoneName}/records/${subdomain}/${type}`) + superagent.get(`${GANDI_API}/domains/${zoneName}/records/${name}/${type}`) .set('X-Api-Key', dnsConfig.token) .timeout(30 * 1000) .end(function (error, result) { @@ -78,19 +82,20 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`del: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`del: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); - superagent.del(`${GANDI_API}/domains/${zoneName}/records/${subdomain}/${type}`) + superagent.del(`${GANDI_API}/domains/${zoneName}/records/${name}/${type}`) .set('X-Api-Key', dnsConfig.token) .timeout(30 * 1000) .end(function (error, result) { @@ -105,19 +110,34 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (!dnsConfig.token || typeof dnsConfig.token !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'token must be a non-empty string')); var credentials = { token: dnsConfig.token }; + const ip = '127.0.0.1'; + if (process.env.BOX_ENV === 'test') return callback(null, credentials); // this shouldn't be here dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { @@ -129,14 +149,14 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to Gandi')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(dnsConfig, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/gcdns.js b/src/dns/gcdns.js index 28b039396..2fe44d939 100644 --- a/src/dns/gcdns.js +++ b/src/dns/gcdns.js @@ -4,16 +4,18 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), debug = require('debug')('box:dns/gcdns'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, GCDNS = require('@google-cloud/dns'), util = require('util'), + waitForDns = require('./waitfordns.js'), _ = require('underscore'); function getDnsCredentials(dnsConfig) { @@ -55,22 +57,23 @@ function getZoneByName(dnsConfig, zoneName, callback) { }); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('add: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + + debug('add: %s for zone %s of type %s with values %j', fqdn, zoneName, type, values); getZoneByName(getDnsCredentials(dnsConfig), zoneName, function (error, zone) { if (error) return callback(error); - var domain = (subdomain ? subdomain + '.' : '') + zoneName + '.'; - - zone.getRecords({ type: type, name: domain }, function (error, oldRecords) { + zone.getRecords({ type: type, name: fqdn + '.' }, function (error, oldRecords) { if (error && error.code === 403) return callback(new DomainsError(DomainsError.ACCESS_DENIED, error.message)); if (error) { debug('upsert->zone.getRecords', error); @@ -78,12 +81,12 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { } var newRecord = zone.record(type, { - name: domain, + name: fqdn + '.', data: values, ttl: 1 }); - zone.createChange({ delete: oldRecords, add: newRecord }, function(error, change) { + zone.createChange({ delete: oldRecords, add: newRecord }, function(error /*, change */) { if (error && error.code === 403) return callback(new DomainsError(DomainsError.ACCESS_DENIED, error.message)); if (error && error.code === 412) return callback(new DomainsError(DomainsError.STILL_BUSY, error.message)); if (error) { @@ -97,18 +100,21 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + getZoneByName(getDnsCredentials(dnsConfig), zoneName, function (error, zone) { if (error) return callback(error); var params = { - name: (subdomain ? subdomain + '.' : '') + zoneName + '.', + name: fqdn + '.', type: type }; @@ -122,20 +128,21 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + getZoneByName(getDnsCredentials(dnsConfig), zoneName, function (error, zone) { if (error) return callback(error); - var domain = (subdomain ? subdomain + '.' : '') + zoneName + '.'; - - zone.getRecords({ type: type, name: domain }, function(error, oldRecords) { + zone.getRecords({ type: type, name: fqdn + '.' }, function(error, oldRecords) { if (error && error.code === 403) return callback(new DomainsError(DomainsError.ACCESS_DENIED, error.message)); if (error) { debug('del->zone.getRecords', error); @@ -156,19 +163,35 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (typeof dnsConfig.projectId !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'projectId must be a string')); if (!dnsConfig.credentials || typeof dnsConfig.credentials !== 'object') return callback(new DomainsError(DomainsError.BAD_FIELD, 'credentials must be an object')); if (typeof dnsConfig.credentials.client_email !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'credentials.client_email must be a string')); if (typeof dnsConfig.credentials.private_key !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'credentials.private_key must be a string')); var credentials = getDnsCredentials(dnsConfig); + + const ip = '127.0.0.1'; + if (process.env.BOX_ENV === 'test') return callback(null, credentials); // this shouldn't be here dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { @@ -184,14 +207,14 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to Google Cloud DNS')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(dnsConfig, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/godaddy.js b/src/dns/godaddy.js index c62877a6d..58fd2101e 100644 --- a/src/dns/godaddy.js +++ b/src/dns/godaddy.js @@ -4,16 +4,18 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), debug = require('debug')('box:dns/godaddy'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, superagent = require('superagent'), - util = require('util'); + util = require('util'), + waitForDns = require('./waitfordns.js'); // const GODADDY_API_OTE = 'https://api.ote-godaddy.com/v1/domains'; const GODADDY_API = 'https://api.godaddy.com/v1/domains'; @@ -27,17 +29,18 @@ function formatError(response) { return util.format(`GoDaddy DNS error [${response.statusCode}] ${response.body.message}`); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`upsert: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`upsert: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); var records = [ ]; values.forEach(function (value) { @@ -53,7 +56,7 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { records.push(record); }); - superagent.put(`${GODADDY_API}/${zoneName}/records/${type}/${subdomain}`) + superagent.put(`${GODADDY_API}/${zoneName}/records/${type}/${name}`) .set('Authorization', `sso-key ${dnsConfig.apiKey}:${dnsConfig.apiSecret}`) .timeout(30 * 1000) .send(records) @@ -68,18 +71,19 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`get: ${subdomain} in zone ${zoneName} of type ${type}`); + debug(`get: ${name} in zone ${zoneName} of type ${type}`); - superagent.get(`${GODADDY_API}/${zoneName}/records/${type}/${subdomain}`) + superagent.get(`${GODADDY_API}/${zoneName}/records/${type}/${name}`) .set('Authorization', `sso-key ${dnsConfig.apiKey}:${dnsConfig.apiSecret}`) .timeout(30 * 1000) .end(function (error, result) { @@ -98,22 +102,23 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`get: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`get: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); if (type !== 'A' && type !== 'TXT') return callback(new DomainsError(DomainsError.EXTERNAL_ERROR, new Error('Record deletion is not supported by GoDaddy API'))); // check if the record exists at all so that we don't insert the "Dead" record for no reason - get(dnsConfig, zoneName, subdomain, type, function (error, values) { + get(domainObject, location, type, function (error, values) { if (error) return callback(error); if (values.length === 0) return callback(); @@ -123,7 +128,7 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { data: type === 'A' ? GODADDY_INVALID_IP : GODADDY_INVALID_TXT }]; - superagent.put(`${GODADDY_API}/${zoneName}/records/${type}/${subdomain}`) + superagent.put(`${GODADDY_API}/${zoneName}/records/${type}/${name}`) .set('Authorization', `sso-key ${dnsConfig.apiKey}:${dnsConfig.apiSecret}`) .send(records) .timeout(30 * 1000) @@ -140,16 +145,31 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (!dnsConfig.apiKey || typeof dnsConfig.apiKey !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'apiKey must be a non-empty string')); if (!dnsConfig.apiSecret || typeof dnsConfig.apiSecret !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'apiSecret must be a non-empty string')); + const ip = '127.0.0.1'; + var credentials = { apiKey: dnsConfig.apiKey, apiSecret: dnsConfig.apiSecret @@ -166,14 +186,14 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to GoDaddy')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(dnsConfig, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/interface.js b/src/dns/interface.js index 129ca82da..458906a03 100644 --- a/src/dns/interface.js +++ b/src/dns/interface.js @@ -10,18 +10,16 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), - DomainsError = require('../domains.js').DomainsError, util = require('util'); -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); @@ -31,10 +29,9 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { callback(new Error('not implemented')); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); @@ -43,10 +40,9 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { callback(new Error('not implemented')); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); @@ -56,11 +52,19 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { callback(new Error('not implemented')); } -function verifyDnsConfig(dnsConfig, domain, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } + assert.strictEqual(typeof callback, 'function'); + + callback(); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); assert.strictEqual(typeof callback, 'function'); // Result: dnsConfig object diff --git a/src/dns/manual.js b/src/dns/manual.js index 332724fac..4893ad84a 100644 --- a/src/dns/manual.js +++ b/src/dns/manual.js @@ -4,43 +4,42 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), debug = require('debug')('box:dns/manual'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, - util = require('util'); + util = require('util'), + waitForDns = require('./waitfordns.js'); -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('upsert: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + debug('upsert: %s for zone %s of type %s with values %j', location, domainObject.zoneName, type, values); return callback(null); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); callback(null, [ ]); // returning ip confuses apptask into thinking the entry already exists } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); @@ -48,13 +47,25 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { return callback(); } -function verifyDnsConfig(dnsConfig, domain, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const zoneName = domainObject.zoneName; + // Very basic check if the nameservers can be fetched dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { if (error && error.code === 'ENOTFOUND') return callback(new DomainsError(DomainsError.BAD_FIELD, 'Unable to resolve nameservers for this domain')); diff --git a/src/dns/namecom.js b/src/dns/namecom.js index a4140a631..444245b2e 100644 --- a/src/dns/namecom.js +++ b/src/dns/namecom.js @@ -4,16 +4,19 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), debug = require('debug')('box:dns/namecom'), dns = require('../native-dns.js'), - safe = require('safetydance'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, - superagent = require('superagent'); + safe = require('safetydance'), + superagent = require('superagent'), + util = require('util'), + waitForDns = require('./waitfordns.js'); const NAMECOM_API = 'https://api.name.com/v4'; @@ -21,18 +24,18 @@ function formatError(response) { return `Name.com DNS error [${response.statusCode}] ${response.text}`; } -function addRecord(dnsConfig, zoneName, subdomain, type, values, callback) { +function addRecord(dnsConfig, zoneName, name, type, values, callback) { assert.strictEqual(typeof dnsConfig, 'object'); assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); + assert.strictEqual(typeof name, 'string'); assert.strictEqual(typeof type, 'string'); assert(Array.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug(`add: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`add: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); var data = { - host: subdomain, + host: name, type: type, ttl: 300 // 300 is the lowest }; @@ -57,19 +60,19 @@ function addRecord(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function updateRecord(dnsConfig, zoneName, recordId, subdomain, type, values, callback) { +function updateRecord(dnsConfig, zoneName, recordId, name, type, values, callback) { assert.strictEqual(typeof dnsConfig, 'object'); assert.strictEqual(typeof zoneName, 'string'); assert.strictEqual(typeof recordId, 'number'); - assert.strictEqual(typeof subdomain, 'string'); + assert.strictEqual(typeof name, 'string'); assert.strictEqual(typeof type, 'string'); assert(Array.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug(`update:${recordId} on ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`update:${recordId} on ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); var data = { - host: subdomain, + host: name, type: type, ttl: 300 // 300 is the lowest }; @@ -94,16 +97,14 @@ function updateRecord(dnsConfig, zoneName, recordId, subdomain, type, values, ca }); } -function getInternal(dnsConfig, zoneName, subdomain, type, callback) { +function getInternal(dnsConfig, zoneName, name, type, callback) { assert.strictEqual(typeof dnsConfig, 'object'); assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); + assert.strictEqual(typeof name, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; - - debug(`getInternal: ${subdomain} in zone ${zoneName} of type ${type}`); + debug(`getInternal: ${name} in zone ${zoneName} of type ${type}`); superagent.get(`${NAMECOM_API}/domains/${zoneName}/records`) .auth(dnsConfig.username, dnsConfig.token) @@ -123,7 +124,7 @@ function getInternal(dnsConfig, zoneName, subdomain, type, callback) { }); var results = result.body.records.filter(function (r) { - return (r.host === subdomain && r.type === type); + return (r.host === name && r.type === type); }); debug('getInternal: %j', results); @@ -132,35 +133,39 @@ function getInternal(dnsConfig, zoneName, subdomain, type, callback) { }); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); - assert(Array.isArray(values)); + assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`upsert: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`upsert: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); - getInternal(dnsConfig, zoneName, subdomain, type, function (error, result) { + getInternal(dnsConfig, zoneName, name, type, function (error, result) { if (error) return callback(error); - if (result.length === 0) return addRecord(dnsConfig, zoneName, subdomain, type, values, callback); + if (result.length === 0) return addRecord(dnsConfig, zoneName, name, type, values, callback); - return updateRecord(dnsConfig, zoneName, result[0].id, subdomain, type, values, callback); + return updateRecord(dnsConfig, zoneName, result[0].id, name, type, values, callback); }); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - getInternal(dnsConfig, zoneName, subdomain, type, function (error, result) { + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; + + getInternal(dnsConfig, zoneName, name, type, function (error, result) { if (error) return callback(error); var tmp = result.map(function (record) { return record.answer; }); @@ -171,19 +176,20 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); - assert(Array.isArray(values)); + assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - subdomain = subdomain || '@'; + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + name = domains.getName(domainObject, location, type) || '@'; - debug(`del: ${subdomain} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); + debug(`del: ${name} in zone ${zoneName} of type ${type} with values ${JSON.stringify(values)}`); - getInternal(dnsConfig, zoneName, subdomain, type, function (error, result) { + getInternal(dnsConfig, zoneName, name, type, function (error, result) { if (error) return callback(error); if (result.length === 0) return callback(); @@ -201,13 +207,26 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (typeof dnsConfig.username !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'username must be a string')); if (typeof dnsConfig.token !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'token must be a string')); @@ -216,6 +235,8 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { token: dnsConfig.token }; + const ip = '127.0.0.1'; + if (process.env.BOX_ENV === 'test') return callback(null, credentials); // this shouldn't be here dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { @@ -227,14 +248,14 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to Name.com')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(dnsConfig, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/noop.js b/src/dns/noop.js index c6f732637..02bfeb0d4 100644 --- a/src/dns/noop.js +++ b/src/dns/noop.js @@ -4,7 +4,7 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: waitForDns, + wait: wait, verifyDnsConfig: verifyDnsConfig }; @@ -12,33 +12,30 @@ var assert = require('assert'), debug = require('debug')('box:dns/noop'), util = require('util'); -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('upsert: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + debug('upsert: %s for zone %s of type %s with values %j', location, domainObject.zoneName, type, values); return callback(null); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); callback(null, [ ]); // returning ip confuses apptask into thinking the entry already exists } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); @@ -46,9 +43,9 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { return callback(); } -function waitForDns(domain, zoneName, type, value, options, callback) { - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof zoneName, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof value, 'string'); assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } @@ -57,11 +54,8 @@ function waitForDns(domain, zoneName, type, value, options, callback) { callback(); } -function verifyDnsConfig(dnsConfig, domain, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); assert.strictEqual(typeof callback, 'function'); return callback(null, { }); diff --git a/src/dns/route53.js b/src/dns/route53.js index 6b1f29df1..1e92cb140 100644 --- a/src/dns/route53.js +++ b/src/dns/route53.js @@ -4,19 +4,18 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), - verifyDnsConfig: verifyDnsConfig, - - // not part of "dns" interface - getHostedZone: getHostedZone + wait: wait, + verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), AWS = require('aws-sdk'), debug = require('debug')('box:dns/route53'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, util = require('util'), + waitForDns = require('./waitfordns.js'), _ = require('underscore'); function getDnsCredentials(dnsConfig) { @@ -82,20 +81,22 @@ function getHostedZone(dnsConfig, zoneName, callback) { }); } -function add(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('add: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + + debug('add: %s for zone %s of type %s with values %j', fqdn, zoneName, type, values); getZoneByName(dnsConfig, zoneName, function (error, zone) { if (error) return callback(error); - var fqdn = subdomain === '' ? zoneName : subdomain + '.' + zoneName; var records = values.map(function (v) { return { Value: v }; }); // for mx records, value is already of the ' ' format var params = { @@ -126,31 +127,23 @@ function add(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); - assert.strictEqual(typeof type, 'string'); - assert(util.isArray(values)); - assert.strictEqual(typeof callback, 'function'); - - add(dnsConfig, zoneName, subdomain, type, values, callback); -} - -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + getZoneByName(dnsConfig, zoneName, function (error, zone) { if (error) return callback(error); var params = { HostedZoneId: zone.Id, MaxItems: '1', - StartRecordName: (subdomain ? subdomain + '.' : '') + zoneName + '.', + StartRecordName: fqdn + '.', StartRecordType: type }; @@ -169,18 +162,20 @@ function get(dnsConfig, zoneName, subdomain, type, callback) { }); } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName, + fqdn = domains.fqdn(location, domainObject); + getZoneByName(dnsConfig, zoneName, function (error, zone) { if (error) return callback(error); - var fqdn = subdomain === '' ? zoneName : subdomain + '.' + zoneName; var records = values.map(function (v) { return { Value: v }; }); var resourceRecordSet = { @@ -226,13 +221,26 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { }); } -function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof fqdn, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const dnsConfig = domainObject.config, + zoneName = domainObject.zoneName; + if (!dnsConfig.accessKeyId || typeof dnsConfig.accessKeyId !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'accessKeyId must be a non-empty string')); if (!dnsConfig.secretAccessKey || typeof dnsConfig.secretAccessKey !== 'string') return callback(new DomainsError(DomainsError.BAD_FIELD, 'secretAccessKey must be a non-empty string')); @@ -244,6 +252,8 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { listHostedZonesByName: true, // new/updated creds require this perm }; + const ip = '127.0.0.1'; + if (process.env.BOX_ENV === 'test') return callback(null, credentials); // this shouldn't be here dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { @@ -258,14 +268,14 @@ function verifyDnsConfig(dnsConfig, fqdn, zoneName, ip, callback) { return callback(new DomainsError(DomainsError.BAD_FIELD, 'Domain nameservers are not set to Route53')); } - const testSubdomain = 'cloudrontestdns'; + const location = 'cloudrontestdns'; - upsert(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error, changeId) { + upsert(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); - debug('verifyDnsConfig: Test A record added with change id %s', changeId); + debug('verifyDnsConfig: Test A record added'); - del(credentials, zoneName, testSubdomain, 'A', [ ip ], function (error) { + del(domainObject, location, 'A', [ ip ], function (error) { if (error) return callback(error); debug('verifyDnsConfig: Test A record removed again'); diff --git a/src/dns/waitfordns.js b/src/dns/waitfordns.js index b5ee4f613..ef60b15d9 100644 --- a/src/dns/waitfordns.js +++ b/src/dns/waitfordns.js @@ -30,8 +30,8 @@ function resolveIp(hostname, options, callback) { }); } -function isChangeSynced(domain, type, value, nameserver, callback) { - assert.strictEqual(typeof domain, 'string'); +function isChangeSynced(hostname, type, value, nameserver, callback) { + assert.strictEqual(typeof hostname, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof value, 'string'); assert.strictEqual(typeof nameserver, 'string'); @@ -46,16 +46,16 @@ function isChangeSynced(domain, type, value, nameserver, callback) { async.every(nsIps, function (nsIp, iteratorCallback) { const resolveOptions = { server: nsIp, timeout: 5000 }; - const resolver = type === 'A' ? resolveIp.bind(null, domain) : dns.resolve.bind(null, domain, 'TXT'); + const resolver = type === 'A' ? resolveIp.bind(null, hostname) : dns.resolve.bind(null, hostname, 'TXT'); resolver(resolveOptions, function (error, answer) { if (error && error.code === 'TIMEOUT') { - debug(`isChangeSynced: NS ${nameserver} (${nsIp}) timed out when resolving ${domain} (${type})`); + debug(`isChangeSynced: NS ${nameserver} (${nsIp}) timed out when resolving ${hostname} (${type})`); return iteratorCallback(null, true); // should be ok if dns server is down } if (error) { - debug(`isChangeSynced: NS ${nameserver} (${nsIp}) errored when resolve ${domain} (${type}): ${error}`); + debug(`isChangeSynced: NS ${nameserver} (${nsIp}) errored when resolve ${hostname} (${type}): ${error}`); return iteratorCallback(null, false); } @@ -66,7 +66,7 @@ function isChangeSynced(domain, type, value, nameserver, callback) { match = answer.some(function (a) { return value === a.join(''); }); } - debug(`isChangeSynced: ${domain} (${type}) was resolved to ${answer} at NS ${nameserver} (${nsIp}). Expecting ${value}. Match ${match}`); + debug(`isChangeSynced: ${hostname} (${type}) was resolved to ${answer} at NS ${nameserver} (${nsIp}). Expecting ${value}. Match ${match}`); iteratorCallback(null, match); }); @@ -76,26 +76,26 @@ function isChangeSynced(domain, type, value, nameserver, callback) { } // check if IP change has propagated to every nameserver -function waitForDns(domain, zoneName, type, value, options, callback) { - assert.strictEqual(typeof domain, 'string'); +function waitForDns(hostname, zoneName, type, value, options, callback) { + assert.strictEqual(typeof hostname, 'string'); assert.strictEqual(typeof zoneName, 'string'); assert(type === 'A' || type === 'TXT'); assert.strictEqual(typeof value, 'string'); assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); - debug('waitForDns: domain %s to be %s in zone %s.', domain, value, zoneName); + debug('waitForDns: hostname %s to be %s in zone %s.', hostname, value, zoneName); var attempt = 0; async.retry(options, function (retryCallback) { ++attempt; - debug(`waitForDns (try ${attempt}): ${domain} to be ${value} in zone ${zoneName}`); + debug(`waitForDns (try ${attempt}): ${hostname} to be ${value} in zone ${zoneName}`); dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { if (error || !nameservers) return retryCallback(error || new DomainsError(DomainsError.EXTERNAL_ERROR, 'Unable to get nameservers')); - async.every(nameservers, isChangeSynced.bind(null, domain, type, value), function (error, synced) { - debug('waitForDns: %s %s ns: %j', domain, synced ? 'done' : 'not done', nameservers); + async.every(nameservers, isChangeSynced.bind(null, hostname, type, value), function (error, synced) { + debug('waitForDns: %s %s ns: %j', hostname, synced ? 'done' : 'not done', nameservers); retryCallback(synced ? null : new DomainsError(DomainsError.EXTERNAL_ERROR, 'ETRYAGAIN')); }); @@ -103,7 +103,7 @@ function waitForDns(domain, zoneName, type, value, options, callback) { }, function retryDone(error) { if (error) return callback(error); - debug(`waitForDns: ${domain} has propagated`); + debug(`waitForDns: ${hostname} has propagated`); callback(null); }); diff --git a/src/dns/wildcard.js b/src/dns/wildcard.js index 0bc1f74e8..08a4850e2 100644 --- a/src/dns/wildcard.js +++ b/src/dns/wildcard.js @@ -4,44 +4,43 @@ exports = module.exports = { upsert: upsert, get: get, del: del, - waitForDns: require('./waitfordns.js'), + wait: wait, verifyDnsConfig: verifyDnsConfig }; var assert = require('assert'), debug = require('debug')('box:dns/manual'), dns = require('../native-dns.js'), + domains = require('../domains.js'), DomainsError = require('../domains.js').DomainsError, sysinfo = require('../sysinfo.js'), - util = require('util'); + util = require('util'), + waitForDns = require('./waitfordns.js'); -function upsert(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function upsert(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('upsert: %s for zone %s of type %s with values %j', subdomain, zoneName, type, values); + debug('upsert: %s for zone %s of type %s with values %j', location, domainObject.zoneName, type, values); return callback(null); } -function get(dnsConfig, zoneName, subdomain, type, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function get(domainObject, location, type, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); callback(null, [ ]); // returning ip confuses apptask into thinking the entry already exists } -function del(dnsConfig, zoneName, subdomain, type, values, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof subdomain, 'string'); +function del(domainObject, location, type, values, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); @@ -49,20 +48,33 @@ function del(dnsConfig, zoneName, subdomain, type, values, callback) { return callback(); } -function verifyDnsConfig(dnsConfig, domain, zoneName, ip, callback) { - assert.strictEqual(typeof dnsConfig, 'object'); - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof zoneName, 'string'); - assert.strictEqual(typeof ip, 'string'); +function wait(domainObject, location, type, value, options, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof location, 'string'); + assert.strictEqual(typeof type, 'string'); + assert.strictEqual(typeof value, 'string'); + assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); + const fqdn = domains.fqdn(location, domainObject); + + waitForDns(fqdn, domainObject.zoneName, type, value, options, callback); +} + +function verifyDnsConfig(domainObject, callback) { + assert.strictEqual(typeof domainObject, 'object'); + assert.strictEqual(typeof callback, 'function'); + + const zoneName = domainObject.zoneName; + // Very basic check if the nameservers can be fetched dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { if (error && error.code === 'ENOTFOUND') return callback(new DomainsError(DomainsError.BAD_FIELD, 'Unable to resolve nameservers for this domain')); if (error || !nameservers) return callback(new DomainsError(DomainsError.BAD_FIELD, error ? error.message : 'Unable to get nameservers')); - const separator = dnsConfig.hyphenatedSubdomains ? '-' : '.'; - const fqdn = `cloudrontest${separator}${domain}`; + const location = 'cloudrontestdns'; + const fqdn = domains.fqdn(location, domainObject); + dns.resolve(fqdn, 'A', { server: '127.0.0.1', timeout: 5000 }, function (error, result) { if (error && error.code === 'ENOTFOUND') return callback(new DomainsError(DomainsError.BAD_FIELD, `Unable to resolve ${fqdn}`)); if (error || !result) return callback(new DomainsError(DomainsError.BAD_FIELD, error ? error.message : `Unable to resolve ${fqdn}`)); diff --git a/src/domains.js b/src/domains.js index ab459ffc8..ec1c3003c 100644 --- a/src/domains.js +++ b/src/domains.js @@ -10,6 +10,7 @@ module.exports = exports = { isLocked: isLocked, fqdn: fqdn, + getName: getName, getDnsRecords: getDnsRecords, upsertDnsRecords: upsertDnsRecords, @@ -28,10 +29,7 @@ module.exports = exports = { prepareDashboardDomain: prepareDashboardDomain, - DomainsError: DomainsError, - - // exported for testing - _getName: getName + DomainsError: DomainsError }; var assert = require('assert'), @@ -105,18 +103,18 @@ function parentDomain(domain) { return domain.replace(/^\S+?\./, ''); // +? means non-greedy } -function verifyDnsConfig(dnsConfig, domain, zoneName, provider, ip, callback) { +function verifyDnsConfig(dnsConfig, domain, zoneName, provider, callback) { assert(dnsConfig && typeof dnsConfig === 'object'); // the dns config to test with assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof zoneName, 'string'); assert.strictEqual(typeof provider, 'string'); - assert.strictEqual(typeof ip, 'string'); assert.strictEqual(typeof callback, 'function'); var backend = api(provider); if (!backend) return callback(new DomainsError(DomainsError.BAD_FIELD, 'Invalid provider')); - api(provider).verifyDnsConfig(dnsConfig, domain, zoneName, ip, function (error, result) { + const domainObject = { config: dnsConfig, domain: domain, zoneName: zoneName }; + api(provider).verifyDnsConfig(domainObject, function (error, result) { if (error && error.reason === DomainsError.ACCESS_DENIED) return callback(new DomainsError(DomainsError.BAD_FIELD, 'Incorrect configuration. Access denied')); if (error && error.reason === DomainsError.NOT_FOUND) return callback(new DomainsError(DomainsError.BAD_FIELD, 'Zone not found')); if (error && error.reason === DomainsError.EXTERNAL_ERROR) return callback(new DomainsError(DomainsError.BAD_FIELD, 'Configuration error: ' + error.message)); @@ -130,12 +128,8 @@ function verifyDnsConfig(dnsConfig, domain, zoneName, provider, ip, callback) { }); } -function fqdn(location, domain, dnsConfig) { - assert.strictEqual(typeof location, 'string'); - assert.strictEqual(typeof domain, 'string'); - assert.strictEqual(typeof dnsConfig, 'object'); - - return location + (location ? (dnsConfig.hyphenatedSubdomains ? '-' : '.') : '') + domain; +function fqdn(location, domainObject) { + return location + (location ? (domainObject.config.hyphenatedSubdomains ? '-' : '.') : '') + domainObject.domain; } // Hostname validation comes from RFC 1123 (section 2.1) @@ -146,7 +140,7 @@ function validateHostname(location, domainObject) { assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domainObject, 'object'); - const hostname = fqdn(location, domainObject.domain, domainObject.config); + const hostname = fqdn(location, domainObject); const RESERVED_LOCATIONS = [ constants.API_LOCATION, @@ -231,23 +225,19 @@ function add(domain, data, auditSource, callback) { let error = validateTlsConfig(tlsConfig, provider); if (error) return callback(error); - sysinfo.getPublicIp(function (error, ip) { - if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, 'Error getting IP:' + error.message)); + verifyDnsConfig(config, domain, zoneName, provider, function (error, sanitizedConfig) { + if (error) return callback(error); - verifyDnsConfig(config, domain, zoneName, provider, ip, function (error, sanitizedConfig) { - if (error) return callback(error); + domaindb.add(domain, { zoneName: zoneName, provider: provider, config: sanitizedConfig, tlsConfig: tlsConfig }, function (error) { + if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new DomainsError(DomainsError.ALREADY_EXISTS)); + if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - domaindb.add(domain, { zoneName: zoneName, provider: provider, config: sanitizedConfig, tlsConfig: tlsConfig }, function (error) { - if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new DomainsError(DomainsError.ALREADY_EXISTS)); + reverseProxy.setFallbackCertificate(domain, fallbackCertificate, function (error) { if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - reverseProxy.setFallbackCertificate(domain, fallbackCertificate, function (error) { - if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); + eventlog.add(eventlog.ACTION_DOMAIN_ADD, auditSource, { domain, zoneName, provider }); - eventlog.add(eventlog.ACTION_DOMAIN_ADD, auditSource, { domain, zoneName, provider }); - - callback(); - }); + callback(); }); }); }); @@ -325,25 +315,21 @@ function update(domain, data, auditSource, callback) { error = validateTlsConfig(tlsConfig, provider); if (error) return callback(error); - sysinfo.getPublicIp(function (error, ip) { - if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, 'Error getting IP:' + error.message)); + verifyDnsConfig(config, domain, zoneName, provider, function (error, sanitizedConfig) { + if (error) return callback(error); - verifyDnsConfig(config, domain, zoneName, provider, ip, function (error, sanitizedConfig) { - if (error) return callback(error); + domaindb.update(domain, { zoneName: zoneName, provider: provider, config: sanitizedConfig, tlsConfig: tlsConfig }, function (error) { + if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new DomainsError(DomainsError.NOT_FOUND)); + if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - domaindb.update(domain, { zoneName: zoneName, provider: provider, config: sanitizedConfig, tlsConfig: tlsConfig }, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new DomainsError(DomainsError.NOT_FOUND)); + if (!fallbackCertificate) return callback(); + + reverseProxy.setFallbackCertificate(domain, fallbackCertificate, function (error) { if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - if (!fallbackCertificate) return callback(); + eventlog.add(eventlog.ACTION_DOMAIN_UPDATE, auditSource, { domain, zoneName, provider }); - reverseProxy.setFallbackCertificate(domain, fallbackCertificate, function (error) { - if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - - eventlog.add(eventlog.ACTION_DOMAIN_UPDATE, auditSource, { domain, zoneName, provider }); - - callback(); - }); + callback(); }); }); }); @@ -379,39 +365,36 @@ function clear(callback) { } // returns the 'name' that needs to be inserted into zone -function getName(domain, subdomain, type) { - // hack for supporting special caas domains. if we want to remove this, we have to fix the appstore domain API first - if (domain.provider === 'caas') return subdomain; - +function getName(domain, location, type) { const part = domain.domain.slice(0, -domain.zoneName.length - 1); - if (subdomain === '') return part; + if (location === '') return part; - if (!domain.config.hyphenatedSubdomains) return part ? `${subdomain}.${part}` : subdomain; + if (!domain.config.hyphenatedSubdomains) return part ? `${location}.${part}` : location; // hyphenatedSubdomains - if (type !== 'TXT') return `${subdomain}-${part}`; + if (type !== 'TXT') return `${location}-${part}`; - if (subdomain.startsWith('_acme-challenge.')) { - return `${subdomain}-${part}`; - } else if (subdomain === '_acme-challenge') { + if (location.startsWith('_acme-challenge.')) { + return `${location}-${part}`; + } else if (location === '_acme-challenge') { const up = part.replace(/^[^.]*\.?/, ''); // this gets the domain one level up - return up ? `${subdomain}.${up}` : subdomain; + return up ? `${location}.${up}` : location; } else { - return `${subdomain}.${part}`; + return `${location}.${part}`; } } -function getDnsRecords(subdomain, domain, type, callback) { - assert.strictEqual(typeof subdomain, 'string'); +function getDnsRecords(location, domain, type, callback) { + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof type, 'string'); assert.strictEqual(typeof callback, 'function'); - get(domain, function (error, result) { + get(domain, function (error, domainObject) { if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - api(result.provider).get(result.config, result.zoneName, getName(result, subdomain, type), type, function (error, values) { + api(domainObject.provider).get(domainObject, location, type, function (error, values) { if (error) return callback(error); callback(null, values); @@ -420,19 +403,19 @@ function getDnsRecords(subdomain, domain, type, callback) { } // note: for TXT records the values must be quoted -function upsertDnsRecords(subdomain, domain, type, values, callback) { - assert.strictEqual(typeof subdomain, 'string'); +function upsertDnsRecords(location, domain, type, values, callback) { + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('upsertDNSRecord: %s on %s type %s values', subdomain, domain, type, values); + debug('upsertDNSRecord: %s on %s type %s values', location, domain, type, values); - get(domain, function (error, result) { + get(domain, function (error, domainObject) { if (error) return callback(new DomainsError(DomainsError.INTERNAL_ERROR, error)); - api(result.provider).upsert(result.config, result.zoneName, getName(result, subdomain, type), type, values, function (error) { + api(domainObject.provider).upsert(domainObject, location, type, values, function (error) { if (error) return callback(error); callback(null); @@ -440,19 +423,19 @@ function upsertDnsRecords(subdomain, domain, type, values, callback) { }); } -function removeDnsRecords(subdomain, domain, type, values, callback) { - assert.strictEqual(typeof subdomain, 'string'); +function removeDnsRecords(location, domain, type, values, callback) { + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof type, 'string'); assert(util.isArray(values)); assert.strictEqual(typeof callback, 'function'); - debug('removeDNSRecord: %s on %s type %s values', subdomain, domain, type, values); + debug('removeDNSRecord: %s on %s type %s values', location, domain, type, values); - get(domain, function (error, result) { + get(domain, function (error, domainObject) { if (error) return callback(error); - api(result.provider).del(result.config, result.zoneName, getName(result, subdomain, type), type, values, function (error) { + api(domainObject.provider).del(domainObject, location, type, values, function (error) { if (error && error.reason !== DomainsError.NOT_FOUND) return callback(error); callback(null); @@ -460,8 +443,8 @@ function removeDnsRecords(subdomain, domain, type, values, callback) { }); } -function waitForDnsRecord(subdomain, domain, type, value, options, callback) { - assert.strictEqual(typeof subdomain, 'string'); +function waitForDnsRecord(location, domain, type, value, options, callback) { + assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); assert(type === 'A' || type === 'TXT'); assert.strictEqual(typeof value, 'string'); @@ -471,9 +454,7 @@ function waitForDnsRecord(subdomain, domain, type, value, options, callback) { get(domain, function (error, domainObject) { if (error) return callback(error); - const hostname = fqdn(subdomain, domainObject.domain, domainObject.config); - - api(domainObject.provider).waitForDns(hostname, domainObject.zoneName, type, value, options, callback); + api(domainObject.provider).wait(domainObject, location, type, value, options, callback); }); } @@ -520,7 +501,7 @@ function prepareDashboardDomain(domain, auditSource, progressCallback, callback) (done) => { progressCallback({ percent: 40, message: 'Waiting for DNS' }); done(); }, waitForDnsRecord.bind(null, constants.ADMIN_LOCATION, domain, 'A', ip, { interval: 30000, times: 50000 }), (done) => { progressCallback({ percent: 70, message: 'Getting certificate' }); done(); }, - reverseProxy.ensureCertificate.bind(null, fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config), domain, auditSource) + reverseProxy.ensureCertificate.bind(null, fqdn(constants.ADMIN_LOCATION, domainObject), domain, auditSource) ], function (error) { if (error) return callback(error); @@ -528,4 +509,4 @@ function prepareDashboardDomain(domain, auditSource, progressCallback, callback) }); }); }); -} +} \ No newline at end of file diff --git a/src/reverseproxy.js b/src/reverseproxy.js index b533bcf44..6895fb204 100644 --- a/src/reverseproxy.js +++ b/src/reverseproxy.js @@ -168,7 +168,7 @@ function validateCertificate(location, domainObject, certificate) { if (cert && !key) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'missing key'); // -checkhost checks for SAN or CN exclusively. SAN takes precedence and if present, ignores the CN. - const fqdn = domains.fqdn(location, domainObject.domain, domainObject.config); + const fqdn = domains.fqdn(location, domainObject); var result = safe.child_process.execSync(`openssl x509 -noout -checkhost "${fqdn}"`, { encoding: 'utf8', input: cert }); if (result === null) return new ReverseProxyError(ReverseProxyError.INVALID_CERT, 'Unable to get certificate subject:' + safe.error.message); @@ -278,7 +278,7 @@ function setAppCertificateSync(location, domainObject, certificate) { assert.strictEqual(typeof domainObject, 'object'); assert.strictEqual(typeof certificate, 'object'); - let fqdn = domains.fqdn(location, domainObject.domain, domainObject.config); + let fqdn = domains.fqdn(location, domainObject); if (certificate.cert && certificate.key) { if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${fqdn}.user.cert`), certificate.cert)) return safe.error; if (!safe.fs.writeFileSync(path.join(paths.APP_CERTS_DIR, `${fqdn}.user.key`), certificate.key)) return safe.error; @@ -412,7 +412,7 @@ function configureAdmin(domain, auditSource, callback) { domains.get(domain, function (error, domainObject) { if (error) return callback(error); - const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config); + const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); ensureCertificate(adminFqdn, domainObject.domain, auditSource, function (error, bundle) { if (error) return callback(error); @@ -429,7 +429,7 @@ function writeAdminConfig(domain, callback) { domains.get(domain, function (error, domainObject) { if (error) return callback(error); - const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject.domain, domainObject.config); + const adminFqdn = domains.fqdn(constants.ADMIN_LOCATION, domainObject); getCertificate(adminFqdn, domainObject.domain, function (error, bundle) { if (error) return callback(error); diff --git a/src/test/reverseproxy-test.js b/src/test/reverseproxy-test.js index 9e1a8f858..4aa711fda 100644 --- a/src/test/reverseproxy-test.js +++ b/src/test/reverseproxy-test.js @@ -90,7 +90,7 @@ describe('Certificates', function () { }); it('does not allow cert without matching domain', function () { - expect(reverseProxy.validateCertificate('', { domain: 'cloudron.io', config: {} }, { cert: validCert0, key: validKey0 })).to.be.an(Error); + expect(reverseProxy.validateCertificate('', { domain: 'cloudron.io' }, { cert: validCert0, key: validKey0 })).to.be.an(Error); expect(reverseProxy.validateCertificate('cloudron.io', foobarDomain, { cert: validCert0, key: validKey0 })).to.be.an(Error); });