diff --git a/src/circuit.rs b/src/circuit.rs index 1045f08..93f3d0e 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -25,6 +25,7 @@ struct EmailCircuitInput { timestamp_idx: usize, code_idx: usize, command_idx: usize, + cleaned_body: Option>, } #[derive(Serialize, Deserialize)] @@ -33,6 +34,7 @@ pub struct EmailCircuitParams { pub max_header_length: Option, pub max_body_length: Option, pub sha_precompute_selector: Option, + pub remove_soft_line_breaks: Option, } #[derive(Serialize, Deserialize)] @@ -92,6 +94,22 @@ impl CircuitInputParams { } } +fn remove_quoted_printable_soft_breaks(body: Vec) -> Vec { + let mut result = Vec::with_capacity(body.len()); + let mut iter = body.iter().enumerate(); + + while let Some((i, &byte)) = iter.next() { + if byte == b'=' && body.get(i + 1..i + 3) == Some(&[b'\r', b'\n']) { + iter.nth(1); // Skip the next two bytes + } else { + result.push(byte); + } + } + + result.resize(body.len(), 0); + result +} + fn generate_circuit_inputs(params: CircuitInputParams) -> CircuitInput { let (header_padded, header_padded_len) = sha256_pad(params.header.clone(), params.max_header_length); @@ -148,16 +166,30 @@ pub async fn generate_email_circuit_input( params .as_ref() .and_then(|p| p.sha_precompute_selector.clone()), - params.as_ref().and_then(|p| p.max_header_length), - params.as_ref().and_then(|p| p.max_body_length), - params.as_ref().and_then(|p| p.ignore_body_hash_check), + // params.as_ref().and_then(|p| p.max_header_length), + // params.as_ref().and_then(|p| p.max_body_length), + // params.as_ref().and_then(|p| p.ignore_body_hash_check) + Some(640), + Some(768), + Some(false), ); let email_circuit_inputs = generate_circuit_inputs(circuit_input_params); + let cleaned_body = match email_circuit_inputs.body_padded.clone() { + Some(body) => remove_quoted_printable_soft_breaks(body), + None => vec![], + }; + + let body_for_circuit = if true { + String::from_utf8(cleaned_body.clone()).unwrap_or_default() + } else { + parsed_email.canonicalized_body.clone() + }; + let from_addr_idx = parsed_email.get_from_addr_idxes()?.0; let domain_idx = parsed_email.get_email_domain_idxes()?.0; let subject_idx = parsed_email.get_subject_all_idxes()?.0; - let code_idx = match parsed_email.get_invitation_code_idxes() { + let code_idx = match parsed_email.get_invitation_code_idxes(&body_for_circuit) { Ok(indexes) => indexes.0, Err(_) => 0, }; @@ -165,7 +197,7 @@ pub async fn generate_email_circuit_input( Ok(indexes) => indexes.0, Err(_) => 0, }; - let command_idx = match parsed_email.get_command_idxes() { + let command_idx = match parsed_email.get_command_idxes(&body_for_circuit) { Ok(indexes) => indexes.0, Err(_) => 0, }; @@ -186,6 +218,7 @@ pub async fn generate_email_circuit_input( padded_body_len: email_circuit_inputs.body_len_padded_bytes, precomputed_sha: email_circuit_inputs.precomputed_sha, command_idx, + cleaned_body: Some(cleaned_body), }; Ok(serde_json::to_string(&email_auth_input)?) diff --git a/src/node/circuit.rs b/src/node/circuit.rs index e4220e2..cc3bbe1 100644 --- a/src/node/circuit.rs +++ b/src/node/circuit.rs @@ -52,11 +52,17 @@ pub(crate) fn generate_email_circuit_input_node(mut cx: FunctionContext) -> JsRe .ok() .and_then(|val: Handle| val.downcast::(&mut cx).ok()) .map(|js_boolean| js_boolean.value(&mut cx)); + let remove_soft_line_breaks = params + .get(&mut cx, "removeSoftLineBreaks") + .ok() + .and_then(|val: Handle| val.downcast::(&mut cx).ok()) + .map(|js_boolean| js_boolean.value(&mut cx)); EmailCircuitParams { sha_precompute_selector, max_header_length, max_body_length, ignore_body_hash_check, + remove_soft_line_breaks, } }); diff --git a/src/parse_email.rs b/src/parse_email.rs index 3333943..c6b5010 100644 --- a/src/parse_email.rs +++ b/src/parse_email.rs @@ -144,17 +144,17 @@ impl ParsedEmail { } /// Extracts the invitation code from the canonicalized email body. - pub fn get_invitation_code(&self) -> Result { + pub fn get_invitation_code(&self, body: &str) -> Result { let regex_config = serde_json::from_str(include_str!("../regexes/invitation_code.json"))?; - let idxes = extract_substr_idxes(&self.canonicalized_body, ®ex_config)?[0]; - let str = self.canonicalized_body[idxes.0..idxes.1].to_string(); + let idxes = extract_substr_idxes(body, ®ex_config)?[0]; + let str = body[idxes.0..idxes.1].to_string(); Ok(str) } /// Retrieves the index range of the invitation code within the canonicalized email body. - pub fn get_invitation_code_idxes(&self) -> Result<(usize, usize)> { + pub fn get_invitation_code_idxes(&self, body: &str) -> Result<(usize, usize)> { let regex_config = serde_json::from_str(include_str!("../regexes/invitation_code.json"))?; - let idxes = extract_substr_idxes(&self.canonicalized_body, ®ex_config)?[0]; + let idxes = extract_substr_idxes(body, ®ex_config)?[0]; Ok(idxes) } @@ -182,9 +182,9 @@ impl ParsedEmail { Ok(str) } - pub fn get_command_idxes(&self) -> Result<(usize, usize)> { + pub fn get_command_idxes(&self, body: &str) -> Result<(usize, usize)> { let regex_config = serde_json::from_str(include_str!("../regexes/command.json"))?; - let idxes = extract_substr_idxes(&self.canonicalized_body, ®ex_config)?[0]; + let idxes = extract_substr_idxes(body, ®ex_config)?[0]; Ok(idxes) } }