'use strict'; module.exports.create = function (deps, config) { var stunnel = require('stunnel'); var activeTunnels = {}; 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; } if (!decoded.aud) { console.warn('tunnel manager given token with no tunnelUrl or audience'); return; } 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' }); }); } return { add: addToken }; };