Skip to content

Commit

Permalink
feat: resolve dns from archive
Browse files Browse the repository at this point in the history
  • Loading branch information
Bisht13 committed Jan 6, 2025
1 parent cb50b38 commit df43ae9
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 45 deletions.
43 changes: 16 additions & 27 deletions src/cryptos.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
//! Cryptographic functions.
#[cfg(target_arch = "wasm32")]
use crate::EmailHeaders;
use crate::{field_to_hex, hex_to_field};
use anyhow::Result;
use ethers::types::Bytes;
use halo2curves::ff::Field;
use poseidon_rs::{poseidon_bytes, poseidon_fields, Fr, PoseidonError};
use rand_core::RngCore;
#[cfg(target_arch = "wasm32")]
use regex::Regex;
#[cfg(target_arch = "wasm32")]
use rsa::pkcs8::DecodePublicKey;
#[cfg(target_arch = "wasm32")]
use rsa::traits::PublicKeyParts;
use serde::{
de::{self, Visitor},
Expand Down Expand Up @@ -622,7 +618,6 @@ pub fn calculate_account_salt(email_addr: &str, account_code: &str) -> String {
field_to_hex(&account_salt.0)
}

#[cfg(target_arch = "wasm32")]
/// Fetches the public key from DNS records using the DKIM signature in the email headers.
///
/// # Arguments
Expand Down Expand Up @@ -655,45 +650,39 @@ pub async fn fetch_public_key(email_headers: EmailHeaders) -> Result<Vec<u8>> {
}
}

println!("Selector: {}, Domain: {}", selector, domain);

// Fetch the DNS TXT record for the domain key
let response = reqwest::get(format!(
"https://dns.google/resolve?name={}._domainkey.{}&type=TXT",
selector, domain
"https://archive.zk.email/api/key?domain={}&selector={}",
domain, selector
))
.await?;
let data: serde_json::Value = response.json().await?;

// Extract the 'p' value from the Answer section
let mut p_value = None;
if let Some(answers) = data.get("Answer").and_then(|a| a.as_array()) {
for answer in answers {
if let Some(data) = answer.get("data").and_then(|d| d.as_str()) {
let parts: Vec<&str> = data.split(';').collect();
for part in parts {
let key_value: Vec<&str> = part.trim().split('=').collect();
if key_value.len() == 2 && key_value[0].trim() == "p" {
p_value = Some(key_value[1].trim().to_string());
break;
}
}
}
}
}
// Extract the 'p' value from the first record
let p_value = data
.as_array()
.and_then(|arr| arr.first())
.and_then(|record| record.get("value"))
.and_then(|value| value.as_str())
.and_then(|data| {
data.split(';')
.find(|part| part.trim().starts_with("p="))
.map(|part| part.trim()[2..].to_string())
});

if let Some(public_key_b64) = p_value {
// Decode the base64 string to get the public key bytes
let public_key_bytes = base64::decode(public_key_b64)?;

// Load the public key from DER format
let public_key = rsa::RsaPublicKey::from_public_key_der(&public_key_bytes)?;
let public_key: rsa::RsaPublicKey =
rsa::RsaPublicKey::from_public_key_der(&public_key_bytes)?;

// Extract the modulus from the public key
let modulus = public_key.n();

// Convert the modulus to a byte array in big-endian order
let modulus_bytes = modulus.to_bytes_be();
let modulus_bytes: Vec<u8> = modulus.to_bytes_be();

Ok(modulus_bytes)
} else {
Expand Down
19 changes: 1 addition & 18 deletions src/parse_email.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@
use std::collections::HashMap;

#[cfg(target_arch = "wasm32")]
use crate::cryptos::fetch_public_key;
use anyhow::{anyhow, Result};
use anyhow::Result;
use cfdkim::canonicalize_signed_email;
#[cfg(not(target_arch = "wasm32"))]
use cfdkim::resolve_public_key;
use hex;
use itertools::Itertools;
use mailparse::{parse_mail, ParsedMail};
#[cfg(target_arch = "wasm32")]
use regex::Regex;
use rsa::traits::PublicKeyParts;
use serde::{Deserialize, Serialize};
use zk_regex_apis::extract_substrs::{
extract_body_hash_idxes, extract_email_addr_idxes, extract_email_domain_idxes,
Expand Down Expand Up @@ -53,21 +47,10 @@ impl ParsedEmail {
///
/// A `Result` which is either a `ParsedEmail` instance or an error if parsing fails.
pub async fn new_from_raw_email(raw_email: &str) -> Result<Self> {
// Initialize a logger for the function scope.
let logger = slog::Logger::root(slog::Discard, slog::o!());

// Extract all headers
let parsed_mail = parse_mail(raw_email.as_bytes())?;
let headers: EmailHeaders = EmailHeaders::new_from_mail(&parsed_mail);

// Resolve the public key from the raw email bytes.
#[cfg(not(target_arch = "wasm32"))]
let public_key = match resolve_public_key(&logger, raw_email.as_bytes()).await? {
cfdkim::DkimPublicKey::Rsa(pk) => Ok(pk.n().to_bytes_be()),
_ => Err(anyhow!("Unsupported public key type.")),
}?;

#[cfg(target_arch = "wasm32")]
let public_key = fetch_public_key(headers.clone()).await?;

// Canonicalize the signed email to separate the header, body, and signature.
Expand Down

0 comments on commit df43ae9

Please sign in to comment.