Giter VIP home page Giter VIP logo

simple-ftpd's Introduction

simple-ftpd

simple-ftpd is a event based ftp-server for node.js.

Features

  • Supports multiple modern ftp clients such as FileZilla, WinSCP, Transmission.
  • A real File System is not required.
  • For now it only supports basic authentication.
  • It supports passive mode only.
  • It only supports streams for writing and reading files.
  • It currently only supports a subset of FTP commands, but it should be enough for any modern FTP client.
  • It is intended to be used mainly to create local network ftp servers.

Used pyftpdlib extensively as a reference for the FTP protocol specification, as reading RFC documents is super boring :=)

Install

yarn add simple-ftpd
# or
npm install simple-ftpd --save
const ftpd = require('simple-ftpd')

API

Syntax: ftpd(opts, sessionCallback) or ftpd(host:port, sessionCallback)

Should you need more control, the ftpd function will return a net.Server instance.

Example

Simple, fs-based ftp server implementation example:

'use strict'

const ftpd = require('simple-ftpd')

ftpd({ host: '127.0.0.1', port: 1337, root: '/public/files' }, (session) => {

  session.on('pass', (username, password, cb) => {
    if (username === 'superadmin' && password === '53cr3t') {
      session.readOnly = false
      session.root = '/private/secret/files'
      cb(null, 'Welcome admin')
    } else {
      cb(null, 'Welcome guest')
    }
  })

  session.on('stat', fs.stat)
  // AKA
  // session.on('stat', (pathName, cb) => {
  //  fs.stat(pathName, cb)
  // })

  session.on('readdir', fs.readdir)
  // AKA
  // session.on('readdir', (pathName, cb) => {
  //   fs.readdir(pathName, cb)
  // })

  session.on('read', (pathName, offset, cb) => {
    cb(null, fs.createReadStream(pathName, { start: offset }))
  })

  session.on('write', (pathName, offset, cb) => {
    cb(null, fs.createWriteStream(pathName, { start: offset }))
  })

  // I'd do some checking if I were you, but hey.

  session.on('mkdir', fs.mkdir)
  session.on('unlink', fs.unlink)
  session.on('rename', fs.rename)
  session.on('remove', require('rimraf'))
})

Options

option description
host required Must be a valid ipv4 address (for now). Defaults to 127.0.0.1
port required Server port. Defaults to 1337.
readOnly optional Disables client write requests. Defaults to true. Can be overridden on a connection-basis by setting the readOnly property on the session object before logging in.
root optional The path passed to events will always be joined to root. Can be overridden on a connection-basis by setting the root property on the session object before logging in. The ftp client will not see root, and will think he's at /. This is simply a convenience to avoid manually joining the path you get in every event.
maxConnections optional Maximum number of server connections. Defaults to 10.

Passive connections will be initialized on an unused port assigned by the os.

Instead of options, you can pass ${host}:${port} ("192.168.1.10:1337").

Events

Every event gets some arguments and a node-style callback you must call with an Error object (if any) and results.

If you do not listen to a specific event, then that feature will become unavailable to the client. For example, if you do not listen to write events, the client will get a 502 error when trying to write files.

pass [username, password, cb]

The client wants to login with username and password. Will consider the user logged in if no error is passed to cb()

User names are always accepted, because (from pyftpdlib):

In order to prevent a malicious client from determining valid usernames on a server, it is suggested by RFC-2577 that a server always return 331 to the USER command and then reject the combination of username and password for an invalid username when PASS is provided later.

read [pathName, offset, cb]:

The client wants to read the file at pathName, starting at offset. Requires a readable stream to be passed as cb(null, readStream).

write [pathName, offset, cb]:

The client wants to write a file at pathName, starting at offset. Requires a writable stream to be passed as cb(null, writeStream).

stat [pathName, cb]:

the client wants the stats to a file or directory at pathName. Requires a fs.stat-like object to be passed as cb(null, stat).

Properties are:

{
  // fs.stat mode
  mode: 16822,
  //  size in bytes
  size: 12345,
  // lastModifiedTime as Date or number (or whatever gets parsed by moment)
  mtime: Date.now(),
  // optional, will use it for display if available, otherwise "owner"
  uname: 'kamicane',
  // optional, will use it for display if available, otherwise "group"
  gname: 'admins',
}

readdir [pathName, cb]:

The client wants a list of files in the directory pathName. requires an array of file names, relative to pathName, to be passed as cb(null, list).

mkdir [pathName, cb]:

The client wants to create a directory at pathName. Will consider the directory written if no error is passed to cb()

unlink [pathName, cb]:

The client wants to delete the file at pathName. Will consider the file deleted if no error is passed to cb()

remove [pathName, cb]:

