refactoring, socket.io update

more refactoring, code standards, updated socket.io to 1.7.4, increment
release to 0.1.1
This commit is contained in:
billchurch 2017-06-03 16:48:45 -04:00
parent 9dace2501c
commit 7cbfed20e9
21 changed files with 286 additions and 211 deletions

3
.gitignore vendored
View file

@ -3,6 +3,9 @@ logs
*.log *.log
npm-debug.log* npm-debug.log*
# Editor preference files
*.sublime-*
# Runtime data # Runtime data
pids pids
*.pid *.pid

View file

@ -1,4 +1,18 @@
# Change Log # Change Log
## [0.1.1] 2017-06-03
### Added
- `serverlog.client` and `serverlog.server` options added to `config.json` to enable logging of client commands to server log (only client portion implemented at this time)
- morgan express middleware for logging
### Changed
- Updated socket.io to 1.7.4
- continued refactoring, breaking up `index.js`
- revised error handling methods
- revised session termination methods
### Fixed
### Removed
- color console decorations from `util/index.js`
- SanatizeHeaders function from `util/index.js`
## [0.1.0] 2017-05-27 ## [0.1.0] 2017-05-27
### Added ### Added
- This ChangeLog.md file - This ChangeLog.md file
@ -6,7 +20,7 @@
- Snyk, Bithound, Travis CI - Snyk, Bithound, Travis CI
- Cross platform improvements (path mappings) - Cross platform improvements (path mappings)
- Session fixup between Express and Socket.io - Session fixup between Express and Socket.io
- Session secret settings in config.json - Session secret settings in `config.json`
- env variable `DEBUG=ssh2` will put the `ssh2` module into debug mode - env variable `DEBUG=ssh2` will put the `ssh2` module into debug mode
- env variable `DEBUG=WebSSH2` will output additional debug messages for functions - env variable `DEBUG=WebSSH2` will output additional debug messages for functions
and events in the application (not including the ssh2 module debug) and events in the application (not including the ssh2 module debug)
@ -19,7 +33,7 @@ and events in the application (not including the ssh2 module debug)
- error handling in public/client.js - error handling in public/client.js
- moved socket.io operations to their own file /socket/index.js, more changes like this to come (./socket/index.js) - moved socket.io operations to their own file /socket/index.js, more changes like this to come (./socket/index.js)
- all session based variables are now under the req.session.ssh property or socket.request.ssh (./index.js) - all session based variables are now under the req.session.ssh property or socket.request.ssh (./index.js)
- moved SSH algorithms to config.json and defined as a session variable (..session.ssh.algorithms) - moved SSH algorithms to `config.json` and defined as a session variable (..session.ssh.algorithms)
-- prep for future feature to define algorithms in header or some other method to enable separate ciphers per host -- prep for future feature to define algorithms in header or some other method to enable separate ciphers per host
- minified and combined all js files to a single js in `./public/webssh2.min.js` also included a sourcemap `./public/webssh2.min.js` which maps to `./public/webssh2.js` for easier troubleshooting. - minified and combined all js files to a single js in `./public/webssh2.min.js` also included a sourcemap `./public/webssh2.min.js` which maps to `./public/webssh2.js` for easier troubleshooting.
- combined all css files to a single css in `./public/webssh2.css` - combined all css files to a single css in `./public/webssh2.css`
@ -28,7 +42,7 @@ and events in the application (not including the ssh2 module debug)
- sourcemaps of all minified code (in /public/src and /public/src/js) - sourcemaps of all minified code (in /public/src and /public/src/js)
- renamed `client.htm` to `client-full.htm` - renamed `client.htm` to `client-full.htm`
- created `client-min.htm` to serve minified javascript - 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. - 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 ### Fixed
- Multiple errors may overwrite 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. - Multiple errors may overwrite 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.

View file

