Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ssh2-sftp-client

Package Overview
Dependencies
Maintainers
2
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ssh2-sftp-client - npm Package Compare versions

Comparing version 4.0.4 to 4.1.0

2

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

@@ -5,0 +5,0 @@ "main": "src/index.js",

# Table of Contents
1. [SSH2 SFTP Client](#org9c08e76)
2. [Installation](#org3f4f406)
3. [Basic Usage](#org93a40da)
4. [Breaking Changes in Version 4.0.0](#org18495a3)
5. [Documentation](#org3222656)
1. [Methods](#org96b12ba)
1. [connect(config) ===> SFTPstream](#orgd70af09)
2. [list(path, pattern) ==> Array[object]](#org6f3a281)
3. [exists(path) ==> boolean](#orgf77e86f)
4. [stat(path) ==> object](#org398bf4f)
5. [get(path, dst, options) ==> String|Stream|Buffer](#org0587f21)
6. [fastGet(remotePath, localPath, options) ===> string](#orgeb63dff)
7. [put(src, remotePath, options) ==> string](#org1fe2c81)
8. [fastPut(localPath, remotePath, options) ==> string](#orgee6b633)
9. [append(input, remotePath, options) ==> string](#orgccf6a54)
10. [mkdir(path, recursive) ==> string](#org0cc89e2)
11. [rmdir(path, recursive) ==> string](#orgca9b1cf)
12. [delete(path) ==> string](#orgb50e5b0)
13. [rename(fromPath, toPath) ==> string](#org3827ade)
14. [chmod(path, mode) ==> string](#org4ac8f13)
15. [end() ==> boolean](#org2c3d2eb)
16. [Add and Remove Listeners](#org6d6ffe5)
6. [FAQ](#org5e4228c)
1. [How can you pass writable stream as dst for get method?](#org8e9aed7)
2. [How can I upload files without having to specify a password?](#org46645bb)
3. [How can I connect through a Socks Proxy](#org785250c)
7. [Change Log](#org9b06f52)
1. [v4.0.4](#org0fd9b56)
2. [v4.0.3](#orgd5633bd)
3. [v4.0.2](#org51ec745)
4. [v4.0.0](#orge421d28)
5. [v2.5.2](#org243214c)
6. [v2.5.1](#org23c6382)
7. [v2.5.0](#orga9175d5)
8. [v2.4.3](#org29bd506)
9. [v2.4.2](#org6d8fc47)
10. [v2.4.1](#org0ea121a)
11. [v2.4.0](#org5f98b56)
12. [v2.3.0](#org5b5e078)
13. [v3.0.0 – deprecate this version](#org03e1923)
14. [v2.1.1](#org38facd8)
15. [v2.0.1](#org56e3cfb)
16. [v1.1.0](#org84a40a5)
17. [v1.0.5:](#org73e9d70)
8. [Logging Issues](#org1e66e09)
9. [Pull Requests](#org08ee895)
10. [Contributors](#org06d8d77)
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)
<a id="org9c08e76"></a>
<a id="org43ca01c"></a>

@@ -63,3 +67,3 @@ # SSH2 SFTP Client

Current stable release is **v4.0.3**.
Current stable release is **v4.1.0**.

@@ -71,3 +75,3 @@ Code has been tested against Node versions 8.16.1, 10.16.3 and 12.9.1

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

@@ -79,3 +83,3 @@ # Installation

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

@@ -101,5 +105,5 @@ # Basic Usage

<a id="org18495a3"></a>
<a id="org11186bf"></a>
# Breaking Changes in Version 4.0.0
# Breaking Changes in Version 4.x

@@ -130,4 +134,17 @@ There has been minor changes to the API signatures

<a id="org3222656"></a>
<a id="orge5f7732"></a>
# Enhancements in Version 4.1.x
- Some of the data upload/download methods would create an empty destination
file when the source file did not exist. This has now been fixed.
- Handling of relative path names was weak and inconsistent. This has now been
made more consistent and reliable. Two new methods `realPath()` and `cwd()`
have been added
- More error checking and provision of error messages with more meaningful
information. Expansion and enhancements of test cases.
<a id="org8b8cd18"></a>
# Documentation

@@ -142,3 +159,3 @@

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

@@ -148,3 +165,3 @@ ## Methods

<a id="orgd70af09"></a>
<a id="org83fbd25"></a>

@@ -219,3 +236,3 @@ ### connect(config) ===> SFTPstream

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -590,3 +607,3 @@ ### append(input, remotePath, options) ==> string

- **input:** string | readStream. Data to append to remote file
- **input:** buffer | readStream. Data to append to remote file
- **remotePath:** string. Path to remote file

@@ -627,3 +644,3 @@ - **options:** object. Options to pass to writeStream (see below)

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

@@ -657,3 +674,3 @@ ### mkdir(path, recursive) ==> string

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

@@ -688,3 +705,3 @@ ### rmdir(path, recursive) ==> string

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

@@ -714,3 +731,3 @@ ### delete(path) ==> string

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

@@ -740,3 +757,3 @@ ### rename(fromPath, toPath) ==> string

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

@@ -769,4 +786,21 @@ ### chmod(path, mode) ==> string

<a id="org2c3d2eb"></a>
<a id="orgde5aa73"></a>
### 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.
- **path:** A file path, either relative or absolute
<a id="org705f820"></a>
### cwd() ==> string
Returns what the server believes is the current remote working directory.
<a id="org40dd1ae"></a>
### end() ==> boolean

@@ -793,3 +827,3 @@

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

@@ -820,3 +854,3 @@ ### Add and Remove Listeners

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

@@ -826,3 +860,3 @@ # FAQ

<a id="org8e9aed7"></a>
<a id="org93da735"></a>

@@ -891,3 +925,3 @@ ## How can you pass writable stream as dst for get method?

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

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

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

@@ -963,3 +997,3 @@ ## How can I connect through a Socks Proxy

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

@@ -969,4 +1003,21 @@ # Change Log

<a id="org0fd9b56"></a>
<a id="org4624fd1"></a>
## v4.1.0 (Prod Version)
- move `end()` call to resolve into close hook
- Prevent `put()` and `get()` from creating empty files in destination when
unable to read source
- Expand tests for operations when lacking required permissions
- Add additional data checks for `append()`
- Verify file exists
- Verify file is writeable
- Verify file is a regular file
- Fix handling of relative paths
- Add `realPath()` method
- Add `cwd()` method
<a id="org99482d5"></a>
## v4.0.4

@@ -978,3 +1029,3 @@

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

@@ -987,3 +1038,3 @@ ## v4.0.3

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

@@ -995,3 +1046,3 @@ ## v4.0.2

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

@@ -1014,3 +1065,3 @@ ## v4.0.0

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

@@ -1023,3 +1074,3 @@ ## v2.5.2

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

@@ -1031,3 +1082,3 @@ ## v2.5.1

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

@@ -1039,3 +1090,3 @@ ## v2.5.0

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

@@ -1048,3 +1099,3 @@ ## v2.4.3

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

@@ -1057,3 +1108,3 @@ ## v2.4.2

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

@@ -1066,3 +1117,3 @@ ## v2.4.1

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

@@ -1080,3 +1131,3 @@ ## v2.4.0

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

@@ -1090,3 +1141,3 @@ ## v2.3.0

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

@@ -1099,3 +1150,3 @@ ## v3.0.0 &#x2013; deprecate this version

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

@@ -1108,3 +1159,3 @@ ## v2.1.1

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

@@ -1119,3 +1170,3 @@ ## v2.0.1

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

@@ -1127,3 +1178,3 @@ ## v1.1.0

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

@@ -1136,3 +1187,3 @@ ## v1.0.5:

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

@@ -1146,3 +1197,3 @@ # Logging Issues

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

@@ -1167,3 +1218,3 @@ # Pull Requests

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

@@ -1170,0 +1221,0 @@ # Contributors

@@ -11,3 +11,3 @@ /**

const retry = require('retry');
const {join, posix} = require('path');
const {join, posix, normalize} = require('path');

@@ -30,2 +30,4 @@ let SftpClient = function() {

//console.dir(err);
if (typeof err === 'string') {

@@ -81,57 +83,20 @@ msg = `${name}: ${err}`;

/**
* Retrieves a directory listing. The pattern argument may be a regular expression
* or simple 'glob' style *.
*
* @param {String} path, a string containing the path to a directory
* @param {regex} pattern - An optional pattern used to filter the list
* @return {Promise} data, list info
*/
SftpClient.prototype.list = function(path, pattern = /.*/) {
const reg = /-/gi;
SftpClient.prototype.realPath = function(path) {
const sftp = this.sftp;
return new Promise((resolve, reject) => {
let sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.list'));
return reject(
formatError('No SFTP connection available', 'sftp.realPath')
);
}
sftp.readdir(path, (err, list) => {
sftp.realpath(path, (err, absPath) => {
if (err) {
reject(formatError(err, 'sftp.list'));
} else {
let newList = [];
// reset file info
if (list) {
newList = list.map(item => {
return {
type: item.longname.substr(0, 1),
name: item.filename,
size: item.attrs.size,
modifyTime: item.attrs.mtime * 1000,
accessTime: item.attrs.atime * 1000,
rights: {
user: item.longname.substr(1, 3).replace(reg, ''),
group: item.longname.substr(4, 3).replace(reg, ''),
other: item.longname.substr(7, 3).replace(reg, '')
},
owner: item.attrs.uid,
group: item.attrs.gid
};
});
}
// provide some compatibility for auxList
let regex;
if (pattern instanceof RegExp) {
regex = pattern;
} else {
let newPattern = pattern.replace(/\*([^*])*?/gi, '.*');
regex = new RegExp(newPattern);
}
resolve(newList.filter(item => regex.test(item.name)));
reject(formatError(`${err.message} ${path}`, 'sftp.realPath'));
}
resolve(absPath);
});
} catch (err) {
reject(formatError(err, 'sftp.list'));
reject(formatError(`${err.message} ${path}`, 'sftp.realPath'));
}

@@ -141,3 +106,74 @@ });

SftpClient.prototype.cwd = function() {
return this.realPath('.');
};
SftpClient.prototype._list = function(path, pattern = /.*/) {
const _this = this;
const reg = /-/gi;
return new Promise((resolve, reject) => {
const sftp = _this.sftp;
sftp.readdir(path, (err, list) => {
if (err) {
reject(formatError(err, 'sftp.list'));
} else {
let newList = [];
// reset file info
if (list) {
newList = list.map(item => {
return {
type: item.longname.substr(0, 1),
name: item.filename,
size: item.attrs.size,
modifyTime: item.attrs.mtime * 1000,
accessTime: item.attrs.atime * 1000,
rights: {
user: item.longname.substr(1, 3).replace(reg, ''),
group: item.longname.substr(4, 3).replace(reg, ''),
other: item.longname.substr(7, 3).replace(reg, '')
},
owner: item.attrs.uid,
group: item.attrs.gid
};
});
}
// provide some compatibility for auxList
let regex;
if (pattern instanceof RegExp) {
regex = pattern;
} else {
let newPattern = pattern.replace(/\*([^*])*?/gi, '.*');
regex = new RegExp(newPattern);
}
resolve(newList.filter(item => regex.test(item.name)));
}
});
});
};
/**
* Retrieves a directory listing. The pattern argument may be a regular expression
* or simple 'glob' style *.
*
* @param {String} path, a string containing the path to a directory
* @param {regex} pattern - An optional pattern used to filter the list
* @return {Promise} data, list info
*/
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'));
}
};
/**
* Retrieves a directory listing with a filter

@@ -158,2 +194,29 @@ *

SftpClient.prototype._exists = function(path) {
return new Promise((resolve, reject) => {
const sftp = this.sftp;
let {dir, base} = posix.parse(path);
sftp.readdir(dir, (err, list) => {
if (err) {
if (err.code === 2) {
resolve(false);
} else {
reject(formatError(err, 'sftp.exists'));
}
} else {
let [type] = list
.filter(item => item.filename === base)
.map(item => item.longname.substr(0, 1));
if (type) {
resolve(type);
} else {
resolve(false);
}
}
});
});
};
/**

@@ -170,36 +233,44 @@ * @async

*/
SftpClient.prototype.exists = function(path) {
SftpClient.prototype.exists = async function(remotePath) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.exists')
);
}
let absPath = await this.realPath(remotePath);
return this._exists(absPath);
} catch (err) {
if (err.message.match(/No such file/)) {
return Promise.resolve(false);
}
return Promise.reject(formatError(err, 'sftp.exists'));
}
};
SftpClient.prototype._stat = function(remotePath) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
const sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.exists'));
sftp.stat(remotePath, function(err, stats) {
if (err) {
reject(formatError(err, 'sftp.stat'));
} else {
resolve({
mode: stats.mode,
uid: stats.uid,
gid: stats.gid,
size: stats.size,
accessTime: stats.atime * 1000,
modifyTime: stats.mtime * 1000,
isDirectory: stats.isDirectory(),
isFile: stats.isFile(),
isBlockDevice: stats.isBlockDevice(),
isCharacterDevice: stats.isCharacterDevice(),
isSymbolicLink: stats.isSymbolicLink(),
isFIFO: stats.isFIFO(),
isSocket: stats.isSocket()
});
}
let {dir, base} = posix.parse(path);
if (base === '.') {
// the '.' directory exists by definition
resolve('d');
}
sftp.readdir(dir, (err, list) => {
if (err) {
if (err.code === 2) {
resolve(false);
} else {
reject(formatError(err, 'sftp.exists'));
}
} else {
let [type] = list
.filter(item => item.filename === base)
.map(item => item.longname.substr(0, 1));
if (type) {
resolve(type);
} else {
resolve(false);
}
}
});
} catch (err) {
reject(formatError(err, 'sftp.exists'));
}
});
});

@@ -214,33 +285,55 @@ };

*/
SftpClient.prototype.stat = function(remotePath) {
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'));
}
};
SftpClient.prototype._get = function(path, dst, options) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
const sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.stat'));
let rdr = sftp.createReadStream(path, options);
rdr.on('error', err => {
removeListeners(rdr);
reject(formatError(err, 'sftp.get'));
});
if (dst === undefined) {
// no dst specified, return buffer of data
let concatStream = concat(buff => {
rdr.removeAllListeners('error');
resolve(buff);
});
rdr.pipe(concatStream);
} else {
let wtr;
if (typeof dst === 'string') {
// dst local file path
wtr = fs.createWriteStream(dst);
} else {
// assume dst is a writeable
wtr = dst;
}
sftp.stat(remotePath, function(err, stats) {
if (err) {
reject(formatError(err, 'sftp.stat'));
wtr.on('error', err => {
removeListeners(rdr);
reject(formatError(err, 'sftp.get'));
});
wtr.on('finish', () => {
removeListeners(rdr);
if (typeof dst === 'string') {
resolve(dst);
} else {
resolve({
mode: stats.mode,
uid: stats.uid,
gid: stats.gid,
size: stats.size,
accessTime: stats.atime * 1000,
modifyTime: stats.mtime * 1000,
isDirectory: stats.isDirectory(),
isFile: stats.isFile(),
isBlockDevice: stats.isBlockDevice(),
isCharacterDevice: stats.isCharacterDevice(),
isSymbolicLink: stats.isSymbolicLink(),
isFIFO: stats.isFIFO(),
isSocket: stats.isSocket()
});
resolve(wtr);
}
});
} catch (err) {
reject(formatError(err, 'sftp.stat'));
rdr.pipe(wtr);
}

@@ -264,50 +357,39 @@ });

*/
SftpClient.prototype.get = function(path, dst, options) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
SftpClient.prototype.get = async function(path, dst, options) {
try {
if (!this.sftp) {
return Promise.reject(
formatError('No SFTP connection available', 'sftp.get')
);
}
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.get'));
}
let rdr = sftp.createReadStream(path, options);
let absPath = await this.realPath(path);
rdr.on('error', err => {
removeListeners(rdr);
reject(formatError(err, 'sftp.get'));
});
let stats = await this.stat(absPath);
if ((stats.mode & 0o444) === 0) {
return Promise.reject(
formatError(`No read permission for ${absPath}`, 'sftp.get')
);
}
if (dst === undefined) {
// no dst specified, return buffer of data
let concatStream = concat(buff => {
rdr.removeAllListeners('error');
resolve(buff);
});
rdr.pipe(concatStream);
} else {
let wtr;
if (typeof dst === 'string') {
// dst local file path
wtr = fs.createWriteStream(dst);
} else {
// assume dst is a writeable
wtr = dst;
}
wtr.on('error', err => {
removeListeners(rdr);
reject(formatError(err, 'sftp.get'));
});
wtr.on('finish', () => {
removeListeners(rdr);
if (typeof dst === 'string') {
resolve(dst);
} else {
resolve(wtr);
}
});
rdr.pipe(wtr);
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'));
}
};
SftpClient.prototype._fastGet = function(remotePath, localPath, options) {
return new Promise((resolve, reject) => {
const sftp = this.sftp;
sftp.fastGet(remotePath, localPath, options, function(err) {
if (err) {
reject(formatError(err, 'sftp.fastGet'));
}
} catch (err) {
reject(formatError(err, 'sftp.get'));
}
resolve(`${remotePath} was successfully download to ${localPath}!`);
});
});

@@ -328,19 +410,27 @@ };

*/
SftpClient.prototype.fastGet = function(remotePath, localPath, options) {
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'));
}
};
SftpClient.prototype._fastPut = function(localPath, remotePath, options) {
const sftp = this.sftp;
return new Promise((resolve, reject) => {
let sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.fastGet'));
sftp.fastPut(localPath, remotePath, options, function(err) {
if (err) {
reject(formatError(err, 'sftp.fastPut'));
}
sftp.fastGet(remotePath, localPath, options, function(err) {
if (err) {
reject(formatError(err, 'sftp.fastGet'));
}
resolve(`${remotePath} was successfully download to ${localPath}!`);
});
} catch (err) {
reject(formatError(err, 'sftp.fastGet'));
}
resolve(`${localPath} was successfully uploaded to ${remotePath}!`);
});
});

@@ -362,18 +452,54 @@ };

*/
SftpClient.prototype.fastPut = function(localPath, remotePath, options) {
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'));
}
};
SftpClient.prototype._put = function(src, remotePath, options) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
const sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.fastPut'));
let stream = sftp.createWriteStream(remotePath, options);
stream.on('error', err => {
reject(formatError(err, 'sftp.put'));
});
stream.on('finish', () => {
removeListeners(stream);
resolve(`Uploaded data stream to ${remotePath}`);
});
if (src instanceof Buffer) {
stream.end(src);
} else {
let rdr;
if (typeof src === 'string') {
rdr = fs.createReadStream(src);
} else {
rdr = src;
}
sftp.fastPut(localPath, remotePath, options, function(err) {
if (err) {
reject(formatError(err, 'sftp.fastPut'));
}
resolve(`${localPath} was successfully uploaded to ${remotePath}!`);
rdr.on('error', err => {
removeListeners(stream);
reject(formatError(err, 'sftp.put'));
});
} catch (err) {
reject(formatError(err, 'sftp.fastPut'));
rdr.pipe(stream);
}

@@ -394,39 +520,59 @@ });

*/
SftpClient.prototype.put = function(src, remotePath, options) {
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'));
}
};
SftpClient.prototype._append = function(input, remotePath, options) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
const sftp = this.sftp;
try {
if (!sftp) {
reject(new Error('sftp.put: No SFTP connections available'));
}
let writerOptions;
let stream = sftp.createWriteStream(remotePath, options);
if (options) {
writerOptions = options;
writerOptions.flags = 'a';
} else {
writerOptions = {
flags: 'a'
};
}
stream.on('error', err => {
reject(formatError(err, 'sftp.put'));
});
let stream = sftp.createWriteStream(remotePath, writerOptions);
stream.on('finish', () => {
removeListeners(stream);
resolve(`Uploaded data stream to ${remotePath}`);
});
stream.on('error', err => {
removeListeners(stream);
reject(formatError(err, 'sftp.append'));
});
if (src instanceof Buffer) {
stream.end(src);
} else {
let rdr;
if (typeof src === 'string') {
rdr = fs.createReadStream(src);
} else {
rdr = src;
}
rdr.on('error', err => {
removeListeners(stream);
reject(formatError(err, 'sftp.put'));
});
rdr.pipe(stream);
}
} catch (err) {
reject(formatError(err, 'sftp.put'));
stream.on('finish', () => {
removeListeners(stream);
resolve(`sftp.append: Uploaded data stream to ${remotePath}`);
});
if (input instanceof Buffer) {
stream.end(input);
} else {
input.pipe(stream);
}

@@ -444,35 +590,33 @@ });

*/
SftpClient.prototype.append = function(input, remotePath, options) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.append'));
}
if (typeof input === 'string') {
reject(formatError('Cannot append one file to another', 'sftp.append'));
}
let stream = sftp.createWriteStream(remotePath, options);
stream.on('error', err => {
removeListeners(stream);
reject(formatError(err, 'sftp.append'));
});
stream.on('finish', () => {
removeListeners(stream);
resolve(`sftp.append: Uploaded data stream to ${remotePath}`);
});
if (input instanceof Buffer) {
stream.end(input);
} else {
input.pipe(stream);
}
} catch (err) {
reject(formatError(err, 'sftp.append'));
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'));
}
};

@@ -490,3 +634,3 @@

SftpClient.prototype.mkdir = async function(path, recursive = false) {
let sftp = this.sftp;
const sftp = this.sftp;

@@ -511,10 +655,15 @@ function doMkdir(p) {

let realPath = path;
let {dir} = posix.parse(path);
if (dir === '') {
dir = '.';
realPath = './' + path;
if (realPath.startsWith('../')) {
let root = await this.realPath('..');
realPath = join(root, realPath.substring(3));
} else if (realPath.startsWith('./')) {
let root = await this.realPath('.');
realPath = join(root, realPath.substring(2));
}
if (!recursive) {
return doMkdir(path);
return doMkdir(realPath);
}
let {dir} = posix.parse(realPath);
let parent = await this.exists(dir);

@@ -543,3 +692,3 @@ if (!parent) {

SftpClient.prototype.rmdir = async function(path, recursive = false) {
let sftp = this.sftp;
const sftp = this.sftp;

@@ -567,6 +716,7 @@ function doRmdir(p) {

}
let absPath = await this.realPath(path);
if (!recursive) {
return doRmdir(path);
return doRmdir(absPath);
}
let list = await this.list(path);
let list = await this.list(absPath);
if (list.length) {

@@ -577,3 +727,3 @@ let files = list.filter(item => item.type !== 'd');

try {
await this.delete(join(path, f.name));
await this.delete(join(absPath, f.name));
} catch (err) {

@@ -585,3 +735,3 @@ return Promise.reject(formatError(err, 'sftp.rmdir'));

try {
await this.rmdir(join(path, d.name), true);
await this.rmdir(join(absPath, d.name), true);
} catch (err) {

@@ -592,3 +742,3 @@ return Promise.reject(formatError(err, 'sftp.rmdir'));

}
return doRmdir(path);
return doRmdir(absPath);
} catch (err) {

@@ -599,2 +749,15 @@ return Promise.reject(formatError(err, 'sftp.rmdir'));

SftpClient.prototype._delete = function(path) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
sftp.unlink(path, err => {
if (err) {
reject(formatError(err, 'sftp.delete'));
}
resolve('Successfully deleted file');
});
});
};
/**

@@ -609,19 +772,26 @@ * @async

*/
SftpClient.prototype.delete = function(path) {
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'));
}
};
SftpClient.prototype._rename = function(fromPath, toPath) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.delete'));
sftp.rename(fromPath, toPath, err => {
if (err) {
reject(formatError(err, 'sftp.rename'));
}
sftp.unlink(path, err => {
if (err) {
reject(formatError(err, 'sftp.delete'));
}
resolve('Successfully deleted file');
});
} catch (err) {
reject(formatError(err, 'sftp.delete'));
}
resolve(`Successfully renamed ${fromPath} to ${toPath}`);
});
});

@@ -641,19 +811,34 @@ };

*/
SftpClient.prototype.rename = function(fromPath, toPath) {
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'));
}
};
SftpClient.prototype._chmod = function(remotePath, mode) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
const sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.rename'));
sftp.chmod(remotePath, mode, err => {
if (err) {
reject(formatError(err, 'sftp.chmod'));
}
sftp.rename(fromPath, toPath, err => {
if (err) {
reject(formatError(err, 'sftp.rename'));
}
resolve(`Successfully renamed ${fromPath} to ${toPath}`);
});
} catch (err) {
reject(formatError(err, 'sftp.rename'));
}
resolve('Successfully change file mode');
});
});

@@ -672,20 +857,14 @@ };

*/
SftpClient.prototype.chmod = function(remotePath, mode) {
return new Promise((resolve, reject) => {
let sftp = this.sftp;
try {
if (!sftp) {
reject(formatError('No SFTP connection available', 'sftp.chmod'));
}
sftp.chmod(remotePath, mode, err => {
if (err) {
reject(formatError(err, 'sftp.chmod'));
}
resolve('Successfully change file mode');
});
} catch (err) {
reject(formatError(err, 'sftp.chmod'));
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'));
}
};

@@ -797,8 +976,13 @@

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

@@ -805,0 +989,0 @@ } catch (err) {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc