function Client() { if (!(this instanceof Client)) return new Client(); EventEmitter.call(this); this.config = { host: undefined, port: undefined, forceIPv4: undefined, forceIPv6: undefined, keepaliveCountMax: undefined, keepaliveInterval: undefined, readyTimeout: undefined, username: undefined, password: undefined, privateKey: undefined, publicKey: undefined, tryKeyboard: undefined, agent: undefined, allowAgentFwd: undefined, hostHashAlgo: undefined, hostHashCb: undefined, strictVendor: undefined, debug: undefined }; this._readyTimeout = undefined; this._channels = undefined; this._callbacks = undefined; this._forwarding = undefined; this._acceptX11 = undefined; this._agentFwdEnabled = undefined; this._curChan = undefined; this._remoteVer = undefined; this._sshstream = undefined; this._sock = undefined; this._resetKA = undefined; }
n/a
function Channel(info, client, opts) {
var streamOpts = {
highWaterMark: MAX_WINDOW,
allowHalfOpen: (!opts || (opts && opts.allowHalfOpen !== false))
};
this.allowHalfOpen = streamOpts.allowHalfOpen;
DuplexStream.call(this, streamOpts);
var self = this;
var server = opts && opts.server;
this.server = server;
this.type = info.type;
this.subtype = undefined;
/*
incoming and outgoing contain these properties:
{
id: undefined,
window: undefined,
packetSize: undefined,
state: 'closed'
}
*/
var incoming = this.incoming = info.incoming;
var incomingId = incoming.id;
var outgoing = this.outgoing = info.outgoing;
var callbacks = this._callbacks = [];
var exitCode;
var exitSignal;
var exitDump;
var exitDesc;
var exitLang;
this._client = client;
this._hasX11 = false;
var channels = client._channels;
var sshstream = client._sshstream;
function ondrain() {
if (self._waitClientDrain) {
self._waitClientDrain = false;
if (!self._waitWindow) {
if (self._chunk)
self._write(self._chunk, null, self._chunkcb);
else if (self._chunkcb)
self._chunkcb();
else if (self._chunkErr)
self.stderr._write(self._chunkErr, null, self._chunkcbErr);
else if (self._chunkcbErr)
self._chunkcbErr();
}
}
}
client._sock.on('drain', ondrain);
sshstream.once('CHANNEL_EOF:' + incomingId, function() {
if (incoming.state === 'closed' || incoming.state === 'eof')
return;
incoming.state = 'eof';
if (self.readable)
self.push(null);
if (!server && self.stderr.readable)
self.stderr.push(null);
}).once('CHANNEL_CLOSE:' + incomingId, function() {
if (incoming.state === 'closed')
return;
incoming.state = 'closed';
if (self.readable)
self.push(null);
if (server && self.stderr.writable)
self.stderr.end();
else if (!server && self.stderr.readable)
self.stderr.push(null);
if (outgoing.state === 'open' || outgoing.state === 'eof')
self.close();
if (outgoing.state === 'closing')
outgoing.state = 'closed';
delete channels[incomingId];
var state = self._writableState;
client._sock.removeListener('drain', ondrain);
if (!state.ending && !state.finished)
self.end();
// Take care of any outstanding channel requests
self._callbacks = [];
for (var i = 0; i < callbacks.length; ++i)
callbacks[i](true);
callbacks = self._callbacks;
if (!server) {
// align more with node child processes, where the close event gets the
// same arguments as the exit event
if (!self.readable) {
if (exitCode === null) {
self.emit('close', exitCode, exitSignal, exitDump, exitDesc,
exitLang);
} else
self.emit('close', exitCode);
} else {
self.once('end', function() {
if (exitCode === null) {
self.emit('close', exitCode, exitSignal, exitDump, exitDesc,
exitLang);
} else
self.emit('close', exitCode);
});
}
if (!self.stderr.readable)
self.stderr.emit('close');
else {
self.stderr.once('end', function() {
self.stderr.emit('close');
});
}
} else { // Server mode
if (!self.readable)
self.emit('close');
else {
self.once('end', function() {
self.emit('close');
});
}
}
for (var i = 0; i < CUSTOM_EVENTS_LEN; ++i)
sshstream.removeAllListeners(CUSTOM_EVENTS[i] + ':' + incomingId);
}).on('CHANNEL_DATA:' + incomingId, function(data) {
// the remote party should not be sending us data if there is no window
// space available ...
if (incoming.window === 0)
return;
incoming.window -= data.length;
if (!self.push(data)) {
self._waitChanDrain = true;
return;
}
if (incoming.window <= WINDOW_THRESHOLD)
windowAdjust(self);
}).on('CHANNEL_WIN ...
n/a
function Client() { if (!(this instanceof Client)) return new Client(); EventEmitter.call(this); this.config = { host: undefined, port: undefined, forceIPv4: undefined, forceIPv6: undefined, keepaliveCountMax: undefined, keepaliveInterval: undefined, readyTimeout: undefined, username: undefined, password: undefined, privateKey: undefined, publicKey: undefined, tryKeyboard: undefined, agent: undefined, allowAgentFwd: undefined, hostHashAlgo: undefined, hostHashCb: undefined, strictVendor: undefined, debug: undefined }; this._readyTimeout = undefined; this._channels = undefined; this._callbacks = undefined; this._forwarding = undefined; this._acceptX11 = undefined; this._agentFwdEnabled = undefined; this._curChan = undefined; this._remoteVer = undefined; this._sshstream = undefined; this._sock = undefined; this._resetKA = undefined; }
n/a
function SFTPWrapper(stream) { var self = this; EventEmitter.call(this); this._stream = stream; stream.on('error', function(err) { self.emit('error', err); }).on('end', function() { self.emit('end'); }).on('close', function() { self.emit('close'); }).on('continue', function() { self.emit('continue'); }); }
n/a
function Server(cfg, listener) { if (!(this instanceof Server)) return new Server(cfg, listener); var hostKeys = { 'ssh-rsa': null, 'ssh-dss': null, 'ecdsa-sha2-nistp256': null, 'ecdsa-sha2-nistp384': null, 'ecdsa-sha2-nistp521': null }; var hostKeys_ = cfg.hostKeys; if (!Array.isArray(hostKeys_)) throw new Error('hostKeys must be an array'); var i; for (i = 0; i < hostKeys_.length; ++i) { var privateKey; if (Buffer.isBuffer(hostKeys_[i]) || typeof hostKeys_[i] === 'string') privateKey = parseKey(hostKeys_[i]); else privateKey = parseKey(hostKeys_[i].key); if (privateKey instanceof Error) throw new Error('Cannot parse privateKey: ' + privateKey.message); if (!privateKey.private) throw new Error('privateKey value contains an invalid private key'); if (hostKeys[privateKey.fulltype]) continue; if (privateKey.encryption) { if (typeof hostKeys_[i].passphrase !== 'string') throw new Error('Missing passphrase for encrypted private key'); decryptKey(privateKey, hostKeys_[i].passphrase); } hostKeys[privateKey.fulltype] = { privateKey: privateKey, publicKey: genPublicKey(privateKey) }; } var algorithms = { kex: undefined, kexBuf: undefined, cipher: undefined, cipherBuf: undefined, serverHostKey: undefined, serverHostKeyBuf: undefined, hmac: undefined, hmacBuf: undefined, compress: undefined, compressBuf: undefined }; if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { var algosSupported; var algoList; algoList = cfg.algorithms.kex; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_KEX; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported key exchange algorithm: ' + algoList[i]); } algorithms.kex = algoList; } algoList = cfg.algorithms.cipher; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_CIPHER; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported cipher algorithm: ' + algoList[i]); } algorithms.cipher = algoList; } algoList = cfg.algorithms.serverHostKey; var copied = false; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_SERVER_HOST_KEY; for (i = algoList.length - 1; i >= 0; --i) { if (algosSupported.indexOf(algoList[i]) === -1) { throw new Error('Unsupported server host key algorithm: ' + algoList[i]); } if (!hostKeys[algoList[i]]) { // Silently discard for now if (!copied) { algoList = algoList.slice(); copied = true; } algoList.splice(i, 1); } } if (algoList.length > 0) algorithms.serverHostKey = algoList; } algoList = cfg.algorithms.hmac; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_HMAC; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported HMAC algorithm: ' + algoList[i]); } algorithms.hmac = algoList; } algoList = cfg.algorithms.compress; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_COMPRESS; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported compression algorithm: ' + algoList[i]); } algorithms.compress = algoList; } } // Make sure we at least have some kind of valid list of support key // formats if (algorithms.serverHostKey === undefined) { var hostKeyAlgos = Object.keys(hostKeys); for (i = hostKeyAlgos.length - 1; i ...
...
var buffersEqual = require('buffer-equal-constant-time');
var ssh2 = require('ssh2');
var utils = ssh2.utils;
var pubKey = utils.genPublicKey(utils.parseKey(fs.readFileSync('user.pub')));
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
if (ctx.method === 'password'
&& ctx.username === 'foo'
...
function Manager(interval, streamInterval, kaCountMax) { var streams = this._streams = []; this._timer = undefined; this._timerInterval = interval; this._timerfn = function() { var now = Date.now(); for (var i = 0, len = streams.length, s, last; i < len; ++i) { s = streams[i]; last = s._kalast; if (last && (now - last) >= streamInterval) { if (++s._kacnt > kaCountMax) { var err = new Error('Keepalive timeout'); err.level = 'client-timeout'; s.emit('error', err); s.disconnect(); spliceOne(streams, i); --i; len = streams.length; } else { s._kalast = now; // XXX: if the server ever starts sending real global requests to the // client, we will need to add a dummy callback here to keep the // correct reply order s.ping(); } } } }; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
function Channel(info, client, opts) {
var streamOpts = {
highWaterMark: MAX_WINDOW,
allowHalfOpen: (!opts || (opts && opts.allowHalfOpen !== false))
};
this.allowHalfOpen = streamOpts.allowHalfOpen;
DuplexStream.call(this, streamOpts);
var self = this;
var server = opts && opts.server;
this.server = server;
this.type = info.type;
this.subtype = undefined;
/*
incoming and outgoing contain these properties:
{
id: undefined,
window: undefined,
packetSize: undefined,
state: 'closed'
}
*/
var incoming = this.incoming = info.incoming;
var incomingId = incoming.id;
var outgoing = this.outgoing = info.outgoing;
var callbacks = this._callbacks = [];
var exitCode;
var exitSignal;
var exitDump;
var exitDesc;
var exitLang;
this._client = client;
this._hasX11 = false;
var channels = client._channels;
var sshstream = client._sshstream;
function ondrain() {
if (self._waitClientDrain) {
self._waitClientDrain = false;
if (!self._waitWindow) {
if (self._chunk)
self._write(self._chunk, null, self._chunkcb);
else if (self._chunkcb)
self._chunkcb();
else if (self._chunkErr)
self.stderr._write(self._chunkErr, null, self._chunkcbErr);
else if (self._chunkcbErr)
self._chunkcbErr();
}
}
}
client._sock.on('drain', ondrain);
sshstream.once('CHANNEL_EOF:' + incomingId, function() {
if (incoming.state === 'closed' || incoming.state === 'eof')
return;
incoming.state = 'eof';
if (self.readable)
self.push(null);
if (!server && self.stderr.readable)
self.stderr.push(null);
}).once('CHANNEL_CLOSE:' + incomingId, function() {
if (incoming.state === 'closed')
return;
incoming.state = 'closed';
if (self.readable)
self.push(null);
if (server && self.stderr.writable)
self.stderr.end();
else if (!server && self.stderr.readable)
self.stderr.push(null);
if (outgoing.state === 'open' || outgoing.state === 'eof')
self.close();
if (outgoing.state === 'closing')
outgoing.state = 'closed';
delete channels[incomingId];
var state = self._writableState;
client._sock.removeListener('drain', ondrain);
if (!state.ending && !state.finished)
self.end();
// Take care of any outstanding channel requests
self._callbacks = [];
for (var i = 0; i < callbacks.length; ++i)
callbacks[i](true);
callbacks = self._callbacks;
if (!server) {
// align more with node child processes, where the close event gets the
// same arguments as the exit event
if (!self.readable) {
if (exitCode === null) {
self.emit('close', exitCode, exitSignal, exitDump, exitDesc,
exitLang);
} else
self.emit('close', exitCode);
} else {
self.once('end', function() {
if (exitCode === null) {
self.emit('close', exitCode, exitSignal, exitDump, exitDesc,
exitLang);
} else
self.emit('close', exitCode);
});
}
if (!self.stderr.readable)
self.stderr.emit('close');
else {
self.stderr.once('end', function() {
self.stderr.emit('close');
});
}
} else { // Server mode
if (!self.readable)
self.emit('close');
else {
self.once('end', function() {
self.emit('close');
});
}
}
for (var i = 0; i < CUSTOM_EVENTS_LEN; ++i)
sshstream.removeAllListeners(CUSTOM_EVENTS[i] + ':' + incomingId);
}).on('CHANNEL_DATA:' + incomingId, function(data) {
// the remote party should not be sending us data if there is no window
// space available ...
if (incoming.window === 0)
return;
incoming.window -= data.length;
if (!self.push(data)) {
self._waitChanDrain = true;
return;
}
if (incoming.window <= WINDOW_THRESHOLD)
windowAdjust(self);
}).on('CHANNEL_WIN ...
n/a
function Duplex(options) { if (!(this instanceof Duplex)) return new Duplex(options); Readable.call(this, options); Writable.call(this, options); if (options && options.readable === false) this.readable = false; if (options && options.writable === false) this.writable = false; this.allowHalfOpen = true; if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; this.once('end', onend); }
n/a
_read = function (n) { if (this._waitChanDrain) { this._waitChanDrain = false; if (this.incoming.window <= WINDOW_THRESHOLD) windowAdjust(this); } }
n/a
_write = function (data, encoding, cb) { var sshstream = this._client._sshstream; var outgoing = this.outgoing; var packetSize = outgoing.packetSize; var id = outgoing.id; var window = outgoing.window; var len = data.length; var p = 0; var ret; var buf; var sliceLen; if (outgoing.state !== 'open') return; while (len - p > 0 && window > 0) { sliceLen = len - p; if (sliceLen > window) sliceLen = window; if (sliceLen > packetSize) sliceLen = packetSize; ret = sshstream.channelData(id, data.slice(p, p + sliceLen)); p += sliceLen; window -= sliceLen; if (!ret) { this._waitClientDrain = true; this._chunk = undefined; this._chunkcb = cb; break; } } outgoing.window = window; if (len - p > 0) { if (window === 0) this._waitWindow = true; if (p > 0) { // partial buf = new Buffer(len - p); data.copy(buf, 0, p); this._chunk = buf; } else this._chunk = data; this._chunkcb = cb; return; } if (!this._waitClientDrain) cb(); }
...
var sshstream = client._sshstream;
function ondrain() {
if (self._waitClientDrain) {
self._waitClientDrain = false;
if (!self._waitWindow) {
if (self._chunk)
self._write(self._chunk, null, self._chunkcb);
else if (self._chunkcb)
self._chunkcb();
else if (self._chunkErr)
self.stderr._write(self._chunkErr, null, self._chunkcbErr);
else if (self._chunkcbErr)
self._chunkcbErr();
}
...
close = function () { var ret = true; var outgoing = this.outgoing; if (outgoing.state === 'open' || outgoing.state === 'eof') { outgoing.state = 'closing'; ret = this._client._sshstream.channelClose(outgoing.id); } return ret; }
...
self.push(null);
if (server && self.stderr.writable)
self.stderr.end();
else if (!server && self.stderr.readable)
self.stderr.push(null);
if (outgoing.state === 'open' || outgoing.state === 'eof')
self.close();
if (outgoing.state === 'closing')
outgoing.state = 'closed';
delete channels[incomingId];
var state = self._writableState;
client._sock.removeListener('drain', ondrain);
...
destroy = function () { this.end(); }
...
sig = new Buffer(siglen);
count = 0;
}
} else {
sig[count] = chunk[i];
if (++count === siglen) {
sock.removeAllListeners('data');
return sock.destroy();
}
}
} else if (type === IDENTITIES_ANSWER) {
/*
byte SSH2_AGENT_IDENTITIES_ANSWER
uint32 num_keys
...
eof = function () { var ret = true; var outgoing = this.outgoing; if (outgoing.state === 'open') { outgoing.state = 'eof'; ret = this._client._sshstream.channelEOF(outgoing.id); } return ret; }
...
this._chunk = undefined;
this._chunkcb = undefined;
this._chunkErr = undefined;
this._chunkcbErr = undefined;
function onFinish() {
self.eof();
if (server || (!server && !self.allowHalfOpen))
self.close();
self.writable = false;
}
this.on('finish', onFinish)
.on('prefinish', onFinish); // for node v0.11+
function onEnd() {
...
exit = function (name, coreDumped, msg) { if (!this.server) throw new Error('Server-only method called in client mode'); if (this.type === 'session' && this.writable && this.outgoing.state === 'open') { if (typeof name === 'number') return this._client._sshstream.exitStatus(this.outgoing.id, name); else { return this._client._sshstream.exitSignal(this.outgoing.id, name, coreDumped, msg); } } return true; }
...
client.on('session', function(accept, reject) {
var session = accept();
session.once('exec', function(accept, reject, info) {
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', function() {
console.log('Client disconnected');
});
}).listen(0, '127.0.0.1', function() {
...
setWindow = function (rows, cols, height, width) { if (this.server) throw new Error('Client-only method called in server mode'); if (this.type === 'session' && (this.subtype === 'shell' || this.subtype === 'exec') && this.writable && this.outgoing.state === 'open') { return this._client._sshstream.windowChange(this.outgoing.id, rows, cols, height, width); } return true; }
n/a
signal = function (signalName) { if (this.server) throw new Error('Client-only method called in server mode'); if (this.type === 'session' && this.writable && this.outgoing.state === 'open') return this._client._sshstream.signal(this.outgoing.id, signalName); return true; }
...
Channel.prototype.signal = function(signalName) {
if (this.server)
throw new Error('Client-only method called in server mode');
if (this.type === 'session'
&& this.writable
&& this.outgoing.state === 'open')
return this._client._sshstream.signal(this.outgoing.id, signalName);
return true;
};
Channel.prototype.exit = function(name, coreDumped, msg) {
if (!this.server)
throw new Error('Server-only method called in client mode');
...
function Client() { if (!(this instanceof Client)) return new Client(); EventEmitter.call(this); this.config = { host: undefined, port: undefined, forceIPv4: undefined, forceIPv6: undefined, keepaliveCountMax: undefined, keepaliveInterval: undefined, readyTimeout: undefined, username: undefined, password: undefined, privateKey: undefined, publicKey: undefined, tryKeyboard: undefined, agent: undefined, allowAgentFwd: undefined, hostHashAlgo: undefined, hostHashCb: undefined, strictVendor: undefined, debug: undefined }; this._readyTimeout = undefined; this._channels = undefined; this._callbacks = undefined; this._forwarding = undefined; this._acceptX11 = undefined; this._agentFwdEnabled = undefined; this._curChan = undefined; this._remoteVer = undefined; this._sshstream = undefined; this._sock = undefined; this._resetKA = undefined; }
n/a
function Server(cfg, listener) { if (!(this instanceof Server)) return new Server(cfg, listener); var hostKeys = { 'ssh-rsa': null, 'ssh-dss': null, 'ecdsa-sha2-nistp256': null, 'ecdsa-sha2-nistp384': null, 'ecdsa-sha2-nistp521': null }; var hostKeys_ = cfg.hostKeys; if (!Array.isArray(hostKeys_)) throw new Error('hostKeys must be an array'); var i; for (i = 0; i < hostKeys_.length; ++i) { var privateKey; if (Buffer.isBuffer(hostKeys_[i]) || typeof hostKeys_[i] === 'string') privateKey = parseKey(hostKeys_[i]); else privateKey = parseKey(hostKeys_[i].key); if (privateKey instanceof Error) throw new Error('Cannot parse privateKey: ' + privateKey.message); if (!privateKey.private) throw new Error('privateKey value contains an invalid private key'); if (hostKeys[privateKey.fulltype]) continue; if (privateKey.encryption) { if (typeof hostKeys_[i].passphrase !== 'string') throw new Error('Missing passphrase for encrypted private key'); decryptKey(privateKey, hostKeys_[i].passphrase); } hostKeys[privateKey.fulltype] = { privateKey: privateKey, publicKey: genPublicKey(privateKey) }; } var algorithms = { kex: undefined, kexBuf: undefined, cipher: undefined, cipherBuf: undefined, serverHostKey: undefined, serverHostKeyBuf: undefined, hmac: undefined, hmacBuf: undefined, compress: undefined, compressBuf: undefined }; if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { var algosSupported; var algoList; algoList = cfg.algorithms.kex; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_KEX; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported key exchange algorithm: ' + algoList[i]); } algorithms.kex = algoList; } algoList = cfg.algorithms.cipher; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_CIPHER; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported cipher algorithm: ' + algoList[i]); } algorithms.cipher = algoList; } algoList = cfg.algorithms.serverHostKey; var copied = false; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_SERVER_HOST_KEY; for (i = algoList.length - 1; i >= 0; --i) { if (algosSupported.indexOf(algoList[i]) === -1) { throw new Error('Unsupported server host key algorithm: ' + algoList[i]); } if (!hostKeys[algoList[i]]) { // Silently discard for now if (!copied) { algoList = algoList.slice(); copied = true; } algoList.splice(i, 1); } } if (algoList.length > 0) algorithms.serverHostKey = algoList; } algoList = cfg.algorithms.hmac; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_HMAC; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported HMAC algorithm: ' + algoList[i]); } algorithms.hmac = algoList; } algoList = cfg.algorithms.compress; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_COMPRESS; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported compression algorithm: ' + algoList[i]); } algorithms.compress = algoList; } } // Make sure we at least have some kind of valid list of support key // formats if (algorithms.serverHostKey === undefined) { var hostKeyAlgos = Object.keys(hostKeys); for (i = hostKeyAlgos.length - 1; i ...
...
var buffersEqual = require('buffer-equal-constant-time');
var ssh2 = require('ssh2');
var utils = ssh2.utils;
var pubKey = utils.genPublicKey(utils.parseKey(fs.readFileSync('user.pub')));
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
if (ctx.method === 'password'
&& ctx.username === 'foo'
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
connect = function (cfg) { var self = this; if (this._sock && this._sock.writable) { this.once('close', function() { self.connect(cfg); }); this.end(); return; } this.config.host = cfg.hostname || cfg.host || 'localhost'; this.config.port = cfg.port || 22; this.config.forceIPv4 = cfg.forceIPv4 || false; this.config.forceIPv6 = cfg.forceIPv6 || false; this.config.keepaliveCountMax = (typeof cfg.keepaliveCountMax === 'number' && cfg.keepaliveCountMax >= 0 ? cfg.keepaliveCountMax : 3); this.config.keepaliveInterval = (typeof cfg.keepaliveInterval === 'number' && cfg.keepaliveInterval > 0 ? cfg.keepaliveInterval : 0); this.config.readyTimeout = (typeof cfg.readyTimeout === 'number' && cfg.readyTimeout >= 0 ? cfg.readyTimeout : 20000); var algorithms = { kex: undefined, kexBuf: undefined, cipher: undefined, cipherBuf: undefined, serverHostKey: undefined, serverHostKeyBuf: undefined, hmac: undefined, hmacBuf: undefined, compress: undefined, compressBuf: undefined }; var i; if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { var algosSupported; var algoList; algoList = cfg.algorithms.kex; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_KEX; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported key exchange algorithm: ' + algoList[i]); } algorithms.kex = algoList; } algoList = cfg.algorithms.cipher; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_CIPHER; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported cipher algorithm: ' + algoList[i]); } algorithms.cipher = algoList; } algoList = cfg.algorithms.serverHostKey; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_SERVER_HOST_KEY; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) { throw new Error('Unsupported server host key algorithm: ' + algoList[i]); } } algorithms.serverHostKey = algoList; } algoList = cfg.algorithms.hmac; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_HMAC; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported HMAC algorithm: ' + algoList[i]); } algorithms.hmac = algoList; } algoList = cfg.algorithms.compress; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_COMPRESS; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported compression algorithm: ' + algoList[i]); } algorithms.compress = algoList; } } if (algorithms.compress === undefined) { if (cfg.compress) { algorithms.compress = ['zlib@openssh.com', 'zlib']; if (cfg.compress !== 'force') algorithms.compress.push('none'); } else if (cfg.compress === false) algorithms.compress = ['none']; } this.config.username = cfg.username || cfg.user; this.config.password = (typeof cfg.password === 'string' ? cfg.password : undefined); this.config.privateKey = (typeof cfg.privateKey === 'string' || Buffer.isBuffer(cfg.privateKey) ? cfg.privateKey ...
...
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
});
}).connect({
host: '192.168.100.100',
port: 22,
username: 'frylock',
privateKey: require('fs').readFileSync('/here/is/my/key')
});
// example output:
...
destroy = function () { this._sock && this._sock.destroy(); }
...
sig = new Buffer(siglen);
count = 0;
}
} else {
sig[count] = chunk[i];
if (++count === siglen) {
sock.removeAllListeners('data');
return sock.destroy();
}
}
} else if (type === IDENTITIES_ANSWER) {
/*
byte SSH2_AGENT_IDENTITIES_ANSWER
uint32 num_keys
...
end = function () { if (this._sock && this._sock.writable && this._sshstream && this._sshstream.writable) return this._sshstream.disconnect(); return false; }
...
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.exec('uptime', function(err, stream) {
if (err) throw err;
stream.on('close', function(code, signal) {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
});
}).connect({
...
exec = function (cmd, opts, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); if (typeof opts === 'function') { cb = opts; opts = {}; } var self = this; var extraOpts = { allowHalfOpen: (opts.allowHalfOpen !== false) }; return openChannel(this, 'session', extraOpts, function(err, chan) { if (err) return cb(err); var todo = []; function reqCb(err) { if (err) { chan.close(); return cb(err); } if (todo.length) todo.shift()(); } if (self.config.allowAgentFwd === true || (opts && opts.agentForward === true && self.config.agent !== undefined)) { todo.push(function() { reqAgentFwd(chan, reqCb); }); } if (typeof opts === 'object') { if (typeof opts.env === 'object') reqEnv(chan, opts.env); if (typeof opts.pty === 'object' || opts.pty === true) todo.push(function() { reqPty(chan, opts.pty, reqCb); }); if (typeof opts.x11 === 'object' || opts.x11 === 'number' || opts.x11 === true) todo.push(function() { reqX11(chan, opts.x11, reqCb); }); } todo.push(function() { reqExec(chan, cmd, opts, cb); }); todo.shift()(); }); }
...
```javascript
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.exec('uptime', function(err, stream) {
if (err) throw err;
stream.on('close', function(code, signal) {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
...
forwardIn = function (bindAddr, bindPort, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); // send a request for the server to start forwarding TCP connections to us // on a particular address and port var self = this; var wantReply = (typeof cb === 'function'); if (wantReply) { this._callbacks.push(function(had_err, data) { if (had_err) { return cb(had_err !== true ? had_err : new Error('Unable to bind to ' + bindAddr + ':' + bindPort)); } var realPort = bindPort; if (bindPort === 0 && data && data.length >= 4) { realPort = data.readUInt32BE(0, true); if (!(self._sshstream.remoteBugs & BUGS.DYN_RPORT_BUG)) bindPort = realPort; } self._forwarding[bindAddr + ':' + bindPort] = realPort; cb(undefined, realPort); }); } return this._sshstream.tcpipForward(bindAddr, bindPort, wantReply); }
...
```javascript
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.forwardIn('127.0.0.1', 8000, function(err) {
if (err) throw err;
console.log('Listening for connections on server on port 8000!');
});
}).on('tcp connection', function(info, accept, reject) {
console.log('TCP :: INCOMING CONNECTION:');
console.dir(info);
accept().on('close', function() {
...
forwardOut = function (srcIP, srcPort, dstIP, dstPort, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); // send a request to forward a TCP connection to the server var cfg = { srcIP: srcIP, srcPort: srcPort, dstIP: dstIP, dstPort: dstPort }; return openChannel(this, 'direct-tcpip', cfg, cb); }
...
```javascript
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.forwardOut('192.168.100.102', 8000, '127.0.0.1', 80, function
(err, stream) {
if (err) throw err;
stream.on('close', function() {
console.log('TCP :: CLOSED');
conn.end();
}).on('data', function(data) {
console.log('TCP :: DATA: ' + data);
}).end([
...
openssh_forwardInStreamLocal = function (socketPath, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); var wantReply = (typeof cb === 'function'); if (!this.config.strictVendor || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { if (wantReply) { this._callbacks.push(function(had_err) { if (had_err) { return cb(had_err !== true ? had_err : new Error('Unable to bind to ' + socketPath)); } cb(); }); } return this._sshstream.openssh_streamLocalForward(socketPath, wantReply); } else if (wantReply) { process.nextTick(function() { cb(new Error('strictVendor enabled and server is not OpenSSH or compatible version')); }); } return true; }
n/a
openssh_forwardOutStreamLocal = function (socketPath, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); if (!this.config.strictVendor || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { var cfg = { socketPath: socketPath }; return openChannel(this, 'direct-streamlocal@openssh.com', cfg, cb); } else { process.nextTick(function() { cb(new Error('strictVendor enabled and server is not OpenSSH or compatible version')); }); } return true; }
n/a
openssh_noMoreSessions = function (cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); var wantReply = (typeof cb === 'function'); if (!this.config.strictVendor || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { if (wantReply) { this._callbacks.push(function(had_err) { if (had_err) { return cb(had_err !== true ? had_err : new Error('Unable to disable future sessions')); } cb(); }); } return this._sshstream.openssh_noMoreSessions(wantReply); } else if (wantReply) { process.nextTick(function() { cb(new Error('strictVendor enabled and server is not OpenSSH or compatible version')); }); } return true; }
n/a
openssh_unforwardInStreamLocal = function (socketPath, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); var wantReply = (typeof cb === 'function'); if (!this.config.strictVendor || (this.config.strictVendor && RE_OPENSSH.test(this._remoteVer))) { if (wantReply) { this._callbacks.push(function(had_err) { if (had_err) { return cb(had_err !== true ? had_err : new Error('Unable to unbind on ' + socketPath)); } cb(); }); } return this._sshstream.openssh_cancelStreamLocalForward(socketPath, wantReply); } else if (wantReply) { process.nextTick(function() { cb(new Error('strictVendor enabled and server is not OpenSSH or compatible version')); }); } return true; }
n/a
sftp = function (cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); var self = this; // start an SFTP session return openChannel(this, 'session', function(err, chan) { if (err) return cb(err); reqSubsystem(chan, 'sftp', function(err, stream) { if (err) return cb(err); var serverIdentRaw = self._sshstream._state.incoming.identRaw; var cfg = { debug: self.config.debug }; var sftp = new SFTPStream(cfg, serverIdentRaw); function onError(err) { sftp.removeListener('ready', onReady); stream.removeListener('exit', onExit); cb(err); } function onReady() { sftp.removeListener('error', onError); stream.removeListener('exit', onExit); cb(undefined, new SFTPWrapper(sftp)); } function onExit(code, signal) { sftp.removeListener('ready', onReady); sftp.removeListener('error', onError); var msg; if (typeof code === 'number') { msg = 'Received exit code ' + code + ' while establishing SFTP session'; } else { msg = 'Received signal ' + signal + ' while establishing SFTP session'; } var err = new Error(msg); err.code = code; err.signal = signal; cb(err); } sftp.once('error', onError) .once('ready', onReady) .once('close', function() { stream.end(); }); // OpenSSH server sends an exit-status if there was a problem spinning up // an sftp server child process, so we listen for that here in order to // properly raise an error. stream.once('exit', onExit); sftp.pipe(stream).pipe(sftp); }); }); }
...
```javascript
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.sftp(function(err, sftp) {
if (err) throw err;
sftp.readdir('foo', function(err, list) {
if (err) throw err;
console.dir(list);
conn.end();
});
});
...
shell = function (wndopts, opts, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); // start an interactive terminal/shell session var self = this; if (typeof wndopts === 'function') { cb = wndopts; wndopts = opts = undefined; } else if (typeof opts === 'function') { cb = opts; opts = undefined; } if (wndopts && wndopts.x11 !== undefined) { opts = wndopts; wndopts = undefined; } return openChannel(this, 'session', function(err, chan) { if (err) return cb(err); var todo = []; function reqCb(err) { if (err) { chan.close(); return cb(err); } if (todo.length) todo.shift()(); } if (self.config.allowAgentFwd === true || (opts && opts.agentForward === true && self.config.agent !== undefined)) { todo.push(function() { reqAgentFwd(chan, reqCb); }); } if (wndopts !== false) todo.push(function() { reqPty(chan, wndopts, reqCb); }); if (typeof opts === 'object') { if (typeof opts.x11 === 'object' || opts.x11 === 'number' || opts.x11 === true) todo.push(function() { reqX11(chan, opts.x11, reqCb); }); } todo.push(function() { reqShell(chan, cb); }); todo.shift()(); }); }
...
```javascript
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.shell(function(err, stream) {
if (err) throw err;
stream.on('close', function() {
console.log('Stream :: close');
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
...
subsys = function (name, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); return openChannel(this, 'session', function(err, chan) { if (err) return cb(err); reqSubsystem(chan, name, function(err, stream) { if (err) return cb(err); cb(undefined, stream); }); }); }
...
' </capabilities>' +
'</hello>]]>]]>';
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.subsys('netconf', function(err, stream) {
if (err) throw err;
stream.on('data', function(data) {
console.log(data);
}).write(xmlhello);
});
}).connect({
host: '1.2.3.4',
...
unforwardIn = function (bindAddr, bindPort, cb) { if (!this._sock || !this._sock.writable || !this._sshstream || !this._sshstream.writable) throw new Error('Not connected'); // send a request to stop forwarding us new connections for a particular // address and port var self = this; var wantReply = (typeof cb === 'function'); if (wantReply) { this._callbacks.push(function(had_err) { if (had_err) { return cb(had_err !== true ? had_err : new Error('Unable to unbind from ' + bindAddr + ':' + bindPort)); } delete self._forwarding[bindAddr + ':' + bindPort]; cb(); }); } return this._sshstream.cancelTcpipForward(bindAddr, bindPort, wantReply); }
n/a
function SFTPWrapper(stream) { var self = this; EventEmitter.call(this); this._stream = stream; stream.on('error', function(err) { self.emit('error', err); }).on('end', function() { self.emit('end'); }).on('close', function() { self.emit('close'); }).on('continue', function() { self.emit('continue'); }); }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
appendFile = function (path, data, options, callback_) { return this._stream.appendFile(path, data, options, callback_); }
...
SFTPWrapper.prototype.readFile = function(path, options, callback_) {
return this._stream.readFile(path, options, callback_);
};
SFTPWrapper.prototype.writeFile = function(path, data, options, callback_) {
return this._stream.writeFile(path, data, options, callback_);
};
SFTPWrapper.prototype.appendFile = function(path, data, options, callback_) {
return this._stream.appendFile(path, data, options, callback_);
};
SFTPWrapper.prototype.exists = function(path, cb) {
return this._stream.exists(path, cb);
};
SFTPWrapper.prototype.unlink = function(filename, cb) {
return this._stream.unlink(filename, cb);
};
...
chmod = function (path, mode, cb) { return this._stream.chmod(path, mode, cb); }
...
SFTPWrapper.prototype.chown = function(path, uid, gid, cb) {
return this._stream.chown(path, uid, gid, cb);
};
SFTPWrapper.prototype.fchmod = function(handle, mode, cb) {
return this._stream.fchmod(handle, mode, cb);
};
SFTPWrapper.prototype.chmod = function(path, mode, cb) {
return this._stream.chmod(path, mode, cb);
};
SFTPWrapper.prototype.readlink = function(path, cb) {
return this._stream.readlink(path, cb);
};
SFTPWrapper.prototype.symlink = function(targetPath, linkPath, cb) {
return this._stream.symlink(targetPath, linkPath, cb);
};
...
chown = function (path, uid, gid, cb) { return this._stream.chown(path, uid, gid, cb); }
...
SFTPWrapper.prototype.utimes = function(path, atime, mtime, cb) {
return this._stream.utimes(path, atime, mtime, cb);
};
SFTPWrapper.prototype.fchown = function(handle, uid, gid, cb) {
return this._stream.fchown(handle, uid, gid, cb);
};
SFTPWrapper.prototype.chown = function(path, uid, gid, cb) {
return this._stream.chown(path, uid, gid, cb);
};
SFTPWrapper.prototype.fchmod = function(handle, mode, cb) {
return this._stream.fchmod(handle, mode, cb);
};
SFTPWrapper.prototype.chmod = function(path, mode, cb) {
return this._stream.chmod(path, mode, cb);
};
...
close = function (handle, cb) { return this._stream.close(handle, cb); }
...
self.push(null);
if (server && self.stderr.writable)
self.stderr.end();
else if (!server && self.stderr.readable)
self.stderr.push(null);
if (outgoing.state === 'open' || outgoing.state === 'eof')
self.close();
if (outgoing.state === 'closing')
outgoing.state = 'closed';
delete channels[incomingId];
var state = self._writableState;
client._sock.removeListener('drain', ondrain);
...
createReadStream = function (path, options) { return this._stream.createReadStream(path, options); }
...
// stream-related methods to pass on
SFTPWrapper.prototype.end = function() {
return this._stream.end();
};
// SFTPStream client methods
SFTPWrapper.prototype.createReadStream = function(path, options) {
return this._stream.createReadStream(path, options);
};
SFTPWrapper.prototype.createWriteStream = function(path, options) {
return this._stream.createWriteStream(path, options);
};
SFTPWrapper.prototype.open = function(path, flags, attrs, cb) {
return this._stream.open(path, flags, attrs, cb);
};
...
createWriteStream = function (path, options) { return this._stream.createWriteStream(path, options); }
...
return this._stream.end();
};
// SFTPStream client methods
SFTPWrapper.prototype.createReadStream = function(path, options) {
return this._stream.createReadStream(path, options);
};
SFTPWrapper.prototype.createWriteStream = function(path, options) {
return this._stream.createWriteStream(path, options);
};
SFTPWrapper.prototype.open = function(path, flags, attrs, cb) {
return this._stream.open(path, flags, attrs, cb);
};
SFTPWrapper.prototype.close = function(handle, cb) {
return this._stream.close(handle, cb);
};
...
end = function () { return this._stream.end(); }
...
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.exec('uptime', function(err, stream) {
if (err) throw err;
stream.on('close', function(code, signal) {
console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
conn.end();
}).on('data', function(data) {
console.log('STDOUT: ' + data);
}).stderr.on('data', function(data) {
console.log('STDERR: ' + data);
});
});
}).connect({
...
exists = function (path, cb) { return this._stream.exists(path, cb); }
...
SFTPWrapper.prototype.writeFile = function(path, data, options, callback_) {
return this._stream.writeFile(path, data, options, callback_);
};
SFTPWrapper.prototype.appendFile = function(path, data, options, callback_) {
return this._stream.appendFile(path, data, options, callback_);
};
SFTPWrapper.prototype.exists = function(path, cb) {
return this._stream.exists(path, cb);
};
SFTPWrapper.prototype.unlink = function(filename, cb) {
return this._stream.unlink(filename, cb);
};
SFTPWrapper.prototype.rename = function(oldPath, newPath, cb) {
return this._stream.rename(oldPath, newPath, cb);
};
...
ext_openssh_fstatvfs = function (handle, cb) { return this._stream.ext_openssh_fstatvfs(handle, cb); }
...
SFTPWrapper.prototype.ext_openssh_rename = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_statvfs = function(path, cb) {
return this._stream.ext_openssh_statvfs(path, cb);
};
SFTPWrapper.prototype.ext_openssh_fstatvfs = function(handle, cb) {
return this._stream.ext_openssh_fstatvfs(handle, cb);
};
SFTPWrapper.prototype.ext_openssh_hardlink = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_hardlink(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_fsync = function(handle, cb) {
return this._stream.ext_openssh_fsync(handle, cb);
};
...
ext_openssh_fsync = function (handle, cb) { return this._stream.ext_openssh_fsync(handle, cb); }
...
SFTPWrapper.prototype.ext_openssh_fstatvfs = function(handle, cb) {
return this._stream.ext_openssh_fstatvfs(handle, cb);
};
SFTPWrapper.prototype.ext_openssh_hardlink = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_hardlink(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_fsync = function(handle, cb) {
return this._stream.ext_openssh_fsync(handle, cb);
};
module.exports = SFTPWrapper;
...
ext_openssh_hardlink = function (oldPath, newPath, cb) { return this._stream.ext_openssh_hardlink(oldPath, newPath, cb); }
...
SFTPWrapper.prototype.ext_openssh_statvfs = function(path, cb) {
return this._stream.ext_openssh_statvfs(path, cb);
};
SFTPWrapper.prototype.ext_openssh_fstatvfs = function(handle, cb) {
return this._stream.ext_openssh_fstatvfs(handle, cb);
};
SFTPWrapper.prototype.ext_openssh_hardlink = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_hardlink(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_fsync = function(handle, cb) {
return this._stream.ext_openssh_fsync(handle, cb);
};
module.exports = SFTPWrapper;
...
ext_openssh_rename = function (oldPath, newPath, cb) { return this._stream.ext_openssh_rename(oldPath, newPath, cb); }
...
return this._stream.symlink(targetPath, linkPath, cb);
};
SFTPWrapper.prototype.realpath = function(path, cb) {
return this._stream.realpath(path, cb);
};
// extended requests
SFTPWrapper.prototype.ext_openssh_rename = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_statvfs = function(path, cb) {
return this._stream.ext_openssh_statvfs(path, cb);
};
SFTPWrapper.prototype.ext_openssh_fstatvfs = function(handle, cb) {
return this._stream.ext_openssh_fstatvfs(handle, cb);
};
...
ext_openssh_statvfs = function (path, cb) { return this._stream.ext_openssh_statvfs(path, cb); }
...
return this._stream.realpath(path, cb);
};
// extended requests
SFTPWrapper.prototype.ext_openssh_rename = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_statvfs = function(path, cb) {
return this._stream.ext_openssh_statvfs(path, cb);
};
SFTPWrapper.prototype.ext_openssh_fstatvfs = function(handle, cb) {
return this._stream.ext_openssh_fstatvfs(handle, cb);
};
SFTPWrapper.prototype.ext_openssh_hardlink = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_hardlink(oldPath, newPath, cb);
};
...
fastGet = function (remotePath, localPath, opts, cb) { return this._stream.fastGet(remotePath, localPath, opts, cb); }
...
SFTPWrapper.prototype.read = function(handle, buf, off, len, position, cb) {
return this._stream.readData(handle, buf, off, len, position, cb);
};
SFTPWrapper.prototype.write = function(handle, buf, off, len, position, cb) {
return this._stream.writeData(handle, buf, off, len, position, cb);
};
SFTPWrapper.prototype.fastGet = function(remotePath, localPath, opts, cb) {
return this._stream.fastGet(remotePath, localPath, opts, cb);
};
SFTPWrapper.prototype.fastPut = function(localPath, remotePath, opts, cb) {
return this._stream.fastPut(localPath, remotePath, opts, cb);
};
SFTPWrapper.prototype.readFile = function(path, options, callback_) {
return this._stream.readFile(path, options, callback_);
};
...
fastPut = function (localPath, remotePath, opts, cb) { return this._stream.fastPut(localPath, remotePath, opts, cb); }
...
SFTPWrapper.prototype.write = function(handle, buf, off, len, position, cb) {
return this._stream.writeData(handle, buf, off, len, position, cb);
};
SFTPWrapper.prototype.fastGet = function(remotePath, localPath, opts, cb) {
return this._stream.fastGet(remotePath, localPath, opts, cb);
};
SFTPWrapper.prototype.fastPut = function(localPath, remotePath, opts, cb) {
return this._stream.fastPut(localPath, remotePath, opts, cb);
};
SFTPWrapper.prototype.readFile = function(path, options, callback_) {
return this._stream.readFile(path, options, callback_);
};
SFTPWrapper.prototype.writeFile = function(path, data, options, callback_) {
return this._stream.writeFile(path, data, options, callback_);
};
...
fchmod = function (handle, mode, cb) { return this._stream.fchmod(handle, mode, cb); }
...
SFTPWrapper.prototype.fchown = function(handle, uid, gid, cb) {
return this._stream.fchown(handle, uid, gid, cb);
};
SFTPWrapper.prototype.chown = function(path, uid, gid, cb) {
return this._stream.chown(path, uid, gid, cb);
};
SFTPWrapper.prototype.fchmod = function(handle, mode, cb) {
return this._stream.fchmod(handle, mode, cb);
};
SFTPWrapper.prototype.chmod = function(path, mode, cb) {
return this._stream.chmod(path, mode, cb);
};
SFTPWrapper.prototype.readlink = function(path, cb) {
return this._stream.readlink(path, cb);
};
...
fchown = function (handle, uid, gid, cb) { return this._stream.fchown(handle, uid, gid, cb); }
...
SFTPWrapper.prototype.futimes = function(handle, atime, mtime, cb) {
return this._stream.futimes(handle, atime, mtime, cb);
};
SFTPWrapper.prototype.utimes = function(path, atime, mtime, cb) {
return this._stream.utimes(path, atime, mtime, cb);
};
SFTPWrapper.prototype.fchown = function(handle, uid, gid, cb) {
return this._stream.fchown(handle, uid, gid, cb);
};
SFTPWrapper.prototype.chown = function(path, uid, gid, cb) {
return this._stream.chown(path, uid, gid, cb);
};
SFTPWrapper.prototype.fchmod = function(handle, mode, cb) {
return this._stream.fchmod(handle, mode, cb);
};
...
fsetstat = function (handle, attrs, cb) { return this._stream.fsetstat(handle, attrs, cb); }
...
SFTPWrapper.prototype.opendir = function(path, cb) {
return this._stream.opendir(path, cb);
};
SFTPWrapper.prototype.setstat = function(path, attrs, cb) {
return this._stream.setstat(path, attrs, cb);
};
SFTPWrapper.prototype.fsetstat = function(handle, attrs, cb) {
return this._stream.fsetstat(handle, attrs, cb);
};
SFTPWrapper.prototype.futimes = function(handle, atime, mtime, cb) {
return this._stream.futimes(handle, atime, mtime, cb);
};
SFTPWrapper.prototype.utimes = function(path, atime, mtime, cb) {
return this._stream.utimes(path, atime, mtime, cb);
};
...
fstat = function (handle, cb) { return this._stream.fstat(handle, cb); }
...
SFTPWrapper.prototype.rmdir = function(path, cb) {
return this._stream.rmdir(path, cb);
};
SFTPWrapper.prototype.readdir = function(where, opts, cb) {
return this._stream.readdir(where, opts, cb);
};
SFTPWrapper.prototype.fstat = function(handle, cb) {
return this._stream.fstat(handle, cb);
};
SFTPWrapper.prototype.stat = function(path, cb) {
return this._stream.stat(path, cb);
};
SFTPWrapper.prototype.lstat = function(path, cb) {
return this._stream.lstat(path, cb);
};
...
futimes = function (handle, atime, mtime, cb) { return this._stream.futimes(handle, atime, mtime, cb); }
...
SFTPWrapper.prototype.setstat = function(path, attrs, cb) {
return this._stream.setstat(path, attrs, cb);
};
SFTPWrapper.prototype.fsetstat = function(handle, attrs, cb) {
return this._stream.fsetstat(handle, attrs, cb);
};
SFTPWrapper.prototype.futimes = function(handle, atime, mtime, cb) {
return this._stream.futimes(handle, atime, mtime, cb);
};
SFTPWrapper.prototype.utimes = function(path, atime, mtime, cb) {
return this._stream.utimes(path, atime, mtime, cb);
};
SFTPWrapper.prototype.fchown = function(handle, uid, gid, cb) {
return this._stream.fchown(handle, uid, gid, cb);
};
...
lstat = function (path, cb) { return this._stream.lstat(path, cb); }
...
SFTPWrapper.prototype.fstat = function(handle, cb) {
return this._stream.fstat(handle, cb);
};
SFTPWrapper.prototype.stat = function(path, cb) {
return this._stream.stat(path, cb);
};
SFTPWrapper.prototype.lstat = function(path, cb) {
return this._stream.lstat(path, cb);
};
SFTPWrapper.prototype.opendir = function(path, cb) {
return this._stream.opendir(path, cb);
};
SFTPWrapper.prototype.setstat = function(path, attrs, cb) {
return this._stream.setstat(path, attrs, cb);
};
...
mkdir = function (path, attrs, cb) { return this._stream.mkdir(path, attrs, cb); }
...
SFTPWrapper.prototype.unlink = function(filename, cb) {
return this._stream.unlink(filename, cb);
};
SFTPWrapper.prototype.rename = function(oldPath, newPath, cb) {
return this._stream.rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.mkdir = function(path, attrs, cb) {
return this._stream.mkdir(path, attrs, cb);
};
SFTPWrapper.prototype.rmdir = function(path, cb) {
return this._stream.rmdir(path, cb);
};
SFTPWrapper.prototype.readdir = function(where, opts, cb) {
return this._stream.readdir(where, opts, cb);
};
...
open = function (path, flags, attrs, cb) { return this._stream.open(path, flags, attrs, cb); }
...
SFTPWrapper.prototype.createReadStream = function(path, options) {
return this._stream.createReadStream(path, options);
};
SFTPWrapper.prototype.createWriteStream = function(path, options) {
return this._stream.createWriteStream(path, options);
};
SFTPWrapper.prototype.open = function(path, flags, attrs, cb) {
return this._stream.open(path, flags, attrs, cb);
};
SFTPWrapper.prototype.close = function(handle, cb) {
return this._stream.close(handle, cb);
};
SFTPWrapper.prototype.read = function(handle, buf, off, len, position, cb) {
return this._stream.readData(handle, buf, off, len, position, cb);
};
...
opendir = function (path, cb) { return this._stream.opendir(path, cb); }
...
SFTPWrapper.prototype.stat = function(path, cb) {
return this._stream.stat(path, cb);
};
SFTPWrapper.prototype.lstat = function(path, cb) {
return this._stream.lstat(path, cb);
};
SFTPWrapper.prototype.opendir = function(path, cb) {
return this._stream.opendir(path, cb);
};
SFTPWrapper.prototype.setstat = function(path, attrs, cb) {
return this._stream.setstat(path, attrs, cb);
};
SFTPWrapper.prototype.fsetstat = function(handle, attrs, cb) {
return this._stream.fsetstat(handle, attrs, cb);
};
...
read = function (handle, buf, off, len, position, cb) { return this._stream.readData(handle, buf, off, len, position, cb); }
n/a
readFile = function (path, options, callback_) { return this._stream.readFile(path, options, callback_); }
...
SFTPWrapper.prototype.fastGet = function(remotePath, localPath, opts, cb) {
return this._stream.fastGet(remotePath, localPath, opts, cb);
};
SFTPWrapper.prototype.fastPut = function(localPath, remotePath, opts, cb) {
return this._stream.fastPut(localPath, remotePath, opts, cb);
};
SFTPWrapper.prototype.readFile = function(path, options, callback_) {
return this._stream.readFile(path, options, callback_);
};
SFTPWrapper.prototype.writeFile = function(path, data, options, callback_) {
return this._stream.writeFile(path, data, options, callback_);
};
SFTPWrapper.prototype.appendFile = function(path, data, options, callback_) {
return this._stream.appendFile(path, data, options, callback_);
};
...
readdir = function (where, opts, cb) { return this._stream.readdir(where, opts, cb); }
...
var Client = require('ssh2').Client;
var conn = new Client();
conn.on('ready', function() {
console.log('Client :: ready');
conn.sftp(function(err, sftp) {
if (err) throw err;
sftp.readdir('foo', function(err, list) {
if (err) throw err;
console.dir(list);
conn.end();
});
});
}).connect({
host: '192.168.100.100',
...
readlink = function (path, cb) { return this._stream.readlink(path, cb); }
...
SFTPWrapper.prototype.fchmod = function(handle, mode, cb) {
return this._stream.fchmod(handle, mode, cb);
};
SFTPWrapper.prototype.chmod = function(path, mode, cb) {
return this._stream.chmod(path, mode, cb);
};
SFTPWrapper.prototype.readlink = function(path, cb) {
return this._stream.readlink(path, cb);
};
SFTPWrapper.prototype.symlink = function(targetPath, linkPath, cb) {
return this._stream.symlink(targetPath, linkPath, cb);
};
SFTPWrapper.prototype.realpath = function(path, cb) {
return this._stream.realpath(path, cb);
};
...
realpath = function (path, cb) { return this._stream.realpath(path, cb); }
...
SFTPWrapper.prototype.readlink = function(path, cb) {
return this._stream.readlink(path, cb);
};
SFTPWrapper.prototype.symlink = function(targetPath, linkPath, cb) {
return this._stream.symlink(targetPath, linkPath, cb);
};
SFTPWrapper.prototype.realpath = function(path, cb) {
return this._stream.realpath(path, cb);
};
// extended requests
SFTPWrapper.prototype.ext_openssh_rename = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.ext_openssh_statvfs = function(path, cb) {
return this._stream.ext_openssh_statvfs(path, cb);
...
rename = function (oldPath, newPath, cb) { return this._stream.rename(oldPath, newPath, cb); }
...
SFTPWrapper.prototype.exists = function(path, cb) {
return this._stream.exists(path, cb);
};
SFTPWrapper.prototype.unlink = function(filename, cb) {
return this._stream.unlink(filename, cb);
};
SFTPWrapper.prototype.rename = function(oldPath, newPath, cb) {
return this._stream.rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.mkdir = function(path, attrs, cb) {
return this._stream.mkdir(path, attrs, cb);
};
SFTPWrapper.prototype.rmdir = function(path, cb) {
return this._stream.rmdir(path, cb);
};
...
rmdir = function (path, cb) { return this._stream.rmdir(path, cb); }
...
SFTPWrapper.prototype.rename = function(oldPath, newPath, cb) {
return this._stream.rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.mkdir = function(path, attrs, cb) {
return this._stream.mkdir(path, attrs, cb);
};
SFTPWrapper.prototype.rmdir = function(path, cb) {
return this._stream.rmdir(path, cb);
};
SFTPWrapper.prototype.readdir = function(where, opts, cb) {
return this._stream.readdir(where, opts, cb);
};
SFTPWrapper.prototype.fstat = function(handle, cb) {
return this._stream.fstat(handle, cb);
};
...
setstat = function (path, attrs, cb) { return this._stream.setstat(path, attrs, cb); }
...
SFTPWrapper.prototype.lstat = function(path, cb) {
return this._stream.lstat(path, cb);
};
SFTPWrapper.prototype.opendir = function(path, cb) {
return this._stream.opendir(path, cb);
};
SFTPWrapper.prototype.setstat = function(path, attrs, cb) {
return this._stream.setstat(path, attrs, cb);
};
SFTPWrapper.prototype.fsetstat = function(handle, attrs, cb) {
return this._stream.fsetstat(handle, attrs, cb);
};
SFTPWrapper.prototype.futimes = function(handle, atime, mtime, cb) {
return this._stream.futimes(handle, atime, mtime, cb);
};
...
stat = function (path, cb) { return this._stream.stat(path, cb); }
...
SFTPWrapper.prototype.readdir = function(where, opts, cb) {
return this._stream.readdir(where, opts, cb);
};
SFTPWrapper.prototype.fstat = function(handle, cb) {
return this._stream.fstat(handle, cb);
};
SFTPWrapper.prototype.stat = function(path, cb) {
return this._stream.stat(path, cb);
};
SFTPWrapper.prototype.lstat = function(path, cb) {
return this._stream.lstat(path, cb);
};
SFTPWrapper.prototype.opendir = function(path, cb) {
return this._stream.opendir(path, cb);
};
...
symlink = function (targetPath, linkPath, cb) { return this._stream.symlink(targetPath, linkPath, cb); }
...
SFTPWrapper.prototype.chmod = function(path, mode, cb) {
return this._stream.chmod(path, mode, cb);
};
SFTPWrapper.prototype.readlink = function(path, cb) {
return this._stream.readlink(path, cb);
};
SFTPWrapper.prototype.symlink = function(targetPath, linkPath, cb) {
return this._stream.symlink(targetPath, linkPath, cb);
};
SFTPWrapper.prototype.realpath = function(path, cb) {
return this._stream.realpath(path, cb);
};
// extended requests
SFTPWrapper.prototype.ext_openssh_rename = function(oldPath, newPath, cb) {
return this._stream.ext_openssh_rename(oldPath, newPath, cb);
...
unlink = function (filename, cb) { return this._stream.unlink(filename, cb); }
...
SFTPWrapper.prototype.appendFile = function(path, data, options, callback_) {
return this._stream.appendFile(path, data, options, callback_);
};
SFTPWrapper.prototype.exists = function(path, cb) {
return this._stream.exists(path, cb);
};
SFTPWrapper.prototype.unlink = function(filename, cb) {
return this._stream.unlink(filename, cb);
};
SFTPWrapper.prototype.rename = function(oldPath, newPath, cb) {
return this._stream.rename(oldPath, newPath, cb);
};
SFTPWrapper.prototype.mkdir = function(path, attrs, cb) {
return this._stream.mkdir(path, attrs, cb);
};
...
utimes = function (path, atime, mtime, cb) { return this._stream.utimes(path, atime, mtime, cb); }
...
SFTPWrapper.prototype.fsetstat = function(handle, attrs, cb) {
return this._stream.fsetstat(handle, attrs, cb);
};
SFTPWrapper.prototype.futimes = function(handle, atime, mtime, cb) {
return this._stream.futimes(handle, atime, mtime, cb);
};
SFTPWrapper.prototype.utimes = function(path, atime, mtime, cb) {
return this._stream.utimes(path, atime, mtime, cb);
};
SFTPWrapper.prototype.fchown = function(handle, uid, gid, cb) {
return this._stream.fchown(handle, uid, gid, cb);
};
SFTPWrapper.prototype.chown = function(path, uid, gid, cb) {
return this._stream.chown(path, uid, gid, cb);
};
...
write = function (handle, buf, off, len, position, cb) { return this._stream.writeData(handle, buf, off, len, position, cb); }
...
conn.on('ready', function() {
console.log('Client :: ready');
conn.subsys('netconf', function(err, stream) {
if (err) throw err;
stream.on('data', function(data) {
console.log(data);
}).write(xmlhello);
});
}).connect({
host: '1.2.3.4',
port: 22,
username: 'blargh',
password: 'honk'
});
...
writeFile = function (path, data, options, callback_) { return this._stream.writeFile(path, data, options, callback_); }
...
SFTPWrapper.prototype.fastPut = function(localPath, remotePath, opts, cb) {
return this._stream.fastPut(localPath, remotePath, opts, cb);
};
SFTPWrapper.prototype.readFile = function(path, options, callback_) {
return this._stream.readFile(path, options, callback_);
};
SFTPWrapper.prototype.writeFile = function(path, data, options, callback_) {
return this._stream.writeFile(path, data, options, callback_);
};
SFTPWrapper.prototype.appendFile = function(path, data, options, callback_) {
return this._stream.appendFile(path, data, options, callback_);
};
SFTPWrapper.prototype.exists = function(path, cb) {
return this._stream.exists(path, cb);
};
...
function Server(cfg, listener) { if (!(this instanceof Server)) return new Server(cfg, listener); var hostKeys = { 'ssh-rsa': null, 'ssh-dss': null, 'ecdsa-sha2-nistp256': null, 'ecdsa-sha2-nistp384': null, 'ecdsa-sha2-nistp521': null }; var hostKeys_ = cfg.hostKeys; if (!Array.isArray(hostKeys_)) throw new Error('hostKeys must be an array'); var i; for (i = 0; i < hostKeys_.length; ++i) { var privateKey; if (Buffer.isBuffer(hostKeys_[i]) || typeof hostKeys_[i] === 'string') privateKey = parseKey(hostKeys_[i]); else privateKey = parseKey(hostKeys_[i].key); if (privateKey instanceof Error) throw new Error('Cannot parse privateKey: ' + privateKey.message); if (!privateKey.private) throw new Error('privateKey value contains an invalid private key'); if (hostKeys[privateKey.fulltype]) continue; if (privateKey.encryption) { if (typeof hostKeys_[i].passphrase !== 'string') throw new Error('Missing passphrase for encrypted private key'); decryptKey(privateKey, hostKeys_[i].passphrase); } hostKeys[privateKey.fulltype] = { privateKey: privateKey, publicKey: genPublicKey(privateKey) }; } var algorithms = { kex: undefined, kexBuf: undefined, cipher: undefined, cipherBuf: undefined, serverHostKey: undefined, serverHostKeyBuf: undefined, hmac: undefined, hmacBuf: undefined, compress: undefined, compressBuf: undefined }; if (typeof cfg.algorithms === 'object' && cfg.algorithms !== null) { var algosSupported; var algoList; algoList = cfg.algorithms.kex; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_KEX; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported key exchange algorithm: ' + algoList[i]); } algorithms.kex = algoList; } algoList = cfg.algorithms.cipher; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_CIPHER; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported cipher algorithm: ' + algoList[i]); } algorithms.cipher = algoList; } algoList = cfg.algorithms.serverHostKey; var copied = false; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_SERVER_HOST_KEY; for (i = algoList.length - 1; i >= 0; --i) { if (algosSupported.indexOf(algoList[i]) === -1) { throw new Error('Unsupported server host key algorithm: ' + algoList[i]); } if (!hostKeys[algoList[i]]) { // Silently discard for now if (!copied) { algoList = algoList.slice(); copied = true; } algoList.splice(i, 1); } } if (algoList.length > 0) algorithms.serverHostKey = algoList; } algoList = cfg.algorithms.hmac; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_HMAC; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported HMAC algorithm: ' + algoList[i]); } algorithms.hmac = algoList; } algoList = cfg.algorithms.compress; if (Array.isArray(algoList) && algoList.length > 0) { algosSupported = ALGORITHMS.SUPPORTED_COMPRESS; for (i = 0; i < algoList.length; ++i) { if (algosSupported.indexOf(algoList[i]) === -1) throw new Error('Unsupported compression algorithm: ' + algoList[i]); } algorithms.compress = algoList; } } // Make sure we at least have some kind of valid list of support key // formats if (algorithms.serverHostKey === undefined) { var hostKeyAlgos = Object.keys(hostKeys); for (i = hostKeyAlgos.length - 1; i ...
...
var buffersEqual = require('buffer-equal-constant-time');
var ssh2 = require('ssh2');
var utils = ssh2.utils;
var pubKey = utils.genPublicKey(utils.parseKey(fs.readFileSync('user.pub')));
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
if (ctx.method === 'password'
&& ctx.username === 'foo'
...
createServer = function (cfg, listener) { return new Server(cfg, listener); }
...
var ssh_config = {
host: '192.168.100.1',
port: 22,
username: 'nodejs',
password: 'rules'
};
socks.createServer(function(info, accept, deny) {
// 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', function() {
conn.forwardOut(info.srcAddr,
info.srcPort,
...
function EventEmitter() { EventEmitter.init.call(this); }
n/a
address = function () { return this._srv.address(); }
...
stream.end();
});
});
}).on('end', function() {
console.log('Client disconnected');
});
}).listen(0, '127.0.0.1', function() {
console.log('Listening on port ' + this.address().port);
});
```
* SFTP only server:
```javascript
var fs = require('fs');
...
close = function (cb) { this._srv.close(cb); return this; }
...
self.push(null);
if (server && self.stderr.writable)
self.stderr.end();
else if (!server && self.stderr.readable)
self.stderr.push(null);
if (outgoing.state === 'open' || outgoing.state === 'eof')
self.close();
if (outgoing.state === 'closing')
outgoing.state = 'closed';
delete channels[incomingId];
var state = self._writableState;
client._sock.removeListener('drain', ondrain);
...
getConnections = function (cb) { this._srv.getConnections(cb); }
n/a
listen = function () { this._srv.listen.apply(this._srv, arguments); return this; }
...
});
} else
conn.end();
});
}).on('error', function(err) {
deny();
}).connect(ssh_config);
}).listen(1080, 'localhost', function() {
console.log('SOCKSv5 proxy server started on port 1080');
}).useAuth(socks.auth.None());
// test with cURL:
// curl -i --socks5 localhost:1080 google.com
```
...
ref = function () { this._srv.ref(); }
n/a
unref = function () { this._srv.unref(); }
n/a
function Manager(interval, streamInterval, kaCountMax) { var streams = this._streams = []; this._timer = undefined; this._timerInterval = interval; this._timerfn = function() { var now = Date.now(); for (var i = 0, len = streams.length, s, last; i < len; ++i) { s = streams[i]; last = s._kalast; if (last && (now - last) >= streamInterval) { if (++s._kacnt > kaCountMax) { var err = new Error('Keepalive timeout'); err.level = 'client-timeout'; s.emit('error', err); s.disconnect(); spliceOne(streams, i); --i; len = streams.length; } else { s._kalast = now; // XXX: if the server ever starts sending real global requests to the // client, we will need to add a dummy callback here to keep the // correct reply order s.ping(); } } } }; }
n/a
add = function (stream) { var streams = this._streams, self = this; stream.once('end', function() { self.remove(stream); }).on('packet', resetKA); streams[streams.length] = stream; resetKA(); if (!this._timer) this.start(); function resetKA() { stream._kalast = Date.now(); stream._kacnt = 0; } }
n/a
remove = function (stream) { var streams = this._streams, index = streams.indexOf(stream); if (index > -1) spliceOne(streams, index); if (!streams.length) this.stop(); }
...
};
Manager.prototype.add = function(stream) {
var streams = this._streams,
self = this;
stream.once('end', function() {
self.remove(stream);
}).on('packet', resetKA);
streams[streams.length] = stream;
resetKA();
if (!this._timer)
...
start = function () { if (this._timer) this.stop(); this._timer = setInterval(this._timerfn, this._timerInterval); }
...
}).on('packet', resetKA);
streams[streams.length] = stream;
resetKA();
if (!this._timer)
this.start();
function resetKA() {
stream._kalast = Date.now();
stream._kacnt = 0;
}
};
...
stop = function () { if (this._timer) { clearInterval(this._timer); this._timer = undefined; } }
...
}
}
};
}
Manager.prototype.start = function() {
if (this._timer)
this.stop();
this._timer = setInterval(this._timerfn, this._timerInterval);
};
Manager.prototype.stop = function() {
if (this._timer) {
clearInterval(this._timer);
this._timer = undefined;
...
function DSAKeySSHToASN1(key, self, callback) { // Convert SSH key parameters to ASN.1 BER values for OpenSSL var p = readString(key, key._pos, self, callback); if (p === false) return false; var q = readString(key, key._pos, self, callback); if (q === false) return false; var g = readString(key, key._pos, self, callback); if (g === false) return false; var y = readString(key, key._pos, self, callback); if (y === false) return false; var asnWriter = new Ber.Writer(); asnWriter.startSequence(); // algorithm asnWriter.startSequence(); asnWriter.writeOID('1.2.840.10040.4.1'); // id-dsa // algorithm parameters asnWriter.startSequence(); asnWriter.writeBuffer(p, Ber.Integer); asnWriter.writeBuffer(q, Ber.Integer); asnWriter.writeBuffer(g, Ber.Integer); asnWriter.endSequence(); asnWriter.endSequence(); // subjectPublicKey asnWriter.startSequence(Ber.BitString); asnWriter.writeByte(0x00); asnWriter.writeBuffer(y, Ber.Integer); asnWriter.endSequence(); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function DSASigBERToBare(signature) { if (signature.length <= 40) return signature; // This is a quick and dirty way to get from BER encoded r and s that // OpenSSL gives us, to just the bare values back to back (40 bytes // total) like OpenSSH (and possibly others) are expecting var asnReader = new Ber.Reader(signature); asnReader.readSequence(); var r = asnReader.readString(Ber.Integer, true); var s = asnReader.readString(Ber.Integer, true); var rOffset = 0; var sOffset = 0; if (r.length < 20) { var rNew = new Buffer(20); r.copy(rNew, 1); r = rNew; r[0] = 0; } if (s.length < 20) { var sNew = new Buffer(20); s.copy(sNew, 1); s = sNew; s[0] = 0; } if (r.length > 20 && r[0] === 0x00) rOffset = 1; if (s.length > 20 && s[0] === 0x00) sOffset = 1; var newSig = new Buffer((r.length - rOffset) + (s.length - sOffset)); r.copy(newSig, 0, rOffset); s.copy(newSig, r.length - rOffset, sOffset); return newSig; }
n/a
function DSASigBareToBER(signature) { if (signature.length > 40) return signature; // Change bare signature r and s values to ASN.1 BER values for OpenSSL var asnWriter = new Ber.Writer(); asnWriter.startSequence(); var r = signature.slice(0, 20); var s = signature.slice(20); if (r[0] & 0x80) { var rNew = new Buffer(21); rNew[0] = 0x00; r.copy(rNew, 1); r = rNew; } else if (r[0] === 0x00 && !(r[1] & 0x80)) { r = r.slice(1); } if (s[0] & 0x80) { var sNew = new Buffer(21); sNew[0] = 0x00; s.copy(sNew, 1); s = sNew; } else if (s[0] === 0x00 && !(s[1] & 0x80)) { s = s.slice(1); } asnWriter.writeBuffer(r, Ber.Integer); asnWriter.writeBuffer(s, Ber.Integer); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function ECDSAKeySSHToASN1(key, self, callback) { // Convert SSH key parameters to ASN.1 BER values for OpenSSL var curve = readString(key, key._pos, self, callback); if (curve === false) return false; var Q = readString(key, key._pos, self, callback); if (Q === false) return false; var ecCurveOID; switch (curve.toString('ascii')) { case 'nistp256': // prime256v1/secp256r1 ecCurveOID = '1.2.840.10045.3.1.7'; break; case 'nistp384': // secp384r1 ecCurveOID = '1.3.132.0.34'; break; case 'nistp521': // secp521r1 ecCurveOID = '1.3.132.0.35'; break; default: return false; } var asnWriter = new Ber.Writer(); asnWriter.startSequence(); // algorithm asnWriter.startSequence(); asnWriter.writeOID('1.2.840.10045.2.1'); // id-ecPublicKey // algorithm parameters (namedCurve) asnWriter.writeOID(ecCurveOID); asnWriter.endSequence(); // subjectPublicKey asnWriter.startSequence(Ber.BitString); asnWriter.writeByte(0x00); // XXX: hack to write a raw buffer without a tag -- yuck asnWriter._ensure(Q.length); Q.copy(asnWriter._buf, asnWriter._offset, 0, Q.length); asnWriter._offset += Q.length; // end hack asnWriter.endSequence(); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function ECDSASigASN1ToSSH(signature) { if (signature[0] === 0x00) return signature; // Convert SSH signature parameters to ASN.1 BER values for OpenSSL var asnReader = new Ber.Reader(signature); asnReader.readSequence(); var r = asnReader.readString(Ber.Integer, true); var s = asnReader.readString(Ber.Integer, true); if (r === null || s === null) throw new Error('Invalid signature'); var newSig = new Buffer(4 + r.length + 4 + s.length); newSig.writeUInt32BE(r.length, 0, true); r.copy(newSig, 4); newSig.writeUInt32BE(s.length, 4 + r.length, true); s.copy(newSig, 4 + 4 + r.length); return newSig; }
n/a
function ECDSASigSSHToASN1(signature, self, callback) { // Convert SSH signature parameters to ASN.1 BER values for OpenSSL var r = readString(signature, 0, self, callback); if (r === false) return false; var s = readString(signature, signature._pos, self, callback); if (s === false) return false; var asnWriter = new Ber.Writer(); asnWriter.startSequence(); asnWriter.writeBuffer(r, Ber.Integer); asnWriter.writeBuffer(s, Ber.Integer); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function RSAKeySSHToASN1(key, self, callback) { // Convert SSH key parameters to ASN.1 BER values for OpenSSL var e = readString(key, key._pos, self, callback); if (e === false) return false; var n = readString(key, key._pos, self, callback); if (n === false) return false; var asnWriter = new Ber.Writer(); asnWriter.startSequence(); // algorithm asnWriter.startSequence(); asnWriter.writeOID('1.2.840.113549.1.1.1'); // rsaEncryption // algorithm parameters (RSA has none) asnWriter.writeNull(); asnWriter.endSequence(); // subjectPublicKey asnWriter.startSequence(Ber.BitString); asnWriter.writeByte(0x00); asnWriter.startSequence(); asnWriter.writeBuffer(n, Ber.Integer); asnWriter.writeBuffer(e, Ber.Integer); asnWriter.endSequence(); asnWriter.endSequence(); asnWriter.endSequence(); return asnWriter.buffer; }
n/a
function convertPPKPrivate(keyInfo) { if (!keyInfo.ppk || !keyInfo.public || !keyInfo.private) throw new Error("Key isn't a PPK"); else if (keyInfo._converted) return false; var pub = keyInfo.public; var priv = keyInfo.private; var asnWriter = new Ber.Writer(); var p; var q; if (keyInfo.type === 'rsa') { var e = readString(pub, 4 + 7); var n = readString(pub, pub._pos); var d = readString(priv, 0); p = readString(priv, priv._pos); q = readString(priv, priv._pos); var iqmp = readString(priv, priv._pos); var p1 = new BigInteger(p, 256); var q1 = new BigInteger(q, 256); var dmp1 = new BigInteger(d, 256); var dmq1 = new BigInteger(d, 256); dmp1 = new Buffer(dmp1.mod(p1.subtract(BigInteger.ONE)).toByteArray()); dmq1 = new Buffer(dmq1.mod(q1.subtract(BigInteger.ONE)).toByteArray()); asnWriter.startSequence(); asnWriter.writeInt(0x00, Ber.Integer); asnWriter.writeBuffer(n, Ber.Integer); asnWriter.writeBuffer(e, Ber.Integer); asnWriter.writeBuffer(d, Ber.Integer); asnWriter.writeBuffer(p, Ber.Integer); asnWriter.writeBuffer(q, Ber.Integer); asnWriter.writeBuffer(dmp1, Ber.Integer); asnWriter.writeBuffer(dmq1, Ber.Integer); asnWriter.writeBuffer(iqmp, Ber.Integer); asnWriter.endSequence(); } else { p = readString(pub, 4 + 7); q = readString(pub, pub._pos); var g = readString(pub, pub._pos); var y = readString(pub, pub._pos); var x = readString(priv, 0); asnWriter.startSequence(); asnWriter.writeInt(0x00, Ber.Integer); asnWriter.writeBuffer(p, Ber.Integer); asnWriter.writeBuffer(q, Ber.Integer); asnWriter.writeBuffer(g, Ber.Integer); asnWriter.writeBuffer(y, Ber.Integer); asnWriter.writeBuffer(x, Ber.Integer); asnWriter.endSequence(); } var b64key = asnWriter.buffer.toString('base64').replace(RE_KEY_LEN, '$1\n'); var fullkey = '-----BEGIN ' + (keyInfo.type === 'rsa' ? 'RSA' : 'DSA') + ' PRIVATE KEY-----\n' + b64key + (b64key[b64key.length - 1] === '\n' ? '' : '\n') + '-----END ' + (keyInfo.type === 'rsa' ? 'RSA' : 'DSA') + ' PRIVATE KEY-----'; keyInfo.private = asnWriter.buffer; keyInfo.privateOrig = new Buffer(fullkey); keyInfo._converted = true; return true; }
n/a
function decryptKey(keyInfo, passphrase) { if (keyInfo._decrypted || !keyInfo.encryption) return; var keylen = 0; var key; var iv; var dc; keyInfo.encryption = (SSH_TO_OPENSSL[keyInfo.encryption] || keyInfo.encryption); switch (keyInfo.encryption) { case 'aes-256-cbc': case 'aes-256-ctr': keylen = 32; break; case 'des-ede3-cbc': case 'des-ede3': case 'aes-192-cbc': case 'aes-192-ctr': keylen = 24; break; case 'aes-128-cbc': case 'aes-128-ctr': case 'cast-cbc': case 'bf-cbc': keylen = 16; break; default: throw new Error('Unsupported cipher for encrypted key: ' + keyInfo.encryption); } if (keyInfo.ppk) { iv = PPK_IV; key = Buffer.concat([ crypto.createHash('sha1') .update('\x00\x00\x00\x00' + passphrase, 'utf8') .digest(), crypto.createHash('sha1') .update('\x00\x00\x00\x01' + passphrase, 'utf8') .digest() ]); key = key.slice(0, keylen); } else { iv = new Buffer(keyInfo.extra[0], 'hex'); key = crypto.createHash('md5') .update(passphrase, 'utf8') .update(iv.slice(0, 8)) .digest(); while (keylen > key.length) { key = Buffer.concat([ key, (crypto.createHash('md5') .update(key) .update(passphrase, 'utf8') .update(iv) .digest()).slice(0, 8) ]); } if (key.length > keylen) key = key.slice(0, keylen); } dc = crypto.createDecipheriv(keyInfo.encryption, key, iv); dc.setAutoPadding(false); keyInfo.private = Buffer.concat([ dc.update(keyInfo.private), dc.final() ]); keyInfo._decrypted = true; if (keyInfo.privateOrig) { // Update our original base64-encoded version of the private key var orig = keyInfo.privateOrig.toString('utf8'); var newOrig = /^(.+(?:\r\n|\n))/.exec(orig)[1]; var b64key = keyInfo.private.toString('base64'); newOrig += b64key.match(/.{1,70}/g).join('\n'); newOrig += /((?:\r\n|\n).+)$/.exec(orig)[1]; keyInfo.privateOrig = newOrig; } else if (keyInfo.ppk) { var valid = verifyPPKMAC(keyInfo, passphrase, keyInfo.private); if (!valid) throw new Error('PPK MAC mismatch'); // Automatically convert private key data to OpenSSL format // (including PEM) convertPPKPrivate(keyInfo); } // Fill in full key type // TODO: make DRY, we do this also in keyParser if (keyInfo.type !== 'ec') { keyInfo.fulltype = 'ssh-' + keyInfo.type; } else { // ECDSA var asnReader = new Ber.Reader(keyInfo.private); asnReader.readSequence(); asnReader.readInt(); asnReader.readString(Ber.OctetString, true); asnReader.readByte(); // Skip "complex" context type byte var offset = asnReader.readLength(); // Skip context length if (offset !== null) { asnReader._offset = offset; switch (asnReader.readOID()) { case '1.2.840.10045.3.1.7': // prime256v1/secp256r1 keyInfo.fulltype = 'ecdsa-sha2-nistp256'; break; case '1.3.132.0.34': // secp384r1 keyInfo.fulltype = 'ecdsa-sha2-nistp384'; break; case '1.3.132.0.35': // secp521r1 keyInfo.fulltype = 'ecdsa-sha2-nistp521'; break; } } if (keyInfo.fulltype === undefined) return new Error('Unsupported EC private key type'); } }
n/a
function genPublicKey(keyInfo) { var publicKey; var i; // RSA var n; var e; // DSA var p; var q; var g; var y; // ECDSA var d; var Q; var ecCurveOID; var ecCurveName; if (keyInfo.private) { // parsing private key in ASN.1 format in order to generate a public key var privKey = keyInfo.private; var asnReader = new Ber.Reader(privKey); var errMsg; if (asnReader.readSequence() === null) { errMsg = 'Malformed private key (expected sequence)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // version (ignored) if (asnReader.readInt() === null) { errMsg = 'Malformed private key (expected version)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } if (keyInfo.type === 'rsa') { // modulus (n) -- integer n = asnReader.readString(Ber.Integer, true); if (n === null) { errMsg = 'Malformed private key (expected RSA n value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // public exponent (e) -- integer e = asnReader.readString(Ber.Integer, true); if (e === null) { errMsg = 'Malformed private key (expected RSA e value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } publicKey = new Buffer(4 + 7 // ssh-rsa + 4 + n.length + 4 + e.length); publicKey.writeUInt32BE(7, 0, true); publicKey.write('ssh-rsa', 4, 7, 'ascii'); i = 4 + 7; publicKey.writeUInt32BE(e.length, i, true); e.copy(publicKey, i += 4); publicKey.writeUInt32BE(n.length, i += e.length, true); n.copy(publicKey, i += 4); } else if (keyInfo.type === 'dss') { // DSA // prime (p) -- integer p = asnReader.readString(Ber.Integer, true); if (p === null) { errMsg = 'Malformed private key (expected DSA p value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // group order (q) -- integer q = asnReader.readString(Ber.Integer, true); if (q === null) { errMsg = 'Malformed private key (expected DSA q value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // group generator (g) -- integer g = asnReader.readString(Ber.Integer, true); if (g === null) { errMsg = 'Malformed private key (expected DSA g value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } // public key value (y) -- integer y = asnReader.readString(Ber.Integer, true); if (y === null) { errMsg = 'Malformed private key (expected DSA y value)'; if (keyInfo._decrypted) errMsg += '. Bad passphrase?'; throw new Error(errMsg); } publicKey = new Buffer(4 + 7 // ssh-dss + 4 + p.length + 4 + q.length + 4 + g.length + 4 + y.length); publicKey.writeUInt32BE(7, 0, true); publicKey.write('ssh-dss', 4, 7, 'ascii'); i = 4 + 7; publicKey.writeUInt32BE(p.length, i, true); p.copy(publicKey, i += 4); publicKey.writeUInt32BE(q.length, i += p.length, true); q.copy(publicKey, i += 4); publicKey.writeUInt32BE(g.length, i += q.length, true); g.copy(publicKey, i += 4); publicKey.writeUInt32BE(y.length, i += g.length, true); y.copy(publicKey, i += 4); } else { // ECDSA d = asnReader.readString(Ber.OctetString, true); if (d === null) throw new Error('Malformed private key (expected ECDSA private key)'); asnReader.readByte(); // Skip "complex" context type byte var offset = asnReader.readLength(); // Sk ...
...
var crypto = require('crypto');
var inspect = require('util').inspect;
var buffersEqual = require('buffer-equal-constant-time');
var ssh2 = require('ssh2');
var utils = ssh2.utils;
var pubKey = utils.genPublicKey(utils.parseKey(fs.readFileSync('user.pub')));
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
...
function isStreamCipher(name) { return RE_STREAM.test(name); }
n/a
function iv_inc(iv) { var n = 12; var c = 0; do { --n; c = iv[n]; if (c === 255) iv[n] = 0; else { iv[n] = ++c; return; } } while (n > 4); }
n/a
parseKey = function (data) { if (Buffer.isBuffer(data)) data = data.toString('utf8'); else if (typeof data !== 'string') return new Error('Key data must be a Buffer or string'); var ret = { fulltype: undefined, type: undefined, curve: undefined, extra: undefined, comment: undefined, encryption: undefined, private: undefined, privateOrig: undefined, public: undefined, publicOrig: undefined }; var m; var i; var len; data = data.trim().split(/\r\n|\n/); while (!data[0].length) data.shift(); while (!data.slice(-1)[0].length) data.pop(); var orig = data.join('\n'); if ((m = RE_HEADER_OPENSSH_PRIV.exec(data[0])) && RE_FOOTER_OPENSSH_PRIV.test(data.slice(-1))) { // OpenSSH private key var keyType = m[1].toLowerCase(); if (keyType === 'dsa') keyType = 'dss'; if (keyType === 'ec' && semver.lt(process.version, '5.2.0')) { return new Error( 'EC private keys are not supported in this version of node' ); } if (!RE_HEADER_OPENSSH.test(data[1])) { // unencrypted, no headers var privData = new Buffer(data.slice(1, -1).join(''), 'base64'); if (keyType !== 'ec') { ret.fulltype = 'ssh-' + keyType; } else { // ECDSA var asnReader = new Ber.Reader(privData); asnReader.readSequence(); asnReader.readInt(); asnReader.readString(Ber.OctetString, true); asnReader.readByte(); // Skip "complex" context type byte var offset = asnReader.readLength(); // Skip context length if (offset !== null) { asnReader._offset = offset; switch (asnReader.readOID()) { case '1.2.840.10045.3.1.7': // prime256v1/secp256r1 ret.fulltype = 'ecdsa-sha2-nistp256'; break; case '1.3.132.0.34': // secp384r1 ret.fulltype = 'ecdsa-sha2-nistp384'; break; case '1.3.132.0.35': // secp521r1 ret.fulltype = 'ecdsa-sha2-nistp521'; break; } } if (ret.fulltype === undefined) return new Error('Unsupported EC private key type'); } ret.private = privData; } else { // possibly encrypted, headers for (i = 1, len = data.length; i < len; ++i) { m = RE_HEADER_OPENSSH.exec(data[i]); if (m) { m[1] = m[1].toLowerCase(); if (m[1] === 'dek-info') { m[2] = m[2].split(','); ret.encryption = m[2][0].toLowerCase(); if (m[2].length > 1) ret.extra = m[2].slice(1); } } else if (data[i].length) break; } ret.private = new Buffer(data.slice(i, -1).join(''), 'base64'); } ret.type = keyType; ret.privateOrig = new Buffer(orig); } else if (m = RE_HEADER_OPENSSH_PUB.exec(data[0])) { // OpenSSH public key ret.fulltype = m[1]; ret.type = (m[2] || 'ec').toLowerCase(); ret.public = new Buffer(m[4], 'base64'); ret.publicOrig = new Buffer(orig); ret.comment = m[5]; if (m[3]) // ECDSA only ret.curve = 'nistp' + m[3]; } else if (RE_HEADER_RFC4716_PUB.test(data[0]) && RE_FOOTER_RFC4716_PUB.test(data.slice(-1))) { if (data[1].indexOf(': ') === -1) { // no headers ret.public = new Buffer(data.slice(1, -1).join(''), 'base64'); } else { // headers for (i = 1, len = data.length; i < len; ++i) { if (data[i].indexOf(': ') === -1) { if (data[i].length) break; // start of key data else continue; // empty line } while (data[i].substr(-1) === '\\') { if (i + 1 < len) { data[i] = data[i].slice(0, -1) + data[i + 1]; data.splice(i + 1, 1); --len; } else return new Error('RFC4716 public key missing header continuation line'); } m = RE_HEADER_RFC4716.exec(data[i]); if (m) { m[1] = m[1].toLo ...
...
var crypto = require('crypto');
var inspect = require('util').inspect;
var buffersEqual = require('buffer-equal-constant-time');
var ssh2 = require('ssh2');
var utils = ssh2.utils;
var pubKey = utils.genPublicKey(utils.parseKey(fs.readFileSync('user.pub')));
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
...
function readInt(buffer, start, stream, cb) { var bufferLen = buffer.length; if (start < 0 || start >= bufferLen || (bufferLen - start) < 4) { stream && stream._cleanup(cb); return false; } return buffer.readUInt32BE(start, true); }
n/a
function readString(buffer, start, encoding, stream, cb, maxLen) { if (encoding && !Buffer.isBuffer(encoding) && typeof encoding !== 'string') { if (typeof cb === 'number') maxLen = cb; cb = stream; stream = encoding; encoding = undefined; } start || (start = 0); var bufferLen = buffer.length; var left = (bufferLen - start); var len; var end; if (start < 0 || start >= bufferLen || left < 4) { stream && stream._cleanup(cb); return false; } len = buffer.readUInt32BE(start, true); if (len > (maxLen || MAX_STRING_LEN) || left < (4 + len)) { stream && stream._cleanup(cb); return false; } start += 4; end = start + len; buffer._pos = end; if (encoding) { if (Buffer.isBuffer(encoding)) { buffer.copy(encoding, 0, start, end); return encoding; } else return buffer.toString(encoding, start, end); } else return buffer.slice(start, end); }
n/a
function verifyPPKMAC(keyInfo, passphrase, privateKey) { if (keyInfo._macresult !== undefined) return keyInfo._macresult; else if (!keyInfo.ppk) throw new Error("Key isn't a PPK"); else if (!keyInfo.privateMAC) throw new Error('Missing MAC'); else if (!privateKey) throw new Error('Missing raw private key data'); else if (keyInfo.encryption && typeof passphrase !== 'string') throw new Error('Missing passphrase for encrypted PPK'); else if (keyInfo.encryption && !keyInfo._decrypted) throw new Error('PPK must be decrypted before verifying MAC'); var mac = keyInfo.privateMAC; var typelen = keyInfo.fulltype.length; // encryption algorithm is converted at this point for use with OpenSSL, // so we need to use the original value so that the MAC is calculated // correctly var enc = (keyInfo.encryption ? 'aes256-cbc' : 'none'); var enclen = enc.length; var commlen = Buffer.byteLength(keyInfo.comment); var pub = keyInfo.public; var publen = pub.length; var privlen = privateKey.length; var macdata = new Buffer(4 + typelen + 4 + enclen + 4 + commlen + 4 + publen + 4 + privlen); var p = 0; macdata.writeUInt32BE(typelen, p, true); macdata.write(keyInfo.fulltype, p += 4, typelen, 'ascii'); macdata.writeUInt32BE(enclen, p += typelen, true); macdata.write(enc, p += 4, enclen, 'ascii'); macdata.writeUInt32BE(commlen, p += enclen, true); macdata.write(keyInfo.comment, p += 4, commlen, 'utf8'); macdata.writeUInt32BE(publen, p += commlen, true); pub.copy(macdata, p += 4); macdata.writeUInt32BE(privlen, p += publen, true); privateKey.copy(macdata, p += 4); if (typeof passphrase !== 'string') passphrase = ''; var mackey = crypto.createHash('sha1') .update('putty-private-key-file-mac-key', 'ascii') .update(passphrase, 'utf8') .digest(); var calcMAC = crypto.createHmac('sha1', mackey) .update(macdata) .digest('hex'); return (keyInfo._macresult = (calcMAC === mac)); }
n/a