The client wants to remove a directory, and all of its contents, at pathName. Will consider the directory and its contents removed if no error is passed to cb()

rename [fromName, toName, cb]:

The client wants to rename a file or directory, from fromName to toName. Will consider the file renamed if no error is passed to cb()

CLI

When installed globally, ftpd will provide a small cli, which will quickly create a fs-based ftp server.

You can use it like this:

ftp-server /public/files --host 192.168.0.1 --port 1234 --max-connections 10
  • --host will default to 127.0.0.1
  • --port will default to 1337
  • --max-connections will default to 10
  • --read-only will default to true
  • Unless specified, the ftp root will default to process.cwd()

The cli will accept any login, so be careful when setting --read-only to false.

License

MIT

simple-ftpd's People

Contributors

kamicane avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

simple-ftpd's Issues

Unhandled exception on write

On write I check if uploaded file is csv and when it is not I return error. After returning the error I got another error and then my client crashes.

strep to reproduce:
Put this part of code to your code and try upload file without csv extension.

session.on("write", (pathName, offset, cb) => {
      if (!pathName.endsWith(".csv")) {
        return cb(new Error("You must upload csv."));
      }
      console.log(pathName)
}

We moved try on https://github.com/kamicane/simple-ftpd/blob/master/lib/requests/stor.js#L39
to line 35 and looks like it works

Event writeCompleted

I need to process uploaded files, so a writeCompleted event or the possibility to put a custom callback into the callback of the write event would be pretty dope :)

Error running the README example

My Machine

  • OS Version: Manjaro Linux 17.1.4
  • Node: v9.0.0

Steps to Reproduce:

Run the example on the README directly with the node command on the command line (eg. node ftp.js )

I think that is something related with my Node.js version.

Error

util.js:976
    throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'superCtor', 'function');
    ^

TypeError [ERR_INVALID_ARG_TYPE]: The "superCtor" argument must be of type function
    at Object.inherits (util.js:976:11)
    at Object.<anonymous> (/home/coderade/repo/tests/ftp-server-example/node_modules/ftpd/lib/ftpd.js:67:6)
    at Module._compile (module.js:641:30)
    at Object.Module._extensions..js (module.js:652:10)
    at Module.load (module.js:560:32)
    at tryModuleLoad (module.js:503:12)
    at Function.Module._load (module.js:495:3)
    at Module.require (module.js:585:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/home/coderade/repo/tests/ftp-server-example/ftp.js:3:14)

Do you know why this can be happening? Need help to solve this issue?

How to close the connection

Looking for something like:

session.on('pass', (username, password, cb) => {
    if (username === 'admin' && password === 'adminpw') {
      session.readOnly = false;
      cb(null, 'Welcome admin')
    } else {
  session.close(); session.end(); // these don't seem to do too much
}

CLI in latest release has unspecified dependency on module 'chalk'

OS: Ubuntu 18.04
Node: v8.9.1
NPM: 5.8.0

Steps to reproduce:

npm install -g simple-ftpd
ftp-server . 

Error (user path redacted):

module.js:538
    throw err;
    ^

Error: Cannot find module 'chalk'
    at Function.Module._resolveFilename (module.js:536:15)
    at Function.Module._load (module.js:466:25)
    at Module.require (module.js:579:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/home/xxx/.nvm/versions/node/v8.9.1/lib/node_modules/simple-ftpd/lib/session.js:8:15)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)

Running npm install -g chalk fixes the issue.

Looks like the package just needs to be tagged/released, as latest package.json contains dependency.

Firefox causes an error "data encoding must be set to utf8 for listing"

When using Firefox to access ftp://localhost:1337/, the library throws the above error. The actual value of dataEncoding is binary. When I comment the check out, LIST works okay anyway.

It's Firefox setting this:

> TYPE I
OK: 200 Transfer type set to binary

Any way to address this?

Additional maintainers?

Since this project doesn't seem to be very active anymore, maybe it makes sense to look for additional maintainers in the community?

process.EventEmitter is deprecated

When using this on a recent release of node you get the following notice:
DeprecationWarning: process.EventEmitter is deprecated. Use require('events') instead.

Cannot find module 'ftpd'

I've installed simple-ftpd but I got the following error.

const ftpd = require('ftpd');

This code gives me error like below.

Error: Cannot find module 'ftpd'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Volumes/Work/Work/WEB/nodejs/simple-ftpd-test/server.js:2:14)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)

I tried to this code.

const ftpd = require('simple-ftpd');

then I'm getting error like this.

Error: Cannot find module 'chalk'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Volumes/Work/Work/WEB/nodejs/simple-ftpd-test/node_modules/simple-ftpd/lib/session.js:8:15)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.