'use strict'; module.exports.create = function (deps, config) { var PromiseA = require('bluebird'); var fs = PromiseA.promisifyAll(require('fs')); var stunnel = require('stunnel'); var activeTunnels = {}; var tokensPath = require('path').join(__dirname, '..', 'var', 'tokens.json'); var storage = { all: function () { var tokens; try { tokens = require(tokensPath); } catch (err) { tokens = {}; } return PromiseA.resolve(Object.keys(tokens).map(function (key) { return tokens[key]; })); } , save: function (result) { var tokens; try { tokens = require(tokensPath); } catch (err) { tokens = {}; } tokens[result.jwt] = result; return fs.writeFileAsync(tokensPath, JSON.stringify(tokens), 'utf8'); } }; function addToken(data) { if (!data.tunnelUrl) { var decoded; try { decoded = JSON.parse(new Buffer(data.jwt.split('.')[1], 'base64').toString('ascii')); } catch (err) { console.warn('invalid web token given to tunnel manager', err); return PromiseA.reject(err); } if (!decoded.aud) { console.warn('tunnel manager given token with no tunnelUrl or audience'); var err = new Error('missing tunnelUrl and audience'); return PromiseA.reject(err); } data.tunnelUrl = 'wss://' + decoded.aud + '/'; } if (!activeTunnels[data.tunnelUrl]) { console.log('creating new tunnel client for', data.tunnelUrl); // We create the tunnel without an initial token so we can append the token and // get the promise that should tell us more about if it worked or not. activeTunnels[data.tunnelUrl] = stunnel.connect({ stunneld: data.tunnelUrl , net: deps.tunnel.net // NOTE: the ports here aren't that important since we are providing a custom // `net.createConnection` that doesn't actually use the port. What is important // is that any services we are interested in are listed in this object and have // a '*' sub-property. , services: { https: { '*': 443 } , http: { '*': 80 } , smtp: { '*': 25 } , smtps: { '*': 587 /*also 465/starttls*/ } , ssh: { '*': 22 } } }); } console.log('appending token to tunnel at', data.tunnelUrl); return activeTunnels[data.tunnelUrl].append(data.jwt); } if (typeof config.tunnel === 'string') { config.tunnel.split(',').forEach(function (jwt) { addToken({ jwt: jwt, owner: 'config' }); }); } storage.all().then(function (stored) { stored.forEach(function (result) { addToken(result); }); }); return { add: function (data) { return addToken(data).then(function () { return storage.save(data); }); } }; };