ssh2-sftp-client 9.0.4 → 10.0.0

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.
Files changed (5) hide show
  1. package/README.md +447 -370
  2. package/README.org +108 -106
  3. package/package.json +10 -10
  4. package/src/index.js +659 -587
  5. package/src/utils.js +78 -56
package/README.org CHANGED
@@ -7,83 +7,34 @@ an SFTP client for node.js, a wrapper around [[https://github.com/mscdex/ssh2][S
7
7
  convenience abstraction as well as a Promise based API.
8
8
 
9
9
  Documentation on the methods and available options in the underlying modules can
10
- be found on the [[https://github.com/mscdex/ssh2][SSH2]] project pages.
11
-
12
- Current stable release is *v9.0.4*.
13
-
14
- Code has been tested against Node versions 14.20.0, 16.17.2 and 18.8.0
15
-
16
- Node versions < 14.x are not supported.
17
-
18
- ** Version 9.x Changes
19
- - Fix bug in ~connect()~ method when private key data was corrupted. The method was not
20
- handling errors fro corrupted ssh private keys and would hang indefinitely without
21
- reporting any error. Now reports that it was unable to parse the private key.
22
- - Fix bug in ~end()~ method where it was possible for the module to attempt calling
23
- the underlying ssh2 ~end()~ method when ssh2 has not been initialised. This could
24
- lead to undefined reference errors.
25
- - Fix bug in ~get()~ method where supplied destination streams were not close, creating
26
- a possible resource leak. If the remote file did not exist, the method would return
27
- an error, but failed to close any passed in stream supplied as the destination for
28
- the data in the ~get()~ call.
29
- - Change the default end and close handlers not to throw error or reject
30
- promises. Previously, an end or close event would cause an error to be raised or a
31
- promise to be rejected if the event was deemed to be /unexpected/. However,
32
- classification of events as being unexpected was unreliable and didn't add much real
33
- value. Both these handlers will now invalidate the SFTP connection object and log that
34
- the event fired and nothing else.
35
- - Changed when event handled flags are reset. Now they are reset after a new set of
36
- temporary listeners are added.
37
- - Don't throw an error when calling end() if there is no active SFTP connection. It does
38
- no harm to call end() when there is no connection, so no need to raise an error.
39
- - Use nullish coalescing when setting retry parameters instead of or'ing with
40
- defaults. Allows setting values to 0.
41
- - *Breaking Change*: This version uses syntax not supported in node versions
42
- prior to v14. Therefore, node versions less than v14 will not work.
43
- - *Breaking Change*: This ~list()~ method no longer accepts a regular expression
44
- for filtering the entries to be returned. You can now specify a filter
45
- function instead. The function is called for each item in the list of items
46
- to be returned, passing in the item object as its only argument.
47
- Essentially, this is just a call to ~Array.filter()~, so the filter function
48
- should behave in the same way i.e. return true for items to be retained and
49
- false for those to be dropped.
50
- - *Breaking Change*: The ability to set ~autoClose~ on read and write streams and
51
- the ability to set ~end~ on ~pipe~ operations has been removed. These options
52
- caused confusion for users and were too easy to get wrong, plus it made the
53
- methods overly complicated. For those use-cases where you want to control
54
- streams at a low level, two new methods have been added, ~createReadStream()~ and
55
- ~createWriteStream()~. However, it should be noted that client code is 100%
56
- responsible for managing streams obtained using these methods. Use at your
57
- own risk!
58
- - *Breaking Change*: The 3rd argument to ~uploadDir()~ and ~downloadDir()~ methods
59
- has been change. Previously, the argument was a filter function used to
60
- select which directories and files to be transferred. The 3rd argument is
61
- now an options object with two supported properties, ~filter~ and ~useFastput~
62
- (for ~uploadDir()~) or ~useFastget~ (for ~downloadDir()~). If ~useFastput~ is true,
63
- the ~fastPut()~ method will be used to upload files. If ~false~ or missing, the
64
- slower, but better supported, ~put()~ method will be used. Likewise, the
65
- ~useFastget~ options can be set to ~true~ to use the ~fastGet()~ method for
66
- downloading files, otherwise the slower, but more reliable, ~get()~ method
67
- will be used.
68
- - The ~uploadDir()~ and ~downloadDir()~ methods now use asynchronous processes to
69
- upload/download files. This should result in improved performance for these
70
- two methods.
71
- - New Methods: Two new methods, ~createWriteStream()~ and ~createReadStream()~
72
- have been added. These methods will return a stream object connected to a
73
- remote file on the ~SFTP~ server. Client code is responsible for managing
74
- these stream objects. This includes adding any necessary event listeners and
75
- disposing of the objects once finished with them.
76
- - Re-factoring of Listeners: The library manages temporary listeners in order
77
- to provide a way to catch events and processes them inside a ~Promise~
78
- context. Previously, every method added its own set of temporary listeners.
79
- However, this could result in multiple sets of listeners being added,
80
- especially for methods which call other methods as part of their processing
81
- e.g. ~rmdir(),~ ~uploadDir()~ and ~dowqnloadDir()~. To avoid this, /internal only/
82
- versions of each method have been created. These internal methods use an
83
- /underscore/ ~_~ prefix. Client code should not use these methods directly.
84
- - New method: Added ~rcopy()~ method to perform a remote copy of a file on the remote SFTP server.
85
- - Bumped ssh2 version to 1.11.0
10
+ be found on the [[https://github.com/mscdex/ssh2][SSH2]] project pages. As this module is really just a wrapper around the
11
+ ~ssh2~ module, you will find lots of useful information, tips and examples in the ~ssh2~
12
+ repository.
86
13
 
14
+ Current stable release is *v10.0.0.
15
+
16
+ Code has been tested against Node versions 16.20.2, 18.18.2, 20.10.0 and 21.5.0. However,
17
+ only versions from v18 are actively supported. It should also be noted that a significant
18
+ performance improvement has been observed with versions >= 18. Version v16 is
19
+ significantly slower.
20
+
21
+ Node versions < 16.x are not supported.
22
+
23
+ ** Version 10.0.0 Changes
24
+
25
+ - The main change in this version is adding of limits on the number of promises which can
26
+ be active at the same time. Version 9.1.0 extended the use of multiple promises to
27
+ improve performance with downloadDir() and uploadDir(). However, for directories with
28
+ really large numbers of files, this often resulted in an error because the methods would
29
+ try to create more concurrent promises than was possible given available resources. This
30
+ issue has been fixed by adding a new property called ~promiseLimit~, which is limited to
31
+ 10 by default. A new configuration property, ~promiseLimit~, is now available for setting
32
+ the maximum number of concurrent promises the downloadDir()/uploadDir() methods will
33
+ create when downloading or uploading directory trees.
34
+
35
+ - Various minor documentation fixes and some minor fixes for typos in option property
36
+ names.
37
+
87
38
  * Installation
88
39
 
89
40
  #+begin_src shell
@@ -92,7 +43,7 @@ Node versions < 14.x are not supported.
92
43
 
93
44
  * Basic Usage
94
45
 
95
- #+begin_src javascript
46
+ #+begin_src js
96
47
  let Client = require('ssh2-sftp-client');
97
48
  let sftp = new Client();
98
49
 
@@ -113,10 +64,20 @@ Node versions < 14.x are not supported.
113
64
  * Documentation
114
65
 
115
66
  The connection options are the same as those offered by the underlying SSH2
116
- module. For full details, please see [[https://github.com/mscdex/ssh2#user-content-client-methods][SSH2 client methods]]
67
+ module, with just a couple of additional properties added to tweak the ~retry~ parameters,
68
+ add a ~debug~ function and set the ~promiseLimit~ property. For full details on the other
69
+ properties, please see [[https://github.com/mscdex/ssh2#user-content-client-methods][SSH2 client methods]]. In particular, see the ~ssh2~ documentation for
70
+ details relating to setting various key exchange and encryption/signing algorithms used as
71
+ part of the ssh2 protocol.
117
72
 
118
- All the methods will return a Promise, except for ~on()~ and
119
- ~removeListener()~, which are typically only used in special use cases.
73
+ All the methods will return a Promise, except for ~on(), ~removeListener()~, ~createReadStream~
74
+ and ~createWriteStream~, which are typically only used in special use cases.
75
+
76
+ Note that I don't use Typescript and I don't maintain any typescript definition
77
+ files. There are some typescript type definition files for this module, but they are
78
+ maintained separately and have nothing to do with this project. Therefore, please do not
79
+ log any issues arising from the use of these definition files with this project. Instead,
80
+ refer your issues to the maintainers of those modules.
120
81
 
121
82
  ** Specifying Paths
122
83
 
@@ -177,7 +138,7 @@ All the methods will return a Promise, except for ~on()~ and
177
138
 
178
139
  This will copy the local file ~test.txt~ to the remote file ~test-copy.txt~
179
140
  in the directory ~/remote/dir~.
180
-
141
+
181
142
  ** Methods
182
143
 
183
144
  *** new SftpClient(name) ===> SFTP client object
@@ -236,6 +197,19 @@ SSH2 module. These are part of the configuration for the [[https://www.npmjs.com
236
197
  is used to enable retrying of sftp connection attempts. See the documentation
237
198
  for that package for an explanation of these values.
238
199
 
200
+ The ~promiseLimit~ is another option which is not part of the ~ssh2~ module and is specific to
201
+ ~ssh2-sftp-client~. It is a property used to limit the maximum number of concurrent promises
202
+ possible when either downloading or uploading a directory tree using the ~downloadDir()~ or
203
+ ~uploadDir()~ methods. The default setting for this property is 10. *NOTE*: bigger doe snot
204
+ mean better. Many factors can affect what is the ideal setting for ~promiseLimit~. If it is
205
+ too large, any benefits are lost while node spends time switching contexts and/or withi
206
+ the overheads associated with creating and cleaning up promises. Lots of factors can
207
+ affect what the setting should be, including size of files, number of files, speed of
208
+ network, version of node, capabilities of remote sftp server etc. A setting of 10 seems to
209
+ be a reasonably good default and should be adequate for most use cases. However, if you
210
+ feel it needs to be changed, I highly recommend that you benchmark different values to
211
+ work out what is the best maximum size before you begin to see a performance drop off.
212
+
239
213
  #+begin_src javascript
240
214
  // common options
241
215
 
@@ -250,12 +224,13 @@ for that package for an explanation of these values.
250
224
  privateKey: fs.readFileSync('/path/to/key'), // Buffer or string that contains
251
225
  passphrase: 'a pass phrase', // string - For an encrypted private key
252
226
  readyTimeout: 20000, // integer How long (in ms) to wait for the SSH handshake
253
- strictVendor: true // boolean - Performs a strict server vendor check
254
- debug: myDebug // function - Set this to a function that receives a single
227
+ strictVendor: true, // boolean - Performs a strict server vendor check
228
+ debug: myDebug,// function - Set this to a function that receives a single
255
229
  // string argument to get detailed (local) debug information.
256
- retries: 2 // integer. Number of times to retry connecting
257
- retry_factor: 2 // integer. Time factor used to calculate time between retries
258
- retry_minTimeout: 2000 // integer. Minimum timeout between attempts
230
+ retries: 2, // integer. Number of times to retry connecting
231
+ retry_factor: 2, // integer. Time factor used to calculate time between retries
232
+ retry_minTimeout: 2000, // integer. Minimum timeout between attempts
233
+ promiseLimit: 10, // max concurrent promises for downloadDir/uploadDir
259
234
  };
260
235
 
261
236
  // rarely used options
@@ -282,7 +257,7 @@ for that package for an explanation of these values.
282
257
 
283
258
  #+begin_src javascript
284
259
  sftp.connect({
285
- host: example.com,
260
+ host: 'example.com',
286
261
  port: 22,
287
262
  username: 'donald',
288
263
  password: 'youarefired'
@@ -313,7 +288,7 @@ directory.
313
288
  password: 'my-secret'
314
289
  };
315
290
 
316
- let sftp = new Client;
291
+ let sftp = new Client();
317
292
 
318
293
  sftp.connect(config)
319
294
  .then(() => {
@@ -336,19 +311,19 @@ The objects in the array returned by ~list()~ have the following properties;
336
311
 
337
312
  #+begin_src javascript
338
313
  {
339
- type: // file type(-, d, l)
340
- name: // file name
341
- size: // file size
342
- modifyTime: // file timestamp of modified time
343
- accessTime: // file timestamp of access time
314
+ type: '-', // file type(-, d, l)
315
+ name: 'example.txt', // file name
316
+ size: 43, // file size
317
+ modifyTime: 1675645360000, // file timestamp of modified time
318
+ accessTime: 1675645360000, // file timestamp of access time
344
319
  rights: {
345
- user:
346
- group:
347
- other:
320
+ user: 'rw',
321
+ group: 'r',
322
+ other: 'r',
348
323
  },
349
- owner: // user ID
350
- group: // group ID
351
- longname: // like ls -l line
324
+ owner: 1000, // user ID
325
+ group: 1000, // group ID
326
+ longname: '-rw-r--r-- 1 fred fred 43 Feb 6 12:02 exaple.txt', // like ls -l line
352
327
  }
353
328
  #+end_src
354
329
 
@@ -369,7 +344,7 @@ if it exists or false if it does not.
369
344
  password: 'my-secret'
370
345
  };
371
346
 
372
- let sftp = new Client;
347
+ let sftp = new Client();
373
348
 
374
349
  sftp.connect(config)
375
350
  .then(() => {
@@ -508,6 +483,12 @@ this for binary files to avoid data corruption.
508
483
 
509
484
  Downloads a file at remotePath to localPath using parallel reads for faster
510
485
  throughput. This is the simplest method if you just want to download a file.
486
+ However, fastGet functionality depends heavily on remote sftp server capabilities and not
487
+ all servers have the concurrency support required. See the Platform Quirks & Warnings
488
+ section of this README.
489
+
490
+ Bottom line, when it works, it tends to work reliably. However, for many servers, it
491
+ simply won't work or will result in truncated/corrupted data.
511
492
 
512
493
  - remotePath :: String. Path to the remote file to download
513
494
  - localPath :: String. Path on local file system for the downloaded file. The
@@ -617,7 +598,14 @@ resolved.
617
598
  *** fastPut(localPath, remotePath, options) ==> string
618
599
 
619
600
  Uploads the data in file at ~localPath~ to a new file on remote server at
620
- ~remotePath~ using concurrency. The options object allows tweaking of the fast put process.
601
+ ~remotePath~ using concurrency. The options object allows tweaking of the fast put
602
+ process. Note that this functionality is heavily dependent on the capabilities of the
603
+ remote sftp server, which must support the concurrency operations used by this
604
+ method. This is not part of the standard and therefore is not available in all sftp
605
+ servers. See the Platform Quirks & Warnings for more details.
606
+
607
+ Bottom line, when it works, it tends to work well. However, when it doesn't work, it may
608
+ fail completely or it may result in truncated or corrupted data transfers.
621
609
 
622
610
  - localPath :: string. Path to local file to upload
623
611
  - remotePath :: string. Path to remote file to create
@@ -1176,6 +1164,7 @@ Removes the specified listener from the event specified in eventType. Note that
1176
1164
  the ~end()~ method automatically removes all listeners from the client object.
1177
1165
 
1178
1166
  * Platform Quirks & Warnings
1167
+
1179
1168
  ** Server Capabilities
1180
1169
 
1181
1170
  All SFTP servers and platforms are not equal. Some facilities provided by
@@ -1456,6 +1445,8 @@ configuration.
1456
1445
 
1457
1446
  This solution was provided by @jmorino.
1458
1447
 
1448
+ When a SOCKS 5 client is connected it must be ingested by ssh2-sftp-client immediately, otherwise a timeout occurs.
1449
+
1459
1450
  #+begin_src javascript
1460
1451
  import { SocksClient } from 'socks';
1461
1452
  import SFTPClient from 'ssh2-sftp-client';
@@ -1464,7 +1455,7 @@ This solution was provided by @jmorino.
1464
1455
  const port = 22; // default SSH/SFTP port on remote server
1465
1456
 
1466
1457
  // connect to SOCKS 5 proxy
1467
- const { socks } = await SocksClient.createConnection({
1458
+ const { socket } = await SocksClient.createConnection({
1468
1459
  proxy: {
1469
1460
  host: 'my.proxy', // proxy hostname
1470
1461
  port: 1080, // proxy port
@@ -1477,9 +1468,8 @@ This solution was provided by @jmorino.
1477
1468
  const client = new SFTPClient();
1478
1469
  client.connect({
1479
1470
  host,
1480
- sock: socks.socket, // pass the socket to proxy here (see ssh2 doc)
1481
- username: '.....',
1482
- privateKey: '.....'
1471
+ sock: socket, // pass the socket to proxy here (see ssh2 doc)
1472
+ // other config options
1483
1473
  })
1484
1474
 
1485
1475
  // client is connected
@@ -1544,6 +1534,7 @@ the =ssh2= README to set the properties in the =algorithms= object.
1544
1534
  await client.end();
1545
1535
  }
1546
1536
  #+end_src
1537
+
1547
1538
  ** Connection hangs or fails for larger files
1548
1539
 
1549
1540
  This was contributed by Ladislav Jacho. Thanks.
@@ -1557,6 +1548,13 @@ the =ssh2= README to set the properties in the =algorithms= object.
1557
1548
 
1558
1549
  For more explanation, see [[https://github.com/theophilusx/ssh2-sftp-client/issues/342][issue #342]].
1559
1550
 
1551
+ ** Typescript definition file out of date
1552
+
1553
+ This project does not use Typescript. However, typescript definition files are provided by
1554
+ other 3rd parties. Sometimes, these definition files have not stayed up-to-date with the
1555
+ current version of this module. If you encounter this issue, you need to report it to the
1556
+ party responsible for the definition file, not this project.
1557
+
1560
1558
  * Examples
1561
1559
 
1562
1560
  I have started collecting example scripts in the example directory of the
@@ -1730,7 +1728,7 @@ the ~ssh2-sftp-client~ wrapper module.
1730
1728
  await sftp.fastGet(`${d}/foo.txt`, 'bat.txt');
1731
1729
  } catch (e) {
1732
1730
  console.error(e.message);
1733
- } finally () {
1731
+ } finally {
1734
1732
  await sftp.end();
1735
1733
  }
1736
1734
  }
@@ -1836,6 +1834,7 @@ based on messages which start with 'CLIENT' e.g.
1836
1834
  }
1837
1835
  }
1838
1836
  #+end_src
1837
+
1839
1838
  * Logging Issues
1840
1839
 
1841
1840
  Please log an issue for all bugs, questions, feature and enhancement
@@ -1880,8 +1879,10 @@ your pull request what level of change it represents i.e.
1880
1879
 
1881
1880
  - Major :: Change to API or major change in functionality which will require an
1882
1881
  increase in major version number.
1882
+
1883
1883
  - Minor :: Minor change, enhancement or new feature which does not change
1884
1884
  existing API and will not break existing client code.
1885
+
1885
1886
  - Bug Fix :: No change to functionality or features. Simple fix of an existing
1886
1887
  bug.
1887
1888
 
@@ -1913,3 +1914,4 @@ Thanks to the following for their contributions -
1913
1914
  Also included test to check for this regression in future.
1914
1915
  - cakemasher :: Contributed fix for removeTempListeners().
1915
1916
 
1917
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssh2-sftp-client",
3
- "version": "9.0.4",
3
+ "version": "10.0.0",
4
4
  "description": "ssh2 sftp client for node",
5
5
  "main": "src/index.js",
6
6
  "repository": {
@@ -18,7 +18,7 @@
18
18
  "lint": "eslint \"src/**/*.js\" \"test/**/*.js\""
19
19
  },
20
20
  "engines": {
21
- "node": ">=10.24.1"
21
+ "node": ">=16.20.2"
22
22
  },
23
23
  "author": "Tim Cross",
24
24
  "email": "theophilusx@gmail.com",
@@ -30,27 +30,27 @@
30
30
  ],
31
31
  "license": "Apache-2.0",
32
32
  "devDependencies": {
33
- "chai": "^4.3.6",
33
+ "chai": "^4.3.10",
34
34
  "chai-as-promised": "^7.1.1",
35
35
  "chai-subset": "^1.6.0",
36
36
  "checksum": "^1.0.0",
37
37
  "dotenv": "^16.0.0",
38
- "eslint": "^8.17.0",
39
- "eslint-config-prettier": "^8.5.0",
40
- "eslint-plugin-mocha": "^10.0.3",
38
+ "eslint": "^8.51.0",
39
+ "eslint-config-prettier": "^9.0.0",
40
+ "eslint-plugin-mocha": "^10.2.0",
41
41
  "eslint-plugin-node": "^11.1.0",
42
42
  "eslint-plugin-promise": "^6.0.0",
43
- "eslint-plugin-unicorn": "^43.0.2",
43
+ "eslint-plugin-unicorn": "^50.0.1",
44
44
  "mocha": "^10.0.0",
45
45
  "moment": "^2.29.1",
46
46
  "nyc": "^15.1.0",
47
- "prettier": "^2.6.1",
47
+ "prettier": "^3.0.3",
48
48
  "through2": "^4.0.2",
49
- "winston": "^3.6.0"
49
+ "winston": "^3.11.0"
50
50
  },
51
51
  "dependencies": {
52
52
  "concat-stream": "^2.0.0",
53
53
  "promise-retry": "^2.0.1",
54
- "ssh2": "^1.11.0"
54
+ "ssh2": "^1.15.0"
55
55
  }
56
56
  }