updated documents, added validation to user input strings

term= query option to specify TERM environment variable for host, valid
strings are alpha-numeric with a hypen (validated). Otherwise the
default ssh.term variable from `config.json` will be used.
- validation for host (v4,v6,fqdn,hostname), port (integer 2-65535),
and header (sanatized) from URL input
This commit is contained in:
billchurch 2017-05-27 18:12:02 -04:00
parent a0b0ec8632
commit 4540cc6e0e
12 changed files with 30 additions and 20 deletions

View file

@ -2,6 +2,7 @@
## [Unreleased]
### Added
- This ChangeLog.md file
- Support for UTF-8 characters (thanks @bara666)
- Snyk, Bithound, Travis CI
- Cross platform improvements (path mappings)
- Session fixup between Express and Socket.io
@ -11,6 +12,8 @@
and events in the application (not including the ssh2 module debug)
- using Grunt to pull js and css source files from other modules `npm run build` to rebuild these if changed or updated.
- `useminified` option in `config.json` to enable using minified client side javascript (true) defaults to false (non-minified)
- term= query option to specify TERM environment variable for host, valid strings are alpha-numeric with a hypen (validated). Otherwise the default ssh.term variable from `config.json` will be used.
- validation for host (v4,v6,fqdn,hostname), port (integer 2-65535), and header (sanatized) from URL input
### Changed
- error handling in public/client.js
@ -25,10 +28,12 @@ and events in the application (not including the ssh2 module debug)
- sourcemaps of all minified code (in /public/src and /public/src/js)
- renamed `client.htm` to `client-full.htm`
- created `client-min.htm` to serve minified javascript
- if header.text is null in config.json and header is not defined as a get parameter the Header will not be displayed. Both of these must be null / undefined and not specified as get parameters.
### Fixed
- Multiple errors may ovewrite status bar which would cause confusion as to what originally caused the error. Example, ssh server disconnects which prompts a cascade of events (conn.on('end'), socket.on('disconnect'), conn.on('close')) and the original reason (conn.on('end')) would be lost and the user would erroneously receive a WEBSOCKET error as the last event to fire would be the websocket connection closing from the app.
- ensure ssh session is closed when a browser disconnects from the websocket
- if headerBackground is changed, status background is changed to the same color (typo, fixed)
### Removed
- Express Static References directly to module source directories due to concatenating and minifying js/css

View file

@ -23,11 +23,11 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
# Options (GET request vars)
port= - port of SSH server (defaults to 22)
* **port=** - _integer_ - port of SSH server (defaults to 22)
header= - optional header to display on page
* **header=** - _string_ - optional header to display on page
headerBackground= - optional background color of header to display on page
* **headerBackground=** - _string_ - optional background color of header to display on page
# Config File Options
`config.json` contains several options which may be specified to customize to your needs, vs editing the javascript direclty. This is JSON format so mind your spacing, brackets, etc...
@ -48,7 +48,7 @@ headerBackground= - optional background color of header to display on page
* **useminified** - _boolean_ - Choose between ./public/client-full.htm (false/non-minified) or ./public/client-min.htm (true/minified js), defaults to false (non-minified version)
* **header.text** - _string_ - Specify header text, defaults to `My Header` but may also be set to `null`.
* **header.text** - _string_ - Specify header text, defaults to `My Header` but may also be set to `null`. When set to `null` no header bar will be displayed on the client.
* **header.background** - _string_ - Header background, defaults to `green`.

View file

