Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9537f4da67 | ||
![]() |
ea12cc8b7e | ||
![]() |
cfa097bd0e | ||
![]() |
170047517b | ||
![]() |
cd64cc0637 | ||
![]() |
533f719cca | ||
![]() |
b8782c565a | ||
![]() |
0dda8d56d9 | ||
![]() |
24c94aed98 | ||
![]() |
7223f2cd8f |
15 changed files with 450 additions and 187 deletions
42
.devcontainer/devcontainer.json
Normal file
42
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,42 @@
|
|||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
|
||||
{
|
||||
"name": "Node.js & TypeScript",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"image": "mcr.microsoft.com/devcontainers/base:jammy",
|
||||
// mount the ssh public identity file for the this project
|
||||
// I limit to just what I need and not the whole ~/.ssh folder
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh/personal_id_rsa.pub,target=/home/vscode/.hostssh/id_rsa.pub,readonly,type=bind,consistency=cached"
|
||||
],
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
"features": {
|
||||
"ghcr.io/devcontainers-contrib/features/node-asdf": {},
|
||||
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"mechatroner.rainbow-csv",
|
||||
"ms-vscode-remote.remote-containers",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"GitHub.copilot",
|
||||
"GitHub.copilot-chat",
|
||||
"esbenp.prettier-vscode",
|
||||
"rvest.vs-code-prettier-eslint",
|
||||
"bierner.markdown-mermaid",
|
||||
"stylelint.vscode-stylelint"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "/bin/bash ./.devcontainer/scripts/tools.sh >> ~/post-create-tools.log"
|
||||
|
||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
// "remoteUser": "root"
|
||||
}
|
18
.devcontainer/scripts/tools.sh
Normal file
18
.devcontainer/scripts/tools.sh
Normal file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -p ~/.ssh && \
|
||||
touch ~/.ssh/known_hosts && \
|
||||
sudo tee ~/.ssh/config > /dev/null << EOF
|
||||
Host github.com
|
||||
HostName github.com
|
||||
PreferredAuthentications publickey
|
||||
IdentityFile ~/.hostssh/id_rsa.pub
|
||||
EOF
|
||||
|
||||
sudo chown -R vscode:vscode ~/.ssh
|
||||
|
||||
# Install Node.js 6.9.1
|
||||
asdf install nodejs 6.9.1
|
||||
asdf local nodejs 6.9.1
|
||||
|
||||
git config --global --add safe.directory /workspaces/webssh2
|
1
.tool-versions
Normal file
1
.tool-versions
Normal file
|
@ -0,0 +1 @@
|
|||
nodejs 6.9.1
|
106
ChangeLog.md
106
ChangeLog.md
|
@ -1,6 +1,47 @@
|
|||
# Change Log
|
||||
## [0.2.9] 2019-06-13
|
||||
|
||||
## [0.2.13] 2024-07-11
|
||||
|
||||
BIG-IP Specific version
|
||||
|
||||
### Fixes
|
||||
|
||||
- fixed missing reference to `read-config-ng` switchover which could prevent `config.json` from being read
|
||||
|
||||
## [0.2.12] 2024-07-10
|
||||
|
||||
BIG-IP Specific version
|
||||
|
||||
### Changes
|
||||
|
||||
- `[ctrl]+[shift]+[6]` or `[ctrl]+[^]` now sends `RS` or `0x1E`
|
||||
|
||||
## [0.2.11] 2020-05-12
|
||||
|
||||
BIG-IP Specific version
|
||||
|
||||
### BREAKING
|
||||
|
||||
- Not compatible with versions of ephemeral_auth before 0.4.8 due to child resources moving under /ssh
|
||||
|
||||
### Changes
|
||||
|
||||
- in `config.json.sample` - `allowreauth` set to `false` by default
|
||||
- in `config.json.sample` - potential future proofing for CORS support `http.origins`
|
||||
- `ssh` module updated to 0.8.9
|
||||
- Move all child resources to start from under /ssh
|
||||
- /socket.io -> /ssh/socket.io
|
||||
- /webssh2.css -> /ssh/webssh2.css
|
||||
- /webssh2.bundle.js -> /ssh/webssh2.bundle.js
|
||||
- /reauth -> /ssh/reauth
|
||||
- perhaps more
|
||||
|
||||
## [0.2.10] not actually released
|
||||
|
||||
## [0.2.9] 2019-06-13
|
||||
|
||||
### Changes
|
||||
|
||||
- Missing require('fs') in `server/app.js` See issue [#135](../../issues/135)
|
||||
- Patched read-config to mitigate vulnerability in js-yaml
|
||||
- issue not exploitable on webssh2 implementation
|
||||
|
@ -9,7 +50,9 @@
|
|||
- See https://github.com/nodeca/js-yaml/issues/475 for more detail
|
||||
|
||||
## [0.2.8] 2019-05-25
|
||||
|
||||
### Changes
|
||||
|
||||
- Fixes issue if no password is entered, browser must be closed and restart to attempt to re-auth. See issue [#118](../../issues/118). Thanks @smilesm2 for the idea.
|
||||
- fixes broken `npm run (build|builddev)`
|
||||
- update font-awesome fonts to 5.6.3
|
||||
|
@ -17,10 +60,13 @@
|
|||
- update xterm to 3.8.0
|
||||
|
||||
### Fixes
|
||||
|
||||
- ILX workspace may not always import properly due to symbolic links (specifically ./node_modules/.bin). This is removed from the ILX package
|
||||
|
||||
## [0.2.7] 2018-11-11
|
||||
|
||||
### Changes
|
||||
|
||||
- `config.reauth` was not respected if initial auth presented was incorrect, regardless of `reauth` setting in `config.json` reauth would always be attempted. fixes [#117](../../issues/117)
|
||||
- **BREAKING** moved app files to /app, this may be a breaking change
|
||||
- Updated dockerfile for new app path
|
||||
|
@ -48,45 +94,59 @@
|
|||
- webpack-cli v3.1.2
|
||||
|
||||
## [0.2.6] 2018-11-09
|
||||
|
||||
### Changes
|
||||
|
||||
- Reauth didn't work if intial auth presented was incorrect, (see issue #112) fixed thanks @vvalchev
|
||||
- Update node version supported to >=6 (PR #115) thanks @perlun
|
||||
- Update packages
|
||||
- developer dependencies
|
||||
|
||||
## [0.2.5] 2018-09-11
|
||||
|
||||
### Added
|
||||
|
||||
- Reauth function thanks to @vbeskrovny and @vvalchev (9bbc116)
|
||||
- Controlled by `config.json` option `options.allowreauth` true presents reauth dialog and false hides dialog
|
||||
|
||||
### Changed
|
||||
|
||||
- `options.challengeButton` enabled
|
||||
- previously this configuration option did nothing, this now enables the Credentials button site-wide regardless of the `allowreplay` header value
|
||||
- Updated debug module to v4
|
||||
|
||||
## [0.2.4] 2018-07-18
|
||||
|
||||
### Added
|
||||
|
||||
- Browser title window now changes with xterm escape sequences (see http://tldp.org/HOWTO/Xterm-Title-3.html)
|
||||
- Added bellStyle options
|
||||
- `GET var`: **bellStyle** - _string_ - Style of terminal bell: ("sound"|"none"). **Default:** "sound". **Enforced Values:** "sound", "none"
|
||||
- `config.json`: **terminal.bellStyle** - _string_ - Style of terminal bell: (sound|none). **Default:** "sound".
|
||||
- `workspace` folder on GITHUB for BIG-IP specific fixes/changes
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated xterm.js to 3.1.0
|
||||
- https://github.com/xtermjs/xterm.js/releases/tag/3.1.0
|
||||
- Default listen IP in `config.json` changed back to 127.0.0.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- ESC]0; is now removed from log files when using the browser-side logging feature
|
||||
|
||||
## [0.2.3] unreleased
|
||||
|
||||
### Fixed
|
||||
|
||||
- ESC]0; is now removed from log files when using the browser-side logging feature
|
||||
|
||||
## [0.2.0] 2018-02-10
|
||||
|
||||
Mostly client (browser) related changes in this release
|
||||
|
||||
### Added
|
||||
|
||||
- Menu system
|
||||
- Fontawesome icons
|
||||
- Resizing browser window sends resize events to terminal container as well as SSH session (pty)
|
||||
|
@ -99,6 +159,7 @@ Mostly client (browser) related changes in this release
|
|||
- Express compression feature
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated xterm.js to 3.0.2
|
||||
- See https://github.com/xtermjs/xterm.js/releases/tag/3.0.2
|
||||
- See https://github.com/xtermjs/xterm.js/releases/tag/3.0.1
|
||||
|
@ -109,23 +170,34 @@ Mostly client (browser) related changes in this release
|
|||
- Removed non-minified options (if you need to disable minification, modify webpack scripts and 'npm run build')
|
||||
|
||||
### Fixed
|
||||
|
||||
- Resolved loss of terminal foucs when interacting with option buttons (Logging, etc...)
|
||||
|
||||
# Change Log
|
||||
|
||||
## [0.1.4] 2018-01-30
|
||||
|
||||
### Changed
|
||||
|
||||
- Moved socket and util out of folders into .js in root.
|
||||
- added keepaliveInterval and keepaliveCountMax config options
|
||||
|
||||
## [0.1.3] 2017-09-28
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to debug@3.1 to eliminate ReDoS in %o formatter
|
||||
- Upgrade Express to 4.15.5 for ReDOS
|
||||
- Upgrade basic-auth to v2.0
|
||||
|
||||
## [0.1.2] 2017-07-31
|
||||
|
||||
### Added
|
||||
|
||||
- ssh.readyTimeout option in config.json (time in ms, default 20000, 20sec)
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated xterm.js to 2.9.2 from 2.6.0
|
||||
- See https://github.com/sourcelair/xterm.js/releases/tag/2.9.2
|
||||
- See https://github.com/sourcelair/xterm.js/releases/tag/2.9.1
|
||||
|
@ -145,23 +217,31 @@ Mostly client (browser) related changes in this release
|
|||
- https://github.com/visionmedia/debug/releases/tag/3.0.0
|
||||
- Running in strict mode ('use strict';)
|
||||
|
||||
|
||||
## [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
|
||||
|
||||
### Added
|
||||
|
||||
- This ChangeLog.md file
|
||||
- Support for UTF-8 characters (thanks @bara666)
|
||||
- Snyk, Bithound, Travis CI
|
||||
|
@ -170,18 +250,19 @@ Mostly client (browser) related changes in this release
|
|||
- Session secret settings in `config.json`
|
||||
- env variable `DEBUG=ssh2` will put the `ssh2` module into debug mode
|
||||
- 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)
|
||||
- sshterm= query option to specify TERM environment variable for host, valid strings are alpha-numeric with a hypen (validated). Otherwise the default ssh.term variable from `config.json` will be used.
|
||||
- validation for host (v4,v6,fqdn,hostname), port (integer 2-65535), and header (sanitized) from URL input
|
||||
|
||||
### Changed
|
||||
|
||||
- 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)
|
||||
- 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)
|
||||
-- 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.
|
||||
- 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`
|
||||
|
@ -192,44 +273,61 @@ and events in the application (not including the ssh2 module debug)
|
|||
- if header.text is null in `config.json` and header is not defined as a get parameter the Header will not be displayed. Both of these must be null / undefined and not specified as get parameters.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Multiple errors may 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.
|
||||
- ensure ssh session is closed when a browser disconnects from the websocket
|
||||
- if headerBackground is changed, status background is changed to the same color (typo, fixed)
|
||||
|
||||
### Removed
|
||||
|
||||
- Express Static References directly to module source directories due to concatenating and minifying js/css
|
||||
|
||||
## [0.0.5] - 2017-03-23
|
||||
|
||||
### Added
|
||||
|
||||
- Added experimental support for logging (see Readme)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Terminal geometry now properly fills the browser screen and communicates this to the ssh session. Tested with IE 11 and recent versions of Chrome/Safari/Firefox.
|
||||
|
||||
## [0.0.4] - 2017-03-23
|
||||
|
||||
### Added
|
||||
|
||||
- Set default terminal to xterm-color
|
||||
- Mouse event support
|
||||
- New config option, config.ssh.term to set terminal
|
||||
|
||||
### Changed
|
||||
|
||||
- Update to Xterm.js 2.4.0
|
||||
- Minor code formatting cleanup
|
||||
|
||||
## [0.0.3] - 2017-02-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Update xterm to latest (2.3.0)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed misspelled config.ssh.port property
|
||||
|
||||
## [0.0.2] - 2017-02-01
|
||||
|
||||
### Changed
|
||||
|
||||
- Moving terminal emulation to xterm.js
|
||||
- updating module version dependencies
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue with banners not being displayed properly from UNIX hosts when only lf is used
|
||||
|
||||
## [0.0.1] - 2016-06-28
|
||||
|
||||
### Added
|
||||
|
||||
- Initial proof of concept and release. For historical purposes only.
|
||||
|
|
|
@ -86,6 +86,8 @@ docker run --name webssh2 -d -p 2222:2222 webssh2
|
|||
|
||||
* **listen.port** - _integer_ - Port node should listen on for client connections, defaults to `2222`
|
||||
|
||||
* **http.origins** - _array_ - COORS origins to allow connections from to socket.io server, defaults to `localhost:2222`. Changed in 0.3.1, to enable previous, less secure, default behavior of everything use `*:*` (not recommended). Check [#240](../../issues/240)
|
||||
|
||||
* **user.name** - _string_ - Specify user name to authenticate with. In normal cases this should be left to the default `null` setting.
|
||||
|
||||
* **user.password** - _string_ - Specify password to authenticate with. In normal cases this should be left to the default `null` setting.
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
<!-- Version Version 0.2.12 - 2024-07-10T13:49:24.751Z - 533f719 -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebSSH2</title>
|
||||
<style>
|
||||
html, body {background-color: #000;height: 100%;margin: 0;}.dropup-content {display: none;}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/webssh2.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div id="header"></div>
|
||||
<div id="terminal-container" class="terminal"></div>
|
||||
<div id="bottomdiv">
|
||||
<div class="dropup" id="menu">
|
||||
<i class="fas fa-bars fa-fw"></i> Menu
|
||||
<div id="dropupContent" class="dropup-content"></div>
|
||||
<head>
|
||||
<title>WebSSH2</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: #000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.dropup-content {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<link href="/ssh/webssh2.css" rel="stylesheet"></head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div id="header"></div>
|
||||
<div id="terminal-container" class="terminal"></div>
|
||||
<div id="bottomdiv">
|
||||
<div class="dropup" id="menu">
|
||||
<i class="fas fa-bars fa-fw"></i> Menu
|
||||
<div id="dropupContent" class="dropup-content"></div>
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/webssh2.bundle.js" defer></script>
|
||||
</body>
|
||||
<script type="text/javascript" src="/ssh/webssh2.bundle.js"></script></body>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,4 @@
|
|||
/*! Version 0.2.12 - 2024-07-10T13:49:24.747Z - 533f719 */
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
<!-- <%= htmlWebpackPlugin.options.version %> -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebSSH2</title>
|
||||
<style>
|
||||
html, body {background-color: #000;height: 100%;margin: 0;}.dropup-content {display: none;}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/webssh2.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div id="header"></div>
|
||||
<div id="terminal-container" class="terminal"></div>
|
||||
<div id="bottomdiv">
|
||||
<div class="dropup" id="menu">
|
||||
<i class="fas fa-bars fa-fw"></i> Menu
|
||||
<div id="dropupContent" class="dropup-content"></div>
|
||||
<head>
|
||||
<title>WebSSH2</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: #000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.dropup-content {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div id="header"></div>
|
||||
<div id="terminal-container" class="terminal"></div>
|
||||
<div id="bottomdiv">
|
||||
<div class="dropup" id="menu">
|
||||
<i class="fas fa-bars fa-fw"></i> Menu
|
||||
<div id="dropupContent" class="dropup-content"></div>
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/webssh2.bundle.js" defer></script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -38,16 +38,9 @@ function resizeScreen () {
|
|||
socket.emit('resize', { cols: term.cols, rows: term.rows })
|
||||
}
|
||||
|
||||
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 = io.connect({
|
||||
path: '/ssh/socket.io'
|
||||
})
|
||||
|
||||
term.on('data', function (data) {
|
||||
socket.emit('data', data)
|
||||
|
@ -171,7 +164,7 @@ function drawMenu (data) {
|
|||
// reauthenticate
|
||||
function reauthSession () { // eslint-disable-line
|
||||
console.log('re-authenticating')
|
||||
window.location.href = '/reauth'
|
||||
window.location.href = '/ssh/reauth'
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -241,3 +234,13 @@ function downloadLog () { // eslint-disable-line
|
|||
}
|
||||
term.focus()
|
||||
}
|
||||
|
||||
// Add an event listener for capturing Ctrl + Shift + 6
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.ctrlKey && event.shiftKey && event.code === 'Digit6') {
|
||||
// Prevent the default action
|
||||
event.preventDefault();
|
||||
// Emit the desired key sequence to the server
|
||||
socket.emit('data', '\x1E'); // 0x1E is the RS control character
|
||||
}
|
||||
});
|
|
@ -3,6 +3,9 @@
|
|||
"ip": "0.0.0.0",
|
||||
"port": 2222
|
||||
},
|
||||
"http": {
|
||||
"origins": ["*:*"]
|
||||
},
|
||||
"user": {
|
||||
"name": null,
|
||||
"password": null
|
||||
|
@ -31,7 +34,7 @@
|
|||
},
|
||||
"options": {
|
||||
"challengeButton": true,
|
||||
"allowreauth": true
|
||||
"allowreauth": false
|
||||
},
|
||||
"algorithms": {
|
||||
"kex": [
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
{
|
||||
"name": "webssh2",
|
||||
"version": "0.2.9",
|
||||
"version": "0.2.13",
|
||||
"ignore": [
|
||||
".gitignore"
|
||||
],
|
||||
"bin": "./index.js",
|
||||
"description": "A Websocket to SSH2 gateway using term.js, socket.io, ssh2, and express",
|
||||
"homepage": "https://github.com/billchurch/WebSSH2",
|
||||
"keywords": "ssh webssh terminal webterminal",
|
||||
"keywords": [
|
||||
"ssh",
|
||||
"webssh",
|
||||
"terminal",
|
||||
"webterminal"
|
||||
],
|
||||
"license": "SEE LICENSE IN FILE - LICENSE",
|
||||
"private": false,
|
||||
"repository": {
|
||||
|
@ -34,9 +39,10 @@
|
|||
"express": "~4.16.4",
|
||||
"express-session": "~1.15.6",
|
||||
"morgan": "~1.9.1",
|
||||
"read-config": "git+https://github.com/billchurch/nodejs-read-config.git",
|
||||
"read-config-ng": "~3.0.7",
|
||||
"serve-favicon": "~2.5.0",
|
||||
"socket.io": "~2.2.0",
|
||||
"ssh2": "~0.6.1",
|
||||
"ssh2": "~0.8.9",
|
||||
"validator": "~10.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -68,6 +74,7 @@
|
|||
"css-loader": "^2.1.0",
|
||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||
"file-loader": "^3.0.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"nodaemon": "0.0.5",
|
||||
"postcss-discard-comments": "^4.0.1",
|
||||
"snazzy": "^8.0.0",
|
||||
|
@ -79,6 +86,7 @@
|
|||
"webpack-cli": "^3.2.1",
|
||||
"webpack-merge": "^4.2.1",
|
||||
"webpack-stream": "^5.2.1",
|
||||
"xterm": "^3.10.1"
|
||||
"xterm": "^3.10.1",
|
||||
"zip-webpack-plugin": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,41 +1,61 @@
|
|||
const webpack = require('webpack')
|
||||
const path = require('path')
|
||||
const CleanWebpackPlugin = require('clean-webpack-plugin')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||
const webpack = require("webpack");
|
||||
const { BannerPlugin } = require("webpack");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const path = require("path");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const CleanWebpackPlugin = require("clean-webpack-plugin");
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
const packageJson = require("../package.json"); // Load package.json
|
||||
const commitHash = require("child_process")
|
||||
.execSync("git rev-parse --short HEAD")
|
||||
.toString()
|
||||
.trim();
|
||||
|
||||
module.exports = {
|
||||
context: path.resolve('__dirname', '../'),
|
||||
context: path.resolve(__dirname, "../"),
|
||||
entry: {
|
||||
webssh2: './client/src/js/index.js'
|
||||
webssh2: "./client/src/js/index.js",
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(['client/public'], {
|
||||
root: path.resolve('__dirname', '../'),
|
||||
verbose: true
|
||||
new BannerPlugin({
|
||||
banner: `Version ${
|
||||
packageJson.version
|
||||
} - ${new Date().toISOString()} - ${commitHash}`,
|
||||
include: /\.(js|css|html|htm)$/,
|
||||
}),
|
||||
new CleanWebpackPlugin(["client/public"], {
|
||||
root: path.resolve("__dirname", "../"),
|
||||
verbose: true,
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./client/src/client.htm", // Path to your source template
|
||||
filename: "client.htm", // Optional: output file name, defaults to index.html
|
||||
minify: false,
|
||||
scriptLoading: "defer",
|
||||
version: `Version ${
|
||||
packageJson.version
|
||||
} - ${new Date().toISOString()} - ${commitHash}`,
|
||||
publicPath: "/ssh/", // Prepend /ssh/ to the script tags
|
||||
}),
|
||||
new CopyWebpackPlugin([
|
||||
'./client/src/client.htm',
|
||||
'./client/src/favicon.ico'
|
||||
{ from: "./client/src/favicon.ico", to: "favicon.ico" },
|
||||
]),
|
||||
new ExtractTextPlugin('[name].css')
|
||||
new ExtractTextPlugin("[name].css"),
|
||||
],
|
||||
output: {
|
||||
filename: '[name].bundle.js',
|
||||
path: path.resolve(__dirname, '../client/public')
|
||||
filename: "[name].bundle.js",
|
||||
path: path.resolve(__dirname, "../client/public"),
|
||||
publicPath: "/ssh/", // Prepend /ssh/ to the script tags
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
fallback: 'style-loader',
|
||||
use: [
|
||||
{
|
||||
loader: 'css-loader'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
fallback: "style-loader",
|
||||
use: [{ loader: "css-loader" }],
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
const merge = require('webpack-merge')
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
|
||||
const common = require('./webpack.common.js')
|
||||
const merge = require("webpack-merge");
|
||||
const UglifyJSPlugin = require("uglifyjs-webpack-plugin");
|
||||
const common = require("./webpack.common.js");
|
||||
|
||||
module.exports = merge(common, {
|
||||
plugins: [
|
||||
new UglifyJSPlugin({
|
||||
uglifyOptions: {
|
||||
ie8: false,
|
||||
dead_code: true,
|
||||
output: {
|
||||
comments: false,
|
||||
beautify: false
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
module.exports = merge(
|
||||
{
|
||||
plugins: [
|
||||
new UglifyJSPlugin({
|
||||
uglifyOptions: {
|
||||
ie8: false,
|
||||
dead_code: true,
|
||||
output: {
|
||||
comments: false,
|
||||
beautify: false,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
common
|
||||
);
|
||||
|
|
|
@ -13,49 +13,52 @@ var logger = require('morgan')
|
|||
|
||||
// sane defaults if config.json or parts are missing
|
||||
let config = {
|
||||
'listen': {
|
||||
'ip': '0.0.0.0',
|
||||
'port': 2222
|
||||
listen: {
|
||||
ip: '0.0.0.0',
|
||||
port: 2222
|
||||
},
|
||||
'user': {
|
||||
'name': null,
|
||||
'password': null
|
||||
http: {
|
||||
origins: ['*:*']
|
||||
},
|
||||
'ssh': {
|
||||
'host': null,
|
||||
'port': 22,
|
||||
'term': 'xterm-color',
|
||||
'readyTimeout': 20000,
|
||||
'keepaliveInterval': 120000,
|
||||
'keepaliveCountMax': 10
|
||||
user: {
|
||||
name: null,
|
||||
password: null
|
||||
},
|
||||
'terminal': {
|
||||
'cursorBlink': true,
|
||||
'scrollback': 10000,
|
||||
'tabStopWidth': 8,
|
||||
'bellStyle': 'sound'
|
||||
ssh: {
|
||||
host: null,
|
||||
port: 22,
|
||||
term: 'xterm-color',
|
||||
readyTimeout: 20000,
|
||||
keepaliveInterval: 120000,
|
||||
keepaliveCountMax: 10
|
||||
},
|
||||
'header': {
|
||||
'text': null,
|
||||
'background': 'green'
|
||||
terminal: {
|
||||
cursorBlink: true,
|
||||
scrollback: 10000,
|
||||
tabStopWidth: 8,
|
||||
bellStyle: 'sound'
|
||||
},
|
||||
'session': {
|
||||
'name': 'WebSSH2',
|
||||
'secret': 'mysecret'
|
||||
header: {
|
||||
text: null,
|
||||
background: 'green'
|
||||
},
|
||||
'options': {
|
||||
'challengeButton': true,
|
||||
'allowreauth': true
|
||||
session: {
|
||||
name: 'WebSSH2',
|
||||
secret: 'mysecret'
|
||||
},
|
||||
'algorithms': {
|
||||
'kex': [
|
||||
options: {
|
||||
challengeButton: true,
|
||||
allowreauth: true
|
||||
},
|
||||
algorithms: {
|
||||
kex: [
|
||||
'ecdh-sha2-nistp256',
|
||||
'ecdh-sha2-nistp384',
|
||||
'ecdh-sha2-nistp521',
|
||||
'diffie-hellman-group-exchange-sha256',
|
||||
'diffie-hellman-group14-sha1'
|
||||
],
|
||||
'cipher': [
|
||||
cipher: [
|
||||
'aes128-ctr',
|
||||
'aes192-ctr',
|
||||
'aes256-ctr',
|
||||
|
@ -65,23 +68,15 @@ let config = {
|
|||
'aes256-gcm@openssh.com',
|
||||
'aes256-cbc'
|
||||
],
|
||||
'hmac': [
|
||||
'hmac-sha2-256',
|
||||
'hmac-sha2-512',
|
||||
'hmac-sha1'
|
||||
],
|
||||
'compress': [
|
||||
'none',
|
||||
'zlib@openssh.com',
|
||||
'zlib'
|
||||
]
|
||||
hmac: ['hmac-sha2-256', 'hmac-sha2-512', 'hmac-sha1'],
|
||||
compress: ['none', 'zlib@openssh.com', 'zlib']
|
||||
},
|
||||
'serverlog': {
|
||||
'client': false,
|
||||
'server': false
|
||||
serverlog: {
|
||||
client: false,
|
||||
server: false
|
||||
},
|
||||
'accesslog': false,
|
||||
'verify': false
|
||||
accesslog: false,
|
||||
verify: false
|
||||
}
|
||||
|
||||
// test if config.json exists, if not provide error message but try to run
|
||||
|
@ -89,13 +84,19 @@ let config = {
|
|||
try {
|
||||
if (fs.existsSync(configPath)) {
|
||||
console.log('ephemeral_auth service reading config from: ' + configPath)
|
||||
config = require('read-config')(configPath)
|
||||
config = require('read-config-ng')(configPath)
|
||||
} else {
|
||||
console.error('\n\nERROR: Missing config.json for webssh. Current config: ' + JSON.stringify(config))
|
||||
console.error(
|
||||
'\n\nERROR: Missing config.json for webssh. Current config: ' +
|
||||
JSON.stringify(config)
|
||||
)
|
||||
console.error('\n See config.json.sample for details\n\n')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('\n\nERROR: Missing config.json for webssh. Current config: ' + JSON.stringify(config))
|
||||
console.error(
|
||||
'\n\nERROR: Missing config.json for webssh. Current config: ' +
|
||||
JSON.stringify(config)
|
||||
)
|
||||
console.error('\n See config.json.sample for details\n\n')
|
||||
console.error('ERROR:\n\n ' + err)
|
||||
}
|
||||
|
@ -112,9 +113,14 @@ var compression = require('compression')
|
|||
var server = require('http').Server(app)
|
||||
var myutil = require('./util')
|
||||
var validator = require('validator')
|
||||
var io = require('socket.io')(server, { serveClient: false })
|
||||
var io = require('socket.io')(server, {
|
||||
serveClient: false,
|
||||
path: '/ssh/socket.io',
|
||||
origins: config.http.origins
|
||||
})
|
||||
var socket = require('./socket')
|
||||
var expressOptions = require('./expressOptions')
|
||||
var favicon = require('serve-favicon')
|
||||
|
||||
// express
|
||||
app.use(compression({ level: 9 }))
|
||||
|
@ -124,23 +130,38 @@ if (config.accesslog) app.use(logger('common'))
|
|||
app.disable('x-powered-by')
|
||||
|
||||
// static files
|
||||
app.use(express.static(publicPath, expressOptions))
|
||||
app.use('/ssh', express.static(publicPath, expressOptions))
|
||||
// app.use(express.static(publicPath, expressOptions))
|
||||
|
||||
app.get('/reauth', function (req, res, next) {
|
||||
// favicon from root if being pre-fetched by browser to prevent a 404
|
||||
app.use(favicon(path.join(publicPath, 'favicon.ico')))
|
||||
|
||||
app.get('/ssh/reauth', function (req, res, next) {
|
||||
var r = req.headers.referer || '/'
|
||||
res.status(401).send('<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=' + r + '"></head><body bgcolor="#000"></body></html>')
|
||||
res
|
||||
.status(401)
|
||||
.send(
|
||||
'<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=' +
|
||||
r +
|
||||
'"></head><body bgcolor="#000"></body></html>'
|
||||
)
|
||||
})
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
app.get('/ssh/host/:host?', function (req, res, next) {
|
||||
res.sendFile(path.join(path.join(publicPath, 'client.htm')))
|
||||
// capture, assign, and validated variables
|
||||
req.session.ssh = {
|
||||
host: (validator.isIP(req.params.host + '') && req.params.host) ||
|
||||
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,
|
||||
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
|
||||
|
@ -148,26 +169,53 @@ app.get('/ssh/host/:host?', function (req, res, next) {
|
|||
algorithms: config.algorithms,
|
||||
keepaliveInterval: config.ssh.keepaliveInterval,
|
||||
keepaliveCountMax: config.ssh.keepaliveCountMax,
|
||||
term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) &&
|
||||
req.query.sshterm) || config.ssh.term,
|
||||
term:
|
||||
(/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) &&
|
||||
req.query.sshterm) ||
|
||||
config.ssh.term,
|
||||
terminal: {
|
||||
cursorBlink: (validator.isBoolean(req.query.cursorBlink + '') ? myutil.parseBool(req.query.cursorBlink) : config.terminal.cursorBlink),
|
||||
scrollback: (validator.isInt(req.query.scrollback + '', { min: 1, max: 200000 }) && req.query.scrollback) ? req.query.scrollback : config.terminal.scrollback,
|
||||
tabStopWidth: (validator.isInt(req.query.tabStopWidth + '', { min: 1, max: 100 }) && req.query.tabStopWidth) ? req.query.tabStopWidth : config.terminal.tabStopWidth,
|
||||
bellStyle: ((req.query.bellStyle) && (['sound', 'none'].indexOf(req.query.bellStyle) > -1)) ? req.query.bellStyle : config.terminal.bellStyle
|
||||
cursorBlink: validator.isBoolean(req.query.cursorBlink + '')
|
||||
? myutil.parseBool(req.query.cursorBlink)
|
||||
: config.terminal.cursorBlink,
|
||||
scrollback:
|
||||
validator.isInt(req.query.scrollback + '', { min: 1, max: 200000 }) &&
|
||||
req.query.scrollback
|
||||
? req.query.scrollback
|
||||
: config.terminal.scrollback,
|
||||
tabStopWidth:
|
||||
validator.isInt(req.query.tabStopWidth + '', { min: 1, max: 100 }) &&
|
||||
req.query.tabStopWidth
|
||||
? req.query.tabStopWidth
|
||||
: config.terminal.tabStopWidth,
|
||||
bellStyle:
|
||||
req.query.bellStyle &&
|
||||
['sound', 'none'].indexOf(req.query.bellStyle) > -1
|
||||
? req.query.bellStyle
|
||||
: config.terminal.bellStyle
|
||||
},
|
||||
allowreplay: config.options.challengeButton || (validator.isBoolean(req.headers.allowreplay + '') ? myutil.parseBool(req.headers.allowreplay) : false),
|
||||
allowreplay:
|
||||
config.options.challengeButton ||
|
||||
(validator.isBoolean(req.headers.allowreplay + '')
|
||||
? myutil.parseBool(req.headers.allowreplay)
|
||||
: false),
|
||||
allowreauth: config.options.allowreauth || false,
|
||||
mrhsession: ((validator.isAlphanumeric(req.headers.mrhsession + '') && req.headers.mrhsession) ? req.headers.mrhsession : 'none'),
|
||||
mrhsession:
|
||||
validator.isAlphanumeric(req.headers.mrhsession + '') &&
|
||||
req.headers.mrhsession
|
||||
? req.headers.mrhsession
|
||||
: 'none',
|
||||
serverlog: {
|
||||
client: config.serverlog.client || false,
|
||||
server: config.serverlog.server || false
|
||||
},
|
||||
readyTimeout: (validator.isInt(req.query.readyTimeout + '', { min: 1, max: 300000 }) &&
|
||||
req.query.readyTimeout) || config.ssh.readyTimeout
|
||||
readyTimeout:
|
||||
(validator.isInt(req.query.readyTimeout + '', { min: 1, max: 300000 }) &&
|
||||
req.query.readyTimeout) ||
|
||||
config.ssh.readyTimeout
|
||||
}
|
||||
if (req.session.ssh.header.name) validator.escape(req.session.ssh.header.name)
|
||||
if (req.session.ssh.header.background) validator.escape(req.session.ssh.header.background)
|
||||
if (req.session.ssh.header.background)
|
||||
validator.escape(req.session.ssh.header.background)
|
||||
})
|
||||
|
||||
// express error handling
|
||||
|
@ -183,7 +231,8 @@ app.use(function (err, req, res, next) {
|
|||
// socket.io
|
||||
// expose express session with socket.request.session
|
||||
io.use(function (socket, next) {
|
||||
(socket.request.res) ? session(socket.request, socket.request.res, next)
|
||||
socket.request.res
|
||||
? session(socket.request, socket.request.res, next)
|
||||
: next(next)
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue