UNPKG

ssh2-promise

Version:
178 lines (177 loc) 6.91 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; const BaseSSH2Promise_1 = __importDefault(require("./BaseSSH2Promise")); const sftp_1 = __importDefault(require("./sftp")); const sshConnection_1 = __importDefault(require("./sshConnection")); const sshConstants_1 = __importDefault(require("./sshConstants")); const sshUtils_1 = __importDefault(require("./sshUtils")); function isRegistered(sshConnection, sshTunnel) { return sshTunnel.deregister.filter((i) => { return i.sshConnection.config.uniqueId === sshConnection.config.uniqueId; }).length > 0; } function register(sshConnection, sshTunnel, isLast) { var events = [sshConstants_1.default.CHANNEL.SSH, sshConstants_1.default.CHANNEL.TUNNEL]; sshConnection.__sshTunnels = sshConnection.__sshTunnels || []; sshConnection.__sshTunnels.push(sshTunnel); var cbs = events.map((event) => { var cb = (function () { this.emit.apply(this, arguments); }).bind(sshTunnel, event); sshConnection.on(event, cb); return cb; }); var disconnectEvent = `${sshConstants_1.default.CHANNEL.SSH}:${sshConstants_1.default.STATUS.DISCONNECT}`; var disconnectCb = () => { var del; for (var i = 0; i < sshTunnel.config.length; i++) { if (sshTunnel.config[i].uniqueId === sshConnection.config.uniqueId) { del = true; } if (del && SSH2Promise.__cache[sshTunnel.config[i].uniqueId]) { SSH2Promise.__cache[sshTunnel.config[i].uniqueId].close(); delete SSH2Promise.__cache[sshTunnel.config[i].uniqueId]; } } }; events.push(disconnectEvent); cbs.push(disconnectCb); sshConnection.on(disconnectEvent, disconnectCb); return { sshConnection: sshConnection, events: events, close: function () { var idx = sshConnection.__sshTunnels.indexOf(sshTunnel); sshConnection.__sshTunnels.splice(idx, 1); if (sshConnection.__sshTunnels.length > 0) { events.forEach((event, idx) => { sshConnection.removeListener(event, cbs[idx]); }); return Promise.resolve(); } else { if (sshConnection.config.sock) { sshConnection.config.sock.destroy(); } return sshConnection.close().then(() => { events.forEach((event, idx) => { sshConnection.removeListener(event, cbs[idx]); }); }); } } }; } var methods = ['exec', 'spawn', { 'rawSFTP': 'sftp' }, 'shell', 'subsys', 'x11', 'getSocksPort', 'getTunnel', 'addTunnel', 'closeTunnel']; var defaultOptions = { reconnect: true, port: 22, reconnectTries: 10, reconnectDelay: 5000 }; class SSH2Promise extends BaseSSH2Promise_1.default { constructor(options, disableCache) { super(); options = Array.isArray(options) ? options : [options]; this.config = options.map((o) => { o = Object.assign({}, defaultOptions, o); o.uniqueId = o.uniqueId || `${o.username}@${o.host}:${o.port}`; return o; }); this.deregister = []; this.disableCache = disableCache || false; methods.forEach((m) => { var k = typeof m == "string" ? m : Object.keys(m)[0]; this[k] = function () { var params = arguments; return this.connect().then((sshConnection) => { return sshConnection[typeof m == "string" ? m : m[k]].apply(sshConnection, params); }); }.bind(this); }); } /** * Get SFTP session, with promise and async/await */ sftp() { return new sftp_1.default(this); } emit(event, ...args) { var config = sshUtils_1.default.peek(this.config); if (config.debug) { config.debug(arguments); } return super.emit.apply(this, arguments); } /** * Get SSH if existing from cache otherwise create new one * @param {*} sshConfig */ getSSHConnection(sshConfig, isLast) { var ret; if (this.disableCache) { ret = new sshConnection_1.default(sshConfig); } else { if (sshConfig && !SSH2Promise.__cache[sshConfig.uniqueId]) { ret = SSH2Promise.__cache[sshConfig.uniqueId] = new sshConnection_1.default(sshConfig); } ret = SSH2Promise.__cache[sshConfig.uniqueId]; } if (!isRegistered(ret, this)) { this.deregister.push(register(ret, this, isLast)); } return ret.connect().then((ssh) => { ssh.emit(sshConstants_1.default.CHANNEL.SSH, sshConstants_1.default.STATUS.CONNECT); return ssh; }); } /** * Connect SSH connection, via single or multiple hopping connection * @param {*} Single/Array of sshConfigs */ connect() { var lastSSH; for (var i = 0; i < this.config.length; i++) { ((sshConfig, isLast) => { if (!lastSSH) { lastSSH = this.getSSHConnection(sshConfig, isLast); } else { lastSSH = lastSSH.then((ssh) => { if (ssh.config.hoppingTool === sshConstants_1.default.HOPPINGTOOL.SOCAT) { return sshUtils_1.default.checkStreamError(ssh.spawn(`socat - TCP:${sshConfig.host}:${sshConfig.port}`)); } else if (ssh.config.hoppingTool === sshConstants_1.default.HOPPINGTOOL.NATIVE) { return ssh.forwardOut('127.0.0.1', sshUtils_1.default.getRandomPort(), sshConfig.host, sshConfig.port); } else { return sshUtils_1.default.checkStreamError(ssh.spawn(`nc ${sshConfig.host} ${sshConfig.port}`)); } }).then((stream) => { sshConfig.sock = stream; return this.getSSHConnection(sshConfig, isLast); }); } })(this.config[i], i == this.config.length - 1); } return lastSSH; } /** * Close SSH Connection */ close() { return Promise.all(this.deregister.map(f => f.close())); } } /** * For caching SSH Connection */ SSH2Promise.__cache = {}; SSH2Promise.SSH = sshConnection_1.default; SSH2Promise.Utils = sshUtils_1.default; SSH2Promise.SFTP = sftp_1.default; SSH2Promise.Constants = sshConstants_1.default; module.exports = SSH2Promise;