From aad3744552ba6c925008f8e23367c3398134ac21 Mon Sep 17 00:00:00 2001 From: billchurch Date: Mon, 8 May 2017 12:03:18 -0700 Subject: [PATCH] codelint and cross platform improvements Used [standard](https://github.com/feross/standard) to lint some of the code. Cross-platform directory handling (updated references to filesystem paths to use path.join) --- index.js | 274 +++++++++++++++++++++++------------------------ public/client.js | 196 ++++++++++++++++----------------- 2 files changed, 235 insertions(+), 235 deletions(-) diff --git a/index.js b/index.js index 9264974..1628572 100644 --- a/index.js +++ b/index.js @@ -1,151 +1,151 @@ /* * WebSSH2 - Web to SSH2 gateway * Bill Church - https://github.com/billchurch - April 2016 - * + * */ var express = require('express'), - app = express(), - cookieParser = require('cookie-parser'), - server = require('http').Server(app), - io = require('socket.io')(server), - path = require('path'), - basicAuth = require('basic-auth'), - ssh = require('ssh2').Client, - readConfig = require('read-config'), - config = readConfig(__dirname + '/config.json'), - myError = " - ", - termCols, - termRows; + app = express(), + cookieParser = require('cookie-parser'), + server = require('http').Server(app), + io = require('socket.io')(server), + path = require('path'), + basicAuth = require('basic-auth'), + ssh = require('ssh2').Client, + readConfig = require('read-config'), + config = readConfig(path.join(__dirname, 'config.json')), + myError = ' - ', + termCols, + termRows -function logErrors(err, req, res, next) { - console.error(err.stack); - next(err); -} +// function logErrors (err, req, res, next) { +// console.error(err.stack) +// next(err) +// } server.listen({ - host: config.listen.ip, - port: config.listen.port -}).on('error', function(err) { - if (err.code === 'EADDRINUSE') { - config.listen.port++; - console.log('Address in use, retrying on port ' + config.listen.port); - setTimeout(function() { - server.listen(config.listen.port); - }, 250); - } -}); + host: config.listen.ip, + port: config.listen.port +}).on('error', function (err) { + if (err.code === 'EADDRINUSE') { + config.listen.port++ + console.log('Address in use, retrying on port ' + config.listen.port) + setTimeout(function () { + server.listen(config.listen.port) + }, 250) + } +}) -app.use(express.static(__dirname + '/public')).use(function(req, res, next) { - var myAuth = basicAuth(req); - if (myAuth === undefined) { - res.statusCode = 401; - res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"'); - res.end('Username and password required for web SSH service.'); - } else if (myAuth.name === "") { - res.statusCode = 401; - res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"'); - res.end('Username and password required for web SSH service.'); - } else { - config.user.name = myAuth.name; - config.user.password = myAuth.pass; - next(); - } -}).use(cookieParser()).get('/ssh/host/:host?', function(req, res) { - res.sendFile(path.join(__dirname + '/public/client.htm')); - config.ssh.host = req.params.host; - if (typeof req.query.port !== 'undefined' && req.query.port !== null) { - config.ssh.port = req.query.port; - } - if (typeof req.query.header !== 'undefined' && req.query.header !== null) { - config.header.text = req.query.header; - } - if (typeof req.query.headerBackground !== 'undefined' && req.query.headerBackground !== null) { - config.header.background = req.query.headerBackground; - } - console.log('webssh2 Login: user=' + config.user.name + ' from=' + req.ip + ' host=' + config.ssh.host + ' port=' + config.ssh.port + ' sessionID=' + req.headers.sessionid + ' allowreplay=' + req.headers.allowreplay); - console.log('Headers: ' + JSON.stringify(req.headers)); - config.options.allowreplay = req.headers.allowreplay; -}).use('/style', express.static(__dirname + '/public')).use('/src', express.static(__dirname + '/node_modules/xterm/dist')).use('/addons', express.static(__dirname + '/node_modules/xterm/dist/addons')); +app.use(express.static(path.join(__dirname, 'public'))).use(function (req, res, next) { + var myAuth = basicAuth(req) + if (myAuth === undefined) { + res.statusCode = 401 + res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"') + res.end('Username and password required for web SSH service.') + } else if (myAuth.name === '') { + res.statusCode = 401 + res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"') + res.end('Username and password required for web SSH service.') + } else { + config.user.name = myAuth.name + config.user.password = myAuth.pass + next() + } +}).use(cookieParser()).get('/ssh/host/:host?', function (req, res) { + res.sendFile(path.join(path.join(__dirname, 'public', 'client.htm'))) + config.ssh.host = req.params.host + if (typeof req.query.port !== 'undefined' && req.query.port !== null) { + config.ssh.port = req.query.port + } + if (typeof req.query.header !== 'undefined' && req.query.header !== null) { + config.header.text = req.query.header + } + if (typeof req.query.headerBackground !== 'undefined' && req.query.headerBackground !== null) { + config.header.background = req.query.headerBackground + } + console.log('webssh2 Login: user=' + config.user.name + ' from=' + req.ip + ' host=' + config.ssh.host + ' port=' + config.ssh.port + ' sessionID=' + req.headers.sessionid + ' allowreplay=' + req.headers.allowreplay) + console.log('Headers: ' + JSON.stringify(req.headers)) + config.options.allowreplay = req.headers.allowreplay +}).use('/style', express.static(path.join(__dirname, 'public'))).use('/src', express.static(path.join(__dirname, 'node_modules', 'xterm', 'dist'))).use('/addons', express.static(path.join(__dirname, 'node_modules', 'xterm', 'dist', 'addons'))) -io.on('connection', function(socket) { - var conn = new ssh(); - socket.on('geometry', function(cols, rows) { - termCols = cols; - termRows = rows; - }); +io.on('connection', function (socket) { + var conn = new ssh() + socket.on('geometry', function (cols, rows) { + termCols = cols + termRows = rows + }) - conn.on('banner', function(d) { - //need to convert to cr/lf for proper formatting - d = d.replace(/\r?\n/g, "\r\n"); - socket.emit('data', d.toString('binary')); - }).on('ready', function() { - socket.emit('title', 'ssh://' + config.ssh.host); - socket.emit('headerBackground', config.header.background); - socket.emit('header', config.header.text); - socket.emit('footer', 'ssh://' + config.user.name + '@' + config.ssh.host + ':' + config.ssh.port); - socket.emit('status', 'SSH CONNECTION ESTABLISHED'); - socket.emit('statusBackground', 'green'); - socket.emit('allowreplay', config.options.allowreplay); + conn.on('banner', function (d) { + // need to convert to cr/lf for proper formatting + d = d.replace(/\r?\n/g, '\r\n') + socket.emit('data', d.toString('binary')) + }).on('ready', function () { + socket.emit('title', 'ssh://' + config.ssh.host) + socket.emit('headerBackground', config.header.background) + socket.emit('header', config.header.text) + socket.emit('footer', 'ssh://' + config.user.name + '@' + config.ssh.host + ':' + config.ssh.port) + socket.emit('status', 'SSH CONNECTION ESTABLISHED') + socket.emit('statusBackground', 'green') + socket.emit('allowreplay', config.options.allowreplay) - conn.shell({ - term: config.ssh.term, - cols: termCols, - rows: termRows - }, function(err, stream) { - if (err) { - console.log(err.message); - myError = myError + err.message; - return socket.emit('status', 'SSH EXEC ERROR: ' + err.message).emit('statusBackground', 'red'); - } - socket.on('data', function(data) { - stream.write(data); - }); - socket.on('control', function(controlData) { - switch (controlData) { - case 'replayCredentials': - stream.write(config.user.password + '\n'); + conn.shell({ + term: config.ssh.term, + cols: termCols, + rows: termRows + }, function (err, stream) { + if (err) { + console.log(err.message) + myError = myError + err.message + return socket.emit('status', 'SSH EXEC ERROR: ' + err.message).emit('statusBackground', 'red') + } + socket.on('data', function (data) { + stream.write(data) + }) + socket.on('control', function (controlData) { + switch (controlData) { + case 'replayCredentials': + stream.write(config.user.password + '\n') /* falls through */ - default: - console.log('controlData: ' + controlData); - } - }); - - stream.on('data', function(d) { - socket.emit('data', d.toString('binary')); - }).on('close', function(code, signal) { - console.log('Stream :: close :: code: ' + code + ', signal: ' + signal); - conn.end(); - socket.disconnect(); - }).stderr.on('data', function(data) { - console.log('STDERR: ' + data); - }); - }); - }).on('end', function() { - socket.emit('status', 'SSH CONNECTION CLOSED BY HOST' + myError); - socket.emit('statusBackground', 'red'); - socket.disconnect(); - }).on('close', function() { - socket.emit('status', 'SSH CONNECTION CLOSE' + myError); - socket.emit('statusBackground', 'red'); - socket.disconnect(); - }).on('error', function(err) { - myError = myError + err; - socket.emit('status', 'SSH CONNECTION ERROR' + myError); - socket.emit('statusBackground', 'red'); - console.log('on.error' + myError); - }).on('keyboard-interactive', function(name, instructions, instructionsLang, prompts, finish) { - console.log('Connection :: keyboard-interactive'); - finish([config.user.password]); - }).connect({ - host: config.ssh.host, - port: config.ssh.port, - username: config.user.name, - password: config.user.password, - tryKeyboard: true, - // some cisco routers need the these cipher strings - algorithms: { - 'cipher': ['aes128-cbc', '3des-cbc', 'aes256-cbc'], - 'hmac': ['hmac-sha1', 'hmac-sha1-96', 'hmac-md5-96'] + default: + console.log('controlData: ' + controlData) } - }); -}); \ No newline at end of file + }) + + stream.on('data', function (d) { + socket.emit('data', d.toString('binary')) + }).on('close', function (code, signal) { + console.log('Stream :: close :: code: ' + code + ', signal: ' + signal) + conn.end() + socket.disconnect() + }).stderr.on('data', function (data) { + console.log('STDERR: ' + data) + }) + }) + }).on('end', function () { + socket.emit('status', 'SSH CONNECTION CLOSED BY HOST' + myError) + socket.emit('statusBackground', 'red') + socket.disconnect() + }).on('close', function () { + socket.emit('status', 'SSH CONNECTION CLOSE' + myError) + socket.emit('statusBackground', 'red') + socket.disconnect() + }).on('error', function (err) { + myError = myError + err + socket.emit('status', 'SSH CONNECTION ERROR' + myError) + socket.emit('statusBackground', 'red') + console.log('on.error' + myError) + }).on('keyboard-interactive', function (name, instructions, instructionsLang, prompts, finish) { + console.log('Connection :: keyboard-interactive') + finish([config.user.password]) + }).connect({ + host: config.ssh.host, + port: config.ssh.port, + username: config.user.name, + password: config.user.password, + tryKeyboard: true, + // some cisco routers need the these cipher strings + algorithms: { + 'cipher': ['aes128-cbc', '3des-cbc', 'aes256-cbc'], + 'hmac': ['hmac-sha1', 'hmac-sha1-96', 'hmac-md5-96'] + } + }) +}) diff --git a/public/client.js b/public/client.js index beb0661..8f24d3f 100644 --- a/public/client.js +++ b/public/client.js @@ -1,117 +1,117 @@ var sessionLog, - sessionLogEnable = false, - sessionFooter, - logDate; + sessionLogEnable = false, + sessionFooter, + logDate -// replay password to server, requires -function replayCredentials() { - socket.emit('control', 'replayCredentials'); - console.log("replaying credentials"); - return false; +// replay password to server, requires +function replayCredentials () { + socket.emit('control', 'replayCredentials') + console.log('replaying credentials') + return false } -// Set variable to toggle log data from client/server to a varialble +// Set variable to toggle log data from client/server to a varialble // for later download -function toggleLog() { - if (sessionLogEnable == true) { - sessionLogEnable = false; - document.getElementById('toggleLog').innerHTML = 'Start Log'; - console.log("stopping log, " + sessionLogEnable); - currentDate = new Date(); - sessionLog = sessionLog + "\r\n\r\nLog End for " + sessionFooter + ": " + currentDate.getFullYear() + "/" + (currentDate.getMonth() + 1) + "/" + currentDate.getDate() + " @ " + currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds() + "\r\n"; - logDate = currentDate; - return false; - } else { - sessionLogEnable = true; - document.getElementById('toggleLog').innerHTML = 'Logging - STOP LOG'; - document.getElementById('downloadLog').style.display = 'inline'; - console.log("starting log, " + sessionLogEnable); - currentDate = new Date(); - sessionLog = "Log Start for " + sessionFooter + ": " + currentDate.getFullYear() + "/" + (currentDate.getMonth() + 1) + "/" + currentDate.getDate() + " @ " + currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds() + "\r\n\r\n"; - logDate = currentDate; - return false; - } +function toggleLog () { + if (sessionLogEnable === true) { + sessionLogEnable = false + document.getElementById('toggleLog').innerHTML = 'Start Log' + console.log('stopping log, ' + sessionLogEnable) + currentDate = new Date() + sessionLog = sessionLog + '\r\n\r\nLog End for ' + sessionFooter + ': ' + currentDate.getFullYear() + '/' + (currentDate.getMonth() + 1) + '/' + currentDate.getDate() + ' @ ' + currentDate.getHours() + ':' + currentDate.getMinutes() + ':' + currentDate.getSeconds() + '\r\n' + logDate = currentDate + return false + } else { + sessionLogEnable = true + document.getElementById('toggleLog').innerHTML = 'Logging - STOP LOG' + document.getElementById('downloadLog').style.display = 'inline' + console.log('starting log, ' + sessionLogEnable) + currentDate = new Date() + sessionLog = 'Log Start for ' + sessionFooter + ': ' + currentDate.getFullYear() + '/' + (currentDate.getMonth() + 1) + '/' + currentDate.getDate() + ' @ ' + currentDate.getHours() + ':' + currentDate.getMinutes() + ':' + currentDate.getSeconds() + '\r\n\r\n' + logDate = currentDate + return false + } } // cross browser method to "download" an element to the local system // used for our client-side logging feature -function downloadLog() { - myFile = "WebSSH2-" + logDate.getFullYear() + (logDate.getMonth() + 1) + logDate.getDate() + "_" + logDate.getHours() + logDate.getMinutes() + logDate.getSeconds() + ".log"; +function downloadLog () { + myFile = 'WebSSH2-' + logDate.getFullYear() + (logDate.getMonth() + 1) + logDate.getDate() + '_' + logDate.getHours() + logDate.getMinutes() + logDate.getSeconds() + '.log' // regex should eliminate escape sequences from being logged. - var blob = new Blob([sessionLog.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')], { - type: 'text/plain' - }); - if (window.navigator.msSaveOrOpenBlob) { - window.navigator.msSaveBlob(blob, myFile); - } else { - var elem = window.document.createElement('a'); - elem.href = window.URL.createObjectURL(blob); - elem.download = myFile; - document.body.appendChild(elem); - elem.click(); - document.body.removeChild(elem); - } + var blob = new Blob([sessionLog.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')], { + type: 'text/plain' + }) + if (window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveBlob(blob, myFile) + } else { + var elem = window.document.createElement('a') + elem.href = window.URL.createObjectURL(blob) + elem.download = myFile + document.body.appendChild(elem) + elem.click() + document.body.removeChild(elem) + } } -document.getElementById('downloadLog').style.display = 'none'; -document.getElementById('credentials').style.display = 'none'; +document.getElementById('downloadLog').style.display = 'none' +document.getElementById('credentials').style.display = 'none' var terminalContainer = document.getElementById('terminal-container'), - term = new Terminal({ - cursorBlink: true - }), - socket, - termid; -term.open(terminalContainer); -term.fit(); + term = new Terminal({ + cursorBlink: true + }), + socket, + termid +term.open(terminalContainer) +term.fit() if (document.location.pathname) { - var parts = document.location.pathname.split('/'), - base = parts.slice(0, parts.length - 1).join('/') + '/', - resource = base.substring(1) + 'socket.io'; - socket = io.connect(null, { - resource: resource - }); + var parts = document.location.pathname.split('/'), + base = parts.slice(0, parts.length - 1).join('/') + '/', + resource = base.substring(1) + 'socket.io' + socket = io.connect(null, { + resource: resource + }) } else { - socket = io.connect(); + socket = io.connect() } -socket.on('connect', function() { - socket.emit('geometry', term.cols, term.rows); - term.on('data', function(data) { - socket.emit('data', data); - }); - socket.on('title', function(data) { - document.title = data; - }).on('status', function(data) { - document.getElementById('status').innerHTML = data; - }).on('headerBackground', function(data) { - document.getElementById('header').style.backgroundColor = data; - }).on('header', function(data) { - document.getElementById('header').innerHTML = data; - }).on('footer', function(data) { - sessionFooter = data; - document.getElementById('footer').innerHTML = data; - }).on('statusBackground', function(data) { - document.getElementById('status').style.backgroundColor = data; - }).on('allowreplay', function(data) { - if (data == 'true') { - console.log('allowreplay: ' + data); - document.getElementById('credentials').style.display = 'inline'; - } else { - document.getElementById('credentials').style.display = 'none'; - } - }).on('data', function(data) { - term.write(data); - if (sessionLogEnable) { - sessionLog = sessionLog + data - } - }).on('disconnect', function(err) { - document.getElementById('status').style.backgroundColor = 'red'; - document.getElementById('status').innerHTML = 'WEBSOCKET SERVER DISCONNECTED' + err; - socket.io.reconnection(false); - }).on('error', function(err) { - document.getElementById('status').style.backgroundColor = 'red'; - document.getElementById('status').innerHTML = 'ERROR ' + err; - }); -}); +socket.on('connect', function () { + socket.emit('geometry', term.cols, term.rows) + term.on('data', function (data) { + socket.emit('data', data) + }) + socket.on('title', function (data) { + document.title = data + }).on('status', function (data) { + document.getElementById('status').innerHTML = data + }).on('headerBackground', function (data) { + document.getElementById('header').style.backgroundColor = data + }).on('header', function (data) { + document.getElementById('header').innerHTML = data + }).on('footer', function (data) { + sessionFooter = data + document.getElementById('footer').innerHTML = data + }).on('statusBackground', function (data) { + document.getElementById('status').style.backgroundColor = data + }).on('allowreplay', function (data) { + if (data === 'true') { + console.log('allowreplay: ' + data) + document.getElementById('credentials').style.display = 'inline' + } else { + document.getElementById('credentials').style.display = 'none' + } + }).on('data', function (data) { + term.write(data) + if (sessionLogEnable) { + sessionLog = sessionLog + data + } + }).on('disconnect', function (err) { + document.getElementById('status').style.backgroundColor = 'red' + document.getElementById('status').innerHTML = 'WEBSOCKET SERVER DISCONNECTED' + err + socket.io.reconnection(false) + }).on('error', function (err) { + document.getElementById('status').style.backgroundColor = 'red' + document.getElementById('status').innerHTML = 'ERROR ' + err + }) +})