-
Notifications
You must be signed in to change notification settings - Fork 537
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
024dd75
commit 982780e
Showing
4 changed files
with
219 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,16 +71,8 @@ let config = { | |
'[email protected]', | ||
'aes256-cbc', | ||
], | ||
hmac: [ | ||
'hmac-sha2-256', | ||
'hmac-sha2-512', | ||
'hmac-sha1', | ||
], | ||
compress: [ | ||
'none', | ||
'[email protected]', | ||
'zlib', | ||
], | ||
hmac: ['hmac-sha2-256', 'hmac-sha2-512', 'hmac-sha1'], | ||
compress: ['none', '[email protected]', 'zlib'], | ||
}, | ||
serverlog: { | ||
client: false, | ||
|
@@ -99,11 +91,15 @@ try { | |
console.log(`webssh2 service reading config from: ${configPath}`); | ||
config = require('read-config-ng')(configPath) // eslint-disable-line | ||
} 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}`); | ||
} | ||
|
@@ -120,7 +116,11 @@ const app = express(); | |
const server = require('http').Server(app); | ||
|
||
const validator = require('validator'); | ||
const io = require('socket.io')(server, { serveClient: false, path: '/ssh/socket.io', origins: config.http.origins }); | ||
const io = require('socket.io')(server, { | ||
serveClient: false, | ||
path: '/ssh/socket.io', | ||
origins: config.http.origins, | ||
}); | ||
const favicon = require('serve-favicon'); | ||
const appSocket = require('./socket'); | ||
const expressOptions = require('./expressOptions'); | ||
|
@@ -166,20 +166,26 @@ app.use(favicon(path.join(publicPath, 'favicon.ico'))); | |
|
||
app.get('/ssh/reauth', (req, res) => { | ||
const 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?', (req, res) => { | ||
res.sendFile(path.join(path.join(publicPath, 'client.htm'))); | ||
// capture, assign, and validate variables | ||
req.session.ssh = { | ||
host: config.ssh.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), | ||
port: (validator.isInt(`${req.query.port}`, { min: 1, max: 65535 }) | ||
&& req.query.port) || config.ssh.port, | ||
host: | ||
config.ssh.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), | ||
port: | ||
(validator.isInt(`${req.query.port}`, { min: 1, max: 65535 }) && req.query.port) || | ||
config.ssh.port, | ||
localAddress: config.ssh.localAddress, | ||
localPort: config.ssh.localPort, | ||
header: { | ||
|
@@ -190,23 +196,44 @@ app.get('/ssh/host/:host?', (req, res) => { | |
keepaliveInterval: config.ssh.keepaliveInterval, | ||
keepaliveCountMax: config.ssh.keepaliveCountMax, | ||
allowedSubnets: config.ssh.allowedSubnets, | ||
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); | ||
|
@@ -228,42 +255,41 @@ io.on('connection', appSocket); | |
// socket.io | ||
// expose express session with socket.request.session | ||
io.use((socket, next) => { | ||
(socket.request.res) | ||
? session(socket.request, socket.request.res, next) | ||
: next(next); // eslint disable-line | ||
socket.request.res ? session(socket.request, socket.request.res, next) : next(next); // eslint disable-line | ||
}); | ||
|
||
io.on('connection', (socket) => { | ||
connectionCount += 1; | ||
|
||
socket.on('disconnect', () => { | ||
connectionCount -= 1; | ||
if ((connectionCount <= 0) && shutdownMode) { | ||
if (connectionCount <= 0 && shutdownMode) { | ||
stopApp('All clients disconnected'); | ||
} | ||
}); | ||
}); | ||
|
||
const signals = ['SIGTERM', 'SIGINT']; | ||
signals.forEach((signal) => process.on(signal, () => { | ||
if (shutdownMode) stopApp('Safe shutdown aborted, force quitting'); | ||
else if (connectionCount > 0) { | ||
let remainingSeconds = config.safeShutdownDuration; | ||
shutdownMode = true; | ||
const message = (connectionCount === 1) | ||
? ' client is still connected' | ||
: ' clients are still connected'; | ||
console.error(connectionCount + message); | ||
console.error(`Starting a ${remainingSeconds} seconds countdown`); | ||
console.error('Press Ctrl+C again to force quit'); | ||
signals.forEach((signal) => | ||
process.on(signal, () => { | ||
if (shutdownMode) stopApp('Safe shutdown aborted, force quitting'); | ||
else if (connectionCount > 0) { | ||
let remainingSeconds = config.safeShutdownDuration; | ||
shutdownMode = true; | ||
const message = | ||
connectionCount === 1 ? ' client is still connected' : ' clients are still connected'; | ||
console.error(connectionCount + message); | ||
console.error(`Starting a ${remainingSeconds} seconds countdown`); | ||
console.error('Press Ctrl+C again to force quit'); | ||
|
||
shutdownInterval = setInterval(() => { | ||
remainingSeconds -= 1; | ||
if ((remainingSeconds) <= 0) { | ||
stopApp('Countdown is over'); | ||
} else { | ||
io.sockets.emit('shutdownCountdownUpdate', remainingSeconds); | ||
} | ||
}, 1000); | ||
} else stopApp(); | ||
})); | ||
shutdownInterval = setInterval(() => { | ||
remainingSeconds -= 1; | ||
if (remainingSeconds <= 0) { | ||
stopApp('Countdown is over'); | ||
} else { | ||
io.sockets.emit('shutdownCountdownUpdate', remainingSeconds); | ||
} | ||
}, 1000); | ||
} else stopApp(); | ||
}) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.