diff --git a/lib/ddns/index.js b/lib/ddns/index.js index 5163ef6..5c71a78 100644 --- a/lib/ddns/index.js +++ b/lib/ddns/index.js @@ -1,9 +1,41 @@ 'use strict'; module.exports.create = function (deps, conf) { + var network = deps.PromiseA.promisify(deps.recase.camelCopy(require('network'))); var loopback = require('./loopback').create(deps, conf); var dnsCtrl = require('./dns-ctrl').create(deps, conf); + var localAddr, gateway, accessible; + 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 gw = await network.getGatewayIpAsync(); + var addr = await network.getPrivateIpAsync(); + if (localAddr === addr && gateway === gw) { + return; + } + + localAddr = addr; + gateway = gw; + var loopResult = await loopback('seth.daplie.me'); + var notLooped = Object.keys(loopResult.ports).filter(function (port) { + return !loopResult.ports[port]; + }); + + // All ports come back to us, so we are either a public address or the router has already + // been configured to forward these ports to us, so no configuration needs to be done we + // just have to make sure the DNS records stay in sync with our public address. + if (!notLooped.length) { + accessible = true; + return; + } + + // TODO: try to automatically configure router to forward ports to us. + accessible = false; + // TODO: move tunnel client here as fall back. + } + async function getSession() { var sessions = await deps.storage.owners.all(); var session = sessions.filter(function (sess) { @@ -28,6 +60,10 @@ module.exports.create = function (deps, conf) { return; } + await checkNetworkEnv(); + if (!accessible) { + return; + } var session = await getSession(); var directives = await deps.OAUTH3.discover(session.token.aud); var addr = await loopback.checkPublicAddr(directives.api); diff --git a/lib/ddns/loopback.js b/lib/ddns/loopback.js index 2f7772d..c35c742 100644 --- a/lib/ddns/loopback.js +++ b/lib/ddns/loopback.js @@ -6,7 +6,7 @@ module.exports.create = function (deps, conf) { async function checkPublicAddr(host) { var result = await deps.request({ method: 'GET' - , url: host+'/api/org.oauth3.tunnel/checkip' + , url: deps.OAUTH3.url.normalize(host)+'/api/org.oauth3.tunnel/checkip' , json: true }); @@ -28,7 +28,7 @@ module.exports.create = function (deps, conf) { var reqObj = { method: 'POST' - , url: host+'/api/org.oauth3.tunnel/loopback' + , url: deps.OAUTH3.url.normalize(host)+'/api/org.oauth3.tunnel/loopback' , json: { address: address , port: port @@ -75,11 +75,13 @@ module.exports.create = function (deps, conf) { console.log('remaining loopback tokens', pending); } - var result = {error: null, address: address}; - ports.forEach(function (port, ind) { - result[port] = values[ind]; - }); - return result; + return { + address: address + , ports: ports.reduce(function (obj, port, ind) { + obj[port] = values[ind]; + return obj; + }, {}) + }; } loopback.checkPublicAddr = checkPublicAddr; diff --git a/package-lock.json b/package-lock.json index 11aca53..02dd078 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1168,6 +1168,11 @@ "resolved": "https://registry.npmjs.org/localhost.daplie.me-certificates/-/localhost.daplie.me-certificates-1.3.5.tgz", "integrity": "sha1-GjqH5PlX8mn2LP7mCmNpe9JVOpo=" }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", @@ -1301,11 +1306,38 @@ "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", "optional": true }, + "needle": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/needle/-/needle-1.1.2.tgz", + "integrity": "sha1-0oQaElv9dP77MMA0QQQ2kGHD4To=", + "requires": { + "debug": "2.6.1", + "iconv-lite": "0.4.15" + } + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "network": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/network/-/network-0.4.0.tgz", + "integrity": "sha1-ngk+TZzpBjmHJTL6YC/oVf87aSk=", + "requires": { + "async": "1.5.2", + "commander": "2.9.0", + "needle": "1.1.2", + "wmic": "0.1.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + } + } + }, "node-forge": { "version": "0.6.49", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.49.tgz", @@ -1967,14 +1999,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" }, - "stream-pair": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-pair/-/stream-pair-1.0.3.tgz", - "integrity": "sha1-vIdY/jnTgQuva3VMj5BI8PuRNn0=", - "requires": { - "readable-stream": "2.2.11" - } - }, "string_decoder": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", @@ -2233,6 +2257,25 @@ } } }, + "wmic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wmic/-/wmic-0.1.0.tgz", + "integrity": "sha1-eLQasR0VTLgSgZ4SkWdNrVXY4dc=", + "requires": { + "async": "2.5.0", + "iconv-lite": "0.4.15" + }, + "dependencies": { + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "requires": { + "lodash": "4.17.4" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index c5e56ee..e026a14 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "le-challenge-sni": "^2.0.1", "le-store-certbot": "git+https://git.daplie.com/Daplie/le-store-certbot.git#master", "localhost.daplie.me-certificates": "^1.3.5", + "network": "^0.4.0", "recase": "git+https://git.daplie.com/coolaj86/recase-js.git#v1.0.4", "redirect-https": "^1.1.0", "request": "^2.81.0",