minification and concatenation
minification and concatenation of javascript and css. added new feature to specify minification in config.json (use minified) updated readme and changelog tasks in grunt to build minified and concatenated files
This commit is contained in:
parent
481cebfab5
commit
7b6d060bc3
24 changed files with 30161 additions and 23 deletions
14
ChangeLog.md
14
ChangeLog.md
|
@ -9,18 +9,30 @@
|
||||||
- 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)
|
||||||
|
- 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)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- erorr 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 algorithims in header or some other method to enable seperate ciphers per host
|
-- prep for future feature to define algorithims in header or some other method to enable seperate 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.
|
||||||
|
- combined all css files to a single css in `./public/webssh2.css`
|
||||||
|
- minified all css files to a single css in `./public/webssh2.min.css`
|
||||||
|
- copied all unmodified source css and js to /public/src/css and /public/src/js respectively (for troubleshooting/etc)
|
||||||
|
- 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
|
||||||
|
|
||||||
### Fixed
|
### 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.
|
- 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
|
- ensure ssh session is closed when a browser disconnects from the websocket
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Express Static References directly to module source directories due to concatenating and minifying js/css
|
||||||
|
|
||||||
## [0.0.5] - 2017-0323
|
## [0.0.5] - 2017-0323
|
||||||
### Added
|
### Added
|
||||||
- Added experimental support for logging (see Readme)
|
- Added experimental support for logging (see Readme)
|
||||||
|
|
73
Gruntfile.js
Normal file
73
Gruntfile.js
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
module.exports = function (grunt) {
|
||||||
|
// Project configuration.
|
||||||
|
grunt.initConfig({
|
||||||
|
pkg: grunt.file.readJSON('package.json'),
|
||||||
|
copy: {
|
||||||
|
main: {
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
expand: true,
|
||||||
|
flatten: true,
|
||||||
|
src: [
|
||||||
|
'node_modules/xterm/dist/xterm.css',
|
||||||
|
'src/css/style.css'
|
||||||
|
],
|
||||||
|
dest: 'public/src/css'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expand: true,
|
||||||
|
flatten: true,
|
||||||
|
src: [
|
||||||
|
'node_modules/xterm/dist/xterm.js',
|
||||||
|
'node_modules/xterm/dist/xterm.js.map',
|
||||||
|
'node_modules/xterm/dist/addons/fit/fit.js',
|
||||||
|
'node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js',
|
||||||
|
'node_modules/socket.io/node_modules/socket.io-client/dist/socket.io.js.map',
|
||||||
|
'src/js/client.js'
|
||||||
|
],
|
||||||
|
dest: 'public/src/js'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
concat: {
|
||||||
|
options: {
|
||||||
|
sourceMap: true,
|
||||||
|
sourceMapName: 'public/src/webssh2.concat.map',
|
||||||
|
sourceMapStyle: 'embed'
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
src: ['public/src/css/*.css'],
|
||||||
|
dest: 'public/webssh2.css'
|
||||||
|
},
|
||||||
|
js: {
|
||||||
|
src: [
|
||||||
|
'public/src/js/xterm.js',
|
||||||
|
'public/src/js/fit.js',
|
||||||
|
'public/src/js/socket.io.js',
|
||||||
|
'public/src/js/client.js'
|
||||||
|
],
|
||||||
|
dest: 'public/webssh2.js'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uglify: {
|
||||||
|
options: {
|
||||||
|
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||||
|
sourceMap: true,
|
||||||
|
sourceMapName: 'public/src/webssh2.min.map'
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
src: ['public/src/js/xterm.js', 'public/src/js/fit.js', 'public/src/js/socket.io.js', 'public/src/js/client.js'],
|
||||||
|
dest: 'public/webssh2.min.js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Load the plugin that provides the "uglify" task.
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-copy')
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-concat')
|
||||||
|
grunt.loadNpmTasks('grunt-contrib-uglify')
|
||||||
|
|
||||||
|
// Default task(s).
|
||||||
|
grunt.registerTask('default', ['copy', 'concat', 'uglify'])
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ Bare bones example of using SSH2 as a client on a host to proxy a Websocket / So
|
||||||
# Instructions
|
# Instructions
|
||||||
To install:
|
To install:
|
||||||
|
|
||||||
1. Clone to a location somewhere and `npm install`
|
1. Clone to a location somewhere and `npm install --production`. If you want to develop and rebuild javascript and other files utilize `npm install` instead.
|
||||||
|
|
||||||
2. If desired, edit config.json to change the listener to your liking. There are also some default options which may be definied for a few of the variables.
|
2. If desired, edit config.json to change the listener to your liking. There are also some default options which may be definied for a few of the variables.
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ headerBackground= - optional background color of header to display on page
|
||||||
|
|
||||||
* **ssh.term** - _string_ - Specify terminal emulation to use, defaults to `xterm-color`
|
* **ssh.term** - _string_ - Specify terminal emulation to use, defaults to `xterm-color`
|
||||||
|
|
||||||
|
* **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`.
|
||||||
|
|
||||||
* **header.background** - _string_ - Header background, defaults to `green`.
|
* **header.background** - _string_ - Header background, defaults to `green`.
|
||||||
|
@ -151,3 +153,7 @@ Clicking `Start logging` on the status bar will log all data to the client. A `D
|
||||||
|
|
||||||
http://localhost:2222/ssh/host/192.168.1.1?port=2244&header=My%20Header&color=red
|
http://localhost:2222/ssh/host/192.168.1.1?port=2244&header=My%20Header&color=red
|
||||||
|
|
||||||
|
# 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
|
||||||
|
* 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
|
|
@ -12,6 +12,7 @@
|
||||||
"port": 22,
|
"port": 22,
|
||||||
"term": "xterm-color"
|
"term": "xterm-color"
|
||||||
},
|
},
|
||||||
|
"useminified": false,
|
||||||
"header": {
|
"header": {
|
||||||
"text": "My Header",
|
"text": "My Header",
|
||||||
"background": "green"
|
"background": "green"
|
||||||
|
|
7
index.js
7
index.js
|
@ -9,8 +9,6 @@ var server = require('http').Server(app)
|
||||||
var io = require('socket.io')(server)
|
var io = require('socket.io')(server)
|
||||||
var path = require('path')
|
var path = require('path')
|
||||||
var config = require('read-config')(path.join(__dirname, 'config.json'))
|
var config = require('read-config')(path.join(__dirname, 'config.json'))
|
||||||
// var debug = require('debug')
|
|
||||||
// var debugWebSSH2 = debug('WebSSH2')
|
|
||||||
var myutil = require('./util')
|
var myutil = require('./util')
|
||||||
var socket = require('./socket/index.js')
|
var socket = require('./socket/index.js')
|
||||||
var session = require('express-session')({
|
var session = require('express-session')({
|
||||||
|
@ -40,7 +38,7 @@ app.use(myutil.basicAuth)
|
||||||
app.disable('x-powered-by')
|
app.disable('x-powered-by')
|
||||||
|
|
||||||
app.get('/ssh/host/:host?', function (req, res, next) {
|
app.get('/ssh/host/:host?', function (req, res, next) {
|
||||||
res.sendFile(path.join(path.join(__dirname, 'public', 'client.htm')))
|
res.sendFile(path.join(path.join(__dirname, 'public', (config.useminified) ? 'client-min.htm' : 'client-full.htm')))
|
||||||
// capture and assign variables
|
// capture and assign variables
|
||||||
req.session.ssh = {
|
req.session.ssh = {
|
||||||
host: req.params.host || config.ssh.host,
|
host: req.params.host || config.ssh.host,
|
||||||
|
@ -57,9 +55,6 @@ app.get('/ssh/host/:host?', function (req, res, next) {
|
||||||
|
|
||||||
// static files
|
// static files
|
||||||
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
|
app.use(express.static(path.join(__dirname, 'public'), expressOptions))
|
||||||
app.use('/style', express.static(path.join(__dirname, 'public')))
|
|
||||||
app.use('/src', express.static(path.join(__dirname, 'node_modules', 'xterm', 'dist')))
|
|
||||||
app.use('/addons', express.static(path.join(__dirname, 'node_modules', 'xterm', 'dist', 'addons')))
|
|
||||||
|
|
||||||
// express error handling
|
// express error handling
|
||||||
app.use(function (req, res, next) {
|
app.use(function (req, res, next) {
|
||||||
|
|
22
package.json
22
package.json
|
@ -34,17 +34,31 @@
|
||||||
"express-session": "^1.15.3",
|
"express-session": "^1.15.3",
|
||||||
"read-config": "^1.6.0",
|
"read-config": "^1.6.0",
|
||||||
"socket.io": "^1.6.0",
|
"socket.io": "^1.6.0",
|
||||||
"ssh2": "^0.5.4",
|
"ssh2": "^0.5.4"
|
||||||
"xterm": "^2.6.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node index",
|
"start": "node index",
|
||||||
"test": "snyk test",
|
"test": "snyk test",
|
||||||
"watch": "nodemon index.js"
|
"watch": "nodemon index.js",
|
||||||
|
"build": "grunt copy concat uglify",
|
||||||
|
"standard": "standard --verbose | snazzy"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bithound": "^1.7.0",
|
"bithound": "^1.7.0",
|
||||||
|
"grunt": "^1.0.1",
|
||||||
|
"grunt-contrib-concat": "^1.0.1",
|
||||||
|
"grunt-contrib-copy": "^1.0.0",
|
||||||
|
"grunt-contrib-uglify": "^3.0.1",
|
||||||
"nodemon": "^1.11.0",
|
"nodemon": "^1.11.0",
|
||||||
"snyk": "^1.30.1"
|
"snazzy": "^7.0.0",
|
||||||
|
"snyk": "^1.30.1",
|
||||||
|
"standard": "^10.0.2",
|
||||||
|
"xterm": "^2.6.0"
|
||||||
|
},
|
||||||
|
"standard": {
|
||||||
|
"ignore": [
|
||||||
|
"public/webssh2.js",
|
||||||
|
"public/src/js/*.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Web SSH</title>
|
<title>Web SSH</title>
|
||||||
<link rel="stylesheet" href="/src/xterm.css" />
|
<link rel="stylesheet" href="/webssh2.css" />
|
||||||
<link rel="stylesheet" href="/style/style.css" />
|
<script src="/webssh2.js" defer></script>
|
||||||
<script src="/socket.io/socket.io.js" defer></script>
|
|
||||||
<script src="/src/xterm.js" defer></script>
|
|
||||||
<script src="/addons/fit/fit.js" defer></script>
|
|
||||||
<script src="/client.js" defer></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="box">
|
<div class="box">
|
20
public/client-min.htm
Normal file
20
public/client-min.htm
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Web SSH</title>
|
||||||
|
<link rel="stylesheet" href="/webssh2.css" />
|
||||||
|
<script src="/webssh2.min.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="box">
|
||||||
|
<div id="header"></div>
|
||||||
|
<div id="terminal-container" class="terminal"></div>
|
||||||
|
<div id="bottomdiv">
|
||||||
|
<div id="footer"></div>
|
||||||
|
<div id="status"></div>
|
||||||
|
<div id="credentials"><a class="credentials" href="javascript:void(0);" onclick="replayCredentials()">CREDENTIALS</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>
|
||||||
|
</body>
|
||||||
|
</html>
|
2247
public/src/css/xterm.css
Normal file
2247
public/src/css/xterm.css
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,9 @@
|
||||||
|
/* global io, Terminal, Blob */
|
||||||
var sessionLogEnable = false
|
var sessionLogEnable = false
|
||||||
var sessionLog, sessionFooter, logDate, currentDate, myFile, errorExists
|
var sessionLog, sessionFooter, logDate, currentDate, myFile, errorExists
|
||||||
|
|
||||||
// replay password to server, requires
|
// replay password to server, requires
|
||||||
function replayCredentials () {
|
function replayCredentials () { // eslint-disable-line
|
||||||
socket.emit('control', 'replayCredentials')
|
socket.emit('control', 'replayCredentials')
|
||||||
console.log('replaying credentials')
|
console.log('replaying credentials')
|
||||||
return false
|
return false
|
||||||
|
@ -10,7 +11,7 @@ function replayCredentials () {
|
||||||
|
|
||||||
// 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 () { // 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>'
|
||||||
|
@ -33,7 +34,7 @@ function toggleLog () {
|
||||||
|
|
||||||
// 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 () { // 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, '')], {
|
||||||
|
@ -58,7 +59,7 @@ var terminalContainer = document.getElementById('terminal-container')
|
||||||
var term = new Terminal({
|
var term = new Terminal({
|
||||||
cursorBlink: true
|
cursorBlink: true
|
||||||
})
|
})
|
||||||
var socket, termid
|
var socket, termid // eslint-disable-line
|
||||||
term.open(terminalContainer, {
|
term.open(terminalContainer, {
|
||||||
focus: true
|
focus: true
|
||||||
})
|
})
|
86
public/src/js/fit.js
Normal file
86
public/src/js/fit.js
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* Fit terminal columns and rows to the dimensions of its DOM element.
|
||||||
|
*
|
||||||
|
* ## Approach
|
||||||
|
* - Rows: Truncate the division of the terminal parent element height by the terminal row height.
|
||||||
|
*
|
||||||
|
* - Columns: Truncate the division of the terminal parent element width by the terminal character
|
||||||
|
* width (apply display: inline at the terminal row and truncate its width with the current
|
||||||
|
* number of columns).
|
||||||
|
* @module xterm/addons/fit/fit
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function (fit) {
|
||||||
|
if (typeof exports === 'object' && typeof module === 'object') {
|
||||||
|
/*
|
||||||
|
* CommonJS environment
|
||||||
|
*/
|
||||||
|
module.exports = fit(require('../../xterm'));
|
||||||
|
} else if (typeof define == 'function') {
|
||||||
|
/*
|
||||||
|
* Require.js is available
|
||||||
|
*/
|
||||||
|
define(['../../xterm'], fit);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Plain browser environment
|
||||||
|
*/
|
||||||
|
fit(window.Terminal);
|
||||||
|
}
|
||||||
|
})(function (Xterm) {
|
||||||
|
var exports = {};
|
||||||
|
|
||||||
|
exports.proposeGeometry = function (term) {
|
||||||
|
if (!term.element.parentElement) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var parentElementStyle = window.getComputedStyle(term.element.parentElement),
|
||||||
|
parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')),
|
||||||
|
parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17),
|
||||||
|
elementStyle = window.getComputedStyle(term.element),
|
||||||
|
elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||||
|
elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')),
|
||||||
|
availableHeight = parentElementHeight - elementPaddingVer,
|
||||||
|
availableWidth = parentElementWidth - elementPaddingHor,
|
||||||
|
container = term.rowContainer,
|
||||||
|
subjectRow = term.rowContainer.firstElementChild,
|
||||||
|
contentBuffer = subjectRow.innerHTML,
|
||||||
|
characterHeight,
|
||||||
|
rows,
|
||||||
|
characterWidth,
|
||||||
|
cols,
|
||||||
|
geometry;
|
||||||
|
|
||||||
|
subjectRow.style.display = 'inline';
|
||||||
|
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
|
||||||
|
characterWidth = subjectRow.getBoundingClientRect().width;
|
||||||
|
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
|
||||||
|
characterHeight = subjectRow.getBoundingClientRect().height;
|
||||||
|
subjectRow.innerHTML = contentBuffer;
|
||||||
|
|
||||||
|
rows = parseInt(availableHeight / characterHeight);
|
||||||
|
cols = parseInt(availableWidth / characterWidth);
|
||||||
|
|
||||||
|
geometry = {cols: cols, rows: rows};
|
||||||
|
return geometry;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.fit = function (term) {
|
||||||
|
var geometry = exports.proposeGeometry(term);
|
||||||
|
|
||||||
|
if (geometry) {
|
||||||
|
term.resize(geometry.cols, geometry.rows);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Xterm.prototype.proposeGeometry = function () {
|
||||||
|
return exports.proposeGeometry(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
Xterm.prototype.fit = function () {
|
||||||
|
return exports.fit(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
});
|
8201
public/src/js/socket.io.js
Normal file
8201
public/src/js/socket.io.js
Normal file
File diff suppressed because it is too large
Load diff
1
public/src/js/socket.io.js.map
Normal file
1
public/src/js/socket.io.js.map
Normal file
File diff suppressed because one or more lines are too long
3
public/src/js/socket.io.min.js
vendored
Normal file
3
public/src/js/socket.io.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4219
public/src/js/xterm.js
Normal file
4219
public/src/js/xterm.js
Normal file
File diff suppressed because it is too large
Load diff
1
public/src/js/xterm.js.map
Normal file
1
public/src/js/xterm.js.map
Normal file
File diff suppressed because one or more lines are too long
1
public/src/webssh2.concat.map
Normal file
1
public/src/webssh2.concat.map
Normal file
File diff suppressed because one or more lines are too long
1
public/src/webssh2.min.map
Normal file
1
public/src/webssh2.min.map
Normal file
File diff suppressed because one or more lines are too long
2374
public/webssh2.css
Normal file
2374
public/webssh2.css
Normal file
File diff suppressed because it is too large
Load diff
12633
public/webssh2.js
Normal file
12633
public/webssh2.js
Normal file
File diff suppressed because it is too large
Load diff
4
public/webssh2.min.js
vendored
Normal file
4
public/webssh2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
124
src/css/style.css
Normal file
124
src/css/style.css
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
body {
|
||||||
|
font-family: helvetica, sans-serif, arial;
|
||||||
|
font-size: 1em;
|
||||||
|
color: #111;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
background-color: rgb(0, 128, 0);
|
||||||
|
width: 100%;
|
||||||
|
border-color: white;
|
||||||
|
border-style: none none solid none;
|
||||||
|
border-width: 1px;
|
||||||
|
text-align: center;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal-container {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal-container .terminal {
|
||||||
|
background-color: #000000;
|
||||||
|
color: #fafafa;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#terminal-container .terminal:focus .terminal-cursor {
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bottomdiv {
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(50, 50, 50);
|
||||||
|
border-color: white;
|
||||||
|
border-style: solid none none none;
|
||||||
|
border-width: 1px;
|
||||||
|
z-index: 99;
|
||||||
|
flex: 0 1 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
display: inline-block;
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
background-color: rgb(50, 50, 50);
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
display: inline-block;
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
background-color: rgb(50, 50, 50);
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-color: white;
|
||||||
|
border-style: none solid none solid;
|
||||||
|
border-width: 1px;
|
||||||
|
text-align: left;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
#credentials {
|
||||||
|
display: inline-block;
|
||||||
|
color: rgb(51, 51, 51);
|
||||||
|
background-color: rgb(255, 127, 0);
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-color: white;
|
||||||
|
border-style: none solid none none;
|
||||||
|
border-width: 1px;
|
||||||
|
text-align: left;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
a.credentials {
|
||||||
|
color: rgb(51, 51, 51);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#downloadLog {
|
||||||
|
display: inline-block;
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
background-color: rgb(255, 127, 0);
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-color: white;
|
||||||
|
border-style: none solid none none;
|
||||||
|
border-width: 1px;
|
||||||
|
text-align: left;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
a.downloadLog {
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
#toggleLog {
|
||||||
|
display: inline-block;
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
background-color: rgb(0, 127, 0);
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-color: white;
|
||||||
|
border-style: none solid none none;
|
||||||
|
border-width: 1px;
|
||||||
|
text-align: left;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
a.toggleLog {
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
125
src/js/client.js
Normal file
125
src/js/client.js
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/* global io, Terminal, Blob */
|
||||||
|
var sessionLogEnable = false
|
||||||
|
var sessionLog, sessionFooter, logDate, currentDate, myFile, errorExists
|
||||||
|
|
||||||
|
// replay password to server, requires
|
||||||
|
function replayCredentials () { // eslint-disable-line
|
||||||
|
socket.emit('control', 'replayCredentials')
|
||||||
|
console.log('replaying credentials')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set variable to toggle log data from client/server to a varialble
|
||||||
|
// for later download
|
||||||
|
function toggleLog () { // eslint-disable-line
|
||||||
|
if (sessionLogEnable === true) {
|
||||||
|
sessionLogEnable = false
|
||||||
|
document.getElementById('toggleLog').innerHTML = '<a class="toggleLog" href="javascript:void(0);" onclick="toggleLog();">Start Log</a>'
|
||||||
|
console.log('stopping log, ' + sessionLogEnable)
|
||||||
|
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'
|
||||||
|
logDate = currentDate
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
sessionLogEnable = true
|
||||||
|
document.getElementById('toggleLog').innerHTML = '<a class="toggleLog" href="javascript:void(0)" onclick="toggleLog();">Logging - STOP LOG</a>'
|
||||||
|
document.getElementById('downloadLog').style.display = 'inline'
|
||||||
|
console.log('starting log, ' + sessionLogEnable)
|
||||||
|
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'
|
||||||
|
logDate = currentDate
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross browser method to "download" an element to the local system
|
||||||
|
// used for our client-side logging feature
|
||||||
|
function downloadLog () { // eslint-disable-line
|
||||||
|
myFile = 'WebSSH2-' + logDate.getFullYear() + (logDate.getMonth() + 1) + logDate.getDate() + '_' + logDate.getHours() + logDate.getMinutes() + logDate.getSeconds() + '.log'
|
||||||
|
// 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, '')], {
|
||||||
|
type: 'text/plain'
|
||||||
|
})
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) {
|
||||||
|
window.navigator.msSaveBlob(blob, myFile)
|
||||||
|
} else {
|
||||||
|
var elem = window.document.createElement('a')
|
||||||
|
elem.href = window.URL.createObjectURL(blob)
|
||||||
|
elem.download = myFile
|
||||||
|
document.body.appendChild(elem)
|
||||||
|
elem.click()
|
||||||
|
document.body.removeChild(elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('downloadLog').style.display = 'none'
|
||||||
|
document.getElementById('credentials').style.display = 'none'
|
||||||
|
|
||||||
|
var terminalContainer = document.getElementById('terminal-container')
|
||||||
|
var term = new Terminal({
|
||||||
|
cursorBlink: true
|
||||||
|
})
|
||||||
|
var socket, termid // eslint-disable-line
|
||||||
|
term.open(terminalContainer, {
|
||||||
|
focus: true
|
||||||
|
})
|
||||||
|
term.fit()
|
||||||
|
|
||||||
|
if (document.location.pathname) {
|
||||||
|
var parts = document.location.pathname.split('/')
|
||||||
|
var base = parts.slice(0, parts.length - 1).join('/') + '/'
|
||||||
|
var resource = base.substring(1) + 'socket.io'
|
||||||
|
socket = io.connect(null, {
|
||||||
|
resource: resource
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
socket = io.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.on('connect', function () {
|
||||||
|
socket.emit('geometry', term.cols, term.rows)
|
||||||
|
term.on('data', function (data) {
|
||||||
|
socket.emit('data', data)
|
||||||
|
})
|
||||||
|
socket.on('title', function (data) {
|
||||||
|
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) {
|
||||||
|
document.getElementById('header').innerHTML = data
|
||||||
|
}).on('footer', function (data) {
|
||||||
|
sessionFooter = data
|
||||||
|
document.getElementById('footer').innerHTML = data
|
||||||
|
}).on('statusBackground', function (data) {
|
||||||
|
document.getElementById('status').style.backgroundColor = data
|
||||||
|
}).on('allowreplay', function (data) {
|
||||||
|
if (data === 'true') {
|
||||||
|
console.log('allowreplay: ' + data)
|
||||||
|
document.getElementById('credentials').style.display = 'inline'
|
||||||
|
} else {
|
||||||
|
document.getElementById('credentials').style.display = 'none'
|
||||||
|
}
|
||||||
|
}).on('data', function (data) {
|
||||||
|
term.write(data)
|
||||||
|
if (sessionLogEnable) {
|
||||||
|
sessionLog = sessionLog + data
|
||||||
|
}
|
||||||
|
}).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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue