Skip to content

Commit

Permalink
refactor: Remove async-std (#1408)
Browse files Browse the repository at this point in the history
* Use trust-dns

* Fix MX to trust-dns

* Better logs

* select_ok

* Fix build

* Remove async-std

* Read system conf like before

* ignore headless tests

* don't unwrap

* Use hickory

* Fx build

* Use asyncresolver
  • Loading branch information
amaury1093 authored Dec 13, 2023
1 parent b9bda40 commit 2374ed3
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 249 deletions.
276 changes: 79 additions & 197 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ repository = "https://github.com/reacherhq/check-if-email-exists"
async-native-tls = { version = "0.4", default-features = false }
async-recursion = "1.0.5"
async-smtp = { version = "0.6.0", features = ["socks5"] }
async-std = "1.12.0"
async-std-resolver = "0.21.2"
chrono = "=0.4.22"
fantoccini = { version = "0.19.3", optional = true }
futures = { version = "0.3.29", optional = true }
fast-socks5 = "0.9.1"
hickory-proto = "0.24.0"
hickory-resolver = "0.24.0"
levenshtein = "1.0.5"
log = "0.4.20"
mailchecker = "6.0.1"
Expand All @@ -33,7 +33,6 @@ regex = "1.10.2"
reqwest = { version = "0.11.22", features = ["json", "socks"] }
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.107"
trust-dns-proto = "0.21.2"

[dev-dependencies]
tokio = { version = "1.29.1" }
Expand Down
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ pub mod smtp;
pub mod syntax;
mod util;

use hickory_proto::rr::rdata::MX;
use misc::{check_misc, MiscDetails};
use mx::check_mx;
use rand::Rng;
use smtp::{check_smtp, SmtpDetails, SmtpError};
use std::time::{Duration, SystemTime};
use syntax::{check_syntax, get_similar_mail_provider};
use trust_dns_proto::rr::rdata::MX;
pub use util::constants::LOG_TARGET;
pub use util::input_output::*;

Expand Down
32 changes: 19 additions & 13 deletions core/src/mx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::io;

use crate::syntax::SyntaxDetails;
use crate::util::ser_with_display::ser_with_display;
use async_std_resolver::{lookup::MxLookup, resolver_from_system_conf, ResolveError};
use hickory_resolver::error::ResolveError;
use hickory_resolver::lookup::MxLookup;
use hickory_resolver::system_conf::read_system_conf;
use hickory_resolver::TokioAsyncResolver;
use serde::{ser::SerializeMap, Serialize, Serializer};
use std::io::Error;

/// Details about the MX lookup.
#[derive(Debug)]
Expand Down Expand Up @@ -70,28 +74,30 @@ impl Serialize for MxDetails {
pub enum MxError {
/// Error with IO.
#[serde(serialize_with = "ser_with_display")]
IoError(Error),
IoError(io::Error),
/// Error while resolving MX lookups.
#[serde(serialize_with = "ser_with_display")]
ResolveError(Box<ResolveError>),
}

impl From<io::Error> for MxError {
fn from(e: io::Error) -> Self {
MxError::IoError(e)
}
}

impl From<ResolveError> for MxError {
fn from(error: ResolveError) -> Self {
MxError::ResolveError(Box::new(error))
fn from(e: ResolveError) -> Self {
MxError::ResolveError(Box::new(e))
}
}

/// Make a MX lookup.
pub async fn check_mx(syntax: &SyntaxDetails) -> Result<MxDetails, MxError> {
// Construct a new Resolver with default configuration options
let resolver = resolver_from_system_conf().await?;
let (config, opts) = read_system_conf()?;
let resolver = TokioAsyncResolver::tokio(config, opts);

// Lookup the MX records associated with a name.
// The final dot forces this to be an FQDN, otherwise the search rules as specified
// in `ResolverOpts` will take effect. FQDN's are generally cheaper queries.
match resolver.mx_lookup(syntax.domain.as_str()).await {
Ok(lookup) => Ok(MxDetails::from(lookup)),
Err(err) => Ok(MxDetails { lookup: Err(err) }),
}
let mx_response: MxLookup = resolver.mx_lookup(&syntax.domain).await?;
Ok(MxDetails::from(mx_response))
}
5 changes: 3 additions & 2 deletions core/src/smtp/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@ async fn connect_to_host(
) -> Result<SmtpTransport, SmtpError> {
let smtp_timeout = if let Some(t) = input.smtp_timeout {
if has_rule(domain, host, &Rule::SmtpTimeout45s) {
let duration = t.max(Duration::from_secs(45));
log::debug!(
target: LOG_TARGET,
"[email={}] Bumping SMTP timeout to at least 45s",
"[email={}] Bumping SMTP timeout to {duration:?} because of rule",
input.to_email,
);
Some(t.max(Duration::from_secs(45)))
Some(duration)
} else {
input.smtp_timeout
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/smtp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use std::default::Default;
use std::env;

use async_smtp::EmailAddress;
use hickory_proto::rr::Name;
use serde::{Deserialize, Serialize};
use trust_dns_proto::rr::Name;

use crate::{
util::input_output::CheckEmailInput, GmailVerifMethod, HotmailVerifMethod, YahooVerifMethod,
Expand Down Expand Up @@ -202,9 +202,9 @@ pub async fn check_smtp(
mod tests {
use super::{check_smtp, CheckEmailInput, SmtpConnection, SmtpError};
use async_smtp::{smtp::error::Error, EmailAddress};
use hickory_proto::rr::Name;
use std::{str::FromStr, time::Duration};
use tokio::runtime::Runtime;
use trust_dns_proto::rr::Name;

#[test]
fn should_timeout() {
Expand Down
23 changes: 14 additions & 9 deletions core/src/smtp/outlook/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::{thread::sleep, time::Duration};
use std::{pin::Pin, thread::sleep, time::Duration};

use async_std::prelude::FutureExt;
use fantoccini::Locator;
use futures::TryFutureExt;
use fantoccini::{error::CmdError, Locator};
use futures::{future::select_ok, Future, TryFutureExt};

use crate::{
smtp::{
Expand Down Expand Up @@ -83,7 +82,13 @@ pub async fn check_password_recovery(
.for_element(Locator::Id("iEnterVerification"))
.and_then(|_| async { Ok(true) });

let is_deliverable = f1.try_race(f2).try_race(f3).try_race(f4).await?;
let vec = vec![
Box::pin(f1) as Pin<Box<dyn Future<Output = Result<bool, CmdError>> + Send>>,
Box::pin(f2),
Box::pin(f3),
Box::pin(f4),
];
let (is_deliverable, _) = select_ok(vec).await?;

if is_deliverable {
log::debug!(
Expand Down Expand Up @@ -113,7 +118,7 @@ pub async fn check_password_recovery(
#[cfg(test)]
mod tests {
use super::check_password_recovery;
use async_std::prelude::FutureExt;
use futures::future::join;

// Ignoring this test as it requires a local process of WebDriver running on
// "http://localhost:9515". To debug the headless password recovery page,
Expand Down Expand Up @@ -144,13 +149,13 @@ mod tests {
// but will fail with geckodriver.
// ref: https://github.com/jonhoo/fantoccini/issues/111#issuecomment-727650629
#[tokio::test]
#[ignore = "Run a **chromedriver** server locally to test this"]
#[ignore = "Run a webdriver server locally to test this"]
async fn test_parallel() {
// This email does not exist.
let f1 = check_password_recovery("foo@bar.baz", "http://localhost:9515");
let f2 = check_password_recovery("foo@bar.baz", "http://localhost:9515");

let f = f1.try_join(f2).await;
assert!(f.is_ok(), "{:?}", f);
let f = join(f1, f2).await;
assert!(f.0.is_ok(), "{:?}", f);
}
}
35 changes: 13 additions & 22 deletions core/src/smtp/yahoo/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use std::pin::Pin;
use std::vec;
use std::{thread::sleep, time::Duration};

use async_std::prelude::FutureExt;
use fantoccini::error::CmdError;
use fantoccini::Locator;
use futures::TryFutureExt;
use futures::future::select_ok;
use futures::{Future, TryFutureExt};

use crate::smtp::headless::{create_headless_client, HeadlessError};
use crate::{smtp::SmtpDetails, LOG_TARGET};
Expand Down Expand Up @@ -82,26 +85,14 @@ pub async fn check_headless(to_email: &str, webdriver: &str) -> Result<SmtpDetai
.for_element(Locator::Id("challenge-selector-challenge"))
.and_then(|_| async { Ok((true, false)) });

let (is_deliverable, is_disabled) = f1
.try_race(f2)
.try_race(f3)
.try_race(f4)
.try_race(f5)
.await?;

if is_deliverable {
log::debug!(
target: LOG_TARGET,
"[email={}] Did not find error message in password recovery, email exists",
to_email,
);
} else {
log::debug!(
target: LOG_TARGET,
"[email={}] Found error message in password recovery, email does not exist",
to_email,
);
}
let vec = vec![
Box::pin(f1) as Pin<Box<dyn Future<Output = Result<(bool, bool), CmdError>> + Send>>,
Box::pin(f2),
Box::pin(f3),
Box::pin(f4),
Box::pin(f5),
];
let ((is_deliverable, is_disabled), _) = select_ok(vec).await?;

c.close().await?;

Expand Down

0 comments on commit 2374ed3

Please sign in to comment.