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

sftp-ws

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sftp-ws - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

lib/channel-stream.js

78

lib/channel.js

@@ -1,77 +0,1 @@

var Channel = (function () {
function Channel(session, ws) {
this.session = session;
this.ws = ws;
this.options = { binary: true }; //WEB: // removed
}
Channel.prototype.start = function () {
var _this = this;
this.ws.on('close', function (code, message) {
//WEB: var code = e.code;
//WEB: var message = e.reason;
_this.log.info("Connection closed:", code, message);
_this.close(1000); // normal close
}); //WEB: };
this.ws.on('error', function (err) {
//this.emit('error', err);
var name = err.name; //WEB: var name = typeof err;
_this.log.error("Socket error:", err.message, name);
_this.close(1011); // unexpected condition
}); //WEB: };
this.ws.on('message', function (data, flags) {
var request;
if (flags.binary) {
request = data; //WEB: request = new Uint8Array(message.data);
}
else {
_this.log.error("Text packet received, but not supported yet.");
_this.close(1003); // unsupported data
return;
}
try {
_this.session._process(request);
}
catch (error) {
_this.log.error("Error while processing packet:", error);
_this.close(1011); // unexpected condition
}
}); //WEB: };
};
Channel.prototype.send = function (packet) {
var _this = this;
if (this.ws == null)
return;
this.ws.send(packet, this.options, function (err) {
if (typeof err !== 'undefined' && err != null) {
_this.log.error("Error while sending:", err.message, err.name); //WEB: // removed
_this.close(1011); //WEB: // removed
} //WEB: // removed
}); //WEB: // removed
};
Channel.prototype.close = function (reason) {
if (this.ws == null)
return;
if (typeof reason === 'undefined')
reason = 1000; // normal close
try {
this.ws.close(reason, "closed");
}
catch (error) {
this.log.error("Error while closing WebSocket:", error);
}
finally {
this.ws = null;
}
try {
this.session._end();
}
catch (error) {
this.log.error("Error while closing session:", error);
}
finally {
this.session = null;
}
};
return Channel;
})();
exports.Channel = Channel;
var fs = require("fs");
var Path = require("path");
var misc = require("./fs-misc");
var Path = misc.Path;
var FileUtil = misc.FileUtil;
var LocalError = (function () {

@@ -15,4 +17,22 @@ function LocalError(message, isPublic) {

}
LocalFilesystem.prototype.checkPath = function (path, name) {
var localPath = Path.create(path, this, name);
var path = localPath.path;
if (path[0] == '~') {
var home = (process.env.HOME || process.env.USERPROFILE || ".");
if (path.length == 1)
return home;
if (path[1] === '/' || (path[1] === '\\' && this.isWindows)) {
path = localPath.join(home, path.substr(2)).path;
}
}
return path;
};
LocalFilesystem.prototype.open = function (path, flags, attrs, callback) {
var mode = typeof attrs === 'object' ? attrs.mode : undefined;
if (typeof attrs === 'function' && typeof callback === 'undefined') {
callback = attrs;
attrs = null;
}
path = this.checkPath(path, 'path');
var mode = (attrs && typeof attrs === 'object') ? attrs.mode : undefined;
fs.open(path, flags, mode, function (err, fd) { return callback(err, fd); });

@@ -48,6 +68,7 @@ //LATER: pay attemtion to attrs other than mode (low priority - many SFTP servers ignore these as well)

if (typeof err === 'undefined' || err == null) {
offset += bytesRead;
length -= bytesRead;
totalBytes += bytesRead;
if (length > 0 && bytesRead > 0) {
offset += bytesRead;
position += bytesRead;
read();

@@ -58,3 +79,3 @@ return;

if (typeof callback === 'function')
callback(err, totalBytes, buffer.slice(initialOffset, initialOffset + totalBytes));
callback(err, totalBytes, buffer);
});

@@ -68,5 +89,6 @@ };

if (typeof err === 'undefined' || err == null) {
offset += bytesWritten;
length -= bytesWritten;
if (length > 0) {
offset += bytesWritten;
position += bytesWritten;
write();

@@ -83,2 +105,3 @@ return;

LocalFilesystem.prototype.lstat = function (path, callback) {
path = this.checkPath(path, 'path');
fs.lstat(path, callback);

@@ -115,2 +138,3 @@ };

LocalFilesystem.prototype.setstat = function (path, attrs, callback) {
path = this.checkPath(path, 'path');
var actions = new Array();

@@ -166,3 +190,7 @@ if (!isNaN(attrs.uid) || !isNaN(attrs.gid))

LocalFilesystem.prototype.opendir = function (path, callback) {
var _this = this;
path = this.checkPath(path, 'path');
fs.readdir(path, function (err, files) {
if (files)
files.splice(0, 0, ".", "..");
if (typeof err !== 'undefined' && err != null) {

@@ -172,3 +200,3 @@ files = null;

else if (Array.isArray(files)) {
files["path"] = path;
files["path"] = new Path(path, _this).normalize();
err = null;

@@ -194,3 +222,3 @@ }

path = handle.path;
if (typeof path !== 'string')
if (typeof path !== 'object')
err = new LocalError("Invalid handle", true);

@@ -202,8 +230,10 @@ }

}
var windows = this.isWindows;
var items = [];
if (err == null) {
var list = handle;
if (list.length > 0) {
var next = function () {
if (items.length >= 64 || list.length == 0) {
var paths = handle.splice(0, 64);
if (paths.length > 0) {
function next() {
var name = paths.shift();
if (!name) {
if (typeof callback == 'function') {

@@ -214,4 +244,3 @@ callback(null, (items.length > 0) ? items : false);

}
var name = list.shift();
var itemPath = Path.join(path, name);
var itemPath = path.join(name).path;
fs.stat(itemPath, function (err, stats) {

@@ -221,7 +250,13 @@ if (typeof err !== 'undefined' && err != null) {

else {
items.push({ filename: name, stats: stats });
//
items.push({
filename: name,
longname: FileUtil.toString(name, stats),
stats: stats
});
}
next();
});
};
}
;
next();

@@ -238,6 +273,12 @@ return;

LocalFilesystem.prototype.unlink = function (path, callback) {
path = this.checkPath(path, 'path');
fs.unlink(path, callback);
};
LocalFilesystem.prototype.mkdir = function (path, attrs, callback) {
var mode = typeof attrs === 'object' ? attrs.mode : undefined;
path = this.checkPath(path, 'path');
if (typeof attrs === 'function' && typeof callback === 'undefined') {
callback = attrs;
attrs = null;
}
var mode = (attrs && typeof attrs === 'object') ? attrs.mode : undefined;
fs.mkdir(path, mode, callback);

@@ -247,23 +288,36 @@ //LATER: pay attemtion to attrs other than mode (low priority - many SFTP servers ignore these as well)

LocalFilesystem.prototype.rmdir = function (path, callback) {
path = this.checkPath(path, 'path');
fs.rmdir(path, callback);
};
LocalFilesystem.prototype.realpath = function (path, callback) {
path = this.checkPath(path, 'path');
fs.realpath(path, callback);
};
LocalFilesystem.prototype.stat = function (path, callback) {
path = this.checkPath(path, 'path');
fs.stat(path, callback);
};
LocalFilesystem.prototype.rename = function (oldPath, newPath, callback) {
oldPath = this.checkPath(oldPath, 'oldPath');
newPath = this.checkPath(newPath, 'newPath');
fs.rename(oldPath, newPath, callback);
};
LocalFilesystem.prototype.readlink = function (path, callback) {
path = this.checkPath(path, 'path');
fs.readlink(path, callback);
};
LocalFilesystem.prototype.symlink = function (targetpath, linkpath, callback) {
LocalFilesystem.prototype.symlink = function (targetPath, linkPath, callback) {
targetPath = this.checkPath(targetPath, 'targetPath');
linkPath = this.checkPath(linkPath, 'linkPath');
//TODO: make sure the order is correct (beware - other SFTP client and server vendors are confused as well)
//TODO: make sure this work on Windows
fs.symlink(linkpath, targetpath, 'file', callback);
fs.symlink(linkPath, targetPath, 'file', callback);
};
LocalFilesystem.prototype.link = function (oldPath, newPath, callback) {
oldPath = this.checkPath(oldPath, 'oldPath');
newPath = this.checkPath(newPath, 'newPath');
fs.link(oldPath, newPath, callback);
};
return LocalFilesystem;
})();
exports.LocalFilesystem = LocalFilesystem;

@@ -7,37 +7,26 @@ var __extends = this.__extends || function (d, b) {

};
var events = require("events"); //WEB: /// <reference path="misc-web.ts" />
var misc = require("./fs-misc");
var sources = require("./fs-sources");
var targets = require("./fs-targets");
var util = require("./util");
var glob = require("./fs-glob");
var events = require("events");
var FileUtil = misc.FileUtil;
var Path = misc.Path;
var FileDataTarget = targets.FileDataTarget;
var StringDataTarget = targets.StringDataTarget;
var BufferDataTarget = targets.BufferDataTarget;
var FileDataSource = sources.FileDataSource;
var toDataSource = sources.toDataSource;
var Task = util.Task;
var wrapCallback = util.wrapCallback;
var EventEmitter = events.EventEmitter;
var search = glob.search;
var FilesystemPlus = (function (_super) {
__extends(FilesystemPlus, _super);
function FilesystemPlus(fs) {
function FilesystemPlus(fs, local) {
_super.call(this);
this._fs = fs;
this._local = local;
}
FilesystemPlus.prototype.wrapCallback = function (callback) {
var _this = this;
if (typeof callback !== 'function') {
// use dummy callback to prevent having to check this later
return function () {
};
}
else {
return function () {
try {
callback.apply(_this, arguments);
}
catch (error) {
_this.emit("error", error);
}
};
}
};
FilesystemPlus.prototype.on = function (event, listener) {
return _super.prototype.on.call(this, event, listener);
};
FilesystemPlus.prototype.once = function (event, listener) {
return _super.prototype.once.call(this, event, listener); //WEB: // removed
}; //WEB: // removed
FilesystemPlus.prototype.addListener = function (event, listener) {
return _super.prototype.addListener.call(this, event, listener);
};
FilesystemPlus.prototype.open = function (path, flags, attrs, callback) {

@@ -48,70 +37,54 @@ if (typeof attrs === 'function' && typeof callback === 'undefined') {

}
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.open(path, flags, attrs, callback);
};
FilesystemPlus.prototype.close = function (handle, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.close(handle, callback);
};
FilesystemPlus.prototype.read = function (handle, buffer, offset, length, position, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.read(handle, buffer, offset, length, position, callback);
};
FilesystemPlus.prototype.write = function (handle, buffer, offset, length, position, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.write(handle, buffer, offset, length, position, callback);
};
FilesystemPlus.prototype.lstat = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.lstat(path, callback);
};
FilesystemPlus.prototype.fstat = function (handle, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.fstat(handle, callback);
};
FilesystemPlus.prototype.setstat = function (path, attrs, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.setstat(path, attrs, callback);
};
FilesystemPlus.prototype.fsetstat = function (handle, attrs, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.fsetstat(handle, attrs, callback);
};
FilesystemPlus.prototype.opendir = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.opendir(path, callback);
};
FilesystemPlus.prototype.readdir = function (handle, callback) {
var _this = this;
callback = this.wrapCallback(callback);
if (typeof handle !== 'string')
return this._fs.readdir(handle, callback);
var path = handle;
var list = [];
var next = function (err, items) {
if (err != null) {
_this.close(handle);
callback(err, list);
return;
}
if (items === false) {
_this.close(handle, function (err) {
callback(err, list);
});
return;
}
list = list.concat(items);
_this._fs.readdir(handle, next);
};
this.opendir(path, function (err, h) {
if (err != null) {
callback(err, null);
return;
}
handle = h;
next(null, []);
});
if (typeof handle === 'string') {
var path = Path.check(handle, 'path');
var options = {
noglobstar: true,
nowildcard: true,
listonly: true,
dotdirs: true
};
search(this._fs, path, null, options, callback);
return;
}
callback = wrapCallback(this, null, callback);
return this._fs.readdir(handle, callback);
};
FilesystemPlus.prototype.unlink = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.unlink(path, callback);

@@ -124,31 +97,254 @@ };

}
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.mkdir(path, attrs, callback);
};
FilesystemPlus.prototype.rmdir = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.rmdir(path, callback);
};
FilesystemPlus.prototype.realpath = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.realpath(path, callback);
};
FilesystemPlus.prototype.stat = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.stat(path, callback);
};
FilesystemPlus.prototype.rename = function (oldPath, newPath, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.rename(oldPath, newPath, callback);
};
FilesystemPlus.prototype.readlink = function (path, callback) {
callback = this.wrapCallback(callback);
callback = wrapCallback(this, null, callback);
this._fs.readlink(path, callback);
};
FilesystemPlus.prototype.symlink = function (targetpath, linkpath, callback) {
callback = this.wrapCallback(callback);
this._fs.symlink(targetpath, linkpath);
callback = wrapCallback(this, null, callback);
this._fs.symlink(targetpath, linkpath, callback);
};
FilesystemPlus.prototype.join = function () {
var paths = [];
for (var _i = 0; _i < arguments.length; _i++) {
paths[_i - 0] = arguments[_i];
}
var path = new Path("", this._fs);
return path.join.apply(path, arguments).normalize().path;
};
FilesystemPlus.prototype.link = function (oldPath, newPath, callback) {
callback = wrapCallback(this, null, callback);
this._fs.link(oldPath, newPath, callback);
};
FilesystemPlus.prototype.list = function (remotePath, callback) {
var remotePath = Path.check(remotePath, 'remotePath');
var options = {
directories: true,
files: true,
nosort: false,
dotdirs: false,
noglobstar: true,
listonly: true
};
var task = new Task();
callback = wrapCallback(this, task, callback);
search(this._fs, remotePath, task, options, callback);
return task;
};
FilesystemPlus.prototype.search = function (remotePath, options, callback) {
var remotePath = Path.check(remotePath, 'remotePath');
if (typeof options === 'function' && typeof callback === 'undefined') {
callback = options;
options = null;
}
var task = new Task();
callback = wrapCallback(this, task, callback);
search(this._fs, remotePath, task, options, callback);
return task;
};
FilesystemPlus.prototype.info = function (remotePath, callback) {
var remotePath = Path.check(remotePath, 'remotePath');
var options = {
itemonly: true
};
var task = new Task();
callback = wrapCallback(this, task, callback);
search(this._fs, remotePath, task, options, function (err, items) {
if (err)
return callback(err, null);
if (!items || items.length != 1)
return callback(new Error("Unexpected result"), null);
callback(null, items[0]);
});
return task;
};
FilesystemPlus.prototype.readFile = function (remotePath, options, callback) {
var remote = Path.create(remotePath, this._fs, 'remotePath');
if (typeof options === 'function' && typeof callback === 'undefined') {
callback = options;
options = null;
}
var task = new Task();
callback = wrapCallback(this, task, callback);
// process options
options = options || {};
var type = options.type;
var encoding = options.encoding;
if (type) {
type = (type + "").toLowerCase();
if (type == "string" || type == "text")
encoding = encoding || "utf8";
}
else {
type = encoding ? "string" : "buffer";
}
// create appropriate target
var target;
switch (type) {
case "text":
case "string":
target = new StringDataTarget(encoding);
break;
case "array":
case "buffer":
target = new BufferDataTarget();
break;
case "blob":
default:
throw new Error("Unsupported data kind: " + options.type);
}
// create source
var source = new FileDataSource(remote.fs, remote.path);
// copy file data
FileUtil.copy(source, target, task, function (err) {
if (err)
return callback(err, null);
callback(null, target.result());
});
return task;
};
FilesystemPlus.prototype.putFile = function (localPath, remotePath, callback) {
var local = Path.create(localPath, this._local, 'localPath');
var remote = Path.create(remotePath, this._fs, 'remotePath');
return this._copyFile(local, remote, callback);
};
FilesystemPlus.prototype.getFile = function (remotePath, localPath, callback) {
var remote = Path.create(remotePath, this._fs, 'remotePath');
var local = Path.create(localPath, this._local, 'localPath');
return this._copyFile(remote, local, callback);
};
FilesystemPlus.prototype._copyFile = function (sourcePath, targetPath, callback) {
var task = new Task();
callback = wrapCallback(this, task, callback);
// append filename if target path ens with slash
if (targetPath.endsWithSlash()) {
var filename = sourcePath.getName();
targetPath = targetPath.join(filename);
}
// create source and target
var source = new FileDataSource(sourcePath.fs, sourcePath.path);
var target = new FileDataTarget(targetPath.fs, targetPath.path);
// copy file data
FileUtil.copy(source, target, task, function (err) { return callback(err); });
return task;
};
FilesystemPlus.prototype.upload = function (input, remotePath, callback) {
var remote = Path.create(remotePath, this._fs, 'remotePath');
return this._copy(input, this._local, remote, callback);
};
FilesystemPlus.prototype.download = function (remotePath, localPath, callback) {
var local = Path.create(localPath, this._local, 'localPath');
return this._copy(remotePath, this._fs, local, callback);
};
FilesystemPlus.prototype._copy = function (from, fromFs, toPath, callback) {
var task = new Task();
callback = wrapCallback(this, task, callback);
var sources = null;
var toFs = toPath.fs;
toPath = toPath.removeTrailingSlash();
toFs.stat(toPath.path, prepare);
var directories = {};
return task;
function prepare(err, stats) {
if (err)
return callback(err);
if (!FileUtil.isDirectory(stats))
return callback(new Error("Target path is not a directory"));
try {
toDataSource(fromFs, from, task, function (err, src) {
if (err)
return callback(err);
try {
sources = src;
sources.forEach(function (source) {
//TODO: calculate total size
//TODO: make sure that source.name is valid on target fs
});
next();
}
catch (err) {
callback(err);
}
});
}
catch (err) {
callback(err);
}
}
function next() {
var source = sources.shift();
if (!source)
return callback(null);
var targetPath;
if (typeof source.relativePath === "string") {
var relativePath = new Path(source.relativePath, fromFs);
targetPath = toPath.join(relativePath).normalize().path;
checkParent(relativePath, transfer);
}
else {
targetPath = toPath.join(source.name).path;
transfer(null);
}
function transfer(err) {
if (err)
return callback(err);
if (FileUtil.isDirectory(source.stats)) {
FileUtil.mkdir(toFs, targetPath, transferred);
}
else {
var target = new FileDataTarget(toFs, targetPath);
FileUtil.copy(source, target, task, transferred);
}
}
function transferred(err) {
if (err)
return callback(err);
next();
}
}
function checkParent(path, callback) {
var parent = path.getParent();
if (parent.isTop())
return callback(null);
var exists = directories[parent];
if (exists)
return callback(null);
checkParent(parent, function (err) {
if (err)
return callback(err);
try {
var targetPath = toPath.join(parent).path;
FileUtil.mkdir(toFs, targetPath, function (err) {
if (err)
return callback(err);
directories[parent] = true;
callback(null);
});
}
catch (err) {
callback(err);
}
});
}
};
return FilesystemPlus;
})(EventEmitter);
exports.FilesystemPlus = FilesystemPlus;

@@ -286,4 +286,18 @@ var Path = require("path");

};
SafeFilesystem.prototype.link = function (oldPath, newPath, callback) {
if (this.isReadOnly()) {
this.reportReadOnly(callback);
return;
}
oldPath = this.toRealPath(oldPath);
newPath = this.toRealPath(newPath);
try {
this.fs.link(oldPath, newPath, callback);
}
catch (err) {
callback(err);
}
};
return SafeFilesystem;
})();
exports.SafeFilesystem = SafeFilesystem;

@@ -11,6 +11,4 @@ var __extends = this.__extends || function (d, b) {

var plus = require("./fs-plus");
var channel = require("./channel");
var util = require("./util");
var fsmisc = require("./fs-misc");
var FilesystemPlus = plus.FilesystemPlus;
var Channel = channel.Channel;
var SftpPacket = packet.SftpPacket;

@@ -21,4 +19,27 @@ var SftpPacketWriter = packet.SftpPacketWriter;

var SftpAttributes = misc.SftpAttributes;
var SftpItem = misc.SftpItem;
var toLogWriter = util.toLogWriter;
var SftpExtensions = misc.SftpExtensions;
var Path = fsmisc.Path;
var SftpItem = (function () {
function SftpItem() {
}
return SftpItem;
})();
var SftpHandle = (function () {
function SftpHandle(handle, owner) {
this._handle = handle;
this._this = owner;
}
SftpHandle.prototype.toString = function () {
var value = "0x";
for (var i = 0; i < this._handle.length; i++) {
var b = this._handle[i];
var c = b.toString(16);
if (b < 16)
value += "0";
value += c;
}
return value;
};
return SftpHandle;
})();
var SftpClientCore = (function () {

@@ -30,2 +51,3 @@ function SftpClientCore() {

this._requests = [];
this._extensions = {};
this._maxWriteBlockLength = 32 * 1024;

@@ -35,3 +57,3 @@ this._maxReadBlockLength = 256 * 1024;

SftpClientCore.prototype.getRequest = function (type) {
var request = new SftpPacketWriter(this._maxWriteBlockLength + 1024); //TODO: cache buffers
var request = new SftpPacketWriter(this._maxWriteBlockLength + 1024);
request.type = type;

@@ -55,8 +77,18 @@ request.id = this._id;

};
SftpClientCore.prototype.execute = function (request, callback, responseParser) {
SftpClientCore.prototype.execute = function (request, callback, responseParser, info) {
var _this = this;
if (typeof callback !== 'function') {
// use dummy callback to prevent having to check this later
callback = function () {
callback = function (err) {
if (err)
throw err;
};
}
if (!this._host) {
process.nextTick(function () {
var error = _this.createError(6 /* NO_CONNECTION */, "Not connected", info);
callback(error);
});
return;
}
if (typeof this._requests[request.id] !== 'undefined')

@@ -66,22 +98,41 @@ throw new Error("Duplicate request");

this._host.send(packet);
this._requests[request.id] = { callback: callback, responseParser: responseParser };
this._requests[request.id] = { callback: callback, responseParser: responseParser, info: info };
};
SftpClientCore.prototype._init = function (host, callback) {
var _this = this;
if (this._host)
throw new Error("Already bound");
this._host = host;
this._extensions = {};
var request = this.getRequest(1 /* INIT */);
request.writeInt32(3); // SFTPv3
var info = { command: "init" };
this.execute(request, callback, function (response, cb) {
if (response.type != 2 /* VERSION */) {
callback(new Error("Protocol violation"));
return;
host.close(3002);
var error = _this.createError(5 /* BAD_MESSAGE */, "Unexpected message", info);
return callback(new Error("Protocol violation"));
}
var version = response.readInt32();
if (version != 3) {
callback(new Error("Protocol violation"));
return;
host.close(3002);
var error = _this.createError(5 /* BAD_MESSAGE */, "Unexpected protocol version", info);
return callback(error);
}
while ((response.length - response.position) >= 4) {
var extensionName = response.readString();
var value;
if (SftpExtensions.isKnown(extensionName)) {
value = response.readString();
}
else {
value = response.readData(true);
}
var values = _this._extensions[extensionName] || [];
values.push(value);
_this._extensions[extensionName] = values;
}
_this._ready = true;
callback(null);
});
}, info);
};

@@ -94,11 +145,30 @@ SftpClientCore.prototype._process = function (packet) {

delete this._requests[response.id];
response.info = request.info;
request.responseParser.call(this, response, request.callback);
};
SftpClientCore.prototype._end = function () {
var host = this._host;
if (host)
this._host = null;
this.failRequests(7 /* CONNECTION_LOST */, "Connection lost");
};
SftpClientCore.prototype.end = function () {
this._host.close();
var host = this._host;
if (host) {
this._host = null;
host.close();
}
this.failRequests(7 /* CONNECTION_LOST */, "Connection closed");
};
SftpClientCore.prototype.failRequests = function (code, message) {
var _this = this;
var requests = this._requests;
this._requests = [];
requests.forEach(function (request) {
var error = _this.createError(code, message, request.info);
request.callback(error);
});
};
SftpClientCore.prototype.open = function (path, flags, attrs, callback) {
path = this.toPath(path, 'path');
path = this.checkPath(path, 'path');
if (typeof attrs === 'function' && typeof callback === 'undefined') {

@@ -110,15 +180,15 @@ callback = attrs;

request.writeString(path);
request.writeInt32(SftpFlags.toFlags(flags));
request.writeInt32(SftpFlags.toNumber(flags));
this.writeStats(request, attrs);
this.execute(request, callback, this.parseHandle);
this.execute(request, callback, this.parseHandle, { command: "open", path: path });
};
SftpClientCore.prototype.close = function (handle, callback) {
handle = this.toHandle(handle);
var h = this.toHandle(handle);
var request = this.getRequest(4 /* CLOSE */);
request.writeData(handle);
this.execute(request, callback, this.parseStatus);
request.writeData(h);
this.execute(request, callback, this.parseStatus, { command: "close", handle: handle });
};
SftpClientCore.prototype.read = function (handle, buffer, offset, length, position, callback) {
var _this = this;
handle = this.toHandle(handle);
var h = this.toHandle(handle);
this.checkBuffer(buffer, offset, length);

@@ -130,9 +200,9 @@ this.checkPosition(position);

var request = this.getRequest(5 /* READ */);
request.writeData(handle);
request.writeData(h);
request.writeInt64(position);
request.writeInt32(length);
this.execute(request, callback, function (response, cb) { return _this.parseData(response, cb, buffer, offset, length); });
this.execute(request, callback, function (response, cb) { return _this.parseData(response, callback, 0, h, buffer, offset, length, position); }, { command: "read", handle: handle });
};
SftpClientCore.prototype.write = function (handle, buffer, offset, length, position, callback) {
handle = this.toHandle(handle);
var h = this.toHandle(handle);
this.checkBuffer(buffer, offset, length);

@@ -143,47 +213,47 @@ this.checkPosition(position);

var request = this.getRequest(6 /* WRITE */);
request.writeData(handle);
request.writeData(h);
request.writeInt64(position);
request.writeData(buffer, offset, offset + length);
this.execute(request, callback, this.parseStatus);
this.execute(request, callback, this.parseStatus, { command: "write", handle: handle });
};
SftpClientCore.prototype.lstat = function (path, callback) {
path = this.toPath(path, 'path');
this.command(7 /* LSTAT */, [path], callback, this.parseAttribs);
path = this.checkPath(path, 'path');
this.command(7 /* LSTAT */, [path], callback, this.parseAttribs, { command: "lstat", path: path });
};
SftpClientCore.prototype.fstat = function (handle, callback) {
handle = this.toHandle(handle);
var h = this.toHandle(handle);
var request = this.getRequest(8 /* FSTAT */);
request.writeData(handle);
this.execute(request, callback, this.parseAttribs);
request.writeData(h);
this.execute(request, callback, this.parseAttribs, { command: "fstat", handle: handle });
};
SftpClientCore.prototype.setstat = function (path, attrs, callback) {
path = this.toPath(path, 'path');
path = this.checkPath(path, 'path');
var request = this.getRequest(9 /* SETSTAT */);
request.writeString(path);
this.writeStats(request, attrs);
this.execute(request, callback, this.parseStatus);
this.execute(request, callback, this.parseStatus, { command: "setstat", path: path });
};
SftpClientCore.prototype.fsetstat = function (handle, attrs, callback) {
handle = this.toHandle(handle);
var h = this.toHandle(handle);
var request = this.getRequest(10 /* FSETSTAT */);
request.writeData(handle);
request.writeData(h);
this.writeStats(request, attrs);
this.execute(request, callback, this.parseStatus);
this.execute(request, callback, this.parseStatus, { command: "fsetstat", handle: handle });
};
SftpClientCore.prototype.opendir = function (path, callback) {
path = this.toPath(path, 'path');
this.command(11 /* OPENDIR */, [path], callback, this.parseHandle);
path = this.checkPath(path, 'path');
this.command(11 /* OPENDIR */, [path], callback, this.parseHandle, { command: "opendir", path: path });
};
SftpClientCore.prototype.readdir = function (handle, callback) {
handle = this.toHandle(handle);
var h = this.toHandle(handle);
var request = this.getRequest(12 /* READDIR */);
request.writeData(handle);
this.execute(request, callback, this.parseItems);
request.writeData(h);
this.execute(request, callback, this.parseItems, { command: "readdir", handle: handle });
};
SftpClientCore.prototype.unlink = function (path, callback) {
path = this.toPath(path, 'path');
this.command(13 /* REMOVE */, [path], callback, this.parseStatus);
path = this.checkPath(path, 'path');
this.command(13 /* REMOVE */, [path], callback, this.parseStatus, { command: "unline", path: path });
};
SftpClientCore.prototype.mkdir = function (path, attrs, callback) {
path = this.toPath(path, 'path');
path = this.checkPath(path, 'path');
if (typeof attrs === 'function' && typeof callback === 'undefined') {

@@ -196,52 +266,45 @@ callback = attrs;

this.writeStats(request, attrs);
this.execute(request, callback, this.parseStatus);
this.execute(request, callback, this.parseStatus, { command: "mkdir", path: path });
};
SftpClientCore.prototype.rmdir = function (path, callback) {
path = this.toPath(path, 'path');
this.command(15 /* RMDIR */, [path], callback, this.parseStatus);
path = this.checkPath(path, 'path');
this.command(15 /* RMDIR */, [path], callback, this.parseStatus, { command: "rmdir", path: path });
};
SftpClientCore.prototype.realpath = function (path, callback) {
path = this.toPath(path, 'path');
this.command(16 /* REALPATH */, [path], callback, this.parsePath);
path = this.checkPath(path, 'path');
this.command(16 /* REALPATH */, [path], callback, this.parsePath, { command: "realpath", path: path });
};
SftpClientCore.prototype.stat = function (path, callback) {
path = this.toPath(path, 'path');
this.command(17 /* STAT */, [path], callback, this.parseAttribs);
path = this.checkPath(path, 'path');
this.command(17 /* STAT */, [path], callback, this.parseAttribs, { command: "stat", path: path });
};
SftpClientCore.prototype.rename = function (oldPath, newPath, callback) {
oldPath = this.toPath(oldPath, 'oldPath');
newPath = this.toPath(newPath, 'newPath');
this.command(18 /* RENAME */, [oldPath, newPath], callback, this.parseStatus);
oldPath = this.checkPath(oldPath, 'oldPath');
newPath = this.checkPath(newPath, 'newPath');
this.command(18 /* RENAME */, [oldPath, newPath], callback, this.parseStatus, { command: "rename", oldPath: oldPath, newPath: newPath });
};
SftpClientCore.prototype.readlink = function (path, callback) {
path = this.toPath(path, 'path');
this.command(19 /* READLINK */, [path], callback, this.parsePath);
path = this.checkPath(path, 'path');
this.command(19 /* READLINK */, [path], callback, this.parsePath, { command: "readlink", path: path });
};
SftpClientCore.prototype.symlink = function (targetPath, linkPath, callback) {
targetPath = this.toPath(targetPath, 'targetPath');
linkPath = this.toPath(linkPath, 'linkPath');
this.command(20 /* SYMLINK */, [targetPath, linkPath], callback, this.parseStatus);
targetPath = this.checkPath(targetPath, 'targetPath');
linkPath = this.checkPath(linkPath, 'linkPath');
this.command(20 /* SYMLINK */, [targetPath, linkPath], callback, this.parseStatus, { command: "symlink", targetPath: targetPath, linkPath: linkPath });
};
SftpClientCore.prototype.link = function (oldPath, newPath, callback) {
oldPath = this.checkPath(oldPath, 'oldPath');
newPath = this.checkPath(newPath, 'newPath');
this.command(SftpExtensions.HARDLINK, [oldPath, newPath], callback, this.parseStatus, { command: "link", oldPath: oldPath, newPath: newPath });
};
SftpClientCore.prototype.toHandle = function (handle) {
if (typeof handle === 'object') {
if (!handle) {
throw new Error("Missing handle");
}
else if (typeof handle === 'object') {
if (SftpPacket.isBuffer(handle._handle) && handle._this == this)
return handle._handle;
}
else if (handle == null || typeof handle === 'undefined') {
throw new Error("Missing handle");
}
throw new Error("Invalid handle");
};
SftpClientCore.prototype.toPath = function (path, name) {
if (typeof path !== 'string') {
if (path == null || typeof path === 'undefined')
throw new Error("Missing " + name);
if (typeof path === 'function')
throw new Error("Invalid " + name);
path = new String(path);
}
if (path.length == 0)
throw new Error("Empty " + name);
return path;
};
SftpClientCore.prototype.checkBuffer = function (buffer, offset, length) {

@@ -257,2 +320,14 @@ if (!SftpPacket.isBuffer(buffer))

};
SftpClientCore.prototype.checkPath = function (path, name) {
path = Path.check(path, name);
if (path[0] === '~') {
if (path[1] === '/') {
path = "." + path.substr(1);
}
else if (path.length == 1) {
path = ".";
}
}
return path;
};
SftpClientCore.prototype.checkPosition = function (position) {

@@ -262,3 +337,3 @@ if (typeof position !== 'number' || position < 0 || position > 0x7FFFFFFFFFFFFFFF)

};
SftpClientCore.prototype.command = function (command, args, callback, responseParser) {
SftpClientCore.prototype.command = function (command, args, callback, responseParser, info) {
var request = this.getRequest(command);

@@ -268,11 +343,80 @@ for (var i = 0; i < args.length; i++) {

}
this.execute(request, callback, responseParser);
this.execute(request, callback, responseParser, info);
};
SftpClientCore.prototype.readStatus = function (response) {
var code = response.readInt32();
var nativeCode = response.readInt32();
var message = response.readString();
if (code == 0 /* OK */)
if (nativeCode == 0 /* OK */)
return null;
var error = new Error("SFTP error " + code + ": " + message);
var info = response.info;
return this.createError(nativeCode, message, info);
};
SftpClientCore.prototype.readItem = function (response) {
var item = new SftpItem();
item.filename = response.readString();
item.longname = response.readString();
item.stats = new SftpAttributes(response);
return item;
};
SftpClientCore.prototype.createError = function (nativeCode, message, info) {
var code;
var errno;
switch (nativeCode) {
case 1 /* EOF */:
code = "EOF";
errno = 1;
break;
case 2 /* NO_SUCH_FILE */:
code = "ENOENT";
errno = 34;
break;
case 3 /* PERMISSION_DENIED */:
code = "EACCES";
errno = 3;
break;
case 0 /* OK */:
case 4 /* FAILURE */:
case 5 /* BAD_MESSAGE */:
code = "EFAILURE";
errno = -2;
break;
case 6 /* NO_CONNECTION */:
code = "ENOTCONN";
errno = 31;
break;
case 7 /* CONNECTION_LOST */:
code = "ESHUTDOWN";
errno = 46;
break;
case 8 /* OP_UNSUPPORTED */:
code = "ENOSYS";
errno = 35;
break;
case 5 /* BAD_MESSAGE */:
code = "ESHUTDOWN";
errno = 46;
break;
default:
code = "UNKNOWN";
errno = -1;
break;
}
var command = info.command;
var arg = info.path || info.handle;
if (typeof arg === "string")
arg = "'" + arg + "'";
else if (arg)
arg = new String(arg);
else
arg = "";
var error = new Error(code + ", " + command + " " + arg);
error['errno'] = errno;
error['code'] = code;
for (var name in info) {
if (name == "command")
continue;
if (info.hasOwnProperty(name))
error[name] = info[name];
}
error['nativeCode'] = nativeCode;
error['description'] = message;

@@ -309,3 +453,3 @@ return error;

var handle = response.readData(true);
callback(null, { _handle: handle, _this: this });
callback(null, new SftpHandle(handle, this));
};

@@ -321,5 +465,14 @@ SftpClientCore.prototype.parsePath = function (response, callback) {

};
SftpClientCore.prototype.parseData = function (response, callback, buffer, offset, length) {
if (!this.checkResponse(response, 103 /* DATA */, callback))
return;
SftpClientCore.prototype.parseData = function (response, callback, retries, h, buffer, offset, length, position) {
var _this = this;
if (response.type == 101 /* STATUS */) {
var error = this.readStatus(response);
if (error != null) {
if (error['nativeCode'] == 1 /* EOF */)
callback(null, 0, buffer);
else
callback(error, 0, null);
return;
}
}
var data = response.readData(false);

@@ -329,5 +482,20 @@ if (data.length > length)

length = data.length;
if (length == 0) {
// workaround for broken servers such as Globalscape 7.1.x that occasionally send empty data
if (retries > 4) {
var error = this.createError(4 /* FAILURE */, "Unable to read data", response.info);
error['code'] = "EIO";
error['errno'] = 55;
callback(error, 0, null);
return;
}
var request = this.getRequest(5 /* READ */);
request.writeData(h);
request.writeInt64(position);
request.writeInt32(length);
this.execute(request, callback, function (response, cb) { return _this.parseData(response, callback, retries + 1, h, buffer, offset, length, position); }, response.info);
return;
}
data.copy(buffer, offset, 0, length); //WEB: buffer.set(data, offset);
var view = buffer.slice(offset, offset + length); //WEB: var view = buffer.subarray(offset, offset + length);
callback(null, length, view); //TODO: make sure that this corresponds to the behavior of fs.read
callback(null, length, buffer);
};

@@ -338,3 +506,3 @@ SftpClientCore.prototype.parseItems = function (response, callback) {

if (error != null) {
if (error['code'] == 1 /* EOF */)
if (error['nativeCode'] == 1 /* EOF */)
callback(null, false);

@@ -351,3 +519,3 @@ else

for (var i = 0; i < count; i++) {
items[i] = new SftpItem(response);
items[i] = this.readItem(response);
}

@@ -360,22 +528,67 @@ callback(null, items);

__extends(SftpClient, _super);
function SftpClient(ws, log) {
function SftpClient(local) {
var sftp = new SftpClientCore();
_super.call(this, sftp, local);
}
SftpClient.prototype.bind = function (channel, callback) {
var _this = this;
var sftp = new SftpClientCore();
var channel = new Channel(sftp, ws);
channel.log = toLogWriter(log);
_super.call(this, sftp);
ws.on("open", function () {
channel.start();
sftp._init(channel, function (err) {
if (err != null) {
_this.emit('error', err);
var sftp = this._fs;
if (this._bound)
throw new Error("Already bound");
this._bound = true;
var ready = false;
var self = this;
channel.on("ready", function () {
ready = true;
sftp._init(channel, function (error) {
if (error) {
sftp._end();
_this._bound = false;
return done(error);
}
else {
_this.emit('ready');
done(null);
_this.emit('ready');
});
});
channel.on("message", function (packet) {
try {
sftp._process(packet);
}
catch (err) {
_this.emit("error", err);
sftp.end();
}
});
channel.on("error", function (err) {
_this.emit("error", err);
sftp.end();
});
channel.on("close", function (err) {
if (!ready) {
err = err || new Error("Unable to connect");
done(err);
}
else {
sftp._end();
_this._bound = false;
_this.emit('close', err);
}
});
function done(error) {
if (typeof callback === "function") {
try {
callback(error);
error = null;
}
});
}); //WEB: };
}
catch (err) {
error = err;
}
}
if (error)
self.emit("error", error);
}
};
SftpClient.prototype.end = function () {
this._fs.end();
var sftp = this._fs;
sftp.end();
};

@@ -382,0 +595,0 @@ return SftpClient;

var packet = require("./sftp-packet");
var api = require("./fs-api");
var enums = require("./sftp-enums");

@@ -6,3 +7,5 @@ var SftpFlags = (function () {

}
SftpFlags.toFlags = function (flags) {
SftpFlags.toNumber = function (flags) {
if (typeof flags === 'number')
return flags & 63 /* ALL */;
switch (flags) {

@@ -19,6 +22,6 @@ case 'r':

case 'xw':
return 2 /* WRITE */ | 8 /* CREATE */ | 16 /* TRUNC */ | 32 /* EXCL */;
return 2 /* WRITE */ | 8 /* CREATE */ | 32 /* EXCL */;
case 'wx+':
case 'xw+':
return 2 /* WRITE */ | 8 /* CREATE */ | 16 /* TRUNC */ | 32 /* EXCL */ | 1 /* READ */;
return 2 /* WRITE */ | 8 /* CREATE */ | 32 /* EXCL */ | 1 /* READ */;
case 'a':

@@ -38,39 +41,35 @@ return 2 /* WRITE */ | 8 /* CREATE */ | 4 /* APPEND */;

};
SftpFlags.fromFlags = function (flags) {
var read = ((flags & 1 /* READ */) != 0);
var write = ((flags & 2 /* WRITE */) != 0);
var append = ((flags & 4 /* APPEND */) != 0);
var create = ((flags & 8 /* CREATE */) != 0);
var trunc = ((flags & 16 /* TRUNC */) != 0);
var excl = ((flags & 32 /* EXCL */) != 0);
var modes = [];
if (create) {
if (excl) {
modes.push("wx+");
}
else if (trunc) {
modes.push("w+");
}
else {
modes.push("wx+");
create = false;
}
SftpFlags.fromNumber = function (flags) {
flags &= 63 /* ALL */;
// 'truncate' does not apply when creating a new file
if ((flags & 32 /* EXCL */) != 0)
flags &= 63 /* ALL */ ^ 16 /* TRUNC */;
// 'append' does not apply when truncating
if ((flags & 16 /* TRUNC */) != 0)
flags &= 63 /* ALL */ ^ 4 /* APPEND */;
// 'read' or 'write' must be specified (or both)
if ((flags & (1 /* READ */ | 2 /* WRITE */)) == 0)
flags |= 1 /* READ */;
// when not creating a new file, only 'read' or 'write' applies
// (and when creating a new file, 'write' is required)
if ((flags & 8 /* CREATE */) == 0)
flags &= 1 /* READ */ | 2 /* WRITE */;
else
flags |= 2 /* WRITE */;
switch (flags) {
case 1: return ["r"];
case 2:
case 3: return ["r+"];
case 10: return ["wx", "r+"];
case 11: return ["wx+", "r+"];
case 14: return ["a"];
case 15: return ["a+"];
case 26: return ["w"];
case 27: return ["w+"];
case 42: return ["wx"];
case 43: return ["wx+"];
case 46: return ["ax"];
case 47: return ["ax+"];
}
if (!create) {
if (append) {
if (read) {
modes.push("a+");
}
else {
modes.push("a");
}
}
else if (write) {
modes.push("r+");
}
else {
modes.push("r");
}
}
return modes;
throw Error("Unsupported flags");
};

@@ -80,2 +79,25 @@ return SftpFlags;

exports.SftpFlags = SftpFlags;
var SftpExtensions = (function () {
function SftpExtensions() {
}
SftpExtensions.isKnown = function (name) {
return SftpExtensions.hasOwnProperty("_" + name);
};
SftpExtensions.POSIX_RENAME = "posix-rename@openssh.com"; // "1"
SftpExtensions.STATVFS = "statvfs@openssh.com"; // "2"
SftpExtensions.FSTATVFS = "fstatvfs@openssh.com"; // "2"
SftpExtensions.HARDLINK = "hardlink@openssh.com"; // "1"
SftpExtensions.FSYNC = "fsync@openssh.com"; // "1"
SftpExtensions.NEWLINE = "newline@sftp.ws"; // "\n"
SftpExtensions.CHARSET = "charset@sftp.ws"; // "utf-8"
SftpExtensions._constructor = (function () {
for (var name in SftpExtensions) {
if (SftpExtensions.hasOwnProperty(name)) {
SftpExtensions["_" + SftpExtensions[name]] = true;
}
}
})();
return SftpExtensions;
})();
exports.SftpExtensions = SftpExtensions;
var SftpStatus = (function () {

@@ -94,98 +116,2 @@ function SftpStatus() {

};
SftpStatus.writeError = function (response, err) {
var message;
var code = 4 /* FAILURE */;
switch (err.errno | 0) {
default:
if (err["isPublic"] === true)
message = err.message;
else
message = "Unknown error";
break;
case 1:
message = "End of file";
code = 1 /* EOF */;
break;
case 3:
message = "Permission denied";
code = 3 /* PERMISSION_DENIED */;
break;
case 4:
message = "Try again";
break;
case 9:
message = "Bad file number";
break;
case 10:
message = "Device or resource busy";
break;
case 18:
message = "Invalid argument";
break;
case 20:
message = "Too many open files";
break;
case 24:
message = "File table overflow";
break;
case 25:
message = "No buffer space available";
break;
case 26:
message = "Out of memory";
break;
case 27:
message = "Not a directory";
break;
case 28:
message = "Is a directory";
break;
case 34:
message = "No such file or directory";
code = 2 /* NO_SUCH_FILE */;
break;
case 35:
message = "Function not implemented";
code = 8 /* OP_UNSUPPORTED */;
break;
case 47:
message = "File exists";
break;
case 49:
message = "File name too long";
break;
case 50:
message = "Operation not permitted";
break;
case 51:
message = "Too many symbolic links encountered";
break;
case 52:
message = "Cross-device link ";
break;
case 53:
message = "Directory not empty";
break;
case 54:
message = "No space left on device";
break;
case 55:
message = "I/O error";
break;
case 56:
message = "Read-only file system";
break;
case 57:
message = "No such device";
code = 2 /* NO_SUCH_FILE */;
break;
case 58:
message = "Illegal seek";
break;
case 59:
message = "Operation canceled";
break;
}
this.write(response, code, message);
};
return SftpStatus;

@@ -200,63 +126,41 @@ })();

exports.SftpOptions = SftpOptions;
var SftpItem = (function () {
function SftpItem(arg, stats) {
if (typeof arg === 'object') {
var request = arg;
this.filename = request.readString();
this.longname = request.readString();
this.stats = new SftpAttributes(request);
}
else {
var filename = arg;
this.filename = filename;
this.longname = filename;
if (typeof stats === 'object') {
var attr = new SftpAttributes();
attr.from(stats);
this.stats = attr;
this.longname = attr.toString() + " " + filename;
}
}
}
SftpItem.prototype.write = function (response) {
response.writeString(this.filename);
response.writeString(this.longname);
if (typeof this.stats === "object")
this.stats.write(response);
else
response.writeInt32(0);
};
return SftpItem;
})();
exports.SftpItem = SftpItem;
var SftpAttributes = (function () {
function SftpAttributes(request) {
if (typeof request === 'undefined') {
function SftpAttributes(reader) {
if (typeof reader === 'undefined') {
this.flags = 0;
return;
}
var flags = this.flags = request.readUint32();
var flags = this.flags = reader.readUint32();
if (flags & 1 /* SIZE */) {
this.size = request.readInt64();
this.size = reader.readInt64();
}
if (flags & 2 /* UIDGID */) {
this.uid = request.readInt32();
this.gid = request.readInt32();
this.uid = reader.readInt32();
this.gid = reader.readInt32();
}
if (flags & 4 /* PERMISSIONS */) {
this.mode = request.readUint32();
this.mode = reader.readUint32();
}
if (flags & 8 /* ACMODTIME */) {
this.atime = new Date(1000 * request.readUint32());
this.mtime = new Date(1000 * request.readUint32());
this.atime = new Date(1000 * reader.readUint32());
this.mtime = new Date(1000 * reader.readUint32());
}
if (flags & 2147483648 /* EXTENDED */) {
this.flags &= ~2147483648 /* EXTENDED */;
this.size = request.readInt64();
this.size = reader.readInt64();
for (var i = 0; i < this.size; i++) {
request.skipString();
request.skipString();
reader.skipString();
reader.skipString();
}
}
}
SftpAttributes.prototype.isDirectory = function () {
return (this.mode & 61440 /* ALL */) == 16384 /* DIRECTORY */;
};
SftpAttributes.prototype.isFile = function () {
return (this.mode & 61440 /* ALL */) == 32768 /* REGULAR_FILE */;
};
SftpAttributes.prototype.isSymbolicLink = function () {
return (this.mode & 61440 /* ALL */) == 40960 /* SYMLINK */;
};
SftpAttributes.prototype.write = function (response) {

@@ -313,57 +217,4 @@ var flags = this.flags;

};
SftpAttributes.prototype.toString = function () {
var attrs = this.mode;
var perms;
switch (attrs & 0xE000) {
case 8192 /* CHARACTER_DEVICE */:
perms = "c";
break;
case 16384 /* DIRECTORY */:
perms = "d";
break;
case 24576 /* BLOCK_DEVICE */:
perms = "b";
break;
case 32768 /* REGULAR_FILE */:
perms = "-";
break;
case 40960 /* SYMLINK */:
perms = "l";
break;
case 49152 /* SOCKET */:
perms = "s";
break;
case 4096 /* FIFO */:
perms = "p";
break;
default:
perms = "-";
break;
}
attrs &= 0x1FF;
for (var j = 0; j < 3; j++) {
var mask = (attrs >> ((2 - j) * 3)) & 0x7;
perms += (mask & 4) ? "r" : "-";
perms += (mask & 2) ? "w" : "-";
perms += (mask & 1) ? "x" : "-";
}
var len = this.size.toString();
if (len.length < 9)
len = " ".slice(len.length - 9) + len;
else
len = " " + len;
var modified = this.mtime;
var diff = (new Date().getTime() - modified.getTime()) / (3600 * 24);
var date = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][modified.getUTCMonth()];
var day = modified.getUTCDate();
date += ((day <= 9) ? " " : " ") + day;
if (diff < -30 || diff > 180)
date += " " + modified.getUTCFullYear();
else
date += " " + ("0" + modified.getUTCHours()).slice(-2) + ":" + ("0" + modified.getUTCMinutes()).slice(-2);
var nlink = (typeof this.nlink === 'undefined') ? 1 : this.nlink;
return perms + " " + nlink + " user group " + len + " " + date;
};
return SftpAttributes;
})();
exports.SftpAttributes = SftpAttributes;

@@ -8,2 +8,4 @@ var __extends = this.__extends || function (d, b) {

var enums = require("./sftp-enums");
var charsets = require("./charsets");
var encodeUTF8 = charsets.encodeUTF8;
var SftpPacket = (function () {

@@ -22,3 +24,3 @@ function SftpPacket() {

SftpPacket.isBuffer = function (obj) {
return Buffer.isBuffer(obj);
return Buffer.isBuffer(obj); //WEB: return obj && obj.buffer instanceof ArrayBuffer && typeof obj.byteLength !== "undefined";
};

@@ -44,2 +46,5 @@ return SftpPacket;

this.id = this.readInt32();
if (this.type == 200 /* EXTENDED */) {
this.type = this.readString();
}
}

@@ -49,10 +54,9 @@ }

this.check(1);
var value = this.buffer.readUInt8(this.position, true);
this.position += 1;
var value = this.buffer.readUInt8(this.position++, true); //WEB: var value = this.buffer[this.position++] & 0xFF;
return value;
};
SftpPacketReader.prototype.readInt32 = function () {
this.check(4);
var value = this.buffer.readInt32BE(this.position, true);
this.position += 4;
this.check(4); //WEB: var value = this.readUint32();
var value = this.buffer.readInt32BE(this.position, true); //WEB: if (value & 0x80000000) value -= 0x100000000;
this.position += 4; //WEB: // removed
return value;

@@ -62,4 +66,8 @@ };

this.check(4);
var value = this.buffer.readUInt32BE(this.position, true);
this.position += 4;
var value = this.buffer.readUInt32BE(this.position, true); //WEB: // removed
this.position += 4; //WEB: var value = 0;
//WEB: value |= (this.buffer[this.position++] & 0xFF) << 24;
//WEB: value |= (this.buffer[this.position++] & 0xFF) << 16;
//WEB: value |= (this.buffer[this.position++] & 0xFF) << 8;
//WEB: value |= (this.buffer[this.position++] & 0xFF);
return value;

@@ -77,3 +85,3 @@ };

var end = this.position + length;
var value = this.buffer.toString('utf8', this.position, end);
var value = this.buffer.toString('utf8', this.position, end); //WEB: var value = decodeUTF8(this.buffer, this.position, end);
this.position = end;

@@ -94,9 +102,10 @@ return value;

this.position = end;
//WEB: var view = this.buffer.subarray(start, end);
if (clone) {
var buffer = new Buffer(length);
this.buffer.copy(buffer, 0, start, end);
var buffer = new Buffer(length); //WEB: var buffer = new Uint8Array(length);
this.buffer.copy(buffer, 0, start, end); //WEB: buffer.set(view, 0);
return buffer;
}
else {
return this.buffer.slice(start, end);
return this.buffer.slice(start, end); //WEB: return view;
}

@@ -118,3 +127,8 @@ };

this.writeInt32(0); // length placeholder
this.writeByte(this.type | 0);
if (typeof this.type === "number") {
this.writeByte(this.type);
}
else {
this.writeByte(200 /* EXTENDED */);
}
if (this.type == 1 /* INIT */ || this.type == 2 /* VERSION */) {

@@ -124,2 +138,5 @@ }

this.writeInt32(this.id | 0);
if (typeof this.type !== "number") {
this.writeString(this.type);
}
}

@@ -129,14 +146,18 @@ };

var length = this.position;
this.buffer.writeInt32BE(length - 4, 0, true);
return this.buffer.slice(0, length);
this.position = 0;
this.buffer.writeInt32BE(length - 4, 0, true); //WEB: this.writeInt32(length - 4);
return this.buffer.slice(0, length); //WEB: return this.buffer.subarray(0, length);
};
SftpPacketWriter.prototype.writeByte = function (value) {
this.check(1);
this.buffer.writeInt8(value, this.position, true);
this.position += 1;
this.buffer.writeInt8(value, this.position++, true); //WEB: this.buffer[this.position++] = value & 0xFF;
};
SftpPacketWriter.prototype.writeInt32 = function (value) {
this.check(4);
this.buffer.writeInt32BE(value, this.position, true);
this.position += 4;
this.buffer.writeInt32BE(value, this.position, true); //WEB: // removed
this.position += 4; //WEB: // removed
//WEB: this.buffer[this.position++] = (value >> 24) & 0xFF;
//WEB: this.buffer[this.position++] = (value >> 16) & 0xFF;
//WEB: this.buffer[this.position++] = (value >> 8) & 0xFF;
//WEB: this.buffer[this.position++] = value & 0xFF;
};

@@ -150,21 +171,21 @@ SftpPacketWriter.prototype.writeInt64 = function (value) {

SftpPacketWriter.prototype.writeString = function (value) {
if (typeof value !== "string")
value = "" + value;
var offset = this.position;
this.writeInt32(0); // will get overwritten later
var charLength = value.length;
this.check(value.length); // does not ensure there is enough space (because of UTF-8)
this.buffer._charsWritten = 0;
var bytesWritten = this.buffer.write(value, this.position, undefined, 'utf-8');
var bytesWritten = encodeUTF8(value, this.buffer, this.position);
if (bytesWritten < 0)
throw new Error("Not enough space in the buffer");
// write number of bytes and seek back to the end
this.position = offset;
this.writeInt32(bytesWritten);
this.position += bytesWritten;
if (Buffer._charsWritten != charLength)
throw new Error("Not enough space in the buffer");
// write number of bytes
this.buffer.writeInt32BE(bytesWritten, offset, true);
};
SftpPacketWriter.prototype.writeData = function (data, start, end) {
if (typeof start !== 'undefined')
data = data.slice(start, end);
data = data.slice(start, end); //WEB: data = data.subarray(start, end);
var length = data.length;
this.writeInt32(length);
this.check(length);
data.copy(this.buffer, this.position, 0, length);
data.copy(this.buffer, this.position, 0, length); //WEB: this.buffer.set(data, this.position);
this.position += length;

@@ -171,0 +192,0 @@ };

@@ -10,11 +10,11 @@ var __extends = this.__extends || function (d, b) {

var safe = require("./fs-safe");
var fsmisc = require("./fs-misc");
var enums = require("./sftp-enums");
var channel = require("./channel");
var Channel = channel.Channel;
var FileUtil = fsmisc.FileUtil;
var SftpPacketWriter = packet.SftpPacketWriter;
var SftpPacketReader = packet.SftpPacketReader;
var SftpItem = misc.SftpItem;
var SftpAttributes = misc.SftpAttributes;
var SftpStatus = misc.SftpStatus;
var SftpFlags = misc.SftpFlags;
var SftpExtensions = misc.SftpExtensions;
var SftpResponse = (function (_super) {

@@ -36,13 +36,136 @@ __extends(SftpResponse, _super);

})();
var SftpServerSessionCore = (function () {
function SftpServerSessionCore(host, fs) {
var SftpException = (function () {
function SftpException(err) {
var message;
var code = 4 /* FAILURE */;
var errno = err.errno | 0;
switch (errno) {
default:
if (err["isPublic"] === true)
message = err.message;
else
message = "Unspecified error (" + errno + ")";
break;
case 1:
message = "End of file";
code = 1 /* EOF */;
break;
case 3:
message = "Permission denied";
code = 3 /* PERMISSION_DENIED */;
break;
case 4:
message = "Try again";
break;
case 9:
message = "Bad file number";
break;
case 10:
message = "Device or resource busy";
break;
case 18:
message = "Invalid argument";
break;
case 20:
message = "Too many open files";
break;
case 24:
message = "File table overflow";
break;
case 25:
message = "No buffer space available";
break;
case 26:
message = "Out of memory";
break;
case 27:
message = "Not a directory";
break;
case 28:
message = "Is a directory";
break;
case -4058:
case 34:
message = "No such file or directory";
code = 2 /* NO_SUCH_FILE */;
break;
case 35:
message = "Function not implemented";
code = 8 /* OP_UNSUPPORTED */;
break;
case 47:
message = "File exists";
break;
case 49:
message = "File name too long";
break;
case 50:
message = "Operation not permitted";
break;
case 51:
message = "Too many symbolic links encountered";
break;
case 52:
message = "Cross-device link";
break;
case 53:
message = "Directory not empty";
break;
case 54:
message = "No space left on device";
break;
case 55:
message = "I/O error";
break;
case 56:
message = "Read-only file system";
break;
case 57:
message = "No such device";
code = 2 /* NO_SUCH_FILE */;
break;
case 58:
message = "Illegal seek";
break;
case 59:
message = "Operation canceled";
break;
}
this.name = "SftpException";
this.message = message;
this.code = code;
this.errno = errno;
}
return SftpException;
})();
var SftpServerSession = (function () {
function SftpServerSession(channel, fs, emitter, log) {
var _this = this;
this._fs = fs;
this._host = host;
this._handles = new Array(SftpServerSessionCore.MAX_HANDLE_COUNT + 1);
this._channel = channel;
this._log = log;
this._handles = new Array(SftpServerSession.MAX_HANDLE_COUNT + 1);
this.nextHandle = 1;
channel.on("message", function (packet) {
try {
_this._process(packet);
}
catch (err) {
emitter.emit("error", err, _this);
_this.end();
}
});
channel.on("error", function (err) {
emitter.emit("error", err, _this);
_this.end();
});
channel.on("close", function (err) {
_this._end();
emitter.emit("closedSession", _this, err);
});
}
SftpServerSessionCore.prototype.send = function (response) {
SftpServerSession.prototype.send = function (response) {
// send packet
var packet = response.finish();
this._host.send(packet);
this._channel.send(packet);
// start next task

@@ -53,20 +176,29 @@ if (typeof response.handleInfo === 'object') {

};
SftpServerSessionCore.prototype.sendStatus = function (response, code, message) {
SftpServerSession.prototype.sendStatus = function (response, code, message) {
SftpStatus.write(response, code, message);
this.send(response);
};
SftpServerSessionCore.prototype.sendError = function (response, err) {
var log = this._host.log;
if (typeof log === 'object' && typeof log.error === 'function')
log.error(err);
SftpStatus.writeError(response, err);
SftpServerSession.prototype.sendError = function (response, err, isFatal) {
var message;
var code;
if (!isFatal) {
var error = new SftpException(err);
code = error.code;
message = error.message;
}
else {
code = 4 /* FAILURE */;
message = "Internal server error";
this._log.error("Fatal error while processing request #" + response.id + ": " + err);
}
SftpStatus.write(response, code, message);
this.send(response);
};
SftpServerSessionCore.prototype.sendIfError = function (response, err) {
SftpServerSession.prototype.sendIfError = function (response, err) {
if (err == null || typeof err === 'undefined')
return false;
this.sendError(response, err);
this.sendError(response, err, false);
return true;
};
SftpServerSessionCore.prototype.sendSuccess = function (response, err) {
SftpServerSession.prototype.sendSuccess = function (response, err) {
if (this.sendIfError(response, err))

@@ -77,3 +209,3 @@ return;

};
SftpServerSessionCore.prototype.sendAttribs = function (response, err, stats) {
SftpServerSession.prototype.sendAttribs = function (response, err, stats) {
if (this.sendIfError(response, err))

@@ -88,3 +220,3 @@ return;

};
SftpServerSessionCore.prototype.sendHandle = function (response, handleInfo) {
SftpServerSession.prototype.sendHandle = function (response, handleInfo) {
response.type = 102 /* HANDLE */;

@@ -96,3 +228,3 @@ response.start();

};
SftpServerSessionCore.prototype.sendPath = function (response, err, path) {
SftpServerSession.prototype.sendPath = function (response, err, path) {
if (this.sendIfError(response, err))

@@ -108,3 +240,12 @@ return;

};
SftpServerSessionCore.prototype.readHandleInfo = function (request) {
SftpServerSession.prototype.writeItem = function (response, item) {
var attr = new SftpAttributes();
attr.from(item.stats);
var filename = item.filename;
var longname = item.longname || FileUtil.toString(filename, attr);
response.writeString(filename);
response.writeString(longname);
attr.write(response);
};
SftpServerSession.prototype.readHandleInfo = function (request) {
// read a 4-byte handle

@@ -119,5 +260,5 @@ if (request.readInt32() != 4)

};
SftpServerSessionCore.prototype.createHandleInfo = function () {
SftpServerSession.prototype.createHandleInfo = function () {
var h = this.nextHandle;
var max = SftpServerSessionCore.MAX_HANDLE_COUNT;
var max = SftpServerSession.MAX_HANDLE_COUNT;
for (var i = 0; i < max; i++) {

@@ -136,4 +277,7 @@ var next = (h % max) + 1; // 1..MAX_HANDLE_COUNT

};
SftpServerSessionCore.prototype.deleteHandleInfo = function (handleInfo) {
SftpServerSession.prototype.deleteHandleInfo = function (handleInfo) {
var h = handleInfo.h;
if (h < 0)
return;
handleInfo.h = -1;
var handleInfo = this._handles[h];

@@ -144,6 +288,6 @@ if (typeof handleInfo !== 'object')

};
SftpServerSessionCore.prototype.end = function () {
this._host.close();
SftpServerSession.prototype.end = function () {
this._channel.close();
};
SftpServerSessionCore.prototype._end = function () {
SftpServerSession.prototype._end = function () {
var _this = this;

@@ -159,3 +303,3 @@ if (typeof this._fs === 'undefined')

};
SftpServerSessionCore.prototype._process = function (data) {
SftpServerSession.prototype._process = function (data) {
var _this = this;

@@ -200,8 +344,13 @@ var request = new SftpPacketReader(data);

else {
handleInfo.tasks.push(function () { return _this.processRequest(request, response, handleInfo); });
handleInfo.tasks.push(function () {
if (handleInfo.h < 0)
_this.sendStatus(response, 4 /* FAILURE */, "Invalid handle");
else
_this.processRequest(request, response, handleInfo);
});
}
};
SftpServerSessionCore.prototype.processNext = function (handleInfo) {
SftpServerSession.prototype.processNext = function (handleInfo) {
if (handleInfo.tasks.length > 0) {
var task = handleInfo.tasks.pop();
var task = handleInfo.tasks.shift();
task();

@@ -213,3 +362,3 @@ }

};
SftpServerSessionCore.prototype.processRequest = function (request, response, handleInfo) {
SftpServerSession.prototype.processRequest = function (request, response, handleInfo) {
var _this = this;

@@ -231,3 +380,3 @@ var fs = this._fs;

var attrs = new SftpAttributes(request);
var modes = SftpFlags.fromFlags(pflags);
var modes = SftpFlags.fromNumber(pflags);
if (modes.length == 0) {

@@ -281,2 +430,6 @@ this.sendStatus(response, 4 /* FAILURE */, "Unsupported flags");

return;
if (bytesRead == 0) {
_this.sendStatus(response, 1 /* EOF */, "EOF");
return;
}
response.writeInt32(bytesRead);

@@ -348,5 +501,4 @@ response.skip(bytesRead);

while (list.length > 0) {
var it = list.shift();
var item = new SftpItem(it.filename, it.stats);
item.write(response);
var item = list.shift();
_this.writeItem(response, item);
count++;

@@ -411,2 +563,7 @@ if (response.position > 0x7000) {

return;
case SftpExtensions.HARDLINK:
var oldpath = request.readString();
var newpath = request.readString();
fs.link(oldpath, newpath, function (err) { return _this.sendSuccess(response, err); });
return;
default:

@@ -417,19 +574,8 @@ this.sendStatus(response, 8 /* OP_UNSUPPORTED */, "Not supported");

catch (err) {
this.sendError(response, err);
this.sendError(response, err, true);
}
};
SftpServerSessionCore.MAX_HANDLE_COUNT = 512;
return SftpServerSessionCore;
SftpServerSession.MAX_HANDLE_COUNT = 512;
return SftpServerSession;
})();
exports.SftpServerSessionCore = SftpServerSessionCore;
var SftpServerSession = (function (_super) {
__extends(SftpServerSession, _super);
function SftpServerSession(ws, fs, log) {
var channel = new Channel(this, ws);
channel.log = log;
_super.call(this, channel, fs);
channel.start();
}
return SftpServerSession;
})(SftpServerSessionCore);
exports.SftpServerSession = SftpServerSession;

@@ -11,2 +11,3 @@ /// <reference path="../typings/node/node.d.ts" />

var path = require("path");
var events = require("events");
var client = require("./sftp-client");

@@ -16,7 +17,9 @@ var server = require("./sftp-server");

var local = require("./fs-local");
var channel = require("./channel");
var plus = require("./fs-plus");
var channel_ws = require("./channel-ws");
var channel_stream = require("./channel-stream");
var util = require("./util");
var SftpClient = client.SftpClient;
var SafeFilesystem = safe.SafeFilesystem;
var WebSocketServer = WebSocket.Server;
var WebSocketChannel = channel_ws.WebSocketChannel;
var SftpServerSession = server.SftpServerSession;

@@ -27,6 +30,14 @@ var SFTP;

__extends(Client, _super);
function Client(address, options) {
if (typeof options == 'undefined') {
options = {};
}
function Client() {
var localFs = new local.LocalFilesystem();
_super.call(this, localFs);
}
Client.prototype.on = function (event, listener) {
return _super.prototype.on.call(this, event, listener);
};
Client.prototype.once = function (event, listener) {
return _super.prototype.on.call(this, event, listener);
};
Client.prototype.connect = function (address, options, callback) {
options = options || {};
if (typeof options.protocol == 'undefined') {

@@ -36,7 +47,22 @@ options.protocol = 'sftp';

var ws = new WebSocket(address, options);
_super.call(this, ws, options.log);
}
var channel = new WebSocketChannel(ws);
_super.prototype.bind.call(this, channel, callback);
};
return Client;
})(SftpClient);
})(client.SftpClient);
SFTP.Client = Client;
var Local = (function (_super) {
__extends(Local, _super);
function Local() {
var fs = new local.LocalFilesystem();
_super.call(this, fs, null);
}
return Local;
})(plus.FilesystemPlus);
SFTP.Local = Local;
var Channels;
(function (Channels) {
Channels.StreamChannel = channel_stream.StreamChannel;
Channels.WebSocketChannel = channel_ws.WebSocketChannel;
})(Channels = SFTP.Channels || (SFTP.Channels = {}));
var RequestInfo = (function () {

@@ -48,5 +74,7 @@ function RequestInfo() {

SFTP.RequestInfo = RequestInfo;
var Server = (function () {
var Server = (function (_super) {
__extends(Server, _super);
function Server(options) {
var _this = this;
_super.call(this);
var serverOptions = {};

@@ -149,11 +177,12 @@ var noServer = false;

log.info("Connection accepted.");
var options = { binary: true };
var fs = new SafeFilesystem(this._fs, this._virtualRoot, this._readOnly);
var session = new SftpServerSession(ws, fs, log);
var channel = new WebSocketChannel(ws);
var session = new SftpServerSession(channel, fs, this, log);
this.emit("startedSession", this);
ws.session = session;
};
return Server;
})();
})(events.EventEmitter);
SFTP.Server = Server;
})(SFTP || (SFTP = {}));
module.exports = SFTP;

@@ -0,1 +1,10 @@

var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
/// <reference path="../typings/node/node.d.ts" />
var events = require("events");
var EventEmitter = events.EventEmitter;
function toLogWriter(writer) {

@@ -28,1 +37,71 @@ writer = writer || {};

exports.toLogWriter = toLogWriter;
var Task = (function (_super) {
__extends(Task, _super);
function Task() {
_super.call(this);
}
Task.prototype.on = function (event, listener) {
return _super.prototype.on.call(this, event, listener);
};
return Task;
})(EventEmitter);
exports.Task = Task;
function wrapCallback(owner, task, callback) {
return finish;
function finish(err) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
var error = arguments[0];
try {
if (typeof callback === 'function') {
callback.apply(owner, arguments);
error = null;
}
else if (task) {
if (!error) {
switch (arguments.length) {
case 0:
case 1:
task.emit("success");
task.emit("finish", error);
break;
case 2:
task.emit("success", arguments[1]);
task.emit("finish", error, arguments[1]);
break;
case 3:
task.emit("success", arguments[1], arguments[2]);
task.emit("finish", error, arguments[1], arguments[2]);
break;
default:
arguments[0] = "success";
task.emit.apply(task, arguments);
if (EventEmitter.listenerCount(task, "finish") > 0) {
arguments[0] = "finish";
Array.prototype.splice.call(arguments, 1, 0, error);
task.emit.apply(task, arguments);
}
break;
}
}
else {
if (EventEmitter.listenerCount(task, "error")) {
task.emit("error", error);
error = null;
}
task.emit("finish", error);
}
}
}
catch (err) {
if (error)
owner.emit("error", error);
error = err;
}
if (error)
owner.emit("error", error);
}
}
exports.wrapCallback = wrapCallback;
{
"name": "sftp-ws",
"version": "0.2.0",
"version": "0.3.0",
"description": "SFTP over WebSockets - client and server library",

@@ -22,6 +22,3 @@ "main": "./lib/sftp.js",

"keywords": ["sftp", "server", "client", "ws"],
"licenses": [{
"type": "MIT",
"url": "https://github.com/lukaaash/sftp-ws/blob/master/LICENSE"
}],
"license": "MIT",
"repository": {

@@ -28,0 +25,0 @@ "type": "git",

sftp-ws
=======
v0.2.0
v0.3.0
------

@@ -12,2 +12,3 @@

SFTP is a simple remote filesystem protocol misnamed as *SSH File Transfer Protocol*. This package provides SFTP v3, but layers it on top of WebSockets instead of SSH.
This makes it possible to run an SFTP client in any modern web browser.
Check out my [blogpost](http://lukas.pokorny.eu/sftp-over-websockets/) for more information.

@@ -25,3 +26,4 @@

The client API aims to be compatible with SFTP client in [ssh2 module](https://github.com/mscdex/ssh2) by Brian White.
The SFTP client provides a high-level API for multi-file operations, but it also aims to be compatible with SFTP client in [ssh2 module](https://github.com/mscdex/ssh2) by Brian White.
Einaros [ws module](https://github.com/einaros/ws) is used to handle WebSockets and this is reflected in parts of the client and server API as well.

@@ -34,8 +36,11 @@

// initialize SFTP over WebSocket connection
var client = new SftpClient('ws://localhost/path');
// create an SFTP over WebSockets object
var client = new SFTP.Client();
// connect to a server
client.connect('ws://localhost/path');
// handle errors
client.on('error', function (err) {
console.log('Error : %s', err.message);
console.log('Error: %s', err.message);
});

@@ -47,8 +52,11 @@

// retrieve directory listing
client.readdir('.', function (err, listing) {
console.log(listing);
client.list('.').on('success', function (list) {
// display the listing
list.forEach(function (item) {
return console.log(item.longname);
});
// close the connection
client.end();
client.end();
});

@@ -58,2 +66,13 @@ });

### SFTP client - downloading files
```javascript
// initialize an SFTP client object here
// download all files matching the pattern
// (into the current local directory)
client.download('sftp-ws-'.tgz", '.');
```
### SFTP server - listening for connections:

@@ -76,3 +95,3 @@

This includes a proof-of-concept version of a [browser-based SFTP/WS client](https://github.com/lukaaash/sftp-ws/tree/v0.1.0/examples/web-client).
This includes a proof-of-concept version of a [browser-based SFTP/WS client](https://github.com/lukaaash/sftp-ws/tree/v0.3.0/examples/web-client).

@@ -84,3 +103,3 @@ ## Virtual filesystems

```typescript
export interface IFilesystem {
interface IFilesystem {
open(path: string, flags: string, attrs?: IStats, callback?: (err: Error, handle: any) => any): void;

@@ -95,3 +114,3 @@ close(handle: any, callback?: (err: Error) => any): void;

opendir(path: string, callback?: (err: Error, handle: any) => any): void;
readdir(handle: any, callback?: (err: Error, items: IItem[]|boolean) => any): void;
readdir(handle: any, callback?: (err: Error, items: IItem[]|boolean) => any): void;
unlink(path: string, callback?: (err: Error) => any): void;

@@ -105,9 +124,5 @@ mkdir(path: string, attrs?: IStats, callback?: (err: Error) => any): void;

symlink(targetpath: string, linkpath: string, callback?: (err: Error) => any): void;
link(oldPath: string, newPath: string, callback?: (err: Error) => any): void;
}
export interface IItem {
filename: string;
stats?: IStats;
}
export interface IStats {

@@ -120,3 +135,15 @@ mode?: number;

mtime?: Date;
isFile? (): boolean;
isDirectory? (): boolean;
isSymbolicLink? (): boolean;
}
export interface IItem {
filename: string;
stats: IStats;
longname?: string;
path?: string;
}
```

@@ -136,3 +163,3 @@

- More unit tests
- Documentation
- Better documentation
- Proper browser-based client

@@ -139,0 +166,0 @@ - Client-side wrapper around `IFilesystem` to simplify common tasks

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