mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2025-10-16 12:05:41 +00:00
436 lines
13 KiB
TypeScript
436 lines
13 KiB
TypeScript
import * as fs from "fs";
|
|
import * as crypto from "crypto";
|
|
import * as ssh2 from 'ssh2';
|
|
import * as ssh2_streams from 'ssh2-streams';
|
|
|
|
declare var inspect: any;
|
|
|
|
//
|
|
// # Client Examples
|
|
//
|
|
|
|
// Authenticate using keys and execute uptime on a server:
|
|
|
|
var Client = require('ssh2').Client;
|
|
|
|
var conn = new Client();
|
|
conn.on('ready', () => {
|
|
console.log('Client :: ready');
|
|
conn.exec('uptime', (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) throw err;
|
|
stream
|
|
.on('close', (code: any, signal: any) => {
|
|
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
|
|
conn.end();
|
|
}).on('data', (data: any) => {
|
|
console.log('STDOUT: ' + data);
|
|
}).stderr.on('data', (data: any) => {
|
|
console.log('STDERR: ' + data);
|
|
});
|
|
});
|
|
}).connect({
|
|
host: '192.168.100.100',
|
|
port: 22,
|
|
username: 'frylock',
|
|
privateKey: require('fs').readFileSync('/here/is/my/key')
|
|
});
|
|
|
|
// Authenticate using keys and start an interactive shell session:
|
|
|
|
var Client = require('ssh2').Client;
|
|
|
|
var conn = new Client();
|
|
conn.on('ready', () => {
|
|
console.log('Client :: ready');
|
|
conn.shell( (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) throw err;
|
|
stream.on('close', () => {
|
|
console.log('Stream :: close');
|
|
conn.end();
|
|
}).on('data', (data: any) => {
|
|
console.log('STDOUT: ' + data);
|
|
}).stderr.on('data', (data: any) => {
|
|
console.log('STDERR: ' + data);
|
|
});
|
|
stream.end('ls -l\nexit\n');
|
|
});
|
|
}).connect({
|
|
host: '192.168.100.100',
|
|
port: 22,
|
|
username: 'frylock',
|
|
privateKey: require('fs').readFileSync('/here/is/my/key')
|
|
});
|
|
|
|
// Authenticate using password and send an HTTP request to port 80 on the server:
|
|
|
|
var Client = require('ssh2').Client;
|
|
|
|
var conn = new Client();
|
|
conn.on('ready', () => {
|
|
console.log('Client :: ready');
|
|
conn.forwardOut('192.168.100.102', 8000, '127.0.0.1', 80, (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) throw err;
|
|
stream.on('close', () => {
|
|
console.log('TCP :: CLOSED');
|
|
conn.end();
|
|
}).on('data', (data: any) => {
|
|
console.log('TCP :: DATA: ' + data);
|
|
}).end([
|
|
'HEAD / HTTP/1.1',
|
|
'User-Agent: curl/7.27.0',
|
|
'Host: 127.0.0.1',
|
|
'Accept: */*',
|
|
'Connection: close',
|
|
'',
|
|
''
|
|
].join('\r\n'));
|
|
});
|
|
}).connect({
|
|
host: '192.168.100.100',
|
|
port: 22,
|
|
username: 'frylock',
|
|
password: 'nodejsrules'
|
|
});
|
|
|
|
// Authenticate using password and forward remote connections on port 8000 to us:
|
|
|
|
var Client = require('ssh2').Client;
|
|
|
|
var conn = new Client();
|
|
conn.on('ready', () => {
|
|
console.log('Client :: ready');
|
|
conn.forwardIn('127.0.0.1', 8000, (err: Error) => {
|
|
if (err) throw err;
|
|
console.log('Listening for connections on server on port 8000!');
|
|
});
|
|
}).on('tcp connection', (info: any, accept: Function, reject: Function) => {
|
|
console.log('TCP :: INCOMING CONNECTION:');
|
|
console.dir(info);
|
|
accept().on('close', () => {
|
|
console.log('TCP :: CLOSED');
|
|
}).on('data', (data: any) => {
|
|
console.log('TCP :: DATA: ' + data);
|
|
}).end([
|
|
'HTTP/1.1 404 Not Found',
|
|
'Date: Thu, 15 Nov 2012 02:07:58 GMT',
|
|
'Server: ForwardedConnection',
|
|
'Content-Length: 0',
|
|
'Connection: close',
|
|
'',
|
|
''
|
|
].join('\r\n'));
|
|
}).connect({
|
|
host: '192.168.100.100',
|
|
port: 22,
|
|
username: 'frylock',
|
|
password: 'nodejsrules'
|
|
});
|
|
|
|
// Authenticate using password and get a directory listing via SFTP:
|
|
|
|
var Client = require('ssh2').Client;
|
|
|
|
var conn = new Client();
|
|
conn.on('ready', () => {
|
|
console.log('Client :: ready');
|
|
conn.sftp( (err: Error, sftp: ssh2.SFTPWrapper) => {
|
|
if (err) throw err;
|
|
sftp.readdir('foo', (err: Error, list: ssh2_streams.FileEntry[]) => {
|
|
if (err) throw err;
|
|
console.dir(list);
|
|
conn.end();
|
|
});
|
|
});
|
|
}).connect({
|
|
host: '192.168.100.100',
|
|
port: 22,
|
|
username: 'frylock',
|
|
password: 'nodejsrules'
|
|
});
|
|
|
|
// Connection hopping:
|
|
|
|
var Client = require('ssh2').Client;
|
|
|
|
var conn1 = new Client(),
|
|
conn2 = new Client();
|
|
|
|
conn1.on('ready', () => {
|
|
console.log('FIRST :: connection ready');
|
|
conn1.exec('nc 192.168.1.2 22', (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) {
|
|
console.log('FIRST :: exec error: ' + err);
|
|
return conn1.end();
|
|
}
|
|
conn2.connect({
|
|
sock: stream,
|
|
username: 'user2',
|
|
password: 'password2',
|
|
});
|
|
});
|
|
}).connect({
|
|
host: '192.168.1.1',
|
|
username: 'user1',
|
|
password: 'password1',
|
|
});
|
|
|
|
conn2.on('ready', () => {
|
|
console.log('SECOND :: connection ready');
|
|
conn2.exec('uptime', (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) {
|
|
console.log('SECOND :: exec error: ' + err);
|
|
return conn1.end();
|
|
}
|
|
stream.on('end', () => {
|
|
conn1.end(); // close parent (and this) connection
|
|
}).on('data', (data: any) => {
|
|
console.log(data.toString());
|
|
});
|
|
});
|
|
});
|
|
|
|
// Forward X11 connections (xeyes):
|
|
|
|
var net = require('net'),
|
|
Client = require('ssh2').Client;
|
|
|
|
var conn = new Client();
|
|
|
|
conn.on('x11', (info: any, accept: any, reject: any) => {
|
|
var xserversock = new net.Socket();
|
|
xserversock.on('connect', () => {
|
|
var xclientsock = accept();
|
|
xclientsock.pipe(xserversock).pipe(xclientsock);
|
|
});
|
|
// connects to localhost:0.0
|
|
xserversock.connect(6000, 'localhost');
|
|
});
|
|
|
|
conn.on('ready', () => {
|
|
conn.exec('xeyes', { x11: true }, (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) throw err;
|
|
var code = 0;
|
|
stream.on('end', () => {
|
|
if (code !== 0)
|
|
console.log('Do you have X11 forwarding enabled on your SSH server?');
|
|
conn.end();
|
|
}).on('exit', (exitcode: number) => {
|
|
code = exitcode;
|
|
});
|
|
});
|
|
}).connect({
|
|
host: '192.168.1.1',
|
|
username: 'foo',
|
|
password: 'bar'
|
|
});
|
|
|
|
// Dynamic (1:1) port forwarding using a SOCKSv5 proxy (using socksv5):
|
|
|
|
var socks = require('socksv5'),
|
|
Client = require('ssh2').Client;
|
|
|
|
var ssh_config = {
|
|
host: '192.168.100.1',
|
|
port: 22,
|
|
username: 'nodejs',
|
|
password: 'rules'
|
|
};
|
|
|
|
socks.createServer( (info: any, accept: any, deny: any) => {
|
|
// NOTE: you could just use one ssh2 client connection for all forwards, but
|
|
// you could run into server-imposed limits if you have too many forwards open
|
|
// at any given time
|
|
var conn = new Client();
|
|
conn.on('ready', () => {
|
|
conn.forwardOut(info.srcAddr,
|
|
info.srcPort,
|
|
info.dstAddr,
|
|
info.dstPort,
|
|
(err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) {
|
|
conn.end();
|
|
return deny();
|
|
}
|
|
|
|
var clientSocket: any;
|
|
if (clientSocket = accept(true)) {
|
|
stream.pipe(clientSocket).pipe(stream).on('close', () => {
|
|
conn.end();
|
|
});
|
|
} else
|
|
conn.end();
|
|
});
|
|
}).on('error', (err: Error) => {
|
|
deny();
|
|
}).connect(ssh_config);
|
|
}).listen(1080, 'localhost', () => {
|
|
console.log('SOCKSv5 proxy server started on port 1080');
|
|
}).useAuth(socks.auth.None());
|
|
|
|
// Invoke an arbitrary subsystem (netconf in this example):
|
|
|
|
var Client = require('ssh2').Client,
|
|
xmlhello = '<?xml version="1.0" encoding="UTF-8"?>'+
|
|
'<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">'+
|
|
' <capabilities>'+
|
|
' <capability>urn:ietf:params:netconf:base:1.0</capability>'+
|
|
' </capabilities>'+
|
|
'</hello>]]>]]>';
|
|
|
|
var conn = new Client();
|
|
|
|
conn.on('ready', () => {
|
|
console.log('Client :: ready');
|
|
conn.subsys('netconf', (err: Error, stream: ssh2.ClientChannel) => {
|
|
if (err) throw err;
|
|
stream.on('data', (data: any) => {
|
|
console.log(data);
|
|
}).write(xmlhello);
|
|
});
|
|
}).connect({
|
|
host: '1.2.3.4',
|
|
port: 22,
|
|
username: 'blargh',
|
|
password: 'honk'
|
|
});
|
|
|
|
// ConnectConfig
|
|
|
|
const sshconfig: ssh2.ConnectConfig = {
|
|
host: 'localhost',
|
|
port: 22,
|
|
username: 'ubuntu',
|
|
password: 'password'
|
|
};
|
|
|
|
//
|
|
// # Server Examples
|
|
//
|
|
|
|
// Only allow password and public key authentication and command execution:
|
|
|
|
var buffersEqual = require('buffer-equal-constant-time'),
|
|
//ssh2 = require('ssh2'),
|
|
utils = ssh2.utils;
|
|
|
|
var pubKey = utils.parseKey(fs.readFileSync('user.pub')) as ssh2_streams.ParsedKey;
|
|
var pubKeySSH = Buffer.from(pubKey.getPublicSSH());
|
|
|
|
new ssh2.Server({
|
|
hostKeys: [fs.readFileSync('host.key')]
|
|
}, (client: ssh2.Connection) => {
|
|
console.log('Client connected!');
|
|
|
|
client.on('authentication', ctx => {
|
|
if (ctx.method === 'password'
|
|
&& ctx.username === 'foo'
|
|
&& ctx.password === 'bar')
|
|
ctx.accept();
|
|
else if (ctx.method === 'publickey'
|
|
&& ctx.key.algo === pubKey.type
|
|
&& buffersEqual(ctx.key.data, pubKeySSH)) {
|
|
if (ctx.signature) {
|
|
if (pubKey.verify(ctx.blob, ctx.signature)) {
|
|
ctx.accept();
|
|
} else {
|
|
ctx.reject();
|
|
}
|
|
} else {
|
|
// if no signature present, that means the client is just checking
|
|
// the validity of the given public key
|
|
ctx.accept();
|
|
}
|
|
} else
|
|
ctx.reject();
|
|
}).on('ready', () => {
|
|
console.log('Client authenticated!');
|
|
|
|
client.on('session', (accept: any, reject: any) => {
|
|
var session = accept();
|
|
session.once('exec', (accept: any, reject: any, info: any) => {
|
|
console.log('Client wants to execute: ' + inspect(info.command));
|
|
var stream = accept();
|
|
stream.stderr.write('Oh no, the dreaded errors!\n');
|
|
stream.write('Just kidding about the errors!\n');
|
|
stream.exit(0);
|
|
stream.end();
|
|
});
|
|
});
|
|
}).on('end', () => {
|
|
console.log('Client disconnected');
|
|
});
|
|
}).listen(0, '127.0.0.1', function () {
|
|
console.log('Listening on port ' + this.address().port);
|
|
});
|
|
|
|
// SFTP only server:
|
|
|
|
//var ssh2 = require('ssh2');
|
|
var OPEN_MODE = ssh2.SFTP_OPEN_MODE,
|
|
STATUS_CODE = ssh2.SFTP_STATUS_CODE;
|
|
|
|
new ssh2.Server({
|
|
hostKeys: [fs.readFileSync('host.key')]
|
|
}, (client: any) => {
|
|
console.log('Client connected!');
|
|
|
|
client.on('authentication', (ctx: any) => {
|
|
if (ctx.method === 'password'
|
|
&& ctx.username === 'foo'
|
|
&& ctx.password === 'bar')
|
|
ctx.accept();
|
|
else
|
|
ctx.reject();
|
|
}).on('ready', () => {
|
|
console.log('Client authenticated!');
|
|
|
|
client.on('session', (accept: any, reject: any) => {
|
|
var session = accept();
|
|
session.on('sftp', (accept: any, reject: any) => {
|
|
console.log('Client SFTP session');
|
|
var openFiles = new Set<number>();
|
|
var handleCount = 0;
|
|
// `sftpStream` is an `SFTPStream` instance in server mode
|
|
// see: https://github.com/mscdex/ssh2-streams/blob/master/SFTPStream.md
|
|
var sftpStream = accept();
|
|
sftpStream.on('OPEN', (reqid: any, filename: any, flags: any, attrs: any) => {
|
|
// only allow opening /tmp/foo.txt for writing
|
|
if (filename !== '/tmp/foo.txt' || !(flags & OPEN_MODE.WRITE))
|
|
return sftpStream.status(reqid, STATUS_CODE.FAILURE);
|
|
// create a fake handle to return to the client, this could easily
|
|
// be a real file descriptor number for example if actually opening
|
|
// the file on the disk
|
|
var handle = new Buffer(4);
|
|
openFiles.add(handleCount);
|
|
handle.writeUInt32BE(handleCount++, 0);
|
|
sftpStream.handle(reqid, handle);
|
|
console.log('Opening file for write')
|
|
}).on('WRITE', (reqid: any, handle: any, offset: any, data: any) => {
|
|
if (handle.length !== 4 || !openFiles.has(handle.readUInt32BE(0)))
|
|
return sftpStream.status(reqid, STATUS_CODE.FAILURE);
|
|
// fake the write
|
|
sftpStream.status(reqid, STATUS_CODE.OK);
|
|
var inspected = require('util').inspect(data);
|
|
console.log('Write to file at offset %d: %s', offset, inspected);
|
|
}).on('CLOSE', (reqid: any, handle: any) => {
|
|
var fnum: any;
|
|
if (handle.length !== 4 || !openFiles.has((fnum = handle.readUInt32BE(0))))
|
|
return sftpStream.status(reqid, STATUS_CODE.FAILURE);
|
|
openFiles.delete(fnum);
|
|
sftpStream.status(reqid, STATUS_CODE.OK);
|
|
console.log('Closing file');
|
|
});
|
|
});
|
|
});
|
|
}).on('end', () => {
|
|
console.log('Client disconnected');
|
|
});
|
|
}).listen(0, '127.0.0.1', function () {
|
|
console.log('Listening on port ' + this.address().port);
|
|
});
|
|
|
|
|
|
|
|
|
|
|