ssh2-sftp-client 7.2.0 → 7.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,11 +61,11 @@ an SFTP client for node.js, a wrapper around [SSH2](https://github.com/mscdex/ss
61
61
 
62
62
  Documentation on the methods and available options in the underlying modules can be found on the [SSH2](https://github.com/mscdex/ssh2) project pages.
63
63
 
64
- Current stable release is **v7.2.0**.
64
+ Current stable release is **v7.2.3**.
65
65
 
66
- Code has been tested against Node versions 14.18.2, 16.13.1 and 17.2.0
66
+ Code has been tested against Node versions 14.19.1, 16.14.2 and 17.8.0
67
67
 
68
- Node versions < 10.x are not supported.
68
+ Node versions < 12.x are not supported. However, node v10.x should still work, although some tests will fail due to changes in file system functions used in test setup and tear down.
69
69
 
70
70
  # Installation<a id="sec-2"></a>
71
71
 
@@ -103,6 +103,8 @@ sftp.connect({
103
103
 
104
104
  - Improved event handling. A listener for a global error event is now defined to catch errors which occur in-between method calls i.e. connection lost in-between calls to the library methods. A new mechanism has also been added for removal of listeners when no longer required.
105
105
 
106
+ - uploadDir/downloadDir change in 7.2.3. THe uploadDir() and downloadDir() methods previously used fastPut() and fastGet() to transfer data. Unfortunately, not all SFTP servers support the concurrent processing used by these methods. This meant these methods would fail on some platforms. For now, the fastPut() and fastGet() calls have been replaced with plain put() and get() calls. This will mean uploadDir()/downloadDir() will be slower. However, there is other larger changes in the works which should see a significant speed imp[rovement for these (and other methods). We may also add an option which will allow for selection of fastPut()/fastGet().
107
+
106
108
  # Documentation<a id="sec-5"></a>
107
109
 
108
110
  The connection options are the same as those offered by the underlying SSH2 module. For full details, please see [SSH2 client methods](https://github.com/mscdex/ssh2#user-content-client-methods)
@@ -392,7 +394,7 @@ Returns the attributes associated with the object pointed to by `path`.
392
394
 
393
395
  Retrieve a file from a remote SFTP server. The `dst` argument defines the destination and can be either a string, a stream object or undefined. If it is a string, it is interpreted as the path to a location on the local file system (path should include the file name). If it is a stream object, the remote data is passed to it via a call to pipe(). If `dst` is undefined, the method will put the data into a buffer and return that buffer when the Promise is resolved. If `dst` is defined, it is returned when the Promise is resolved.
394
396
 
395
- In general, if your going to pass in a string as the destination, you are better off using the `fastGet()` method.
397
+ In general, if you're going to pass in a string as the destination, you are better off using the `fastGet()` method.
396
398
 
397
399
  - **path:** String. Path to the remote file to download
398
400
  - **dst:** String|Stream. Destination for the data. If a string, it should be a local file path.
@@ -1332,7 +1334,7 @@ Perhaps the best assistance is a minimal reproducible example of the issue. Once
1332
1334
 
1333
1335
  # Pull Requests<a id="sec-11"></a>
1334
1336
 
1335
- Pull requests are always welcomed. However, please ensure your changes pass all tests and if your adding a new feature, that tests for that feature are included. Likewise, for new features or enhancements, please include any relevant documentation updates.
1337
+ Pull requests are always welcomed. However, please ensure your changes pass all tests and if you're adding a new feature, that tests for that feature are included. Likewise, for new features or enhancements, please include any relevant documentation updates.
1336
1338
 
1337
1339
  **Note**: The `README.md` file is generated from the `README.org` file. Therefore, any documentation updates or fixes need to be made to the `README.org` file. This file is *tangled* using `Emacs` org mode. If you don't use Emacs or org-mode, don't be too concerned. The org-mode syntax is straight-forward and similar to *markdown*. I will verify any updates to `README.org` and generate a new `README.md` when necessary. The main point to note is that any changes made directly to `README.md` will not persist and will be lost when a new version is generated, so don't modify that file.
1338
1340
 
@@ -1361,3 +1363,4 @@ Thanks to the following for their contributions -
1361
1363
  - **Emma Milner:** Contributed fix for put() bug
1362
1364
  - **Witni Davis:** Contributed PR to fix put() RCE when using 'finish' rather than 'close' to resolve promise
1363
1365
  - **Maik Marschner:** Contributed fix for connect() not returning sftp object. Also included test to check for this regression in future.
1366
+ - **cakemasher:** Contributed fix for removeTempListeners().
package/README.org CHANGED
@@ -9,11 +9,13 @@ convenience abstraction as well as a Promise based API.
9
9
  Documentation on the methods and available options in the underlying modules can
10
10
  be found on the [[https://github.com/mscdex/ssh2][SSH2]] project pages.
11
11
 
12
- Current stable release is *v7.2.0*.
12
+ Current stable release is *v7.2.3*.
13
13
 
14
- Code has been tested against Node versions 14.18.2, 16.13.1 and 17.2.0
14
+ Code has been tested against Node versions 14.19.1, 16.14.2 and 17.8.0
15
15
 
16
- Node versions < 10.x are not supported.
16
+ Node versions < 12.x are not supported. However, node v10.x should still work,
17
+ although some tests will fail due to changes in file system functions used in
18
+ test setup and tear down.
17
19
 
18
20
  * Installation
19
21
 
@@ -75,6 +77,16 @@ npm install ssh2-sftp-client
75
77
  in-between calls to the library methods. A new mechanism has also been added
76
78
  for removal of listeners when no longer required.
77
79
 
80
+ - uploadDir/downloadDir change in 7.2.3. THe uploadDir() and downloadDir()
81
+ methods previously used fastPut() and fastGet() to transfer data.
82
+ Unfortunately, not all SFTP servers support the concurrent processing used by
83
+ these methods. This meant these methods would fail on some platforms. For now,
84
+ the fastPut() and fastGet() calls have been replaced with plain put() and
85
+ get() calls. This will mean uploadDir()/downloadDir() will be slower. However,
86
+ there is other larger changes in the works which should see a significant
87
+ speed imp[rovement for these (and other methods). We may also add an option
88
+ which will allow for selection of fastPut()/fastGet().
89
+
78
90
  * Documentation
79
91
 
80
92
  The connection options are the same as those offered by the underlying SSH2
@@ -422,7 +434,7 @@ is passed to it via a call to pipe(). If ~dst~ is undefined, the method will put
422
434
  the data into a buffer and return that buffer when the Promise is resolved. If
423
435
  ~dst~ is defined, it is returned when the Promise is resolved.
424
436
 
425
- In general, if your going to pass in a string as the destination, you are
437
+ In general, if you're going to pass in a string as the destination, you are
426
438
  better off using the ~fastGet()~ method.
427
439
 
428
440
  - path :: String. Path to the remote file to download
@@ -1732,10 +1744,10 @@ the issue. Things which will help
1732
1744
  Perhaps the best assistance is a minimal reproducible example of the issue. Once
1733
1745
  the issue can be readily reproduced, it can usually be fixed very quickly.
1734
1746
 
1735
- * Pull Requests
1747
+ * Pull Requests
1736
1748
 
1737
1749
  Pull requests are always welcomed. However, please ensure your changes pass all
1738
- tests and if your adding a new feature, that tests for that feature are
1750
+ tests and if you're adding a new feature, that tests for that feature are
1739
1751
  included. Likewise, for new features or enhancements, please include any
1740
1752
  relevant documentation updates.
1741
1753
 
@@ -1784,3 +1796,5 @@ Thanks to the following for their contributions -
1784
1796
  'close' to resolve promise
1785
1797
  - Maik Marschner :: Contributed fix for connect() not returning sftp object.
1786
1798
  Also included test to check for this regression in future.
1799
+ - cakemasher :: Contributed fix for removeTempListeners().
1800
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssh2-sftp-client",
3
- "version": "7.2.0",
3
+ "version": "7.2.3",
4
4
  "description": "ssh2 sftp client for node",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -25,28 +25,28 @@
25
25
  }
26
26
  ],
27
27
  "license": "Apache-2.0",
28
- "dependencies": {
29
- "concat-stream": "^2.0.0",
30
- "promise-retry": "^2.0.1",
31
- "ssh2": "^1.5.0"
32
- },
33
28
  "devDependencies": {
34
- "chai": "^4.3.4",
29
+ "chai": "^4.3.6",
35
30
  "chai-as-promised": "^7.1.1",
36
31
  "chai-subset": "^1.6.0",
37
32
  "checksum": "^1.0.0",
38
- "dotenv": "^10.0.0",
39
- "eslint": "^8.3.0",
40
- "eslint-config-prettier": "^8.3.0",
41
- "eslint-plugin-mocha": "^9.0.0",
33
+ "dotenv": "^16.0.0",
34
+ "eslint": "^8.12.0",
35
+ "eslint-config-prettier": "^8.5.0",
36
+ "eslint-plugin-mocha": "^10.0.3",
42
37
  "eslint-plugin-node": "^11.1.0",
43
- "eslint-plugin-promise": "^5.2.0",
44
- "eslint-plugin-unicorn": "^39.0.0",
45
- "mocha": "^9.1.2",
38
+ "eslint-plugin-promise": "^6.0.0",
39
+ "eslint-plugin-unicorn": "^41.0.1",
40
+ "mocha": "^9.2.2",
46
41
  "moment": "^2.29.1",
47
42
  "nyc": "^15.1.0",
48
- "prettier": "^2.5.0",
43
+ "prettier": "^2.6.1",
49
44
  "through2": "^4.0.2",
50
- "winston": "^3.3.3"
45
+ "winston": "^3.6.0"
46
+ },
47
+ "dependencies": {
48
+ "concat-stream": "^2.0.0",
49
+ "promise-retry": "^2.0.1",
50
+ "ssh2": "^1.8.0"
51
51
  }
52
52
  }
package/src/index.js CHANGED
@@ -59,7 +59,7 @@ class SftpClient {
59
59
  this.client.on('error', (err) => {
60
60
  if (this.endCalled || this.errorHandled) {
61
61
  // error event expected or handled elsewhere
62
- this.debugMsg('Global: Ignoring handled error');
62
+ this.debugMsg(`Global: Ignoring handled error: ${err.message}`);
63
63
  } else {
64
64
  this.debugMsg(`Global; Handling unexpected error; ${err.message}`);
65
65
  this.sftp = undefined;
@@ -120,28 +120,24 @@ class SftpClient {
120
120
  */
121
121
  getConnection(config) {
122
122
  let doReady;
123
- return (
124
- new Promise((resolve, reject) => {
125
- addTempListeners(this, 'getConnection', reject);
126
- this.debugMsg('getConnection: created promise');
127
- doReady = () => {
128
- this.debugMsg('getConnection: got connection - promise resolved');
129
- resolve(true);
130
- };
131
- this.on('ready', doReady);
132
- this.client.connect(config);
133
- })
134
- // .catch((err) => {
135
- // return Promise.reject(err);
136
- // })
137
- .finally(async () => {
138
- this.debugMsg('getConnection: finally clause fired');
139
- await sleep(500);
140
- this.removeListener('ready', doReady);
141
- removeTempListeners(this, 'getConnection');
142
- this._resetEventFlags();
143
- })
144
- );
123
+ return new Promise((resolve, reject) => {
124
+ addTempListeners(this, 'getConnection', reject);
125
+ this.debugMsg('getConnection: created promise');
126
+ doReady = () => {
127
+ this.debugMsg(
128
+ 'getConnection ready listener: got connection - promise resolved'
129
+ );
130
+ resolve(true);
131
+ };
132
+ this.on('ready', doReady);
133
+ this.client.connect(config);
134
+ }).finally(async () => {
135
+ this.debugMsg('getConnection: finally clause fired');
136
+ await sleep(500);
137
+ this.removeListener('ready', doReady);
138
+ removeTempListeners(this, 'getConnection');
139
+ this._resetEventFlags();
140
+ });
145
141
  }
146
142
 
147
143
  getSftpChannel() {
@@ -196,8 +192,17 @@ class SftpClient {
196
192
  (retry, attempt) => {
197
193
  this.debugMsg(`connect: Connect attempt ${attempt}`);
198
194
  return this.getConnection(config).catch((err) => {
199
- this.debugMsg('getConnection retry catch');
200
- retry(err);
195
+ this.debugMsg(
196
+ `getConnection retry catch: ${err.message} Code: ${err.code}`
197
+ );
198
+ switch (err.code) {
199
+ case 'ENOTFOUND':
200
+ case 'ECONNREFUSED':
201
+ case 'ERR_SOCKET_BAD_PORT':
202
+ throw err;
203
+ default:
204
+ retry(err);
205
+ }
201
206
  });
202
207
  },
203
208
  {
@@ -515,13 +520,29 @@ class SftpClient {
515
520
  )
516
521
  );
517
522
  });
518
- rdr.once('end', () => {
519
- if (typeof dst === 'string') {
520
- resolve(dst);
521
- } else {
522
- resolve(wtr);
523
- }
524
- });
523
+ if (
524
+ Object.hasOwnProperty.call(options, 'pipeOptions') &&
525
+ Object.hasOwnProperty.call(options.pipeOptions, 'end') &&
526
+ !options.pipeOptions.end
527
+ ) {
528
+ rdr.once('end', () => {
529
+ this.debugMsg('get resolved on reader end event');
530
+ if (typeof dst === 'string') {
531
+ resolve(dst);
532
+ } else {
533
+ resolve(wtr);
534
+ }
535
+ });
536
+ } else {
537
+ wtr.once('finish', () => {
538
+ this.debugMsg('get resolved on writer finish event');
539
+ if (typeof dst === 'string') {
540
+ resolve(dst);
541
+ } else {
542
+ resolve(wtr);
543
+ }
544
+ });
545
+ }
525
546
  }
526
547
  rdr.pipe(wtr, options.pipeOptions ? options.pipeOptions : {});
527
548
  }
@@ -530,14 +551,16 @@ class SftpClient {
530
551
  this._resetEventFlags();
531
552
  if (
532
553
  rdr &&
533
- options.readStreamOptions &&
554
+ Object.hasOwnProperty.call(options, 'readStreamOptions') &&
555
+ Object.hasOwnProperty.call(options.readStreamOptions, 'autoClose') &&
534
556
  options.readStreamOptions.autoClose === false
535
557
  ) {
536
558
  rdr.destroy();
537
559
  }
538
560
  if (
539
561
  wtr &&
540
- options.writeStreamOptions &&
562
+ Object.hasOwnProperty.call(options, 'writeStreamOptions') &&
563
+ Object.hasOwnProperty.call(options.writeStreamOptions, 'autoClose') &&
541
564
  options.writeStreamOptions.autoClose === false &&
542
565
  typeof dst === 'string'
543
566
  ) {
@@ -747,7 +770,8 @@ class SftpClient {
747
770
  this._resetEventFlags();
748
771
  if (
749
772
  rdr &&
750
- options.readStreamOptions &&
773
+ Object.hasOwnProperty.call(options, 'readStreamOptions') &&
774
+ Object.hasOwnProperty.call(options.readStreamOptions, 'autoClose') &&
751
775
  options.readStreamOptions.autoClose === false &&
752
776
  typeof localSrc === 'string'
753
777
  ) {
@@ -1110,7 +1134,7 @@ class SftpClient {
1110
1134
  } else if (e.isFile()) {
1111
1135
  let src = join(srcDir, e.name);
1112
1136
  let dst = dstDir + this.remotePathSep + e.name;
1113
- await this.fastPut(src, dst);
1137
+ await this.put(src, dst);
1114
1138
  this.client.emit('upload', { source: src, destination: dst });
1115
1139
  } else {
1116
1140
  this.debugMsg(
@@ -1166,7 +1190,7 @@ class SftpClient {
1166
1190
  } else if (f.type === '-') {
1167
1191
  let src = srcDir + this.remotePathSep + f.name;
1168
1192
  let dst = join(dstDir, f.name);
1169
- await this.fastGet(src, dst);
1193
+ await this.get(src, dst);
1170
1194
  this.client.emit('download', { source: src, destination: dst });
1171
1195
  } else {
1172
1196
  this.debugMsg(
package/src/utils.js CHANGED
@@ -76,15 +76,15 @@ function addToTempListenerList(obj, name, evt, fn) {
76
76
  function errorListener(client, name, reject) {
77
77
  let fn = (err) => {
78
78
  if (client.endCalled || client.errorHandled) {
79
- client.debugMsg(`${name}: Ignoring handled error: ${err.message}`);
79
+ client.debugMsg(`${name} Error: Ignoring handled error: ${err.message}`);
80
80
  } else {
81
- client.debugMsg(`${name}: Handling error: ${err.message}`);
81
+ client.debugMsg(`${name} Error: Handling error: ${err.message}`);
82
82
  client.errorHandled = true;
83
83
  if (reject) {
84
- client.debugMsg(`${name}: handled error with reject`);
84
+ client.debugMsg(`${name} Error: handled error with reject`);
85
85
  reject(fmtError(err, name, err.code));
86
86
  } else {
87
- client.debugMsg(`${name}: handling error with throw`);
87
+ client.debugMsg(`${name} Error: handling error with throw`);
88
88
  throw fmtError(err, name, err.code);
89
89
  }
90
90
  }
@@ -96,16 +96,16 @@ function errorListener(client, name, reject) {
96
96
  function endListener(client, name, reject) {
97
97
  let fn = function () {
98
98
  if (client.endCalled || client.endHandled) {
99
- client.debugMsg(`${name}: Ignoring expected end event`);
99
+ client.debugMsg(`${name} End: Ignoring expected end event`);
100
100
  } else {
101
- client.debugMsg(`${name}: Handling end event`);
101
+ client.debugMsg(`${name} End: Handling end event`);
102
102
  client.sftp = undefined;
103
103
  client.endHandled = true;
104
104
  if (reject) {
105
- client.debugMsg(`${name}: handling end event with reject'`);
105
+ client.debugMsg(`${name} End: handling end event with reject'`);
106
106
  reject(fmtError('Unexpected end event raised', name));
107
107
  } else {
108
- client.debugMsg(`${name}: handling end event with throw`);
108
+ client.debugMsg(`${name} End: handling end event with throw`);
109
109
  throw fmtError('Unexpected end event raised', name);
110
110
  }
111
111
  }
@@ -117,16 +117,16 @@ function endListener(client, name, reject) {
117
117
  function closeListener(client, name, reject) {
118
118
  let fn = function () {
119
119
  if (client.endCalled || client.closeHandled) {
120
- client.debugMsg(`${name}: ignoring expected close event`);
120
+ client.debugMsg(`${name} Close: ignoring expected close event`);
121
121
  } else {
122
- client.debugMsg(`${name}: handling unexpected close event`);
122
+ client.debugMsg(`${name} Close: handling unexpected close event`);
123
123
  client.sftp = undefined;
124
124
  client.closeHandled = true;
125
125
  if (reject) {
126
- client.debugMsg(`${name}: handling close event with reject`);
126
+ client.debugMsg(`${name} Close: handling close event with reject`);
127
127
  reject(fmtError('Unexpected close event raised', name));
128
128
  } else {
129
- client.debugMsg(`${name}: handling close event with throw`);
129
+ client.debugMsg(`${name} Close: handling close event with throw`);
130
130
  throw fmtError('Unexpected close event raised', name);
131
131
  }
132
132
  }
@@ -148,7 +148,7 @@ function removeTempListeners(obj, name) {
148
148
  obj.tempListeners[name].forEach(([e, fn]) => {
149
149
  obj.client.removeListener(e, fn);
150
150
  });
151
- obj.tempListeners = [];
151
+ obj.tempListeners[name] = [];
152
152
  }
153
153
  }
154
154