butlerx
8 years ago
9 changed files with 3207 additions and 148 deletions
@ -0,0 +1,2 @@ |
|||||
|
node_modules/ |
||||
|
public/ |
@ -0,0 +1,47 @@ |
|||||
|
{ |
||||
|
"extends": "standard", |
||||
|
"env": { |
||||
|
"es6": true, |
||||
|
"jest": true, |
||||
|
"node": true |
||||
|
}, |
||||
|
"globals": { |
||||
|
"GENTLY": true |
||||
|
}, |
||||
|
"rules": { |
||||
|
"no-multi-spaces": 0, |
||||
|
"comma-dangle": [ |
||||
|
"error", |
||||
|
"always-multiline" |
||||
|
], |
||||
|
"key-spacing": [ |
||||
|
"error", |
||||
|
{ |
||||
|
"multiLine": { |
||||
|
"beforeColon": false, |
||||
|
"afterColon": true |
||||
|
}, |
||||
|
"align": { |
||||
|
"beforeColon": false, |
||||
|
"afterColon": true, |
||||
|
"on": "colon", |
||||
|
"mode": "strict" |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
"semi": [ |
||||
|
"error", |
||||
|
"always" |
||||
|
], |
||||
|
"no-var": [ |
||||
|
"error" |
||||
|
], |
||||
|
"prefer-const": [ |
||||
|
"error", |
||||
|
{ |
||||
|
"destructuring": "any", |
||||
|
"ignoreReadBeforeAssign": false |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
@ -1,15 +1,12 @@ |
|||||
FROM node:0.10.38 |
FROM node:boron |
||||
MAINTAINER Nathan LeClaire <nathan@docker.com> |
MAINTAINER Nathan LeClaire <nathan@docker.com> |
||||
|
|
||||
ADD . /app |
ADD . /app |
||||
WORKDIR /app |
WORKDIR /app |
||||
|
RUN apt-get update && apt-get upgrade |
||||
RUN npm install |
RUN npm install |
||||
RUN apt-get update |
|
||||
RUN apt-get install -y vim |
|
||||
RUN useradd -d /home/term -m -s /bin/bash term |
|
||||
RUN echo 'term:term' | chpasswd |
|
||||
|
|
||||
EXPOSE 3000 |
EXPOSE 3000 |
||||
|
|
||||
ENTRYPOINT ["node"] |
ENTRYPOINT ["node"] |
||||
CMD ["app.js", "-p", "3000"] |
CMD ["app.js"] |
||||
|
@ -1,37 +1,36 @@ |
|||||
module.exports = function (grunt) { |
module.exports = grunt => { |
||||
|
require('load-grunt-tasks')(grunt); |
||||
|
|
||||
require('load-grunt-tasks')(grunt); |
const config = { |
||||
|
mkdir: { |
||||
var config = { |
tmp: { |
||||
mkdir: { |
options: { |
||||
tmp: { |
create: ['tmp'], |
||||
options: { |
|
||||
create: ['tmp'] |
|
||||
} |
|
||||
} |
|
||||
}, |
}, |
||||
gitclone: { |
}, |
||||
hterm: { |
}, |
||||
options: { |
gitclone: { |
||||
cwd: './tmp', |
hterm: { |
||||
repository: 'https://chromium.googlesource.com/apps/libapps' |
options: { |
||||
} |
cwd : './tmp', |
||||
} |
repository: 'https://chromium.googlesource.com/apps/libapps', |
||||
}, |
}, |
||||
shell: { |
}, |
||||
build_hterm: { |
}, |
||||
command: 'LIBDOT_SEARCH_PATH=$(pwd) ./libdot/bin/concat.sh -i ./hterm/concat/hterm_all.concat -o ../../public/wetty/hterm_all.js', |
shell: { |
||||
options: { |
build_hterm: { |
||||
execOptions: { |
command: 'LIBDOT_SEARCH_PATH=$(pwd) ./libdot/bin/concat.sh -i ./hterm/concat/hterm_all.concat -o ../../public/wetty/hterm_all.js', |
||||
cwd: './tmp/libapps' |
options: { |
||||
} |
execOptions: { |
||||
} |
cwd: './tmp/libapps', |
||||
} |
}, |
||||
}, |
}, |
||||
clean: ['./tmp'] |
}, |
||||
}; |
}, |
||||
|
clean: ['./tmp'], |
||||
|
}; |
||||
|
|
||||
grunt.initConfig(config); |
grunt.initConfig(config); |
||||
|
|
||||
grunt.registerTask('update-hterm', ['mkdir:tmp', 'gitclone:hterm', 'shell:build_hterm', 'clean']); |
grunt.registerTask('update-hterm', ['mkdir:tmp', 'gitclone:hterm', 'shell:build_hterm', 'clean']); |
||||
}; |
}; |
||||
|
@ -1,142 +1,149 @@ |
|||||
var express = require('express'); |
const express = require('express'); |
||||
var http = require('http'); |
const http = require('http'); |
||||
var https = require('https'); |
const https = require('https'); |
||||
var path = require('path'); |
const path = require('path'); |
||||
var server = require('socket.io'); |
const server = require('socket.io'); |
||||
var pty = require('pty.js'); |
const pty = require('pty.js'); |
||||
var fs = require('fs'); |
const fs = require('fs'); |
||||
|
|
||||
var opts = require('optimist') |
const opts = require('optimist') |
||||
.options({ |
.options({ |
||||
sslkey: { |
sslkey: { |
||||
demand: false, |
demand : false, |
||||
description: 'path to SSL key' |
description: 'path to SSL key', |
||||
}, |
}, |
||||
sslcert: { |
sslcert: { |
||||
demand: false, |
demand : false, |
||||
description: 'path to SSL certificate' |
description: 'path to SSL certificate', |
||||
}, |
}, |
||||
sshhost: { |
sshhost: { |
||||
demand: false, |
demand : false, |
||||
description: 'ssh server host' |
description: 'ssh server host', |
||||
}, |
}, |
||||
sshport: { |
sshport: { |
||||
demand: false, |
demand : false, |
||||
description: 'ssh server port' |
description: 'ssh server port', |
||||
}, |
}, |
||||
sshuser: { |
sshuser: { |
||||
demand: false, |
demand : false, |
||||
description: 'ssh user' |
description: 'ssh user', |
||||
}, |
}, |
||||
sshauth: { |
sshauth: { |
||||
demand: false, |
demand : false, |
||||
description: 'defaults to "password", you can use "publickey,password" instead' |
description: 'defaults to "password", you can use "publickey,password" instead', |
||||
}, |
}, |
||||
port: { |
port: { |
||||
demand: true, |
demand : false, |
||||
alias: 'p', |
alias : 'p', |
||||
description: 'wetty listen port' |
description: 'wetty listen port', |
||||
}, |
}, |
||||
}).boolean('allow_discovery').argv; |
}) |
||||
|
.boolean('allow_discovery').argv; |
||||
|
|
||||
var runhttps = false; |
let runhttps = process.env.HTTPS || false; |
||||
var sshport = 22; |
let globalsshuser = process.env.SSHUSER || ''; |
||||
var sshhost = 'localhost'; |
let sshhost = process.env.SSHHOST || 'localhost'; |
||||
var sshauth = 'password'; |
let sshauth = process.env.SSHAUTH || 'password'; |
||||
var globalsshuser = ''; |
let sshport = process.env.SSHPOST || 22; |
||||
|
let port = process.env.PORT || 3000; |
||||
|
|
||||
if (opts.sshport) { |
if (opts.sshport) { |
||||
sshport = opts.sshport; |
sshport = opts.sshport; |
||||
} |
} |
||||
|
|
||||
if (opts.sshhost) { |
if (opts.sshhost) { |
||||
sshhost = opts.sshhost; |
sshhost = opts.sshhost; |
||||
} |
} |
||||
|
|
||||
if (opts.sshauth) { |
if (opts.sshauth) { |
||||
sshauth = opts.sshauth |
sshauth = opts.sshauth; |
||||
} |
} |
||||
|
|
||||
if (opts.sshuser) { |
if (opts.sshuser) { |
||||
globalsshuser = opts.sshuser; |
globalsshuser = opts.sshuser; |
||||
|
} |
||||
|
|
||||
|
if (opts.port) { |
||||
|
port = opts.port; |
||||
} |
} |
||||
|
|
||||
if (opts.sslkey && opts.sslcert) { |
if (opts.sslkey && opts.sslcert) { |
||||
runhttps = true; |
runhttps = true; |
||||
opts['ssl'] = {}; |
opts['ssl'] = {}; |
||||
opts.ssl['key'] = fs.readFileSync(path.resolve(opts.sslkey)); |
opts.ssl['key'] = fs.readFileSync(path.resolve(opts.sslkey)); |
||||
opts.ssl['cert'] = fs.readFileSync(path.resolve(opts.sslcert)); |
opts.ssl['cert'] = fs.readFileSync(path.resolve(opts.sslcert)); |
||||
} |
} |
||||
|
|
||||
process.on('uncaughtException', function(e) { |
process.on('uncaughtException', e => { |
||||
console.error('Error: ' + e); |
console.error(`Error: ${e}`); |
||||
}); |
}); |
||||
|
|
||||
var httpserv; |
let httpserv; |
||||
|
|
||||
var app = express(); |
const app = express(); |
||||
app.get('/wetty/ssh/:user', function(req, res) { |
app.get('/wetty/ssh/:user', (req, res) => { |
||||
res.sendfile(__dirname + '/public/wetty/index.html'); |
res.sendfile(`${__dirname}/public/wetty/index.html`); |
||||
}); |
}); |
||||
app.use('/', express.static(path.join(__dirname, 'public'))); |
app.use('/', express.static(path.join(__dirname, 'public'))); |
||||
|
|
||||
if (runhttps) { |
if (runhttps) { |
||||
httpserv = https.createServer(opts.ssl, app).listen(opts.port, function() { |
httpserv = https.createServer(opts.ssl, app).listen(port, () => { |
||||
console.log('https on port ' + opts.port); |
console.log(`https on port ${port}`); |
||||
}); |
}); |
||||
} else { |
} else { |
||||
httpserv = http.createServer(app).listen(opts.port, function() { |
httpserv = http.createServer(app).listen(port, () => { |
||||
console.log('http on port ' + opts.port); |
console.log(`http on port ${port}`); |
||||
}); |
}); |
||||
} |
} |
||||
|
|
||||
var io = server(httpserv,{path: '/wetty/socket.io'}); |
const io = server(httpserv, { path: '/wetty/socket.io' }); |
||||
io.on('connection', function(socket){ |
io.on('connection', socket => { |
||||
var sshuser = ''; |
let sshuser = ''; |
||||
var request = socket.request; |
const request = socket.request; |
||||
console.log((new Date()) + ' Connection accepted.'); |
console.log(`${new Date()} Connection accepted.`); |
||||
if (match = request.headers.referer.match('/wetty/ssh/.+$')) { |
const match = request.headers.referer.match('/wetty/ssh/.+$'); |
||||
sshuser = match[0].replace('/wetty/ssh/', '') + '@'; |
if (match) { |
||||
} else if (globalsshuser) { |
sshuser = `${match[0].replace('/wetty/ssh/', '')}@`; |
||||
sshuser = globalsshuser + '@'; |
} else if (globalsshuser) { |
||||
} |
sshuser = `${globalsshuser}@`; |
||||
|
} |
||||
var 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) |
let term; |
||||
term.on('data', function(data) { |
if (process.getuid() === 0 && sshhost === 'localhost') { |
||||
socket.emit('output', data); |
term = pty.spawn('/bin/login', [], { |
||||
|
name: 'xterm-256color', |
||||
|
cols: 80, |
||||
|
rows: 30, |
||||
}); |
}); |
||||
term.on('exit', function(code) { |
} else if (sshuser) { |
||||
console.log((new Date()) + " PID=" + term.pid + " ENDED"); |
term = pty.spawn('ssh', [sshuser + sshhost, '-p', sshport, '-o', `PreferredAuthentications=${sshauth}`], { |
||||
socket.emit('logout'); |
name: 'xterm-256color', |
||||
|
cols: 80, |
||||
|
rows: 30, |
||||
}); |
}); |
||||
socket.on('resize', function(data) { |
} else { |
||||
term.resize(data.col, data.row); |
term = pty.spawn('./bin/ssh', [sshhost, '-p', sshport, '-o', `PreferredAuthentications=${sshauth}`], { |
||||
|
name: 'xterm-256color', |
||||
|
cols: 80, |
||||
|
rows: 30, |
||||
}); |
}); |
||||
socket.on('input', function(data) { |
} |
||||
term.write(data); |
|
||||
}); |
console.log(`${new Date()} PID=${term.pid} STARTED on behalf of user=${sshuser}`); |
||||
socket.on('disconnect', function() { |
term.on('data', data => { |
||||
term.end(); |
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(); |
||||
|
}); |
||||
|
}); |
||||
|
@ -1,3 +1,3 @@ |
|||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||
|
|
||||
require("../app"); |
require('../app'); |
||||
|
@ -0,0 +1,15 @@ |
|||||
|
version: "3" |
||||
|
|
||||
|
services: |
||||
|
wetty: |
||||
|
image: node:boron |
||||
|
container_name: wetty |
||||
|
build: . |
||||
|
tty: true |
||||
|
working_dir: /app |
||||
|
ports: |
||||
|
- "3000:3000" |
||||
|
environment: |
||||
|
PORT: 3000 |
||||
|
SSHHOST: 'localhost' |
||||
|
SSHPORT: 22 |
File diff suppressed because it is too large
Loading…
Reference in new issue