150 lines
4.5 KiB
JavaScript
150 lines
4.5 KiB
JavaScript
'use strict';
|
|
|
|
module.exports.create = function (deps, conf) {
|
|
var PromiseA = deps.PromiseA;
|
|
var request = PromiseA.promisify(require('request'));
|
|
var OAUTH3 = require('../packages/assets/org.oauth3');
|
|
require('../packages/assets/org.oauth3/oauth3.dns.js');
|
|
OAUTH3._hooks = require('../packages/assets/org.oauth3/oauth3.node.storage.js');
|
|
|
|
function dnsType(addr) {
|
|
if (/^\d+\.\d+\.\d+\.\d+$/.test(addr)) {
|
|
return 'A';
|
|
}
|
|
if (-1 !== addr.indexOf(':') && /^[a-f:\.\d]+$/i.test(addr)) {
|
|
return 'AAAA';
|
|
}
|
|
}
|
|
|
|
async function getSession() {
|
|
var sessions = await deps.storage.owners.all();
|
|
var session = sessions.filter(function (sess) {
|
|
return sess.token.scp.indexOf('dns') >= 0;
|
|
})[0];
|
|
|
|
if (!session) {
|
|
throw new Error('no sessions with DNS grants');
|
|
}
|
|
|
|
// The OAUTH3 library stores some things on the root session object that we usually
|
|
// just leave inside the token, but we need to pull those out before we use it here
|
|
session.provider_uri = session.provider_uri || session.token.provider_uri || session.token.iss;
|
|
session.client_uri = session.client_uri || session.token.azp;
|
|
session.scope = session.scope || session.token.scp;
|
|
return session;
|
|
}
|
|
|
|
async function setDeviceAddress(addr) {
|
|
var session = await getSession();
|
|
var directives = await OAUTH3.discover(session.token.aud);
|
|
|
|
// Set the address of the device to our public address.
|
|
await request({
|
|
url: directives.api+'/api/com.daplie.domains/acl/devices/' + conf.device.hostname
|
|
, method: 'POST'
|
|
, headers: {
|
|
'Authorization': 'Bearer ' + session.refresh_token
|
|
, 'Accept': 'application/json; charset=utf-8'
|
|
}
|
|
, json: {
|
|
addresses: [
|
|
{ value: addr, type: dnsType(addr) }
|
|
]
|
|
}
|
|
});
|
|
|
|
// 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 = 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 common = {
|
|
api: 'devices.detach'
|
|
, session: session
|
|
, device: conf.device.hostname
|
|
};
|
|
await PromiseA.all(ourDomains.map(function (record) {
|
|
return OAUTH3.api(directives.api, Object.assign({}, common, record));
|
|
}));
|
|
|
|
common = {
|
|
api: 'devices.attach'
|
|
, session: session
|
|
, device: conf.device.hostname
|
|
, ip: addr
|
|
, ttl: 300
|
|
};
|
|
await PromiseA.all(ourDomains.map(function (record) {
|
|
return OAUTH3.api(directives.api, Object.assign({}, common, record));
|
|
}));
|
|
}
|
|
|
|
async function getDeviceAddresses() {
|
|
var session = await getSession();
|
|
var directives = await OAUTH3.discover(session.token.aud);
|
|
|
|
var result = await request({
|
|
url: directives.api+'/api/org.oauth3.dns/acl/devices'
|
|
, method: 'GET'
|
|
, headers: {
|
|
'Authorization': 'Bearer ' + session.refresh_token
|
|
, 'Accept': 'application/json; charset=utf-8'
|
|
}
|
|
, json: true
|
|
});
|
|
|
|
if (!result.body) {
|
|
throw new Error('No response body in request for device addresses');
|
|
}
|
|
if (result.body.error) {
|
|
throw Object.assign(new Error('error getting device list'), result.body.error);
|
|
}
|
|
|
|
var dev = result.body.devices.filter(function (dev) {
|
|
return dev.name === conf.device.hostname;
|
|
})[0];
|
|
return (dev || {}).addresses || [];
|
|
}
|
|
|
|
var publicAddress;
|
|
async function recheckPubAddr() {
|
|
if (!conf.ddns.enabled) {
|
|
return;
|
|
}
|
|
|
|
var session = await getSession();
|
|
var directives = await OAUTH3.discover(session.token.aud);
|
|
var addr = await deps.loopback.checkPublicAddr(directives.api);
|
|
|
|
if (publicAddress === addr) {
|
|
return;
|
|
}
|
|
|
|
if (conf.debug) {
|
|
console.log('previous public address',publicAddress, 'does not match current public address', addr);
|
|
}
|
|
|
|
await setDeviceAddress(addr);
|
|
publicAddress = addr;
|
|
}
|
|
|
|
recheckPubAddr();
|
|
setInterval(recheckPubAddr, 5*60*1000);
|
|
|
|
return {
|
|
setDeviceAddress: setDeviceAddress
|
|
, getDeviceAddresses: getDeviceAddresses
|
|
, recheckPubAddr: recheckPubAddr
|
|
};
|
|
};
|