Socket
Socket
Sign inDemoInstall

ssh2-sftp-client

Package Overview
Dependencies
16
Maintainers
2
Versions
73
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.1.0 to 4.2.0

4

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

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

"name": "见见 (original author)",
"email": "jyu213@gmail.com"
"email": "jyu213@gmail.com"
}

@@ -25,0 +25,0 @@ ],

# Table of Contents
1. [SSH2 SFTP Client](#org43ca01c)
2. [Installation](#org85ec107)
3. [Basic Usage](#org7ca5e28)
4. [Breaking Changes in Version 4.x](#org11186bf)
5. [Enhancements in Version 4.1.x](#orge5f7732)
6. [Documentation](#org8b8cd18)
1. [Methods](#org820f1d6)
1. [connect(config) ===> SFTPstream](#org83fbd25)
2. [list(path, pattern) ==> Array[object]](#org2871c47)
3. [exists(path) ==> boolean](#org1f19090)
4. [stat(path) ==> object](#org625195b)
5. [get(path, dst, options) ==> String|Stream|Buffer](#org2c1f4a0)
6. [fastGet(remotePath, localPath, options) ===> string](#orgdc896c4)
7. [put(src, remotePath, options) ==> string](#orgb196a2e)
8. [fastPut(localPath, remotePath, options) ==> string](#org243adae)
9. [append(input, remotePath, options) ==> string](#org7d9d07f)
10. [mkdir(path, recursive) ==> string](#orgb972a31)
11. [rmdir(path, recursive) ==> string](#org5db8003)
12. [delete(path) ==> string](#org6301aa9)
13. [rename(fromPath, toPath) ==> string](#orgae0f051)
14. [chmod(path, mode) ==> string](#org462d46f)
15. [realPath(path) ===> string](#orgde5aa73)
16. [cwd() ==> string](#org705f820)
17. [end() ==> boolean](#org40dd1ae)
18. [Add and Remove Listeners](#org169bbdb)
7. [FAQ](#org0dd8098)
1. [How can you pass writable stream as dst for get method?](#org93da735)
2. [How can I upload files without having to specify a password?](#orgde3dfae)
3. [How can I connect through a Socks Proxy](#org97b11c7)
8. [Change Log](#orgcd88ff2)
1. [v4.1.0 (Prod Version)](#org4624fd1)
2. [v4.0.4](#org99482d5)
3. [v4.0.3](#orga917421)
4. [v4.0.2](#orgc8b9bd3)
5. [v4.0.0](#org56a1855)
6. [v2.5.2](#org7c011ac)
7. [v2.5.1](#orgfb00d0f)
8. [v2.5.0](#org175b195)
9. [v2.4.3](#org5c185aa)
10. [v2.4.2](#org70e34eb)
11. [v2.4.1](#orgcc4683d)
12. [v2.4.0](#org4413262)
13. [v2.3.0](#orgd6201fe)
14. [v3.0.0 – deprecate this version](#org24ca85f)
15. [v2.1.1](#org6410067)
16. [v2.0.1](#orgd0190f0)
17. [v1.1.0](#org2007ebd)
18. [v1.0.5:](#org6eb1f80)
9. [Logging Issues](#orgec61686)
10. [Pull Requests](#orgb91eb96)
11. [Contributors](#orgdd815db)
1. [SSH2 SFTP Client](#org2d4beb0)
2. [Installation](#org1b2885a)
3. [Basic Usage](#org225126f)
4. [Breaking Changes in Version 4.x](#org2cf43bd)
5. [Enhancements in Version 4.2.x](#org30c96ac)
6. [Enhancements in Version 4.1.x](#org5777d99)
7. [Documentation](#org8c25b6e)
1. [Methods](#org8f330c9)
1. [new SftpClient(name) ===> SFTP client object](#orgb660d8f)
2. [connect(config) ===> SFTPstream](#org1a60cfb)
3. [list(path, pattern) ==> Array[object]](#org8a1dff4)
4. [exists(path) ==> boolean](#orgaa778db)
5. [stat(path) ==> object](#org5184595)
6. [get(path, dst, options) ==> String|Stream|Buffer](#orga0dfcd5)
7. [fastGet(remotePath, localPath, options) ===> string](#org1f07b2e)
8. [put(src, remotePath, options) ==> string](#org372e9a1)
9. [fastPut(localPath, remotePath, options) ==> string](#org6c596b7)
10. [append(input, remotePath, options) ==> string](#orgfdb9a8f)
11. [mkdir(path, recursive) ==> string](#orgd57aded)
12. [rmdir(path, recursive) ==> string](#orgdb74ea9)
13. [delete(path) ==> string](#orga755e94)
14. [rename(fromPath, toPath) ==> string](#org74fb8ca)
15. [chmod(path, mode) ==> string](#orgf44a17a)
16. [realPath(path) ===> string](#orge8bc11c)
17. [cwd() ==> string](#orgc9d3058)
18. [end() ==> boolean](#org72b3f6f)
19. [Add and Remove Listeners](#orge7b5b8a)
8. [FAQ](#org06ab353)
1. [Remote server drops connections with only an end event](#org5bac919)
2. [How can you pass writable stream as dst for get method?](#org5e6420c)
3. [How can I upload files without having to specify a password?](#org6ec13f2)
4. [How can I connect through a Socks Proxy](#org5501a07)
9. [Change Log](#orgf32a1e7)
1. [v4.2.0 (Prod Version)](#org8f7647b)
2. [v4.1.0](#org790e255)
3. [v4.0.4](#orgbc6936f)
4. [v4.0.3](#orga5291fb)
5. [v4.0.2](#orgbf82349)
6. [v4.0.0](#org9d05647)
7. [v2.5.2](#orgee92c3b)
8. [v2.5.1](#orgca044c2)
9. [v2.5.0](#orgfd95552)
10. [v2.4.3](#orge8df065)
11. [v2.4.2](#org1c6d986)
12. [v2.4.1](#orgc755940)
13. [v2.4.0](#orgc29393a)
14. [v2.3.0](#orgd43c13b)
15. [v3.0.0 – deprecate this version](#orgc15e6ab)
16. [v2.1.1](#org3d8c204)
17. [v2.0.1](#org186bc44)
18. [v1.1.0](#orgeec7323)
19. [v1.0.5:](#org54b2653)
10. [Logging Issues](#org8c07de1)
11. [Pull Requests](#orge0fc98c)
12. [Contributors](#org3d70747)
<a id="org43ca01c"></a>
<a id="org2d4beb0"></a>

@@ -74,3 +78,3 @@ # SSH2 SFTP Client

<a id="org85ec107"></a>
<a id="org1b2885a"></a>

@@ -82,3 +86,3 @@ # Installation

<a id="org7ca5e28"></a>
<a id="org225126f"></a>

@@ -104,3 +108,3 @@ # Basic Usage

<a id="org11186bf"></a>
<a id="org2cf43bd"></a>

@@ -133,4 +137,23 @@ # Breaking Changes in Version 4.x

<a id="orge5f7732"></a>
<a id="org30c96ac"></a>
# Enhancements in Version 4.2.x
- Added ability to set a client name in `Client()` constructor. This can be
useful when creating multiple clients as the client name will be displayed
in error messages, providing a clue as to which client has failed.
- Added a work-around for the SSH2 bug which results in only an `end` event
being raised when the remote server drops the connection during the connect
process. (see FAQ section below).
- Added additional error checking to prevent attempts to call `connect()` on
an already connected client. While a client can be used to make multiple
connections, you must call `end()` before calling `connect()` again. Each
client object can only represent a single connection to an SFTP
server. However, some methods, such as `fastPut()` and `fastGet()` will use
concurrency to speed up the transfer of data.
- Added some more examples in the example directory of the repository
<a id="org5777d99"></a>
# Enhancements in Version 4.1.x

@@ -147,3 +170,3 @@

<a id="org8b8cd18"></a>
<a id="org8c25b6e"></a>

@@ -159,3 +182,3 @@ # Documentation

<a id="org820f1d6"></a>
<a id="org8f330c9"></a>

@@ -165,4 +188,43 @@ ## Methods

<a id="org83fbd25"></a>
<a id="orgb660d8f"></a>
### new SftpClient(name) ===> SFTP client object
Constructor to create a new `ssh2-sftp-client` object. An optional `name` string
can be provided, which will be used in error messages to help identify which
client has thrown the error.
1. Constructor arguments
- **name:** string. An optional name string used in error messages
2. Example Used
'use strict';
const Client = require('ssh2-sftp-client');
const config = {
host: 'example.com',
user: 'donald',
password: 'my-secret'
};
const sftp = new Client('example-client');
sftp.connect(config)
.then(() => {
return sftp.cwd();
})
.then(p => {
console.log(`Remote working directory is ${p}`);
return sftp.end();
})
.catch(err => {
console.log(`Error: ${err.message}`); // error message will include 'example-client'
});
<a id="org1a60cfb"></a>
### connect(config) ===> SFTPstream

@@ -236,3 +298,3 @@

<a id="org2871c47"></a>
<a id="org8a1dff4"></a>

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

<a id="org1f19090"></a>
<a id="orgaa778db"></a>

@@ -346,3 +408,3 @@ ### exists(path) ==> boolean

<a id="org625195b"></a>
<a id="org5184595"></a>

@@ -394,3 +456,3 @@ ### stat(path) ==> object

<a id="org2c1f4a0"></a>
<a id="orga0dfcd5"></a>

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

<a id="orgdc896c4"></a>
<a id="org1f07b2e"></a>

@@ -499,3 +561,3 @@ ### fastGet(remotePath, localPath, options) ===> string

<a id="orgb196a2e"></a>
<a id="org372e9a1"></a>

@@ -553,3 +615,3 @@ ### put(src, remotePath, options) ==> string

<a id="org243adae"></a>
<a id="org6c596b7"></a>

@@ -597,3 +659,3 @@ ### fastPut(localPath, remotePath, options) ==> string

<a id="org7d9d07f"></a>
<a id="orgfdb9a8f"></a>

@@ -643,3 +705,3 @@ ### append(input, remotePath, options) ==> string

<a id="orgb972a31"></a>
<a id="orgd57aded"></a>

@@ -673,3 +735,3 @@ ### mkdir(path, recursive) ==> string

<a id="org5db8003"></a>
<a id="orgdb74ea9"></a>

@@ -704,3 +766,3 @@ ### rmdir(path, recursive) ==> string

<a id="org6301aa9"></a>
<a id="orga755e94"></a>

@@ -730,3 +792,3 @@ ### delete(path) ==> string

<a id="orgae0f051"></a>
<a id="org74fb8ca"></a>

@@ -756,3 +818,3 @@ ### rename(fromPath, toPath) ==> string

<a id="org462d46f"></a>
<a id="orgf44a17a"></a>

@@ -785,3 +847,3 @@ ### chmod(path, mode) ==> string

<a id="orgde5aa73"></a>
<a id="orge8bc11c"></a>

@@ -796,3 +858,3 @@ ### realPath(path) ===> string

<a id="org705f820"></a>
<a id="orgc9d3058"></a>

@@ -804,3 +866,3 @@ ### cwd() ==> string

<a id="org40dd1ae"></a>
<a id="org72b3f6f"></a>

@@ -828,3 +890,3 @@ ### end() ==> boolean

<a id="org169bbdb"></a>
<a id="orge7b5b8a"></a>

@@ -855,3 +917,3 @@ ### Add and Remove Listeners

<a id="org0dd8098"></a>
<a id="org06ab353"></a>

@@ -861,4 +923,34 @@ # FAQ

<a id="org93da735"></a>
<a id="org5bac919"></a>
## Remote server drops connections with only an end event
Many SFTP servers have rate limiting protection which will drop connections once
a limit has been reached. In particular, openSSH has the setting `MaxStartups`,
which can be a tuple of the form `max:drop:full` where `max` is the maximum
allowed unauthenticated connections, `drop` is a percentage value which
specifies percentage of connections to be dropped once `max` connections has
been reached and `full` is the number of connections at which point all
subsequent connections will be dropped. e.g. `10:30:60` means allow up to 10
unauthenticated connections after which drop 30% of connection attempts until
reaching 60 unauthenticated connections, at which time, drop all attempts.
Clients first make an unauthenticated connection to the SFTP server to begin
negotiation of protocol settings (cipher, authentication method etc). If you are
creating multiple connections in a script, it is easy to exceed the limit,
resulting in some connections being dropped. As SSH2 only raises an 'end' event
for these dropped connections, no error is detected. The `ssh2-sftp-client` now
listens for `end` events during the connection process and if one is detected,
will reject the connection promise.
One way to avoid this type of issue is to add a delay between connection
attempts. It does not need to be a very long delay - just sufficient to permit
the previous connection to be authenticated. In fact, the default setting for
openSSH is `10:30:60`, so you really just need to have enough delay to ensure
that the 1st connection has completed authentication before the 11th connection
is attempted.
<a id="org5e6420c"></a>
## How can you pass writable stream as dst for get method?

@@ -926,3 +1018,3 @@

<a id="orgde3dfae"></a>
<a id="org6ec13f2"></a>

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

<a id="org97b11c7"></a>
<a id="org5501a07"></a>

@@ -998,3 +1090,3 @@ ## How can I connect through a Socks Proxy

<a id="orgcd88ff2"></a>
<a id="orgf32a1e7"></a>

@@ -1004,6 +1096,17 @@ # Change Log

<a id="org4624fd1"></a>
<a id="org8f7647b"></a>
## v4.1.0 (Prod Version)
## v4.2.0 (Prod Version)
- Work-around for SSH2 `end` event bug
- Added ability to set client name in constructor method
- Added additional error checking to prevent `connect()` being called on
already connected client
- Added additional examples in `example` directory
<a id="org790e255"></a>
## v4.1.0
- move `end()` call to resolve into close hook

@@ -1022,3 +1125,3 @@ - Prevent `put()` and `get()` from creating empty files in destination when

<a id="org99482d5"></a>
<a id="orgbc6936f"></a>

@@ -1031,3 +1134,3 @@ ## v4.0.4

<a id="orga917421"></a>
<a id="orga5291fb"></a>

@@ -1040,3 +1143,3 @@ ## v4.0.3

<a id="orgc8b9bd3"></a>
<a id="orgbf82349"></a>

@@ -1048,3 +1151,3 @@ ## v4.0.2

<a id="org56a1855"></a>
<a id="org9d05647"></a>

@@ -1067,3 +1170,3 @@ ## v4.0.0

<a id="org7c011ac"></a>
<a id="orgee92c3b"></a>

@@ -1076,3 +1179,3 @@ ## v2.5.2

<a id="orgfb00d0f"></a>
<a id="orgca044c2"></a>

@@ -1084,3 +1187,3 @@ ## v2.5.1

<a id="org175b195"></a>
<a id="orgfd95552"></a>

@@ -1092,3 +1195,3 @@ ## v2.5.0

<a id="org5c185aa"></a>
<a id="orge8df065"></a>

@@ -1101,3 +1204,3 @@ ## v2.4.3

<a id="org70e34eb"></a>
<a id="org1c6d986"></a>

@@ -1110,3 +1213,3 @@ ## v2.4.2

<a id="orgcc4683d"></a>
<a id="orgc755940"></a>

@@ -1119,3 +1222,3 @@ ## v2.4.1

<a id="org4413262"></a>
<a id="orgc29393a"></a>

@@ -1133,3 +1236,3 @@ ## v2.4.0

<a id="orgd6201fe"></a>
<a id="orgd43c13b"></a>

@@ -1143,3 +1246,3 @@ ## v2.3.0

<a id="org24ca85f"></a>
<a id="orgc15e6ab"></a>

@@ -1152,3 +1255,3 @@ ## v3.0.0 &#x2013; deprecate this version

<a id="org6410067"></a>
<a id="org3d8c204"></a>

@@ -1161,3 +1264,3 @@ ## v2.1.1

<a id="orgd0190f0"></a>
<a id="org186bc44"></a>

@@ -1172,3 +1275,3 @@ ## v2.0.1

<a id="org2007ebd"></a>
<a id="orgeec7323"></a>

@@ -1180,3 +1283,3 @@ ## v1.1.0

<a id="org6eb1f80"></a>
<a id="org54b2653"></a>

@@ -1189,3 +1292,3 @@ ## v1.0.5:

<a id="orgec61686"></a>
<a id="org8c07de1"></a>

@@ -1199,3 +1302,3 @@ # Logging Issues

<a id="orgb91eb96"></a>
<a id="orge0fc98c"></a>

@@ -1220,3 +1323,3 @@ # Pull Requests

<a id="orgdd815db"></a>
<a id="org3d70747"></a>

@@ -1223,0 +1326,0 @@ # Contributors

@@ -13,4 +13,6 @@ /**

let SftpClient = function() {
let SftpClient = function(clientName = '') {
this.client = new Client();
this.clientName = clientName;
this.endCalled = false;
};

@@ -27,3 +29,3 @@

*/
function formatError(err, name = 'ssh2-sftp-client', retryCount) {
function formatError(err, name = 'sftp', retryCount) {
let msg = '';

@@ -39,4 +41,4 @@

msg =
`${name}: ${err.level} error. Address lookup failed for host ` +
`${err.hostname}`;
`${name}: ` +
`${err.level} error. Address lookup failed for host ${err.hostname}`;
break;

@@ -69,3 +71,5 @@ case 'ECONNREFUSED':

let listeners = emitter.eventNames();
listeners.map(name => emitter.removeAllListeners(name));
listeners.forEach(name => {
emitter.removeAllListeners(name);
});
}

@@ -80,7 +84,17 @@

*/
function errorListener(err, source) {
let newErr = formatError(err, source);
throw newErr;
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) {

@@ -166,13 +180,7 @@ const sftp = this.sftp;

SftpClient.prototype.list = async function(path, pattern = /.*/) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.list')
);
}
let absPath = await this.realPath(path);
return this._list(absPath, pattern);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.list'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.list');
}
let absPath = await this.realPath(path);
return this._list(absPath, pattern);
};

@@ -237,5 +245,3 @@

if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.exists')
);
throw formatError('No SFTP connection available', 'sftp.exists');
}

@@ -246,5 +252,5 @@ let absPath = await this.realPath(remotePath);

if (err.message.match(/No such file/)) {
return Promise.resolve(false);
return false;
}
return Promise.reject(formatError(err, 'sftp.exists'));
throw formatError(err, 'sftp.exists');
}

@@ -288,13 +294,7 @@ };

SftpClient.prototype.stat = async function(remotePath) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.stat')
);
}
let absPath = await this.realPath(remotePath);
return this._stat(absPath);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.stat'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.stat');
}
let absPath = await this.realPath(remotePath);
return this._stat(absPath);
};

@@ -360,26 +360,18 @@

SftpClient.prototype.get = async function(path, dst, options) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.get')
);
}
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.get');
}
let absPath = await this.realPath(path);
let absPath = await this.realPath(path);
let stats = await this.stat(absPath);
if ((stats.mode & 0o444) === 0) {
return Promise.reject(
formatError(`No read permission for ${absPath}`, 'sftp.get')
);
}
let stats = await this.stat(absPath);
if ((stats.mode & 0o444) === 0) {
throw formatError(`No read permission for ${absPath}`, 'sftp.get');
}
if (typeof dst === 'string') {
let dstPath = normalize(dst);
return this._get(absPath, dstPath, options);
}
return this._get(absPath, dst, options);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.get'));
if (typeof dst === 'string') {
let dstPath = normalize(dst);
return this._get(absPath, dstPath, options);
}
return this._get(absPath, dst, options);
};

@@ -413,14 +405,8 @@

SftpClient.prototype.fastGet = async function(remotePath, localPath, options) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.fastGet')
);
}
let src = await this.realPath(remotePath);
let dst = normalize(localPath);
return this._fastGet(src, dst, options);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.fastGet'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.fastGet');
}
let src = await this.realPath(remotePath);
let dst = normalize(localPath);
return this._fastGet(src, dst, options);
};

@@ -455,22 +441,15 @@

SftpClient.prototype.fastPut = async function(localPath, remotePath, options) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.fastPut')
);
}
let src = fs.realpathSync(localPath);
let dst = remotePath;
if (dst.startsWith('../')) {
let root = await this.realPath('..');
dst = join(root, dst.substring(3));
} else if (dst.startsWith('./')) {
let root = await this.realPath('.');
dst = join(root, dst.substring(2));
}
return this._fastPut(src, dst, options);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.fastPut'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.fastPut');
}
let src = fs.realpathSync(localPath);
let dst = remotePath;
if (dst.startsWith('../')) {
let root = await this.realPath('..');
dst = join(root, dst.substring(3));
} else if (dst.startsWith('./')) {
let root = await this.realPath('.');
dst = join(root, dst.substring(2));
}
return this._fastPut(src, dst, options);
};

@@ -523,25 +502,19 @@

SftpClient.prototype.put = async function(localSrc, remotePath, options) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connections available', 'sftp.put')
);
}
let src = localSrc;
if (typeof src === 'string') {
src = fs.realpathSync(src);
fs.accessSync(src, fs.constants.R_OK);
}
let dst = remotePath;
if (dst.startsWith('../')) {
let root = await this.realPath('..');
dst = join(root, dst.substring(3));
} else if (dst.startsWith('./')) {
let root = await this.realPath('.');
dst = join(root, dst.substring(2));
}
return this._put(src, dst, options);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.put'));
if (!this.sftp) {
throw formatError('No SFTP connections available', 'sftp.put');
}
let src = localSrc;
if (typeof src === 'string') {
src = fs.realpathSync(src);
fs.accessSync(src, fs.constants.R_OK);
}
let dst = remotePath;
if (dst.startsWith('../')) {
let root = await this.realPath('..');
dst = join(root, dst.substring(3));
} else if (dst.startsWith('./')) {
let root = await this.realPath('.');
dst = join(root, dst.substring(2));
}
return this._put(src, dst, options);
};

@@ -593,32 +566,20 @@

SftpClient.prototype.append = async function(input, remotePath, options) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.append')
);
}
if (typeof input === 'string') {
return Promise.reject(
formatError('Cannot append one file to another', 'sftp.append')
);
}
let absPath = await this.realPath(remotePath);
let stats = await this.stat(absPath);
if ((stats.mode & 0o0100000) === 0) {
return Promise.reject(
formatError(
`${remotePath} Remote path must be a regular file`,
'sftp-append'
)
);
}
if ((stats.mode & 0o0444) === 0) {
return Promise.reject(
formatError(`${remotePath} No write permission`, 'sftp-append')
);
}
return this._append(input, absPath, options);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.append'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.append');
}
if (typeof input === 'string') {
throw formatError('Cannot append one file to another', 'sftp.append');
}
let absPath = await this.realPath(remotePath);
let stats = await this.stat(absPath);
if ((stats.mode & 0o0100000) === 0) {
throw formatError(
`${remotePath} Remote path must be a regular file`,
'sftp-append'
);
}
if ((stats.mode & 0o0444) === 0) {
throw formatError(`${remotePath} No write permission`, 'sftp-append');
}
return this._append(input, absPath, options);
};

@@ -651,5 +612,3 @@

if (!sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.mkdir')
);
throw formatError('No SFTP connection available', 'sftp.mkdir');
}

@@ -674,7 +633,7 @@ let realPath = path;

} else if (parent !== 'd') {
return Promise.reject(formatError('Bad directory path', 'sftp.mkdir'));
throw formatError('Bad directory path', 'sftp.mkdir');
}
return doMkdir(realPath);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.mkdir'));
throw formatError(err, 'sftp.mkdir');
}

@@ -713,5 +672,3 @@ };

if (!sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.rmdir')
);
throw formatError('No SFTP connection available', 'sftp.rmdir');
}

@@ -730,3 +687,3 @@ let absPath = await this.realPath(path);

} catch (err) {
return Promise.reject(formatError(err, 'sftp.rmdir'));
throw formatError(err, 'sftp.rmdir');
}

@@ -738,3 +695,3 @@ }

} catch (err) {
return Promise.reject(formatError(err, 'sftp.rmdir'));
throw formatError(err, 'sftp.rmdir');
}

@@ -745,3 +702,3 @@ }

} catch (err) {
return Promise.reject(formatError(err, 'sftp.rmdir'));
throw formatError(err, 'sftp.rmdir');
}

@@ -773,13 +730,7 @@ };

SftpClient.prototype.delete = async function(path) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.delete')
);
}
let absPath = await this.realPath(path);
return this._delete(absPath);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.delete'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.delete');
}
let absPath = await this.realPath(path);
return this._delete(absPath);
};

@@ -812,21 +763,15 @@

SftpClient.prototype.rename = async function(fromPath, toPath) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.rename')
);
}
let src = await this.realPath(fromPath);
let dst = toPath;
if (dst.startsWith('../')) {
let root = await this.realPath('..');
dst = join(root, dst.substring(3));
} else if (dst.startsWith('./')) {
let root = await this.realPath('.');
dst = join(root, dst.substring(2));
}
return this._rename(src, dst);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.rename'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.rename');
}
let src = await this.realPath(fromPath);
let dst = toPath;
if (dst.startsWith('../')) {
let root = await this.realPath('..');
dst = join(root, dst.substring(3));
} else if (dst.startsWith('./')) {
let root = await this.realPath('.');
dst = join(root, dst.substring(2));
}
return this._rename(src, dst);
};

@@ -858,13 +803,7 @@

SftpClient.prototype.chmod = async function(remotePath, mode) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.chmod')
);
}
let path = await this.realPath(remotePath);
return this._chmod(path, mode);
} catch (err) {
return Promise.reject(formatError(err, 'sftp.chmod'));
if (!this.sftp) {
throw formatError('No SFTP connection available', 'sftp.chmod');
}
let path = await this.realPath(remotePath);
return this._chmod(path, mode);
};

@@ -884,17 +823,17 @@

SftpClient.prototype.connect = function(config) {
let obj = this;
let self = this;
var operation = retry.operation({
retries: config.retries || 2,
retries: config.retries || 1,
factor: config.retry_factor || 2,
minTimeout: config.retry_minTimeout || 2000
minTimeout: config.retry_minTimeout || 1000
});
function retryConnect(sftpObj, config, callback) {
function retryConnect(config, callback) {
try {
operation.attempt(function(attemptCount) {
sftpObj.client
self.client
.on('ready', () => {
sftpObj.client.sftp((err, sftp) => {
self.client.sftp((err, sftp) => {
if (err) {
removeListeners(sftpObj.client);
removeListeners(self.client);
if (operation.retry(err)) {

@@ -908,7 +847,9 @@ // failed to connect, but not yet reached max attempt count

}
sftpObj.sftp = sftp;
self.sftp = sftp;
// remove retry error listener and add generic error listener
sftpObj.client.removeAllListeners('error');
sftpObj.client.on('error', errorListener);
sftpObj.client.on('finish', withError => {
self.client.removeAllListeners('error');
self.client.removeAllListeners('end');
self.client.on('end', makeEndListener(self));
self.client.on('error', makeErrorListener(self.clientName));
self.client.on('close', withError => {
if (withError) {

@@ -921,7 +862,4 @@ console.error('Client ended due to errors');

})
.on('end', () => {
sftpObj.sftp = null;
})
.on('error', err => {
removeListeners(sftpObj.client);
removeListeners(self.client);
if (operation.retry(err)) {

@@ -935,11 +873,15 @@ // failed to connect, but not yet reached max attempt count

})
.on('close', withError => {
if (withError) {
console.error('sftp client closed due to errors');
}
.on('end', () => {
callback(
formatError(
'Connection ended unexpectedly by remote server',
self.clientName
)
);
})
.connect(config);
});
} catch (err) {
removeListeners(sftpObj.client);
removeListeners(self.client);
callback(formatError(err, 'sftp.connect'), null);

@@ -950,11 +892,16 @@ }

return new Promise((resolve, reject) => {
try {
retryConnect(obj, config, (err, sftp) => {
if (self.sftp) {
reject(
formatError(
'An existing SFTP connection is already defined',
'sftp.connect'
)
);
} else {
retryConnect(config, (err, sftp) => {
if (err) {
reject(formatError(err, 'sftp.connect'));
reject(err);
}
resolve(sftp);
});
} catch (err) {
reject(formatError(err, 'sftp.connect'));
}

@@ -981,14 +928,17 @@ });

SftpClient.prototype.end = function() {
let obj = this;
let self = this;
return new Promise((resolve, reject) => {
try {
self.endCalled = true;
// debugListeners(this.client);
obj.client.on('close', () => {
removeListeners(obj.client);
resolve(true);
});
obj.client.end();
//removeListeners(obj.client);
// obj.client.on('close', () => {
// removeListeners(obj.client);
// //resolve(true);
// });
self.client.end();
removeListeners(self.client);
self.sftp = undefined;
resolve(true);
self.endCalled = false;
} catch (err) {

@@ -995,0 +945,0 @@ reject(formatError(err, 'sftp.end'));

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