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

jsftp

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsftp - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

222

lib/jsftp.js

@@ -15,3 +15,2 @@ /* vim:set ts=2 sw=2 sts=2 expandtab */

var ListingParser = require("parse-listing");
var Utils = require("./utils");
var util = require("util");

@@ -22,5 +21,5 @@ var fs = require("fs");

var FTP_PORT = 21;
var DEBUG_MODE = false;
var TIMEOUT = 10 * 60 * 1000;
var IDLE_TIME = 30000;
var NOOP = function() {};
var COMMANDS = [

@@ -31,3 +30,3 @@ // Commands without parameters

"cwd", "dele", "list", "mdtm", "mkd", "mode", "nlst", "pass", "retr", "rmd",
"rnfr", "rnto", "site", "stat", "stor", "type", "user", "pass", "xrmd", "opts",
"rnfr", "rnto", "site", "stat", "stor", "type", "user", "xrmd", "opts",
// Extended features

@@ -37,19 +36,28 @@ "chmod", "size"

var Cmds = {};
COMMANDS.forEach(function(cmd) {
cmd = cmd.toLowerCase();
Cmds[cmd] = function() {
var callback = function() {};
var completeCmd = cmd;
if (arguments.length) {
var args = Array.prototype.slice.call(arguments);
if (typeof args[args.length - 1] === "function")
callback = args.pop();
function getPasvPort(text, cb) {
var RE_PASV = /([-\d]+,[-\d]+,[-\d]+,[-\d]+),([-\d]+),([-\d]+)/;
var match = RE_PASV.exec(text);
if (!match) {
return cb(new Error("Bad passive host/port combination"));
}
completeCmd += " " + args.join(" ");
}
this.execute(completeCmd.trim(), callback);
};
});
cb(null, {
host: match[1].replace(/,/g, "."),
port: (parseInt(match[2], 10) & 255) * 256 + (parseInt(match[3], 10) & 255)
});
}
function runCmd(cmd) {
var callback = NOOP;
var args = [].slice.call(arguments);
var completeCmd = args.shift();
if (args.length) {
if (typeof args[args.length - 1] === "function")
callback = args.pop();
completeCmd += " " + args.join(" ");
}
this.execute(completeCmd.trim(), callback);
}
var Ftp = module.exports = function(cfg) {

@@ -76,5 +84,16 @@ "use strict";

// it is the responsability of the user to validate the parameters.
var raw = this.raw = {};
COMMANDS.forEach(function(cmd) { raw[cmd] = Cmds[cmd].bind(this); }, this);
this.raw = function() {
return runCmd.apply(this, arguments);
}.bind(this);
COMMANDS.forEach(function(cmd) {
this.raw[cmd] = runCmd.bind(this, cmd);
}, this);
var self = this;
this.on('data', function(data) {
if (self.debugMode) {
self.emit('jsftp_debug', 'response', data || {});
}
});
this.socket = this._createSocket(this.port, this.host);

@@ -85,5 +104,14 @@ };

Ftp.prototype.setDebugMode = function(debugOn) {
this.debugMode = (debugOn !== false);
};
Ftp.prototype.reemit = function(event) {
var self = this;
return function(data) { self.emit(event, data); }
return function(data) {
self.emit(event, data);
if (self.debugMode) {
self.emit('jsftp_debug', 'event:' + event, data || {});
}
}
};

@@ -95,9 +123,6 @@

this.authenticated = false;
var socket = Net.createConnection(port, host);
var socket = Net.createConnection(port, host, firstAction || NOOP);
socket.on("connect", this.reemit("connect"));
socket.on("timeout", this.reemit("timeout"));
if (firstAction)
socket.once("connect", firstAction);
this._createStreams(socket);

@@ -147,6 +172,6 @@

/**
* Writes a new command to the server.
* Sends a new command to the server.
*
* @param {String} command Command to write in the FTP socket
* @returns void
* @return void
*/

@@ -159,2 +184,6 @@ Ftp.prototype.send = function(command) {

this.pipeline.write(command + "\r\n");
if (this.debugMode) {
this.emit('jsftp_debug', 'user_command', command || {});
}
};

@@ -184,17 +213,18 @@

Ftp.prototype.execute = function(action, callback) {
if (!callback) callback = function() {};
if (!callback) callback = NOOP;
if (this.socket && this.socket.writable) {
this._executeCommand(action, callback);
} else {
var self = this;
this.authenticated = false;
this.socket = this._createSocket(this.port, this.host, function() {
self._executeCommand(action, callback);
});
return this.runCommand(action, callback);
}
var self = this;
this.authenticated = false;
this.socket = this._createSocket(this.port, this.host, function() {
self.runCommand(action, callback);
});
};
Ftp.prototype._executeCommand = function(action, callback) {
Ftp.prototype.runCommand = function(action, callback) {
var self = this;
function executeCmd() {

@@ -206,8 +236,8 @@ self.cmdBuffer_.push([action, callback]);

if (self.authenticated || /feat|syst|user|pass/.test(action)) {
executeCmd();
} else {
this.getFeatures(function() {
self.auth(self.user, self.pass, executeCmd);
});
return executeCmd();
}
this.getFeatures(function() {
self.auth(self.user, self.pass, executeCmd);
});
};

@@ -218,8 +248,6 @@

* together. That is, each time that there is a round trip of actions
* between the client and the server. The `action` param contains an array
* with the response from the server as a first element (text) and an array
* with the command executed and the callback (if any) as the second
* element.
* between the client and the server.
*
* @param action {Array} Contains server response and client command info.
* @param response {Object} Response from the server (contains text and code).
* @param command {Array} Contains the command executed and a callback (if any).
*/

@@ -239,3 +267,3 @@ Ftp.prototype.parse = function(response, command) {

/**
* Returns true if the current server has the requested feature. False otherwise.
* Returns true if the current server has the requested feature.
*

@@ -246,4 +274,3 @@ * @param {String} feature Feature to look for

Ftp.prototype.hasFeat = function(feature) {
if (feature)
return this.features.indexOf(feature.toLowerCase()) > -1;
return !!feature && this.features.indexOf(feature.toLowerCase()) > -1;
};

@@ -264,6 +291,4 @@

// Below this point all the methods are action helpers for FTP that compose
// several actions in one command
Ftp.prototype.getFeatures = function(callback) {

@@ -311,6 +336,5 @@ var self = this;

if (err)
notifyAll(new Error("Login not accepted"));
if ([230, 202].indexOf(res.code) > -1) {
if (err) {
notifyAll(err);
} else if ([230, 202].indexOf(res.code) > -1) {
self.authenticated = true;

@@ -328,3 +352,3 @@ self.user = user;

self.authenticating = false;
notifyAll(new Error("Login not accepted"));
notifyAll(err);
}

@@ -372,2 +396,4 @@ });

self.getPasvSocket(function(err, socket) {
self.pasvTimeout.bind(self, socket, cb);
socket.on("data", function(data) {

@@ -409,6 +435,6 @@ listing += data;

if (arguments.length === 2) {
callback = once(localPath || function() {});
callback = once(localPath || NOOP);
this.getGetSocket(remotePath, callback);
} else {
callback = once(callback || function() {});
callback = once(callback || NOOP);
this.getGetSocket(remotePath, function(err, socket) {

@@ -450,2 +476,3 @@ if (err) {

self.pasvTimeout.bind(self, socket, cmdCallback);
socket.pause();

@@ -479,2 +506,20 @@

Ftp.prototype.put = function(from, to, callback) {
var self = this;
function putReadable(from, to, totalSize, callback) {
from.on("readable", function() {
self.emitProgress({
filename: to,
action: "put",
socket: from,
totalSize: totalSize
});
});
self.getPutSocket(to, function(err, socket) {
if (err) return;
from.pipe(socket);
}, callback);
}
if (from instanceof Buffer) {

@@ -484,4 +529,3 @@ this.getPutSocket(to, function(err, socket) {

}, callback);
} else {
var self = this;
} else if (typeof from === "string" || from instanceof String) {
fs.exists(from, function(exists) {

@@ -491,22 +535,12 @@ if (!exists)

self.getPutSocket(to, function(err, socket) {
if (err) return;
fs.stat(from, function(err, stats) {
var totalSize = err ? 0 : stats.size;
var read = fs.createReadStream(from, {
bufferSize: 4 * 1024
});
read.pipe(socket);
read.on('readable', function() {
self.emitProgress({
filename: to,
action: 'put',
socket: read,
totalSize: totalSize
});
});
fs.stat(from, function(err, stats) {
var totalSize = err ? 0 : stats.size;
var read = fs.createReadStream(from, {
bufferSize: 4 * 1024
});
}, callback);
putReadable(read, to, totalSize, callback);
});
});
} else {
putReadable(from, to, from.size, callback);
}

@@ -518,3 +552,3 @@ };

doneCallback = once(doneCallback || function() {});
doneCallback = once(doneCallback || NOOP);
var _callback = once(function(err, _socket) {

@@ -540,2 +574,3 @@ if (err) {

socket.on('error', doneCallback);
self.pasvTimeout.bind(self, socket, doneCallback);
_callback(null, socket);

@@ -554,17 +589,24 @@ } else {

Ftp.prototype.pasvTimeout = function(socket, cb) {
var self = this;
socket.once('timeout', function() {
self.emit('timeout');
socket.destroy();
cb(new Error("Passive socket timeout"));
});
};
Ftp.prototype.getPasvSocket = function(callback) {
var timeout = this.timeout;
callback = once(callback || function() {});
callback = once(callback || NOOP);
this.execute("pasv", function(err, res) {
if (err) return callback(err);
var pasvRes = Utils.getPasvPort(res.text);
if (pasvRes === false)
return callback(new Error("PASV: Bad host/port combination"));
getPasvPort(res.text, function(err, res) {
if (err) return callback(err);
var host = pasvRes[0];
var port = pasvRes[1];
var socket = Net.createConnection(port, host);
socket.setTimeout(timeout || TIMEOUT);
callback(null, socket);
var socket = Net.createConnection(res.port, res.host);
socket.setTimeout(timeout || TIMEOUT);
callback(null, socket);
});
});

@@ -643,3 +685,3 @@ };

Ftp.prototype.keepAlive = function() {
Ftp.prototype.keepAlive = function(wait) {
var self = this;

@@ -649,3 +691,3 @@ if (this._keepAliveInterval)

this._keepAliveInterval = setInterval(self.raw.noop, IDLE_TIME);
this._keepAliveInterval = setInterval(self.raw.noop, wait || IDLE_TIME);
};

@@ -652,0 +694,0 @@

{
"name": "jsftp",
"id": "jsftp",
"version": "1.2.1",
"version": "1.3.0",
"description": "A sane FTP client implementation for NodeJS",

@@ -6,0 +6,0 @@ "keywords": [ "ftp", "protocol", "files", "server", "client", "async" ],

@@ -200,4 +200,4 @@ jsftp <a href="http://flattr.com/thing/1452098/" target="_blank"><img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>

#### Ftp.keepAlive()
Refreshes the interval thats keep the server connection active.
#### Ftp.keepAlive([wait])
Refreshes the interval thats keep the server connection active. `wait` is an optional time period (in milliseconds) to wait between intervals.

@@ -207,2 +207,50 @@ You can find more usage examples in the [unit tests](https://github.com/sergi/jsftp/blob/master/test/jsftp_test.js). This documentation

Debugging
---------
In order to enable debug mode in a FTP connection, a `debugMode` parameter can
be used in the constructors's config object:
```javascript
var Ftp = new JSFtp({
host: "myserver.com",
port: 3331,
user: "user",
pass: "1234",
debugMode: true
});
```
It can also be activated or deactivated by calling the `setDebugMode` method:
```javascript
Ftp.setDebugMode(true); // Debug Mode on
Ftp.setDebugMode(false; // Debug mode off
```
If the debug mode is on, the jsftp instance will emit `jsftp_debug` events with
two parameters: the first is the type of the event and the second and object
including data related to the event. There are 3 possible types of events:
- `response` events: These are response from the FTP server to the user's FTP
commands
- `user_command` events: These are commands that the user issuendss to the
FTP server.
- `event:{event name}` events: These are other events mostly related to the server
connection, such as `timeout`, `connect` or `disconnect`. For example,
a timeout event will have the name `event:timeout`.
In order to react to print all debug events (for example), we would listen to the
debug messages like this:
```javascript
Ftp.on('jsftp_debug', function(eventType, data) {
console.log('DEBUG: ', eventType);
console.log(JSON.stringify(data, null, 2));
});
```
Installation

@@ -222,4 +270,4 @@ ------------

Current overall coverage rate:
lines......: 92.1% (316 of 343 lines)
functions..: 91.0% (71 of 78 functions)
lines......: 95.5% (278 of 291 lines)
functions..: 100% (69 of 69 functions)

@@ -226,0 +274,0 @@

@@ -16,3 +16,2 @@ /*

var Path = require("path");
var Utils = require("../lib/utils");
var sinon = require("sinon");

@@ -223,2 +222,26 @@ var EventEmitter = require("events").EventEmitter;

it("test invalid username", function(next) {
this.timeout(10000);
ftp.auth(
FTPCredentials.user + '_invalid',
FTPCredentials.pass,
function(err, data) {
assert.equal(err.code, 530);
assert.equal(data, null);
next();
});
});
it("test invalid password", function(next) {
this.timeout(10000);
ftp.auth(
FTPCredentials.user,
FTPCredentials.pass + '_invalid',
function(err, data) {
assert.equal(err.code, 530);
assert.equal(data, null);
next();
});
});
it("test getFeatures", function(next) {

@@ -233,2 +256,6 @@ ftp.getFeatures(function(err, feats) {

assert.equal(false, ftp.hasFeat("madeup-feat"));
assert.equal(false, ftp.hasFeat());
assert.equal(false, ftp.hasFeat(null));
assert.equal(false, ftp.hasFeat(''));
assert.equal(false, ftp.hasFeat(0));
next();

@@ -368,2 +395,22 @@ });

it("test streaming put", function(next) {
var readStream = Fs.createReadStream(__filename);
var remoteFileName = "file_ftp_test.txt";
var filePath = getRemotePath(remoteFileName);
ftp.put(readStream, filePath, function(hadError) {
assert.ok(!hadError);
ftp.ls(filePath, function(err, res) {
assert.ok(!err);
assert.equal(res[0].size, Fs.statSync(CWD + "/jsftp_test.js").size);
ftp.raw.dele(filePath, function(err, data) {
assert.ok(!err);
next();
});
});
});
});
it("test rename a file", function(next) {

@@ -671,2 +718,51 @@ var from = getRemotePath("file_ftp_test.txt");

});
it("Test raw method with PWD", function(next) {
ftp.raw('pwd', function(err, res) {
assert(!err, err);
var code = parseInt(res.code, 10);
assert.ok(code === 257, "Raw PWD command was not successful: " + res.text);
next();
});
});
it("Test raw method with HELP", function(next) {
ftp.raw('help', function(err, res) {
assert(!err, err);
var code = parseInt(res.code, 10);
assert.ok(code === 214, "Raw HELP command was not successful: " + res.text);
next();
});
});
it("Test keep-alive with NOOP", function(next) {
this.timeout(10000);
ftp.keepAlive();
ftp.keepAlive(1000);
setTimeout(function() {
ftp.destroy();
next();
}, 5000);
});
it("Test debug mode", function(next) {
var debugCredentials = JSON.parse(JSON.stringify(FTPCredentials));
debugCredentials.debugMode = true;
var ftp2 = new Ftp(debugCredentials);
ftp2.once('jsftp_debug', function(type, data) {
next();
});
});
it("Test debug mode `setDebugMode`", function(next) {
ftp.setDebugMode(true);
ftp.once('jsftp_debug', function(type, data) {
next();
});
});
});

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