Skip to content

๐Ÿ“ฎ Modern, extensible FTP server (daemon) for Node.js with ESM support. Based on ftp-srv.

License

Notifications You must be signed in to change notification settings

timint/ftp-srv-esm

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

ftp-srv-esm

Modern, extensible FTP Server. Based on ftp-srv 4.6.3. How is it different from v4? Code has been rewritten for ECMAScript Modules (ESM). Deprecated, outdated and vulnerable npm dependencies has been removed, replaced and updated.

Features

  • Extensible file systems per connection
  • Passive and active transfers
  • Automatic WAN IP detection
  • Explicit & Implicit TLS connections
  • Promise based API

Install

npm install ftp-srv-esm

Usage

// Quick start, create an active ftp server.
import FtpSrv from 'ftp-srv-esm';

const ftpServer = new FtpSrv({
  url: "ftp://0.0.0.0:21,
  anonymous: false
});

ftpServer.on('login', ({ connection, username, password }, resolve, reject) => {
  if(username === 'john' && password === 'doe'){
    return resolve({ root: '/' });
  }
  return reject(new errors.GeneralError('Invalid username or password', 401));
});

ftpServer.listen().then(() => {
  console.log('FTP server is starting...')
});

API

new FtpSrv({options})

url

URL string indicating the protocol, hostname, and port to listen on for connections. Supported protocols:

  • ftp Plain FTP
  • ftps Implicit FTP over TLS

Note: The hostname must be the external IP address to accept external connections. 0.0.0.0 will listen on any available hosts for server and passive connections. Default: "ftp://127.0.0.1:21"

pasv_hostname

ftp-srv-esm provides an IP address to the client when a PASV command is received in the handshake for a passive connection. Reference PASV verb. This can be one of two options:

  • A function which takes one parameter containing the remote IP address of the FTP client. This can be useful when the user wants to return a different IP address depending if the user is connecting from Internet or from an LAN address. Example:
import os from 'os';
import { Netmask } from 'netmask';
import FtpSrv from 'ftp-srv-esm';

const nets = os.networkInterfaces();
function getNetworks() {
 let networks = {};
 for (const name of Object.keys(nets)) {
   for (const net of nets[name]) {
     if (net.family === 'IPv4' && !net.internal) {
       networks[net.address + "/24"] = net.address;
     }
   }
 }
 return networks;
}

const resolverFunction = (address) => {
 // const networks = {
 //     '$GATEWAY_IP/32': `${public_ip}`,
 //     '10.0.0.0/8'    : `${lan_ip}`
 // }
 const networks = getNetworks();
 for (const network in networks) {
   if (new Netmask(network).contains(address)) {
     return networks[network];
   }
 }
 return '127.0.0.1';
};

new FtpSrv({pasv_hostname: resolverFunction});
  • A static IP address (ie. an external WAN IP address that the FTP server is bound to). In this case, only connections from localhost are handled differently returning 127.0.0.1 to the client.

If not provided, the server will attempt to fetch and use the WAN IP for passive mode transfers.

wan_ip_check_url

The URL to use for automatic WAN IP detection when pasv_hostname is not provided. This is useful when deploying the server in different environments that may need alternative IP detection services. Default: "https://checkip.amazonaws.com"

pasv_min

The starting port to accept passive connections. Default: 1024

pasv_max

The ending port to accept passive connections. The range is then queried for an available port to use when required. Default: 65535

greeting

A human readable array of lines or string to send when a client connects. Default: null

tls

Node TLS secure context object used for implicit (ftps protocol) or explicit (AUTH TLS) connections. Example: { key: readFileSync('server.key'), cert: readFileSync('server.crt'), ca: readFileSync('server.csr') } Default: false

anonymous

If true, will allow clients to authenticate using the username anonymous, not requiring a password from the user. Can also set as a string which allows users to authenticate using the username provided. The login event is then sent with the provided username and @anonymous as the password. Default: false

blacklist

Array of commands that are not allowed. Response code 502 is sent to clients sending one of these commands. Example: ['RMD', 'RNFR', 'RNTO'] will not allow users to delete directories or rename any files. Default: []

whitelist

Array of commands that are only allowed. Response code 502 is sent to clients sending any other command. Default: []

list_format

Sets the format to use for file stat queries such as LIST. Default: "ls" Allowable values:

log

A winston logger instance. Created by default.

timeout

Sets the timeout (in ms) after that an idle connection is closed by the server Default: 0

endOnProcessSignal

