2016-04-07 19:22:13 -06:00
'use strict' ;
2017-08-02 08:44:59 -07: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 && obj !== Symbol . prototype ? "symbol" : typeof obj ; } ;
2016-04-08 18:25:08 -06:00
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
* /
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 ( ) {
2017-08-02 08:44:59 -07:00
var conf = arguments . length > 0 && arguments [ 0 ] !== undefined ? arguments [ 0 ] : { } ;
2016-04-07 19:22:13 -06:00
2016-04-08 01:35:38 -06:00
_classCallCheck ( this , AutoSSH ) ;
2016-04-07 19:22:13 -06:00
2017-08-02 08:44:59 -07:00
var _this = _possibleConstructorReturn ( this , ( AutoSSH . _ _proto _ _ || Object . getPrototypeOf ( AutoSSH ) ) . call ( this ) ) ;
2016-04-07 19:22:13 -06:00
2016-05-17 09:24:27 -06:00
_this . configure ( conf ) ;
2016-05-05 15:49:34 -06:00
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-05-17 09:24:27 -06:00
_createClass ( AutoSSH , [ {
key : 'configure' ,
value : function configure ( conf ) {
this . host = conf . host ;
2017-07-29 20:26:44 +02:00
this . localHost = conf . localHost || 'localhost' ;
this . reverse = conf . reverse === true || this . localHost !== 'localhost' ;
2016-05-17 09:24:27 -06:00
this . username = conf . username || 'root' ;
this . remotePort = conf . remotePort ;
2016-04-19 20:21:30 -06:00
2016-05-17 09:24:27 -06:00
if ( this . reverse ) this . localPort = parseInt ( conf . localPort ) || 22 ; else this . localPort = conf . localPort || 'auto' ;
this . pollCount = 0 ;
2017-08-02 08:44:59 -07:00
this . maxPollCount = parseInt ( conf . maxPollCount ) || 30 ;
this . pollTimeout = parseInt ( conf . pollTimeout ) || 75 ;
2016-05-17 09:24:27 -06:00
this . serverAliveInterval = typeof conf . serverAliveInterval === 'number' ? conf . serverAliveInterval : 120 ;
this . serverAliveCountMax = typeof conf . serverAliveCountMax === 'number' ? conf . serverAliveCountMax : 1 ;
this . sshPort = conf . sshPort || 22 ;
this . privateKey = conf . privateKey || null ;
}
/ *
* /
} , {
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 ;
2017-07-29 20:26:44 +02:00
if ( this . reverse || this . localHost !== 'localhost' ) {
2016-05-17 09:24:27 -06:00
this . execTunnel ( function ( ) {
_this2 . pollConnection ( ) ;
} ) ;
} else {
_portfinder2 . default . getPort ( { port : port } , function ( portfinderErr , freePort ) {
if ( _this2 . killed ) return ;
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
}
2016-05-13 18:13:25 -06:00
/ *
2016-04-19 20:21:30 -06:00
* /
} , {
2016-05-13 18:13:25 -06:00
key : 'getConnectionInfo' ,
value : function getConnectionInfo ( ) {
2016-05-06 23:19:00 -06:00
var _this3 = this ;
2016-05-13 18:13:25 -06:00
var infoObj = {
2016-05-06 23:19:00 -06:00
kill : function kill ( ) {
return _this3 . kill ;
} ,
2016-05-13 18:13:25 -06:00
pid : null ,
host : this . host || null ,
2017-07-29 20:26:44 +02:00
localHost : this . localHost || null ,
2016-05-13 18:13:25 -06:00
username : this . username || null ,
remotePort : parseInt ( this . remotePort ) ,
localPort : parseInt ( this . localPort ) ,
execString : this . execString || null
} ;
if ( this . currentProcess ) infoObj . pid = this . currentProcess . pid ;
if ( ! infoObj . localPort ) infoObj . localPort = null ;
if ( ! infoObj . remotePort ) infoObj . remotePort = null ;
return infoObj ;
}
/ * 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 ( ) {
this . emit ( 'connect' , this . getConnectionInfo ( ) ) ;
2016-04-19 20:21:30 -06:00
}
2016-05-07 18:18:48 -06:00
/ * f i r e d w h e n t i m e o u t e r r o r o c c u r s
* /
} , {
key : 'emitTimeout' ,
value : function emitTimeout ( ) {
var _this4 = this ;
this . emit ( 'timeout' , {
kill : function kill ( ) {
return _this4 . kill ;
} ,
pid : this . currentProcess . pid ,
host : this . host ,
username : this . username ,
remotePort : this . remotePort ,
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-07 18:18:48 -06:00
var _this5 = 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-07 18:18:48 -06:00
if ( result ) _this5 . emitConnect ( ) ; else {
2016-04-29 15:50:29 -06:00
setTimeout ( function ( ) {
2016-05-07 18:18:48 -06:00
_this5 . pollCount ++ ;
_this5 . pollConnection ( ) ;
} , _this5 . 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-07 18:18:48 -06:00
var _this6 = this ;
2016-04-08 19:32:09 -06:00
2017-07-29 20:26:44 +02:00
if ( this . localHost !== 'localhost' || this . reverse ) {
connEstablishedCb ( true ) ;
return ;
}
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-07 18:18:48 -06:00
if ( _this6 . localPort === freePort ) return connEstablishedCb ( false ) ; else return connEstablishedCb ( true ) ;
2016-04-08 19:32:09 -06:00
} ) ;
2017-07-29 20:26:44 +02:00
return ;
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-17 09:24:27 -06:00
if ( ! conf . localPort ) errors . push ( 'Missing localPort' ) ;
if ( conf . reverse === true && ( conf . localPort === 'auto' || isNaN ( parseInt ( conf . localPort ) ) ) ) errors . push ( 'Invalid value for localPort' ) ; else if ( isNaN ( parseInt ( conf . localPort ) ) && conf . localPort !== 'auto' ) errors . push ( 'Invalid value for 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-17 09:24:27 -06:00
var sshPort = this . sshPort === 22 ? '' : '-p ' + this . sshPort ;
2017-07-29 20:26:44 +02:00
var gatewayPorts = this . localHost === 'localhost' ? '' : '-o GatewayPorts=yes' ;
2016-05-05 18:14:31 -06:00
2017-07-29 20:26:44 +02:00
return defaultOpts + ' ' + serverAliveOpts + ' ' + gatewayPorts + ' ' + privateKey + ' ' + sshPort ;
2016-05-05 18:14:31 -06:00
}
/ *
* /
2016-05-05 15:49:34 -06:00
2016-05-05 18:14:31 -06:00
} , {
key : 'generateExecString' ,
value : function generateExecString ( ) {
2016-05-17 09:24:27 -06:00
var startPort = this . reverse ? this . remotePort : this . localPort ;
var endPort = this . reverse ? this . localPort : this . remotePort ;
2017-07-29 20:26:44 +02:00
var bindAddress = startPort + ':' + this . localHost + ':' + endPort ;
2016-05-05 18:14:31 -06:00
var options = this . generateExecOptions ( ) ;
var userAtHost = this . username + '@' + this . host ;
2016-05-17 09:24:27 -06:00
var method = this . reverse ? 'R' : 'L' ;
2016-04-29 15:50:29 -06:00
2016-05-17 09:24:27 -06:00
return 'ssh -N' + method + ' ' + 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-07 18:18:48 -06:00
var _this7 = 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 18:18:48 -06:00
if ( _this7 . killed ) return ;
2016-05-07 17:16:54 -06:00
2016-04-08 01:35:38 -06:00
if ( /Address already in use/i . test ( stderr ) ) {
2016-05-07 18:18:48 -06:00
_this7 . kill ( ) ;
_this7 . 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-07 18:18:48 -06:00
if ( execErr ) {
if ( /(timeout)|(timed out)/i . test ( stderr ) ) _this7 . emitTimeout ( ) ; else _this7 . emit ( 'error' , execErr ) ;
}
2016-04-07 19:22:13 -06:00
2016-05-07 18:18:48 -06:00
if ( ! _this7 . killed ) _this7 . 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
2016-05-13 18:13:25 -06:00
Object . defineProperty ( autosshInterface , 'info' , {
get : function get ( ) {
return autossh . getConnectionInfo ( ) ;
}
} ) ;
2016-04-08 18:25:08 -06:00
Object . defineProperty ( autosshInterface , 'pid' , {
2016-04-08 01:35:38 -06:00
get : function get ( ) {
2016-05-13 18:13:25 -06:00
if ( autossh . currentProcess ) return autossh . currentProcess . pid ; else return null ;
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 ;
} ;