Compare commits

..

5 Commits

Author SHA1 Message Date
Tyler Stewart
5508c2346c fix: disallow PORT connections to alternate hosts
Ensure the data socket that the server connects to from the PORT command is the same IP as the current command socket.

* fix: add error handling to additional connection commands
2020-08-17 14:01:12 -06:00
Devonte
03ff982959 fix: correct writable checks (#147)
fix: correct writable checks
2019-02-21 18:30:58 +00:00
Sergey Kuvakin
8c8f3922a3 feat: expose a RNTO event (#151)
* feat(commands): expose a RNTO event, updated a readme file

* feat(commands): fixed test for the RNTO

* chore: fixed prepush errors

* fix: turnback spaces into a README.md
2019-02-21 18:04:01 +00:00
zGwit
eca26ee86a fix: close connection on timeout (#145)
* Close connection when timeout

* Add promise processing
2019-01-17 02:44:48 +00:00
David Van Gompel
811db7b1a7 fix: add correct typing for tls option (#141) 2019-01-16 23:55:20 +00:00
57 changed files with 663 additions and 643 deletions

View File

@@ -23,7 +23,7 @@ base-build: &base-build
- node_modules
- run:
name: Lint
command: npm run verify -- --silent
command: npm run verify:js
- run:
name: Test
command: npm run test:once

View File

@@ -36,8 +36,6 @@
## Overview
`ftp-srv` is a modern and extensible FTP server designed to be simple yet configurable.
You can use `ftp-srv` to traverse the file system on the server, but it's biggest strength comes from it's customizable file system. This allows you to serve a custom, dynamic, or unique file system to users. You can even server a different system depending on the user connecting.
## Features
- Extensible [file systems](#file-system) per connection
- Passive and active transfers
@@ -126,11 +124,6 @@ __Allowable values:__
#### `log`
A [bunyan logger](https://github.com/trentm/node-bunyan) instance. Created by default.
Piping the output into bunyan will format logs nicely, eg:
```
$ node ./test/start.js | npx bunyan
```
## CLI
`ftp-srv` also comes with a builtin CLI.
@@ -242,6 +235,16 @@ Occurs when a file is uploaded.
`error` if successful, will be `null`
`fileName` name of the file that was uploaded
### `RNTO`
```js
connection.on('RNTO', (error, fileName) => { ... });
```
Occurs when a file is renamed.
`error` if successful, will be `null`
`fileName` name of the file that was renamed
## Supported Commands
See the [command registry](src/commands/registration) for a list of all implemented FTP commands.

2
ftp-srv.d.ts vendored
View File

@@ -64,7 +64,7 @@ export interface FtpServerOptions {
pasv_max?: number,
pasv_url?: string,
greeting?: string | string[],
tls?: tls.SecureContext | false,
tls?: tls.SecureContextOptions | false,
anonymous?: boolean,
blacklist?: Array<string>,
whitelist?: Array<string>,

1064
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,9 @@
"start": "npm run dev",
"test": "cross-env NODE_ENV=test mocha --opts config/testUnit/mocha.opts -w",
"test:once": "cross-env NODE_ENV=test mocha --opts config/testUnit/mocha.opts",
"verify": "eslint -c config/verify/.eslintrc \"src/**/*.js\" \"test/**/*.js\""
"verify": "npm run verify:js --silent",
"verify:js": "eslint -c config/verify/.eslintrc \"src/**/*.js\" \"test/**/*.js\" \"config/**/*.js\" && echo ✅ verify:js success",
"verify:js:fix": "eslint --fix -c config/verify/.eslintrc \"src/**/*.js\" \"test/**/*.js\" \"config/**/*.js\" && echo ✅ verify:js:fix success"
},
"release": {
"verifyConditions": "condition-circle"
@@ -51,30 +53,31 @@
"bunyan": "^1.8.12",
"ip": "^1.1.5",
"lodash": "^4.17.10",
"moment": "^2.22.2",
"uuid": "^3.3.2",
"yargs": "^12.0.1"
"moment": "^2.22.1",
"uuid": "^3.2.1",
"yargs": "^11.0.0"
},
"devDependencies": {
"@icetee/ftp": "^1.0.3",
"chai": "^4.1.2",
"condition-circle": "^2.0.1",
"cross-env": "5.2.0",
"@icetee/ftp": "^1.0.2",
"chai": "^4.0.2",
"condition-circle": "^1.6.0",
"cross-env": "3.1.4",
"cz-customizable": "5.2.0",
"cz-customizable-ghooks": "1.5.0",
"eslint": "5.3.0",
"eslint-config-google": "0.9.1",
"eslint-friendly-formatter": "4.0.1",
"eslint-plugin-mocha": "^5.1.0",
"eslint-plugin-node": "7.0.1",
"husky": "0.14.3",
"dotenv": "^4.0.0",
"eslint": "4.5.0",
"eslint-config-google": "0.8.0",
"eslint-friendly-formatter": "3.0.0",
"eslint-plugin-mocha": "^4.11.0",
"eslint-plugin-node": "5.1.1",
"husky": "0.13.3",
"istanbul": "0.4.5",
"mocha": "^5.2.0",
"mocha-junit-reporter": "1.18.0",
"mocha-multi-reporters": "1.1.7",
"rimraf": "2.6.2",
"semantic-release": "^15.9.8",
"sinon": "^6.1.5"
"mocha-junit-reporter": "1.13.0",
"mocha-multi-reporters": "1.1.5",
"rimraf": "2.6.1",
"semantic-release": "^15.10.6",
"sinon": "^2.3.5"
},
"engines": {
"node": ">=6.x",

View File

@@ -8,14 +8,18 @@ const FAMILY = {
module.exports = {
directive: 'EPRT',
handler: function ({command} = {}) {
handler: function ({log, command} = {}) {
const [, protocol, ip, port] = _.chain(command).get('arg', '').split('|').value();
const family = FAMILY[protocol];
if (!family) return this.reply(504, 'Unknown network protocol');
this.connector = new ActiveConnector(this);
return this.connector.setupConnection(ip, port, family)
.then(() => this.reply(200));
.then(() => this.reply(200))
.catch((err) => {
log.error(err);
return this.reply(err.code || 425, err.message);
});
},
syntax: '{{cmd}} |<protocol>|<address>|<port>|',
description: 'Specifies an address and port to which the server should connect'

View File

@@ -2,13 +2,17 @@ const PassiveConnector = require('../../connector/passive');
module.exports = {
directive: 'EPSV',
handler: function () {
handler: function ({log}) {
this.connector = new PassiveConnector(this);
return this.connector.setupServer()
.then((server) => {
const {port} = server.address();
return this.reply(229, `EPSV OK (|||${port}|)`);
})
.catch((err) => {
log.error(err);
return this.reply(err.code || 425, err.message);
});
},
syntax: '{{cmd}} [<protocol>]',

View File

@@ -13,6 +13,10 @@ module.exports = {
const portByte2 = port % 256;
return this.reply(227, `PASV OK (${host},${portByte1},${portByte2})`);
})
.catch((err) => {
log.error(err);
return this.reply(err.code || 425, err.message);
});
},
syntax: '{{cmd}}',

View File

@@ -14,7 +14,11 @@ module.exports = {
const port = portBytes[0] * 256 + portBytes[1];
return this.connector.setupConnection(ip, port)
.then(() => this.reply(200));
.then(() => this.reply(200))
.catch((err) => {
log.error(err);
return this.reply(err.code || 425, err.message);
});
},
syntax: '{{cmd}} <x>,<x>,<x>,<x>,<y>,<y>',
description: 'Specifies an address and port to which the server should connect'

View File

@@ -15,8 +15,10 @@ module.exports = {
.then(() => {
return this.reply(250);
})
.tap(() => this.emit('RNTO', null, to))
.catch((err) => {
log.error(err);
this.emit('RNTO', err);
return this.reply(550, err.message);
})
.finally(() => {

View File

@@ -22,7 +22,7 @@ module.exports = {
const destroyConnection = (connection, reject) => (err) => {
if (connection) {
if (connection.writeable) connection.end();
if (connection.writable) connection.end();
connection.destroy(err);
}
reject(err);
@@ -36,7 +36,7 @@ module.exports = {
const socketPromise = new Promise((resolve, reject) => {
this.connector.socket.on('data', (data) => {
if (this.connector.socket) this.connector.socket.pause();
if (stream) {
if (stream && stream.writable) {
stream.write(data, this.transferType, () => this.connector.socket && this.connector.socket.resume());
}
});

View File

@@ -30,7 +30,10 @@ class FtpConnection extends EventEmitter {
this.server.emit('client-error', {connection: this, context: 'commandSocket', error: err});
});
this.commandSocket.on('data', this._handleData.bind(this));
this.commandSocket.on('timeout', () => {});
this.commandSocket.on('timeout', (err) => {
this.log.trace(err, 'Client timeout');
this.close().catch((e) => this.log.trace(e, 'Client close error'));
});
this.commandSocket.on('close', () => {
if (this.connector) this.connector.end();
if (this.commandSocket && !this.commandSocket.destroyed) this.commandSocket.destroy();

View File

@@ -1,7 +1,9 @@
const {Socket} = require('net');
const tls = require('tls');
const ip = require('ip');
const Promise = require('bluebird');
const Connector = require('./base');
const {SocketError} = require('../errors');
class Active extends Connector {
constructor(connection) {
@@ -27,6 +29,10 @@ class Active extends Connector {
return closeExistingServer()
.then(() => {
if (!ip.isEqual(this.connection.commandSocket.remoteAddress, host)) {
throw new SocketError('The given address is not yours', 500);
}
this.dataSocket = new Socket();
this.dataSocket.setEncoding(this.connection.transferType);
this.dataSocket.on('error', (err) => this.server && this.server.emit('client-error', {connection: this.connection, context: 'dataSocket', error: err}));

View File

@@ -29,7 +29,7 @@ class Connector {
closeSocket() {
if (this.dataSocket) {
const socket = this.dataSocket;
this.dataSocket.end(() => socket.destroy());
this.dataSocket.end(() => socket && socket.destroy());
this.dataSocket = null;
}
}

View File

@@ -20,7 +20,7 @@ describe('FtpCommands', function () {
};
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
commands = new FtpCommands(mockConnection);

View File

@@ -15,7 +15,7 @@ describe.skip(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
sandbox.spy(mockClient.connector, 'waitForConnection');

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -16,7 +16,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -16,7 +16,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
sandbox.spy(mockClient.fs, 'chdir');

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'chdir').resolves();

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'delete').resolves();

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
sandbox.stub(ActiveConnector.prototype, 'setupConnection').resolves();
@@ -23,7 +23,7 @@ describe(CMD, function () {
});
it('// unsuccessful | no argument', () => {
return cmdFn()
return cmdFn({})
.then(() => {
expect(mockClient.reply.args[0][0]).to.equal(504);
});

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(PassiveConnector.prototype, 'setupServer').resolves({
@@ -25,7 +25,7 @@ describe(CMD, function () {
});
it('// successful IPv4', () => {
return cmdFn()
return cmdFn({})
.then(() => {
const [code, message] = mockClient.reply.args[0];
expect(code).to.equal(229);

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -25,7 +25,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'get').resolves({

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'get').resolves({mtime: 'Mon, 10 Oct 2011 23:24:11 GMT'});

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'mkdir').resolves();

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -25,7 +25,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'get').resolves({

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});
@@ -29,7 +29,7 @@ describe(CMD, function () {
it('BAD // unsuccessful', () => {
return cmdFn({command: {arg: 'BAD', directive: CMD}})
.then(() => {
expect(mockClient.reply.args[0][0]).to.equal(500);
expect(mockClient.reply.args[0][0]).to.equal(501);
});
});

View File

@@ -15,7 +15,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient, 'login').resolves();

View File

@@ -12,7 +12,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
sandbox.stub(ActiveConnector.prototype, 'setupConnection').resolves();

View File

@@ -12,7 +12,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
sandbox.stub(mockClient.fs, 'currentDirectory').resolves();

View File

@@ -10,7 +10,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'close').resolves();
});

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -25,7 +25,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.fs = {
read: () => {}

View File

@@ -10,7 +10,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.renameFrom = 'test';
mockClient.fs = {

View File

@@ -1,16 +1,18 @@
const Promise = require('bluebird');
const {expect} = require('chai');
const sinon = require('sinon');
const EventEmitter = require('events');
const CMD = 'RNTO';
describe(CMD, function () {
let sandbox;
const mockLog = {error: () => {}};
let emitter;
const mockClient = {reply: () => Promise.resolve()};
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.renameFrom = 'test';
mockClient.fs = {
@@ -18,6 +20,9 @@ describe(CMD, function () {
rename: () => Promise.resolve()
};
emitter = new EventEmitter();
mockClient.emit = emitter.emit.bind(emitter);
sandbox.spy(mockClient, 'reply');
sandbox.spy(mockClient.fs, 'rename');
});

View File

@@ -10,7 +10,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../../src/commands/registration/site/${CMD.toLowerCase()}`).bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.fs = {
chmod: () => Promise.resolve()

View File

@@ -17,7 +17,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.stub(mockClient, 'reply').resolves();
});

View File

@@ -10,7 +10,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.fs = {
get: () => Promise.resolve({size: 1})

View File

@@ -10,7 +10,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.fs = {
get: () => Promise.resolve({}),

View File

@@ -25,7 +25,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.fs = {
write: () => {}

View File

@@ -13,7 +13,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.fs = {
get: () => Promise.resolve(),

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
sandbox.spy(mockClient, 'reply');
});

View File

@@ -11,7 +11,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
mockClient.transferType = null;
sandbox.spy(mockClient, 'reply');

View File

@@ -16,7 +16,7 @@ describe(CMD, function () {
const cmdFn = require(`../../../src/commands/registration/${CMD.toLowerCase()}`).handler.bind(mockClient);
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
delete mockClient.username;
mockClient.server.options = {};

View File

@@ -12,15 +12,17 @@ describe('Connector - Active //', function () {
let getNextPort = getNextPortFactory(1024);
let PORT;
let active;
let mockConnection = {};
let mockConnection = {
commandSocket: {
remoteAddress: '::ffff:127.0.0.1'
}
};
let sandbox;
let server;
before(() => {
active = new ActiveConnector(mockConnection);
});
beforeEach((done) => {
sandbox = sinon.createSandbox().usingPromise(Promise);
active = new ActiveConnector(mockConnection);
sandbox = sinon.sandbox.create().usingPromise(Promise);
getNextPort()
.then((port) => {
@@ -30,9 +32,12 @@ describe('Connector - Active //', function () {
.listen(PORT, () => done());
});
});
afterEach((done) => {
afterEach(() => {
sandbox.restore();
server.close(done);
server.close();
active.end();
});
it('sets up a connection', function () {
@@ -42,13 +47,27 @@ describe('Connector - Active //', function () {
});
});
it('destroys existing connection, then sets up a connection', function () {
const destroyFnSpy = sandbox.spy(active.dataSocket, 'destroy');
it('rejects alternative host', function () {
return active.setupConnection('123.45.67.89', PORT)
.catch((err) => {
expect(err.code).to.equal(500);
expect(err.message).to.equal('The given address is not yours');
})
.finally(() => {
expect(active.dataSocket).not.to.exist;
});
});
return active.setupConnection('127.0.0.1', PORT)
it('destroys existing connection, then sets up a connection', function () {
return active.setupConnection(host, PORT)
.then(() => {
expect(destroyFnSpy.callCount).to.equal(1);
expect(active.dataSocket).to.exist;
const destroyFnSpy = sandbox.spy(active.dataSocket, 'destroy');
return active.setupConnection(host, PORT)
.then(() => {
expect(destroyFnSpy.callCount).to.equal(1);
expect(active.dataSocket).to.exist;
});
});
});

View File

@@ -9,7 +9,7 @@ describe('helpers // file-stat', function () {
let sandbox;
before(function () {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
});
afterEach(function () {
sandbox.restore();

View File

@@ -10,7 +10,7 @@ describe('helpers // find-port', function () {
let getNextPort;
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
getNextPort = getNextPortFactory(1, 2);
});

View File

@@ -7,7 +7,7 @@ describe('helpers //resolve-host', function () {
let sandbox;
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
});
afterEach(() => sandbox.restore());

View File

@@ -25,7 +25,7 @@ describe('Integration', function () {
return startServer({url: 'ftp://127.0.0.1:8880'});
});
beforeEach(() => {
sandbox = sinon.createSandbox().usingPromise(Promise);
sandbox = sinon.sandbox.create().usingPromise(Promise);
});
afterEach(() => sandbox.restore());
after(() => server.close());

View File

@@ -1,3 +1,4 @@
require('dotenv').load();
const bunyan = require('bunyan');
const fs = require('fs');
const FtpServer = require('../src');