From fbd4d1d155598257804d24cb1e269c02f3ad0e31 Mon Sep 17 00:00:00 2001 From: Tushar Mathur Date: Sat, 23 Nov 2024 16:17:03 -0800 Subject: [PATCH] feat: add email source (#3141) --- Cargo.lock | 1 + tailcall-tracker/Cargo.toml | 1 + tailcall-tracker/src/dispatch.rs | 69 ++++++++++++++++---------------- tailcall-tracker/src/error.rs | 3 ++ 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5143e44519..b1a3482b1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5679,6 +5679,7 @@ dependencies = [ "lazy_static", "machineid-rs", "posthog-rs", + "regex", "reqwest 0.11.27", "serde", "serde_json", diff --git a/tailcall-tracker/Cargo.toml b/tailcall-tracker/Cargo.toml index 641c2ab0f3..7909648e81 100644 --- a/tailcall-tracker/Cargo.toml +++ b/tailcall-tracker/Cargo.toml @@ -27,3 +27,4 @@ whoami = "1.5.2" strum = "0.26.3" convert_case = { workspace = true } http = { workspace = true } +regex = "1.11.1" diff --git a/tailcall-tracker/src/dispatch.rs b/tailcall-tracker/src/dispatch.rs index 1a5e6ddcfa..09ab276c34 100644 --- a/tailcall-tracker/src/dispatch.rs +++ b/tailcall-tracker/src/dispatch.rs @@ -118,50 +118,39 @@ async fn email() -> HashSet { } // From Git - async fn git() -> Option { - let output = Command::new("git") + async fn git() -> Result { + Ok(Command::new("git") .args(["config", "--global", "user.email"]) .output() - .await - .ok()?; - - parse(output) + .await?) } // From SSH Keys - async fn ssh() -> Option> { - // Single command to find all unique email addresses from .pub files - let output = Command::new("sh") - .args([ - "-c", - "cat ~/.ssh/*.pub | grep -o '[^ ]\\+@[^ ]\\+\\.[^ ]\\+'", - ]) + async fn ssh() -> Result { + Ok(Command::new("sh") + .args(["-c", "cat ~/.ssh/*.pub"]) .output() - .await - .ok()?; - - Some(parse(output)?.lines().map(|o| o.to_owned()).collect()) + .await?) } - let git_email = git().await; - let ssh_emails = ssh().await; - let mut email_ids = HashSet::new(); - - if let Some(email) = git_email { - if !email.trim().is_empty() { - email_ids.insert(email.trim().to_string()); - } - } - - if let Some(emails) = ssh_emails { - for email in emails { - if !email.trim().is_empty() { - email_ids.insert(email.trim().to_string()); - } - } + // From defaults read MobileMeAccounts Accounts + async fn mobile_me() -> Result { + Ok(Command::new("defaults") + .args(["read", "MobileMeAccounts", "Accounts"]) + .output() + .await?) } - email_ids + vec![git().await, ssh().await, mobile_me().await] + .into_iter() + .flat_map(|output| { + output + .ok() + .and_then(parse) + .map(parse_email) + .unwrap_or_default() + }) + .collect::>() } // Generates a random client ID @@ -215,6 +204,18 @@ fn os_name() -> String { System::long_os_version().unwrap_or("Unknown".to_string()) } +// Should take arbitrary text and be able to extract email addresses +fn parse_email(text: String) -> Vec { + let mut email_ids = Vec::new(); + + let re = regex::Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").unwrap(); + for email in re.find_iter(&text) { + email_ids.push(email.as_str().to_string()); + } + + email_ids +} + #[cfg(test)] mod tests { diff --git a/tailcall-tracker/src/error.rs b/tailcall-tracker/src/error.rs index e9ba5f8e74..f6c2dbc214 100644 --- a/tailcall-tracker/src/error.rs +++ b/tailcall-tracker/src/error.rs @@ -20,6 +20,9 @@ pub enum Error { #[debug(fmt = "Tokio Join Error: {}", _0)] TokioJoin(tokio::task::JoinError), + + #[debug(fmt = "IO Error: {}", _0)] + IO(std::io::Error), } pub type Result = std::result::Result;