Initial Commit
Initial Commit
This commit is contained in:
commit
638fafb95d
6 changed files with 281 additions and 0 deletions
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
104
index.js
Normal file
104
index.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
var express = require('express');
|
||||
var app = express();
|
||||
var server = require('http').Server(app);
|
||||
var io = require('socket.io')(server);
|
||||
var path = require('path');
|
||||
var basicAuth = require('basic-auth');
|
||||
var term = require('term.js');
|
||||
var ssh = require('ssh2');
|
||||
|
||||
var username = null;
|
||||
var password = null;
|
||||
var host = null;
|
||||
var port = 22;
|
||||
var header = 'Default Header';
|
||||
var headerBackground = 'rgb (0,90,0)';
|
||||
|
||||
function checkParams(arr) {
|
||||
return function(req, res, next) {
|
||||
// Make sure each param listed in arr is present in req.query
|
||||
var missing_params = [];
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (!eval("req.query." + arr[i])) {
|
||||
missing_params.push(arr[i]);
|
||||
}
|
||||
}
|
||||
if (missing_params.length == 0) {
|
||||
next();
|
||||
} else {
|
||||
next(JSON.stringify({
|
||||
"error": "query error",
|
||||
"message": "Parameter(s) missing: " + missing_params.join(",")
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server.listen({
|
||||
host: '127.0.0.1',
|
||||
port: 2222
|
||||
});
|
||||
|
||||
app.use(express.static(__dirname + '/public')).use(term.middleware()).use(function(req, res, next) {
|
||||
var myAuth = basicAuth(req);
|
||||
if (myAuth === undefined) {
|
||||
res.statusCode = 401;
|
||||
res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"');
|
||||
res.end('Username and password required for web SSH service.');
|
||||
} else {
|
||||
username = myAuth['name'];
|
||||
password = myAuth['pass'];
|
||||
next();
|
||||
}
|
||||
}).get('/', checkParams(["host"]), function(req, res) {
|
||||
res.sendFile(path.join(__dirname + '/public/client.htm'))
|
||||
host = req.query.host
|
||||
if (typeof req.query.port !== 'undefined' && req.query.port !== null){ port = req.query.port;}
|
||||
if (typeof req.query.header !== 'undefined' && req.query.header !== null){ header = req.query.header;}
|
||||
if (typeof req.query.headerBackground !== 'undefined' && req.query.headerBackground !== null){ headerBackground = req.query.headerBackground;}
|
||||
// debug // console.log('varibles passwd: ' + username + '/' + host + '/' + port);
|
||||
});
|
||||
|
||||
io.on('connection', function(socket) {
|
||||
var conn = new ssh();
|
||||
conn.on('banner', function(msg, lng) {
|
||||
socket.emit('data', msg);
|
||||
}).on('ready', function() {
|
||||
socket.emit('title', 'ssh://' + host);
|
||||
socket.emit('headerBackground', headerBackground);
|
||||
socket.emit('header', header);
|
||||
socket.emit('footer', 'ssh://' + username + '@' + host + ':' + port);
|
||||
socket.emit('status', 'SSH CONNECTION ESTABLISHED');
|
||||
socket.emit('statusBackground', 'green');
|
||||
conn.shell(function(err, stream) {
|
||||
if (err) return socket.emit('status', 'SSH EXEC ERROR: ' + err.message).emit('statusBackground', 'red');
|
||||
socket.on('data', function(data) {
|
||||
stream.write(data);
|
||||
});
|
||||
stream.on('data', function(d) {
|
||||
socket.emit('data', d.toString('binary'));
|
||||
}).on('close', function() {
|
||||
conn.end();
|
||||
});
|
||||
});
|
||||
}).on('end', function() {
|
||||
socket.emit('status', 'SSH CONNECTION CLOSED BY HOST');
|
||||
socket.emit('statusBackground', 'red');
|
||||
}).on('close', function() {
|
||||
socket.emit('status', 'SSH CONNECTION CLOSED');
|
||||
socket.emit('statusBackground', 'red');
|
||||
}).on('error', function(error) {
|
||||
socket.emit('status', 'SSH CONNECTION ERROR - ' + error)
|
||||
socket.emit('statusBackground', 'red');
|
||||
}).connect({
|
||||
host: host,
|
||||
port: port,
|
||||
username: username,
|
||||
password: password,
|
||||
// some cisco routers need the these cipher strings
|
||||
algorithms: {
|
||||
'cipher': ['aes128-cbc', '3des-cbc', 'aes256-cbc'],
|
||||
'hmac': ['hmac-sha1', 'hmac-sha1-96', 'hmac-md5-96']
|
||||
}
|
||||
});
|
||||
});
|
19
package.json
Normal file
19
package.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"BIG-IP-comments": [
|
||||
"package.json is the standard npm (www.npmjs.org) package definition file.",
|
||||
"For more information please see www.npmjs.org/doc/package.json.html. "
|
||||
],
|
||||
"description": "A custom iRulesLX extension for BIG-IP",
|
||||
"private": true,
|
||||
"repository": {},
|
||||
"engines": {
|
||||
"node": "0.11.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"basic-auth": "^1.0.3",
|
||||
"express": "^4.13.4",
|
||||
"socket.io": "^1.4.5",
|
||||
"ssh2": "^0.5.0",
|
||||
"term.js": "0.0.7"
|
||||
}
|
||||
}
|
22
public/client.htm
Normal file
22
public/client.htm
Normal file
|
@ -0,0 +1,22 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Web SSH</title>
|
||||
<link rel="stylesheet" href="/xterm.css" />
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
<script src="/term.js"></script>
|
||||
<script src="/client.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header"></div>
|
||||
<div id="terminal" class="terminal">
|
||||
<script>
|
||||
client.run();
|
||||
</script>
|
||||
</div>
|
||||
<div id="bottomdiv">
|
||||
<div id="footer"></div>
|
||||
<div id="status"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
33
public/client.js
Normal file
33
public/client.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
var client = {};
|
||||
client.run = function(options) {
|
||||
options = options || {};
|
||||
window.addEventListener('load', function() {
|
||||
var socket = io.connect();
|
||||
socket.on('connect', function() {
|
||||
var term = new Terminal();
|
||||
term.on('data', function(data) {
|
||||
socket.emit('data', data);
|
||||
});
|
||||
socket.on('title', function(data) {
|
||||
document.title = data;
|
||||
}).on('status', function(data) {
|
||||
document.getElementById('status').innerHTML = data;
|
||||
}).on('headerBackground', function(data) {
|
||||
document.getElementById('header').style.backgroundColor = data;
|
||||
}).on('header', function(data) {
|
||||
document.getElementById('header').innerHTML = data;
|
||||
}).on('footer', function(data) {
|
||||
document.getElementById('footer').innerHTML = data;
|
||||
}).on('statusBackground', function(data) {
|
||||
document.getElementById('status').style.backgroundColor = data;
|
||||
});
|
||||
term.open(document.getElementById("terminal"));
|
||||
socket.on('data', function(data) {
|
||||
term.write(data);
|
||||
}).on('disconnect', function() {
|
||||
document.getElementById('status').innerHTML = 'WEBSOCKET SERVER DISCONNECTED';
|
||||
socket.io.reconnection(false);
|
||||
});
|
||||
});
|
||||
}, false);
|
||||
}
|
66
public/style.css
Normal file
66
public/style.css
Normal file
|
@ -0,0 +1,66 @@
|
|||
body {
|
||||
font-family: helvetica, sans-serif, arial;
|
||||
font-size: 1em;
|
||||
color: #111;
|
||||
background-color: rgb(0, 0, 0);
|
||||
color: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
#header {
|
||||
color: rgb(240, 240, 240);
|
||||
background-color: rgb(0, 128, 0);
|
||||
width: 100%;
|
||||
border-color: white;
|
||||
border-style: none none solid none;
|
||||
border-width: 1px;
|
||||
text-align: center;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
#terminal {
|
||||
width: 960px;
|
||||
height: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#terminal .terminal {
|
||||
background-color: #111;
|
||||
color: #fafafa;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#terminal .terminal .terminal-cursor {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
#bottomdiv {
|
||||
width: 100%;
|
||||
background-color: rgb(50, 50, 50);
|
||||
border-color: white;
|
||||
border-style: solid none none none;
|
||||
border-width: 1px;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
#footer {
|
||||
display: inline-block;
|
||||
color: rgb(240, 240, 240);
|
||||
background-color: rgb(50, 50, 50);
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#status {
|
||||
display: inline-block;
|
||||
color: rgb(240, 240, 240);
|
||||
background-color: rgb(50, 50, 50);
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
border-color: white;
|
||||
border-style: none solid none solid;
|
||||
border-width: 1px;
|
||||
text-align: left;
|
||||
z-index: 100;
|
||||
}
|
Loading…
Reference in a new issue