2016-09-30 22:03:41 +00:00
#!/usr/bin/env node
( function ( ) {
'use strict' ;
var pkg = require ( '../package.json' ) ;
var program = require ( 'commander' ) ;
var url = require ( 'url' ) ;
var stunneld = require ( '../wstunneld.js' ) ;
function collectProxies ( val , memo ) {
var vals = val . split ( /,/g ) ;
vals . map ( function ( location ) {
// http:john.example.com:3000
// http://john.example.com:3000
var parts = location . split ( ':' ) ;
2016-10-01 06:39:20 +00:00
if ( 1 === parts . length ) {
parts [ 1 ] = parts [ 0 ] ;
parts [ 0 ] = 'wss' ;
}
if ( 2 === parts . length ) {
if ( /\./ . test ( parts [ 0 ] ) ) {
parts [ 2 ] = parts [ 1 ] ;
parts [ 1 ] = parts [ 0 ] ;
parts [ 0 ] = 'wss' ;
}
if ( ! /\./ . test ( parts [ 1 ] ) ) {
throw new Error ( "bad --serve option Example: wss://tunnel.example.com:1337" ) ;
}
}
2016-09-30 22:03:41 +00:00
parts [ 0 ] = parts [ 0 ] . toLowerCase ( ) ;
parts [ 1 ] = parts [ 1 ] . toLowerCase ( ) . replace ( /(\/\/)?/ , '' ) || '*' ;
parts [ 2 ] = parseInt ( parts [ 2 ] , 10 ) || 0 ;
if ( ! parts [ 2 ] ) {
// TODO grab OS list of standard ports?
2016-10-01 06:39:20 +00:00
if ( - 1 !== [ 'ws' , 'http' ] . indexOf ( parts [ 0 ] ) ) {
//parts[2] = 80;
2016-09-30 22:03:41 +00:00
}
2016-10-01 06:39:20 +00:00
else if ( - 1 !== [ 'wss' , 'https' ] . indexOf ( parts [ 0 ] ) ) {
//parts[2] = 443;
2016-09-30 22:03:41 +00:00
}
else {
throw new Error ( "port must be specified - ex: tls:*:1337" ) ;
}
}
return {
protocol : parts [ 0 ]
, hostname : parts [ 1 ]
, port : parts [ 2 ]
} ;
} ) . forEach ( function ( val ) {
memo . push ( val ) ;
} ) ;
return memo ;
}
2016-10-01 06:39:20 +00:00
function collectPorts ( val , memo ) {
memo = memo . concat ( val . split ( /,/g ) . filter ( Boolean ) ) ;
return memo ;
}
2016-09-30 22:03:41 +00:00
program
. version ( pkg . version )
//.command('jsurl <url>')
. arguments ( '<url>' )
. action ( function ( url ) {
program . url = url ;
} )
2016-10-01 06:39:20 +00:00
. option ( '--serve <URL>' , 'comma separated list of <proto>:<//><servername>:<port> to which matching incoming http and https should forward (reverse proxy). Ex: https://john.example.com,tls:*:1337' , collectProxies , [ ] )
. option ( '--ports <PORT>' , 'comma separated list of ports on which to listen. Ex: 80,443,1337' , collectPorts , [ ] )
2016-09-30 22:03:41 +00:00
. option ( '--secret <STRING>' , 'the same secret used by stunneld (used for JWT authentication)' )
. parse ( process . argv )
;
2016-10-18 21:33:43 +00:00
program . stunneld = program . stunneld || 'wss://tunnel.daplie.com' ;
2016-09-30 22:03:41 +00:00
var jwt = require ( 'jsonwebtoken' ) ;
var domainsMap = { } ;
2016-10-01 06:39:20 +00:00
var tokenData = { name : null , domains : null } ;
2016-09-30 22:03:41 +00:00
var location = url . parse ( program . stunneld ) ;
if ( ! location . protocol || /\./ . test ( location . protocol ) ) {
program . stunneld = 'wss://' + program . stunneld ;
location = url . parse ( program . stunneld ) ;
}
program . stunneld = location . protocol + '//' + location . hostname + ( location . port ? ':' + location . port : '' ) ;
2016-10-01 05:52:37 +00:00
program . serve . forEach ( function ( proxy ) {
2016-09-30 22:03:41 +00:00
domainsMap [ proxy . hostname ] = true ;
} ) ;
tokenData . domains = Object . keys ( domainsMap ) ;
tokenData . name = tokenData . domains [ 0 ] ;
2016-10-01 06:39:20 +00:00
if ( ! program . ports . length ) {
program . ports = [ 80 , 443 ] ;
}
2016-09-30 22:03:41 +00:00
program . services = { } ;
2016-10-01 06:39:20 +00:00
program . portsMap = { } ;
program . servernamesMap = { } ;
2016-10-01 05:52:37 +00:00
program . serve . forEach ( function ( proxy ) {
2016-09-30 22:03:41 +00:00
//program.services = { 'ssh': 22, 'http': 80, 'https': 443 };
2016-10-01 06:39:20 +00:00
program . servernamesMap [ proxy . hostname ] = true ;
2016-09-30 22:03:41 +00:00
program . services [ proxy . protocol ] = proxy . port ;
2016-10-01 06:39:20 +00:00
if ( proxy . port ) {
program . portsMap [ proxy . port ] = true ;
}
2016-09-30 22:03:41 +00:00
} ) ;
2016-10-01 06:39:20 +00:00
program . servernames = Object . keys ( program . servernamesMap ) ;
program . ports = program . ports . concat ( Object . keys ( program . portsMap ) ) ;
2016-09-30 22:03:41 +00:00
program . token = program . token || jwt . sign ( tokenData , program . secret || 'shhhhh' ) ;
2016-10-01 06:39:20 +00:00
if ( ! program . serve . length ) {
throw new Error ( "must specify at least on server" ) ;
}
2016-10-01 05:52:37 +00:00
// TODO letsencrypt
program . tlsOptions = require ( 'localhost.daplie.com-certificates' ) . merge ( { } ) ;
if ( ! program . secret ) {
// TODO randomly generate and store in file?
console . warn ( "[SECURITY] using default --secret 'shhhhh'" ) ;
program . secret = 'shhhhh' ;
}
2016-10-01 06:39:20 +00:00
//require('cluster-store').create().then(function (store) {
//program.store = store;
2016-10-01 05:52:37 +00:00
2016-10-01 06:39:20 +00:00
stunneld . create ( program ) ;
//});
2016-09-30 22:03:41 +00:00
} ( ) ) ;