@ -1,7 +1,7 @@
# WebSSH2 [![GitHub version](https://badge.fury.io/gh/billchurch%2FWebSSH2.svg)](https://badge.fury.io/gh/billchurch%2FWebSSH2) [![Build Status](https://travis-ci.org/billchurch/WebSSH2.svg?branch=master)](https://travis-ci.org/billchurch/WebSSH2) [![Known Vulnerabilities](https://snyk.io/test/github/billchurch/webssh2/badge.svg)](https://snyk.io/test/github/billchurch/webssh2) [![bitHound Overall Score](https://www.bithound.io/github/billchurch/WebSSH2/badges/score.svg)](https://www.bithound.io/github/billchurch/WebSSH2) [![bitHound Dependencies](https://www.bithound.io/github/billchurch/WebSSH2/badges/dependencies.svg)](https://www.bithound.io/github/billchurch/WebSSH2/master/dependencies/npm) [![NSP Status](https://nodesecurity.io/orgs/billchurch/projects/b0a0d9df-1340-43ef-9736-ef983c057764/badge)](https://nodesecurity.io/orgs/billchurch/projects/b0a0d9df-1340-43ef-9736-ef983c057764) # WebSSH2 [![GitHub version](https://badge.fury.io/gh/billchurch%2FWebSSH2.svg)](https://badge.fury.io/gh/billchurch%2FWebSSH2) [![Build Status](https://travis-ci.org/billchurch/WebSSH2.svg?branch=master)](https://travis-ci.org/billchurch/WebSSH2) [![Known Vulnerabilities](https://snyk.io/test/github/billchurch/webssh2/badge.svg)](https://snyk.io/test/github/billchurch/webssh2) [![bitHound Overall Score](https://www.bithound.io/github/billchurch/WebSSH2/badges/score.svg)](https://www.bithound.io/github/billchurch/WebSSH2) [![bitHound Dependencies](https://www.bithound.io/github/billchurch/WebSSH2/badges/dependencies.svg)](https://www.bithound.io/github/billchurch/WebSSH2/master/dependencies/npm) [![NSP Status](https://nodesecurity.io/orgs/billchurch/projects/b0a0d9df-1340-43ef-9736-ef983c057764/badge)](https://nodesecurity.io/orgs/billchurch/projects/b0a0d9df-1340-43ef-9736-ef983c057764)
Web SSH Client using ssh2, socket.io, xterm.js, and express Web SSH Client using ssh2, socket.io, xterm.js, and express
Bare bones example of using SSH2 as a client on a host to proxy a Websocket / Socket.io connection to a SSH2 server. Bare bones example of using SSH2 as a client on a host to proxy a Websocket / Socket.io connection to a SSH2 server.
<img width="1044" alt="Screenshot 2017-03-23 18.13.59" src="https://cloud.githubusercontent.com/assets/1668075/24272639/8ad4fef0-0ff4-11e7-8dd0-72b26605e467.png"> <img width="1044" alt="Screenshot 2017-03-23 18.13.59" src="https://cloud.githubusercontent.com/assets/1668075/24272639/8ad4fef0-0ff4-11e7-8dd0-72b26605e467.png">
@ -29,7 +29,7 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
* **header=** - _string_ - optional header to display on page * **header=** - _string_ - optional header to display on page
* **headerBackground=** - _string_ - optional background color of header to display on page * **headerBackground=** - _string_ - optional background color of header to display on page
## Headers ## Headers
@ -62,7 +62,7 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
* **session.secret** - _string_ - Secret key for cookie encryption. You should change this in production. * **session.secret** - _string_ - Secret key for cookie encryption. You should change this in production.
* **options.challengeButton** - _boolean_ - Challenge button. This option, which is still under development, allows the user to resend the password to the server (in cases of step-up authentication for things like `sudo` or a router `enable` command. * **options.challengeButton** - _boolean_ - Challenge button. This option, which is still under development, allows the user to resend the password to the server (in cases of step-up authentication for things like `sudo` or a router `enable` command.
* **algorithms** - _object_ - This option allows you to explicitly override the default transport layer algorithms used for the connection. Each value must be an array of valid algorithms for that category. The order of the algorithms in the arrays are important, with the most favorable being first. Valid keys: * **algorithms** - _object_ - This option allows you to explicitly override the default transport layer algorithms used for the connection. Each value must be an array of valid algorithms for that category. The order of the algorithms in the arrays are important, with the most favorable being first. Valid keys:
@ -152,6 +152,11 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
* zlib@openssh.com * zlib@openssh.com
* zlib * zlib
* **serverlog.client** - _boolean_ - Enables client command logging on server log (console.log). Very simple at this point, buffers data from client until it receives a line-feed then dumps buffer to console.log with session information for tracking. Will capture anything send from client, including passwords, so use for testing only... Default: false. Example:
* _serverlog.client: GcZDThwA4UahDiKO2gkMYd7YPIfVAEFW/mnf0NUugLMFRHhsWAAAA host: 192.168.99.80 command: ls -lat_
* **serverlog.server** - _boolean_ - not implemented, default: false.
# Experimental client-side logging # Experimental client-side logging
Clicking `Start logging` on the status bar will log all data to the client. A `Download log` option will appear after starting the logging. You may download at any time to the client. You may stop logging at any time my pressing the `Logging - STOP LOG`. Note that clicking the `Start logging` option again will cause the current log to be overwritten, so be sure to download first. Clicking `Start logging` on the status bar will log all data to the client. A `Download log` option will appear after starting the logging. You may download at any time to the client. You may stop logging at any time my pressing the `Logging - STOP LOG`. Note that clicking the `Start logging` option again will cause the current log to be overwritten, so be sure to download first.
@ -162,4 +167,4 @@ http://localhost:2222/ssh/host/192.168.1.1?port=2244&header=My%20Header&color=re
# Tips # Tips
* If you want to add custom JavaScript to the browser client you can either modify `./public/client-(full|min).html` and add a **<script>** element or check out `Gulpfile.js` and add your custom javascript file to the concat task * If you want to add custom JavaScript to the browser client you can either modify `./public/client-(full|min).html` and add a **<script>** element or check out `Gulpfile.js` and add your custom javascript file to the concat task
* BIG-IP Acess Policy Manager (APM) doesn't always care for minified javascript when run in portal mode. Be sure to Set `useminified` option in `config.json` to `false` for these environments * BIG-IP Acess Policy Manager (APM) doesn't always care for minified javascript when run in portal mode. Be sure to Set `useminified` option in `config.json` to `false` for these environments
* Set `useminified` option in `config.json` to `true` to utilize minified javascript * Set `useminified` option in `config.json` to `true` to utilize minified javascript

80
app.js Normal file
View file

@ -0,0 +1,80 @@
// app.js
var path = require('path')
var config = require('read-config')(path.join(__dirname, 'config.json'))
var express = require('express')
var logger = require('morgan')
var session = require('express-session')({
secret: config.session.secret,
name: config.session.name,
resave: true,
saveUninitialized: false,
unset: 'destroy'
})
var app = express()
var server = require('http').Server(app)
var myutil = require('./util')
var validator = require('validator')
var io = require('socket.io')(server, { serveClient: false })
var socket = require('./socket')
var expressOptions = require('./expressOptions')
// express
app.use(session)
app.use(myutil.basicAuth)
if (config.accesslog) app.use(logger('common'))
app.disable('x-powered-by')
// static files
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
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, assign, and validated variables
req.session.ssh = {
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: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) &&
req.query.sshterm) || config.ssh.term,
allowreplay: validator.isBoolean(req.headers.allowreplay + '') || false,
serverlog: {
client: config.serverlog.client || false,
server: config.serverlog.server || 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)
})
// express error handling
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
// expose express session with socket.request.session
io.use(function (socket, next) {
(socket.request.res) ? session(socket.request, socket.request.res, next)
: next()
})
// bring up socket
io.on('connection', socket)
module.exports = {server: server, config: config}

