From 9f1a7eef83cec1f978be7cac467d23bbb3ba56f5 Mon Sep 17 00:00:00 2001 From: Alexey Kasyanchuk Date: Sat, 17 Mar 2018 19:21:38 +0300 Subject: [PATCH] basic ssh relay functionality --- src/background/isPortReachable.js | 26 +++++++++++ src/background/ssh.js | 73 +++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/background/isPortReachable.js create mode 100644 src/background/ssh.js diff --git a/src/background/isPortReachable.js b/src/background/isPortReachable.js new file mode 100644 index 0000000..5941f14 --- /dev/null +++ b/src/background/isPortReachable.js @@ -0,0 +1,26 @@ +// https://github.com/sindresorhus/is-port-reachable +// Copyright (c) Sindre Sorhus (sindresorhus.com) + +const net = require('net'); + +module.exports = (port, opts) => { + opts = Object.assign({timeout: 1000}, opts); + + return new Promise((resolve => { + const socket = new net.Socket(); + + const onError = () => { + socket.destroy(); + resolve(false); + }; + + socket.setTimeout(opts.timeout); + socket.on('error', onError); + socket.on('timeout', onError); + + socket.connect(port, opts.host, () => { + socket.end(); + resolve(true); + }); + })); +}; diff --git a/src/background/ssh.js b/src/background/ssh.js new file mode 100644 index 0000000..3355fdd --- /dev/null +++ b/src/background/ssh.js @@ -0,0 +1,73 @@ +import appPath from './electronAppPath' +const { spawn } = require('child_process') + +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min)) + min; +} + +let tryies = 5; + +const startSSH = (port, host, user, password, callback) => { + let remotePort = getRandomInt(10000, 65000) + + if(tryies-- <= 0) + { + if(callback) + callback(false) + + return + } + + const options = [ + '-T', + '-R', `0.0.0.0:${remotePort}:127.0.0.1:${port}`, + `${user}@${host}`, + '-pw', password, + '-v' + ] + console.log(options) + + const ssh = spawn(appPath('plink'), options) + + const checkMessage = (data) => { + if(data.includes(`Remote port forwarding from 0.0.0.0:${remotePort}`)) + { + if(data.includes('refused')) + { + ssh.kill() + startSSH(port, host, user, password, callback) + } + else if(data.includes('enabled')) + { + if(callback) + callback({address: host, port: remotePort}) + } + } + } + + ssh.stdout.on('data', (data) => { + console.log(`ssh: ${data}`) + checkMessage(data) + }) + + ssh.stderr.on('data', (data) => { + console.log(`ssh error: ${data}`); + checkMessage(data) + if(data.includes('Password authentication failed')) + { + ssh.kill() + if(callback) + callback(false) + } + }); + + ssh.on('close', (code, signal) => { + if(callback) + callback(false) + console.log(`ssh closed with code ${code} and signal ${signal}`) + }) + + return ssh +} + +export default startSSH \ No newline at end of file