Skip to content

Commit 7cbfed2

Browse files
committed
refactoring, socket.io update
more refactoring, code standards, updated socket.io to 1.7.4, increment release to 0.1.1
1 parent 9dace25 commit 7cbfed2

21 files changed

Lines changed: 286 additions & 211 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ logs
33
*.log
44
npm-debug.log*
55

6+
# Editor preference files
7+
*.sublime-*
8+
69
# Runtime data
710
pids
811
*.pid

ChangeLog.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
# Change Log
2+
## [0.1.1] 2017-06-03
3+
### Added
4+
- `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)
5+
- morgan express middleware for logging
6+
### Changed
7+
- Updated socket.io to 1.7.4
8+
- continued refactoring, breaking up `index.js`
9+
- revised error handling methods
10+
- revised session termination methods
11+
### Fixed
12+
### Removed
13+
- color console decorations from `util/index.js`
14+
- SanatizeHeaders function from `util/index.js`
15+
216
## [0.1.0] 2017-05-27
317
### Added
418
- This ChangeLog.md file
519
- Support for UTF-8 characters (thanks @bara666)
620
- Snyk, Bithound, Travis CI
721
- Cross platform improvements (path mappings)
822
- Session fixup between Express and Socket.io
9-
- Session secret settings in config.json
23+
- Session secret settings in `config.json`
1024
- env variable `DEBUG=ssh2` will put the `ssh2` module into debug mode
1125
- env variable `DEBUG=WebSSH2` will output additional debug messages for functions
1226
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)
1933
- error handling in public/client.js
2034
- moved socket.io operations to their own file /socket/index.js, more changes like this to come (./socket/index.js)
2135
- all session based variables are now under the req.session.ssh property or socket.request.ssh (./index.js)
22-
- moved SSH algorithms to config.json and defined as a session variable (..session.ssh.algorithms)
36+
- moved SSH algorithms to `config.json` and defined as a session variable (..session.ssh.algorithms)
2337
-- prep for future feature to define algorithms in header or some other method to enable separate ciphers per host
2438
- 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.
2539
- 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)
2842
- sourcemaps of all minified code (in /public/src and /public/src/js)
2943
- renamed `client.htm` to `client-full.htm`
3044
- created `client-min.htm` to serve minified javascript
31-
- 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.
45+
- 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.
3246

3347
### Fixed
3448
- 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.

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# 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)
22
Web SSH Client using ssh2, socket.io, xterm.js, and express
33

4-
Bare bones example of using SSH2 as a client on a host to proxy a Websocket / Socket.io connection to a SSH2 server.
4+
Bare bones example of using SSH2 as a client on a host to proxy a Websocket / Socket.io connection to a SSH2 server.
55

66
<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">
77

@@ -29,7 +29,7 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
2929

3030
* **header=** - _string_ - optional header to display on page
3131

32-
* **headerBackground=** - _string_ - optional background color of header to display on page
32+
* **headerBackground=** - _string_ - optional background color of header to display on page
3333

3434
## Headers
3535

@@ -62,7 +62,7 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
6262

6363
* **session.secret** - _string_ - Secret key for cookie encryption. You should change this in production.
6464

65-
* **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.
65+
* **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.
6666

6767
* **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:
6868

@@ -152,6 +152,11 @@ You will be prompted for credentials to use on the SSH server via HTTP Basic aut
152152
* zlib@openssh.com
153153
* zlib
154154

155+
* **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:
156+
* _serverlog.client: GcZDThwA4UahDiKO2gkMYd7YPIfVAEFW/mnf0NUugLMFRHhsWAAAA host: 192.168.99.80 command: ls -lat_
157+
158+
* **serverlog.server** - _boolean_ - not implemented, default: false.
159+
155160
# Experimental client-side logging
156161
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.
157162

@@ -162,4 +167,4 @@ http://localhost:2222/ssh/host/192.168.1.1?port=2244&header=My%20Header&color=re
162167
# Tips
163168
* 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
164169
* 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
165-
* Set `useminified` option in `config.json` to `true` to utilize minified javascript
170+
* Set `useminified` option in `config.json` to `true` to utilize minified javascript

app.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// app.js
2+
3+
var path = require('path')
4+
var config = require('read-config')(path.join(__dirname, 'config.json'))
5+
var express = require('express')
6+
var logger = require('morgan')
7+
var session = require('express-session')({
8+
secret: config.session.secret,
9+
name: config.session.name,
10+
resave: true,
11+
saveUninitialized: false,
12+
unset: 'destroy'
13+
})
14+
var app = express()
15+
var server = require('http').Server(app)
16+
var myutil = require('./util')
17+
var validator = require('validator')
18+
var io = require('socket.io')(server, { serveClient: false })
19+
var socket = require('./socket')
20+
var expressOptions = require('./expressOptions')
21+
22+
// express
23+
app.use(session)
24+
app.use(myutil.basicAuth)
25+
if (config.accesslog) app.use(logger('common'))
26+
app.disable('x-powered-by')
27+
28+
// static files
29+
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
30+
31+
app.get('/ssh/host/:host?', function (req, res, next) {
32+
res.sendFile(path.join(path.join(__dirname, 'public', (config.useminified)
33+
? 'client-min.htm' : 'client-full.htm')))
34+
// capture, assign, and validated variables
35+
req.session.ssh = {
36+
host: (validator.isIP(req.params.host + '') && req.params.host) ||
37+
(validator.isFQDN(req.params.host) && req.params.host) ||
38+
(/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.params.host) &&
39+
req.params.host) || config.ssh.host,
40+
port: (validator.isInt(req.query.port + '', {min: 1, max: 65535}) &&
41+
req.query.port) || config.ssh.port,
42+
header: {
43+
name: req.query.header || config.header.text,
44+
background: req.query.headerBackground || config.header.background
45+
},
46+
algorithms: config.algorithms,
47+
term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) &&
48+
req.query.sshterm) || config.ssh.term,
49+
allowreplay: validator.isBoolean(req.headers.allowreplay + '') || false,
50+
serverlog: {
51+
client: config.serverlog.client || false,
52+
server: config.serverlog.server || false
53+
}
54+
}
55+
req.session.ssh.header.name && validator.escape(req.session.ssh.header.name)
56+
req.session.ssh.header.background &&
57+
validator.escape(req.session.ssh.header.background)
58+
})
59+
60+
// express error handling
61+
app.use(function (req, res, next) {
62+
res.status(404).send("Sorry can't find that!")
63+
})
64+
65+
app.use(function (err, req, res, next) {
66+
console.error(err.stack)
67+
res.status(500).send('Something broke!')
68+
})
69+
70+
// socket.io
71+
// expose express session with socket.request.session
72+
io.use(function (socket, next) {
73+
(socket.request.res) ? session(socket.request, socket.request.res, next)
74+
: next()
75+
})
76+
77+
// bring up socket
78+
io.on('connection', socket)
79+
80+
module.exports = {server: server, config: config}

config.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,10 @@
5252
"zlib@openssh.com",
5353
"zlib"
5454
]
55-
}
56-
}
55+
},
56+
"serverlog": {
57+
"client": false, // proof-of-concept to log commands from client to server
58+
"server": false // not yet implemented
59+
},
60+
"accesslog": false // http style access logging to console.log
61+
}

expressOptions.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
dotfiles: 'ignore',
3+
etag: false,
4+
extensions: ['htm', 'html'],
5+
index: false,
6+
maxAge: '1s',
7+
redirect: false,
8+
setHeaders: function (res, path, stat) {
9+
res.set('x-timestamp', Date.now())
10+
}
11+
}

index.js

Lines changed: 6 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,24 @@
1+
// server.js
12
/*
23
* WebSSH2 - Web to SSH2 gateway
34
* Bill Church - https://github.com/billchurch/WebSSH2 - May 2017
45
*
56
*/
6-
var express = require('express')
7-
var app = express()
8-
var server = require('http').Server(app)
9-
var io = require('socket.io')(server)
10-
var path = require('path')
11-
var config = require('read-config')(path.join(__dirname, 'config.json'))
12-
var myutil = require('./util')
13-
var socket = require('./socket/index.js')
14-
var validator = require('validator')
15-
var session = require('express-session')({
16-
secret: config.session.secret,
17-
name: config.session.name,
18-
resave: true,
19-
saveUninitialized: false,
20-
unset: 'destroy'
21-
})
22-
23-
// express
24-
var expressOptions = {
25-
dotfiles: 'ignore',
26-
etag: false,
27-
extensions: ['htm', 'html'],
28-
index: false,
29-
maxAge: '1s',
30-
redirect: false,
31-
setHeaders: function (res, path, stat) {
32-
res.set('x-timestamp', Date.now())
33-
}
34-
}
35-
36-
app.use(session)
37-
app.use(myutil.basicAuth)
38-
39-
app.disable('x-powered-by')
40-
41-
app.get('/ssh/host/:host?', function (req, res, next) {
42-
res.sendFile(path.join(path.join(__dirname, 'public', (config.useminified) ? 'client-min.htm' : 'client-full.htm')))
43-
// capture and assign variables
44-
req.session.ssh = {
45-
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,
46-
port: (validator.isInt(req.query.port + '', {min: 1, max: 65535}) && req.query.port) || config.ssh.port,
47-
header: {
48-
name: req.query.header || config.header.text,
49-
background: req.query.headerBackground || config.header.background
50-
},
51-
algorithms: config.algorithms,
52-
term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) && req.query.sshterm) || config.ssh.term,
53-
allowreplay: validator.isBoolean(req.headers.allowreplay + '') || false
54-
}
55-
req.session.ssh.header.name && validator.escape(req.session.ssh.header.name)
56-
req.session.ssh.header.background && validator.escape(req.session.ssh.header.background)
57-
})
58-
59-
// static files
60-
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
61-
62-
// express error handling
63-
app.use(function (req, res, next) {
64-
res.status(404).send("Sorry can't find that!")
65-
})
66-
67-
app.use(function (err, req, res, next) {
68-
console.error(err.stack)
69-
res.status(500).send('Something broke!')
70-
})
71-
72-
// socket.io
73-
// expose express session with socket.request.session
74-
io.use(function (socket, next) {
75-
(socket.request.res) ? session(socket.request, socket.request.res, next) : next()
76-
})
777

78-
// bring up socket
79-
io.on('connection', socket)
8+
var config = require('./app').config
9+
var server = require('./app').server
8010

81-
// server
82-
server.listen({
83-
host: config.listen.ip,
84-
port: config.listen.port
11+
server.listen({ host: config.listen.ip, port: config.listen.port
8512
})
8613

8714
server.on('error', function (err) {
8815
if (err.code === 'EADDRINUSE') {
8916
config.listen.port++
90-
console.warn('Address in use, retrying on port ' + config.listen.port)
17+
console.warn('WebSSH2 Address in use, retrying on port ' + config.listen.port)
9118
setTimeout(function () {
9219
server.listen(config.listen.port)
9320
}, 250)
9421
} else {
95-
console.log('server.listen ERROR: ' + err.code)
22+
console.log('WebSSH2 server.listen ERROR: ' + err.code)
9623
}
9724
})

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "WebSSH2",
3-
"version": "0.1.0",
3+
"version": "0.1.1",
44
"ignore": [
55
".gitignore"
66
],
@@ -32,8 +32,9 @@
3232
"debug": "^2.6.8",
3333
"express": "^4.15.3",
3434
"express-session": "^1.15.3",
35+
"morgan": "^1.8.2",
3536
"read-config": "^1.6.0",
36-
"socket.io": "^1.6.0",
37+
"socket.io": "^1.7.4",
3738
"ssh2": "^0.5.4",
3839
"validator": "^7.0.0"
3940
},

public/client-full.htm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
<div id="bottomdiv">
1212
<div id="footer"></div>
1313
<div id="status"></div>
14-
<div id="credentials"><a class="credentials" href="javascript:void(0);" onclick="replayCredentials()">CREDENTIALS</a></div>
15-
<div id="downloadLog"><a class="downloadLog" href="javascript:void(0);" onclick="downloadLog()">Download Log</a></div>
16-
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a></div>
14+
<div id="credentials"><a class="credentials" href="javascript:void(0);"
15+
onclick="replayCredentials()">CREDENTIALS</a></div>
16+
<div id="downloadLog"><a class="downloadLog" href="javascript:void(0);"
17+
onclick="downloadLog()">Download Log</a></div>
18+
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);"
19+
onclick="toggleLog();">Start Log</a></div>
1720
</div>
1821
</div>
1922
</body>

public/client-min.htm

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
1111
<div id="bottomdiv">
1212
<div id="footer"></div>
1313
<div id="status"></div>
14-
<div id="credentials"><a class="credentials" href="javascript:void(0);" onclick="replayCredentials()">CREDENTIALS</a></div>
15-
<div id="downloadLog"><a class="downloadLog" href="javascript:void(0);" onclick="downloadLog()">Download Log</a></div>
16-
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a></div>
14+
<div id="credentials"><a class="credentials" href="javascript:void(0);"
15+
onclick="replayCredentials()">CREDENTIALS</a></div>
16+
<div id="downloadLog"><a class="downloadLog" href="javascript:void(0);"
17+
onclick="downloadLog()">Download Log</a></div>
18+
<div id="toggleLog"><a class="toggleLog" href="javascript:void(0);"
19+
onclick="toggleLog();">Start Log</a></div>
1720
</div>
1821
</div>
1922
</body>

0 commit comments

Comments
 (0)