Whether to close ftp server and exit process on SIGTERM/SIGINT/SIGQUIT signals or not Default: true

CLI

ftp-srv-esm also comes with a builtin CLI.

$ ftp-srv [url] [options]
$ ftp-srv-esm ftp://0.0.0.0:9876 --root ~/Documents

url

Set the listening URL.

Defaults to ftp://127.0.0.1:21

--pasv_hostname

The hostname to provide a client when attempting a passive connection (PASV). If not provided, clients can only connect using an Active connection.

--pasv_min

The starting port to accept passive connections. Default: 1024

--pasv_max

The ending port to accept passive connections. The range is then queried for an available port to use when required. Default: 65535

--root / -r

Set the default root directory for users.

Defaults to the current directory.

--credentials / -c

Set the path to a json credentials file.

Format:

[
  {
    "username": "...",
    "password": "...",
    "root": "..." // Root directory
  },
  ...
]

--username

Set the username for the only user. Do not provide an argument to allow anonymous login.

--password

Set the password for the given username.

--read-only

Disable write actions such as upload, delete, etc.

Events

The FtpSrv class extends the node net.Server. Some custom events can be resolved or rejected, such as login.

client-error

import FtpSrv from 'ftp-srv-esm';.on('client-error', ({connection, context, error}) => { ... });

Occurs when an error arises in the client connection.

connection client class object context string of where the error occurred error error object

disconnect

ftpServer.on('disconnect', ({connection, id, newConnectionCount}) => { ... });

Occurs when a client has disconnected.

connection client class object id string of the disconnected connection id id number of the new connection count (exclusive the disconnected client connection)

closed

ftpServer.on('closed', ({}) => { ... });

Occurs when the FTP server has been closed.

closing

ftpServer.on('closing', ({}) => { ... });

Occurs when the FTP server has started closing.

login

ftpServer.on('login', ({ connection, username, password }, resolve, reject) => { ... });

Occurs when a client is attempting to login. Here you can resolve the login request by username and password.

connection client class object username string of username from USER command password string of password from PASS command resolve takes an object of arguments:

  • fs
    • Set a custom file system class for this connection to use.
    • See File System for implementation details.
  • root
    • If fs is not provided, this will set the root directory for the connection.
    • The user cannot traverse lower than this directory.
  • cwd
    • If fs is not provided, will set the starting directory for the connection
    • This is relative to the root directory.
  • blacklist
    • Commands that are forbidden for only this connection
  • whitelist
    • If set, this connection will only be able to use the provided commands

reject takes an error object

server-error

ftpServer.on('server-error', ({error}) => { ... });

Occurs when an error arises in the FTP server.

error error object

RETR

connection.on('RETR', (error, filePath) => { ... });

Occurs when a file is downloaded.

error if successful, will be null filePath location to which file was downloaded

STOR

connection.on('STOR', (error, fileName) => { ... });

Occurs when a file is uploaded.

error if successful, will be null fileName name of the file that was uploaded

RNTO

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 for a list of all implemented FTP commands.

File System

The default file system can be overwritten to use your own implementation. This can allow for virtual file systems, and more. Each connection can set it's own file system based on the user.

The default file system is exported and can be extended as needed:

import {FtpSrv, FileSystem} from 'ftp-srv-esm';

class MyFileSystem extends FileSystem {
  constructor() {
    super(...arguments);
  }

  get(fileName) {
    ...
  }
}

Custom file systems can implement the following variables depending on the developers needs:

Methods

Returns a string of the current working directory Used in: PWD

Returns a file stat object of file or directory Used in: LIST, NLST, STAT, SIZE, RNFR, MDTM

Returns array of file and directory stat objects Used in: LIST, NLST, STAT

Returns new directory relative to current directory Used in: CWD, CDUP

Returns a path to a newly created directory Used in: MKD

Returns a writable stream Options: append if true, append to existing file start if set, specifies the byte offset to write to Used in: STOR, APPE

Returns a readable stream Options: start if set, specifies the byte offset to read from Used in: RETR

Delete a file or directory Used in: DELE

Renames a file or directory Used in: RNFR, RNTO

Modifies a file or directory's permissions Used in: SITE CHMOD

Returns a unique file name to write to. Client requested filename available if you want to base your function on it. Used in: STOU

Contributing

See CONTRIBUTING.md.

License

This software is licensed under the MIT Licence. See LICENSE.

References

About

๐Ÿ“ฎ Modern, extensible FTP server (daemon) for Node.js with ESM support. Based on ftp-srv.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%