Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
fclairamb authored Dec 30, 2020
1 parent b2dac2c commit 3a28816
Showing 1 changed file with 103 additions and 103 deletions.
206 changes: 103 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,148 +36,150 @@ If you're interested in a fully featured FTP server, you should use [sftpgo](htt
* [REST](https://tools.ietf.org/html/rfc3659#page-13) - Restart of interrupted transfer
* [MLST](https://tools.ietf.org/html/rfc3659#page-23) - Simple file listing for machine processing
* [MLSD](https://tools.ietf.org/html/rfc3659#page-23) - Directory listing for machine processing
* [HASH](https://tools.ietf.org/html/draft-bryan-ftpext-hash-02) - Hashing of files
* [AVLB](https://tools.ietf.org/html/draft-peterson-streamlined-ftp-command-extensions-10#section-4) - Available space
* [COMB](https://help.globalscape.com/help/archive/eft6-4/mergedprojects/eft/allowingmultiparttransferscomb_command.htm) - Combine files

## Quick test
We are providing a server so that you can test how the library behaves.

```sh
# Get and install the server
go install github.com/fclairamb/ftpserver

# Create a storage dir
mkdir -p data

ftpserver -data data &

# Download some file
if [ ! -f file.bin ]; then
wget -O file.bin.tmp https://github.com/fclairamb/ftpserver/releases/download/v0.5/ftpserver-linux-amd64 && mv file.bin.tmp file.bin
fi

# Connecting to the server and uploading the file
ftp ftp://test:test@localhost:2121
put file.bin
quit
ls -lh data/file.bin
```

## Quick test with docker
There's also a containerized version of the demo server (15MB, based on alpine).

```sh
# Creating a storage dir
mkdir -p data

# Starting the sample FTP server
docker run --rm -d -p 2121-2130:2121-2130 -v $(pwd)/data:/data fclairamb/ftpserver

# Download some file
if [ ! -f kitty.jpg ]; then
curl -o kitty.jpg.tmp https://placekitten.com/2048/2048 && mv kitty.jpg.tmp kitty.jpg
fi

curl -v -T kitty.bin ftp://test:test@localhost:2121/
```
The easiest way to test this library is to use [ftpserver](https://github.com/fclairamb/ftpserver).

## The driver
The simplest way to get a good understanding of how the driver shall be implemented, you can have a look at the [tests driver](https://github.com/fclairamb/ftpserverlib/blob/master/driver_test.go).

### The API
### The base API

The API is directly based on [afero](https://github.com/spf13/afero).

```go
// ServerDriver handles the authentication and ClientHandlingDriver selection
type ServerDriver interface {
// Load some general settings around the server setup
GetSettings() *Settings
// MainDriver handles the authentication and ClientHandlingDriver selection
type MainDriver interface {
// GetSettings returns some general settings around the server setup
GetSettings() (*Settings, error)

// WelcomeUser is called to send the very first welcome message
WelcomeUser(cc ClientContext) (string, error)
// ClientConnected is called to send the very first welcome message
ClientConnected(cc ClientContext) (string, error)

// UserLeft is called when the user disconnects, even if he never authenticated
UserLeft(cc ClientContext)
// ClientDisconnected is called when the user disconnects, even if he never authenticated
ClientDisconnected(cc ClientContext)

// AuthUser authenticates the user and selects an handling driver
AuthUser(cc ClientContext, user, pass string) (afero.Fs, error)
AuthUser(cc ClientContext, user, pass string) (ClientDriver, error)

// GetCertificate returns a TLS Certificate to use
// GetTLSConfig returns a TLS Certificate to use
// The certificate could frequently change if we use something like "let's encrypt"
GetTLSConfig() (*tls.Config, error)
}


// ClientDriver is the base FS implementation that allows to manipulate files
type ClientDriver interface {
afero.Fs
}

// ClientContext is implemented on the server side to provide some access to few data around the client
type ClientContext interface {
// Get current path
// Path provides the path of the current connection
Path() string

// SetDebug activates the debugging of this connection commands
SetDebug(debug bool)

// Debug returns the current debugging status of this connection commands
Debug() bool

// Client's ID on the server
ID() uint32

// Client's address
RemoteAddr() net.Addr

// Servers's address
LocalAddr() net.Addr

// Client's version can be empty
GetClientVersion() string

// Close closes the connection and disconnects the client.
Close() error

// HasTLSForControl returns true if the control connection is over TLS
HasTLSForControl() bool

// HasTLSForTransfers returns true if the transfer connection is over TLS
HasTLSForTransfers() bool

// GetLastCommand returns the last received command
GetLastCommand() string
}

// Settings define all the server settings
type Settings struct {
ListenHost string // Host to receive connections on
ListenPort int // Port to listen on
PublicHost string // Public IP to expose (only an IP address is accepted at this stage)
DataPortRange *PortRange // Port Range for data connections. Random one will be used if not specified
Listener net.Listener // (Optional) To provide an already initialized listener
ListenAddr string // Listening address
PublicHost string // Public IP to expose (only an IP address is accepted at this stage)
PublicIPResolver PublicIPResolver // (Optional) To fetch a public IP lookup
PassiveTransferPortRange *PortRange // (Optional) Port Range for data connections. Random if not specified
ActiveTransferPortNon20 bool // Do not impose the port 20 for active data transfer (#88, RFC 1579)
IdleTimeout int // Maximum inactivity time before disconnecting (#58)
ConnectionTimeout int // Maximum time to establish passive or active transfer connections
DisableMLSD bool // Disable MLSD support
DisableMLST bool // Disable MLST support
DisableMFMT bool // Disable MFMT support (modify file mtime)
Banner string // Banner to use in server status response
TLSRequired TLSRequirement // defines the TLS mode
DisableLISTArgs bool // Disable ls like options (-a,-la etc.) for directory listing
DisableSite bool // Disable SITE command
DisableActiveMode bool // Disable Active FTP
EnableHASH bool // Enable support for calculating hash value of files
DisableSTAT bool // Disable Server STATUS, STAT on files and directories will still work
DisableSYST bool // Disable SYST
EnableCOMB bool // Enable COMB support
DefaultTransferType TransferType // Transfer type to use if the client don't send the TYPE command
}
```

### Sample implementation
### Extensions
There are a few extensions to the base afero APIs so that you can perform some operations that aren't offered by afero.

Have a look at the [sample driver](https://github.com/fclairamb/ftpserver/tree/master/sample). It shows how you can plug your FTP server to something else, in this case your file system.
#### Pre-allocate some space
```go
// ClientDriverExtensionAllocate is an extension to support the "ALLO" - file allocation - command
type ClientDriverExtensionAllocate interface {

## Sample run
// AllocateSpace reserves the space necessary to upload files
AllocateSpace(size int) error
}
```
$ ftp ftp://a:a@localhost:2121
Trying ::1...
Connected to localhost.
220 Welcome on https://github.com/fclairamb/ftpserver
331 OK
230 Password ok, continue
Remote system type is UNIX.
Using binary mode to transfer files.
200 Type set to binary
ftp> put iMX7D_RM_Rev_B.pdf
local: iMX7D_RM_Rev_B.pdf remote: iMX7D_RM_Rev_B.pdf
229 Entering Extended Passive Mode (|||62362|)
150 Using transfer connection
100% |******************************************************************************************************************************************************************| 44333 KiB 635.92 MiB/s 00:00 ETA
226 OK, received 45397173 bytes
45397173 bytes sent in 00:00 (538.68 MiB/s)
ftp> cd virtual
250 CD worked on /virtual
ftp> ls
229 Entering Extended Passive Mode (|||62369|)
150 Using transfer connection
-rw-rw-rw- 1 ftp ftp 1024 Sep 28 01:44 localpath.txt
-rw-rw-rw- 1 ftp ftp 2048 Sep 28 01:44 file2.txt
226 Closing data connection, sent some bytes
ftp> get localpath.txt
local: localpath.txt remote: localpath.txt
229 Entering Extended Passive Mode (|||62371|)
150 Using transfer connection
67 241.43 KiB/s
226 OK, sent 67 bytes
67 bytes received in 00:00 (160.36 KiB/s)
ftp> ^D
221 Goodbye
$ more localpath.txt
/var/folders/vk/vgsfkf9975xfrc4_fk102g200000gn/T/ftpserver020090599
$ shasum /var/folders/vk/vgsfkf9975xfrc4_fk102g200000gn/T/ftpserver020090599/iMX7D_RM_Rev_B.pdf
03b3686b31867fb14d3f3a61e20d28a029883a32 /var/folders/vk/vgsfkf9975xfrc4_fk102g200000gn/T/ftpserver020090599/iMX7D_RM_Rev_B.pdf
$ more localpath.txt
$ shasum iMX7D_RM_Rev_B.pdf
03b3686b31867fb14d3f3a61e20d28a029883a32 iMX7D_RM_Rev_B.pdf

#### Get available space
```go
// ClientDriverExtensionAvailableSpace is an extension to implement to support
// the AVBL ftp command
type ClientDriverExtensionAvailableSpace interface {
GetAvailableSpace(dirName string) (int64, error)
}
```

#### Create symbolic link
```go
// ClientDriverExtensionSymlink is an extension to support the "SITE SYMLINK" - symbolic link creation - command
type ClientDriverExtensionSymlink interface {

// Symlink creates a symlink
Symlink(oldname, newname string) error

// SymlinkIfPossible allows to get the source of a symlink (but we don't need for now)
// ReadlinkIfPossible(name string) (string, error)
}
```

#### Compute file hash
```go
// ClientDriverExtensionHasher is an extension to implement if you want to handle file digests
// yourself. You have to set EnableHASH to true for this extension to be called
type ClientDriverExtensionHasher interface {
ComputeHash(name string, algo HASHAlgo, startOffset, endOffset int64) (string, error)
}
```

## History of the project
Expand All @@ -189,5 +191,3 @@ I wanted to make a system which would accept files through FTP and redirect them
* [yob/graval](https://github.com/yob/graval) is 3 years old and “experimental”.
* [goftp/server](https://github.com/goftp/server) seemed OK but I couldn't use it on both Filezilla and the MacOs ftp client.
* [andrewarrow/paradise_ftp](https://github.com/andrewarrow/paradise_ftp) - Was the only one of the list I could test right away. This is the project I forked from.

That's why I forked from this last one.

0 comments on commit 3a28816

Please sign in to comment.