# SuppaFTP

logo

~ A super FTP/FTPS client library for Rust ~

Documentation ยท Crates.io

Developed by veeso and Matt McCoy

Current version: 6.0.3 (15/10/2024)

License-Apache-2.0/MIT Repo stars Downloads counter Latest version Ko-fi conventional-commits

Lib-CI Cli-bin-ci Coveralls Docs

--- - [SuppaFTP](#suppaftp) - [Introduction ๐Ÿ‘‹](#introduction-) - [Main differences between SuppaFTP and rust-ftp ๐Ÿค”](#main-differences-between-suppaftp-and-rust-ftp-) - [Get started ๐Ÿ](#get-started-) - [Features](#features) - [SSL/TLS Support](#ssltls-support) - [Async support](#async-support) - [Deprecated methods](#deprecated-methods) - [Logging](#logging) - [Examples ๐Ÿ“š](#examples-) - [Ftp with TLS (native-tls)](#ftp-with-tls-native-tls) - [Ftp with TLS (rustls)](#ftp-with-tls-rustls) - [Going Async](#going-async) - [Built-in CLI client ๐Ÿ–ฅ๏ธ](#built-in-cli-client-๏ธ) - [Support the developer โ˜•](#support-the-developer-) - [Changelog โŒ›](#changelog-) - [License ๐Ÿ“œ](#license-) - [Contribution ๐Ÿค](#contribution-) --- ## Introduction ๐Ÿ‘‹ SuppaFTP is the main FTP/FTPS client library for Rust, with both support for sync/async programming and for all the FTP protocol features. It is a fork of the original ftp library "[rust-ftp](https://github.com/mattnenterprise/rust-ftp)", but since the original library is currently unmaintained, I decided to keep working on this library by myself. Currently, I consider myself as the only maintainer of this project, indeed I've already added some features to the library and improved it with better error handling and test units. ### Main differences between SuppaFTP and rust-ftp ๐Ÿค” - Replaced OpenSSL with **native-tls** or **rustls** as you prefer ๐Ÿ”’ - Added methods to work with streams (e.g. `put_with_stream`) โฌ‡๏ธ - suppaftp supports **Active mode** - Added `get_welcome_msg` method ๐Ÿ‘‹ - Supports for both **sync/async** rust ๐Ÿ•™ - Supports for more commands ๐ŸŒŸ - ABOR - APPE - REST - EPSV - EPRT - Some extra features, such as the **LIST** command output parser - Implementation of [RFC 2428](https://www.rfc-editor.org/rfc/rfc2428.html) - Implementationb of [RFC 2389](https://www.rfc-editor.org/rfc/rfc2389) - Removed deprecated statements โšฐ๏ธ - Better error handling ๐Ÿ› - Added test units keeping an eye on code coverage ๐Ÿ‘€ --- ## Get started ๐Ÿ To get started, first add **suppaftp** to your dependencies: ```toml suppaftp = "^6" ``` ### Features #### SSL/TLS Support If you want to enable **support for FTPS**, you must enable the `native-tls` or `rustls` feature in your cargo dependencies, based on the TLS provider you prefer. ```toml suppaftp = { version = "^6", features = ["native-tls"] } # or suppaftp = { version = "^6", features = ["rustls"] } ``` > ๐Ÿ’ก If you don't know what to choose, `native-tls` should be preferred for compatibility reasons. > โ— If you want to link libssl statically, enable feature `native-tls-vendored` #### Async support If you want to enable **async** support, you must enable `async` feature in your cargo dependencies. ```toml suppaftp = { version = "^6", features = ["async"] } ``` > โš ๏ธ If you want to enable both **native-tls** and **async** you must use the **async-native-tls** feature โš ๏ธ > โš ๏ธ If you want to enable both **rustls** and **async** you must use the **async-rustls** feature โš ๏ธ > โ— If you want to link libssl statically, enable feature `async-native-tls-vendored` #### Deprecated methods If you want to enable deprecated methods of FTPS, please enable the `deprecated` feature in your cargo dependencies. This feature enables these methods: - `connect_secure_implicit()`: used to connect via implicit FTPS #### Logging By default, the library will log if there is any `log` crate consumer on the user implementation. Logging can be if preferred, disabled via the `no-log` feature. ### Examples ๐Ÿ“š ```rust use std::str; use std::io::Cursor; use suppaftp::FtpStream; fn main() { // Create a connection to an FTP server and authenticate to it. let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap(); let _ = ftp_stream.login("username", "password").unwrap(); // Get the current directory that the client will be reading from and writing to. println!("Current directory: {}", ftp_stream.pwd().unwrap()); // Change into a new directory, relative to the one we are currently in. let _ = ftp_stream.cwd("test_data").unwrap(); // Retrieve (GET) a file from the FTP server in the current working directory. let data = ftp_stream.retr_as_buffer("ftpext-charter.txt").unwrap(); println!("Read file with contents\n{}\n", str::from_utf8(&data.into_inner()).unwrap()); // Store (PUT) a file from the client to the current working directory of the server. let mut reader = Cursor::new("Hello from the Rust \"ftp\" crate!".as_bytes()); let _ = ftp_stream.put_file("greeting.txt", &mut reader); println!("Successfully wrote greeting.txt"); // Terminate the connection to the server. let _ = ftp_stream.quit(); } ``` #### Ftp with TLS (native-tls) ```rust use suppaftp::{NativeTlsFtpStream, NativeTlsConnector}; use suppaftp::native_tls::{TlsConnector, TlsStream}; fn main() { let ftp_stream = NativeTlsFtpStream::connect("test.rebex.net:21").unwrap(); // Switch to the secure mode let mut ftp_stream = ftp_stream.into_secure(NativeTlsConnector::from(TlsConnector::new().unwrap()), "test.rebex.net").unwrap(); ftp_stream.login("demo", "password").unwrap(); // Do other secret stuff assert!(ftp_stream.quit().is_ok()); } ``` #### Ftp with TLS (rustls) ```rust use std::str; use std::io::Cursor; use std::sync::Arc; use suppaftp::{RustlsFtpStream, RustlsConnector}; use suppaftp::rustls::ClientConfig; fn main() { let mut root_store = rustls::RootCertStore::empty(); root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) })); let config = ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); // Create a connection to an FTP server and authenticate to it. let config = Arc::new(rustls_config()); let mut ftp_stream = RustlsFtpStream::connect("test.rebex.net:21") .unwrap() .into_secure(RustlsConnector::from(Arc::clone(&config)), "test.rebex.net") .unwrap(); // Terminate the connection to the server. let _ = ftp_stream.quit(); } ``` #### Going Async ```rust use suppaftp::{AsyncNativeTlsFtpStream, AsyncNativeTlsConnector}; use suppaftp::async_native_tls::{TlsConnector, TlsStream}; let ftp_stream = AsyncNativeTlsFtpStream::connect("test.rebex.net:21").await.unwrap(); // Switch to the secure mode let mut ftp_stream = ftp_stream.into_secure(AsyncNativeTlsConnector::from(TlsConnector::new()), "test.rebex.net").await.unwrap(); ftp_stream.login("demo", "password").await.unwrap(); // Do other secret stuff assert!(ftp_stream.quit().await.is_ok()); ``` ## Built-in CLI client ๐Ÿ–ฅ๏ธ SuppaFTP comes also with a built-in command-line FTP client. This CLI application provides all the commands to interact with a remote FTP server and supports FTPS too. You can also use it as a reference to implement your project. You can find it in the `cli/` directory. You can simply install as any other rust application via **Cargo**: ```sh cargo install suppaftp-cli suppaftp --version ``` --- ## Support the developer โ˜• If you like **SuppaFTP**, please consider a little donation ๐Ÿฅณ [![ko-fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/veeso) [![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://www.paypal.me/chrisintin) --- ## Changelog โŒ› View Changelog [here](CHANGELOG.md) --- ## License ๐Ÿ“œ Licensed under either of - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) - MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. --- ### Contribution ๐Ÿค Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. If you want to contribute to this project, please read the [Contributing guide](CONTRIBUTING.md) first ๐Ÿ™‚.