forked from coolaj86/goldilocks.js
		
	
		
			
				
	
	
		
			96 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| module.exports.create = function (deps) {
 | |
|   var PromiseA = require('bluebird');
 | |
|   var request = PromiseA.promisify(require('request'));
 | |
|   var pending = {};
 | |
| 
 | |
|   function checkPublicAddr(host) {
 | |
|     return request({
 | |
|       method: 'GET'
 | |
|     , url: 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));
 | |
|       }
 | |
|       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: 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(provider) {
 | |
|     return deps.OAUTH3.discover(provider).then(function (directives) {
 | |
|       return checkPublicAddr(directives.api).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(directives.api, address, port);
 | |
|         }))
 | |
|         .then(function (values) {
 | |
|           console.log(pending);
 | |
|           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;
 | |
| };
 |