View file

@ -52,5 +52,10 @@
"zlib@openssh.com", "zlib@openssh.com",
"zlib" "zlib"
] ]
} },
} "serverlog": {
"client": false, // proof-of-concept to log commands from client to server
"server": false // not yet implemented
},
"accesslog": false // http style access logging to console.log
}

11
expressOptions.js Normal file
View file

@ -0,0 +1,11 @@
module.exports = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1s',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now())
}
}

View file

@ -1,97 +1,24 @@
// server.js
/* /*
* WebSSH2 - Web to SSH2 gateway * WebSSH2 - Web to SSH2 gateway
* Bill Church - https://github.com/billchurch/WebSSH2 - May 2017 * Bill Church - https://github.com/billchurch/WebSSH2 - May 2017
* *
*/ */
var express = require('express')
var app = express()
var server = require('http').Server(app)
var io = require('socket.io')(server)
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,
resave: true,
saveUninitialized: false,
unset: 'destroy'
})
// express var config = require('./app').config
var expressOptions = { var server = require('./app').server
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) server.listen({ host: config.listen.ip, port: config.listen.port
app.use(myutil.basicAuth)
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
req.session.ssh = {
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: (/^(([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
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
// express error handling
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
// expose express session with socket.request.session
io.use(function (socket, next) {
(socket.request.res) ? session(socket.request, socket.request.res, next) : next()
})
// bring up socket
io.on('connection', socket)
// server
server.listen({
host: config.listen.ip,
port: config.listen.port
}) })
server.on('error', function (err) { server.on('error', function (err) {
if (err.code === 'EADDRINUSE') { if (err.code === 'EADDRINUSE') {
config.listen.port++ config.listen.port++
console.warn('Address in use, retrying on port ' + config.listen.port) console.warn('WebSSH2 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)
} else { } else {
console.log('server.listen ERROR: ' + err.code) console.log('WebSSH2 server.listen ERROR: ' + err.code)
} }
}) })

View file

@ -1,6 +1,6 @@
{ {
"name": "WebSSH2", "name": "WebSSH2",
"version": "0.1.0", "version": "0.1.1",
"ignore": [ "ignore": [
".gitignore" ".gitignore"
], ],
@ -32,8 +32,9 @@
"debug": "^2.6.8", "debug": "^2.6.8",
"express": "^4.15.3", "express": "^4.15.3",
"express-session": "^1.15.3", "express-session": "^1.15.3",
"morgan": "^1.8.2",
"read-config": "^1.6.0", "read-config": "^1.6.0",
"socket.io": "^1.6.0", "socket.io": "^1.7.4",
"ssh2": "^0.5.4", "ssh2": "^0.5.4",
"validator": "^7.0.0" "validator": "^7.0.0"
}, },

View file

@ -11,9 +11,12 @@
<div id="bottomdiv"> <div id="bottomdiv">
<div id="footer"></div> <div id="footer"></div>
<div id="status"></div> <div id="status"></div>
<div id="credentials"><a class="credentials" href="javascript:void(0);" onclick="replayCredentials()">CREDENTIALS</a></div> <div id="credentials"><a class="credentials" href="javascript:void(0);"
<div id="downloadLog"><a class="downloadLog" href="javascript:void(0);" onclick="downloadLog()">Download Log</a></div> onclick="replayCredentials()">CREDENTIALS</a></div>
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a></div> <div id="downloadLog"><a class="downloadLog" href="javascript:void(0);"
onclick="downloadLog()">Download Log</a></div>
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);"
onclick="toggleLog();">Start Log</a></div>
</div> </div>
</div> </div>
</body> </body>

View file

@ -11,9 +11,12 @@
<div id="bottomdiv"> <div id="bottomdiv">
<div id="footer"></div> <div id="footer"></div>
<div id="status"></div> <div id="status"></div>
<div id="credentials"><a class="credentials" href="javascript:void(0);" onclick="replayCredentials()">CREDENTIALS</a></div> <div id="credentials"><a class="credentials" href="javascript:void(0);"
<div id="downloadLog"><a class="downloadLog" href="javascript:void(0);" onclick="downloadLog()">Download Log</a></div> onclick="replayCredentials()">CREDENTIALS</a></div>
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a></div> <div id="downloadLog"><a class="downloadLog" href="javascript:void(0);"
onclick="downloadLog()">Download Log</a></div>
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);"
onclick="toggleLog();">Start Log</a></div>
</div> </div>
</div> </div>
</body> </body>

View file

@ -88,7 +88,7 @@ body {
} }
a.credentials { a.credentials {
color: rgb(51, 51, 51); color: rgb(51, 51, 51);
text-decoration: none; text-decoration: none;
} }
#downloadLog { #downloadLog {
display: inline-block; display: inline-block;
@ -104,7 +104,7 @@ a.credentials {
} }
a.downloadLog { a.downloadLog {
color: rgb(240, 240, 240); color: rgb(240, 240, 240);
text-decoration: none; text-decoration: none;
} }
#toggleLog { #toggleLog {
display: inline-block; display: inline-block;
@ -120,5 +120,5 @@ a.downloadLog {
} }
a.toggleLog { a.toggleLog {
color: rgb(240, 240, 240); color: rgb(240, 240, 240);
text-decoration: none; text-decoration: none;
} }

View file

@ -14,19 +14,27 @@ function replayCredentials () { // eslint-disable-line
function toggleLog () { // eslint-disable-line function toggleLog () { // eslint-disable-line
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
} }
@ -35,7 +43,9 @@ function toggleLog () { // eslint-disable-line
// 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 () { // eslint-disable-line function downloadLog () { // eslint-disable-line
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'
@ -113,7 +123,8 @@ socket.on('connect', function () {
}).on('disconnect', function (err) { }).on('disconnect', function (err) {
if (!errorExists) { if (!errorExists) {
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) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -88,7 +88,7 @@ body {
} }
a.credentials { a.credentials {
color: rgb(51, 51, 51); color: rgb(51, 51, 51);
text-decoration: none; text-decoration: none;
} }
#downloadLog { #downloadLog {
display: inline-block; display: inline-block;
@ -104,7 +104,7 @@ a.credentials {
} }
a.downloadLog { a.downloadLog {
color: rgb(240, 240, 240); color: rgb(240, 240, 240);
text-decoration: none; text-decoration: none;
} }
#toggleLog { #toggleLog {
display: inline-block; display: inline-block;
@ -120,7 +120,7 @@ a.downloadLog {
} }
a.toggleLog { a.toggleLog {
color: rgb(240, 240, 240); color: rgb(240, 240, 240);
text-decoration: none; text-decoration: none;
} }
/** /**

View file

@ -12520,19 +12520,27 @@ function replayCredentials () { // eslint-disable-line
function toggleLog () { // eslint-disable-line function toggleLog () { // eslint-disable-line
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
} }
@ -12541,7 +12549,9 @@ function toggleLog () { // eslint-disable-line
// 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 () { // eslint-disable-line function downloadLog () { // eslint-disable-line
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'
@ -12619,7 +12629,8 @@ socket.on('connect', function () {
}).on('disconnect', function (err) { }).on('disconnect', function (err) {
if (!errorExists) { if (!errorExists) {
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) {

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,5 @@
// socket/index.js
// private // private
var debug = require('debug') var debug = require('debug')
var debugWebSSH2 = require('debug')('WebSSH2') var debugWebSSH2 = require('debug')('WebSSH2')
@ -5,30 +7,7 @@ var SSH = require('ssh2').Client
var termCols, termRows var termCols, termRows
// public // public
module.exports = function (socket) { module.exports = function socket (socket) {
function SSHerror (myFunc, err) {
socket.request.session.error = (socket.request.session.error) || ((err) ? err.message : undefined)
var theError = (socket.request.session.error) ? ': ' + socket.request.session.error : ''
// log unsuccessful login attempt
if (err && (err.level === 'client-authentication')) {
console.log('webssh2 ' + 'error: Authentication failure'.red.bold +
' user=' + socket.request.session.username.yellow.bold.underline +
' from=' + socket.handshake.address.yellow.bold.underline)
}
switch (myFunc) {
case 'STREAM CLOSE':
debugWebSSH2('SSH ' + myFunc + theError.red)
socket.emit('ssherror', 'SSH ' + myFunc + theError)
socket.disconnect(true)
break
default:
debugWebSSH2('SSHerror: default'.red)
debugWebSSH2('SSH ' + myFunc + theError)
socket.emit('ssherror', 'SSH ' + myFunc + theError)
socket.disconnect(true)
}
}
// if websocket connection arrives without an express session, kill it // if websocket connection arrives without an express session, kill it
if (!socket.request.session) { if (!socket.request.session) {
socket.emit('401 UNAUTHORIZED') socket.emit('401 UNAUTHORIZED')
@ -37,19 +16,18 @@ module.exports = function (socket) {
return return
} }
var conn = new SSH() var conn = new SSH()
socket.on('geometry', function (cols, rows) { socket.on('geometry', function socketOnGeometry (cols, rows) {
termCols = cols termCols = cols
termRows = rows termRows = rows
}) })
console.log('webssh2 ' + 'IO ON:'.cyan.bold + ' 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) conn.on('banner', function connOnBanner (data) {
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') data = data.replace(/\r?\n/g, '\r\n')
socket.emit('data', d.toString('binary')) socket.emit('data', data.toString('utf-8'))
}) })
conn.on('ready', function () { conn.on('ready', function connOnReady () {
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) 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('title', 'ssh://' + socket.request.session.ssh.host)
socket.request.session.ssh.header.background && socket.emit('headerBackground', socket.request.session.ssh.header.background) 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.request.session.ssh.header.name && socket.emit('header', socket.request.session.ssh.header.name)
@ -61,25 +39,27 @@ module.exports = function (socket) {
term: socket.request.session.ssh.term, term: socket.request.session.ssh.term,
cols: termCols, cols: termCols,
rows: termRows rows: termRows
}, function (err, stream) { }, function connShell (err, stream) {
if (err) { if (err) {
SSHerror('EXEC ERROR' + err) SSHerror('EXEC ERROR' + err)
conn.end() conn.end()
return return
} }
// poc to log commands from client // poc to log commands from client
// var dataBuffer if (socket.request.session.ssh.serverlog.client) var dataBuffer
socket.on('data', function (data) { socket.on('data', function socketOnData (data) {
stream.write(data) stream.write(data)
// poc to log commands from client // poc to log commands from client
// if (data === '\r') { if (socket.request.session.ssh.serverlog.client) {
// console.log(socket.request.session.id + '/' + socket.id + ' command: ' + socket.request.session.ssh.host + ': ' + dataBuffer) if (data === '\r') {
// dataBuffer = undefined console.log('serverlog.client: ' + socket.request.session.id + '/' + socket.id + ' host: ' + socket.request.session.ssh.host + ' command: ' + dataBuffer)
// } else { dataBuffer = undefined
// dataBuffer = (dataBuffer) ? dataBuffer + data : data } else {
// } dataBuffer = (dataBuffer) ? dataBuffer + data : data
}
}
}) })
socket.on('control', function (controlData) { socket.on('control', function socketOnControl (controlData) {
switch (controlData) { switch (controlData) {
case 'replayCredentials': case 'replayCredentials':
stream.write(socket.request.session.userpassword + '\n') stream.write(socket.request.session.userpassword + '\n')
@ -88,55 +68,82 @@ module.exports = function (socket) {
console.log('controlData: ' + controlData) console.log('controlData: ' + controlData)
} }
}) })
socket.on('disconnecting', function socketOnDisconnecting (reason) { debugWebSSH2('SOCKET DISCONNECTING: ' + reason) })
socket.on('disconnecting', function (reason) { debugWebSSH2('SOCKET DISCONNECTING: ' + reason) }) socket.on('disconnect', function socketOnDisconnect (reason) {
socket.on('disconnect', function (reason) {
debugWebSSH2('SOCKET DISCONNECT: ' + reason) debugWebSSH2('SOCKET DISCONNECT: ' + reason)
err = { message: reason } err = { message: reason }
SSHerror('CLIENT SOCKET DISCONNECT', err) SSHerror('CLIENT SOCKET DISCONNECT', err)
conn.end() conn.end()
// socket.request.session.destroy()
})
socket.on('error', function socketOnError (err) {
SSHerror('SOCKET ERROR', err)
conn.end()
}) })
socket.on('error', function (error) { debugWebSSH2('SOCKET ERROR: ' + JSON.stringify(error)) }) stream.on('data', function streamOnData (data) { socket.emit('data', data.toString('utf-8')) })
stream.on('close', function streamOnClose (code, signal) {
stream.on('data', function (d) { socket.emit('data', d.toString('utf-8')) })
stream.on('close', function (code, signal) {
err = { message: ((code || signal) ? (((code) ? 'CODE: ' + code : '') + ((code && signal) ? ' ' : '') + ((signal) ? 'SIGNAL: ' + signal : '')) : undefined) } err = { message: ((code || signal) ? (((code) ? 'CODE: ' + code : '') + ((code && signal) ? ' ' : '') + ((signal) ? 'SIGNAL: ' + signal : '')) : undefined) }
SSHerror('STREAM CLOSE', err) SSHerror('STREAM CLOSE', err)
conn.end() conn.end()
}) })
stream.stderr.on('data', function streamStderrOnData (data) {
stream.stderr.on('data', function (data) {
console.log('STDERR: ' + data) console.log('STDERR: ' + data)
}) })
}) })
}) })
conn.on('end', function (err) { SSHerror('CONN END BY HOST', err) }) conn.on('end', function connOnEnd (err) { SSHerror('CONN END BY HOST', err) })
conn.on('close', function (err) { SSHerror('CONN CLOSE', err) }) conn.on('close', function connOnClose (err) { SSHerror('CONN CLOSE', err) })
conn.on('error', function (err) { SSHerror('CONN ERROR', err) }) conn.on('error', function connOnError (err) { SSHerror('CONN ERROR', err) })
conn.on('keyboard-interactive', function connOnKeyboardInteractive (name, instructions, instructionsLang, prompts, finish) {
conn.on('keyboard-interactive', function (name, instructions, instructionsLang, prompts, finish) {
debugWebSSH2('conn.on(\'keyboard-interactive\')') debugWebSSH2('conn.on(\'keyboard-interactive\')')
finish([socket.request.session.userpassword]) finish([socket.request.session.userpassword])
}) })
if (socket.request.session.username && socket.request.session.userpassword) { if (socket.request.session.username && socket.request.session.userpassword && socket.request.session.ssh) {
conn.connect({ conn.connect({
host: socket.request.session.ssh.host, host: socket.request.session.ssh.host,
port: socket.request.session.ssh.port, port: socket.request.session.ssh.port,
username: socket.request.session.username, username: socket.request.session.username,
password: socket.request.session.userpassword, password: socket.request.session.userpassword,
tryKeyboard: true, tryKeyboard: true,
// some cisco routers need the these cipher strings
algorithms: socket.request.session.ssh.algorithms, algorithms: socket.request.session.ssh.algorithms,
debug: debug('ssh2') debug: debug('ssh2')
}) })
} else { } 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)) debugWebSSH2('Attempt to connect without session.username/password or session varialbles defined, potentially previously abandoned client session. disconnecting websocket client.\r\nHandshake information: \r\n ' + JSON.stringify(socket.handshake))
socket.emit('statusBackground', 'red') socket.emit('ssherror', 'WEBSOCKET ERROR - Refresh the browser and try again')
socket.emit('status', 'WEBSOCKET ERROR - Reload and try again') socket.request.session.destroy()
socket.disconnect(true) socket.disconnect(true)
} }
/**
* Error handling for various events. Outputs error to client, logs to
* server, destroys session and disconnects socket.
* @param {string} myFunc Function calling this function
* @param {object} err error object or error message
*/
function SSHerror (myFunc, err) {
var theError
if (socket.request.session) {
// we just want the first error of the session to pass to the client
socket.request.session.error = (socket.request.session.error) || ((err) ? err.message : undefined)
theError = (socket.request.session.error) ? ': ' + socket.request.session.error : ''
// log unsuccessful login attempt
if (err && (err.level === 'client-authentication')) {
console.log('WebSSH2 ' + 'error: Authentication failure'.red.bold +
' user=' + socket.request.session.username.yellow.bold.underline +
' from=' + socket.handshake.address.yellow.bold.underline)
} else {
console.log('WebSSH2 Logout: 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('ssherror', 'SSH ' + myFunc + theError)
socket.request.session.destroy()
socket.disconnect(true)
} else {
theError = (err) ? ': ' + err.message : ''
socket.disconnect(true)
}
debugWebSSH2('SSHerror ' + myFunc + theError)
}
} }

View file

@ -88,7 +88,7 @@ body {
} }
a.credentials { a.credentials {
color: rgb(51, 51, 51); color: rgb(51, 51, 51);
text-decoration: none; text-decoration: none;
} }
#downloadLog { #downloadLog {
display: inline-block; display: inline-block;
@ -104,7 +104,7 @@ a.credentials {
} }
a.downloadLog { a.downloadLog {
color: rgb(240, 240, 240); color: rgb(240, 240, 240);
text-decoration: none; text-decoration: none;
} }
#toggleLog { #toggleLog {
display: inline-block; display: inline-block;
@ -120,5 +120,5 @@ a.downloadLog {
} }
a.toggleLog { a.toggleLog {
color: rgb(240, 240, 240); color: rgb(240, 240, 240);
text-decoration: none; text-decoration: none;
} }

