chore: lint ./app/client/src/js/index.js #242
This commit is contained in:
parent
982780ed1d
commit
259f4f0afe
3 changed files with 258 additions and 240 deletions
10
README.md
10
README.md
|
|
@ -246,11 +246,15 @@ 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&headerBackground=red
|
||||
|
||||
# Tips
|
||||
* If you want to add custom JavaScript to the browser client you can either modify `./src/client.html` and add a **<script>** element, modify `./src/index.js` directly, or check out `webpack.*.js` and add your custom javascript file to a task there (best option).
|
||||
# CONTRIBUTING
|
||||
As of 0.4.0, we're trying our best to conform to the [Airbnb Javascript Style Guide](https://airbnb.io/projects/javascript/). I'm hoping this will make contributions easier and keep the code readable. I love shortcuts more than anyone but I've found when making changes to code I've not looked at in a while, it can take me a few momements to deconstruct what was being done due to readbility issues. While I don't agree with every decision in the style guide (semi-colons, yuk), it is a good base to keep the code consistent.
|
||||
|
||||
If you've not used it before, I recommend installing the [vscode extensions](https://blog.echobind.com/integrating-prettier-eslint-airbnb-style-guide-in-vscode-47f07b5d7d6a) for that and [Prettier](https://prettier.io/) and getting familiar. The autocorrections are great (especially if you hate dealing with semi-colons...)
|
||||
|
||||
All contributions are welcome, all may not make it into a release... To increase the chances of your contribution making it into a release, try your best to conform to the style guides and targets of the project.
|
||||
All contributions are welcome, all may not make it into a release... To increase the chances of your contribution making it into a release, try your best to conform to the style guides and targets of the project.
|
||||
|
||||
# Tips
|
||||
* You can enable extended debug messages in the browser Java console using:
|
||||
* `localStorage.debug = '*';` - Debug Everything (a lot of messages)
|
||||
* `localStorage.debug = 'WebSSH2';` - Debug potentially interesting WebSSH2 related messages (replaying credentials, resizing data, other control messages)
|
||||
* If you want to add custom JavaScript to the browser client you can either modify `./src/client.html` and add a **\<script\>** element, modify `./src/index.js` directly, or check out `webpack.*.js` and add your custom javascript file to a task there (best option).
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,257 +1,271 @@
|
|||
'use strict'
|
||||
import * as io from 'socket.io-client/dist/socket.io.js';
|
||||
import { Terminal } from 'xterm';
|
||||
import { FitAddon } from 'xterm-addon-fit';
|
||||
import { library, dom } from '@fortawesome/fontawesome-svg-core';
|
||||
import { faBars, faClipboard, faDownload, faKey, faCog } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import * as io from 'socket.io-client/dist/socket.io.js'
|
||||
import { Terminal } from 'xterm'
|
||||
import { FitAddon } from 'xterm-addon-fit'
|
||||
import { library, dom } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faBars, faClipboard, faDownload, faKey, faCog } from '@fortawesome/free-solid-svg-icons'
|
||||
library.add(faBars, faClipboard, faDownload, faKey, faCog)
|
||||
dom.watch()
|
||||
library.add(faBars, faClipboard, faDownload, faKey, faCog);
|
||||
dom.watch();
|
||||
|
||||
require('xterm/css/xterm.css')
|
||||
require('../css/style.css')
|
||||
const debug = require('debug')('WebSSH2');
|
||||
require('xterm/css/xterm.css');
|
||||
require('../css/style.css');
|
||||
|
||||
/* global Blob, logBtn, credentialsBtn, reauthBtn, downloadLogBtn */ // eslint-disable-line
|
||||
let sessionLogEnable = false
|
||||
let loggedData = false
|
||||
let allowreplay = false
|
||||
let allowreauth = false
|
||||
let sessionLog, sessionFooter, logDate, currentDate, myFile, errorExists
|
||||
let sessionLogEnable = false;
|
||||
let loggedData = false;
|
||||
let allowreplay = false;
|
||||
let allowreauth = false;
|
||||
let sessionLog;
|
||||
let sessionFooter;
|
||||
let logDate;
|
||||
let currentDate;
|
||||
let myFile;
|
||||
let errorExists;
|
||||
let socket, termid // eslint-disable-line
|
||||
const term = new Terminal()
|
||||
const term = new Terminal();
|
||||
// DOM properties
|
||||
const status = document.getElementById('status')
|
||||
const header = document.getElementById('header')
|
||||
const dropupContent = document.getElementById('dropupContent')
|
||||
const footer = document.getElementById('footer')
|
||||
const countdown = document.getElementById('countdown')
|
||||
const fitAddon = new FitAddon()
|
||||
const terminalContainer = document.getElementById('terminal-container')
|
||||
term.loadAddon(fitAddon)
|
||||
term.open(terminalContainer)
|
||||
term.focus()
|
||||
fitAddon.fit()
|
||||
|
||||
window.addEventListener('resize', resizeScreen, false)
|
||||
|
||||
function resizeScreen () {
|
||||
fitAddon.fit()
|
||||
socket.emit('resize', { cols: term.cols, rows: term.rows })
|
||||
}
|
||||
|
||||
socket = io.connect({
|
||||
path: '/ssh/socket.io'
|
||||
})
|
||||
|
||||
term.onData(function (data) {
|
||||
socket.emit('data', data)
|
||||
})
|
||||
|
||||
socket.on('data', function (data) {
|
||||
term.write(data)
|
||||
if (sessionLogEnable) {
|
||||
sessionLog = sessionLog + data
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('connect', function () {
|
||||
socket.emit('geometry', term.cols, term.rows)
|
||||
})
|
||||
|
||||
socket.on('setTerminalOpts', function (data) {
|
||||
term.setOption('cursorBlink', data.cursorBlink)
|
||||
term.setOption('scrollback', data.scrollback)
|
||||
term.setOption('tabStopWidth', data.tabStopWidth)
|
||||
term.setOption('bellStyle', data.bellStyle)
|
||||
})
|
||||
|
||||
socket.on('title', function (data) {
|
||||
document.title = data
|
||||
})
|
||||
|
||||
socket.on('menu', function (data) {
|
||||
drawMenu(data)
|
||||
})
|
||||
|
||||
socket.on('status', function (data) {
|
||||
status.innerHTML = data
|
||||
})
|
||||
|
||||
socket.on('ssherror', function (data) {
|
||||
status.innerHTML = data
|
||||
status.style.backgroundColor = 'red'
|
||||
errorExists = true
|
||||
})
|
||||
|
||||
socket.on('headerBackground', function (data) {
|
||||
header.style.backgroundColor = data
|
||||
})
|
||||
|
||||
socket.on('header', function (data) {
|
||||
if (data) {
|
||||
header.innerHTML = data
|
||||
header.style.display = 'block'
|
||||
// header is 19px and footer is 19px, recaculate new terminal-container and resize
|
||||
terminalContainer.style.height = 'calc(100% - 38px)'
|
||||
resizeScreen()
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('footer', function (data) {
|
||||
sessionFooter = data
|
||||
footer.innerHTML = data
|
||||
})
|
||||
|
||||
socket.on('statusBackground', function (data) {
|
||||
status.style.backgroundColor = data
|
||||
})
|
||||
|
||||
socket.on('allowreplay', function (data) {
|
||||
if (data === true) {
|
||||
console.log('allowreplay: ' + data)
|
||||
allowreplay = true
|
||||
drawMenu(dropupContent.innerHTML + '<a id="credentialsBtn"><i class="fas fa-key fa-fw"></i> Credentials</a>')
|
||||
} else {
|
||||
allowreplay = false
|
||||
console.log('allowreplay: ' + data)
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('allowreauth', function (data) {
|
||||
if (data === true) {
|
||||
console.log('allowreauth: ' + data)
|
||||
allowreauth = true
|
||||
drawMenu(dropupContent.innerHTML + '<a id="reauthBtn"><i class="fas fa-key fa-fw"></i> Switch User</a>')
|
||||
} else {
|
||||
allowreauth = false
|
||||
console.log('allowreauth: ' + data)
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('disconnect', function (err) {
|
||||
if (!errorExists) {
|
||||
status.style.backgroundColor = 'red'
|
||||
status.innerHTML =
|
||||
'WEBSOCKET SERVER DISCONNECTED: ' + err
|
||||
}
|
||||
socket.io.reconnection(false)
|
||||
countdown.classList.remove('active')
|
||||
})
|
||||
|
||||
socket.on('error', function (err) {
|
||||
if (!errorExists) {
|
||||
status.style.backgroundColor = 'red'
|
||||
status.innerHTML = 'ERROR: ' + err
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('reauth', function () {
|
||||
if (allowreauth) {
|
||||
reauthSession()
|
||||
}
|
||||
})
|
||||
|
||||
// safe shutdown
|
||||
let hasCountdownStarted = false
|
||||
|
||||
socket.on('shutdownCountdownUpdate', function (remainingSeconds) {
|
||||
if (!hasCountdownStarted) {
|
||||
countdown.classList.add('active')
|
||||
hasCountdownStarted = true
|
||||
}
|
||||
countdown.innerText = 'Shutting down in ' + remainingSeconds + 's'
|
||||
})
|
||||
|
||||
term.onTitleChange(function (title) {
|
||||
document.title = title
|
||||
})
|
||||
|
||||
// draw/re-draw menu and reattach listeners
|
||||
// when dom is changed, listeners are abandonded
|
||||
function drawMenu (data) {
|
||||
dropupContent.innerHTML = data
|
||||
logBtn.addEventListener('click', toggleLog)
|
||||
if (allowreauth) {
|
||||
reauthBtn.addEventListener('click', reauthSession)
|
||||
}
|
||||
if (allowreplay) {
|
||||
credentialsBtn.addEventListener('click', replayCredentials)
|
||||
}
|
||||
if (loggedData) {
|
||||
downloadLogBtn.addEventListener('click', downloadLog)
|
||||
}
|
||||
}
|
||||
const status = document.getElementById('status');
|
||||
const header = document.getElementById('header');
|
||||
const dropupContent = document.getElementById('dropupContent');
|
||||
const footer = document.getElementById('footer');
|
||||
const countdown = document.getElementById('countdown');
|
||||
const fitAddon = new FitAddon();
|
||||
const terminalContainer = document.getElementById('terminal-container');
|
||||
term.loadAddon(fitAddon);
|
||||
term.open(terminalContainer);
|
||||
term.focus();
|
||||
fitAddon.fit();
|
||||
|
||||
// reauthenticate
|
||||
function reauthSession () { // eslint-disable-line
|
||||
console.log('re-authenticating')
|
||||
window.location.href = '/ssh/reauth'
|
||||
return false
|
||||
}
|
||||
|
||||
// replay password to server, requires
|
||||
function replayCredentials () { // eslint-disable-line
|
||||
socket.emit('control', 'replayCredentials')
|
||||
console.log('replaying credentials')
|
||||
term.focus()
|
||||
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
|
||||
loggedData = true
|
||||
logBtn.innerHTML = '<i class="fas fa-clipboard fa-fw"></i> Start Log'
|
||||
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
|
||||
term.focus()
|
||||
return false
|
||||
} else {
|
||||
sessionLogEnable = true
|
||||
loggedData = true
|
||||
logBtn.innerHTML = '<i class="fas fa-cog fa-spin fa-fw"></i> Stop Log'
|
||||
downloadLogBtn.style.color = '#000'
|
||||
downloadLogBtn.addEventListener('click', downloadLog)
|
||||
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
|
||||
term.focus()
|
||||
return false
|
||||
}
|
||||
debug('re-authenticating');
|
||||
window.location.href = '/ssh/reauth';
|
||||
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
|
||||
if (loggedData === true) {
|
||||
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.
|
||||
const blob = new Blob([sessionLog.replace(/[\u001b\u009b][[\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><;]/g, '')], { // eslint-disable-line no-control-regex
|
||||
type: 'text/plain'
|
||||
})
|
||||
const blob = new Blob(
|
||||
[
|
||||
sessionLog.replace(
|
||||
// eslint-disable-next-line no-control-regex
|
||||
/[\u001b\u009b][[\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><;]/g,
|
||||
''
|
||||
),
|
||||
],
|
||||
{
|
||||
// eslint-disable-line no-control-regex
|
||||
type: 'text/plain',
|
||||
}
|
||||
);
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
window.navigator.msSaveBlob(blob, myFile)
|
||||
window.navigator.msSaveBlob(blob, myFile);
|
||||
} else {
|
||||
const elem = window.document.createElement('a')
|
||||
elem.href = window.URL.createObjectURL(blob)
|
||||
elem.download = myFile
|
||||
document.body.appendChild(elem)
|
||||
elem.click()
|
||||
document.body.removeChild(elem)
|
||||
const elem = window.document.createElement('a');
|
||||
elem.href = window.URL.createObjectURL(blob);
|
||||
elem.download = myFile;
|
||||
document.body.appendChild(elem);
|
||||
elem.click();
|
||||
document.body.removeChild(elem);
|
||||
}
|
||||
}
|
||||
term.focus()
|
||||
term.focus();
|
||||
}
|
||||
// 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;
|
||||
loggedData = true;
|
||||
logBtn.innerHTML = '<i class="fas fa-clipboard fa-fw"></i> Start Log';
|
||||
// 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;
|
||||
term.focus();
|
||||
return false;
|
||||
}
|
||||
sessionLogEnable = true;
|
||||
loggedData = true;
|
||||
logBtn.innerHTML = '<i class="fas fa-cog fa-spin fa-fw"></i> Stop Log';
|
||||
downloadLogBtn.style.color = '#000';
|
||||
downloadLogBtn.addEventListener('click', downloadLog);
|
||||
// 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;
|
||||
term.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// replay password to server, requires
|
||||
function replayCredentials () { // eslint-disable-line
|
||||
socket.emit('control', 'replayCredentials');
|
||||
// console.log('replaying credentials');
|
||||
term.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// draw/re-draw menu and reattach listeners
|
||||
// when dom is changed, listeners are abandonded
|
||||
function drawMenu(data) {
|
||||
dropupContent.innerHTML = data;
|
||||
logBtn.addEventListener('click', toggleLog);
|
||||
if (allowreauth) {
|
||||
reauthBtn.addEventListener('click', reauthSession);
|
||||
}
|
||||
if (allowreplay) {
|
||||
credentialsBtn.addEventListener('click', replayCredentials);
|
||||
}
|
||||
if (loggedData) {
|
||||
downloadLogBtn.addEventListener('click', downloadLog);
|
||||
}
|
||||
}
|
||||
|
||||
function resizeScreen() {
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', { cols: term.cols, rows: term.rows });
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeScreen, false);
|
||||
|
||||
socket = io.connect({
|
||||
path: '/ssh/socket.io',
|
||||
});
|
||||
|
||||
term.onData((data) => {
|
||||
socket.emit('data', data);
|
||||
});
|
||||
|
||||
socket.on('data', (data) => {
|
||||
term.write(data);
|
||||
if (sessionLogEnable) {
|
||||
sessionLog += data;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('connect', () => {
|
||||
socket.emit('geometry', term.cols, term.rows);
|
||||
});
|
||||
|
||||
socket.on('setTerminalOpts', (data) => {
|
||||
term.setOption('cursorBlink', data.cursorBlink);
|
||||
term.setOption('scrollback', data.scrollback);
|
||||
term.setOption('tabStopWidth', data.tabStopWidth);
|
||||
term.setOption('bellStyle', data.bellStyle);
|
||||
});
|
||||
|
||||
socket.on('title', (data) => {
|
||||
document.title = data;
|
||||
});
|
||||
|
||||
socket.on('menu', (data) => {
|
||||
drawMenu(data);
|
||||
});
|
||||
|
||||
socket.on('status', (data) => {
|
||||
status.innerHTML = data;
|
||||
});
|
||||
|
||||
socket.on('ssherror', (data) => {
|
||||
status.innerHTML = data;
|
||||
status.style.backgroundColor = 'red';
|
||||
errorExists = true;
|
||||
});
|
||||
|
||||
socket.on('headerBackground', (data) => {
|
||||
header.style.backgroundColor = data;
|
||||
});
|
||||
|
||||
socket.on('header', (data) => {
|
||||
if (data) {
|
||||
header.innerHTML = data;
|
||||
header.style.display = 'block';
|
||||
// header is 19px and footer is 19px, recaculate new terminal-container and resize
|
||||
terminalContainer.style.height = 'calc(100% - 38px)';
|
||||
resizeScreen();
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('footer', (data) => {
|
||||
sessionFooter = data;
|
||||
footer.innerHTML = data;
|
||||
});
|
||||
|
||||
socket.on('statusBackground', (data) => {
|
||||
status.style.backgroundColor = data;
|
||||
});
|
||||
|
||||
socket.on('allowreplay', (data) => {
|
||||
if (data === true) {
|
||||
debug(`allowreplay: ${data}`);
|
||||
allowreplay = true;
|
||||
drawMenu(
|
||||
`${dropupContent.innerHTML}<a id="credentialsBtn"><i class="fas fa-key fa-fw"></i> Credentials</a>`
|
||||
);
|
||||
} else {
|
||||
allowreplay = false;
|
||||
debug(`allowreplay: ${data}`);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('allowreauth', (data) => {
|
||||
if (data === true) {
|
||||
debug(`allowreauth: ${data}`);
|
||||
allowreauth = true;
|
||||
drawMenu(
|
||||
`${dropupContent.innerHTML}<a id="reauthBtn"><i class="fas fa-key fa-fw"></i> Switch User</a>`
|
||||
);
|
||||
} else {
|
||||
allowreauth = false;
|
||||
debug(`allowreauth: ${data}`);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('disconnect', (err) => {
|
||||
if (!errorExists) {
|
||||
status.style.backgroundColor = 'red';
|
||||
status.innerHTML = `WEBSOCKET SERVER DISCONNECTED: ${err}`;
|
||||
}
|
||||
socket.io.reconnection(false);
|
||||
countdown.classList.remove('active');
|
||||
});
|
||||
|
||||
socket.on('error', (err) => {
|
||||
if (!errorExists) {
|
||||
status.style.backgroundColor = 'red';
|
||||
status.innerHTML = `ERROR: ${err}`;
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('reauth', () => {
|
||||
if (allowreauth) {
|
||||
reauthSession();
|
||||
}
|
||||
});
|
||||
|
||||
// safe shutdown
|
||||
let hasCountdownStarted = false;
|
||||
|
||||
socket.on('shutdownCountdownUpdate', (remainingSeconds) => {
|
||||
if (!hasCountdownStarted) {
|
||||
countdown.classList.add('active');
|
||||
hasCountdownStarted = true;
|
||||
}
|
||||
countdown.innerText = `Shutting down in ${remainingSeconds}s`;
|
||||
});
|
||||
|
||||
term.onTitleChange((title) => {
|
||||
document.title = title;
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue