Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. var Server = require('../lib/server');
  2. var utils = require('ssh2-streams').utils;
  3. var fs = require('fs');
  4. var path = require('path');
  5. var join = path.join;
  6. var assert = require('assert');
  7. var spawn = require('child_process').spawn;
  8. var exec = require('child_process').exec;
  9. var t = -1;
  10. var group = path.basename(__filename, '.js') + '/';
  11. var fixturesdir = join(__dirname, 'fixtures');
  12. var CLIENT_TIMEOUT = 5000;
  13. var USER = 'nodejs';
  14. var HOST_KEY_RSA = fs.readFileSync(join(fixturesdir, 'ssh_host_rsa_key'));
  15. var HOST_KEY_DSA = fs.readFileSync(join(fixturesdir, 'ssh_host_dsa_key'));
  16. var HOST_KEY_ECDSA = fs.readFileSync(join(fixturesdir, 'ssh_host_ecdsa_key'));
  17. var CLIENT_KEY_RSA_PATH = join(fixturesdir, 'id_rsa');
  18. var CLIENT_KEY_RSA_RAW = fs.readFileSync(CLIENT_KEY_RSA_PATH);
  19. var CLIENT_KEY_RSA = utils.parseKey(CLIENT_KEY_RSA_RAW);
  20. var CLIENT_KEY_DSA_PATH = join(fixturesdir, 'id_dsa');
  21. var CLIENT_KEY_DSA_RAW = fs.readFileSync(CLIENT_KEY_DSA_PATH);
  22. var CLIENT_KEY_DSA = utils.parseKey(CLIENT_KEY_DSA_RAW);
  23. var CLIENT_KEY_ECDSA_PATH = join(fixturesdir, 'id_ecdsa');
  24. var CLIENT_KEY_ECDSA_RAW = fs.readFileSync(CLIENT_KEY_ECDSA_PATH);
  25. var CLIENT_KEY_ECDSA = utils.parseKey(CLIENT_KEY_ECDSA_RAW);
  26. var opensshPath = 'ssh';
  27. var opensshVer;
  28. var DEBUG = false;
  29. // Fix file modes to avoid OpenSSH client complaints about keys' permissions
  30. fs.readdirSync(fixturesdir).forEach(function(file) {
  31. fs.chmodSync(join(fixturesdir, file), '0600');
  32. });
  33. var tests = [
  34. { run: function() {
  35. var what = this.what;
  36. var server;
  37. server = setup(
  38. this,
  39. { privateKeyPath: CLIENT_KEY_RSA_PATH },
  40. { hostKeys: [HOST_KEY_RSA] }
  41. );
  42. server.on('connection', function(conn) {
  43. conn.on('authentication', function(ctx) {
  44. if (ctx.method === 'none')
  45. return ctx.reject();
  46. assert(ctx.method === 'publickey',
  47. makeMsg(what, 'Unexpected auth method: ' + ctx.method));
  48. assert(ctx.username === USER,
  49. makeMsg(what, 'Unexpected username: ' + ctx.username));
  50. assert(ctx.key.algo === 'ssh-rsa',
  51. makeMsg(what, 'Unexpected key algo: ' + ctx.key.algo));
  52. assert.deepEqual(CLIENT_KEY_RSA.getPublicSSH(),
  53. ctx.key.data,
  54. makeMsg(what, 'Public key mismatch'));
  55. if (ctx.signature) {
  56. assert(CLIENT_KEY_RSA.verify(ctx.blob, ctx.signature) === true,
  57. makeMsg(what, 'Could not verify PK signature'));
  58. ctx.accept();
  59. } else
  60. ctx.accept();
  61. }).on('ready', function() {
  62. conn.on('session', function(accept, reject) {
  63. var session = accept();
  64. if (session) {
  65. session.on('exec', function(accept, reject) {
  66. var stream = accept();
  67. if (stream) {
  68. stream.exit(0);
  69. stream.end();
  70. }
  71. }).on('pty', function(accept, reject) {
  72. accept && accept();
  73. });
  74. }
  75. });
  76. });
  77. });
  78. },
  79. what: 'Authenticate with an RSA key'
  80. },
  81. { run: function() {
  82. var what = this.what;
  83. var server;
  84. server = setup(
  85. this,
  86. { privateKeyPath: CLIENT_KEY_DSA_PATH },
  87. { hostKeys: [HOST_KEY_RSA] }
  88. );
  89. server.on('connection', function(conn) {
  90. conn.on('authentication', function(ctx) {
  91. if (ctx.method === 'none')
  92. return ctx.reject();
  93. assert(ctx.method === 'publickey',
  94. makeMsg(what, 'Unexpected auth method: ' + ctx.method));
  95. assert(ctx.username === USER,
  96. makeMsg(what, 'Unexpected username: ' + ctx.username));
  97. assert(ctx.key.algo === 'ssh-dss',
  98. makeMsg(what, 'Unexpected key algo: ' + ctx.key.algo));
  99. assert.deepEqual(CLIENT_KEY_DSA.getPublicSSH(),
  100. ctx.key.data,
  101. makeMsg(what, 'Public key mismatch'));
  102. if (ctx.signature) {
  103. assert(CLIENT_KEY_DSA.verify(ctx.blob, ctx.signature) === true,
  104. makeMsg(what, 'Could not verify PK signature'));
  105. }
  106. ctx.accept();
  107. }).on('ready', function() {
  108. conn.on('session', function(accept, reject) {
  109. var session = accept();
  110. if (session) {
  111. session.on('exec', function(accept, reject) {
  112. var stream = accept();
  113. if (stream) {
  114. stream.exit(0);
  115. stream.end();
  116. }
  117. }).on('pty', function(accept, reject) {
  118. accept && accept();
  119. });
  120. }
  121. });
  122. });
  123. });
  124. },
  125. what: 'Authenticate with a DSA key'
  126. },
  127. { run: function() {
  128. var what = this.what;
  129. var server;
  130. server = setup(
  131. this,
  132. { privateKeyPath: CLIENT_KEY_ECDSA_PATH },
  133. { hostKeys: [HOST_KEY_RSA] }
  134. );
  135. server.on('connection', function(conn) {
  136. conn.on('authentication', function(ctx) {
  137. if (ctx.method === 'none')
  138. return ctx.reject();
  139. assert(ctx.method === 'publickey',
  140. makeMsg(what, 'Unexpected auth method: ' + ctx.method));
  141. assert(ctx.username === USER,
  142. makeMsg(what, 'Unexpected username: ' + ctx.username));
  143. assert(ctx.key.algo === 'ecdsa-sha2-nistp256',
  144. makeMsg(what, 'Unexpected key algo: ' + ctx.key.algo));
  145. assert.deepEqual(CLIENT_KEY_ECDSA.getPublicSSH(),
  146. ctx.key.data,
  147. makeMsg(what, 'Public key mismatch'));
  148. if (ctx.signature) {
  149. assert(CLIENT_KEY_ECDSA.verify(ctx.blob, ctx.signature) === true,
  150. makeMsg(what, 'Could not verify PK signature'));
  151. ctx.accept();
  152. } else
  153. ctx.accept();
  154. }).on('ready', function() {
  155. conn.on('session', function(accept, reject) {
  156. var session = accept();
  157. if (session) {
  158. session.on('exec', function(accept, reject) {
  159. var stream = accept();
  160. if (stream) {
  161. stream.exit(0);
  162. stream.end();
  163. }
  164. }).on('pty', function(accept, reject) {
  165. accept && accept();
  166. });
  167. }
  168. });
  169. });
  170. });
  171. },
  172. what: 'Authenticate with a ECDSA key'
  173. },
  174. { run: function() {
  175. var server;
  176. server = setup(
  177. this,
  178. { privateKeyPath: CLIENT_KEY_RSA_PATH },
  179. { hostKeys: [HOST_KEY_DSA] }
  180. );
  181. server.on('connection', function(conn) {
  182. conn.on('authentication', function(ctx) {
  183. ctx.accept();
  184. }).on('ready', function() {
  185. conn.on('session', function(accept, reject) {
  186. var session = accept();
  187. if (session) {
  188. session.on('exec', function(accept, reject) {
  189. var stream = accept();
  190. if (stream) {
  191. stream.exit(0);
  192. stream.end();
  193. }
  194. }).on('pty', function(accept, reject) {
  195. accept && accept();
  196. });
  197. }
  198. });
  199. });
  200. });
  201. },
  202. what: 'Server with DSA host key'
  203. },
  204. { run: function() {
  205. var server;
  206. server = setup(
  207. this,
  208. { privateKeyPath: CLIENT_KEY_RSA_PATH },
  209. { hostKeys: [HOST_KEY_ECDSA] }
  210. );
  211. server.on('connection', function(conn) {
  212. conn.on('authentication', function(ctx) {
  213. ctx.accept();
  214. }).on('ready', function() {
  215. conn.on('session', function(accept, reject) {
  216. var session = accept();
  217. if (session) {
  218. session.on('exec', function(accept, reject) {
  219. var stream = accept();
  220. if (stream) {
  221. stream.exit(0);
  222. stream.end();
  223. }
  224. }).on('pty', function(accept, reject) {
  225. accept && accept();
  226. });
  227. }
  228. });
  229. });
  230. });
  231. },
  232. what: 'Server with ECDSA host key'
  233. },
  234. { run: function() {
  235. var server;
  236. var what = this.what;
  237. server = setup(
  238. this,
  239. { privateKeyPath: CLIENT_KEY_RSA_PATH },
  240. { hostKeys: [HOST_KEY_RSA] }
  241. );
  242. server.on('_child', function(childProc) {
  243. childProc.stderr.once('data', function(data) {
  244. childProc.stdin.end();
  245. });
  246. childProc.stdin.write('ping');
  247. }).on('connection', function(conn) {
  248. conn.on('authentication', function(ctx) {
  249. ctx.accept();
  250. }).on('ready', function() {
  251. conn.on('session', function(accept, reject) {
  252. var session = accept();
  253. assert(session, makeMsg(what, 'Missing session'));
  254. session.on('exec', function(accept, reject) {
  255. var stream = accept();
  256. assert(stream, makeMsg(what, 'Missing exec stream'));
  257. stream.stdin.on('data', function(data) {
  258. stream.stdout.write('pong on stdout');
  259. stream.stderr.write('pong on stderr');
  260. }).on('end', function() {
  261. stream.stdout.write('pong on stdout');
  262. stream.stderr.write('pong on stderr');
  263. stream.exit(0);
  264. stream.close();
  265. });
  266. }).on('pty', function(accept, reject) {
  267. accept && accept();
  268. });
  269. });
  270. });
  271. });
  272. },
  273. what: 'Server closes stdin too early'
  274. },
  275. ];
  276. function setup(self, clientcfg, servercfg) {
  277. self.state = {
  278. serverReady: false,
  279. clientClose: false,
  280. serverClose: false
  281. };
  282. var client;
  283. var server = new Server(servercfg);
  284. server.on('error', onError)
  285. .on('connection', function(conn) {
  286. conn.on('error', onError)
  287. .on('ready', onReady);
  288. server.close();
  289. })
  290. .on('close', onClose);
  291. function onError(err) {
  292. var which = (arguments.length >= 3 ? 'client' : 'server');
  293. assert(false, makeMsg(self.what, 'Unexpected ' + which + ' error: ' + err));
  294. }
  295. function onReady() {
  296. assert(!self.state.serverReady,
  297. makeMsg(self.what, 'Received multiple ready events for server'));
  298. self.state.serverReady = true;
  299. self.onReady && self.onReady();
  300. }
  301. function onClose() {
  302. if (arguments.length >= 3) {
  303. assert(!self.state.clientClose,
  304. makeMsg(self.what, 'Received multiple close events for client'));
  305. self.state.clientClose = true;
  306. } else {
  307. assert(!self.state.serverClose,
  308. makeMsg(self.what, 'Received multiple close events for server'));
  309. self.state.serverClose = true;
  310. }
  311. if (self.state.clientClose && self.state.serverClose)
  312. next();
  313. }
  314. process.nextTick(function() {
  315. server.listen(0, 'localhost', function() {
  316. var cmd = opensshPath;
  317. var args = ['-o', 'UserKnownHostsFile=/dev/null',
  318. '-o', 'StrictHostKeyChecking=no',
  319. '-o', 'CheckHostIP=no',
  320. '-o', 'ConnectTimeout=3',
  321. '-o', 'GlobalKnownHostsFile=/dev/null',
  322. '-o', 'GSSAPIAuthentication=no',
  323. '-o', 'IdentitiesOnly=yes',
  324. '-o', 'BatchMode=yes',
  325. '-o', 'VerifyHostKeyDNS=no',
  326. '-vvvvvv',
  327. '-T',
  328. '-o', 'KbdInteractiveAuthentication=no',
  329. '-o', 'HostbasedAuthentication=no',
  330. '-o', 'PasswordAuthentication=no',
  331. '-o', 'PubkeyAuthentication=yes',
  332. '-o', 'PreferredAuthentications=publickey'];
  333. if (clientcfg.privateKeyPath)
  334. args.push('-o', 'IdentityFile=' + clientcfg.privateKeyPath);
  335. if (!/^[0-6]\./.test(opensshVer)) {
  336. // OpenSSH 7.0+ disables DSS/DSA host (and user) key support by
  337. // default, so we explicitly enable it here
  338. args.push('-o', 'HostKeyAlgorithms=+ssh-dss');
  339. args.push('-o', 'PubkeyAcceptedKeyTypes=+ssh-dss');
  340. }
  341. args.push('-p', server.address().port.toString(),
  342. '-l', USER,
  343. 'localhost',
  344. 'uptime');
  345. client = spawn(cmd, args);
  346. server.emit('_child', client);
  347. if (DEBUG) {
  348. client.stdout.pipe(process.stdout);
  349. client.stderr.pipe(process.stderr);
  350. } else {
  351. client.stdout.resume();
  352. client.stderr.resume();
  353. }
  354. client.on('error', function(err) {
  355. onError(err, null, null);
  356. }).on('exit', function(code) {
  357. clearTimeout(client.timer);
  358. if (code !== 0)
  359. return onError(new Error('Non-zero exit code ' + code), null, null);
  360. onClose(null, null, null);
  361. });
  362. client.timer = setTimeout(function() {
  363. assert(false, makeMsg(self.what, 'Client timeout'));
  364. }, CLIENT_TIMEOUT);
  365. });
  366. });
  367. return server;
  368. }
  369. function next() {
  370. if (Array.isArray(process._events.exit))
  371. process._events.exit = process._events.exit[1];
  372. if (++t === tests.length)
  373. return;
  374. var v = tests[t];
  375. v.run.call(v);
  376. }
  377. function makeMsg(what, msg) {
  378. return '[' + group + what + ']: ' + msg;
  379. }
  380. process.once('uncaughtException', function(err) {
  381. if (t > -1 && !/(?:^|\n)AssertionError: /i.test(''+err))
  382. console.log(makeMsg(tests[t].what, 'Unexpected Exception:'));
  383. throw err;
  384. });
  385. process.once('exit', function() {
  386. assert(t === tests.length,
  387. makeMsg('_exit',
  388. 'Only finished ' + t + '/' + tests.length + ' tests'));
  389. });
  390. // Get OpenSSH client version first
  391. exec(opensshPath + ' -V', function(err, stdout, stderr) {
  392. if (err) {
  393. console.log('OpenSSH client is required for these tests');
  394. process.exitCode = 5;
  395. return;
  396. }
  397. var re = /^OpenSSH_([\d\.]+)/;
  398. var m = re.exec(stdout.toString());
  399. if (!m || !m[1]) {
  400. m = re.exec(stderr.toString());
  401. if (!m || !m[1]) {
  402. console.log('OpenSSH client is required for these tests');
  403. process.exitCode = 5;
  404. return;
  405. }
  406. }
  407. opensshVer = m[1];
  408. next();
  409. });