View file

@ -14,19 +14,27 @@ function replayCredentials () { // eslint-disable-line
function toggleLog () { // eslint-disable-line function toggleLog () { // eslint-disable-line
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
} }
@ -35,7 +43,9 @@ function toggleLog () { // eslint-disable-line
// 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 () { // eslint-disable-line function downloadLog () { // eslint-disable-line
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'
@ -113,7 +123,8 @@ socket.on('connect', function () {
}).on('disconnect', function (err) { }).on('disconnect', function (err) {
if (!errorExists) { if (!errorExists) {
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) {

View file

@ -1,28 +1,18 @@
// util/index.js
// private // private
require('colors') // allow for color property extensions in log messages require('colors') // allow for color property extensions in log messages
var debug = require('debug')('WebSSH2') var debug = require('debug')('WebSSH2')
var Auth = require('basic-auth') var Auth = require('basic-auth')
var util = require('util')
console.warn = makeColorConsole(console.warn, 'yellow') exports.basicAuth = function basicAuth (req, res, next) {
console.error = makeColorConsole(console.error, 'red')
// public
function makeColorConsole (fct, color) {
return function () {
for (var i in arguments) {
if (arguments[i] instanceof Object) { arguments[i] = util.inspect(arguments[i]) }
}
fct(Array.prototype.join.call(arguments, ' ')[color])
}
}
exports.basicAuth = function (req, res, next) {
var myAuth = Auth(req) var myAuth = Auth(req)
if (myAuth) { if (myAuth) {
req.session.username = myAuth.name req.session.username = myAuth.name
req.session.userpassword = myAuth.pass req.session.userpassword = myAuth.pass
debug('myAuth.name: ' + myAuth.name.yellow.bold.underline + ' and password ' + ((myAuth.pass) ? 'exists'.yellow.bold.underline : 'is blank'.underline.red.bold)) debug('myAuth.name: ' + myAuth.name.yellow.bold.underline +
' and password ' + ((myAuth.pass) ? 'exists'.yellow.bold.underline
: 'is blank'.underline.red.bold))
next() next()
} else { } else {
res.statusCode = 401 res.statusCode = 401
@ -31,10 +21,3 @@ exports.basicAuth = function (req, res, next) {
res.end('Username and password required for web SSH service.') res.end('Username and password required for web SSH service.')
} }
} }
// expects headers to be a JSON object, will replace authroization header with 'Sanatized//Exists'
// we don't want to log basic auth header since it contains a password...
exports.SanatizeHeaders = function (headers) {
if (headers.authorization) { headers.authorization = 'Sanitized//Exists' }
return (headers)
}