Socket
Socket
Sign inDemoInstall

ssh2-sftp-client

Package Overview
Dependencies
3
Maintainers
2
Versions
73
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 5.0.2 to 5.1.0

6

package.json
{
"name": "ssh2-sftp-client",
"version": "5.0.2",
"version": "5.1.0",
"description": "ssh2 sftp client for node",

@@ -30,3 +30,3 @@ "main": "src/index.js",

"retry": "^0.12.0",
"ssh2": "^0.8.7"
"ssh2": "^0.8.8"
},

@@ -39,5 +39,5 @@ "devDependencies": {

"dotenv": "^8.2.0",
"mocha": "^7.0.0",
"mocha": "^7.1.0",
"through2": "^3.0.1"
}
}
# Table of Contents
1. [SSH2 SFTP Client](#org59926bb)
2. [Installation](#orgfa12105)
3. [Basic Usage](#orgdcb4ac8)
4. [Version 5.x](#orgb1a2c3d)
1. [Breaking Changes in Version 5.x](#org50ff9f1)
1. [Error Event Handling](#orgbc36ac2)
2. [Technical Details](#orgdc9ce74)
2. [New Methods](#org2dd8843)
3. [Version 5.0.1](#orge044fce)
4. [Version 5.0.2](#org7ccd57d)
5. [Documentation](#org050dbca)
1. [Specifying Paths](#org899b50f)
2. [Methods](#orgb3c2cb6)
1. [new SftpClient(name) ===> SFTP client object](#org99655e8)
2. [connect(config) ===> SFTPstream](#org29a9aa8)
3. [list(path, pattern) ==> Array[object]](#org28fc220)
4. [exists(path) ==> boolean](#org9bbdfd9)
5. [stat(path) ==> object](#org9ae7824)
6. [get(path, dst, options) ==> String|Stream|Buffer](#org1608509)
7. [fastGet(remotePath, localPath, options) ===> string](#org9e40286)
8. [put(src, remotePath, options) ==> string](#org21a04fa)
9. [fastPut(localPath, remotePath, options) ==> string](#orgccbc75b)
10. [append(input, remotePath, options) ==> string](#org37e8a28)
11. [mkdir(path, recursive) ==> string](#orgc976219)
12. [rmdir(path, recursive) ==> string](#orga51f516)
13. [delete(path) ==> string](#org29f1cd8)
14. [rename(fromPath, toPath) ==> string](#orgf371df6)
15. [chmod(path, mode) ==> string](#org0ea3423)
16. [realPath(path) ===> string](#org17fe515)
17. [cwd() ==> string](#org8ba0584)
18. [uploadDir(srcDir, dstDir) ==> string](#orgf015b8f)
19. [downloadDir(srcDir, dstDir) ==> string](#org0c10cb8)
20. [end() ==> boolean](#org936ae21)
21. [Add and Remove Listeners](#org15a9c85)
6. [FAQ](#orgc79f3d2)
1. [Remote server drops connections with only an end event](#org8c068da)
2. [How can you pass writable stream as dst for get method?](#org06acfd2)
3. [How can I upload files without having to specify a password?](#orgcd6ac49)
4. [How can I connect through a Socks Proxy](#orga601cc9)
5. [Timeout while waiting for handshake or handshake errors](#orgb9d4439)
7. [Examples](#org5c46982)
8. [Change Log](#org39062e6)
1. [v5.0.2 (Prod Version)](#orga3081db)
2. [v5.0.1](#org5c223c2)
3. [v5.0.0](#orgc1ea505)
4. [v4.3.1](#org9674bc2)
5. [v4.3.0](#org9fdf4b5)
6. [v4.2.4](#org7ed824b)
7. [v4.2.3](#orgd3028bd)
8. [v4.2.2](#org2ac3d75)
9. [v4.2.1](#orgcd4e9e2)
10. [v4.2.0](#org199764b)
11. [v4.1.0](#org10bedf8)
12. [v4.0.4](#org0962876)
13. [v4.0.3](#org3d4fa37)
14. [v4.0.2](#orgeebc8d6)
15. [v4.0.0](#org5d18cf9)
16. [v2.5.2](#orgbc22ad1)
17. [v2.5.1](#org2f89ba7)
18. [v2.5.0](#orgb8683aa)
19. [v2.4.3](#org8c37fb0)
20. [v2.4.2](#orgbe5c717)
21. [v2.4.1](#orgeeb9805)
22. [v2.4.0](#orgbd36319)
23. [v2.3.0](#orgf07ea36)
24. [v3.0.0 – deprecate this version](#org95d7555)
25. [v2.1.1](#orgcca455a)
26. [v2.0.1](#orga11176a)
27. [v1.1.0](#orgc33c477)
28. [v1.0.5:](#orgb12a992)
9. [Troubleshooting](#orgd779dc4)
10. [Logging Issues](#orgfe3d18c)
11. [Pull Requests](#orgd60ef19)
12. [Contributors](#orgf30aa6b)
1. [SSH2 SFTP Client](#org71b320d)
2. [Installation](#orgc904404)
3. [Basic Usage](#orgb7288c2)
4. [Version 5.x](#org117386b)
1. [Breaking Changes in Version 5.x](#orgaf9ad42)
1. [Error Event Handling](#orgb01e3b7)
2. [Technical Details](#org1ae0a28)
2. [New Methods](#orgc8305e8)
3. [Version 5.0.1](#orgc2e0e38)
4. [Version 5.0.2](#org677cda9)
5. [Version 5.1.0](#orgb363dc7)
5. [Documentation](#org46b5997)
1. [Specifying Paths](#orga935b97)
2. [Methods](#org98305c1)
1. [new SftpClient(name) ===> SFTP client object](#org13f62cb)
2. [connect(config) ===> SFTPstream](#orgd1717c5)
3. [list(path, pattern) ==> Array[object]](#org7ba4acf)
4. [exists(path) ==> boolean](#orgdfefb95)
5. [stat(path) ==> object](#orgc98fc30)
6. [get(path, dst, options) ==> String|Stream|Buffer](#org71ac9c4)
7. [fastGet(remotePath, localPath, options) ===> string](#org0ba08cd)
8. [put(src, remotePath, options) ==> string](#org72f0ed8)
9. [fastPut(localPath, remotePath, options) ==> string](#orgef22916)
10. [append(input, remotePath, options) ==> string](#orgf632046)
11. [mkdir(path, recursive) ==> string](#org58685da)
12. [rmdir(path, recursive) ==> string](#org5e796c1)
13. [delete(path) ==> string](#orgdbe4c26)
14. [rename(fromPath, toPath) ==> string](#org269c68f)
15. [chmod(path, mode) ==> string](#org6779ad7)
16. [realPath(path) ===> string](#org40cf2d8)
17. [cwd() ==> string](#org725a728)
18. [uploadDir(srcDir, dstDir) ==> string](#orgae9657b)
19. [downloadDir(srcDir, dstDir) ==> string](#orgd222561)
20. [end() ==> boolean](#orge874563)
21. [Add and Remove Listeners](#org1dfc8a0)
6. [FAQ](#org3f4cd3f)
1. [Remote server drops connections with only an end event](#org1f7302e)
2. [How can you pass writable stream as dst for get method?](#org6e4ae33)
3. [How can I upload files without having to specify a password?](#orgc7ddd7b)
4. [How can I connect through a Socks Proxy](#orgd8d9681)
5. [Timeout while waiting for handshake or handshake errors](#orgbb36729)
7. [Examples](#orge55657d)
8. [Change Log](#orgbc833f6)
1. [v5.1.0 (Prod Version)](#org873e7dc)
2. [v5.0.2](#org23aa953)
3. [v5.0.1](#org512cca9)
4. [v5.0.0](#orgffe1d77)
5. [v4.3.1](#orgf1b1ab1)
6. [v4.3.0](#org25a4659)
7. [v4.2.4](#org5ea6cd7)
8. [v4.2.3](#org9dd805f)
9. [v4.2.2](#org1d5f037)
10. [v4.2.1](#orgfdf42ef)
11. [v4.2.0](#org1c700cb)
12. [v4.1.0](#org1349876)
13. [v4.0.4](#org8f40eff)
14. [v4.0.3](#orga5a2b24)
15. [v4.0.2](#orga51086a)
16. [v4.0.0](#org8912607)
17. [v2.5.2](#org69cd5a2)
18. [v2.5.1](#org22c1cfa)
19. [v2.5.0](#orge9fd1d9)
20. [v2.4.3](#orgc46f51e)
21. [v2.4.2](#orge36de5b)
22. [v2.4.1](#orgb05ccdc)
23. [v2.4.0](#org1720444)
24. [v2.3.0](#orgd9d6b14)
25. [v3.0.0 – deprecate this version](#orgaa07c2d)
26. [v2.1.1](#org2f15e75)
27. [v2.0.1](#org9c51b08)
28. [v1.1.0](#orgca16e6c)
29. [v1.0.5:](#org9995b3c)
9. [Troubleshooting](#orgcc9e37c)
1. [Debugging Support](#org668ad1e)
10. [Logging Issues](#orgde016a7)
11. [Pull Requests](#orga4e4a57)
12. [Contributors](#org6b3cc00)
<a id="org59926bb"></a>
<a id="org71b320d"></a>

@@ -90,3 +93,3 @@ # SSH2 SFTP Client

Current stable release is **v5.0.2**.
Current stable release is **v5.1.0**.

@@ -98,3 +101,3 @@ Code has been tested against Node versions 10.18.1, 12.14.1 and 13.6.0

<a id="orgfa12105"></a>
<a id="orgc904404"></a>

@@ -106,3 +109,3 @@ # Installation

<a id="orgdcb4ac8"></a>
<a id="orgb7288c2"></a>

@@ -113,3 +116,3 @@ # Basic Usage

let sftp = new Client();
sftp.connect({

@@ -129,3 +132,3 @@ host: '127.0.0.1',

<a id="orgb1a2c3d"></a>
<a id="org117386b"></a>

@@ -135,3 +138,3 @@ # Version 5.x

<a id="org50ff9f1"></a>
<a id="orgaf9ad42"></a>

@@ -165,3 +168,3 @@ ## Breaking Changes in Version 5.x

<a id="orgbc36ac2"></a>
<a id="orgb01e3b7"></a>

@@ -173,3 +176,3 @@ ### Error Event Handling

events to communicate various state changes and error conditions. These
events can fire at any time.
events can fire at any time.

@@ -183,3 +186,3 @@ On the client side, we wrap basic SFTP actions in Javascript Promises,

downloaded or rejected, indicating the download failed. All pretty
straight-forward.
straight-forward.

@@ -193,3 +196,3 @@ When the Promise is created, an error event handler is added to the SFTP

a promise can only be resolved or rejected once, after the Promise has
completed, the error listener is of no further use.
completed, the error listener is of no further use.

@@ -214,3 +217,3 @@ This all works fine when an error event fires during the execution of a

try/catch block around the SFTP client object. Basically, there is nothing
listening of any errors at this point. What will happen?
listening of any errors at this point. What will happen?

@@ -220,3 +223,3 @@ Well, basically, the error event will bubble up to the top level of the node

dump a stack trace and cause the node process to exit. In basic terms, your
process will crash. Not a great outcome.
process will crash. Not a great outcome.

@@ -250,3 +253,3 @@ There are a number of things we can do to improve the situation. However,

attempts to use the connection will throw an error inside the Promise which
attempts to use it.
attempts to use it.

@@ -265,6 +268,6 @@ The advantage of this approach is that it stops the abrupt exiting of the

want to end, then you can just ignore the error, perform any necessary
cleanup work and exit successfully.
cleanup work and exit successfully.
<a id="orgdc9ce74"></a>
<a id="org1ae0a28"></a>

@@ -276,3 +279,3 @@ ### Technical Details

which may be defined. As part of the processing, these error handler set a flag
property `this.errorHandled` to true, indicating the error has been handled.
property `this.errorHandled` to true, indicating the error has been handled.

@@ -287,6 +290,6 @@ In addition to the Promise error handlers, there is a default error handler

further attempts to use it and finally, ensure the `this.errorHandler` flag is
reset to false in preparation for the next error.
reset to false in preparation for the next error.
<a id="org2dd8843"></a>
<a id="orgc8305e8"></a>

@@ -307,3 +310,3 @@ ## New Methods

<a id="orge044fce"></a>
<a id="orgc2e0e38"></a>

@@ -318,3 +321,3 @@ ## Version 5.0.1

<a id="org7ccd57d"></a>
<a id="org677cda9"></a>

@@ -328,4 +331,17 @@ ## Version 5.0.2

<a id="org050dbca"></a>
<a id="orgb363dc7"></a>
## Version 5.1.0
- Add missing connection check in end() method
- Add debugging support. Now adding a debug property to the connection
configuration object will enable debugging. The value of the debug property
should be a function which accepts a single string argument. Typically,
this function will send the value passed in to stderr or a file.
- Fix bug in checkRemotePath() relating to poor path specifications where
you cannot determine parent directory.
<a id="org46b5997"></a>
# Documentation

@@ -340,19 +356,25 @@

<a id="org899b50f"></a>
<a id="orga935b97"></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).
All remote paths must either be absolute e.g. `/absolute/path/to/file` or they
can be relative with a prefix of either `./` (relative to current remote
directory) or `../` (relative to parent of current remote directory) e.g.
`./relative/path/to/file` or `../relative/to/parent/file`. It is also possible
to do things like `../../../file` to specify the parent of the parent of the
parent of the current remote directory. The shell tilde (`~`) and common
environment variables like `$HOME` are NOT supported.
It is important to recognise that the current remote directory may not always be
what you may expect. A lot will depend on the remote platform of the SFTP server
and how the SFTP server has been configured. When things don't seem to be
working as expected, it is often a good idea to verify your assumptions
regarding the remote directory and remote paths. One way to do this is to login
using a command line program like `sftp` or `lftp`.
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.
robust.

@@ -379,3 +401,3 @@ When specifying file paths, ensure to include a full path i.e. include the

<a id="orgb3c2cb6"></a>
<a id="org98305c1"></a>

@@ -385,3 +407,3 @@ ## Methods

<a id="org99655e8"></a>
<a id="org13f62cb"></a>

@@ -401,5 +423,5 @@ ### new SftpClient(name) ===> SFTP client object

'use strict';
const Client = require('ssh2-sftp-client');
const config = {

@@ -410,5 +432,5 @@ host: 'example.com',

};
const sftp = new Client('example-client');
sftp.connect(config)

@@ -427,3 +449,3 @@ .then(() => {

<a id="org29a9aa8"></a>
<a id="orgd1717c5"></a>

@@ -442,3 +464,3 @@ ### connect(config) ===> SFTPstream

the minimum needed and stick to the options listed in the `commonOpts` below.
The `retries`, `retry_factor` and `retry_minTimeout` options are not part of the

@@ -448,5 +470,5 @@ SSH2 module. These are part of the configuration for the [retry](https://www.npmjs.com/package/retry) package and what

for that package for an explanation of these values.
// common options
let commonOpts {

@@ -465,3 +487,3 @@ host: 'localhost', // string Hostname or IP of server.

debug: myDebug // function - Set this to a function that receives a single
// string argument to get detailed (local) debug information.
// string argument to get detailed (local) debug information.
retries: 2 // integer. Number of times to retry connecting

@@ -471,5 +493,5 @@ retry_factor: 2 // integer. Time factor used to calculate time between retries

};
// rarely used options
let advancedOpts {

@@ -502,3 +524,3 @@ localAddress,

<a id="org28fc220"></a>
<a id="org7ba4acf"></a>

@@ -519,3 +541,3 @@ ### list(path, pattern) ==> Array[object]

const Client = require('ssh2-sftp-client');
const config = {

@@ -527,5 +549,5 @@ host: 'example.com',

};
let sftp = new Client;
sftp.connect(config)

@@ -548,3 +570,3 @@ .then(() => {

The objects in the array returned by `list()` have the following properties;
{

@@ -569,7 +591,7 @@ type: // file type(-, d, l)

simple *glob*-like string where \* will match any number of characters, e.g.
foo* => foo, foobar, foobaz
*bar => bar, foobar, tabbar
*oo* => foo, foobar, look, book
The *glob*-style matching is very simple. In most cases, you are best off using

@@ -580,3 +602,3 @@ a real regular expression which will allow you to do more powerful matching and

<a id="org9bbdfd9"></a>
<a id="orgdfefb95"></a>

@@ -591,3 +613,3 @@ ### exists(path) ==> boolean

const Client = require('ssh2-sftp-client');
const config = {

@@ -599,5 +621,5 @@ host: 'example.com',

};
let sftp = new Client;
sftp.connect(config)

@@ -618,3 +640,3 @@ .then(() => {

<a id="org9ae7824"></a>
<a id="orgc98fc30"></a>

@@ -630,3 +652,3 @@ ### stat(path) ==> object

The `stat()` method returns an object with the following properties;
let stats = {

@@ -651,3 +673,3 @@ mode: 33279, // integer representing type and permissions

let client = new Client();
client.connect(config)

@@ -668,3 +690,3 @@ .then(() => {

<a id="org1608509"></a>
<a id="org71ac9c4"></a>

@@ -693,3 +715,3 @@ ### get(path, dst, options) ==> String|Stream|Buffer

to read the data from the remote server.
{

@@ -702,3 +724,3 @@ flags: 'r',

}
Most of the time, you won't want to use any options. Sometimes, it may be useful

@@ -711,6 +733,6 @@ to set the encoding. For example, to 'utf-8'. However, it is important not to do

let client = new Client();
let remotePath = '/remote/server/path/file.txt';
let dst = fs.createWriteStream('/local/file/path/copy.txt');
client.connect(config)

@@ -726,3 +748,3 @@ .then(() => {

});
- **Tip:** See examples file in the Git repository for more examples. You can pass

@@ -734,3 +756,3 @@ any writeable stream in as the destination. For example, if you pass in

<a id="org9e40286"></a>
<a id="org0ba08cd"></a>

@@ -754,5 +776,5 @@ ### fastGet(remotePath, localPath, options) ===> string

step: function(total_transferred, chunk, total) // callback called each time a
// chunk is transferred
// chunk is transferred
}
- **Warning:** Some servers do not respond correctly to requests to alter chunk

@@ -766,3 +788,3 @@ size. This can result in lost or corrupted data.

let localPath = '/local/path/file.txt';
client.connect(config)

@@ -780,3 +802,3 @@ .then(() => {

<a id="org21a04fa"></a>
<a id="org72f0ed8"></a>

@@ -800,3 +822,3 @@ ### put(src, remotePath, options) ==> string

The following options are supported;
{

@@ -808,3 +830,3 @@ flags: 'w', // w - write and a - append

}
The most common options to use are mode and encoding. The values shown above are

@@ -818,6 +840,6 @@ the defaults. You do not have to set encoding to utf-8 for text files, null is

let client = new Client();
let data = fs.createReadStream('/path/to/local/file.txt');
let remote = '/path/to/remote/file.txt';
client.connect(config)

@@ -833,7 +855,7 @@ .then(() => {

});
- **Tip:** If the src argument is a path string, consider just using `fastPut()`.
<a id="orgccbc75b"></a>
<a id="orgef22916"></a>

@@ -858,3 +880,3 @@ ### fastPut(localPath, remotePath, options) ==> string

}
- **Warning:** There have been reports that some SFTP servers will not honour

@@ -869,3 +891,3 @@ requests for non-default chunk sizes. This can result in data loss

let client = new Client();
client.connect(config)

@@ -883,3 +905,3 @@ .then(() => {

<a id="org37e8a28"></a>
<a id="orgf632046"></a>

@@ -900,3 +922,3 @@ ### append(input, remotePath, options) ==> string

The following options are supported;
{

@@ -908,3 +930,3 @@ flags: 'a', // w - write and a - append

}
The most common options to use are mode and encoding. The values shown above are

@@ -918,3 +940,3 @@ the defaults. You do not have to set encoding to utf-8 for text files, null is

let client = new Client();
client.connect(config)

@@ -932,3 +954,3 @@ .then(() => {

<a id="orgc976219"></a>
<a id="org58685da"></a>

@@ -949,3 +971,3 @@ ### mkdir(path, recursive) ==> string

let client = new Client();
client.connect(config)

@@ -963,3 +985,3 @@ .then(() => {

<a id="orga51f516"></a>
<a id="org5e796c1"></a>

@@ -981,3 +1003,3 @@ ### rmdir(path, recursive) ==> string

let client = new Client();
client.connect(config)

@@ -995,3 +1017,3 @@ .then(() => {

<a id="org29f1cd8"></a>
<a id="orgdbe4c26"></a>

@@ -1008,3 +1030,3 @@ ### delete(path) ==> string

let client = new Client();
client.connect(config)

@@ -1022,3 +1044,3 @@ .then(() => {

<a id="orgf371df6"></a>
<a id="org269c68f"></a>

@@ -1035,3 +1057,3 @@ ### rename(fromPath, toPath) ==> string

let client = new Client();
client.connect(config)

@@ -1049,3 +1071,3 @@ .then(() => {

<a id="org0ea3423"></a>
<a id="org6779ad7"></a>

@@ -1065,3 +1087,3 @@ ### chmod(path, mode) ==> string

let client = new Client();
client.connect(config)

@@ -1079,3 +1101,3 @@ .then(() => {

<a id="org17fe515"></a>
<a id="org40cf2d8"></a>

@@ -1085,4 +1107,4 @@ ### realPath(path) ===> string

Converts a relative path to an absolute path on the remote server. This method
is mainly used internally to resolve remote path names. Returns '' if the
path is not valid.
is mainly used internally to resolve remote path names. Returns '' if the
path is not valid.

@@ -1093,3 +1115,3 @@ - **path:** A file path, either relative or absolute. Can handle '.' and '..', but

<a id="org8ba0584"></a>
<a id="org725a728"></a>

@@ -1101,3 +1123,3 @@ ### cwd() ==> string

<a id="orgf015b8f"></a>
<a id="orgae9657b"></a>

@@ -1117,3 +1139,3 @@ ### uploadDir(srcDir, dstDir) ==> string

client code to get feedback on the upload progress. You can add your own lisener
using the `on()` method.
using the `on()` method.

@@ -1125,48 +1147,48 @@ - **srcDir:** A local file path specified as a string

'use strict';
// Example of using the uploadDir() method to upload a directory
// to a remote SFTP server
const path = require('path');
const SftpClient = require('../src/index');
const dotenvPath = path.join(__dirname, '..', '.env');
require('dotenv').config({path: dotenvPath});
const config = {
host: process.env.SFTP_SERVER,
username: process.env.SFTP_USER,
password: process.env.SFTP_PASSWORD,
port: process.env.SFTP_PORT || 22
};
async function main() {
const client = new SftpClient('upload-test');
const src = path.join(__dirname, '..', 'test', 'testData', 'upload-src');
const dst = '/home/tim/upload-test';
try {
await client.connect(config);
client.on('upload', info => {
console.log(`Listener: Uploaded ${info.source}`);
});
let rslt = await client.uploadDir(src, dst);
return rslt;
} finally {
client.end();
}
'use strict';
// Example of using the uploadDir() method to upload a directory
// to a remote SFTP server
const path = require('path');
const SftpClient = require('../src/index');
const dotenvPath = path.join(__dirname, '..', '.env');
require('dotenv').config({path: dotenvPath});
const config = {
host: process.env.SFTP_SERVER,
username: process.env.SFTP_USER,
password: process.env.SFTP_PASSWORD,
port: process.env.SFTP_PORT || 22
};
async function main() {
const client = new SftpClient('upload-test');
const src = path.join(__dirname, '..', 'test', 'testData', 'upload-src');
const dst = '/home/tim/upload-test';
try {
await client.connect(config);
client.on('upload', info => {
console.log(`Listener: Uploaded ${info.source}`);
});
let rslt = await client.uploadDir(src, dst);
return rslt;
} finally {
client.end();
}
main()
.then(msg => {
console.log(msg);
})
.catch(err => {
console.log(`main error: ${err.message}`);
});
}
main()
.then(msg => {
console.log(msg);
})
.catch(err => {
console.log(`main error: ${err.message}`);
});
<a id="org0c10cb8"></a>
<a id="orgd222561"></a>
### downloadDir(srcDir, dstDir) ==> string

@@ -1178,3 +1200,3 @@

files in the local path will be overwritten. No files in the local path will be
deleted.
deleted.

@@ -1186,3 +1208,3 @@ The method also emites `download` events to provide a way to monitor download

to where the file was downloaded to. You can add a listener for this event using
the `on()` method.
the `on()` method.

@@ -1195,12 +1217,12 @@ - **srcDir:** A remote file path specified as a string

'use strict';
// Example of using the downloadDir() method to upload a directory
// to a remote SFTP server
const path = require('path');
const SftpClient = require('../src/index');
const dotenvPath = path.join(__dirname, '..', '.env');
require('dotenv').config({path: dotenvPath});
const config = {

@@ -1212,3 +1234,3 @@ host: process.env.SFTP_SERVER,

};
async function main() {

@@ -1218,7 +1240,7 @@ const client = new SftpClient('upload-test');

const src = '/home/tim/upload-test';
try {
await client.connect(config);
client.on('download', info => {
console.log(`Listener: Download ${info.source}`);
console.log(`Listener: Download ${info.source}`);
});

@@ -1231,3 +1253,3 @@ let rslt = await client.downloadDir(src, dst);

}
main()

@@ -1242,3 +1264,3 @@ .then(msg => {

<a id="org936ae21"></a>
<a id="orge874563"></a>

@@ -1253,3 +1275,3 @@ ### end() ==> boolean

let client = new Client();
client.connect(config)

@@ -1267,3 +1289,3 @@ .then(() => {

<a id="org15a9c85"></a>
<a id="org1dfc8a0"></a>

@@ -1294,3 +1316,3 @@ ### Add and Remove Listeners

<a id="orgc79f3d2"></a>
<a id="org3f4cd3f"></a>

@@ -1300,3 +1322,3 @@ # FAQ

<a id="org8c068da"></a>
<a id="org1f7302e"></a>

@@ -1331,3 +1353,3 @@ ## Remote server drops connections with only an end event

<a id="org06acfd2"></a>
<a id="org6e4ae33"></a>

@@ -1348,7 +1370,7 @@ ## How can you pass writable stream as dst for get method?

'use strict';
// Example of using a writeable with get to retrieve a file.
// This code will read the remote file, convert all characters to upper case
// and then save it to a local file
const Client = require('../src/index.js');

@@ -1358,3 +1380,3 @@ const path = require('path');

const through = require('through2');
const config = {

@@ -1366,6 +1388,6 @@ host: 'arch-vbox',

};
const sftp = new Client();
const remoteDir = '/home/tim/testServer';
function toupper() {

@@ -1376,3 +1398,3 @@ return through(function(buf, enc, next) {

}
sftp

@@ -1400,3 +1422,3 @@ .connect(config)

<a id="orgcd6ac49"></a>
<a id="orgc7ddd7b"></a>

@@ -1436,3 +1458,3 @@ ## How can I upload files without having to specify a password?

<a id="orga601cc9"></a>
<a id="orgd8d9681"></a>

@@ -1445,6 +1467,6 @@ ## How can I connect through a Socks Proxy

import SFTPClient from 'ssh2-sftp-client';
const host = 'my-sftp-server.net';
const port = 22; // default SSH/SFTP port on remote server
// connect to SOCKS 5 proxy

@@ -1460,3 +1482,3 @@ const { socket } = await SocksClient.createConnection({

});
const client = new SFTPClient();

@@ -1469,7 +1491,7 @@ client.connect({

})
// client is connected
<a id="orgb9d4439"></a>
<a id="orgbb36729"></a>

@@ -1486,6 +1508,6 @@ ## Timeout while waiting for handshake or handshake errors

documentation for details. Getting these parameters correct usually resolves the
issue.
issue.
<a id="org5c46982"></a>
<a id="orge55657d"></a>

@@ -1498,6 +1520,6 @@ # Examples

handling and may contain errors. However, I think they are still useful for
helping developers see how the module and API can be used.
helping developers see how the module and API can be used.
<a id="org39062e6"></a>
<a id="orgbc833f6"></a>

@@ -1507,6 +1529,17 @@ # Change Log

<a id="orga3081db"></a>
<a id="org873e7dc"></a>
## v5.0.2 (Prod Version)
## v5.1.0 (Prod Version)
- Fix bug in checkRemotePath() relating to handling of badly
specified paths (issue #213)
- Added additional debugging support
- Add missing test for valid connection in end() method.
- Bump ssh2 version to v0.8.8
<a id="org23aa953"></a>
## v5.0.2
- Fix bugs related to win32 platform and local tests for valid directories

@@ -1516,11 +1549,11 @@ - Fix problem with parsing of file paths

<a id="org5c223c2"></a>
<a id="org512cca9"></a>
## v5.0.1
- Turn down error checking to be less stringent and handle situations
- Turn down error checking to be less stringent and handle situations
where user does not have read permission on parent directory.
<a id="orgc1ea505"></a>
<a id="orgffe1d77"></a>

@@ -1544,3 +1577,3 @@ ## v5.0.0

<a id="org9674bc2"></a>
<a id="orgf1b1ab1"></a>

@@ -1555,3 +1588,3 @@ ## v4.3.1

<a id="org9fdf4b5"></a>
<a id="org25a4659"></a>

@@ -1566,3 +1599,3 @@ ## v4.3.0

<a id="org7ed824b"></a>
<a id="org5ea6cd7"></a>

@@ -1576,3 +1609,3 @@ ## v4.2.4

<a id="orgd3028bd"></a>
<a id="org9dd805f"></a>

@@ -1586,3 +1619,3 @@ ## v4.2.3

<a id="org2ac3d75"></a>
<a id="org1d5f037"></a>

@@ -1595,3 +1628,3 @@ ## v4.2.2

<a id="orgcd4e9e2"></a>
<a id="orgfdf42ef"></a>

@@ -1610,3 +1643,3 @@ ## v4.2.1

<a id="org199764b"></a>
<a id="org1c700cb"></a>

@@ -1622,3 +1655,3 @@ ## v4.2.0

<a id="org10bedf8"></a>
<a id="org1349876"></a>

@@ -1640,3 +1673,3 @@ ## v4.1.0

<a id="org0962876"></a>
<a id="org8f40eff"></a>

@@ -1649,3 +1682,3 @@ ## v4.0.4

<a id="org3d4fa37"></a>
<a id="orga5a2b24"></a>

@@ -1658,3 +1691,3 @@ ## v4.0.3

<a id="orgeebc8d6"></a>
<a id="orga51086a"></a>

@@ -1666,3 +1699,3 @@ ## v4.0.2

<a id="org5d18cf9"></a>
<a id="org8912607"></a>

@@ -1685,3 +1718,3 @@ ## v4.0.0

<a id="orgbc22ad1"></a>
<a id="org69cd5a2"></a>

@@ -1694,3 +1727,3 @@ ## v2.5.2

<a id="org2f89ba7"></a>
<a id="org22c1cfa"></a>

@@ -1702,3 +1735,3 @@ ## v2.5.1

<a id="orgb8683aa"></a>
<a id="orge9fd1d9"></a>

@@ -1710,3 +1743,3 @@ ## v2.5.0

<a id="org8c37fb0"></a>
<a id="orgc46f51e"></a>

@@ -1719,3 +1752,3 @@ ## v2.4.3

<a id="orgbe5c717"></a>
<a id="orge36de5b"></a>

@@ -1728,3 +1761,3 @@ ## v2.4.2

<a id="orgeeb9805"></a>
<a id="orgb05ccdc"></a>

@@ -1737,3 +1770,3 @@ ## v2.4.1

<a id="orgbd36319"></a>
<a id="org1720444"></a>

@@ -1751,3 +1784,3 @@ ## v2.4.0

<a id="orgf07ea36"></a>
<a id="orgd9d6b14"></a>

@@ -1761,3 +1794,3 @@ ## v2.3.0

<a id="org95d7555"></a>
<a id="orgaa07c2d"></a>

@@ -1770,3 +1803,3 @@ ## v3.0.0 &#x2013; deprecate this version

<a id="orgcca455a"></a>
<a id="org2f15e75"></a>

@@ -1779,3 +1812,3 @@ ## v2.1.1

<a id="orga11176a"></a>
<a id="org9c51b08"></a>

@@ -1790,3 +1823,3 @@ ## v2.0.1

<a id="orgc33c477"></a>
<a id="orgca16e6c"></a>

@@ -1798,3 +1831,3 @@ ## v1.1.0

<a id="orgb12a992"></a>
<a id="org9995b3c"></a>

@@ -1807,3 +1840,3 @@ ## v1.0.5:

<a id="orgd779dc4"></a>
<a id="orgcc9e37c"></a>

@@ -1821,3 +1854,3 @@ # Troubleshooting

to those later 2 modules and therefore and issue which should be referred to the
maintainer of that module.
maintainer of that module.

@@ -1832,3 +1865,3 @@ The `ssh2` and `ssh2-streams` modules are very solid, high quality modules with

documentation for both the `ssh2` and `ssh2-streams` module is quite
comprehensive and there is lots of valuable information in the issue logs.
comprehensive and there is lots of valuable information in the issue logs.

@@ -1842,3 +1875,3 @@ If you run into an issue which is not repeatable with just the `ssh2` and

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.
additional bit of detail to help fix any problems you are encountering.

@@ -1849,7 +1882,26 @@ The second directory is the tools directory. I have some very basic simple

trying to determine if the issue is with the underlying `ssh2` and
`ssh2-streams` modules.
`ssh2-streams` modules.
<a id="orgfe3d18c"></a>
<a id="org668ad1e"></a>
## Debugging Support
You can add a `debug` property to the config object passed in to `connect()` to
turn on debugging. This will generate quite a lot of output. The value of the
property should be a function which accepts a single string argument. For example;
config.debug = msg => {
console.error(msg);
};
Enabling debugging can generate a lot of output. If you use console.error() as
the output (as in the example above), you can redirect the output to a file
using shell redirection e.g.
node script.js 2> debug.log
<a id="orgde016a7"></a>
# Logging Issues

@@ -1875,6 +1927,6 @@

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.
the issue can be readily reproduced, it can usually be fixed very quickly.
<a id="orgd60ef19"></a>
<a id="orga4e4a57"></a>

@@ -1899,3 +1951,3 @@ # Pull Requests

<a id="orgf30aa6b"></a>
<a id="org6b3cc00"></a>

@@ -1913,2 +1965,1 @@ # Contributors

- **waldyrious:** Documentation fixes

@@ -24,4 +24,17 @@ /**

this.errorHandled = false;
this.debug = undefined;
}
debugMsg(msg, obj) {
if (this.debug) {
if (obj) {
this.debug(
`CLIENT[${this.clientName}]: ${msg} ${JSON.stringify(obj, null, ' ')}`
);
} else {
this.debug(`CLIENT[${this.clientName}]: ${msg}`);
}
}
}
/**

@@ -37,2 +50,3 @@ * Add a listner to the client object. This is rarely necessary and can be

on(eventType, callback) {
this.debugMsg(`Adding listener to ${eventType}`);
this.client.on(eventType, callback);

@@ -42,2 +56,3 @@ }

removeListener(eventType, callback) {
this.debugMsg(`Removing listener from ${eventType}`);
this.client.removeListener(eventType, callback);

@@ -72,5 +87,9 @@ }

// remove the listeners and try again
this.debugMsg(
`Connection attempt ${attemptCount} failed. Trying again.`
);
return;
}
// exhausted retries - do callback with error
this.debugMsg('Exhausted all connection attempts. Giving up');
callback(

@@ -98,2 +117,3 @@ utils.formatError(err, 'connect', err.code, attemptCount),

}
this.debugMsg('SFTP connection established');
this.sftp = sftp;

@@ -133,2 +153,6 @@ // remove retry error listener and add generic error listener

} else {
if (config.debug) {
this.debug = config.debug;
this.debug('Debugging turned on');
}
retryConnect(config, (err, sftp) => {

@@ -151,5 +175,7 @@ if (err) {

this.remotePlatform = 'unix';
this.debugMsg('Remote platform unix like');
} else {
this.remotePathSep = '\\';
this.remotePlatform = 'windows';
this.debugMsg('remote platform windows like');
}

@@ -182,2 +208,3 @@ resolve(sftp);

try {
this.debugMsg(`realPath -> ${remotePath}`);
errorListener = utils.makeErrorListener(reject, this, 'realPath');

@@ -188,2 +215,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`realPath Error: ${err.message} Code: ${err.code}`);
if (err.code === 2) {

@@ -201,2 +229,3 @@ resolve('');

}
this.debugMsg(`realPath <- ${absPath}`);
resolve(absPath);

@@ -226,2 +255,3 @@ });

try {
this.debugMsg(`stat -> ${aPath}`);
errorListener = utils.makeErrorListener(reject, this, 'stat');

@@ -231,2 +261,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`stat error ${err.message} code: ${err.code}`);
if (err.code === 2) {

@@ -246,2 +277,3 @@ reject(

} else {
this.debugMsg('stats <- ', stats);
resolve({

@@ -298,3 +330,5 @@ mode: stats.mode,

try {
this.debugMsg(`exists -> ${absPath}`);
let info = await this.stat(absPath);
this.debugMsg('exists <- ', info);
if (info.isDirectory) {

@@ -345,2 +379,3 @@ return 'd';

try {
this.debugMsg(`list -> ${aPath} filter -> ${filter}`);
errorListener = utils.makeErrorListener(reject, this, 'list');

@@ -350,4 +385,6 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`list error ${err.message} code: ${err.code}`);
reject(utils.formatError(`${err.message} ${aPath}`, '_list'));
} else {
this.debugMsg('list <- ', fileList);
let newList = [];

@@ -426,2 +463,3 @@ // reset file info

try {
this.debugMsg(`get -> ${sftpPath} `, options);
errorListener = utils.makeErrorListener(reject, this, 'get');

@@ -436,2 +474,3 @@ this.client.prependListener('error', errorListener);

// no dst specified, return buffer of data
this.debugMsg('get returning buffer of data');
let concatStream = concat(buff => {

@@ -446,4 +485,6 @@ rdr.removeAllListeners('error');

// dst local file path
this.debugMsg('get returning local file');
wtr = fs.createWriteStream(localDst);
} else {
this.debugMsg('get returning data into supplied stream');
wtr = localDst;

@@ -483,2 +524,3 @@ }

);
this.debugMsg('get remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -490,2 +532,3 @@ let e = utils.formatError(pathInfo.msg, 'get', pathInfo.code);

let localInfo = await utils.checkLocalPath(dst, targetType.writeFile);
this.debugMsg('get local path info ', localInfo);
if (localInfo.valid) {

@@ -522,2 +565,3 @@ dst = localInfo.path;

try {
this.debugMsg(`fastGet -> ${from} ${to} `, opts);
errorListener = utils.makeErrorListener(reject, this, 'fastGet');

@@ -527,2 +571,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`fastGet error ${err.message} code: ${err.code}`);
reject(

@@ -550,2 +595,3 @@ utils.formatError(

);
this.debugMsg('fastGet remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -559,2 +605,3 @@ let e = utils.formatError(pathInfo.msg, 'fastGet', pathInfo.code);

);
this.debugMsg('fastGet local path info ', localInfo);
if (!localInfo.valid) {

@@ -592,2 +639,3 @@ let e = utils.formatError(

try {
this.debugMsg(`fastPut -> ${localPath} ${remotePath} `, opts);
errorListener = utils.makeErrorListener(reject, this, 'fastPut');

@@ -597,2 +645,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`fastPut error ${err.message} ${err.code}`);
reject(

@@ -616,2 +665,3 @@ utils.formatError(

let localInfo = await utils.checkLocalPath(localPath);
this.debugMsg('fastPut local path info ', localInfo);
if (!localInfo.valid) {

@@ -626,2 +676,3 @@ let e = utils.formatError(localInfo.msg, 'fastPut', localInfo.code);

);
this.debugMsg('fastPut remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -653,2 +704,3 @@ let e = utils.formatError(pathInfo.msg, 'fastPut', pathInfo.code);

try {
this.debugMsg(`put -> ${dst} `, opts);
errorListener = utils.makeErrorListener(reject, this, 'put');

@@ -665,2 +717,3 @@ this.client.prependListener('error', errorListener);

if (src instanceof Buffer) {
this.debugMsg('put source is a buffer');
stream.end(src);

@@ -670,4 +723,6 @@ } else {

if (typeof src === 'string') {
this.debugMsg(`put source is a file path: ${src}`);
rdr = fs.createReadStream(src);
} else {
this.debugMsg('put source is a stream');
rdr = src;

@@ -698,2 +753,3 @@ }

let localInfo = await utils.checkLocalPath(localSrc);
this.debugMsg('put local path info ', localInfo);
if (!localInfo.valid) {

@@ -710,2 +766,3 @@ let e = utils.formatError(localInfo.msg, 'put', localInfo.code);

);
this.debugMsg('put remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -734,2 +791,3 @@ let e = utils.formatError(pathInfo.msg, 'put', pathInfo.code);

try {
this.debugMsg(`append -> ${aPath} `, opts);
errorListener = utils.makeErrorListener(reject, this, 'append');

@@ -781,2 +839,3 @@ this.client.prependListener('error', errorListener);

);
this.debugMsg('append remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -815,2 +874,3 @@ let e = utils.formatError(pathInfo.msg, 'append', pathInfo.code);

try {
this.debugMsg(`mkdir -> ${p}`);
errorListener = utils.makeErrorListener(reject, this, 'mkdir');

@@ -820,2 +880,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`mkdir error ${err.message} code: ${err.code}`);
reject(

@@ -840,2 +901,3 @@ utils.formatError(`${err.message} ${p}`, '_mkdir', err.code)

);
this.debugMsg('mkdir remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -852,2 +914,3 @@ throw utils.formatError(pathInfo.msg, 'mkdir', pathInfo.code);

let parent = await utils.checkRemotePath(this, dir, targetType.writeDir);
this.debugMsg('mkdir parent path info ', parent);
if (parent.valid && !parent.type) {

@@ -877,2 +940,3 @@ await this.mkdir(dir, true);

try {
this.debugMsg(`rmdir -> ${p}`);
errorListener = utils.makeErrorListener(reject, this, 'rmdir');

@@ -882,2 +946,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`rmdir error ${err.message} code: ${err.code}`);
reject(

@@ -902,2 +967,3 @@ utils.formatError(`${err.message} ${p}`, '_rmdir', err.code)

);
this.debugMsg('rmdir remoe path info ', pathInfo);
if (!pathInfo.valid) {

@@ -914,2 +980,4 @@ let e = utils.formatError(pathInfo.msg, 'rmdir', pathInfo.code);

let dirs = list.filter(item => item.type === 'd');
this.debugMsg('rmdir contents (files): ', files);
this.debugMsg('rmdir contents (dirs): ', dirs);
for (let f of files) {

@@ -942,2 +1010,3 @@ await this.delete(pathInfo.path + this.remotePathSep + f.name);

try {
this.debugMsg(`delete -> ${p}`);
errorListener = utils.makeErrorListener(reject, this, 'delete');

@@ -947,2 +1016,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`delete error ${err.message} code: ${err.code}`);
reject(

@@ -967,2 +1037,3 @@ utils.formatError(`${err.message} ${p}`, '_delete', err.code)

);
this.debugMsg('delete remote path info ', pathInfo);
if (!pathInfo.valid) {

@@ -994,2 +1065,3 @@ let e = utils.formatError(pathInfo.msg, 'delete', pathInfo.code);

try {
this.debugMsg(`rename -> ${from} ${to}`);
errorListener = utils.makeErrorListener(reject, this, 'rename');

@@ -999,2 +1071,3 @@ this.client.prependListener('error', errorListener);

if (err) {
this.debugMsg(`rename error ${err.message} code: ${err.code}`);
reject(

@@ -1022,2 +1095,3 @@ utils.formatError(

);
this.debugMsg('rename from path info ', fromInfo);
if (!fromInfo.valid) {

@@ -1032,2 +1106,3 @@ let e = utils.formatError(fromInfo.msg, 'rename', fromInfo.code);

);
this.debugMsg('rename to path info ', toInfo);
if (toInfo.type) {

@@ -1070,2 +1145,3 @@ let e = utils.formatError(

try {
this.debugMsg(`chmod -> ${p} ${m}`);
errorListener = utils.makeErrorListener(reject, this, 'chmod');

@@ -1092,2 +1168,3 @@ this.client.prependListener('error', errorListener);

);
this.debugMsg('chmod path info ', pathInfo);
if (!pathInfo.valid) {

@@ -1116,2 +1193,3 @@ let e = utils.formatError(pathInfo.msg, 'chmod', pathInfo.code);

try {
this.debugMsg(`uploadDir -> ${srcDir} ${dstDir}`);
utils.haveConnection(this, 'uploadDir');

@@ -1123,2 +1201,3 @@ let localInfo = await utils.checkLocalPath(srcDir, targetType.readDir);

}
this.debugMsg('uploadDir local path info ', localInfo);
let remoteInfo = await utils.checkRemotePath(

@@ -1129,2 +1208,3 @@ this,

);
this.debugMsg('uploadDir remote path info ', remoteInfo);
if (!remoteInfo.valid) {

@@ -1163,2 +1243,3 @@ let e = utils.formatError(remoteInfo.msg, 'uploadDir', remoteInfo.code);

try {
this.debugMsg(`downloadDir -> ${srcDir} ${dstDir}`);
utils.haveConnection(this, 'downloadDir');

@@ -1170,2 +1251,3 @@ let remoteInfo = await utils.checkRemotePath(

);
this.debugMsg('downloadDir remote path info ', remoteInfo);
if (!remoteInfo.valid) {

@@ -1180,2 +1262,3 @@ let e = utils.formatError(

let localInfo = await utils.checkLocalPath(dstDir, targetType.writeDir);
this.debugMsg('downloadDir lcoal path info ', localInfo);
if (localInfo.valid && !localInfo.type) {

@@ -1218,2 +1301,3 @@ fs.mkdirSync(localInfo.path, {recursive: true});

try {
utils.haveConnection(this, 'end');
this.client.prependListener('error', err => {

@@ -1220,0 +1304,0 @@ // we don't care about errors at this point

@@ -480,2 +480,11 @@ 'use strict';

let parentDir = path.parse(aPath).dir;
if (!parentDir) {
return {
path: aPath,
type: false,
valid: false,
msg: `Bad path: ${aPath} cannot determine parent directory`,
code: errorCode.badPath
};
}
let parentType = await client.exists(parentDir);

@@ -523,2 +532,11 @@ if (!parentType) {

let parentDir = path.parse(aPath).dir;
if (!parentDir) {
return {
path: aPath,
type: false,
valid: false,
msg: `Bad path: ${aPath} cannot determine directory parent`,
code: errorCode.badPath
};
}
let parentType = await client.exists(parentDir);

@@ -525,0 +543,0 @@ if (parentType && parentType !== 'd') {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc