| 
									
										
										
										
											2016-10-17 17:40:55 -06:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 15:26:19 -06:00
										 |  |  | module.exports.create = function (deps, conf) { | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |   var dns = deps.PromiseA.promisifyAll(require('dns')); | 
					
						
							| 
									
										
										
										
											2017-10-02 15:37:58 -06:00
										 |  |  |   var network = deps.PromiseA.promisifyAll(deps.recase.camelCopy(require('network'))); | 
					
						
							| 
									
										
										
										
											2017-09-25 18:06:48 -06:00
										 |  |  |   var loopback = require('./loopback').create(deps, conf); | 
					
						
							| 
									
										
										
										
											2017-09-27 10:54:35 -06:00
										 |  |  |   var dnsCtrl = require('./dns-ctrl').create(deps, conf); | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |   var equal = require('deep-equal'); | 
					
						
							| 
									
										
										
										
											2016-10-17 17:40:55 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-18 13:48:08 -06:00
										 |  |  |   var loopbackDomain; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 15:38:10 -06:00
										 |  |  |   function iterateAllModules(action, curConf) { | 
					
						
							|  |  |  |     curConf = curConf || conf; | 
					
						
							|  |  |  |     var promises = curConf.ddns.modules.map(function (mod) { | 
					
						
							| 
									
										
										
										
											2017-10-19 12:37:08 -06:00
										 |  |  |       return action(mod, mod.domains); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 15:38:10 -06:00
										 |  |  |     curConf.domains.forEach(function (dom) { | 
					
						
							| 
									
										
										
										
											2017-10-19 12:37:08 -06:00
										 |  |  |       if (!dom.modules || !Array.isArray(dom.modules.ddns) || !dom.modules.ddns.length) { | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // For the time being all of our things should only be tried once (regardless if it succeeded)
 | 
					
						
							|  |  |  |       // TODO: revisit this behavior when we support multiple ways of setting records, and/or
 | 
					
						
							|  |  |  |       // if we want to allow later modules to run if early modules fail.
 | 
					
						
							|  |  |  |       promises.push(dom.modules.ddns.reduce(function (prom, mod) { | 
					
						
							|  |  |  |         if (prom) { return prom; } | 
					
						
							|  |  |  |         return action(mod, dom.names); | 
					
						
							|  |  |  |       }, null)); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return deps.PromiseA.all(promises.filter(Boolean)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 12:58:04 -06:00
										 |  |  |   async function getSession(id) { | 
					
						
							|  |  |  |     var session = await deps.storage.tokens.get(id); | 
					
						
							|  |  |  |     if (!session) { | 
					
						
							|  |  |  |       throw new Error('no user token with ID "'+id+'"'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return session; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |   var tunnelActive = false; | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |   async function startTunnel(tunnelSession, mod, domainList) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       var dnsSession = await getSession(mod.tokenId); | 
					
						
							|  |  |  |       var tunnelDomain = await deps.tunnelClients.start(tunnelSession || dnsSession, domainList); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var addrList; | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         addrList = await dns.resolve4Async(tunnelDomain); | 
					
						
							|  |  |  |       } catch (e) {} | 
					
						
							|  |  |  |       if (!addrList || !addrList.length) { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           addrList = await dns.resolve6Async(tunnelDomain); | 
					
						
							|  |  |  |         } catch (e) {} | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!addrList || !addrList.length || !addrList[0]) { | 
					
						
							|  |  |  |         throw new Error('failed to lookup IP for tunnel domain "' + tunnelDomain + '"'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       await dnsCtrl.setDeviceAddress(dnsSession, addrList[0], domainList); | 
					
						
							|  |  |  |     } catch (err) { | 
					
						
							|  |  |  |       console.log('error starting tunnel for', domainList.join(', ')); | 
					
						
							|  |  |  |       console.log(err); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   async function connectAllTunnels() { | 
					
						
							| 
									
										
										
										
											2017-10-19 12:58:04 -06:00
										 |  |  |     var tunnelSession; | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  |     if (conf.ddns.tunnel) { | 
					
						
							| 
									
										
										
										
											2017-10-19 12:58:04 -06:00
										 |  |  |       // In the case of a non-existant token, I'm not sure if we want to throw here and prevent
 | 
					
						
							|  |  |  |       // any tunnel connections, or if we  want to ignore it and fall back to the DNS tokens
 | 
					
						
							|  |  |  |       tunnelSession = await deps.storage.tokens.get(conf.ddns.tunnel.tokenId); | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |     await iterateAllModules(function (mod, domainList) { | 
					
						
							| 
									
										
										
										
											2017-10-19 12:37:08 -06:00
										 |  |  |       if (mod.type !== 'dns@oauth3.org') { return null; } | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |       return startTunnel(tunnelSession, mod, domainList); | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-19 12:37:08 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  |     tunnelActive = true; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |   async function disconnectTunnels() { | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  |     deps.tunnelClients.disconnect(); | 
					
						
							|  |  |  |     tunnelActive = false; | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |     await Promise.resolve(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   async function checkTunnelTokens() { | 
					
						
							|  |  |  |     var oldTokens = deps.tunnelClients.current(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var newTokens = await iterateAllModules(function checkTokens(mod, domainList) { | 
					
						
							|  |  |  |       if (mod.type !== 'dns@oauth3.org') { return null; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var domainStr = domainList.slice().sort().join(','); | 
					
						
							|  |  |  |       // If there is already a token handling exactly the domains this modules
 | 
					
						
							|  |  |  |       // needs handled remove it from the list of tokens to be removed. Otherwise
 | 
					
						
							|  |  |  |       // return the module and domain list so we can get new tokens.
 | 
					
						
							|  |  |  |       if (oldTokens[domainStr]) { | 
					
						
							|  |  |  |         delete oldTokens[domainStr]; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         return Promise.resolve({ mod, domainList }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     await Promise.all(Object.values(oldTokens).map(deps.tunnelClients.remove)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!newTokens.length) { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var tunnelSession; | 
					
						
							|  |  |  |     if (conf.ddns.tunnel) { | 
					
						
							|  |  |  |       // In the case of a non-existant token, I'm not sure if we want to throw here and prevent
 | 
					
						
							|  |  |  |       // any tunnel connections, or if we  want to ignore it and fall back to the DNS tokens
 | 
					
						
							|  |  |  |       tunnelSession = await deps.storage.tokens.get(conf.ddns.tunnel.tokenId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |     await Promise.all(newTokens.map(function ({mod, domainList}) { | 
					
						
							|  |  |  |       return startTunnel(tunnelSession, mod, domainList); | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |     })); | 
					
						
							| 
									
										
										
										
											2017-10-18 15:37:35 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var localAddr, gateway; | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |   async function checkNetworkEnv() { | 
					
						
							|  |  |  |     // Since we can't detect the OS level events when a user plugs in an ethernet cable to recheck
 | 
					
						
							|  |  |  |     // what network environment we are in we check our local network address and the gateway to
 | 
					
						
							|  |  |  |     // determine if we need to run the loopback check and router configuration again.
 | 
					
						
							|  |  |  |     var addr = await network.getPrivateIpAsync(); | 
					
						
							| 
									
										
										
										
											2017-11-03 15:16:30 -06:00
										 |  |  |     // Until the author of the `network` package publishes the pull request we gave him
 | 
					
						
							|  |  |  |     // checking the gateway on our units fails because we have the busybox versions of
 | 
					
						
							|  |  |  |     // the linux commands. Gateway is realistically less important than address, so if
 | 
					
						
							|  |  |  |     // we fail in getting it go ahead and use the null value.
 | 
					
						
							|  |  |  |     var gw; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       gw = await network.getGatewayIpAsync(); | 
					
						
							|  |  |  |     } catch (err) { | 
					
						
							|  |  |  |       gw = null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |     if (localAddr === addr && gateway === gw) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-18 13:48:08 -06:00
										 |  |  |     var loopResult = await loopback(loopbackDomain); | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |     var notLooped = Object.keys(loopResult.ports).filter(function (port) { | 
					
						
							|  |  |  |       return !loopResult.ports[port]; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |     // if (notLooped.length) {
 | 
					
						
							|  |  |  |     //   // TODO: try to automatically configure router to forward ports to us.
 | 
					
						
							|  |  |  |     // }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 12:37:08 -06:00
										 |  |  |     // If we are on a public address or all ports we are listening on are forwarded to us then
 | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |     // we don't need the tunnel and we can set the DNS records for all our domains to our public
 | 
					
						
							| 
									
										
										
										
											2017-11-01 11:40:56 -06:00
										 |  |  |     // address. Otherwise we need to use the tunnel to accept traffic. Also since the tunnel will
 | 
					
						
							|  |  |  |     // only be listening on ports 80 and 443 if those are forwarded to us we don't want the tunnel.
 | 
					
						
							|  |  |  |     if (!notLooped.length || (loopResult.ports['80'] && loopResult.ports['443'])) { | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |       if (tunnelActive) { | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |         await disconnectTunnels(); | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       if (!tunnelActive) { | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |         await connectAllTunnels(); | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-27 13:49:37 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Don't assign these until the end of the function. This means that if something failed
 | 
					
						
							|  |  |  |     // in the loopback or tunnel connection that we will try to go through the whole process
 | 
					
						
							|  |  |  |     // again next time and hopefully the error is temporary (but if not I'm not sure what the
 | 
					
						
							|  |  |  |     // correct course of action would be anyway).
 | 
					
						
							|  |  |  |     localAddr = addr; | 
					
						
							|  |  |  |     gateway = gw; | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 15:26:19 -06:00
										 |  |  |   var publicAddress; | 
					
						
							| 
									
										
										
										
											2017-09-19 13:18:22 -06:00
										 |  |  |   async function recheckPubAddr() { | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |     await checkNetworkEnv(); | 
					
						
							| 
									
										
										
										
											2017-09-28 11:18:44 -06:00
										 |  |  |     if (tunnelActive) { | 
					
						
							| 
									
										
										
										
											2017-09-27 14:53:18 -06:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-10-17 17:40:55 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-18 16:06:44 -06:00
										 |  |  |     var addr = await loopback.checkPublicAddr(loopbackDomain); | 
					
						
							| 
									
										
										
										
											2017-09-19 13:18:22 -06:00
										 |  |  |     if (publicAddress === addr) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (conf.debug) { | 
					
						
							|  |  |  |       console.log('previous public address',publicAddress, 'does not match current public address', addr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     publicAddress = addr; | 
					
						
							| 
									
										
										
										
											2017-10-18 16:06:44 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |     await iterateAllModules(function setModuleDNS(mod, domainList) { | 
					
						
							| 
									
										
										
										
											2017-10-19 12:37:08 -06:00
										 |  |  |       if (mod.type !== 'dns@oauth3.org' || mod.disabled) { return null; } | 
					
						
							| 
									
										
										
										
											2017-10-18 16:06:44 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |       return getSession(mod.tokenId).then(function (session) { | 
					
						
							|  |  |  |         return dnsCtrl.setDeviceAddress(session, addr, domainList); | 
					
						
							| 
									
										
										
										
											2017-10-18 16:06:44 -06:00
										 |  |  |       }).catch(function (err) { | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |         console.log('error setting DNS records for', domainList.join(', ')); | 
					
						
							| 
									
										
										
										
											2017-10-18 16:06:44 -06:00
										 |  |  |         console.log(err); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-09-14 15:26:19 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-17 17:40:55 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 15:38:10 -06:00
										 |  |  |   function getModuleDiffs(prevConf) { | 
					
						
							|  |  |  |     var prevMods = {}; | 
					
						
							|  |  |  |     var curMods = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // this returns a Promise, but since the functions we use are synchronous
 | 
					
						
							|  |  |  |     // and change our enclosed variables we don't need to wait for the return.
 | 
					
						
							|  |  |  |     iterateAllModules(function (mod, domainList) { | 
					
						
							|  |  |  |       if (mod.type !== 'dns@oauth3.org') { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       prevMods[mod.id] = { mod, domainList }; | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     }, prevConf); | 
					
						
							|  |  |  |     iterateAllModules(function (mod, domainList) { | 
					
						
							|  |  |  |       if (mod.type !== 'dns@oauth3.org') { return; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       curMods[mod.id] = { mod, domainList }; | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Filter out all of the modules that are exactly the same including domainList
 | 
					
						
							|  |  |  |     // since there is no required action to transition.
 | 
					
						
							|  |  |  |     Object.keys(prevMods).map(function (id) { | 
					
						
							|  |  |  |       if (equal(prevMods[id], curMods[id])) { | 
					
						
							|  |  |  |         delete prevMods[id]; | 
					
						
							|  |  |  |         delete curMods[id]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return {prevMods, curMods}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   async function cleanOldDns(prevConf) { | 
					
						
							|  |  |  |     var {prevMods, curMods} = getModuleDiffs(prevConf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Then remove DNS records for the domains that we are no longer responsible for.
 | 
					
						
							|  |  |  |     await Promise.all(Object.values(prevMods).map(function ({mod, domainList}) { | 
					
						
							|  |  |  |       var oldDomains; | 
					
						
							|  |  |  |       if (!curMods[mod.id] || mod.tokenId !== curMods[mod.id].mod.tokenId) { | 
					
						
							|  |  |  |         oldDomains = domainList.slice(); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         oldDomains = domainList.filter(function (domain) { | 
					
						
							|  |  |  |           return curMods[mod.id].domainList.indexOf(domain) < 0; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (conf.debug) { | 
					
						
							|  |  |  |         console.log('removing old domains for module', mod.id, oldDomains.join(', ')); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!oldDomains.length) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return getSession(mod.tokenId).then(function (session) { | 
					
						
							|  |  |  |         return dnsCtrl.removeDomains(session, oldDomains); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }).filter(Boolean)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   async function setNewDns(prevConf) { | 
					
						
							|  |  |  |     var {prevMods, curMods} = getModuleDiffs(prevConf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // And add DNS records for any newly added domains.
 | 
					
						
							|  |  |  |     await Promise.all(Object.values(curMods).map(function ({mod, domainList}) { | 
					
						
							|  |  |  |       var newDomains; | 
					
						
							|  |  |  |       if (!prevMods[mod.id] || mod.tokenId !== prevMods[mod.id].mod.tokenId) { | 
					
						
							|  |  |  |         newDomains = domainList.slice(); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         newDomains = domainList.filter(function (domain) { | 
					
						
							|  |  |  |           return prevMods[mod.id].domainList.indexOf(domain) < 0; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (conf.debug) { | 
					
						
							|  |  |  |         console.log('adding new domains for module', mod.id, newDomains.join(', ')); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!newDomains.length) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return getSession(mod.tokenId).then(function (session) { | 
					
						
							|  |  |  |         return dnsCtrl.setDeviceAddress(session, publicAddress, newDomains); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }).filter(Boolean)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-25 11:00:06 -06:00
										 |  |  |   function check() { | 
					
						
							|  |  |  |     recheckPubAddr().catch(function (err) { | 
					
						
							|  |  |  |       console.error('failed to handle all actions needed for DDNS'); | 
					
						
							|  |  |  |       console.error(err); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   check(); | 
					
						
							|  |  |  |   setInterval(check, 5*60*1000); | 
					
						
							| 
									
										
										
										
											2016-10-17 17:40:55 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |   var curConf; | 
					
						
							|  |  |  |   function updateConf() { | 
					
						
							|  |  |  |     if (curConf && equal(curConf.ddns, conf.ddns) && equal(curConf.domains, conf.domains)) { | 
					
						
							|  |  |  |       // We could update curConf, but since everything we care about is the same...
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!curConf || !equal(curConf.ddns.loopback, conf.ddns.loopback)) { | 
					
						
							|  |  |  |       loopbackDomain = 'oauth3.org'; | 
					
						
							|  |  |  |       if (conf.ddns && conf.ddns.loopback) { | 
					
						
							|  |  |  |         if (conf.ddns.loopback.type === 'tunnel@oauth3.org' && conf.ddns.loopback.domain) { | 
					
						
							|  |  |  |           loopbackDomain = conf.ddns.loopback.domain; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           console.error('invalid loopback configuration: bad type or missing domain'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 15:38:10 -06:00
										 |  |  |     if (!curConf) { | 
					
						
							|  |  |  |       // We need to make a deep copy of the config so we can use it next time to
 | 
					
						
							|  |  |  |       // compare and see what setup/cleanup is needed to adapt to the changes.
 | 
					
						
							|  |  |  |       curConf = JSON.parse(JSON.stringify(conf)); | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-20 15:38:10 -06:00
										 |  |  |     cleanOldDns(curConf).then(function () { | 
					
						
							|  |  |  |       if (!tunnelActive) { | 
					
						
							|  |  |  |         return setNewDns(curConf); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (equal(curConf.ddns.tunnel, conf.ddns.tunnel)) { | 
					
						
							|  |  |  |         return checkTunnelTokens(); | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2017-10-20 18:02:55 -06:00
										 |  |  |         return disconnectTunnels().then(connectAllTunnels); | 
					
						
							| 
									
										
										
										
											2017-10-20 15:38:10 -06:00
										 |  |  |       } | 
					
						
							|  |  |  |     }).catch(function (err) { | 
					
						
							|  |  |  |       console.error('error transitioning DNS between configurations'); | 
					
						
							|  |  |  |       console.error(err); | 
					
						
							|  |  |  |     }).then(function () { | 
					
						
							|  |  |  |       // We need to make a deep copy of the config so we can use it next time to
 | 
					
						
							|  |  |  |       // compare and see what setup/cleanup is needed to adapt to the changes.
 | 
					
						
							|  |  |  |       curConf = JSON.parse(JSON.stringify(conf)); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-10-19 17:45:05 -06:00
										 |  |  |   } | 
					
						
							|  |  |  |   updateConf(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 15:26:19 -06:00
										 |  |  |   return { | 
					
						
							| 
									
										
										
										
											2017-09-25 18:06:48 -06:00
										 |  |  |     loopbackServer:     loopback.server | 
					
						
							| 
									
										
										
										
											2017-09-27 10:54:35 -06:00
										 |  |  |   , setDeviceAddress:   dnsCtrl.setDeviceAddress | 
					
						
							|  |  |  |   , getDeviceAddresses: dnsCtrl.getDeviceAddresses | 
					
						
							| 
									
										
										
										
											2017-09-14 15:26:19 -06:00
										 |  |  |   , recheckPubAddr:     recheckPubAddr | 
					
						
							| 
									
										
										
										
											2017-10-18 13:48:08 -06:00
										 |  |  |   , updateConf:         updateConf | 
					
						
							| 
									
										
										
										
											2016-10-17 17:40:55 -06:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-09-14 15:26:19 -06:00
										 |  |  | }; |