index.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. "use strict";
  2. var __extends = (this && this.__extends) || (function () {
  3. var extendStatics = function (d, b) {
  4. extendStatics = Object.setPrototypeOf ||
  5. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  6. function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
  7. return extendStatics(d, b);
  8. };
  9. return function (d, b) {
  10. if (typeof b !== "function" && b !== null)
  11. throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
  12. extendStatics(d, b);
  13. function __() { this.constructor = d; }
  14. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  15. };
  16. })();
  17. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  18. if (k2 === undefined) k2 = k;
  19. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  20. }) : (function(o, m, k, k2) {
  21. if (k2 === undefined) k2 = k;
  22. o[k2] = m[k];
  23. }));
  24. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  25. Object.defineProperty(o, "default", { enumerable: true, value: v });
  26. }) : function(o, v) {
  27. o["default"] = v;
  28. });
  29. var __importStar = (this && this.__importStar) || function (mod) {
  30. if (mod && mod.__esModule) return mod;
  31. var result = {};
  32. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  33. __setModuleDefault(result, mod);
  34. return result;
  35. };
  36. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  37. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  38. return new (P || (P = Promise))(function (resolve, reject) {
  39. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  40. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  41. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  42. step((generator = generator.apply(thisArg, _arguments || [])).next());
  43. });
  44. };
  45. var __generator = (this && this.__generator) || function (thisArg, body) {
  46. var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
  47. return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
  48. function verb(n) { return function (v) { return step([n, v]); }; }
  49. function step(op) {
  50. if (f) throw new TypeError("Generator is already executing.");
  51. while (_) try {
  52. if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
  53. if (y = 0, t) op = [op[0] & 2, t.value];
  54. switch (op[0]) {
  55. case 0: case 1: t = op; break;
  56. case 4: _.label++; return { value: op[1], done: false };
  57. case 5: _.label++; y = op[1]; op = [0]; continue;
  58. case 7: op = _.ops.pop(); _.trys.pop(); continue;
  59. default:
  60. if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
  61. if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
  62. if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
  63. if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
  64. if (t[2]) _.ops.pop();
  65. _.trys.pop(); continue;
  66. }
  67. op = body.call(thisArg, _);
  68. } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
  69. if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
  70. }
  71. };
  72. Object.defineProperty(exports, "__esModule", { value: true });
  73. exports.Client = exports.ScpClient = void 0;
  74. var events_1 = require("events");
  75. var fs_1 = require("fs");
  76. var path_1 = require("path");
  77. var ssh2_1 = require("ssh2");
  78. var constant_1 = require("./constant");
  79. var utils = __importStar(require("./utils"));
  80. var ScpClient = /** @class */ (function (_super) {
  81. __extends(ScpClient, _super);
  82. function ScpClient(options) {
  83. var _this = _super.call(this) || this;
  84. _this.sftpWrapper = null;
  85. _this.sshClient = null;
  86. _this.remotePathSep = path_1.posix.sep;
  87. _this.endCalled = false;
  88. _this.errorHandled = false;
  89. var ssh = new ssh2_1.Client();
  90. ssh.on('connect', function () {
  91. _this.emit('connect');
  92. });
  93. ssh.on('ready', function () {
  94. ssh.sftp(function (err, sftp) {
  95. if (err) {
  96. throw err;
  97. }
  98. // save for reuse
  99. _this.sftpWrapper = sftp;
  100. _this.emit('ready');
  101. });
  102. });
  103. ssh.on('error', function (err) {
  104. _this.emit('error', err);
  105. });
  106. ssh.on('end', function () {
  107. _this.emit('end');
  108. });
  109. ssh.on('close', function () {
  110. if (!_this.endCalled) {
  111. _this.sftpWrapper = null;
  112. }
  113. _this.emit('close');
  114. });
  115. ssh.on('keyboard-interactive', function (name, instructions, instructionsLang, prompts, finish) {
  116. _this.emit('keyboard-interactive', name, instructions, instructionsLang, prompts, finish);
  117. });
  118. ssh.on('change password', function (message, language, done) {
  119. _this.emit('change password', message, language, done);
  120. });
  121. ssh.on('tcp connection', function (details, accept, reject) {
  122. _this.emit('tcp connection', details, accept, reject);
  123. });
  124. ssh.connect(options);
  125. _this.sshClient = ssh;
  126. if (options.remoteOsType === 'win32') {
  127. _this.remotePathSep = path_1.win32.sep;
  128. }
  129. return _this;
  130. }
  131. ScpClient.prototype.uploadFile = function (localPath, remotePath) {
  132. return __awaiter(this, void 0, void 0, function () {
  133. var _this = this;
  134. return __generator(this, function (_a) {
  135. utils.haveConnection(this, 'uploadFile');
  136. return [2 /*return*/, new Promise(function (resolve, reject) {
  137. _this.sftpWrapper.fastPut(localPath, remotePath, function (err) {
  138. if (err) {
  139. reject(err);
  140. }
  141. else {
  142. resolve();
  143. }
  144. });
  145. })];
  146. });
  147. });
  148. };
  149. ScpClient.prototype.downloadFile = function (remotePath, localPath) {
  150. return __awaiter(this, void 0, void 0, function () {
  151. var _this = this;
  152. return __generator(this, function (_a) {
  153. utils.haveConnection(this, 'downloadFile');
  154. return [2 /*return*/, new Promise(function (resolve, reject) {
  155. _this.sftpWrapper.fastGet(remotePath, localPath, function (err) {
  156. if (err) {
  157. reject(err);
  158. }
  159. else {
  160. resolve();
  161. }
  162. });
  163. })];
  164. });
  165. });
  166. };
  167. ScpClient.prototype.emptyDir = function (dir) {
  168. return __awaiter(this, void 0, void 0, function () {
  169. var isExist, error_1;
  170. return __generator(this, function (_a) {
  171. switch (_a.label) {
  172. case 0:
  173. utils.haveConnection(this, 'uploadDir');
  174. _a.label = 1;
  175. case 1:
  176. _a.trys.push([1, 8, , 9]);
  177. return [4 /*yield*/, this.exists(dir)];
  178. case 2:
  179. isExist = _a.sent();
  180. if (!!isExist) return [3 /*break*/, 4];
  181. return [4 /*yield*/, this.mkdir(dir)];
  182. case 3:
  183. _a.sent();
  184. return [3 /*break*/, 7];
  185. case 4:
  186. if (!(isExist === 'd')) return [3 /*break*/, 7];
  187. return [4 /*yield*/, this.rmdir(dir)];
  188. case 5:
  189. _a.sent();
  190. return [4 /*yield*/, this.mkdir(dir)];
  191. case 6:
  192. _a.sent();
  193. _a.label = 7;
  194. case 7: return [3 /*break*/, 9];
  195. case 8:
  196. error_1 = _a.sent();
  197. throw error_1;
  198. case 9: return [2 /*return*/];
  199. }
  200. });
  201. });
  202. };
  203. ScpClient.prototype.uploadDir = function (src, dest) {
  204. return __awaiter(this, void 0, void 0, function () {
  205. var isExist, dirEntries, _i, dirEntries_1, e, newSrc, newDst, newSrc, newDst, error_2;
  206. return __generator(this, function (_a) {
  207. switch (_a.label) {
  208. case 0:
  209. utils.haveConnection(this, 'uploadDir');
  210. _a.label = 1;
  211. case 1:
  212. _a.trys.push([1, 11, , 12]);
  213. return [4 /*yield*/, this.exists(dest)];
  214. case 2:
  215. isExist = _a.sent();
  216. if (!!isExist) return [3 /*break*/, 4];
  217. return [4 /*yield*/, this.mkdir(dest)];
  218. case 3:
  219. _a.sent();
  220. _a.label = 4;
  221. case 4:
  222. dirEntries = fs_1.readdirSync(src, {
  223. encoding: 'utf8',
  224. withFileTypes: true,
  225. });
  226. _i = 0, dirEntries_1 = dirEntries;
  227. _a.label = 5;
  228. case 5:
  229. if (!(_i < dirEntries_1.length)) return [3 /*break*/, 10];
  230. e = dirEntries_1[_i];
  231. if (!e.isDirectory()) return [3 /*break*/, 7];
  232. newSrc = path_1.join(src, e.name);
  233. newDst = utils.joinRemote(this, dest, e.name);
  234. return [4 /*yield*/, this.uploadDir(newSrc, newDst)];
  235. case 6:
  236. _a.sent();
  237. return [3 /*break*/, 9];
  238. case 7:
  239. if (!e.isFile()) return [3 /*break*/, 9];
  240. newSrc = path_1.join(src, e.name);
  241. newDst = utils.joinRemote(this, dest, e.name);
  242. return [4 /*yield*/, this.uploadFile(newSrc, newDst)
  243. // this.client.emit('upload', {source: src, destination: dst})
  244. ];
  245. case 8:
  246. _a.sent();
  247. _a.label = 9;
  248. case 9:
  249. _i++;
  250. return [3 /*break*/, 5];
  251. case 10: return [3 /*break*/, 12];
  252. case 11:
  253. error_2 = _a.sent();
  254. throw error_2;
  255. case 12: return [2 /*return*/];
  256. }
  257. });
  258. });
  259. };
  260. ScpClient.prototype.downloadDir = function (remotePath, localPath) {
  261. return __awaiter(this, void 0, void 0, function () {
  262. var remoteInfo, localInfo, fileList, _i, fileList_1, f, newSrc, newDst, src, dst, err_1;
  263. return __generator(this, function (_a) {
  264. switch (_a.label) {
  265. case 0:
  266. utils.haveConnection(this, 'downloadDir');
  267. _a.label = 1;
  268. case 1:
  269. _a.trys.push([1, 12, , 13]);
  270. return [4 /*yield*/, utils.checkRemotePath(this, remotePath, constant_1.targetType.readDir)];
  271. case 2:
  272. remoteInfo = _a.sent();
  273. if (!remoteInfo.valid) {
  274. throw new Error(remoteInfo.msg);
  275. }
  276. if (!fs_1.existsSync(localPath)) {
  277. fs_1.mkdirSync(localPath);
  278. }
  279. return [4 /*yield*/, utils.checkLocalPath(localPath, constant_1.targetType.writeDir)];
  280. case 3:
  281. localInfo = _a.sent();
  282. if (localInfo.valid && !localInfo.type) {
  283. fs_1.mkdirSync(localInfo.path, { recursive: true });
  284. }
  285. if (!localInfo.valid) {
  286. throw new Error(localInfo.msg);
  287. }
  288. return [4 /*yield*/, this.list(remoteInfo.path)];
  289. case 4:
  290. fileList = _a.sent();
  291. _i = 0, fileList_1 = fileList;
  292. _a.label = 5;
  293. case 5:
  294. if (!(_i < fileList_1.length)) return [3 /*break*/, 11];
  295. f = fileList_1[_i];
  296. if (!(f.type === 'd')) return [3 /*break*/, 7];
  297. newSrc = remoteInfo.path + this.remotePathSep + f.name;
  298. newDst = path_1.join(localInfo.path, f.name);
  299. return [4 /*yield*/, this.downloadDir(newSrc, newDst)];
  300. case 6:
  301. _a.sent();
  302. return [3 /*break*/, 10];
  303. case 7:
  304. if (!(f.type === '-')) return [3 /*break*/, 9];
  305. src = remoteInfo.path + this.remotePathSep + f.name;
  306. dst = path_1.join(localInfo.path, f.name);
  307. return [4 /*yield*/, this.downloadFile(src, dst)];
  308. case 8:
  309. _a.sent();
  310. this.sshClient.emit('download', { source: src, destination: dst });
  311. return [3 /*break*/, 10];
  312. case 9:
  313. console.log("downloadDir: File ignored: " + f.name + " not regular file");
  314. _a.label = 10;
  315. case 10:
  316. _i++;
  317. return [3 /*break*/, 5];
  318. case 11: return [2 /*return*/, remoteInfo.path + " downloaded to " + localInfo.path];
  319. case 12:
  320. err_1 = _a.sent();
  321. throw new Error(err_1);
  322. case 13: return [2 /*return*/];
  323. }
  324. });
  325. });
  326. };
  327. ScpClient.prototype.stat = function (remotePath) {
  328. return __awaiter(this, void 0, void 0, function () {
  329. var _this = this;
  330. return __generator(this, function (_a) {
  331. utils.haveConnection(this, 'stat');
  332. return [2 /*return*/, new Promise(function (resolve, reject) {
  333. _this.sftpWrapper.stat(remotePath, function (err, stats) {
  334. if (err) {
  335. reject(err);
  336. }
  337. else {
  338. resolve(stats);
  339. }
  340. });
  341. })];
  342. });
  343. });
  344. };
  345. ScpClient.prototype.unlink = function (remotePath) {
  346. return __awaiter(this, void 0, void 0, function () {
  347. var _this = this;
  348. return __generator(this, function (_a) {
  349. utils.haveConnection(this, 'unlink');
  350. return [2 /*return*/, new Promise(function (resolve, reject) {
  351. _this.sftpWrapper.unlink(remotePath, function (err) {
  352. if (err) {
  353. reject(err);
  354. }
  355. else {
  356. resolve();
  357. }
  358. });
  359. })];
  360. });
  361. });
  362. };
  363. // _rmdir - only works with an empty directory
  364. ScpClient.prototype._rmdir = function (remotePath) {
  365. return __awaiter(this, void 0, void 0, function () {
  366. var _this = this;
  367. return __generator(this, function (_a) {
  368. return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
  369. return __generator(this, function (_a) {
  370. this.sftpWrapper.rmdir(remotePath, function (err) {
  371. if (err) {
  372. reject(err);
  373. }
  374. else {
  375. resolve();
  376. }
  377. });
  378. return [2 /*return*/];
  379. });
  380. }); })];
  381. });
  382. });
  383. };
  384. ScpClient.prototype.rmdir = function (remotePath) {
  385. return __awaiter(this, void 0, void 0, function () {
  386. var files, _i, files_1, file, fullFilename;
  387. return __generator(this, function (_a) {
  388. switch (_a.label) {
  389. case 0: return [4 /*yield*/, this.list(remotePath)];
  390. case 1:
  391. files = _a.sent();
  392. _i = 0, files_1 = files;
  393. _a.label = 2;
  394. case 2:
  395. if (!(_i < files_1.length)) return [3 /*break*/, 7];
  396. file = files_1[_i];
  397. fullFilename = utils.joinRemote(this, remotePath, file.name);
  398. if (!(file.type === 'd')) return [3 /*break*/, 4];
  399. return [4 /*yield*/, this.rmdir(fullFilename)];
  400. case 3:
  401. _a.sent();
  402. return [3 /*break*/, 6];
  403. case 4: return [4 /*yield*/, this.unlink(fullFilename)];
  404. case 5:
  405. _a.sent();
  406. _a.label = 6;
  407. case 6:
  408. _i++;
  409. return [3 /*break*/, 2];
  410. case 7: return [4 /*yield*/, this._rmdir(remotePath)];
  411. case 8:
  412. _a.sent();
  413. return [2 /*return*/];
  414. }
  415. });
  416. });
  417. };
  418. ScpClient.prototype.mkdir = function (remotePath) {
  419. return __awaiter(this, void 0, void 0, function () {
  420. var _this = this;
  421. return __generator(this, function (_a) {
  422. utils.haveConnection(this, 'mkdir');
  423. return [2 /*return*/, new Promise(function (resolve, reject) {
  424. _this.sftpWrapper.mkdir(remotePath, function (err) {
  425. if (err) {
  426. reject(err);
  427. }
  428. else {
  429. resolve();
  430. }
  431. });
  432. })];
  433. });
  434. });
  435. };
  436. ScpClient.prototype.exists = function (remotePath) {
  437. return __awaiter(this, void 0, void 0, function () {
  438. var stats, error_3;
  439. return __generator(this, function (_a) {
  440. switch (_a.label) {
  441. case 0:
  442. utils.haveConnection(this, 'exists');
  443. _a.label = 1;
  444. case 1:
  445. _a.trys.push([1, 3, , 4]);
  446. return [4 /*yield*/, this.stat(remotePath)];
  447. case 2:
  448. stats = _a.sent();
  449. if (stats.isDirectory()) {
  450. return [2 /*return*/, 'd'];
  451. }
  452. if (stats.isSymbolicLink()) {
  453. return [2 /*return*/, 'l'];
  454. }
  455. if (stats.isFile()) {
  456. return [2 /*return*/, '-'];
  457. }
  458. return [2 /*return*/, false];
  459. case 3:
  460. error_3 = _a.sent();
  461. return [2 /*return*/, false];
  462. case 4: return [2 /*return*/];
  463. }
  464. });
  465. });
  466. };
  467. ScpClient.prototype.close = function () {
  468. if (this.sftpWrapper) {
  469. this.sftpWrapper.end();
  470. this.sftpWrapper = null;
  471. }
  472. if (this.sshClient) {
  473. this.sshClient.end();
  474. this.sshClient = null;
  475. }
  476. this.endCalled = true;
  477. };
  478. ScpClient.prototype.list = function (remotePath, pattern) {
  479. if (pattern === void 0) { pattern = /.*/; }
  480. return __awaiter(this, void 0, void 0, function () {
  481. var _list, pathInfo, err_2;
  482. var _this = this;
  483. return __generator(this, function (_a) {
  484. switch (_a.label) {
  485. case 0:
  486. _list = function (aPath, filter) {
  487. return new Promise(function (resolve, reject) {
  488. var reg = /-/gi;
  489. _this.sftpWrapper.readdir(aPath, function (err, fileList) {
  490. if (err) {
  491. reject(err);
  492. }
  493. else {
  494. var newList = [];
  495. // reset file info
  496. if (fileList) {
  497. newList = fileList.map(function (item) {
  498. return {
  499. type: item.longname.substr(0, 1),
  500. name: item.filename,
  501. size: item.attrs.size,
  502. modifyTime: item.attrs.mtime * 1000,
  503. accessTime: item.attrs.atime * 1000,
  504. rights: {
  505. user: item.longname.substr(1, 3).replace(reg, ''),
  506. group: item.longname.substr(4, 3).replace(reg, ''),
  507. other: item.longname.substr(7, 3).replace(reg, '')
  508. },
  509. owner: item.attrs.uid,
  510. group: item.attrs.gid
  511. };
  512. });
  513. }
  514. // provide some compatibility for auxList
  515. var regex_1;
  516. if (filter instanceof RegExp) {
  517. regex_1 = filter;
  518. }
  519. else {
  520. var newPattern = filter.replace(/\*([^*])*?/gi, '.*');
  521. regex_1 = new RegExp(newPattern);
  522. }
  523. resolve(newList.filter(function (item) { return regex_1.test(item.name); }));
  524. }
  525. });
  526. });
  527. };
  528. _a.label = 1;
  529. case 1:
  530. _a.trys.push([1, 3, , 4]);
  531. utils.haveConnection(this, 'list');
  532. return [4 /*yield*/, utils.checkRemotePath(this, remotePath, constant_1.targetType.readDir)];
  533. case 2:
  534. pathInfo = _a.sent();
  535. if (!pathInfo.valid) {
  536. throw new Error('Remote path is invalid');
  537. }
  538. return [2 /*return*/, _list(pathInfo.path, pattern)];
  539. case 3:
  540. err_2 = _a.sent();
  541. throw new Error(err_2);
  542. case 4: return [2 /*return*/];
  543. }
  544. });
  545. });
  546. };
  547. ScpClient.prototype.realPath = function (remotePath) {
  548. var _this = this;
  549. return new Promise(function (resolve, reject) {
  550. var closeListener = utils.makeCloseListener(_this, reject, 'realPath');
  551. _this.sshClient.prependListener('close', closeListener);
  552. var errorListener = utils.makeErrorListener(reject, _this, 'realPath');
  553. _this.sshClient.prependListener('error', errorListener);
  554. if (utils.haveConnection(_this, 'realPath', reject)) {
  555. _this.sftpWrapper.realpath(remotePath, function (err, absPath) {
  556. if (err) {
  557. if (err.code === 2) {
  558. resolve('');
  559. }
  560. else {
  561. reject(utils.formatError(err.message + " " + remotePath, 'realPath', err.code));
  562. }
  563. }
  564. resolve(absPath);
  565. _this.removeListener('error', errorListener);
  566. _this.removeListener('close', closeListener);
  567. });
  568. }
  569. });
  570. };
  571. return ScpClient;
  572. }(events_1.EventEmitter));
  573. exports.ScpClient = ScpClient;
  574. function Client(options) {
  575. return __awaiter(this, void 0, void 0, function () {
  576. var client;
  577. return __generator(this, function (_a) {
  578. client = new ScpClient(options);
  579. return [2 /*return*/, new Promise(function (resolve, reject) {
  580. client.on('ready', function () {
  581. resolve(client);
  582. });
  583. client.on('error', function (err) {
  584. reject(err);
  585. });
  586. })];
  587. });
  588. });
  589. }
  590. exports.Client = Client;
  591. exports.default = Client;