more network handling stuff
This commit is contained in:
parent
3b5d7a49d4
commit
54a8bc15d9
|
@ -12,6 +12,12 @@
|
||||||
Server Name: '<span ng-bind="vm.config.device.hostname"></span>' running from
|
Server Name: '<span ng-bind="vm.config.device.hostname"></span>' running from
|
||||||
<br/>
|
<br/>
|
||||||
<code><span ng-bind="vm.config.cwd"></span>/</code>
|
<code><span ng-bind="vm.config.cwd"></span>/</code>
|
||||||
|
<br/>
|
||||||
|
iface: <span ng-bind="vm.admin.network.iface"></span>
|
||||||
|
<br/>
|
||||||
|
ipv4: <span ng-bind="vm.admin.network.ipv4"></span>
|
||||||
|
<br/>
|
||||||
|
ipv6: <span ng-bind="vm.admin.network.ipv6"></span>
|
||||||
</span>
|
</span>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -20,7 +26,7 @@
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-sm-3">
|
||||||
<ul class="nav nav-pills nav-stacked" ng-init="vm.admin.page = 'authn'">
|
<ul class="nav nav-pills nav-stacked" ng-init="vm.admin.page = 'authn'">
|
||||||
<li
|
<li
|
||||||
role="presentation"
|
role="presentation"
|
||||||
|
@ -104,7 +110,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-8">
|
<div class="col-sm-9">
|
||||||
|
|
||||||
<div ng-if="!vm.config || 'authn' === vm.admin.page">
|
<div ng-if="!vm.config || 'authn' === vm.admin.page">
|
||||||
<p>In order to administer this server you must authenticate.</p>
|
<p>In order to administer this server you must authenticate.</p>
|
||||||
|
@ -155,6 +161,7 @@
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
ng-click="vm.admin.setDeviceName(vm.admin.servername)"
|
ng-click="vm.admin.setDeviceName(vm.admin.servername)"
|
||||||
ng-disabled="vm.config.device.hostname === vm.admin.servername"
|
ng-disabled="vm.config.device.hostname === vm.admin.servername"
|
||||||
>Save</button>
|
>Save</button>
|
||||||
|
@ -214,6 +221,11 @@
|
||||||
<div ng-if="'oauth3-tunnel' === vm.admin.network.iface">
|
<div ng-if="'oauth3-tunnel' === vm.admin.network.iface">
|
||||||
<div ng-if="vm.admin.tunnel.advanced">
|
<div ng-if="vm.admin.tunnel.advanced">
|
||||||
<h2>OAuth3 Tunnel Options</h2>
|
<h2>OAuth3 Tunnel Options</h2>
|
||||||
|
<label><input
|
||||||
|
type="checkbox"
|
||||||
|
ng-model="vm.admin.tunnel.optimistic"
|
||||||
|
ng-change="vm.setTunnel()"> Prefer local network when available</label>
|
||||||
|
<br/>
|
||||||
<label>URL</label> <input
|
<label>URL</label> <input
|
||||||
class"form-input"
|
class"form-input"
|
||||||
type="url"
|
type="url"
|
||||||
|
|
|
@ -19,7 +19,9 @@ angular.module('com.daplie.cloud', [ 'org.oauth3' ])
|
||||||
var vm = this;
|
var vm = this;
|
||||||
var OAUTH3 = window.OAUTH3;
|
var OAUTH3 = window.OAUTH3;
|
||||||
|
|
||||||
vm.hello = 'Hello!';
|
vm.admin = { network: { iface: null, ipv4: null, ipv6: null } };
|
||||||
|
vm.admin.ipify = 'https://api.ipify.org?format=json';
|
||||||
|
|
||||||
vm.clientUri = OAUTH3.clientUri(window.location);
|
vm.clientUri = OAUTH3.clientUri(window.location);
|
||||||
|
|
||||||
vm.setSimple = function () {
|
vm.setSimple = function () {
|
||||||
|
@ -178,10 +180,52 @@ angular.module('com.daplie.cloud', [ 'org.oauth3' ])
|
||||||
}).then(function (configResp) {
|
}).then(function (configResp) {
|
||||||
console.log('config', configResp.data);
|
console.log('config', configResp.data);
|
||||||
vm.config = configResp.data;
|
vm.config = configResp.data;
|
||||||
|
vm.config.addresses.forEach(function (addr) {
|
||||||
|
if (/unicast/.test(addr.range) || /internet/i.test(addr.range)) {
|
||||||
|
// TODO
|
||||||
|
// there could be more than one iface (ipv4 on one and ipv6 on the other)
|
||||||
|
// there could also be more than one valid public ip
|
||||||
|
|
||||||
|
if ("IPv4" === addr.family) {
|
||||||
|
vm.admin.network.iface = addr.iface;
|
||||||
|
vm.admin.network.ipv4 = addr.address;
|
||||||
|
}
|
||||||
|
else if ("IPv6" === addr.family) {
|
||||||
|
// IPv6 gives valid internet address even when behind a firewall
|
||||||
|
// IPv6 requires a loopback test
|
||||||
|
// TODO always do the loopback / firewall test anyway
|
||||||
|
vm.admin.network.ipv6 = addr.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.admin.servername = vm.config.device.hostname;
|
||||||
//vm.config.ifaces
|
//vm.config.ifaces
|
||||||
//vm.config.addresses = [];
|
//vm.config.addresses = [];
|
||||||
vm.viewDomains(vm.config, domains, dns);
|
vm.viewDomains(vm.config, domains, dns);
|
||||||
return resp;
|
|
||||||
|
if (vm.admin.network.iface) {
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO try UPnP IGD / NAT-PMP / DNS-SD / PCP (ipv6) here
|
||||||
|
// TODO two requests - one to {{ipv4.ipify.org}}, the other to {{ipv6.ipify.org}}
|
||||||
|
vm.admin.network.iface = 'gateway';
|
||||||
|
return OAUTH3.request({
|
||||||
|
method: 'POST'
|
||||||
|
, url: 'https://' + vm.clientUri + '/api/com.daplie.caddy/request'
|
||||||
|
, session: session
|
||||||
|
, data: {
|
||||||
|
method: 'GET'
|
||||||
|
, url: 'https://api.ipify.org?format=json'
|
||||||
|
}
|
||||||
|
}).then(function (ipResp) {
|
||||||
|
console.log('ip-response', ipResp);
|
||||||
|
vm.admin.network.ipv4 = ipResp.data.body.ipv4 || ipResp.data.body.ip;
|
||||||
|
vm.admin.network.ipv6 = ipResp.data.body.ipv6;
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
|
@ -75,6 +75,7 @@ module.exports = function (opts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, recase: require('recase').create({})
|
, recase: require('recase').create({})
|
||||||
|
, request: PromiseA.promisify(require('request'))
|
||||||
, options: opts
|
, options: opts
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -163,6 +164,10 @@ module.exports = function (opts) {
|
||||||
serveInit.config(req, res);
|
serveInit.config(req, res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if ('/api/com.daplie.caddy/request' === req.url) {
|
||||||
|
serveInit.request(req, res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (content && '/' === req.url) {
|
if (content && '/' === req.url) {
|
||||||
// res.setHeader('Content-Type', 'application/octet-stream');
|
// res.setHeader('Content-Type', 'application/octet-stream');
|
||||||
|
|
|
@ -48,54 +48,65 @@ module.exports.create = function (deps) {
|
||||||
init: function (req, res) {
|
init: function (req, res) {
|
||||||
jsonParser(req, res, function () {
|
jsonParser(req, res, function () {
|
||||||
|
|
||||||
console.log('req.body', req.body);
|
return deps.PromiseA.resolve().then(function () {
|
||||||
var auth = jwt.decode((req.headers.authorization||'').replace(/^bearer\s+/i, ''));
|
|
||||||
var token = jwt.decode(req.body.access_token);
|
|
||||||
var refresh = jwt.decode(req.body.refresh_token);
|
|
||||||
auth.sub = auth.sub || auth.acx.id;
|
|
||||||
token.sub = token.sub || token.acx.id;
|
|
||||||
refresh.sub = refresh.sub || refresh.acx.id;
|
|
||||||
|
|
||||||
// TODO validate token with issuer, but as-is the sub is already a secret
|
console.log('req.body', req.body);
|
||||||
var id = crypto.createHash('sha256').update(auth.sub).digest('hex');
|
var auth = jwt.decode((req.headers.authorization||'').replace(/^bearer\s+/i, ''));
|
||||||
var tid = crypto.createHash('sha256').update(token.sub).digest('hex');
|
var token = jwt.decode(req.body.access_token);
|
||||||
var rid = crypto.createHash('sha256').update(refresh.sub).digest('hex');
|
var refresh = jwt.decode(req.body.refresh_token);
|
||||||
|
auth.sub = auth.sub || auth.acx.id;
|
||||||
|
token.sub = token.sub || token.acx.id;
|
||||||
|
refresh.sub = refresh.sub || refresh.acx.id;
|
||||||
|
|
||||||
console.log('ids', id, tid, rid);
|
// TODO validate token with issuer, but as-is the sub is already a secret
|
||||||
return deps.storage.owners.all().then(function (results) {
|
var id = crypto.createHash('sha256').update(auth.sub).digest('hex');
|
||||||
console.log('results', results);
|
var tid = crypto.createHash('sha256').update(token.sub).digest('hex');
|
||||||
var err;
|
var rid = crypto.createHash('sha256').update(refresh.sub).digest('hex');
|
||||||
|
|
||||||
// There is no owner yet. First come, first serve.
|
console.log('ids', id, tid, rid);
|
||||||
if (!results || !results.length) {
|
|
||||||
if (tid !== id || rid !== id) {
|
if (req.body.ip_url) {
|
||||||
err = new Error("When creating an owner the Authorization Bearer and Token and Refresh must all match");
|
// TODO set options / GunDB
|
||||||
|
deps.options.ip_url = req.body.ip_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deps.storage.owners.all().then(function (results) {
|
||||||
|
console.log('results', results);
|
||||||
|
var err;
|
||||||
|
|
||||||
|
// There is no owner yet. First come, first serve.
|
||||||
|
if (!results || !results.length) {
|
||||||
|
if (tid !== id || rid !== id) {
|
||||||
|
err = new Error(
|
||||||
|
"When creating an owner the Authorization Bearer and Token and Refresh must all match"
|
||||||
|
);
|
||||||
|
return deps.PromiseA.reject(err);
|
||||||
|
}
|
||||||
|
console.log('no owner, creating');
|
||||||
|
return deps.storage.owners.set(id, { token: token, refresh: refresh });
|
||||||
|
}
|
||||||
|
console.log('has results');
|
||||||
|
|
||||||
|
// There are onwers. Is this one of them?
|
||||||
|
if (!results.some(function (token) {
|
||||||
|
return scmp(id, token.id);
|
||||||
|
})) {
|
||||||
|
err = new Error("Authorization token does not belong to an existing owner.");
|
||||||
return deps.PromiseA.reject(err);
|
return deps.PromiseA.reject(err);
|
||||||
}
|
}
|
||||||
console.log('no owner, creating');
|
console.log('has correct owner');
|
||||||
return deps.storage.owners.set(id, { token: token, refresh: refresh });
|
|
||||||
}
|
|
||||||
console.log('has results');
|
|
||||||
|
|
||||||
// There are onwers. Is this one of them?
|
// We're adding an owner, unless it already exists
|
||||||
if (!results.some(function (token) {
|
if (!results.some(function (token) {
|
||||||
return scmp(id, token.id);
|
return scmp(tid, token.id);
|
||||||
})) {
|
})) {
|
||||||
err = new Error("Authorization token does not belong to an existing owner.");
|
console.log('adds new owner with existing owner');
|
||||||
return deps.PromiseA.reject(err);
|
return deps.storage.owners.set(id, { token: token, refresh: refresh });
|
||||||
}
|
}
|
||||||
console.log('has correct owner');
|
}).then(function () {
|
||||||
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
// We're adding an owner, unless it already exists
|
res.end(JSON.stringify({ success: true }));
|
||||||
if (!results.some(function (token) {
|
});
|
||||||
return scmp(tid, token.id);
|
|
||||||
})) {
|
|
||||||
console.log('adds new owner with existing owner');
|
|
||||||
return deps.storage.owners.set(id, { token: token, refresh: refresh });
|
|
||||||
}
|
|
||||||
}).then(function () {
|
|
||||||
res.setHeader('Content-Type', 'application/json;');
|
|
||||||
res.end(JSON.stringify({ success: true }));
|
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
res.setHeader('Content-Type', 'application/json;');
|
res.setHeader('Content-Type', 'application/json;');
|
||||||
res.end(JSON.stringify({ error: { message: err.message, code: err.code, uri: err.uri } }));
|
res.end(JSON.stringify({ error: { message: err.message, code: err.code, uri: err.uri } }));
|
||||||
|
@ -120,5 +131,33 @@ module.exports.create = function (deps) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
, request: function (req, res) {
|
||||||
|
jsonParser(req, res, function () {
|
||||||
|
isAuthorized(req, res, function () {
|
||||||
|
|
||||||
|
deps.request({
|
||||||
|
method: req.body.method || 'GET'
|
||||||
|
, url: req.body.url
|
||||||
|
, headers: req.body.headers
|
||||||
|
, body: req.body.data
|
||||||
|
}).then(function (resp) {
|
||||||
|
if (resp.body instanceof Buffer || 'string' === typeof resp.body) {
|
||||||
|
resp.body = JSON.parse(resp.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusCode: resp.statusCode
|
||||||
|
, status: resp.status
|
||||||
|
, headers: resp.headers
|
||||||
|
, body: resp.body
|
||||||
|
, data: resp.data
|
||||||
|
};
|
||||||
|
}).then(function (result) {
|
||||||
|
res.send(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue