hexo/node_modules/ssh2-streams/test/test-packet60.js

257 lines
8.4 KiB
JavaScript

var SSH2Stream = require('../lib/ssh');
var parseKey = require('../lib/utils').parseKey;
var genPubKey = require('../lib/utils').genPublicKey;
var assert = require('assert');
var crypto = require('crypto');
var fs = require('fs');
var t = -1;
var SERVER_PRV_KEY = fs.readFileSync(__dirname + '/fixtures/ssh_host_rsa_key');
var PARSED_SERVER_PRV_KEY = parseKey(SERVER_PRV_KEY);
var PARSED_SERVER_PUB_KEY = genPubKey(PARSED_SERVER_PRV_KEY);
var CLIENT_PRV_KEY = fs.readFileSync(__dirname + '/fixtures/id_rsa');
var PARSED_CLIENT_PRV_KEY = parseKey(CLIENT_PRV_KEY);
var PARSED_CLIENT_PUB_KEY = genPubKey(PARSED_CLIENT_PRV_KEY);
function makePair(cb) {
var server = new SSH2Stream({
server: true,
hostKeys: {
'ssh-rsa': {
privateKey: PARSED_SERVER_PRV_KEY,
publicKey: PARSED_SERVER_PUB_KEY
}
}
});
var client = new SSH2Stream();
var done = [];
function tryDone(who) {
done.push(who);
if (done.length !== 2)
return;
cb(server, client);
}
server.on('NEWKEYS', function () { tryDone('server'); });
client.on('NEWKEYS', function () { tryDone('client'); });
server.pipe(client).pipe(server);
}
function signWithClientKey(blob, syncCb) {
var signType = (PARSED_CLIENT_PRV_KEY.type === 'rsa' ? 'R' : 'D') + 'SA-SHA1';
var signature = crypto.createSign(signType);
signature.update(blob);
signature = signature.sign(PARSED_CLIENT_PRV_KEY.privateOrig);
syncCb(signature);
}
function bufferEqual(a, b) {
if (a.length !== b.length)
return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i])
return false;
}
return true;
}
function publickey(server, client) {
server.on('USERAUTH_REQUEST', function(user, service, method, data) {
assert.equal(user, 'bob');
assert.equal(service, 'ssh-connection');
assert.equal(method, 'publickey');
assert.equal(data.keyAlgo, PARSED_CLIENT_PUB_KEY.fulltype);
assert.equal(true, bufferEqual(data.key, PARSED_CLIENT_PUB_KEY.public));
assert.equal(data.signature, undefined);
assert.equal(data.blob, undefined);
return server.authPKOK(data.keyAlgo, data.key);
});
client.on('USERAUTH_PK_OK', function() {
next();
}).authPK('bob', PARSED_CLIENT_PUB_KEY);
}
function keyboardInteractive(server, client) {
var infoReqsRxed = 0;
server.on('USERAUTH_REQUEST', function(user, service, method, data) {
assert.equal(user, 'bob');
assert.equal(service, 'ssh-connection');
assert.equal(method, 'keyboard-interactive');
assert.equal(data, '');
process.nextTick(function() {
server.authInfoReq('req 0', 'instructions', [
{ prompt: 'Say something to req 0', echo: true }
]);
});
}).on('USERAUTH_INFO_RESPONSE', function(responses) {
if (infoReqsRxed === 1) {
assert.equal(responses.length, 1);
assert.equal(responses[0], 'hello to req 0');
process.nextTick(function() {
server.authInfoReq('req 1', 'new instructions', [
{ prompt: 'Say something to req 1', echo: true },
{ prompt: 'Say something else', echo: false }
]);
});
} else if (infoReqsRxed === 2) {
assert.equal(responses.length, 2);
assert.equal(responses[0], 'hello to req 1');
assert.equal(responses[1], 'something else');
next();
} else {
throw new Error('Received too many info reqs: ' + infoReqsRxed);
}
});
client.on('USERAUTH_INFO_REQUEST', function (name, inst, lang, prompts) {
infoReqsRxed++;
if (infoReqsRxed === 1) {
assert.equal(name, 'req 0');
assert.equal(inst, 'instructions');
assert.equal(lang, '');
assert.deepEqual(prompts, [
{ prompt: 'Say something to req 0', echo: true }
]);
process.nextTick(function() {
client.authInfoRes([ 'hello to req 0' ]);
});
} else if (infoReqsRxed === 2) {
assert.equal(name, 'req 1');
assert.equal(inst, 'new instructions');
assert.equal(lang, '');
assert.deepEqual(prompts, [
{ prompt: 'Say something to req 1', echo: true },
{ prompt: 'Say something else', echo: false }
]);
process.nextTick(function() {
client.authInfoRes([ 'hello to req 1', 'something else' ]);
});
} else {
throw new Error('Received too many info reqs: ' + infoReqsRxed);
}
}).authKeyboard('bob');
}
function mixedMethods(server, client) {
var expectedStages = [
'SERVER_SEES_PK_CHECK',
'SERVER_SEES_PK_REQUEST',
'SERVER_SEES_PASSWORD',
'SERVER_SEES_KEYBOARD_INTERACTIVE',
'CLIENT_SEES_PK_OK',
'CLIENT_SEES_USERAUTH_FAILURE_PK',
'CLIENT_SEES_USERAUTH_FAILURE_PASSWORD',
'CLIENT_SEES_KEYBOARD_REQ',
'SERVER_SEES_KEYBOARD_RES',
'CLIENT_SEES_USERAUTH_SUCCESS',
];
server.on('USERAUTH_REQUEST', function(name, service, method, data) {
assert.equal(name, 'bob');
assert.equal(service, 'ssh-connection');
var expectedStage = expectedStages.shift();
switch (expectedStage) {
case 'SERVER_SEES_PK_CHECK':
assert.equal(method, 'publickey');
assert.equal(data.signature, undefined);
return process.nextTick(function() {
server.authPKOK(data.keyAlgo, data.key);
});
case 'SERVER_SEES_PK_REQUEST':
assert.equal(method, 'publickey');
assert.notEqual(data.signature, undefined);
return process.nextTick(function() {
server.authFailure(
['publickey', 'password', 'keyboard-interactive'],
false
);
});
case 'SERVER_SEES_PASSWORD':
assert.equal(method, 'password');
assert.equal(data, 'seekrit');
return process.nextTick(function() {
server.authFailure(
['publickey', 'password', 'keyboard-interactive'],
false
);
});
case 'SERVER_SEES_KEYBOARD_INTERACTIVE':
assert.equal(method, 'keyboard-interactive');
assert.equal(data, '');
return process.nextTick(function() {
server.authInfoReq('Password required', 'Password prompt', [
{ prompt: 'Password:', echo: false }
]);
});
default:
throw new Error('Server saw USERAUTH_REQUEST ' + method +
' but expected ' + expectedStage);
}
}).on('USERAUTH_INFO_RESPONSE', function(responses) {
assert.equal(expectedStages.shift(), 'SERVER_SEES_KEYBOARD_RES');
assert.deepEqual(responses, [ 'seekrit' ]);
process.nextTick(function() {
server.authSuccess();
});
});
client.on('USERAUTH_PK_OK', function() {
assert.equal(expectedStages.shift(), 'CLIENT_SEES_PK_OK');
}).on('USERAUTH_FAILURE', function() {
var expectedStage = expectedStages.shift();
if (expectedStage !== 'CLIENT_SEES_USERAUTH_FAILURE_PK' &&
expectedStage !== 'CLIENT_SEES_USERAUTH_FAILURE_PASSWORD') {
throw new Error('Client saw USERAUTH_FAILURE but expected ' +
expectedStage);
}
}).on('USERAUTH_INFO_REQUEST', function(name, inst, lang, prompts) {
assert.equal(expectedStages.shift(), 'CLIENT_SEES_KEYBOARD_REQ');
assert.equal(name, 'Password required');
assert.equal(inst, 'Password prompt');
assert.equal(lang, '');
assert.deepEqual(prompts, [ { prompt: 'Password:', echo: false } ]);
process.nextTick(function() {
client.authInfoRes([ 'seekrit' ]);
});
}).on('USERAUTH_SUCCESS', function() {
assert.equal(expectedStages.shift(), 'CLIENT_SEES_USERAUTH_SUCCESS');
assert.equal(expectedStages.shift(), undefined);
next();
});
// Silly to submit all these auths at once, but allowed by RFC4252
client.authPK('bob', PARSED_CLIENT_PUB_KEY);
client.authPK('bob', PARSED_CLIENT_PUB_KEY, signWithClientKey);
client.authPassword('bob', 'seekrit');
client.authKeyboard('bob');
}
var tests = [
publickey,
keyboardInteractive,
// password // ssh2-streams can't generate a password change request
mixedMethods
];
function next() {
if (Array.isArray(process._events.exit))
process._events.exit = process._events.exit[1];
if (++t === tests.length)
return;
var v = tests[t];
makePair(v);
}
process.once('exit', function() {
assert(t === tests.length,
'Only finished ' + t + '/' + tests.length + ' tests');
});
next();