Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implicit ftps #15

Merged
merged 1 commit into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 78 additions & 7 deletions src/async_ftp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,9 @@ impl FtpStream {
}
}

/// Switch to a secure mode if possible, using a provided SSL configuration.
/// Switch to secure mode if possible (FTPS), using a provided SSL configuration.
/// This method does nothing if the connect is already secured.
///
/// ## Panics
///
/// Panics if the plain TCP connection cannot be switched to TLS mode.
///
/// ## Example
///
/// ```rust,no_run
Expand Down Expand Up @@ -154,6 +150,60 @@ impl FtpStream {
Ok(secured_ftp_tream)
}

/// Switch to implicit secure mode (FTPS), using a provided SSL configuration.
///
///
/// ## Example
///
/// ```rust,no_run
/// use suppaftp::FtpStream;
/// use suppaftp::async_native_tls::{TlsConnector, TlsStream};
/// use std::path::Path;
///
/// // Create a TlsConnector
/// // NOTE: For custom options see <https://docs.rs/native-tls/0.2.6/native_tls/struct.TlsConnectorBuilder.html>
/// let mut ctx = TlsConnector::new();
/// let mut ftp_stream = FtpStream::connect("127.0.0.1:21").await.unwrap();
/// let mut ftp_stream = ftp_stream.into_secure(ctx, "localhost:990", "localhost").await.unwrap();
/// ```
#[cfg(feature = "async-secure")]
pub async fn into_secure_implicit<A: ToSocketAddrs>(
mut self,
tls_connector: TlsConnector,
addr: A,
domain: &str,
) -> FtpResult<Self> {
debug!("Switching to FTPS (implicit)");
self.reader = TcpStream::connect(addr)
.await
.map_err(FtpError::ConnectionError)
.map(|stream| BufReader::new(DataStream::Tcp(stream)))?;
debug!("Established connection with server");
debug!("TLS OK; initializing ssl stream");
let stream = tls_connector
.connect(domain, self.reader.into_inner().into_tcp_stream())
.await
.map_err(|e| FtpError::SecureError(format!("{}", e)))?;
debug!("TLS Steam OK");
let mut stream = FtpStream {
reader: BufReader::new(DataStream::Ssl(stream)),
mode: self.mode,
tls_ctx: Some(tls_connector),
domain: Some(String::from(domain)),
welcome_msg: self.welcome_msg,
};
debug!("Reading server response...");
match stream.read_response(Status::Ready).await {
Ok(response) => {
debug!("Server READY; response: {}", response.body);
self.welcome_msg = Some(response.body);
}
Err(err) => return Err(err),
}

Ok(stream)
}

/// Enable active mode for data channel
pub fn active_mode(mut self) -> Self {
self.mode = Mode::Active;
Expand Down Expand Up @@ -611,7 +661,7 @@ impl FtpStream {

let msb = addr.port() / 256;
let lsb = addr.port() % 256;
let ip_port = format!("{},{},{}", ip.to_string().replace(".", ","), msb, lsb);
let ip_port = format!("{},{},{}", ip.to_string().replace('.', ","), msb, lsb);
debug!("Active mode, listening on {}:{}", ip, addr.port());

debug!("Running PORT command");
Expand Down Expand Up @@ -743,7 +793,7 @@ mod test {
#[async_attributes::test]
#[cfg(feature = "async-secure")]
#[serial]
async fn connect_ssl() {
async fn should_connect_ssl() {
crate::log_init();
let ftp_stream = FtpStream::connect("test.rebex.net:21").await.unwrap();
let mut ftp_stream = ftp_stream
Expand All @@ -761,6 +811,27 @@ mod test {
assert!(ftp_stream.quit().await.is_ok());
}

#[async_attributes::test]
#[serial]
#[cfg(feature = "async-secure")]
async fn should_connect_ssl_implicit() {
crate::log_init();
let ftp_stream = FtpStream::connect("test.rebex.net:21").await.unwrap();
let mut ftp_stream = ftp_stream
.into_secure_implicit(TlsConnector::new(), "test.rebex.net:990", "test.rebex.net")
.await
.ok()
.unwrap();
// Set timeout (to test ref to ssl)
assert!(ftp_stream.get_ref().await.set_ttl(255).is_ok());
// Login
assert!(ftp_stream.login("demo", "password").await.is_ok());
// PWD
assert_eq!(ftp_stream.pwd().await.ok().unwrap().as_str(), "/");
// Quit
assert!(ftp_stream.quit().await.is_ok());
}

#[async_attributes::test]
#[cfg(feature = "async-secure")]
#[serial]
Expand Down
89 changes: 82 additions & 7 deletions src/sync_ftp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,9 @@ impl FtpStream {
self.mode = mode;
}

/// Switch to a secure mode if possible, using a provided SSL configuration.
/// Switch to explicit secure mode if possible (FTPS), using a provided SSL configuration.
/// This method does nothing if the connect is already secured.
///
/// ## Panics
///
/// Panics if the plain TCP connection cannot be switched to TLS mode.
///
/// ## Example
///
/// ```rust,no_run
Expand Down Expand Up @@ -160,6 +156,58 @@ impl FtpStream {
Ok(secured_ftp_tream)
}

/// Switch to implicit secure mode (FTPS), using a provided SSL configuration.
///
///
/// ## Example
///
/// ```rust,no_run
/// use suppaftp::FtpStream;
/// use suppaftp::native_tls::{TlsConnector, TlsStream};
/// use std::path::Path;
///
/// // Create a TlsConnector
/// // NOTE: For custom options see <https://docs.rs/native-tls/0.2.6/native_tls/struct.TlsConnectorBuilder.html>
/// let mut ctx = TlsConnector::new().unwrap();
/// let mut ftp_stream = FtpStream::connect("127.0.0.1:21").unwrap();
/// let mut ftp_stream = ftp_stream.into_secure_implicit(ctx, "localhost:990", "localhost").unwrap();
/// ```
#[cfg(feature = "secure")]
pub fn into_secure_implicit<A: ToSocketAddrs>(
mut self,
tls_connector: TlsConnector,
addr: A,
domain: &str,
) -> FtpResult<Self> {
debug!("Switching to FTPS (implicit)");
self.reader = TcpStream::connect(addr)
.map_err(FtpError::ConnectionError)
.map(|stream| BufReader::new(DataStream::Tcp(stream)))?;
debug!("Established connection with server");
debug!("TLS OK; initializing ssl stream");
let stream = tls_connector
.connect(domain, self.reader.into_inner().into_tcp_stream())
.map_err(|e| FtpError::SecureError(format!("{}", e)))?;
debug!("TLS Steam OK");
let mut stream = FtpStream {
reader: BufReader::new(DataStream::Ssl(stream.into())),
mode: self.mode,
tls_ctx: Some(tls_connector),
domain: Some(String::from(domain)),
welcome_msg: self.welcome_msg,
};
debug!("Reading server response...");
match stream.read_response(Status::Ready) {
Ok(response) => {
debug!("Server READY; response: {}", response.body);
self.welcome_msg = Some(response.body);
}
Err(err) => return Err(err),
}

Ok(stream)
}

/// Returns welcome message retrieved from server (if available)
pub fn get_welcome_msg(&self) -> Option<&str> {
self.welcome_msg.as_deref()
Expand Down Expand Up @@ -676,7 +724,7 @@ impl FtpStream {

let msb = addr.port() / 256;
let lsb = addr.port() % 256;
let ip_port = format!("{},{},{}", ip.to_string().replace(".", ","), msb, lsb);
let ip_port = format!("{},{},{}", ip.to_string().replace('.', ","), msb, lsb);
debug!("Active mode, listening on {}:{}", ip, addr.port());

debug!("Running PORT command");
Expand Down Expand Up @@ -751,7 +799,7 @@ mod test {
#[test]
#[serial]
#[cfg(feature = "secure")]
fn connect_ssl() {
fn should_connect_ssl() {
crate::log_init();
let ftp_stream = FtpStream::connect("test.rebex.net:21").unwrap();
let mut ftp_stream = ftp_stream
Expand Down Expand Up @@ -792,6 +840,33 @@ mod test {
assert!(ftp_stream.quit().is_ok());
}

#[test]
#[serial]
#[cfg(feature = "secure")]
fn should_connect_ssl_implicit() {
crate::log_init();
let ftp_stream = FtpStream::connect("test.rebex.net:21").unwrap();
let mut ftp_stream = ftp_stream
.into_secure_implicit(
TlsConnector::new().unwrap(),
"test.rebex.net:990",
"test.rebex.net",
)
.ok()
.unwrap();
// Set timeout (to test ref to ssl)
assert!(ftp_stream
.get_ref()
.set_read_timeout(Some(Duration::from_secs(10)))
.is_ok());
// Login
assert!(ftp_stream.login("demo", "password").is_ok());
// PWD
assert_eq!(ftp_stream.pwd().ok().unwrap().as_str(), "/");
// Quit
assert!(ftp_stream.quit().is_ok());
}

#[test]
#[serial]
fn should_change_mode() {
Expand Down