From 9e9b5ca9ad055ba1c16aad0381991bdd7ae91c43 Mon Sep 17 00:00:00 2001 From: tigerbot Date: Fri, 29 Sep 2017 15:29:47 -0600 Subject: [PATCH] update DDNS to also use the specified list of domains --- lib/ddns/dns-ctrl.js | 90 +++++++++++++++++++++++++++++++++++++------- lib/ddns/index.js | 2 +- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/lib/ddns/dns-ctrl.js b/lib/ddns/dns-ctrl.js index 500e590..ed290ac 100644 --- a/lib/ddns/dns-ctrl.js +++ b/lib/ddns/dns-ctrl.js @@ -10,7 +10,63 @@ module.exports.create = function (deps, conf) { } } - async function setDeviceAddress(session, addr) { + var tldCache = {}; + async function getTlds(provider) { + async function updateCache() { + var reqObj = { + url: deps.OAUTH3.url.normalize(provider)+'/api/com.daplie.domains/prices' + , method: 'GET' + , json: true + }; + + var resp = await deps.OAUTH3.request(reqObj); + var tldObj = {}; + resp.data.forEach(function (tldInfo) { + if (tldInfo.enabled) { + tldObj[tldInfo.com] = true; + } + }); + + tldCache[provider] = { + time: Date.now() + , tlds: tldObj + }; + return tldObj; + } + + // If we've never cached the results we need to return the promise that will fetch the recult, + // otherwise we can return the cached value. If the cached value has "expired", we can still + // return the cached value we just want to update the cache in parellel (making sure we only + // update once). + if (!tldCache[provider]) { + return updateCache(); + } + if (!tldCache[provider].updating && Date.now() - tldCache[provider].time > 24*60*60*1000) { + tldCache[provider].updating = true; + updateCache(); + } + + return tldCache[provider].tlds; + } + + async function splitDomains(provider, domains) { + var tlds = await getTlds(provider); + return domains.map(function (domain) { + var split = domain.split('.'); + var tldSegCnt = tlds[split.slice(-2).join('.')] ? 2 : 1; + + // Currently assuming that the sld can't contain dots, and that the tld can have at + // most one dot. Not 100% sure this is a valid assumption, but exceptions should be + // rare even if the assumption isn't valid. + return { + tld: split.slice(-tldSegCnt).join('.') + , sld: split.slice(-tldSegCnt-1, 1) + , sub: split.slice(0, -tldSegCnt-1) + }; + }); + } + + async function setDeviceAddress(session, addr, domains) { var directives = await deps.OAUTH3.discover(session.token.aud); // Set the address of the device to our public address. @@ -31,27 +87,33 @@ module.exports.create = function (deps, conf) { // Then update all of the records attached to our hostname, first removing the old records // to remove the reference to the old address, then creating new records for the same domains // using our new address. - var allDns = deps.OAUTH3.api(directives.api, {session: session, api: 'dns.list'}); - var ourDomains = allDns.filter(function (record) { - return record.device === conf.device.hostname; - }).map(function (record) { - var zoneSplit = record.zone.split('.'); - return { - tld: zoneSplit.slice(1).join('.') - , sld: zoneSplit[0] - , sub: record.host.slice(0, -(record.zone.length + 1)) - }; + var allDns = await deps.OAUTH3.api(directives.api, {session: session, api: 'dns.list'}); + var ourDns = allDns.filter(function (record) { + if (record.device !== conf.device.hostname) { + return false; + } + if ([ 'A', 'AAAA' ].indexOf(record.type) < 0) { + return false; + } + return domains.indexOf(record.host) !== -1; }); + var oldDomains = ourDns.filter(function (record) { + return record.value !== addr; + }).map(function (record) { + return record.host; + }); + var oldDns = await splitDomains(directives.api, oldDomains); var common = { api: 'devices.detach' , session: session , device: conf.device.hostname }; - await deps.PromiseA.all(ourDomains.map(function (record) { + await deps.PromiseA.all(oldDns.map(function (record) { return deps.OAUTH3.api(directives.api, Object.assign({}, common, record)); })); + var newDns = await splitDomains(directives.api, domains); common = { api: 'devices.attach' , session: session @@ -59,7 +121,7 @@ module.exports.create = function (deps, conf) { , ip: addr , ttl: 300 }; - await deps.PromiseA.all(ourDomains.map(function (record) { + await deps.PromiseA.all(newDns.map(function (record) { return deps.OAUTH3.api(directives.api, Object.assign({}, common, record)); })); } @@ -93,5 +155,5 @@ module.exports.create = function (deps, conf) { return { getDeviceAddresses: getDeviceAddresses , setDeviceAddress: setDeviceAddress -, }; + }; }; diff --git a/lib/ddns/index.js b/lib/ddns/index.js index e63f131..8221306 100644 --- a/lib/ddns/index.js +++ b/lib/ddns/index.js @@ -85,7 +85,7 @@ module.exports.create = function (deps, conf) { console.log('previous public address',publicAddress, 'does not match current public address', addr); } - await dnsCtrl.setDeviceAddress(session, addr); + await dnsCtrl.setDeviceAddress(session, addr, conf.ddns.domains); publicAddress = addr; }