error handling fixups
added some additional error handing functions and debugging points - `DEBUG=ssh` will put the ssh2 module into debug mode - `debug=WebSSH2` will output additional debug messages for functions and events in the application (not including the ssh2 module debug) - created socket/index.js to start the process of separating out app functions, just holds error logging function at this point - corrected some events on public/client.js so the primary error cause is not overwritten - ensure that ssh connection is terminated when websocked is disconnected by the client
This commit is contained in:
parent
e3b8ff8189
commit
2c1c3ac911
3 changed files with 85 additions and 59 deletions
107
index.js
107
index.js
|
@ -11,7 +11,9 @@ var path = require('path')
|
|||
var SSH = require('ssh2').Client
|
||||
var config = require('read-config')(path.join(__dirname, 'config.json'))
|
||||
var debug = require('debug')
|
||||
var debugWebSSH2 = debug('WebSSH2')
|
||||
var util = require('./util')
|
||||
var SocketUtil = require('./socket')
|
||||
var session = require('express-session')({
|
||||
secret: config.session.secret,
|
||||
name: config.session.name,
|
||||
|
@ -22,17 +24,7 @@ var termCols, termRows, myError
|
|||
// var LogPrefix
|
||||
// var dataBuffer = ''
|
||||
|
||||
var expressOptions = {
|
||||
dotfiles: 'ignore',
|
||||
etag: false,
|
||||
extensions: ['htm', 'html'],
|
||||
index: false,
|
||||
maxAge: '1s',
|
||||
redirect: false,
|
||||
setHeaders: function (res, path, stat) {
|
||||
res.set('x-timestamp', Date.now())
|
||||
}
|
||||
}
|
||||
// server
|
||||
|
||||
server.listen({
|
||||
host: config.listen.ip,
|
||||
|
@ -51,17 +43,22 @@ server.on('error', function (err) {
|
|||
}
|
||||
})
|
||||
|
||||
// express
|
||||
var expressOptions = {
|
||||
dotfiles: 'ignore',
|
||||
etag: false,
|
||||
extensions: ['htm', 'html'],
|
||||
index: false,
|
||||
maxAge: '1s',
|
||||
redirect: false,
|
||||
setHeaders: function (res, path, stat) {
|
||||
res.set('x-timestamp', Date.now())
|
||||
}
|
||||
}
|
||||
|
||||
app.use(session)
|
||||
app.use(util.basicAuth)
|
||||
|
||||
io.use(function (socket, next) {
|
||||
if (socket.request.res) {
|
||||
session(socket.request, socket.request.res, next)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
app.disable('x-powered-by')
|
||||
|
||||
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
|
||||
|
@ -85,13 +82,32 @@ app.use('/src', express.static(path.join(__dirname, 'node_modules', 'xterm', 'di
|
|||
|
||||
app.use('/addons', express.static(path.join(__dirname, 'node_modules', 'xterm', 'dist', 'addons')))
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
res.status(404).send("Sorry can't find that!")
|
||||
})
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
console.error(err.stack)
|
||||
res.status(500).send('Something broke!')
|
||||
})
|
||||
|
||||
// socket.io
|
||||
|
||||
io.use(function (socket, next) {
|
||||
if (socket.request.res) {
|
||||
session(socket.request, socket.request.res, next)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
io.on('connection', function (socket) {
|
||||
// if websocket connection arrives without an express session, kill it
|
||||
if (!socket.request.session) {
|
||||
socket.disconnect(true)
|
||||
return
|
||||
}
|
||||
|
||||
var socketutil = new SocketUtil(socket, io)
|
||||
var conn = new SSH()
|
||||
socket.on('geometry', function (cols, rows) {
|
||||
termCols = cols
|
||||
|
@ -119,12 +135,9 @@ io.on('connection', function (socket) {
|
|||
rows: termRows
|
||||
}, function (err, stream) {
|
||||
if (err) {
|
||||
console.log(err.message)
|
||||
myError = err.message
|
||||
socket.emit('status', 'SSH EXEC ERROR: ' + err.message)
|
||||
socket.emit('statusBackground', 'red')
|
||||
console.log('conn.shell err: ' + err.message)
|
||||
return socket.close(true)
|
||||
socketutil.SSHerror('EXEC ERROR' + err)
|
||||
conn.end()
|
||||
return
|
||||
}
|
||||
socket.on('data', function (data) {
|
||||
stream.write(data)
|
||||
|
@ -145,15 +158,24 @@ io.on('connection', function (socket) {
|
|||
console.log('controlData: ' + controlData)
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('disconnecting', function (reason) { debugWebSSH2('SOCKET DISCONNECTING: ' + reason) })
|
||||
|
||||
stream.on('data', function (d) {
|
||||
socket.emit('data', d.toString('binary'))
|
||||
socket.on('disconnect', function (reason) {
|
||||
debugWebSSH2('SOCKET DISCONNECT: ' + reason)
|
||||
err = { message: reason }
|
||||
socketutil.SSHerror ('CLIENT SOCKET DISCONNECT', err)
|
||||
conn.end()
|
||||
})
|
||||
|
||||
socket.on('error', function (error) { debugWebSSH2('SOCKET ERROR: ' + JSON.stringify(error)) })
|
||||
|
||||
stream.on('data', function (d) { socket.emit('data', d.toString('binary')) })
|
||||
|
||||
stream.on('close', function (code, signal) {
|
||||
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal)
|
||||
err = { message: ((code||signal) ? (((code)? 'CODE: ' + code: '') + ((code&&signal)? ' ':'') + ((signal)? 'SIGNAL: ' + signal : '')) : undefined) }
|
||||
socketutil.SSHerror('STREAM CLOSE', err)
|
||||
conn.end()
|
||||
socket.disconnect()
|
||||
})
|
||||
|
||||
stream.stderr.on('data', function (data) {
|
||||
|
@ -162,27 +184,12 @@ io.on('connection', function (socket) {
|
|||
})
|
||||
})
|
||||
|
||||
conn.on('end', function () {
|
||||
socket.emit('status', 'SSH CONNECTION CLOSED BY HOST ' + myError)
|
||||
socket.emit('statusBackground', 'red')
|
||||
socket.disconnect()
|
||||
})
|
||||
|
||||
conn.on('close', function () {
|
||||
socket.emit('status', 'SSH CONNECTION CLOSE ' + myError)
|
||||
socket.emit('statusBackground', 'red')
|
||||
socket.disconnect()
|
||||
})
|
||||
|
||||
conn.on('error', function (err) {
|
||||
myError = err
|
||||
socket.emit('status', 'SSH CONNECTION ERROR ' + myError)
|
||||
socket.emit('statusBackground', 'red')
|
||||
console.error('conn.on(\'error\'): ' + myError)
|
||||
})
|
||||
conn.on('end', function (err) { socketutil.SSHerror('CONN END BY HOST', err) })
|
||||
conn.on('close', function (err) { socketutil.SSHerror('CONN CLOSE', err) })
|
||||
conn.on('error', function (err) { socketutil.SSHerror('CONN ERROR', err ) })
|
||||
|
||||
conn.on('keyboard-interactive', function (name, instructions, instructionsLang, prompts, finish) {
|
||||
console.log('Connection :: keyboard-interactive')
|
||||
debugWebSSH2('Connection :: keyboard-interactive')
|
||||
finish([socket.request.session.userpassword])
|
||||
})
|
||||
if (socket.request.session.username && socket.request.session.userpassword) {
|
||||
|
@ -197,7 +204,7 @@ io.on('connection', function (socket) {
|
|||
'cipher': ['aes128-cbc', '3des-cbc', 'aes256-cbc', 'aes128-ctr', 'aes192-ctr', 'aes256-ctr'],
|
||||
'hmac': ['hmac-sha1', 'hmac-sha1-96', 'hmac-md5-96']
|
||||
},
|
||||
debug: debug('WebSSH2:debug')
|
||||
debug: debug('ssh2')
|
||||
})
|
||||
} else {
|
||||
console.warn('Attempt to connect without session.username/password defined, potentially previously abandoned client session. disconnecting websocket client.\r\nHandshake information: \r\n ' + JSON.stringify(socket.handshake))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
var sessionLogEnable = false
|
||||
var sessionLog, sessionFooter, logDate, currentDate, myFile
|
||||
var sessionLog, sessionFooter, logDate, currentDate, myFile, errorExists
|
||||
|
||||
// replay password to server, requires
|
||||
function replayCredentials () {
|
||||
|
@ -84,6 +84,10 @@ socket.on('connect', function () {
|
|||
document.title = data
|
||||
}).on('status', function (data) {
|
||||
document.getElementById('status').innerHTML = data
|
||||
}).on('ssherror', function (data) {
|
||||
document.getElementById('status').innerHTML = data
|
||||
document.getElementById('status').style.backgroundColor = 'red'
|
||||
errorExists = true
|
||||
}).on('headerBackground', function (data) {
|
||||
document.getElementById('header').style.backgroundColor = data
|
||||
}).on('header', function (data) {
|
||||
|
@ -105,12 +109,16 @@ socket.on('connect', function () {
|
|||
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
|
||||
// })
|
||||
}).on('disconnect', function (err) {
|
||||
if (!errorExists) {
|
||||
document.getElementById('status').style.backgroundColor = 'red'
|
||||
document.getElementById('status').innerHTML = 'WEBSOCKET SERVER DISCONNECTED: ' + err
|
||||
}
|
||||
socket.io.reconnection(false)
|
||||
}).on('error', function (err) {
|
||||
if (!errorExists) {
|
||||
document.getElementById('status').style.backgroundColor = 'red'
|
||||
document.getElementById('status').innerHTML = 'ERROR: ' + err
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
11
socket/index.js
Normal file
11
socket/index.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
var myError = myError
|
||||
|
||||
module.exports = function (socket, io) {
|
||||
this.SSHerror = function (myFunc, err) {
|
||||
myError = (myError) ? myError : ((err) ? err.message:undefined)
|
||||
thisError = (myError) ? ': ' + myError : ''
|
||||
console.error('SSH ' + myFunc + thisError)
|
||||
socket.emit('ssherror', 'SSH ' + myFunc + thisError)
|
||||
socket.disconnect(true)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue