Add imap::connect_starttls convenience function

Add a `imap::connect_starttls` convenience function, with the same
syntax as `imap::connect`, to make STARTTLS connections as easily as
IMAPS.

PR#140 removed `imap::connect_insecure` with the stated goal of
encouraging users to connect securely. With that change, users are
forced to construct their own `TcpStream`s when interacting with
non-IMAPS servers.

This change may perversely incentivise the use of insecure connections,
instead of discouraging them, as users may blindly copy-paste code
involving `Client::new` and `TcpStream`s so things "just work", without
the visual indicator of `_insecure` suggesting something is wrong.

Tangentially, [RFC 2595] encourages using STARTTLS instead of raw SSL
sockets. Ideally, we should support both options equally well.

[RFC 2595]: https://tools.ietf.org/html/rfc2595#section-7
This commit is contained in:
Celti Burroughs 2019-11-30 04:58:24 -07:00
parent 271599bb78
commit a4b03568be
No known key found for this signature in database
GPG key ID: 446E116C2B180AA4

View file

@ -154,6 +154,46 @@ pub fn connect<A: ToSocketAddrs, S: AsRef<str>>(
} }
} }
/// Connect to a server and upgrade to a TLS-encrypted connection.
///
/// This is the [STARTTLS](https://tools.ietf.org/html/rfc2595) equivalent to [`connect`]. All
/// notes there also apply here.
///
/// # Examples
///
/// ```no_run
/// # extern crate native_tls;
/// # extern crate imap;
/// # use std::io;
/// # use native_tls::TlsConnector;
/// # fn main() {
/// let tls = TlsConnector::builder().build().unwrap();
/// let client = imap::connect_starttls(("imap.example.org", 143), "imap.example.org", &tls).unwrap();
/// # }
/// ```
#[cfg(feature = "tls")]
pub fn connect_starttls<A: ToSocketAddrs, S: AsRef<str>>(
addr: A,
domain: S,
ssl_connector: &TlsConnector,
) -> Result<Client<TlsStream<TcpStream>>> {
match TcpStream::connect(addr) {
Ok(stream) => {
let mut socket = Client::new(stream);
socket.read_greeting()?;
socket.run_command_and_check_ok("STARTTLS")?;
TlsConnector::connect(
ssl_connector,
domain.as_ref(),
socket.conn.stream.into_inner()?,
)
.map(Client::new)
.map_err(Error::TlsHandshake)
}
Err(e) => Err(Error::Io(e)),
}
}
impl Client<TcpStream> { impl Client<TcpStream> {
/// This will upgrade an IMAP client from using a regular TCP connection to use TLS. /// This will upgrade an IMAP client from using a regular TCP connection to use TLS.
/// ///