diff --git a/app.js b/app.js index f39a299..32d86db 100644 --- a/app.js +++ b/app.js @@ -1,12 +1,10 @@ -const express = require('express'); -const http = require('http'); -const https = require('https'); -const path = require('path'); -const server = require('socket.io'); -const pty = require('pty.js'); +const wetty = require('./package.js'); const fs = require('fs'); +const path = require('path'); + +const optimist = require('optimist'); -const opts = require('optimist') +const opts = optimist .options({ sslkey: { demand : false, @@ -37,38 +35,26 @@ const opts = require('optimist') alias : 'p', description: 'wetty listen port', }, + help: { + demand : false, + alias : 'h', + description: 'Print help message', + }, }) .boolean('allow_discovery').argv; -let runhttps = process.env.HTTPS || false; -let globalsshuser = process.env.SSHUSER || ''; -let sshhost = process.env.SSHHOST || 'localhost'; -let sshauth = process.env.SSHAUTH || 'password'; -let sshport = process.env.SSHPOST || 22; -let port = process.env.PORT || 3000; - -if (opts.sshport) { - sshport = opts.sshport; -} - -if (opts.sshhost) { - sshhost = opts.sshhost; -} - -if (opts.sshauth) { - sshauth = opts.sshauth; -} - -if (opts.sshuser) { - globalsshuser = opts.sshuser; +if (opts.help) { + optimist.showHelp(); + process.exit(0); } -if (opts.port) { - port = opts.port; -} +const globalsshuser = opts.sshuser || process.env.SSHUSER || ''; +const sshhost = opts.sshhost || process.env.SSHHOST || 'localhost'; +const sshauth = opts.sshauth || process.env.SSHAUTH || 'password'; +const sshport = opts.sshport || process.env.SSHPOST || 22; +const port = opts.port || process.env.PORT || 3000; if (opts.sslkey && opts.sslcert) { - runhttps = true; opts['ssl'] = {}; opts.ssl['key'] = fs.readFileSync(path.resolve(opts.sslkey)); opts.ssl['cert'] = fs.readFileSync(path.resolve(opts.sslcert)); @@ -78,85 +64,10 @@ process.on('uncaughtException', e => { console.error(`Error: ${e}`); }); -let httpserv; - -const app = express(); -app.use(require('serve-favicon')(`${__dirname}/public/favicon.ico`)); -// For using wetty at /wetty on a vhost -app.get('/wetty/ssh/:user', (req, res) => { - res.sendfile(`${__dirname}/public/wetty/index.html`); -}); -app.get('/wetty/', (req, res) => { - res.sendfile(`${__dirname}/public/wetty/index.html`); -}); -// For using wetty on a vhost by itself -app.get('/ssh/:user', (req, res) => { - res.sendfile(`${__dirname}/public/wetty/index.html`); -}); -app.get('/', (req, res) => { - res.sendfile(`${__dirname}/public/wetty/index.html`); +const e = wetty.serve(port, globalsshuser, sshhost, sshport, sshauth, opts.ssl); +e.on('exit', code => { + console.log(`exit with code: ${code}`); }); -// For serving css and javascript -app.use('/', express.static(path.join(__dirname, 'public'))); - -if (runhttps) { - httpserv = https.createServer(opts.ssl, app).listen(port, () => { - console.log(`https on port ${port}`); - }); -} else { - httpserv = http.createServer(app).listen(port, () => { - console.log(`http on port ${port}`); - }); -} - -const io = server(httpserv, { path: '/wetty/socket.io' }); -io.on('connection', socket => { - let sshuser = ''; - const request = socket.request; - console.log(`${new Date()} Connection accepted.`); - const match = request.headers.referer.match('.+/ssh/.+$'); - if (match) { - sshuser = `${match[0].split('/ssh/').pop()}@`; - } else if (globalsshuser) { - sshuser = `${globalsshuser}@`; - } - - let term; - if (process.getuid() === 0 && sshhost === 'localhost') { - term = pty.spawn('/bin/login', [], { - name: 'xterm-256color', - cols: 80, - rows: 30, - }); - } else if (sshuser) { - term = pty.spawn('ssh', [sshuser + sshhost, '-p', sshport, '-o', `PreferredAuthentications=${sshauth}`], { - name: 'xterm-256color', - cols: 80, - rows: 30, - }); - } else { - term = pty.spawn('./bin/ssh', [sshhost, '-p', sshport, '-o', `PreferredAuthentications=${sshauth}`], { - name: 'xterm-256color', - cols: 80, - rows: 30, - }); - } - - console.log(`${new Date()} PID=${term.pid} STARTED on behalf of user=${sshuser}`); - term.on('data', data => { - socket.emit('output', data); - }); - term.on('exit', code => { - console.log(`${new Date()} PID=${term.pid} ENDED`); - socket.emit('logout'); - }); - socket.on('resize', ({ col, row }) => { - term.resize(col, row); - }); - socket.on('input', data => { - term.write(data); - }); - socket.on('disconnect', () => { - term.end(); - }); +e.on('disconnect', () => { + console.log('disconnect'); }); diff --git a/package.js b/package.js new file mode 100755 index 0000000..a689ad1 --- /dev/null +++ b/package.js @@ -0,0 +1,99 @@ +const express = require('express'); +const http = require('http'); +const https = require('https'); +const path = require('path'); +const server = require('socket.io'); +const pty = require('pty.js'); +const EventEmitter = require('events'); + +const app = express(); +app.use(require('serve-favicon')(`${__dirname}/public/favicon.ico`)); +// For using wetty at /wetty on a vhost +app.get('/wetty/ssh/:user', (req, res) => { + res.sendfile(`${__dirname}/public/wetty/index.html`); +}); +app.get('/wetty/', (req, res) => { + res.sendfile(`${__dirname}/public/wetty/index.html`); +}); +// For using wetty on a vhost by itself +app.get('/ssh/:user', (req, res) => { + res.sendfile(`${__dirname}/public/wetty/index.html`); +}); +app.get('/', (req, res) => { + res.sendfile(`${__dirname}/public/wetty/index.html`); +}); +// For serving css and javascript +app.use('/', express.static(path.join(__dirname, 'public'))); + +function createServer (port, sslopts) { + if (sslopts && sslopts.key && sslopts.cert) { + return https.createServer(sslopts, app).listen(port, () => { + console.log(`https on port ${port}`); + }); + } + + return http.createServer(app).listen(port, () => { + console.log(`http on port ${port}`); + }); +} + +exports.serve = function (port, globalsshuser, sshhost, sshport, sshauth, sslopts) { + const httpserv = createServer(port, sslopts); + + const events = new EventEmitter(); + const io = server(httpserv, { path: '/wetty/socket.io' }); + io.on('connection', socket => { + let sshuser = ''; + const request = socket.request; + console.log(`${new Date()} Connection accepted.`); + const match = request.headers.referer.match('.+/ssh/.+$'); + if (match) { + sshuser = `${match[0].split('/ssh/').pop()}@`; + } else if (globalsshuser) { + sshuser = `${globalsshuser}@`; + } + + let term; + if (process.getuid() === 0 && sshhost === 'localhost') { + term = pty.spawn('/bin/login', [], { + name: 'xterm-256color', + cols: 80, + rows: 30, + }); + } else if (sshuser) { + term = pty.spawn('ssh', [sshuser + sshhost, '-p', sshport, '-o', `PreferredAuthentications=${sshauth}`], { + name: 'xterm-256color', + cols: 80, + rows: 30, + }); + } else { + term = pty.spawn('./bin/ssh', [sshhost, '-p', sshport, '-o', `PreferredAuthentications=${sshauth}`], { + name: 'xterm-256color', + cols: 80, + rows: 30, + }); + } + + console.log(`${new Date()} PID=${term.pid} STARTED on behalf of user=${sshuser}`); + term.on('data', data => { + socket.emit('output', data); + }); + term.on('exit', code => { + console.log(`${new Date()} PID=${term.pid} ENDED`); + socket.emit('logout'); + events.emit('exit', code); + }); + socket.on('resize', ({ col, row }) => { + term.resize(col, row); + }); + socket.on('input', data => { + term.write(data); + }); + socket.on('disconnect', () => { + term.end(); + events.emit('disconnect'); + }); + }); + + return events; +};