ssh2-sftp-client
Advanced tools
Comparing version 4.2.4 to 4.3.0
{ | ||
"name": "ssh2-sftp-client", | ||
"version": "4.2.4", | ||
"version": "4.3.0", | ||
"description": "ssh2 sftp client for node", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
370
README.md
# Table of Contents | ||
1. [SSH2 SFTP Client](#org7400e89) | ||
2. [Installation](#org7d7e4c5) | ||
3. [Basic Usage](#orge99dd26) | ||
4. [Breaking Changes in Version 4.x](#orge468d24) | ||
5. [Enhancements in Version 4.2.x](#org4c74dfe) | ||
6. [Enhancements in Version 4.1.x](#org2a9c3e8) | ||
7. [Documentation](#orgf338891) | ||
1. [Methods](#org3f4f654) | ||
1. [new SftpClient(name) ===> SFTP client object](#org12aba1f) | ||
2. [connect(config) ===> SFTPstream](#orgb70b952) | ||
3. [list(path, pattern) ==> Array[object]](#org6f63a2b) | ||
4. [exists(path) ==> boolean](#orgfc9a547) | ||
5. [stat(path) ==> object](#org9da2da3) | ||
6. [get(path, dst, options) ==> String|Stream|Buffer](#orgd76a983) | ||
7. [fastGet(remotePath, localPath, options) ===> string](#org3d6ca47) | ||
8. [put(src, remotePath, options) ==> string](#org0581c7e) | ||
9. [fastPut(localPath, remotePath, options) ==> string](#org3279a82) | ||
10. [append(input, remotePath, options) ==> string](#org9c222dc) | ||
11. [mkdir(path, recursive) ==> string](#orga03da22) | ||
12. [rmdir(path, recursive) ==> string](#org6fa5b33) | ||
13. [delete(path) ==> string](#org8587c72) | ||
14. [rename(fromPath, toPath) ==> string](#orgd05e95a) | ||
15. [chmod(path, mode) ==> string](#orgc287962) | ||
16. [realPath(path) ===> string](#orged43f6f) | ||
17. [cwd() ==> string](#orgb0de7f0) | ||
18. [end() ==> boolean](#org1dd0d01) | ||
19. [Add and Remove Listeners](#org286cecf) | ||
8. [FAQ](#org2a22e47) | ||
1. [Remote server drops connections with only an end event](#org571d83b) | ||
2. [How can you pass writable stream as dst for get method?](#orgbb940dd) | ||
3. [How can I upload files without having to specify a password?](#org21d4d3d) | ||
4. [How can I connect through a Socks Proxy](#org86cbd46) | ||
9. [Change Log](#orgc84f948) | ||
1. [v4.2.4 (Prod Version)](#org1d5bf96) | ||
2. [v4.2.3 (Prod Version)](#org2f25624) | ||
3. [v4.2.2](#org0f002d7) | ||
4. [v4.2.1](#orgd0736dc) | ||
5. [v4.2.0](#orgaf4a670) | ||
6. [v4.1.0](#org83f8bee) | ||
7. [v4.0.4](#org38a4ce1) | ||
8. [v4.0.3](#org562913d) | ||
9. [v4.0.2](#orgbeee89a) | ||
10. [v4.0.0](#org4c13e5b) | ||
11. [v2.5.2](#org5177424) | ||
12. [v2.5.1](#orgc7e105f) | ||
13. [v2.5.0](#org21a5666) | ||
14. [v2.4.3](#orgf8b9af3) | ||
15. [v2.4.2](#org731a8fd) | ||
16. [v2.4.1](#org8d4fa04) | ||
17. [v2.4.0](#orgc83049f) | ||
18. [v2.3.0](#org8bc5a34) | ||
19. [v3.0.0 – deprecate this version](#org975b51b) | ||
20. [v2.1.1](#orgbd91243) | ||
21. [v2.0.1](#org436f470) | ||
22. [v1.1.0](#org732b3ea) | ||
23. [v1.0.5:](#orga73280b) | ||
10. [Logging Issues](#org981e79b) | ||
11. [Pull Requests](#org1e9c199) | ||
12. [Contributors](#org11f1c6b) | ||
1. [SSH2 SFTP Client](#org267d546) | ||
2. [Installation](#org0e60bbd) | ||
3. [Basic Usage](#org8909930) | ||
4. [Breaking Changes in Version 4.x](#orgca01e2d) | ||
5. [Enhancements in Version 4.2.x](#org0e32703) | ||
6. [Enhancements in Version 4.1.x](#org79e4417) | ||
7. [Documentation](#orgd4a25af) | ||
1. [Specifying Paths](#orga9c844f) | ||
2. [Methods](#org6c79b4a) | ||
1. [new SftpClient(name) ===> SFTP client object](#org7a0a9e1) | ||
2. [connect(config) ===> SFTPstream](#org1f5410a) | ||
3. [list(path, pattern) ==> Array[object]](#org5417985) | ||
4. [exists(path) ==> boolean](#org28aac7f) | ||
5. [stat(path) ==> object](#org71adaa4) | ||
6. [get(path, dst, options) ==> String|Stream|Buffer](#orgd328e59) | ||
7. [fastGet(remotePath, localPath, options) ===> string](#orgd4bd21a) | ||
8. [put(src, remotePath, options) ==> string](#org0a2d58e) | ||
9. [fastPut(localPath, remotePath, options) ==> string](#org294a587) | ||
10. [append(input, remotePath, options) ==> string](#org9fdab91) | ||
11. [mkdir(path, recursive) ==> string](#orgfbf72de) | ||
12. [rmdir(path, recursive) ==> string](#org1289f17) | ||
13. [delete(path) ==> string](#org0716cd6) | ||
14. [rename(fromPath, toPath) ==> string](#orgdd9fbf5) | ||
15. [chmod(path, mode) ==> string](#orga8eec7c) | ||
16. [realPath(path) ===> string](#org547e541) | ||
17. [cwd() ==> string](#orgd387072) | ||
18. [end() ==> boolean](#org775e00b) | ||
19. [Add and Remove Listeners](#org4914107) | ||
8. [FAQ](#orgf69d6fd) | ||
1. [Remote server drops connections with only an end event](#org38ba4e7) | ||
2. [How can you pass writable stream as dst for get method?](#org107f3f9) | ||
3. [How can I upload files without having to specify a password?](#org921d1f3) | ||
4. [How can I connect through a Socks Proxy](#org0bddc7f) | ||
5. [Timeout while waiting for handshake or handshake errors](#org589ca10) | ||
9. [Change Log](#org7bb4cae) | ||
1. [v4.3.0 (Prod Version)](#org618f095) | ||
2. [v4.2.4](#org76b7f52) | ||
3. [v4.2.3](#org9fa5015) | ||
4. [v4.2.2](#orge37659a) | ||
5. [v4.2.1](#org491a66a) | ||
6. [v4.2.0](#org0793b9c) | ||
7. [v4.1.0](#org9a4dfcd) | ||
8. [v4.0.4](#org8a386f0) | ||
9. [v4.0.3](#orge32012b) | ||
10. [v4.0.2](#org9ebe71b) | ||
11. [v4.0.0](#org5d93979) | ||
12. [v2.5.2](#orgca20652) | ||
13. [v2.5.1](#orgfd0a5c7) | ||
14. [v2.5.0](#org97b1182) | ||
15. [v2.4.3](#orga42252f) | ||
16. [v2.4.2](#orgdbbd328) | ||
17. [v2.4.1](#orgfb53e98) | ||
18. [v2.4.0](#orgd7a2b04) | ||
19. [v2.3.0](#org6cdc190) | ||
20. [v3.0.0 – deprecate this version](#org90a18c2) | ||
21. [v2.1.1](#orgdc410bb) | ||
22. [v2.0.1](#org68064ec) | ||
23. [v1.1.0](#orgd4b3afc) | ||
24. [v1.0.5:](#org55e6b6a) | ||
10. [Troubleshooting](#orgaa25190) | ||
11. [Logging Issues](#orga9fb6b0) | ||
12. [Pull Requests](#org5052247) | ||
13. [Contributors](#org08081be) | ||
<a id="org7400e89"></a> | ||
<a id="org267d546"></a> | ||
@@ -75,10 +79,10 @@ # SSH2 SFTP Client | ||
Current stable release is **v4.1.0**. | ||
Current stable release is **v4.3.0**. | ||
Code has been tested against Node versions 8.16.1, 10.16.3 and 12.9.1 | ||
Code has been tested against Node versions 10.17.0 and 12.13.1 | ||
Node versions < 8.x are not supported. | ||
Node versions < 10.x are not supported. | ||
<a id="org7d7e4c5"></a> | ||
<a id="org0e60bbd"></a> | ||
@@ -90,3 +94,3 @@ # Installation | ||
<a id="orge99dd26"></a> | ||
<a id="org8909930"></a> | ||
@@ -112,3 +116,3 @@ # Basic Usage | ||
<a id="orge468d24"></a> | ||
<a id="orgca01e2d"></a> | ||
@@ -141,3 +145,3 @@ # Breaking Changes in Version 4.x | ||
<a id="org4c74dfe"></a> | ||
<a id="org0e32703"></a> | ||
@@ -161,3 +165,3 @@ # Enhancements in Version 4.2.x | ||
<a id="org2a9c3e8"></a> | ||
<a id="org79e4417"></a> | ||
@@ -175,3 +179,3 @@ # Enhancements in Version 4.1.x | ||
<a id="orgf338891"></a> | ||
<a id="orgd4a25af"></a> | ||
@@ -187,8 +191,46 @@ # Documentation | ||
<a id="org3f4f654"></a> | ||
<a id="orga9c844f"></a> | ||
## Specifying Paths | ||
Both `./` and `../` are supported in path specifiers. Tilde (`~`) expansion is | ||
not supported. Relative paths i.e. paths which do not start with a `/`, will be | ||
considered to be relative to whatever the remote server considers to be the | ||
`root` directory of the login. Depending on how the remote SFTP server is | ||
configured, this may not always be what you expect. The module also does some | ||
very basic tests on results returned from the remote server to try and determine | ||
platform type and will replace path separators with whatever the remote systems | ||
uses (e.g. replace `/` with `\` on MS Windows). | ||
There is a small performance hit for using `./` and `../` as the module must | ||
query the remote server to determine what the root path is and derive the | ||
absolute path. Using absolute paths are therefore more efficient and likely more | ||
robust. | ||
When specifying file paths, ensure to include a full path i.e. include the | ||
remote filename. Don't expect the module to append the local file name to the | ||
path you provide. For example, the following will not work | ||
client.put('/home/fred/test.txt', '/remote/dir'); | ||
will not result in the file `test.txt` being copied to | ||
`/remote/dir/test.txt`. You need to specify the target filename as well e.g. | ||
client.put('/home/fred/test.txt', '/remote/dir/test.txt'); | ||
Note that the remote file name does not have to be the same as the local file | ||
name. The following works fine; | ||
client.put('/home/fred/test.txt', '/remote/dir/test-copy.txt'); | ||
This will copy the local file `test.txt` to the remote file `test-copy.txt` in | ||
the directory `/remote/dir`. | ||
<a id="org6c79b4a"></a> | ||
## Methods | ||
<a id="org12aba1f"></a> | ||
<a id="org7a0a9e1"></a> | ||
@@ -232,3 +274,3 @@ ### new SftpClient(name) ===> SFTP client object | ||
<a id="orgb70b952"></a> | ||
<a id="org1f5410a"></a> | ||
@@ -303,3 +345,3 @@ ### connect(config) ===> SFTPstream | ||
<a id="org6f63a2b"></a> | ||
<a id="org5417985"></a> | ||
@@ -377,3 +419,3 @@ ### list(path, pattern) ==> Array[object] | ||
<a id="orgfc9a547"></a> | ||
<a id="org28aac7f"></a> | ||
@@ -413,3 +455,3 @@ ### exists(path) ==> boolean | ||
<a id="org9da2da3"></a> | ||
<a id="org71adaa4"></a> | ||
@@ -461,3 +503,3 @@ ### stat(path) ==> object | ||
<a id="orgd76a983"></a> | ||
<a id="orgd328e59"></a> | ||
@@ -523,3 +565,3 @@ ### get(path, dst, options) ==> String|Stream|Buffer | ||
<a id="org3d6ca47"></a> | ||
<a id="orgd4bd21a"></a> | ||
@@ -567,3 +609,3 @@ ### fastGet(remotePath, localPath, options) ===> string | ||
<a id="org0581c7e"></a> | ||
<a id="org0a2d58e"></a> | ||
@@ -621,3 +663,3 @@ ### put(src, remotePath, options) ==> string | ||
<a id="org3279a82"></a> | ||
<a id="org294a587"></a> | ||
@@ -665,3 +707,3 @@ ### fastPut(localPath, remotePath, options) ==> string | ||
<a id="org9c222dc"></a> | ||
<a id="org9fdab91"></a> | ||
@@ -711,3 +753,3 @@ ### append(input, remotePath, options) ==> string | ||
<a id="orga03da22"></a> | ||
<a id="orgfbf72de"></a> | ||
@@ -741,3 +783,3 @@ ### mkdir(path, recursive) ==> string | ||
<a id="org6fa5b33"></a> | ||
<a id="org1289f17"></a> | ||
@@ -772,3 +814,3 @@ ### rmdir(path, recursive) ==> string | ||
<a id="org8587c72"></a> | ||
<a id="org0716cd6"></a> | ||
@@ -798,3 +840,3 @@ ### delete(path) ==> string | ||
<a id="orgd05e95a"></a> | ||
<a id="orgdd9fbf5"></a> | ||
@@ -824,3 +866,3 @@ ### rename(fromPath, toPath) ==> string | ||
<a id="orgc287962"></a> | ||
<a id="orga8eec7c"></a> | ||
@@ -853,3 +895,3 @@ ### chmod(path, mode) ==> string | ||
<a id="orged43f6f"></a> | ||
<a id="org547e541"></a> | ||
@@ -864,3 +906,3 @@ ### realPath(path) ===> string | ||
<a id="orgb0de7f0"></a> | ||
<a id="orgd387072"></a> | ||
@@ -872,3 +914,3 @@ ### cwd() ==> string | ||
<a id="org1dd0d01"></a> | ||
<a id="org775e00b"></a> | ||
@@ -896,3 +938,3 @@ ### end() ==> boolean | ||
<a id="org286cecf"></a> | ||
<a id="org4914107"></a> | ||
@@ -923,3 +965,3 @@ ### Add and Remove Listeners | ||
<a id="org2a22e47"></a> | ||
<a id="orgf69d6fd"></a> | ||
@@ -929,3 +971,3 @@ # FAQ | ||
<a id="org571d83b"></a> | ||
<a id="org38ba4e7"></a> | ||
@@ -960,3 +1002,3 @@ ## Remote server drops connections with only an end event | ||
<a id="orgbb940dd"></a> | ||
<a id="org107f3f9"></a> | ||
@@ -1025,3 +1067,3 @@ ## How can you pass writable stream as dst for get method? | ||
<a id="org21d4d3d"></a> | ||
<a id="org921d1f3"></a> | ||
@@ -1061,3 +1103,3 @@ ## How can I upload files without having to specify a password? | ||
<a id="org86cbd46"></a> | ||
<a id="org0bddc7f"></a> | ||
@@ -1096,11 +1138,36 @@ ## How can I connect through a Socks Proxy | ||
<a id="orgc84f948"></a> | ||
<a id="org589ca10"></a> | ||
## Timeout while waiting for handshake or handshake errors | ||
Some users have encountered the error 'Timeout while waiting for handshake' or | ||
'Handshake failed, no matching client->server ciphers. This is often due to the | ||
client not having the correct configuration for the transport layer algorithms | ||
used by ssh2. One of the connect options provided by the ssh2 module is | ||
`algorithm`, which is an object that allows you to explicitly set the key | ||
exchange, ciphers, hmac and compression algorithms as well as server | ||
host key used to establish the initial secure connection. See the SSH2 | ||
documentation for details. Getting these parameters correct usually resolves the | ||
issue. | ||
<a id="org7bb4cae"></a> | ||
# Change Log | ||
<a id="org1d5bf96"></a> | ||
<a id="org618f095"></a> | ||
## v4.2.4 (Prod Version) | ||
## v4.3.0 (Prod Version) | ||
- Ensure errors include an err.code property and pass through the error code | ||
from the originating error | ||
- Change tests for error type to use `error.code` instead of matching on | ||
`error.message`. | ||
<a id="org76b7f52"></a> | ||
## v4.2.4 | ||
- Bumped ssh2 to v0.8.6 | ||
@@ -1111,5 +1178,5 @@ - Added exists() usage example to examples directory | ||
<a id="org2f25624"></a> | ||
<a id="org9fa5015"></a> | ||
## v4.2.3 (Prod Version) | ||
## v4.2.3 | ||
@@ -1121,3 +1188,3 @@ - Fix bug in `exist()` where tests on root directory returned false | ||
<a id="org0f002d7"></a> | ||
<a id="orge37659a"></a> | ||
@@ -1130,3 +1197,3 @@ ## v4.2.2 | ||
<a id="orgd0736dc"></a> | ||
<a id="org491a66a"></a> | ||
@@ -1145,3 +1212,3 @@ ## v4.2.1 | ||
<a id="orgaf4a670"></a> | ||
<a id="org0793b9c"></a> | ||
@@ -1157,3 +1224,3 @@ ## v4.2.0 | ||
<a id="org83f8bee"></a> | ||
<a id="org9a4dfcd"></a> | ||
@@ -1175,3 +1242,3 @@ ## v4.1.0 | ||
<a id="org38a4ce1"></a> | ||
<a id="org8a386f0"></a> | ||
@@ -1184,3 +1251,3 @@ ## v4.0.4 | ||
<a id="org562913d"></a> | ||
<a id="orge32012b"></a> | ||
@@ -1193,3 +1260,3 @@ ## v4.0.3 | ||
<a id="orgbeee89a"></a> | ||
<a id="org9ebe71b"></a> | ||
@@ -1201,3 +1268,3 @@ ## v4.0.2 | ||
<a id="org4c13e5b"></a> | ||
<a id="org5d93979"></a> | ||
@@ -1220,3 +1287,3 @@ ## v4.0.0 | ||
<a id="org5177424"></a> | ||
<a id="orgca20652"></a> | ||
@@ -1229,3 +1296,3 @@ ## v2.5.2 | ||
<a id="orgc7e105f"></a> | ||
<a id="orgfd0a5c7"></a> | ||
@@ -1237,3 +1304,3 @@ ## v2.5.1 | ||
<a id="org21a5666"></a> | ||
<a id="org97b1182"></a> | ||
@@ -1245,3 +1312,3 @@ ## v2.5.0 | ||
<a id="orgf8b9af3"></a> | ||
<a id="orga42252f"></a> | ||
@@ -1254,3 +1321,3 @@ ## v2.4.3 | ||
<a id="org731a8fd"></a> | ||
<a id="orgdbbd328"></a> | ||
@@ -1263,3 +1330,3 @@ ## v2.4.2 | ||
<a id="org8d4fa04"></a> | ||
<a id="orgfb53e98"></a> | ||
@@ -1272,3 +1339,3 @@ ## v2.4.1 | ||
<a id="orgc83049f"></a> | ||
<a id="orgd7a2b04"></a> | ||
@@ -1286,3 +1353,3 @@ ## v2.4.0 | ||
<a id="org8bc5a34"></a> | ||
<a id="org6cdc190"></a> | ||
@@ -1296,3 +1363,3 @@ ## v2.3.0 | ||
<a id="org975b51b"></a> | ||
<a id="org90a18c2"></a> | ||
@@ -1305,3 +1372,3 @@ ## v3.0.0 – deprecate this version | ||
<a id="orgbd91243"></a> | ||
<a id="orgdc410bb"></a> | ||
@@ -1314,3 +1381,3 @@ ## v2.1.1 | ||
<a id="org436f470"></a> | ||
<a id="org68064ec"></a> | ||
@@ -1325,3 +1392,3 @@ ## v2.0.1 | ||
<a id="org732b3ea"></a> | ||
<a id="orgd4b3afc"></a> | ||
@@ -1333,3 +1400,3 @@ ## v1.1.0 | ||
<a id="orga73280b"></a> | ||
<a id="org55e6b6a"></a> | ||
@@ -1342,4 +1409,45 @@ ## v1.0.5: | ||
<a id="org981e79b"></a> | ||
<a id="orgaa25190"></a> | ||
# Troubleshooting | ||
The `ssh2-sftp-client` module is essentially a wrapper around the `ssh2` and | ||
`ssh2-streams` modules, providing a higher level `promise` based API. When you | ||
run into issues, it is important to try and determine where the issue lies - | ||
either in the ssh2-sftp-client module or the underlying `ssh2` and | ||
`ssh2-streams` modules. One way to do this is to first identify a minimal | ||
reproducible example which reproduces the issue. Once you have that, try to | ||
replicate the functionality just using the `ssh2` and `ssh2-streams` modules. If | ||
the issue still occurs, then you can be fairly confident it is something related | ||
to those later 2 modules and therefore and issue which should be referred to the | ||
maintainer of that module. | ||
The `ssh2` and `ssh2-streams` modules are very solid, high quality modules with | ||
a large user base. Most of the time, issues with those modules are due to client | ||
misconfiguration. It is therefore very important when trying to diagnose an | ||
issue to also check the documentation for both `ssh2` and `ssh2-streams`. While | ||
these modules have good defaults, the flexibility of the ssh2 protocol means | ||
that not all options are available by default. You may need to tweak the | ||
connection options, ssh2 algorithms and ciphers etc for some remote servers. The | ||
documentation for both the `ssh2` and `ssh2-streams` module is quite | ||
comprehensive and there is lots of valuable information in the issue logs. | ||
If you run into an issue which is not repeatable with just the `ssh2` and | ||
`ssh2-streams` modules, then please log an issue against the `ssh2-sftp-client` | ||
module and I will investigate. Please note the next section on logging issues. | ||
Note also that in the repository there are two useful directories. The first is | ||
the examples directory, which contain some examples of using `ssh2-sftp-client` | ||
to perform common tasks. A few minutes reviewing these examples can provide that | ||
additional bit of detail to help fix any problems you are encountering. | ||
The second directory is the tools directory. I have some very basic simple | ||
scripts in this directory which perform basic tasks using only the `ssh2` and | ||
`ssh2-streams` modules (no ssh2-sftp-client module). These can be useful when | ||
trying to determine if the issue is with the underlying `ssh2` and | ||
`ssh2-streams` modules. | ||
<a id="orga9fb6b0"></a> | ||
# Logging Issues | ||
@@ -1351,5 +1459,21 @@ | ||
I am happy to try and help diagnose and fix any issues you encounter while using | ||
the `ssh2-sftp-client` module. However, I will only put in effort if you are | ||
prepared to put in the effort to provide the information necessary to reproduce | ||
the issue. Things which will help | ||
<a id="org1e9c199"></a> | ||
- Node version you are using | ||
- Version of ssh2-sftp-client you are using | ||
- Platform your client is running on (Linux, macOS, Windows) | ||
- Platform and software for the remote SFTP server when possible | ||
- Example of your code. By far, the most common issue is incorrect use of the | ||
module API. Example code can usually result in such issues being resolved very | ||
quickly. | ||
Perhaps the best assistance is a minimal reproducible example of the issue. Once | ||
the issue can be readily reproduced, it can usually be fixed very quickly. | ||
<a id="org5052247"></a> | ||
# Pull Requests | ||
@@ -1373,3 +1497,3 @@ | ||
<a id="org11f1c6b"></a> | ||
<a id="org08081be"></a> | ||
@@ -1376,0 +1500,0 @@ # Contributors |
365
src/index.js
@@ -12,3 +12,11 @@ /** | ||
const {posix, normalize} = require('path'); | ||
const utils = require('./utils'); | ||
const errorCode = { | ||
generic: 'ERR_GENERIC_CLIENT', | ||
connect: 'ERR_NOT_CONNECTED', | ||
badPath: 'ERR_BAD_PATH', | ||
permission: 'ERR_NO_PERMISSON' | ||
}; | ||
let SftpClient = function(clientName = '') { | ||
@@ -22,78 +30,2 @@ this.client = new Client(); | ||
/** | ||
* Generate a new Error object with a reformatted error message which | ||
* is a little more informative and useful to users. | ||
* | ||
* @param {Error|string} err - The Error object the new error will be based on | ||
* @param {number} retryCount - For those functions which use retry. Number of | ||
* attempts to complete before giving up | ||
* @returns {Error} New error with custom error message | ||
*/ | ||
function formatError(err, name = 'sftp', retryCount) { | ||
let msg = ''; | ||
//console.dir(err); | ||
if (typeof err === 'string') { | ||
msg = `${name}: ${err}`; | ||
} else { | ||
switch (err.code) { | ||
case 'ENOTFOUND': | ||
msg = | ||
`${name}: ` + | ||
`${err.level} error. Address lookup failed for host ${err.hostname}`; | ||
break; | ||
case 'ECONNREFUSED': | ||
msg = | ||
`${name}: ${err.level} error. Remote host at ` + | ||
`${err.address} refused connection`; | ||
break; | ||
case 'ENOENT': | ||
msg = `${name}: ${err.message}`; | ||
break; | ||
default: | ||
msg = `${name}: ${err.message}`; | ||
} | ||
} | ||
if (retryCount) { | ||
msg += ` after ${retryCount} ${retryCount > 1 ? 'attempts' : 'attempt'}`; | ||
} | ||
return new Error(msg); | ||
} | ||
/** | ||
* Remove all ready, error and end listeners. | ||
* | ||
* @param {Emitter} emitter - The emitter object to remove listeners from | ||
*/ | ||
function removeListeners(emitter) { | ||
let listeners = emitter.eventNames(); | ||
listeners.forEach(name => { | ||
emitter.removeAllListeners(name); | ||
}); | ||
} | ||
/** | ||
* Simple default error listener. Will reformat the error message and | ||
* throw a new error. | ||
* | ||
* @param {Error} err - source for defining new error | ||
* @throws {Error} Throws new error | ||
*/ | ||
function makeErrorListener(name) { | ||
return function(err) { | ||
throw formatError(err, name); | ||
}; | ||
} | ||
function makeEndListener(client) { | ||
return function() { | ||
if (!client.endCalled) { | ||
client.sftp = undefined; | ||
throw formatError('Connection ended unexpectedly', client.clientName); | ||
} | ||
}; | ||
} | ||
SftpClient.prototype.realPath = function(path) { | ||
@@ -105,7 +37,19 @@ const sftp = this.sftp; | ||
if (!sftp) { | ||
reject(formatError('No SFTP connection available', 'sftp.realPath')); | ||
reject( | ||
utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.realPath', | ||
errorCode.connect | ||
) | ||
); | ||
} else { | ||
sftp.realpath(path, (err, absPath) => { | ||
if (err) { | ||
reject(formatError(`${err.message} ${path}`, 'sftp.realPath')); | ||
reject( | ||
utils.formatError( | ||
`${err.message} ${path}`, | ||
'sftp.realPath', | ||
err.code | ||
) | ||
); | ||
} | ||
@@ -116,3 +60,5 @@ resolve(absPath); | ||
} catch (err) { | ||
reject(formatError(`${err.message} ${path}`, 'sftp.realPath')); | ||
reject( | ||
utils.formatError(`${err.message} ${path}`, 'sftp.realPath', err.code) | ||
); | ||
} | ||
@@ -135,3 +81,5 @@ }); | ||
if (err) { | ||
reject(formatError(`${err.message} ${path}`, 'sftp.list')); | ||
reject( | ||
utils.formatError(`${err.message} ${path}`, 'sftp.list', err.code) | ||
); | ||
} else { | ||
@@ -182,3 +130,7 @@ let newList = []; | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.list'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.list', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -219,3 +171,3 @@ let absPath = await this.realPath(path); | ||
} else { | ||
reject(formatError(err, 'sftp.exists')); | ||
reject(utils.formatError(err, 'sftp.exists')); | ||
} | ||
@@ -251,3 +203,7 @@ } else { | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.exists'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.exists', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -257,6 +213,6 @@ let absPath = await this.realPath(remotePath); | ||
} catch (err) { | ||
if (err.message.match(/No such file/)) { | ||
if (err.code === 2) { | ||
return false; | ||
} | ||
throw formatError(err, 'sftp.exists'); | ||
throw utils.formatError(err, 'sftp.exists'); | ||
} | ||
@@ -271,3 +227,9 @@ }; | ||
if (err) { | ||
reject(formatError(`${err.message} ${remotePath}`, 'sftp.stat')); | ||
reject( | ||
utils.formatError( | ||
`${err.message} ${remotePath}`, | ||
'sftp.stat', | ||
err.code | ||
) | ||
); | ||
} else { | ||
@@ -302,3 +264,7 @@ resolve({ | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.stat'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.stat', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -315,4 +281,4 @@ let absPath = await this.realPath(remotePath); | ||
rdr.on('error', err => { | ||
removeListeners(rdr); | ||
reject(formatError(`${err.message} ${path}`, 'sftp.get')); | ||
utils.removeListeners(rdr); | ||
reject(utils.formatError(`${err.message} ${path}`, 'sftp.get', err.code)); | ||
}); | ||
@@ -337,7 +303,8 @@ | ||
wtr.on('error', err => { | ||
removeListeners(rdr); | ||
utils.removeListeners(rdr); | ||
reject( | ||
formatError( | ||
utils.formatError( | ||
`${err.message} ${typeof dst === 'string' ? dst : ''}`, | ||
'sftp.get' | ||
'sftp.get', | ||
err.code | ||
) | ||
@@ -347,3 +314,3 @@ ); | ||
wtr.on('finish', () => { | ||
removeListeners(rdr); | ||
utils.removeListeners(rdr); | ||
if (typeof dst === 'string') { | ||
@@ -376,3 +343,7 @@ resolve(dst); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.get'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.get', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -384,3 +355,7 @@ | ||
if ((stats.mode & 0o444) === 0) { | ||
throw formatError(`No read permission for ${absPath}`, 'sftp.get'); | ||
throw utils.formatError( | ||
`No read permission for ${absPath}`, | ||
'sftp.get', | ||
errorCode.permission | ||
); | ||
} | ||
@@ -401,3 +376,9 @@ | ||
if (err) { | ||
reject(formatError(`${err.message} ${remotePath}`, 'sftp.fastGet')); | ||
reject( | ||
utils.formatError( | ||
`${err.message} ${remotePath}`, | ||
'sftp.fastGet', | ||
err.code | ||
) | ||
); | ||
} | ||
@@ -423,3 +404,7 @@ resolve(`${remotePath} was successfully download to ${localPath}!`); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.fastGet'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.fastGet', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -438,5 +423,6 @@ let src = await this.realPath(remotePath); | ||
reject( | ||
formatError( | ||
utils.formatError( | ||
`${err.message} Local: ${localPath} Remote: ${remotePath}`, | ||
'sftp.fastPut' | ||
'sftp.fastPut', | ||
err.code | ||
) | ||
@@ -465,3 +451,7 @@ ); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.fastPut'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.fastPut', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -487,7 +477,9 @@ let src = fs.realpathSync(localPath); | ||
stream.on('error', err => { | ||
reject(formatError(`${err.message} ${remotePath}`, 'sftp.put')); | ||
reject( | ||
utils.formatError(`${err.message} ${remotePath}`, 'sftp.put', err.code) | ||
); | ||
}); | ||
stream.on('finish', () => { | ||
removeListeners(stream); | ||
utils.removeListeners(stream); | ||
resolve(`Uploaded data stream to ${remotePath}`); | ||
@@ -506,7 +498,8 @@ }); | ||
rdr.on('error', err => { | ||
removeListeners(stream); | ||
utils.removeListeners(stream); | ||
reject( | ||
formatError( | ||
utils.formatError( | ||
`${err.message} ${typeof src === 'string' ? src : ''}`, | ||
'sftp.put' | ||
'sftp.put', | ||
err.code | ||
) | ||
@@ -533,3 +526,7 @@ ); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connections available', 'sftp.put'); | ||
throw utils.formatError( | ||
'No SFTP connections available', | ||
'sftp.put', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -570,8 +567,14 @@ let src = localSrc; | ||
stream.on('error', err => { | ||
removeListeners(stream); | ||
reject(formatError(`${err.message} ${remotePath}`, 'sftp.append')); | ||
utils.removeListeners(stream); | ||
reject( | ||
utils.formatError( | ||
`${err.message} ${remotePath}`, | ||
'sftp.append', | ||
err.code | ||
) | ||
); | ||
}); | ||
stream.on('finish', () => { | ||
removeListeners(stream); | ||
utils.removeListeners(stream); | ||
resolve(`sftp.append: Uploaded data stream to ${remotePath}`); | ||
@@ -598,6 +601,14 @@ }); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.append'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.append', | ||
errorCode.connect | ||
); | ||
} | ||
if (typeof input === 'string') { | ||
throw formatError('Cannot append one file to another', 'sftp.append'); | ||
throw utils.formatError( | ||
'Cannot append one file to another', | ||
'sftp.append', | ||
errorCode.badPath | ||
); | ||
} | ||
@@ -607,9 +618,14 @@ let absPath = await this.realPath(remotePath); | ||
if ((stats.mode & 0o0100000) === 0) { | ||
throw formatError( | ||
throw utils.formatError( | ||
`${remotePath} Remote path must be a regular file`, | ||
'sftp-append' | ||
'sftp-append', | ||
errorCode.badPath | ||
); | ||
} | ||
if ((stats.mode & 0o0444) === 0) { | ||
throw formatError(`${remotePath} No write permission`, 'sftp-append'); | ||
throw utils.formatError( | ||
`${remotePath} No write permission`, | ||
'sftp-append', | ||
errorCode.permission | ||
); | ||
} | ||
@@ -635,3 +651,5 @@ return this._append(input, absPath, options); | ||
if (err) { | ||
reject(formatError(`${err.message} ${p}`, 'sftp.mkdir')); | ||
reject( | ||
utils.formatError(`${err.message} ${p}`, 'sftp.mkdir', err.code) | ||
); | ||
} | ||
@@ -645,3 +663,7 @@ resolve(`${p} directory created`); | ||
if (!sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.mkdir'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.mkdir', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -665,7 +687,11 @@ let realPath = path; | ||
} else if (parent !== 'd') { | ||
throw formatError('Bad directory path', 'sftp.mkdir'); | ||
throw utils.formatError( | ||
'Bad directory path', | ||
'sftp.mkdir', | ||
errorCode.badPath | ||
); | ||
} | ||
return doMkdir(realPath); | ||
} catch (err) { | ||
throw formatError(err, 'sftp.mkdir'); | ||
throw utils.formatError(err, 'sftp.mkdir', err.code); | ||
} | ||
@@ -692,3 +718,5 @@ }; | ||
if (err) { | ||
reject(formatError(`${err.message} ${p}`, 'sftp.rmdir')); | ||
reject( | ||
utils.formatError(`${err.message} ${p}`, 'sftp.rmdir', err.code) | ||
); | ||
} | ||
@@ -698,3 +726,3 @@ resolve('Successfully removed directory'); | ||
} catch (err) { | ||
reject(formatError(err, 'sftp.rmdir')); | ||
reject(utils.formatError(err, 'sftp.rmdir', err.code)); | ||
} | ||
@@ -706,3 +734,7 @@ }); | ||
if (!sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.rmdir'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.rmdir', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -721,3 +753,3 @@ let absPath = await this.realPath(path); | ||
} catch (err) { | ||
throw formatError(err, 'sftp.rmdir'); | ||
throw utils.formatError(err, 'sftp.rmdir', err.code); | ||
} | ||
@@ -729,3 +761,3 @@ } | ||
} catch (err) { | ||
throw formatError(err, 'sftp.rmdir'); | ||
throw utils.formatError(err, 'sftp.rmdir', err.code); | ||
} | ||
@@ -736,3 +768,3 @@ } | ||
} catch (err) { | ||
throw formatError(err, 'sftp.rmdir'); | ||
throw utils.formatError(err, 'sftp.rmdir', err.code); | ||
} | ||
@@ -747,3 +779,5 @@ }; | ||
if (err) { | ||
reject(formatError(`${err.message} ${path}`, 'sftp.delete')); | ||
reject( | ||
utils.formatError(`${err.message} ${path}`, 'sftp.delete', err.code) | ||
); | ||
} | ||
@@ -766,3 +800,7 @@ resolve('Successfully deleted file'); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.delete'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.delete', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -780,5 +818,6 @@ let absPath = await this.realPath(path); | ||
reject( | ||
formatError( | ||
utils.formatError( | ||
`${err.message} From: ${fromPath} To: ${toPath}`, | ||
'sftp.rename' | ||
'sftp.rename', | ||
err.code | ||
) | ||
@@ -805,3 +844,7 @@ ); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.rename'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.rename', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -826,3 +869,9 @@ let src = await this.realPath(fromPath); | ||
if (err) { | ||
reject(formatError(`${err.message} ${remotePath}`, 'sftp.chmod')); | ||
reject( | ||
utils.formatError( | ||
`${err.message} ${remotePath}`, | ||
'sftp.chmod', | ||
err.code | ||
) | ||
); | ||
} | ||
@@ -846,3 +895,7 @@ resolve('Successfully change file mode'); | ||
if (!this.sftp) { | ||
throw formatError('No SFTP connection available', 'sftp.chmod'); | ||
throw utils.formatError( | ||
'No SFTP connection available', | ||
'sftp.chmod', | ||
errorCode.connect | ||
); | ||
} | ||
@@ -879,3 +932,3 @@ let path = await this.realPath(remotePath); | ||
if (err) { | ||
removeListeners(self.client); | ||
utils.removeListeners(self.client); | ||
if (operation.retry(err)) { | ||
@@ -887,3 +940,11 @@ // failed to connect, but not yet reached max attempt count | ||
// exhausted retries - do callback with error | ||
callback(formatError(err, 'sftp.connect', attemptCount), null); | ||
callback( | ||
utils.formatError( | ||
err, | ||
'sftp.connect', | ||
err.code, | ||
attemptCount | ||
), | ||
null | ||
); | ||
} | ||
@@ -894,4 +955,8 @@ self.sftp = sftp; | ||
self.client.removeAllListeners('end'); | ||
self.client.on('end', makeEndListener(self)); | ||
self.client.on('error', makeErrorListener(self.clientName)); | ||
self.client.on('end', utils.makeEndListener(self)); | ||
self.client.on('error', utils.makeErrorListener(self.clientName)); | ||
self.client.on( | ||
'uncaughtException', | ||
utils.makeErrorListener(self.clientName) | ||
); | ||
callback(null, sftp); | ||
@@ -901,3 +966,3 @@ }); | ||
.on('error', err => { | ||
removeListeners(self.client); | ||
utils.removeListeners(self.client); | ||
if (operation.retry(err)) { | ||
@@ -909,9 +974,13 @@ // failed to connect, but not yet reached max attempt count | ||
// exhausted retries - do callback with error | ||
callback(formatError(err, 'sftp.connect', attemptCount), null); | ||
callback( | ||
utils.formatError(err, 'sftp.connect', err.code, attemptCount), | ||
null | ||
); | ||
}) | ||
.on('end', () => { | ||
callback( | ||
formatError( | ||
utils.formatError( | ||
'Connection ended unexpectedly by remote server', | ||
self.clientName | ||
self.clientName, | ||
errorCode.connect | ||
) | ||
@@ -923,4 +992,4 @@ ); | ||
} catch (err) { | ||
removeListeners(self.client); | ||
callback(formatError(err, 'sftp.connect'), null); | ||
utils.removeListeners(self.client); | ||
callback(utils.formatError(err, 'sftp.connect', err.code), null); | ||
} | ||
@@ -932,5 +1001,6 @@ } | ||
reject( | ||
formatError( | ||
utils.formatError( | ||
'An existing SFTP connection is already defined', | ||
'sftp.connect' | ||
'sftp.connect', | ||
errorCode.connect | ||
) | ||
@@ -946,5 +1016,6 @@ ); | ||
reject( | ||
formatError( | ||
utils.formatError( | ||
`Failed to determine remote server type: ${err.message}`, | ||
'sftp.connect' | ||
'sftp.connect', | ||
err.code | ||
) | ||
@@ -993,3 +1064,3 @@ ); | ||
self.client.end(); | ||
removeListeners(self.client); | ||
utils.removeListeners(self.client); | ||
self.sftp = undefined; | ||
@@ -999,3 +1070,3 @@ resolve(true); | ||
} catch (err) { | ||
reject(formatError(err, 'sftp.end')); | ||
reject(utils.formatError(err, 'sftp.end', err.code)); | ||
} | ||
@@ -1002,0 +1073,0 @@ }); |
Sorry, the diff of this file is not supported yet
130593
6
1061
1456