From 15059116ee94ab0712eb9bf958b18659f5d50584 Mon Sep 17 00:00:00 2001 From: Amaury <1293565+amaury1093@users.noreply.github.com> Date: Fri, 20 Dec 2024 00:46:03 +0100 Subject: [PATCH] Fix tests --- Cargo.lock | 108 ++++++++++++++++++++++++++++++-- backend/Cargo.toml | 1 - backend/src/main.rs | 3 - cli/Cargo.toml | 1 - cli/src/main.rs | 3 - core/Cargo.toml | 2 + core/src/lib.rs | 14 +++++ core/src/smtp/yahoo/headless.rs | 40 ++++++++++-- 8 files changed, 154 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db32755d7..9f99b66b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,7 +327,7 @@ dependencies = [ "anyhow", "base64 0.13.1", "futures", - "hostname", + "hostname 0.3.1", "log", "nom", "pin-project", @@ -592,6 +592,7 @@ dependencies = [ "futures", "hickory-proto", "hickory-resolver", + "lettre", "levenshtein", "log", "mailchecker", @@ -600,6 +601,7 @@ dependencies = [ "rand", "regex", "reqwest", + "rustls 0.23.20", "sentry", "serde", "serde_json", @@ -617,7 +619,6 @@ dependencies = [ "clap", "once_cell", "openssl", - "rustls 0.23.20", "serde", "serde_json", "tokio", @@ -639,6 +640,16 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "chumsky" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" +dependencies = [ + "hashbrown 0.14.5", + "stacker", +] + [[package]] name = "cipher" version = "0.4.4" @@ -1115,6 +1126,22 @@ dependencies = [ "serde", ] +[[package]] +name = "email-encoding" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3d894bbbab314476b265f9b2d46bf24b123a36dd0e96b06a1b49545b9d9dcc" +dependencies = [ + "base64 0.22.1", + "memchr", +] + +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1676,6 +1703,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "hostname" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" +dependencies = [ + "cfg-if", + "libc", + "windows", +] + [[package]] name = "http" version = "0.2.12" @@ -2144,6 +2182,31 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lettre" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c9a167ff73df98a5ecc07e8bf5ce90b583665da3d1762eb1f775ad4d0d6f5" +dependencies = [ + "base64 0.22.1", + "chumsky", + "email-encoding", + "email_address", + "fastrand 2.3.0", + "futures-util", + "hostname 0.4.0", + "httpdate", + "idna", + "mime", + "native-tls", + "nom", + "percent-encoding", + "quoted_printable", + "socket2 0.5.8", + "tokio", + "url", +] + [[package]] name = "levenshtein" version = "1.0.5" @@ -2864,6 +2927,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psm" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +dependencies = [ + "cc", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -2931,6 +3003,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73" + [[package]] name = "rand" version = "0.8.5" @@ -2984,7 +3062,6 @@ dependencies = [ "lapin", "openssl", "reqwest", - "rustls 0.23.20", "sentry", "sentry-anyhow", "serde", @@ -3100,7 +3177,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ - "hostname", + "hostname 0.3.1", "quick-error", ] @@ -3905,6 +3982,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "stacker" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + [[package]] name = "stringprep" version = "0.1.5" @@ -4733,6 +4823,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.52.0" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index b64bbea9e..c2eaa105d 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -43,7 +43,6 @@ tracing = "0.1.40" tracing-subscriber = "0.3.18" uuid = "1.10" warp = "0.3" -rustls = { version = "0.23", features = ["ring"] } [dev-dependencies] toml = "0.8" diff --git a/backend/src/main.rs b/backend/src/main.rs index eaaa3e7b2..6ca3eefde 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -31,9 +31,6 @@ const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); async fn main() -> Result<(), anyhow::Error> { // Initialize logging. tracing_subscriber::fmt::init(); - rustls::crypto::ring::default_provider() - .install_default() - .expect("Failed to install rustls crypto provider"); info!(target: LOG_TARGET, version=?CARGO_PKG_VERSION, "Running Reacher"); let mut config = load_config().await?; diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 93b30186a..33e1dcb14 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -18,7 +18,6 @@ check-if-email-exists = { path = "../core" } clap = { version = "3.2", features = ["derive", "env"] } once_cell = "1.19" openssl = { version = "0.10", features = ["vendored"] } -rustls = { version = "0.23", features = ["ring"] } serde = "1.0" serde_json = "1.0" tracing-subscriber = "0.3.18" diff --git a/cli/src/main.rs b/cli/src/main.rs index f3978b3cd..fa90df434 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -90,9 +90,6 @@ pub(crate) static CONF: Lazy = Lazy::new(Cli::parse); #[tokio::main] async fn main() -> Result<(), anyhow::Error> { tracing_subscriber::fmt::init(); - rustls::crypto::ring::default_provider() - .install_default() - .expect("Failed to install rustls crypto provider"); let to_email = &CONF.to_email; diff --git a/core/Cargo.toml b/core/Cargo.toml index 01572530d..2ec27134b 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -27,6 +27,7 @@ futures = { version = "0.3.30" } hickory-proto = "0.24.0" hickory-resolver = "0.24.0" levenshtein = "1.0.5" +lettre = { version = "0.11", features = ["smtp-transport"] } log = "0.4.22" mailchecker = "6.0.11" md5 = "0.7.0" @@ -37,6 +38,7 @@ reqwest = { version = "0.12.5", default-features = false, features = [ "json", "rustls-tls", ] } +rustls = { version = "0.23", features = ["ring"] } sentry = { version = "0.32", default-features = false, features = [ "reqwest", "rustls", diff --git a/core/src/lib.rs b/core/src/lib.rs index 4d34e1e6e..587965f1a 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -75,8 +75,10 @@ use hickory_proto::rr::rdata::MX; use misc::{check_misc, MiscDetails}; use mx::check_mx; use rand::Rng; +use rustls::crypto::ring; use smtp::{check_smtp, SmtpDetails, SmtpError}; pub use smtp::{is_gmail, is_hotmail, is_hotmail_b2b, is_hotmail_b2c, is_yahoo}; +use std::sync::Once; use std::time::{Duration, SystemTime}; use syntax::{check_syntax, get_similar_mail_provider}; pub use util::input_output::*; @@ -88,6 +90,16 @@ use crate::rules::{has_rule, Rule}; /// The target where to log check-if-email-exists logs. pub const LOG_TARGET: &str = "reacher"; +static INIT: Once = Once::new(); + +/// check-if-email-exists uses rustls for its TLS connections. This function +/// initializes the default crypto provider for rustls. +pub fn initialize_crypto_provider() { + INIT.call_once(|| { + ring::default_provider().install_default().unwrap(); + }); +} + /// Given an email's misc and smtp details, calculate an estimate of our /// confidence on how reachable the email is. /// @@ -120,6 +132,7 @@ fn calculate_reachable(misc: &MiscDetails, smtp: &Result /// Returns a `CheckEmailOutput` output, whose `is_reachable` field is one of /// `Safe`, `Invalid`, `Risky` or `Unknown`. pub async fn check_email(input: &CheckEmailInput) -> CheckEmailOutput { + initialize_crypto_provider(); let start_time = SystemTime::now(); let to_email = &input.to_email; @@ -273,6 +286,7 @@ pub async fn check_email(input: &CheckEmailInput) -> CheckEmailOutput { }, }; + #[cfg(feature = "sentry")] log_unknown_errors(&output, &input.backend_name); output diff --git a/core/src/smtp/yahoo/headless.rs b/core/src/smtp/yahoo/headless.rs index 3d7d4bb8e..fd7d028e9 100644 --- a/core/src/smtp/yahoo/headless.rs +++ b/core/src/smtp/yahoo/headless.rs @@ -31,12 +31,37 @@ use crate::{smtp::SmtpDetails, LOG_TARGET}; /// browser. Make sure you have a WebDriver server running locally before /// running this, or this will error. pub async fn check_headless(to_email: &str, webdriver: &str) -> Result { - tracing::debug!( - target: LOG_TARGET, - email=%to_email, - "Using Yahoo password recovery in headless navigator" - ); + let mut attempts = 0; + let max_attempts = 3; + let mut last_error = None; + + while attempts < max_attempts { + attempts += 1; + tracing::debug!( + target: LOG_TARGET, + email=%to_email, + attempt=%attempts, + "Using Yahoo password recovery in headless navigator" + ); + + match check_headless_inner(to_email, webdriver).await { + Ok(result) => return Ok(result), + Err(e) => { + last_error = Some(e); + if attempts < max_attempts { + sleep(Duration::from_secs(1)); + } + } + } + } + Err(last_error.unwrap()) +} + +async fn check_headless_inner( + to_email: &str, + webdriver: &str, +) -> Result { let c = create_headless_client(webdriver).await?; // Navigate to Microsoft password recovery page. @@ -107,6 +132,8 @@ pub async fn check_headless(to_email: &str, webdriver: &str) -> Result