101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
module.exports.create = function () {
|
|
var PromiseA = require('bluebird');
|
|
var request = PromiseA.promisify(require('request'));
|
|
var pending = {};
|
|
|
|
function checkPublicAddr(host) {
|
|
return request({
|
|
method: 'GET'
|
|
, url: 'https://'+host+'/api/org.oauth3.tunnel/checkip'
|
|
, json: true
|
|
}).then(function (result) {
|
|
if (!result.body) {
|
|
return PromiseA.reject(new Error('No response body in request for public address'));
|
|
}
|
|
if (result.body.error) {
|
|
var err = new Error(result.body.error.message);
|
|
return PromiseA.reject(Object.assign(err, result.body.error));
|
|
}
|
|
console.log(result.body, result.body.address);
|
|
return result.body.address;
|
|
});
|
|
}
|
|
|
|
function checkSinglePort(host, address, port) {
|
|
var crypto = require('crypto');
|
|
var token = crypto.randomBytes(8).toString('hex');
|
|
var keyAuth = crypto.randomBytes(32).toString('hex');
|
|
pending[token] = keyAuth;
|
|
|
|
var opts = {
|
|
address: address
|
|
, port: port
|
|
, token: token
|
|
, keyAuthorization: keyAuth
|
|
, iat: Date.now()
|
|
};
|
|
|
|
return request({
|
|
method: 'POST'
|
|
, url: 'https://'+host+'/api/org.oauth3.tunnel/loopback'
|
|
, json: opts
|
|
})
|
|
.then(function (result) {
|
|
delete pending[token];
|
|
if (!result.body) {
|
|
return PromiseA.reject(new Error('No response body in loopback request for port '+port));
|
|
}
|
|
// If the loopback requests don't go to us then there are all kinds of ways it could
|
|
// error, but none of them really provide much extra information so we don't do
|
|
// anything that will break the PromiseA.all out and mask the other results.
|
|
if (result.body.error) {
|
|
console.log('error on remote side of port '+port+' loopback', result.body.error);
|
|
}
|
|
return !!result.body.success;
|
|
}, function (err) {
|
|
delete pending[token];
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
function loopback(session) {
|
|
var host;
|
|
if (!session) {
|
|
host = 'api.oauth3.org';
|
|
} else {
|
|
host = 'api.' + ((session.token || {}).aud || 'oauth3.org');
|
|
}
|
|
|
|
return checkPublicAddr(host).then(function (address) {
|
|
console.log('checking to see if', address, 'gets back to us');
|
|
var ports = require('./servers').listeners.tcp.list();
|
|
return PromiseA.all(ports.map(function (port) {
|
|
return checkSinglePort(host, address, port);
|
|
}))
|
|
.then(function (values) {
|
|
var result = {error: null, address: address};
|
|
ports.forEach(function (port, ind) {
|
|
result[port] = values[ind];
|
|
});
|
|
return result;
|
|
});
|
|
});
|
|
}
|
|
|
|
loopback.server = require('http').createServer(function (req, res) {
|
|
var parsed = require('url').parse(req.url);
|
|
var token = parsed.pathname.replace('/.well-known/cloud-challenge/', '');
|
|
if (pending[token]) {
|
|
res.setHeader('Content-Type', 'text/plain');
|
|
res.end(pending[token]);
|
|
} else {
|
|
res.statusCode = 404;
|
|
res.end();
|
|
}
|
|
});
|
|
|
|
return loopback;
|
|
};
|