diff --git a/ChangeLog.md b/ChangeLog.md index db223f1..6e71973 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,6 +5,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) +- Adding terminal options +- New serverside (nodejs) terminal configuration options (cursorBlink, scrollback, tabStopWidth) +- Logging of MRH session (unassigned if not present) ### Changed - Updated xterm.js to 3.0.2 diff --git a/README.md b/README.md index 16273c6..c8cb6b7 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,12 @@ docker run --name webssh2 -d -p 2222:2222 webssh2 * **ssh.keepaliveCountMax** - _integer_ - How many consecutive, unanswered SSH-level keepalive packets that can be sent to the server before disconnection (similar to OpenSSH's ServerAliveCountMax config option). **Default:** 10. +* **terminal.cursorBlink** - _boolean_ - Cursor blinks (true), does not (false) **Default:** true. + +* **terminal.scrollback** - _integer_ - Lines in the scrollback buffer. **Default:** 10000. + +* **terminal.tabStopWidth** - _integer_ - Tab stops at _n_ characters **Default:** 8. + * **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`. When set to `null` no header bar will be displayed on the client. diff --git a/app.js b/app.js index 4ac8c72..c2649da 100644 --- a/app.js +++ b/app.js @@ -48,8 +48,13 @@ app.get('/ssh/host/:host?', function (req, res, next) { keepaliveCountMax: config.ssh.keepaliveCountMax, term: (/^(([a-z]|[A-Z]|[0-9]|[!^(){}\-_~])+)?\w$/.test(req.query.sshterm) && req.query.sshterm) || config.ssh.term, - allowreplay: validator.isBoolean(req.headers.allowreplay + '') || false, - sessionID: validator.isAlphanumeric(req.headers.sessionID + '') || false, + terminal: { + cursorBlink: (validator.isBoolean(req.query.cursorBlink + '') ? myutil.parseBool(req.query.cursorBlink) : config.terminal.cursorBlink), + scrollback: config.terminal.scrollback, + tabStopWidth: config.terminal.tabStopWidth + }, + allowreplay: (validator.isBoolean(req.headers.allowreplay + '') ? myutil.parseBool(req.headers.allowreplay) : false), + MRH_Session: validator.isAlphanumeric(req.headers.lastMRH_Session + '') && req.headers.lastMRH_Session || 'none', serverlog: { client: config.serverlog.client || false, server: config.serverlog.server || false diff --git a/config.json b/config.json index c5e886c..87b20ef 100644 --- a/config.json +++ b/config.json @@ -15,6 +15,11 @@ "keepaliveInterval": 120000, "keepaliveCountMax": 10 }, + "terminal": { + "cursorBlink": true, + "scrollback": 10000, + "tabStopWidth": 8 + }, "useminified": false, "header": { "text": null, diff --git a/public/webssh2.bundle.js b/public/webssh2.bundle.js index d5add14..d7e7feb 100644 --- a/public/webssh2.bundle.js +++ b/public/webssh2.bundle.js @@ -125,15 +125,20 @@ logBtn.addEventListener('click', toggleLog) logBtn.style.color = '#000' var terminalContainer = document.getElementById('terminal-container') - -var term = new __WEBPACK_IMPORTED_MODULE_1__node_modules_xterm_dist_xterm__({ - cursorBlink: true -}) var socket, termid // eslint-disable-line +var term = new __WEBPACK_IMPORTED_MODULE_1__node_modules_xterm_dist_xterm__() term.open(terminalContainer) term.focus() term.fit() +document.body.onresize = function () { + term.fit() + term.resize(term.cols, term.rows) + console.log('document resize...') + console.log('geometry cols: ' + term.cols + ' rows: ' + term.rows) + 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('/') + '/' @@ -149,6 +154,12 @@ socket.on('connect', function () { socket.emit('geometry', term.cols, term.rows) console.log('geometry cols: ' + term.cols + ' rows: ' + term.rows) }) +socket.on('setTerminalOpts', function (data) { + console.log('terminalOpts: ' + JSON.stringify(data)) + term.setOption('cursorBlink', data.cursorBlink) + term.setOption('scrollback', data.scrollback) + term.setOption('tabStopWidth', data.tabStopWidth) +}) term.on('data', function (data) { socket.emit('data', data) }) diff --git a/socket.js b/socket.js index 0a8c7f4..0e3c84b 100644 --- a/socket.js +++ b/socket.js @@ -29,8 +29,10 @@ module.exports = function socket (socket) { }) conn.on('ready', function connOnReady () { - console.log('WebSSH2 Login: user=' + socket.request.session.username + ' from=' + socket.handshake.address + ' host=' + socket.request.session.ssh.host + ' port=' + socket.request.session.ssh.port + ' sessionID=' + socket.request.sessionID + '/' + socket.id + ' allowreplay=' + socket.request.session.ssh.allowreplay + ' term=' + socket.request.session.ssh.term) + console.log('WebSSH2 Login: user=' + socket.request.session.username + ' from=' + socket.handshake.address + ' host=' + socket.request.session.ssh.host + ' port=' + socket.request.session.ssh.port + ' sessionID=' + socket.request.sessionID + '/' + socket.id + ' MRH_Session=' + socket.request.session.ssh.MRH_Session + ' allowreplay=' + socket.request.session.ssh.allowreplay + ' term=' + socket.request.session.ssh.term) + socket.emit('setTerminalOpts', socket.request.session.ssh.terminal) socket.emit('title', 'ssh://' + socket.request.session.ssh.host) + console.log('terminal: ' + JSON.stringify(socket.request.session.ssh.terminal)) if (socket.request.session.ssh.header.background) socket.emit('headerBackground', socket.request.session.ssh.header.background) if (socket.request.session.ssh.header.name) socket.emit('header', socket.request.session.ssh.header.name) socket.emit('footer', 'ssh://' + socket.request.session.username + '@' + socket.request.session.ssh.host + ':' + socket.request.session.ssh.port) @@ -64,12 +66,17 @@ module.exports = function socket (socket) { socket.on('control', function socketOnControl (controlData) { switch (controlData) { case 'replayCredentials': - stream.write(socket.request.session.userpassword + '\n') + if (socket.request.session.ssh.allowreplay) { + stream.write(socket.request.session.userpassword + '\n') + } /* falls through */ default: console.log('controlData: ' + controlData) } }) + socket.on('resize', function socketOnResize (data) { + stream.setWindow(data.rows, data.cols) + }) socket.on('disconnecting', function socketOnDisconnecting (reason) { debugWebSSH2('SOCKET DISCONNECTING: ' + reason) }) socket.on('disconnect', function socketOnDisconnect (reason) { debugWebSSH2('SOCKET DISCONNECT: ' + reason) diff --git a/src/js/index.js b/src/js/index.js index 883edda..1fc555d 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -37,15 +37,20 @@ logBtn.addEventListener('click', toggleLog) logBtn.style.color = '#000' var terminalContainer = document.getElementById('terminal-container') - -var term = new Terminal({ - cursorBlink: true -}) var socket, termid // eslint-disable-line +var term = new Terminal() term.open(terminalContainer) term.focus() term.fit() +document.body.onresize = function () { + term.fit() + term.resize(term.cols, term.rows) + console.log('document resize...') + console.log('geometry cols: ' + term.cols + ' rows: ' + term.rows) + 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('/') + '/' @@ -61,6 +66,12 @@ socket.on('connect', function () { socket.emit('geometry', term.cols, term.rows) console.log('geometry cols: ' + term.cols + ' rows: ' + term.rows) }) +socket.on('setTerminalOpts', function (data) { + console.log('terminalOpts: ' + JSON.stringify(data)) + term.setOption('cursorBlink', data.cursorBlink) + term.setOption('scrollback', data.scrollback) + term.setOption('tabStopWidth', data.tabStopWidth) +}) term.on('data', function (data) { socket.emit('data', data) }) diff --git a/util.js b/util.js index 8137112..546a0b5 100644 --- a/util.js +++ b/util.js @@ -21,3 +21,8 @@ exports.basicAuth = function basicAuth (req, res, next) { res.end('Username and password required for web SSH service.') } } + +// takes a string, makes it boolean (true if the string is true, false otherwise) +exports.parseBool = function parseBool (str) { + return (str.toLowerCase() === 'true') +}