2016-04-07 19:22:13 -06:00
'use strict' ;
2016-04-08 18:25:08 -06:00
var _typeof = typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ? function ( obj ) { return typeof obj ; } : function ( obj ) { return obj && typeof Symbol === "function" && obj . constructor === Symbol ? "symbol" : typeof obj ; } ;
2016-04-07 19:22:13 -06:00
var _createClass = function ( ) { function defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } } return function ( Constructor , protoProps , staticProps ) { if ( protoProps ) defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) defineProperties ( Constructor , staticProps ) ; return Constructor ; } ; } ( ) ;
var _child _process = require ( 'child_process' ) ;
var _events = require ( 'events' ) ;
2016-04-08 10:48:25 -06:00
var _portfinder = require ( 'portfinder' ) ;
var _portfinder2 = _interopRequireDefault ( _portfinder ) ;
function _interopRequireDefault ( obj ) { return obj && obj . _ _esModule ? obj : { default : obj } ; }
2016-04-07 19:22:13 -06:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
function _possibleConstructorReturn ( self , call ) { if ( ! self ) { throw new ReferenceError ( "this hasn't been initialised - super() hasn't been called" ) ; } return call && ( typeof call === "object" || typeof call === "function" ) ? call : self ; }
function _inherits ( subClass , superClass ) { if ( typeof superClass !== "function" && superClass !== null ) { throw new TypeError ( "Super expression must either be null or a function, not " + typeof superClass ) ; } subClass . prototype = Object . create ( superClass && superClass . prototype , { constructor : { value : subClass , enumerable : false , writable : true , configurable : true } } ) ; if ( superClass ) Object . setPrototypeOf ? Object . setPrototypeOf ( subClass , superClass ) : subClass . _ _proto _ _ = superClass ; }
2016-04-08 01:35:38 -06:00
/ * A u t o S S H c l a s s
* /
2016-04-07 19:22:13 -06:00
2016-04-08 01:35:38 -06:00
var AutoSSH = function ( _EventEmitter ) {
_inherits ( AutoSSH , _EventEmitter ) ;
2016-04-19 20:21:30 -06:00
/ *
* /
2016-04-08 01:35:38 -06:00
function AutoSSH ( ) {
2016-04-07 19:22:13 -06:00
var conf = arguments . length <= 0 || arguments [ 0 ] === undefined ? { } : arguments [ 0 ] ;
2016-04-08 01:35:38 -06:00
_classCallCheck ( this , AutoSSH ) ;
2016-04-07 19:22:13 -06:00
2016-04-08 01:35:38 -06:00
var _this = _possibleConstructorReturn ( this , Object . getPrototypeOf ( AutoSSH ) . call ( this ) ) ;
2016-04-07 19:22:13 -06:00
_this . host = conf . host ;
2016-04-08 18:25:08 -06:00
_this . username = conf . username || 'root' ;
2016-04-07 19:22:13 -06:00
_this . remotePort = conf . remotePort ;
2016-04-08 18:25:08 -06:00
_this . localPort = conf . localPort || 'auto' ;
2016-04-07 19:22:13 -06:00
2016-04-08 19:35:38 -06:00
_this . pollCount = 0 ;
2016-04-28 13:39:14 -06:00
_this . maxPollCount = conf . maxPollCount || 30 ;
2016-04-29 15:50:29 -06:00
_this . pollTimeout = 75 ;
_this . serverAliveInterval = typeof conf . serverAliveInterval === 'number' ? conf . serverAliveInterval : 120 ;
_this . serverAliveCountMax = typeof conf . serverAliveCountMax === 'number' ? conf . serverAliveCountMax : 1 ;
2016-04-08 19:32:09 -06:00
2016-05-06 22:28:03 -06:00
_this . sshPort = conf . sshPort || 22 ;
2016-05-05 15:49:34 -06:00
_this . privateKey = conf . privateKey || null ;
2016-04-07 19:22:13 -06:00
setImmediate ( function ( ) {
2016-04-08 18:25:08 -06:00
var confErrors = _this . getConfErrors ( conf ) ;
2016-04-29 15:50:29 -06:00
if ( confErrors . length ) return confErrors . forEach ( function ( confErr ) {
return _this . emit ( 'error' , confErr ) ;
2016-04-08 18:25:08 -06:00
} ) ;
2016-04-07 19:22:13 -06:00
2016-04-29 15:50:29 -06:00
return _this . connect ( conf ) ;
2016-04-08 01:35:38 -06:00
} ) ;
process . on ( 'exit' , function ( ) {
_this . kill ( ) ;
2016-04-07 19:22:13 -06:00
} ) ;
return _this ;
}
2016-04-19 20:21:30 -06:00
/ *
* /
2016-04-08 01:35:38 -06:00
_createClass ( AutoSSH , [ {
2016-04-19 20:21:30 -06:00
key : 'connect' ,
value : function connect ( conf ) {
2016-04-08 19:32:09 -06:00
var _this2 = this ;
2016-04-19 20:21:30 -06:00
var port = this . localPort === 'auto' ? this . generateRandomPort ( ) : this . localPort ;
2016-04-29 15:50:29 -06:00
_portfinder2 . default . getPort ( { port : port } , function ( portfinderErr , freePort ) {
2016-05-07 17:16:54 -06:00
if ( _this2 . killed ) return ;
2016-04-29 15:50:29 -06:00
if ( portfinderErr ) _this2 . emit ( 'error' , 'Port error: ' + portfinderErr ) ;
if ( _this2 . localPort !== 'auto' && _this2 . localPort !== freePort ) _this2 . emit ( 'error' , 'Port ' + _this2 . localPort + ' is not available' ) ; else {
_this2 . localPort = freePort ;
// creates tunnel and then polls port until connection is established
_this2 . execTunnel ( function ( ) {
_this2 . pollConnection ( ) ;
} ) ;
}
2016-04-19 20:21:30 -06:00
} ) ;
}
/ * f i r e d w h e n c o n n e c t i o n e s t a b l i s h e d
* /
} , {
key : 'emitConnect' ,
value : function emitConnect ( ) {
2016-05-06 23:19:00 -06:00
var _this3 = this ;
2016-04-19 20:21:30 -06:00
this . emit ( 'connect' , {
2016-05-06 23:19:00 -06:00
kill : function kill ( ) {
return _this3 . kill ;
} ,
2016-04-19 20:21:30 -06:00
pid : this . currentProcess . pid ,
host : this . host ,
username : this . username ,
remotePort : this . remotePort ,
2016-04-29 15:50:29 -06:00
localPort : this . localPort ,
execString : this . execString
2016-04-19 20:21:30 -06:00
} ) ;
}
/ * s t a r t s p o l l i n g t h e p o r t t o s e e i f c o n n e c t i o n e s t a b l i s h e d
* /
} , {
key : 'pollConnection' ,
value : function pollConnection ( ) {
2016-05-06 23:19:00 -06:00
var _this4 = this ;
2016-04-19 20:21:30 -06:00
2016-05-07 17:16:54 -06:00
if ( this . killed ) return ;
2016-04-28 13:39:14 -06:00
if ( this . maxPollCount && this . pollCount >= this . maxPollCount ) {
2016-04-08 19:35:38 -06:00
this . emit ( 'error' , 'Max poll count reached. Aborting...' ) ;
2016-04-29 15:50:29 -06:00
this . kill ( ) ;
} else {
this . isConnectionEstablished ( function ( result ) {
2016-05-06 23:19:00 -06:00
if ( result ) _this4 . emitConnect ( ) ; else {
2016-04-29 15:50:29 -06:00
setTimeout ( function ( ) {
2016-05-06 23:19:00 -06:00
_this4 . pollCount ++ ;
_this4 . pollConnection ( ) ;
} , _this4 . pollTimeout ) ;
2016-04-29 15:50:29 -06:00
}
} ) ;
2016-04-08 19:32:09 -06:00
}
}
2016-04-19 20:21:30 -06:00
/ * c h e c k s i f c o n n e c t i o n i s e s t a b l i s h e d a t p o r t
* /
2016-04-08 19:32:09 -06:00
} , {
key : 'isConnectionEstablished' ,
2016-04-29 15:50:29 -06:00
value : function isConnectionEstablished ( connEstablishedCb ) {
2016-05-06 23:19:00 -06:00
var _this5 = this ;
2016-04-08 19:32:09 -06:00
2016-04-29 15:50:29 -06:00
_portfinder2 . default . getPort ( { port : this . localPort } , function ( portfinderErr , freePort ) {
if ( portfinderErr ) return connEstablishedCb ( false ) ;
2016-04-08 19:32:09 -06:00
2016-05-06 23:19:00 -06:00
if ( _this5 . localPort === freePort ) return connEstablishedCb ( false ) ; else return connEstablishedCb ( true ) ;
2016-04-08 19:32:09 -06:00
} ) ;
}
2016-04-19 20:21:30 -06:00
/ * p a r s e s t h e c o n f f o r e r r o r s
* /
2016-04-08 19:32:09 -06:00
} , {
2016-04-08 18:25:08 -06:00
key : 'getConfErrors' ,
value : function getConfErrors ( conf ) {
var errors = [ ] ;
2016-05-06 22:28:03 -06:00
if ( ! conf . localPort ) errors . push ( 'Missing localPort' ) ; else if ( isNaN ( parseInt ( conf . localPort ) ) && conf . localPort !== 'auto' ) errors . push ( 'Invalid localPort' ) ;
2016-04-19 20:21:30 -06:00
2016-05-06 22:28:03 -06:00
if ( ! conf . host ) errors . push ( 'Missing host' ) ; else if ( typeof conf . host !== 'string' ) {
errors . push ( 'host must be type "string". was given "' + _typeof ( conf . host ) + '"' ) ;
}
2016-04-08 18:25:08 -06:00
2016-05-06 22:28:03 -06:00
if ( ! conf . username ) errors . push ( 'Missing username' ) ; else if ( typeof conf . username !== 'string' ) {
errors . push ( 'username must be type "string". was given "' + _typeof ( conf . username ) + '"' ) ;
}
2016-04-08 18:25:08 -06:00
2016-05-06 22:28:03 -06:00
if ( ! conf . remotePort ) errors . push ( 'Missing remotePort' ) ; else if ( isNaN ( parseInt ( conf . remotePort ) ) ) {
errors . push ( 'remotePort must be type "number". was given "' + _typeof ( conf . remotePort ) + '"' ) ;
}
2016-04-08 18:25:08 -06:00
2016-05-06 22:28:03 -06:00
if ( conf . sshPort && isNaN ( parseInt ( conf . sshPort ) ) ) {
errors . push ( 'sshPort must be type "number". was given "' + _typeof ( conf . sshPort ) + '"' ) ;
}
2016-04-08 18:25:08 -06:00
return errors ;
}
2016-04-19 20:21:30 -06:00
/ *
* /
2016-04-08 18:25:08 -06:00
} , {
2016-04-08 14:28:58 -06:00
key : 'generateRandomPort' ,
value : function generateRandomPort ( ) {
var minPort = 3000 ;
var maxPort = 65535 ;
return Math . floor ( Math . random ( ) * ( maxPort - minPort + 1 ) ) + minPort ;
}
2016-04-19 20:21:30 -06:00
/ *
* /
2016-04-08 14:28:58 -06:00
} , {
2016-05-05 18:14:31 -06:00
key : 'generateDefaultOptions' ,
value : function generateDefaultOptions ( ) {
2016-05-05 16:08:15 -06:00
var exitOnFailure = '-o ExitOnForwardFailure=yes' ;
2016-05-05 18:14:31 -06:00
var strictHostCheck = '-o StrictHostKeyChecking=no' ;
return exitOnFailure + ' ' + strictHostCheck ;
}
/ *
* /
} , {
key : 'generateServerAliveOptions' ,
value : function generateServerAliveOptions ( ) {
2016-04-29 15:50:29 -06:00
var serverAliveInterval = '-o ServerAliveInterval=' + this . serverAliveInterval ;
var serverAliveCountMax = '-o ServerAliveCountMax=' + this . serverAliveCountMax ;
2016-05-05 18:14:31 -06:00
return serverAliveInterval + ' ' + serverAliveCountMax ;
}
/ *
* /
} , {
key : 'generateExecOptions' ,
value : function generateExecOptions ( ) {
var serverAliveOpts = this . generateServerAliveOptions ( ) ;
var defaultOpts = this . generateDefaultOptions ( ) ;
2016-05-05 15:49:34 -06:00
var privateKey = this . privateKey ? '-i ' + this . privateKey : '' ;
2016-05-05 18:14:31 -06:00
var sshPort = this . sshPort ? '-p ' + this . sshPort : '' ;
return defaultOpts + ' ' + serverAliveOpts + ' ' + privateKey + ' ' + sshPort ;
}
/ *
* /
2016-05-05 15:49:34 -06:00
2016-05-05 18:14:31 -06:00
} , {
key : 'generateExecString' ,
value : function generateExecString ( ) {
var bindAddress = this . localPort + ':localhost:' + this . remotePort ;
var options = this . generateExecOptions ( ) ;
var userAtHost = this . username + '@' + this . host ;
2016-04-29 15:50:29 -06:00
2016-05-05 18:14:31 -06:00
return 'ssh -NL ' + bindAddress + ' ' + options + ' ' + userAtHost ;
2016-04-08 18:25:08 -06:00
}
2016-04-19 20:21:30 -06:00
2016-04-29 15:50:29 -06:00
/ *
2016-04-19 20:21:30 -06:00
* /
2016-04-08 18:25:08 -06:00
} , {
key : 'execTunnel' ,
2016-04-29 15:50:29 -06:00
value : function execTunnel ( execTunnelCb ) {
2016-05-06 23:19:00 -06:00
var _this6 = this ;
2016-04-08 14:28:58 -06:00
2016-05-05 18:14:31 -06:00
this . execString = this . generateExecString ( ) ;
this . currentProcess = ( 0 , _child _process . exec ) ( this . execString , function ( execErr , stdout , stderr ) {
2016-05-07 17:16:54 -06:00
if ( _this6 . killed ) return ;
2016-04-08 01:35:38 -06:00
if ( /Address already in use/i . test ( stderr ) ) {
2016-05-06 23:19:00 -06:00
_this6 . kill ( ) ;
_this6 . emit ( 'error' , stderr ) ;
2016-04-29 15:50:29 -06:00
return ;
2016-04-08 01:35:38 -06:00
}
2016-04-07 19:22:13 -06:00
2016-05-06 23:19:00 -06:00
if ( execErr ) _this6 . emit ( 'error' , execErr ) ;
2016-04-07 19:22:13 -06:00
2016-05-06 23:19:00 -06:00
if ( ! _this6 . killed ) _this6 . execTunnel ( function ( ) {
2016-04-08 18:25:08 -06:00
return console . log ( 'Restarting autossh...' ) ;
} ) ;
} ) ;
2016-04-29 15:50:29 -06:00
if ( typeof execTunnelCb === 'function' ) setImmediate ( function ( ) {
return execTunnelCb ( ) ;
2016-04-07 19:22:13 -06:00
} ) ;
}
2016-04-19 20:21:30 -06:00
/ *
* /
2016-04-07 19:22:13 -06:00
} , {
key : 'kill' ,
value : function kill ( ) {
this . killed = true ;
2016-04-08 18:25:08 -06:00
if ( this . currentProcess && typeof this . currentProcess . kill === 'function' ) this . currentProcess . kill ( ) ;
2016-04-07 19:22:13 -06:00
return this ;
}
} ] ) ;
2016-04-08 01:35:38 -06:00
return AutoSSH ;
2016-04-07 19:22:13 -06:00
} ( _events . EventEmitter ) ;
2016-04-08 19:35:38 -06:00
/ * E x p o r t
* /
2016-04-08 18:25:08 -06:00
module . exports = function ( conf ) {
var autossh = new AutoSSH ( conf ) ;
/ * C r e a t e i n t e r f a c e o b j e c t
A new object creates an abstraction from class implementation
* /
var autosshInterface = {
2016-04-08 01:35:38 -06:00
on : function on ( evt ) {
for ( var _len = arguments . length , args = Array ( _len > 1 ? _len - 1 : 0 ) , _key = 1 ; _key < _len ; _key ++ ) {
args [ _key - 1 ] = arguments [ _key ] ;
}
2016-04-08 18:25:08 -06:00
autossh . on . apply ( autossh , [ evt ] . concat ( args ) ) ;
2016-04-08 01:35:38 -06:00
return this ;
} ,
kill : function kill ( ) {
2016-04-08 18:25:08 -06:00
autossh . kill ( ) ;
2016-04-08 01:35:38 -06:00
return this ;
}
} ;
2016-04-08 18:25:08 -06:00
Object . defineProperty ( autosshInterface , 'pid' , {
2016-04-08 01:35:38 -06:00
get : function get ( ) {
2016-04-08 18:25:08 -06:00
return autossh . currentProcess . pid ;
2016-04-08 01:35:38 -06:00
}
} ) ;
2016-04-07 19:22:13 -06:00
2016-04-08 18:25:08 -06:00
return autosshInterface ;
} ;