Skip to content

(feature) Allow opt-out from native_tls crate #140

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

Merged
merged 4 commits into from
Sep 24, 2019
Merged

(feature) Allow opt-out from native_tls crate #140

merged 4 commits into from
Sep 24, 2019

Conversation

brycefisher
Copy link
Contributor

@brycefisher brycefisher commented Sep 20, 2019

Ready for review! @jonhoo

Establishes conditional compilation for all integration with the native_tls crate. Since native_tls has been deeply integrated into this crate for a long time, we want to maintain backwards compatibility by making this feature part of the default.

For a consumer of this crate to "opt-out", include this in cargo.toml:

[dependencies.imap]
version = "0.16.0"        # Replace this with the correct version
default-features = false

See the conversation for details on this approach:
#123


In order to discourage developers from avoiding TLS, we're also simultaneously removing the connect_insecure method. However, it is still possible to use an unsecured TCP connection for an imap session by using imap::Client::new() and providing a naked TcpStream.

@brycefisher brycefisher mentioned this pull request Sep 21, 2019
@brycefisher brycefisher changed the title WIP add cargo feature (feature) Allow opt-out from native_tls crate Sep 21, 2019
src/error.rs Outdated
@@ -22,8 +25,10 @@ pub enum Error {
/// An `io::Error` that occurred while trying to read or write to a network stream.
Io(IoError),
/// An error from the `native_tls` library during the TLS handshake.
#[cfg(feature = "default")]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is actually pretty problematic, because it makes features non-additive. I think for this to be okay, we'll need rust-lang/rust#44109, which hasn't landed yet. One possible solution would be to add a variant to the end of this enum like this:

#[doc(hidden)]
__Nonexhaustive,

That prevents people from matching on Error, and thus makes the features additive again.

@jonhoo
Copy link
Owner

jonhoo commented Sep 21, 2019

I also just saw #123 (comment), and I think secure does still make sense. It should be generic though; currently it is under impl Client<TcpStream>, but I think it should be possible to secure any transport that is Read + Write.

@jonhoo
Copy link
Owner

jonhoo commented Sep 21, 2019

As for that test, I would re-write it to manually establish the TcpStream, then use Client::new + secure.

@jonhoo jonhoo mentioned this pull request Sep 21, 2019
@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@brycefisher
Copy link
Contributor Author

brycefisher commented Sep 21, 2019 via email

@jonhoo
Copy link
Owner

jonhoo commented Sep 22, 2019

So, with regards to Azure Pipelines, the current CI already checks with --no-default-features, so it should already include all the steps you had there :)

As for additive features, consider if one crate, A, has:

[dependencies]
imap = { version = "...", default-features = false }

And another, B, has:

[dependencies]
imap = "..." # so with the tls feature

If you have a crate C that depends on both A and B, then cargo will only compile imap once with all the features enabled. However, consider if A contained something like:

match imap::connect(...) {
  Ok(c) => ...,
  Err(imap::Error::Io(...)) => ...,
  Err(imap::Error::Bad(...)) => ...,
  Err(imap::Error::No(...)) => ...,
  ...
}

That compiles just fine if the tls feature is not enabled, but would not compiled if the tls feature is enabled (it would complain that you are missing the variants TlsHandshake and Tls). This is what we mean by features having to be "additive" — adding a feature can never remove something or otherwise cause something that compiled to no longer compile, because cargo will frequently add features to combine dependencies.

By adding the proposed hidden variant:

#[doc(hidden)]
__Nonexhaustive,

Now it'd be pretty clear to whoever wrote crate A that they should never be trying to match on all the variants of Error, because new variants may be added.

@brycefisher
Copy link
Contributor Author

I see! Okay, got it.

@brycefisher
Copy link
Contributor Author

secure does still make sense. It should be generic though; currently it is under impl Client, but I think it should be possible to secure any transport that is Read + Write.

I'm happy to tackle this! However, I'm seeing what looks like a lot of refactoring work here to nudge the type signatures. In particular the Error::TlsHandshake also knows about the underlying type of the transport. Making this enum generic will probably make a lot of other things more generic, and may make the Error type itself a wee bit unergonomic to users of the library.

I spent a few minutes trying to think of how to change the Error type without being so generic. The only decent idea I came up with was trying to immediately pull out the values of the TlsHandshakeError as strings and storing those on the Error::TlsHandshake. It feels a bit unidiomatic, but on the other hand, the any Error trait object should be easy to pull strings from.

@brycefisher brycefisher requested a review from jonhoo September 24, 2019 05:16
@jonhoo
Copy link
Owner

jonhoo commented Sep 24, 2019

I think the __Nonexhaustive change is still missing?

@jonhoo
Copy link
Owner

jonhoo commented Sep 24, 2019

Ah, that's a shame about .secure, but it's probably okay for now. It should be a backwards-compatible change to change it later anyway.

@brycefisher
Copy link
Contributor Author

Oh good catch! I wrote this code last night but somehow forgot to push it.

Establishes conditional compilation for all integration with the
native_tls crate in this crate. Since native_tls has been deeply
integrated into this crate for a long time, we want to maintain
backwards compatibility by making this feature part of the default.

For a consumer of this crate to "opt-out", including this in
cargo.toml:

```
[dependencies.imap]
version = 0.16.0        # Replace this with the correct version
default-features = false
```

See the conversation on Github for details on this approach:
#123
In order to discourage folks from connecting securely, we're removing the
convenience method imap::connect_insecure.

Fear not\! For those who manage security in another way (aka a private network
or similar measures), it is still possible to connect without TLS by using the
imap::Client::new() method. See that method for examples of how to do this.
Also point out the examples/rustlts.rs file for pure Rust TLS goodness
@jonhoo jonhoo merged commit 7aa5aa7 into jonhoo:master Sep 24, 2019
@jonhoo
Copy link
Owner

jonhoo commented Sep 24, 2019

Looks great, thank you!

@brycefisher brycefisher deleted the feat/cargo-feature-nativetls branch September 25, 2019 01:37
@jonhoo
Copy link
Owner

jonhoo commented Feb 20, 2020

Published in 2.0.0 🎉

Riduidel added a commit to Riduidel/rrss2imap that referenced this pull request Oct 28, 2020
Unfortunatly, this implies removing support of unsecured IMAP connection due to evolutions of the IMAP library
See jonhoo/rust-imap#140
Riduidel added a commit to Riduidel/rrss2imap that referenced this pull request Oct 28, 2020
* Updating non-conflicting deps
* Updating atom is not so straightforward
* reqwests will be hard to migrate
* Upgraded IMAP.
Unfortunatly, this implies removing support of unsecured IMAP connection due to evolutions of the IMAP library
See jonhoo/rust-imap#140
* Migrating reqwest was just a little harder : I had to get the dependency with the correct feature, then use the blocking part everywhere
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants