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)
This commit is contained in:
billchurch 2017-05-08 12:03:18 -07:00
parent cef50b870c
commit aad3744552
2 changed files with 235 additions and 235 deletions

272
index.js
View file

@ -4,148 +4,148 @@
* *
*/ */
var express = require('express'), var express = require('express'),
app = express(), app = express(),
cookieParser = require('cookie-parser'), cookieParser = require('cookie-parser'),
server = require('http').Server(app), server = require('http').Server(app),
io = require('socket.io')(server), io = require('socket.io')(server),
path = require('path'), path = require('path'),
basicAuth = require('basic-auth'), basicAuth = require('basic-auth'),
ssh = require('ssh2').Client, ssh = require('ssh2').Client,
readConfig = require('read-config'), readConfig = require('read-config'),
config = readConfig(__dirname + '/config.json'), config = readConfig(path.join(__dirname, 'config.json')),
myError = " - ", myError = ' - ',
termCols, termCols,
termRows; termRows
function logErrors(err, req, res, next) { // function logErrors (err, req, res, next) {
console.error(err.stack); // console.error(err.stack)
next(err); // next(err)
} // }
server.listen({ server.listen({
host: config.listen.ip, host: config.listen.ip,
port: config.listen.port port: config.listen.port
}).on('error', function(err) { }).on('error', function (err) {
if (err.code === 'EADDRINUSE') { if (err.code === 'EADDRINUSE') {
config.listen.port++; config.listen.port++
console.log('Address in use, retrying on port ' + config.listen.port); console.log('Address in use, retrying on port ' + config.listen.port)
setTimeout(function() { setTimeout(function () {
server.listen(config.listen.port); server.listen(config.listen.port)
}, 250); }, 250)
} }
}); })
app.use(express.static(__dirname + '/public')).use(function(req, res, next) { app.use(express.static(path.join(__dirname, 'public'))).use(function (req, res, next) {
var myAuth = basicAuth(req); var myAuth = basicAuth(req)
if (myAuth === undefined) { if (myAuth === undefined) {
res.statusCode = 401; res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"'); res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"')
res.end('Username and password required for web SSH service.'); res.end('Username and password required for web SSH service.')
} else if (myAuth.name === "") { } else if (myAuth.name === '') {
res.statusCode = 401; res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"'); res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"')
res.end('Username and password required for web SSH service.'); res.end('Username and password required for web SSH service.')
} else { } else {
config.user.name = myAuth.name; config.user.name = myAuth.name
config.user.password = myAuth.pass; config.user.password = myAuth.pass
next(); next()
} }
}).use(cookieParser()).get('/ssh/host/:host?', function(req, res) { }).use(cookieParser()).get('/ssh/host/:host?', function (req, res) {
res.sendFile(path.join(__dirname + '/public/client.htm')); res.sendFile(path.join(path.join(__dirname, 'public', 'client.htm')))
config.ssh.host = req.params.host; config.ssh.host = req.params.host
if (typeof req.query.port !== 'undefined' && req.query.port !== null) { if (typeof req.query.port !== 'undefined' && req.query.port !== null) {
config.ssh.port = req.query.port; config.ssh.port = req.query.port
} }
if (typeof req.query.header !== 'undefined' && req.query.header !== null) { if (typeof req.query.header !== 'undefined' && req.query.header !== null) {
config.header.text = req.query.header; config.header.text = req.query.header
} }
if (typeof req.query.headerBackground !== 'undefined' && req.query.headerBackground !== null) { if (typeof req.query.headerBackground !== 'undefined' && req.query.headerBackground !== null) {
config.header.background = req.query.headerBackground; 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('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)); console.log('Headers: ' + JSON.stringify(req.headers))
config.options.allowreplay = req.headers.allowreplay; 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')); }).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) { io.on('connection', function (socket) {
var conn = new ssh(); var conn = new ssh()
socket.on('geometry', function(cols, rows) { socket.on('geometry', function (cols, rows) {
termCols = cols; termCols = cols
termRows = rows; termRows = rows
}); })
conn.on('banner', function(d) { conn.on('banner', function (d) {
//need to convert to cr/lf for proper formatting // need to convert to cr/lf for proper formatting
d = d.replace(/\r?\n/g, "\r\n"); d = d.replace(/\r?\n/g, '\r\n')
socket.emit('data', d.toString('binary')); socket.emit('data', d.toString('binary'))
}).on('ready', function() { }).on('ready', function () {
socket.emit('title', 'ssh://' + config.ssh.host); socket.emit('title', 'ssh://' + config.ssh.host)
socket.emit('headerBackground', config.header.background); socket.emit('headerBackground', config.header.background)
socket.emit('header', config.header.text); socket.emit('header', config.header.text)
socket.emit('footer', 'ssh://' + config.user.name + '@' + config.ssh.host + ':' + config.ssh.port); socket.emit('footer', 'ssh://' + config.user.name + '@' + config.ssh.host + ':' + config.ssh.port)
socket.emit('status', 'SSH CONNECTION ESTABLISHED'); socket.emit('status', 'SSH CONNECTION ESTABLISHED')
socket.emit('statusBackground', 'green'); socket.emit('statusBackground', 'green')
socket.emit('allowreplay', config.options.allowreplay); socket.emit('allowreplay', config.options.allowreplay)
conn.shell({ conn.shell({
term: config.ssh.term, term: config.ssh.term,
cols: termCols, cols: termCols,
rows: termRows rows: termRows
}, function(err, stream) { }, function (err, stream) {
if (err) { if (err) {
console.log(err.message); console.log(err.message)
myError = myError + err.message; myError = myError + err.message
return socket.emit('status', 'SSH EXEC ERROR: ' + err.message).emit('statusBackground', 'red'); return socket.emit('status', 'SSH EXEC ERROR: ' + err.message).emit('statusBackground', 'red')
} }
socket.on('data', function(data) { socket.on('data', function (data) {
stream.write(data); stream.write(data)
}); })
socket.on('control', function(controlData) { socket.on('control', function (controlData) {
switch (controlData) { switch (controlData) {
case 'replayCredentials': case 'replayCredentials':
stream.write(config.user.password + '\n'); stream.write(config.user.password + '\n')
/* falls through */ /* falls through */
default: default:
console.log('controlData: ' + controlData); 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']
} }
}); })
});
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']
}
})
})

View file

@ -1,117 +1,117 @@
var sessionLog, var sessionLog,
sessionLogEnable = false, sessionLogEnable = false,
sessionFooter, sessionFooter,
logDate; logDate
// replay password to server, requires // replay password to server, requires
function replayCredentials() { function replayCredentials () {
socket.emit('control', 'replayCredentials'); socket.emit('control', 'replayCredentials')
console.log("replaying credentials"); console.log('replaying credentials')
return false; 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 // for later download
function toggleLog() { function toggleLog () {
if (sessionLogEnable == true) { if (sessionLogEnable === true) {
sessionLogEnable = false; sessionLogEnable = false
document.getElementById('toggleLog').innerHTML = '<a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a>'; document.getElementById('toggleLog').innerHTML = '<a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a>'
console.log("stopping log, " + sessionLogEnable); console.log('stopping log, ' + sessionLogEnable)
currentDate = new Date(); 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"; 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; logDate = currentDate
return false; return false
} else { } else {
sessionLogEnable = true; sessionLogEnable = true
document.getElementById('toggleLog').innerHTML = '<a class="toggleLog" href="javascript:void(0)" onclick="toggleLog();">Logging - STOP LOG</a>'; document.getElementById('toggleLog').innerHTML = '<a class="toggleLog" href="javascript:void(0)" onclick="toggleLog();">Logging - STOP LOG</a>'
document.getElementById('downloadLog').style.display = 'inline'; document.getElementById('downloadLog').style.display = 'inline'
console.log("starting log, " + sessionLogEnable); console.log('starting log, ' + sessionLogEnable)
currentDate = new Date(); 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"; sessionLog = 'Log Start for ' + sessionFooter + ': ' + currentDate.getFullYear() + '/' + (currentDate.getMonth() + 1) + '/' + currentDate.getDate() + ' @ ' + currentDate.getHours() + ':' + currentDate.getMinutes() + ':' + currentDate.getSeconds() + '\r\n\r\n'
logDate = currentDate; logDate = currentDate
return false; return false
} }
} }
// cross browser method to "download" an element to the local system // cross browser method to "download" an element to the local system
// used for our client-side logging feature // used for our client-side logging feature
function downloadLog() { function downloadLog () {
myFile = "WebSSH2-" + logDate.getFullYear() + (logDate.getMonth() + 1) + logDate.getDate() + "_" + logDate.getHours() + logDate.getMinutes() + logDate.getSeconds() + ".log"; myFile = 'WebSSH2-' + logDate.getFullYear() + (logDate.getMonth() + 1) + logDate.getDate() + '_' + logDate.getHours() + logDate.getMinutes() + logDate.getSeconds() + '.log'
// regex should eliminate escape sequences from being logged. // 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, '')], { var blob = new Blob([sessionLog.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')], {
type: 'text/plain' type: 'text/plain'
}); })
if (window.navigator.msSaveOrOpenBlob) { if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, myFile); window.navigator.msSaveBlob(blob, myFile)
} else { } else {
var elem = window.document.createElement('a'); var elem = window.document.createElement('a')
elem.href = window.URL.createObjectURL(blob); elem.href = window.URL.createObjectURL(blob)
elem.download = myFile; elem.download = myFile
document.body.appendChild(elem); document.body.appendChild(elem)
elem.click(); elem.click()
document.body.removeChild(elem); document.body.removeChild(elem)
} }
} }
document.getElementById('downloadLog').style.display = 'none'; document.getElementById('downloadLog').style.display = 'none'
document.getElementById('credentials').style.display = 'none'; document.getElementById('credentials').style.display = 'none'
var terminalContainer = document.getElementById('terminal-container'), var terminalContainer = document.getElementById('terminal-container'),
term = new Terminal({ term = new Terminal({
cursorBlink: true cursorBlink: true
}), }),
socket, socket,
termid; termid
term.open(terminalContainer); term.open(terminalContainer)
term.fit(); term.fit()
if (document.location.pathname) { if (document.location.pathname) {
var parts = document.location.pathname.split('/'), var parts = document.location.pathname.split('/'),
base = parts.slice(0, parts.length - 1).join('/') + '/', base = parts.slice(0, parts.length - 1).join('/') + '/',
resource = base.substring(1) + 'socket.io'; resource = base.substring(1) + 'socket.io'
socket = io.connect(null, { socket = io.connect(null, {
resource: resource resource: resource
}); })
} else { } else {
socket = io.connect(); socket = io.connect()
} }
socket.on('connect', function() { socket.on('connect', function () {
socket.emit('geometry', term.cols, term.rows); socket.emit('geometry', term.cols, term.rows)
term.on('data', function(data) { term.on('data', function (data) {
socket.emit('data', data); socket.emit('data', data)
}); })
socket.on('title', function(data) { socket.on('title', function (data) {
document.title = data; document.title = data
}).on('status', function(data) { }).on('status', function (data) {
document.getElementById('status').innerHTML = data; document.getElementById('status').innerHTML = data
}).on('headerBackground', function(data) { }).on('headerBackground', function (data) {
document.getElementById('header').style.backgroundColor = data; document.getElementById('header').style.backgroundColor = data
}).on('header', function(data) { }).on('header', function (data) {
document.getElementById('header').innerHTML = data; document.getElementById('header').innerHTML = data
}).on('footer', function(data) { }).on('footer', function (data) {
sessionFooter = data; sessionFooter = data
document.getElementById('footer').innerHTML = data; document.getElementById('footer').innerHTML = data
}).on('statusBackground', function(data) { }).on('statusBackground', function (data) {
document.getElementById('status').style.backgroundColor = data; document.getElementById('status').style.backgroundColor = data
}).on('allowreplay', function(data) { }).on('allowreplay', function (data) {
if (data == 'true') { if (data === 'true') {
console.log('allowreplay: ' + data); console.log('allowreplay: ' + data)
document.getElementById('credentials').style.display = 'inline'; document.getElementById('credentials').style.display = 'inline'
} else { } else {
document.getElementById('credentials').style.display = 'none'; document.getElementById('credentials').style.display = 'none'
} }
}).on('data', function(data) { }).on('data', function (data) {
term.write(data); term.write(data)
if (sessionLogEnable) { if (sessionLogEnable) {
sessionLog = sessionLog + data sessionLog = sessionLog + data
} }
}).on('disconnect', function(err) { }).on('disconnect', function (err) {
document.getElementById('status').style.backgroundColor = 'red'; document.getElementById('status').style.backgroundColor = 'red'
document.getElementById('status').innerHTML = 'WEBSOCKET SERVER DISCONNECTED' + err; document.getElementById('status').innerHTML = 'WEBSOCKET SERVER DISCONNECTED' + err
socket.io.reconnection(false); socket.io.reconnection(false)
}).on('error', function(err) { }).on('error', function (err) {
document.getElementById('status').style.backgroundColor = 'red'; document.getElementById('status').style.backgroundColor = 'red'
document.getElementById('status').innerHTML = 'ERROR ' + err; document.getElementById('status').innerHTML = 'ERROR ' + err
}); })
}); })