@ -14,7 +14,7 @@
},
"useminified": false,
"header": {
"text": "My Header",
"text": null,
"background": "green"
},
"session": {

View file

@ -11,6 +11,7 @@ var path = require('path')
var config = require('read-config')(path.join(__dirname, 'config.json'))
var myutil = require('./util')
var socket = require('./socket/index.js')
var validator = require('validator')
var session = require('express-session')({
secret: config.session.secret,
name: config.session.name,
@ -40,17 +41,21 @@ app.disable('x-powered-by')
app.get('/ssh/host/:host?', function (req, res, next) {
res.sendFile(path.join(path.join(__dirname, 'public', (config.useminified) ? 'client-min.htm' : 'client-full.htm')))
// capture and assign variables
myHost = validator.isIP(req.params.host) ? req.params.host : undefined
console.log('req.params.host: ', myHost)
req.session.ssh = {
host: req.params.host || config.ssh.host,
port: req.query.port || config.ssh.port,
host: validator.isIP(req.params.host + '') && req.params.host || validator.isFQDN(req.params.host) && req.params.host || /^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.params.host) && req.params.host || config.ssh.host,
port: validator.isInt(req.query.port + '', {min: 1, max: 65535}) && req.query.port || config.ssh.port,
header: {
name: req.query.header || config.header.text,
background: req.query.headerBackground || config.header.background
},
algorithms: config.algorithms,
term: config.ssh.term,
allowreplay: req.headers.allowreplay || false
term: /^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) && req.query.sshterm || config.ssh.term,
allowreplay: validator.isBoolean(req.headers.allowreplay + '') || false
}
req.session.ssh.header.name && validator.escape(req.session.ssh.header.name)
req.session.ssh.header.background && validator.escape(req.session.ssh.header.background)
})
// static files

View file

@ -34,7 +34,8 @@
"express-session": "^1.15.3",
"read-config": "^1.6.0",
"socket.io": "^1.6.0",
"ssh2": "^0.5.4"
"ssh2": "^0.5.4",
"validator": "^7.0.0"
},
"scripts": {
"start": "node index",

View file

@ -99,7 +99,7 @@ socket.on('connect', function () {
}).on('statusBackground', function (data) {
document.getElementById('status').style.backgroundColor = data
}).on('allowreplay', function (data) {
if (data === 'true') {
if (data == true) {
console.log('allowreplay: ' + data)
document.getElementById('credentials').style.display = 'inline'
} else {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -12605,7 +12605,7 @@ socket.on('connect', function () {
}).on('statusBackground', function (data) {
document.getElementById('status').style.backgroundColor = data
}).on('allowreplay', function (data) {
if (data === 'true') {
if (data == true) {
console.log('allowreplay: ' + data)
document.getElementById('credentials').style.display = 'inline'
} else {

File diff suppressed because one or more lines are too long

View file

@ -51,13 +51,12 @@ module.exports = function (socket) {
conn.on('ready', function () {
console.log('webssh2 Login: user=' + socket.request.session.username + ' from=' + socket.handshake.address + ' host=' + socket.request.session.ssh.host + ' port=' + socket.request.session.ssh.port + ' sessionID=' + socket.request.sessionID + '/' + socket.id + ' allowreplay=' + socket.request.session.ssh.allowreplay + ' term=' + socket.request.session.ssh.term)
socket.emit('title', 'ssh://' + socket.request.session.ssh.host)
socket.emit('headerBackground', socket.request.session.ssh.header.background)
socket.emit('header', socket.request.session.ssh.header.name)
socket.request.session.ssh.header.background && socket.emit('headerBackground', socket.request.session.ssh.header.background)
socket.request.session.ssh.header.name && socket.emit('header', socket.request.session.ssh.header.name)
socket.emit('footer', 'ssh://' + socket.request.session.username + '@' + socket.request.session.ssh.host + ':' + socket.request.session.ssh.port)
socket.emit('status', 'SSH CONNECTION ESTABLISHED')
socket.emit('statusBackground', socket.request.session.ssh.header.background)
socket.emit('statusBackground', 'green')
socket.emit('allowreplay', socket.request.session.ssh.allowreplay)
conn.shell({
term: socket.request.session.ssh.term,
cols: termCols,

View file

@ -99,7 +99,7 @@ socket.on('connect', function () {
}).on('statusBackground', function (data) {
document.getElementById('status').style.backgroundColor = data
}).on('allowreplay', function (data) {
if (data === 'true') {
if (data == true) {
console.log('allowreplay: ' + data)
document.getElementById('credentials').style.display = 'inline'
} else {