diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e56399f..3e8866e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -3,28 +3,26 @@ name: Test on: [push] jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Setup Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - components: rustfmt, clippy - - name: Install wasm-pack - run: cargo install wasm-pack - - name: Download circom v2.1.9 (Linux) - run: wget https://github.com/iden3/circom/releases/download/v2.1.9/circom-linux-amd64 -O /usr/local/bin/circom && chmod +x /usr/local/bin/circom - - name: Install yarn - run: npm install -g yarn - - name: Install dependencies - run: yarn install --immutable - - name: Run tests - run: yarn test + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rustfmt, clippy + - name: Install wasm-pack + run: cargo install wasm-pack + - name: Download circom v2.1.9 (Linux) + run: wget https://github.com/iden3/circom/releases/download/v2.1.9/circom-linux-amd64 -O /usr/local/bin/circom && chmod +x /usr/local/bin/circom + - name: Install dependencies + run: bun install + - name: Run tests + run: bun test diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a7ab234 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": true, + "endOfLine": "lf", + "trailingComma": "none", + "bracketSpacing": true, + "arrowParens": "avoid" +} diff --git a/packages/apis/package.json b/packages/apis/package.json index 9526418..19ee320 100644 --- a/packages/apis/package.json +++ b/packages/apis/package.json @@ -1,26 +1,31 @@ { - "name": "@zk-email/zk-regex-apis", - "version": "2.2.0", - "description": "apis compatible with [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", - "contributors": [ - "Javier Su ", - "Kata Choi ", - "Sora Suegami ", - "Yush G ", - "Aditya Bisht " - ], - "repository": { - "type": "git", - "url": "git+https://github.com/zkemail/zk-regex.git" - }, - "scripts": { - "build": "wasm-pack build --target nodejs --out-dir ./pkg/", - "build-debug": "npm run build --", - "build-release": "npm run build --", - "install": "npm run build-debug", - "install-release": "npm run build-release", - "test": "cargo test && wasm-pack test --node", - "upload-binary": "wasm-pack publish -t nodejs" - }, - "license": "MIT" -} \ No newline at end of file + "name": "@zk-email/zk-regex-apis", + "version": "2.2.0", + "description": "apis compatible with [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", + "contributors": [ + "Javier Su ", + "Kata Choi ", + "Sora Suegami ", + "Yush G ", + "Aditya Bisht " + ], + "repository": { + "type": "git", + "url": "git+https://github.com/zkemail/zk-regex.git" + }, + "scripts": { + "build": "wasm-pack build --target nodejs --out-dir ./pkg/", + "build-debug": "npm run build --", + "build-release": "npm run build --", + "install": "npm run build-debug", + "install-release": "npm run build-release", + "test": "cargo test && wasm-pack test --node", + "test-js": "jest", + "upload-binary": "wasm-pack publish -t nodejs" + }, + "license": "MIT", + "devDependencies": { + "@types/jest": "^29.5.13", + "jest": "^29.7.0" + } +} diff --git a/packages/apis/src/extract_substrs.rs b/packages/apis/src/extract_substrs.rs index 18e1a92..b805f8c 100644 --- a/packages/apis/src/extract_substrs.rs +++ b/packages/apis/src/extract_substrs.rs @@ -22,9 +22,9 @@ pub struct RegexPartConfig { pub enum ExtractSubstrssError { // #[error("The max length is {} but the input length is {}",.0,.1)] // InvalidInputLen(usize, usize), - #[error("Substring of the entire regex {} is not found in {}",.0,.1)] - SubstringOfEntireNotFound(Regex, String), - #[error("Substring of {} is not found in {}",.0,.1)] + #[error("Substring of the entire regex {} is not found given input_str",.0)] + SubstringOfEntireNotFound(Regex), + #[error("Substring of {} is not found in given input_str",.0)] SubstringNotFound(Regex, String), #[error(transparent)] RegexError(#[from] fancy_regex::Error), @@ -33,6 +33,7 @@ pub enum ExtractSubstrssError { pub fn extract_substr_idxes( input_str: &str, regex_config: &DecomposedRegexConfig, + reveal_private: bool, ) -> Result, ExtractSubstrssError> { // Construct the full regex pattern with groups for each part let mut entire_regex_str = String::new(); @@ -47,24 +48,14 @@ pub fn extract_substr_idxes( // Find the match for the entire regex let entire_captures = entire_regex .captures(input_str) - .map_err(|_| { - ExtractSubstrssError::SubstringOfEntireNotFound( - entire_regex.clone(), - input_str.to_string(), - ) - })? - .ok_or_else(|| { - ExtractSubstrssError::SubstringOfEntireNotFound( - entire_regex.clone(), - input_str.to_string(), - ) - })?; + .map_err(|_| ExtractSubstrssError::SubstringOfEntireNotFound(entire_regex.clone()))? + .ok_or_else(|| ExtractSubstrssError::SubstringOfEntireNotFound(entire_regex.clone()))?; let mut public_idxes = vec![]; // Iterate over each part to extract the relevant indices for (i, part) in regex_config.parts.iter().enumerate() { - if part.is_public { + if part.is_public || reveal_private { if let Some(matched) = entire_captures.get(i + 1) { // Capture group indices are 1-based public_idxes.push((matched.start(), matched.end())); @@ -75,18 +66,41 @@ pub fn extract_substr_idxes( Ok(public_idxes) } +pub fn extract_substr( + input_str: &str, + regex_config: &DecomposedRegexConfig, + reveal_private: bool, +) -> Result, ExtractSubstrssError> { + let substr_idxes = extract_substr_idxes(input_str, regex_config, reveal_private)?; + + let result: Vec = substr_idxes + .iter() + .map(|&(start, end)| input_str[start..end].to_string()) + .collect(); + + Ok(result) +} + pub fn extract_email_addr_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/email_addr.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_email_domain_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/email_domain.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } // pub fn extract_email_addr_with_name_idxes( @@ -100,52 +114,84 @@ pub fn extract_from_all_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/from_all.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_from_addr_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/from_addr.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_to_all_idxes(input_str: &str) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/to_all.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_to_addr_idxes(input_str: &str) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/to_addr.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_subject_all_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/subject_all.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_body_hash_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/body_hash.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_timestamp_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/timestamp.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } pub fn extract_message_id_idxes( input_str: &str, ) -> Result, ExtractSubstrssError> { let regex_config = include_str!("./decomposed_defs/message_id.json"); - extract_substr_idxes(input_str, &serde_json::from_str(regex_config).unwrap()) + extract_substr_idxes( + input_str, + &serde_json::from_str(regex_config).unwrap(), + false, + ) } #[cfg(test)] @@ -215,7 +261,7 @@ mod test { ], }; let input_str = "sepolia+ACCOUNTKEY.0xabc123@sendeth.org"; - let idxes = extract_substr_idxes(input_str, &code_regex).unwrap(); + let idxes = extract_substr_idxes(input_str, &code_regex, false).unwrap(); assert_eq!(idxes, vec![(21, 27)]); } @@ -260,7 +306,7 @@ mod test { ], }; let input_str = "azb"; - let idxes = extract_substr_idxes(input_str, &code_regex).unwrap(); + let idxes = extract_substr_idxes(input_str, &code_regex, false).unwrap(); assert_eq!(idxes, vec![(1, 2)]); } @@ -279,7 +325,65 @@ mod test { ], }; let input_str = "b"; - let idxes = extract_substr_idxes(input_str, &code_regex).unwrap(); + let idxes = extract_substr_idxes(input_str, &code_regex, false).unwrap(); assert_eq!(idxes, vec![(0, 0)]); } + + #[test] + fn extract_str_hide_private() { + let code_regex = DecomposedRegexConfig { + parts: vec![ + RegexPartConfig { + is_public: true, + regex_def: "Hello ".to_string(), + }, + RegexPartConfig { + is_public: false, + regex_def: "guys!".to_string(), + }, + ], + }; + let input_str = "some email: Hello guys! Best, ZK Email"; + let strs = extract_substr(input_str, &code_regex, false).unwrap(); + assert_eq!(strs, vec!["Hello ".to_string()]); + } + + #[test] + fn extract_str_show_private() { + let code_regex = DecomposedRegexConfig { + parts: vec![ + RegexPartConfig { + is_public: true, + regex_def: "Hello ".to_string(), + }, + RegexPartConfig { + is_public: false, + regex_def: "guys!".to_string(), + }, + ], + }; + let input_str = "some email: Hello guys! Best, ZK Email"; + let strs = extract_substr(input_str, &code_regex, true).unwrap(); + assert_eq!(strs, vec!["Hello ".to_string(), "guys!".to_string()]); + } + + #[test] + fn extract_str_empty_vec_all_private() { + let code_regex = DecomposedRegexConfig { + parts: vec![ + RegexPartConfig { + is_public: false, + regex_def: "Hello ".to_string(), + }, + RegexPartConfig { + is_public: false, + regex_def: "guys!".to_string(), + }, + ], + }; + let input_str = "some email: Hello guys! Best, ZK Email"; + let strs = extract_substr(input_str, &code_regex, false).unwrap(); + let empty_vec: Vec = Vec::new(); + assert_eq!(strs, empty_vec); + } } diff --git a/packages/apis/src/wasm.rs b/packages/apis/src/wasm.rs index 9e5b0ff..1fceda6 100644 --- a/packages/apis/src/wasm.rs +++ b/packages/apis/src/wasm.rs @@ -1,6 +1,7 @@ use crate::extract_substrs::*; use crate::*; use js_sys::Array; +use serde_json::Value; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -18,33 +19,67 @@ pub fn padString(str: &str, paddedBytesSize: usize) -> Array { #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractSubstrIdxes(inputStr: &str, regexConfig: JsValue) -> Array { - let regex_config_str = regexConfig.as_string().unwrap(); - let regex_config: DecomposedRegexConfig = serde_json::from_str(®ex_config_str).unwrap(); - let public_idxes = extract_substrs::extract_substr_idxes(inputStr, ®ex_config).unwrap(); - let arr = Array::new_with_length(public_idxes.len() as u32); - for (i, idx) in public_idxes.iter().enumerate() { +pub fn extractSubstrIdxes( + inputStr: &str, + regexConfig: JsValue, + reveal_private: bool, +) -> Result { + let regex_config = parse_js_regex_config(regexConfig)?; + + let idxes = extract_substrs::extract_substr_idxes(inputStr, ®ex_config, reveal_private) + .map_err(|e| { + println!("e: {:?}", e); + let error_msg = format!("Failed to extract indxes: {}", e); + JsValue::from_str(&error_msg) + })?; + + let arr = Array::new_with_length(idxes.len() as u32); + for (i, idx) in idxes.iter().enumerate() { let js_arr = Array::new_with_length(2); js_arr.set(0, JsValue::from(idx.0 as u32)); js_arr.set(1, JsValue::from(idx.1 as u32)); arr.set(i as u32, JsValue::from(js_arr)); } - arr + Ok(arr) +} + +#[wasm_bindgen] +#[allow(non_snake_case)] +pub fn extractSubstr( + inputStr: &str, + regexConfig: JsValue, + reveal_private: bool, +) -> Result { + let regex_config = parse_js_regex_config(regexConfig)?; + + let result_strs = extract_substrs::extract_substr(inputStr, ®ex_config, reveal_private) + .map_err(|e| { + println!("e: {:?}", e); + let error_msg = format!("Failed to extract strings: {}", e); + JsValue::from_str(&error_msg) + })?; + + let js_array = Array::new_with_length(result_strs.len() as u32); + for (i, s) in result_strs.into_iter().enumerate() { + js_array.set(i as u32, JsValue::from_str(&s)); + } + + Ok(js_array) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractEmailAddrIdxes(inputStr: &str) -> Array { +pub fn extractEmailAddrIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/email_addr.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractEmailDomainIdxes(inputStr: &str) -> Array { +pub fn extractEmailDomainIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/email_domain.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } // #[wasm_bindgen] @@ -56,56 +91,87 @@ pub fn extractEmailDomainIdxes(inputStr: &str) -> Array { #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractFromAllIdxes(inputStr: &str) -> Array { +pub fn extractFromAllIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/from_all.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractFromAddrIdxes(inputStr: &str) -> Array { +pub fn extractFromAddrIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/from_addr.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractToAllIdxes(inputStr: &str) -> Array { +pub fn extractToAllIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/to_all.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractToAddrIdxes(inputStr: &str) -> Array { +pub fn extractToAddrIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/to_addr.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractSubjectAllIdxes(inputStr: &str) -> Array { +pub fn extractSubjectAllIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/subject_all.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractBodyHashIdxes(inputStr: &str) -> Array { +pub fn extractBodyHashIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/body_hash.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractTimestampIdxes(inputStr: &str) -> Array { +pub fn extractTimestampIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/timestamp.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) } #[wasm_bindgen] #[allow(non_snake_case)] -pub fn extractMessageIdIdxes(inputStr: &str) -> Array { +pub fn extractMessageIdIdxes(inputStr: &str) -> Result { let regex_config = include_str!("./decomposed_defs/message_id.json"); - extractSubstrIdxes(inputStr, JsValue::from_str(regex_config)) + extractSubstrIdxes(inputStr, JsValue::from_str(regex_config), false) +} + +// Accepts regexConfig either as string or js object +fn parse_js_regex_config(regex_config: JsValue) -> Result { + // Checks if regexConfig is passed as string or object + // As string + let parsed_config: DecomposedRegexConfig = if regex_config.is_string() { + let config_str = regex_config.as_string().unwrap(); + serde_json::from_str(&config_str).map_err(|e| { + let error_msg = format!("Failed to parse JSON string: {}", e); + JsValue::from_str(&error_msg) + })? + // As object + } else { + serde_wasm_bindgen::from_value(regex_config).map_err(|e| { + let error_msg = simplify_error(&e); + JsValue::from_str(&error_msg) + })? + }; + + Ok(parsed_config) +} + +fn simplify_error(e: &serde_wasm_bindgen::Error) -> String { + let error_string = e.to_string(); + if let Some(json_error) = serde_json::from_str::(&error_string).ok() { + if let Some(message) = json_error["message"].as_str() { + return message.to_string(); + } + } + error_string } diff --git a/packages/apis/tests/airbnb_eml.ts b/packages/apis/tests/airbnb_eml.ts new file mode 100644 index 0000000..64e68bd --- /dev/null +++ b/packages/apis/tests/airbnb_eml.ts @@ -0,0 +1,1146 @@ +export default `Delivered-To: dimitridumonet@gmail.com +Received: by 2002:a0c:fecd:0:b0:6c3:6081:347f with SMTP id z13csp81193qvs; + Thu, 10 Oct 2024 16:19:45 -0700 (PDT) +X-Google-Smtp-Source: AGHT+IEd0XrzNnTswxWNTmEZgIArn+BlrkDF1vp1CyMewhYGmJAj19KVofiC8WRBHgTjYX7aQ6Cc +X-Received: by 2002:a05:6214:3b86:b0:6cb:e662:c59a with SMTP id 6a1803df08f44-6cbeff36cf0mr10369186d6.11.1728602385043; + Thu, 10 Oct 2024 16:19:45 -0700 (PDT) +ARC-Seal: i=1; a=rsa-sha256; t=1728602385; cv=none; + d=google.com; s=arc-20240605; + b=E0qFuaOfdPQc+Ld1vLPYWAZYD+jbI5AzUeQ/wL7UcJv1SSr0Pl4Ku+LBuzDOG+Gai+ + Pfn9ZHwXjMEFk/nZJw9RiXP3/c8y+0oi5dx4ojupMriS3WzsGB3r/T5+tLz7HDiMP8Zk + f7zRkqEeCIY0OUJU/QMfxAdRmCUmE9TsqnKJ7e+Pf4Y1sIHwo0eoEGz0afHsizoaPOTJ + KtUB0VYLLC/JmaPnpUZcD/biZRQgCsaL0XPLBvIK/URHnZniPM/hgB/9nQ24lJVX9/ZP + tRT8yxnlmHDcfiauoSzVmBwC9Gh6+JFXoNC0mOkK1t7/RhPlSpPVj1RzhJHEwH+JPTn4 + EkvQ== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; + h=to:priority:importance:bimi-selector:reply-to:subject:message-id + :mime-version:from:date:dkim-signature:dkim-signature; + bh=qRjFxOyp02fNtl8fsqa9P9TfXf+KOCimKHiS6d8XZa8=; + fh=wfDbold4LZmvpOGNo2jQk0a98jfSD+kr9vmhclYezSA=; + b=ghyFgwCF/FyqVXrbUiiuPSa3Zu4yHwcLH6VIB/duhMOfiI3VTyV4QIduL41MfNnbg+ + gMe5x1JrkHdevne5zP1JRtR6cUPiyW2Rah6tXNsmxRPOJr2oqgq3SAorXRkLTX3VRoe9 + wv51uWUNGaVmfSS6mLmtmADlISwaV8Q47cusyUOnowVtvcAO3BtNnfMNUsR/eblplWiH + VkuRbS61kqnnh8jL8Xj4LUj4lYvfhUPvwY6gGv2MET6OZu5+mdsr69RJ42mOIezZuDqy + ZntooVCjbBCmRMKC3GzYq/tCJGtA5/EtGnd3PdZI+A0P/Z+WnTpH+HZZmgy0+XG/U38m + GeWw==; + dara=google.com +ARC-Authentication-Results: i=1; mx.google.com; + dkim=pass header.i=@email.airbnb.com header.s=s20150428 header.b=i5GLT4zT; + dkim=pass header.i=@sendgrid.info header.s=smtpapi header.b=D3G4ED+y; + spf=pass (google.com: domain of bounces+168748-181c-dimitridumonet=gmail.com@email.airbnb.com designates 50.31.32.157 as permitted sender) smtp.mailfrom="bounces+168748-181c-dimitridumonet=gmail.com@email.airbnb.com"; + dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=airbnb.com +Return-Path: +Received: from o11.email.airbnb.com (o11.email.airbnb.com. [50.31.32.157]) + by mx.google.com with ESMTPS id 6a1803df08f44-6cbe85e049asi24990216d6.161.2024.10.10.16.19.44 + for + (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); + Thu, 10 Oct 2024 16:19:45 -0700 (PDT) +Received-SPF: pass (google.com: domain of bounces+168748-181c-dimitridumonet=gmail.com@email.airbnb.com designates 50.31.32.157 as permitted sender) client-ip=50.31.32.157; +Authentication-Results: mx.google.com; + dkim=pass header.i=@email.airbnb.com header.s=s20150428 header.b=i5GLT4zT; + dkim=pass header.i=@sendgrid.info header.s=smtpapi header.b=D3G4ED+y; + spf=pass (google.com: domain of bounces+168748-181c-dimitridumonet=gmail.com@email.airbnb.com designates 50.31.32.157 as permitted sender) smtp.mailfrom="bounces+168748-181c-dimitridumonet=gmail.com@email.airbnb.com"; + dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=airbnb.com +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=email.airbnb.com; + h=content-type:from:mime-version:subject:reply-to:x-feedback-id:to:cc: + content-type:from:subject:to; + s=s20150428; bh=qRjFxOyp02fNtl8fsqa9P9TfXf+KOCimKHiS6d8XZa8=; + b=i5GLT4zTtTTSt901iUHFaQ9de9Ai4d01FdDK4MVZ3NsL7h8mN7IBr2iIpmv6AM0Q2Cok + 3hGxRysyIAF7fQ3qR1/drVCuzh0v5AQPu2tf3hbPv/+BCHLiD4sVt9iPY3FBbo/UnFNEqz + 0UjR4IfLboxLkdHv5/cSmEovnKoj0RX5k= +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sendgrid.info; + h=content-type:from:mime-version:subject:reply-to:x-feedback-id:to:cc: + content-type:from:subject:to; + s=smtpapi; bh=qRjFxOyp02fNtl8fsqa9P9TfXf+KOCimKHiS6d8XZa8=; + b=D3G4ED+yMdDJd90YTuhqvFdCDTfCU/cjAxBmB2MdDA9YquweURwttkoHraS02sYUznUK + pg15OmQzP4WbAB2PRJAtSNF28FrZJOxs68ss7tEVAcF9YqHaYj6F5j/sMCZunhnr1aBJfY + MMr8i8FPie9OlpKFcCG4y4VX0DtjHzBQ8= +Received: by recvd-fdb77b5cb-l2cqh with SMTP id recvd-fdb77b5cb-l2cqh-1-67086110-34 + 2024-10-10 23:19:44.63636295 +0000 UTC m=+2438527.951122372 +Received: from MTY4NzQ4 (unknown) + by geopod-ismtpd-20 (SG) with HTTP + id ozjDOM3PS6WltaTtjuJFaA + Thu, 10 Oct 2024 23:19:44.626 +0000 (UTC) +Content-Type: multipart/alternative; boundary=49a8ec9b277e6a96e7373b3e4727df74d25ab6158dd0a8fb1221118a1304 +Date: Thu, 10 Oct 2024 23:19:44 +0000 (UTC) +From: Airbnb +Mime-Version: 1.0 +Message-ID: +Subject: RE: Reservation at Luxurious 5B/3BA home Nob Hill! for 22 September + 2024 - 22 October 2024 +Reply-To: "Isabella (Airbnb)" + <4of5lutm2rzokajdtd2j25ek6whsg045r01d@reply.airbnb.com> +X-Priority: 1 +X-Category: message +X-Strategy: push_and_email_and_web_push +X-rpcampaign: airbnb20241010152328760092722452715530303223890373903 +X-Locale: en-GB +X-Message-Package-UUID: 7e892d74-33f4-ebf8-ef9a-cba7f9c2c579 +BIMI-Selector: v=BIMI1; s=belov2; +X-User-ID: 467606067 +X-MSMail-Priority: High +Return-Path: express@airbnb.com +Importance: high +Priority: Urgent +X-Template: homes_messaging/new_message +X-Feedback-ID: 168748:SG +X-SG-EID: + =?us-ascii?Q?u001=2E373TPjtMqGbzwgRnUiLO4aQplIiW+Q7azdMrDCU1iICBGcf7GI8fS8Yas?= + =?us-ascii?Q?=2FrvZ5srvc=2FUg+Y3QtuuZu8t9IoQj8U67X=2Ftferm?= + =?us-ascii?Q?GqR0cRkWsdIQdo0l4Ezae3j01oY06yQrm91GBfs?= + =?us-ascii?Q?5cx=2FNZOz3bvJt7R7OpkA=2FGLSMdeFwqzm9dhpSx8?= + =?us-ascii?Q?YqLodw=2FoFKqS178kFLThUhL1OMuR7EJqMudXl81?= + =?us-ascii?Q?Z1ab7TzKTs=2F1Ok7Pkf8CSI=3D?= +X-SG-ID: + =?us-ascii?Q?u001=2ESdBcvi+Evd=2FbQef8eZF3BqZ9cHLZlaQH8LGBOs0K2+F024wgXfxgfZf8o?= + =?us-ascii?Q?wozgZzIDr0SWjqkz0Hzl15He+3JiV4qiZ3NftmN?= + =?us-ascii?Q?AQKXfQpNpidNvJalNic6JYjllxfNAmK52O3GlhD?= + =?us-ascii?Q?FOjjI2YBmc2SQ5GYtyJGmycybZOQvvNcazI85yt?= + =?us-ascii?Q?mPQq+Hz8fniF9EjPeVlfxQ0CoVMew0o+IUL9q46?= + =?us-ascii?Q?+hi7Q+9jQAOPMZV=2FIZ4e3JazWnV58Av2FlUBtP0?= + =?us-ascii?Q?yA=2F5kfOMtemfJB+3OWwPtttyQF8gCtEFp3cmd6m?= + =?us-ascii?Q?39i+4FRprLKQypcH6HFCAg0WHbhyiK=2Fa+8ZWE5i?= + =?us-ascii?Q?OTyPI3ajl5gFGwtrbgYnMTHOAERzqQMstiK3=2F=2F0?= + =?us-ascii?Q?EpJEOMxvs8rkjoxbWnvEWjQMiJSyk+=2F2q6FDbow?= + =?us-ascii?Q?s=2FGRpDmfjJeaiTN0jI8QLdDkHCWdfuPY5jnt8Xv?= + =?us-ascii?Q?pX8cfwsbZpmoZflQ8PrIjcd=2FkxK7Gf4e5krU4Md?= + =?us-ascii?Q?nzRx3=2FxRRYLEzocKrzMv=2FP1hpAC+RN7GKeKaosl?= + =?us-ascii?Q?PD7zzN0jSqkzXnN1CKlcNYEygz0tPE=3D?= +To: dimitridumonet@gmail.com +X-Entity-ID: u001.xNm+654l4yZx3FKLl1hq6g== + +--49a8ec9b277e6a96e7373b3e4727df74d25ab6158dd0a8fb1221118a1304 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/plain; charset=iso-8859-1 +Mime-Version: 1.0 + +%opentrack% + +https://www.airbnb.co.uk/?c=3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL25ld19tZXNzYWdl&= +euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579 + +RE: RESERVATION AT LUXURIOUS 5B/3BA HOME NOB HILL! FOR 22 +SEPTEMBER 2024 - 22 OCTOBER 2024 + +For your protection and safety, always communicate through +Airbnb +[https://www.airbnb.co.uk/help/article/209?c=3D.pi80.pkaG9tZXNfbWVzc2FnaW5n= +L25ld19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579]. + + Isabella + =20 + Hello guys! I need to let you know that the owner has + scheduled a FaceTime tour with a long term group this + Saturday at 1:30pm. + I apologize for the inconvenience and + Thank you for the cooperation. + +Reply +[https://www.airbnb.co.uk/messaging/thread/1919382305?thread_type=3Dhome_bo= +oking&c=3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL25ld19tZXNzYWdl&euid=3D7e892d74-33f4= +-ebf8-ef9a-cba7f9c2c579] + +Respond to Isabella by replying directly to this email. + +https://www.airbnb.co.uk/rooms/1193537369002070065?c=3D.pi80.pkaG9tZXNfbWVz= +c2FnaW5nL25ld19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579 + +RESERVATION DETAILS + +Luxurious 5B/3BA home Nob Hill! + +Rental unit - Entire home/flat hosted by Isabella + +GUESTS + +10 guests + + CHECK-IN CHECKOUT + =20 +Sunday Tuesday + =20 +22 September 2024 22 October 2024 + + https://www.airbnb.co.uk/external_link?c=3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL= +25ld19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579&url=3Dhttps%3A%= +2F%2Fwww.facebook.com%2Fairbnb https://www.airbnb.co.uk/external_link?c= +=3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL25ld19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-e= +f9a-cba7f9c2c579&url=3Dhttps%3A%2F%2Fwww.instagram.com%2Fairbnb https://w= +ww.airbnb.co.uk/external_link?c=3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL25ld19tZXNzY= +Wdl&euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579&url=3Dhttps%3A%2F%2Ftwitter= +.com%2FAirbnb + +Airbnb Ireland UC + +8 Hanover Quay + +Dublin 2, Ireland + +Get the Airbnb app + +https://www.airbnb.co.uk/external_link?c=3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL25l= +d19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579&url=3Dhttps%3A%2F%= +2Fairbnb.sng.link%2FA6f9up%2Fdvs6%3F_smtype%3D3%26pcid%3D.pi80.pkaG9tZXNfbW= +Vzc2FnaW5nL25ld19tZXNzYWdl https://www.airbnb.co.uk/external_link?c=3D.pi= +80.pkaG9tZXNfbWVzc2FnaW5nL25ld19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-ef9a-cb= +a7f9c2c579&url=3Dhttps%3A%2F%2Fairbnb.sng.link%2FA6f9up%2Fqh0lc%3Fid%3Dcom.= +airbnb.android%26pcid%3D.pi80.pkaG9tZXNfbWVzc2FnaW5nL25ld19tZXNzYWdl =20 + +Update your email preferences +[https://www.airbnb.co.uk/account-settings/notifications?c=3D.pi80.pkaG9tZX= +NfbWVzc2FnaW5nL25ld19tZXNzYWdl&euid=3D7e892d74-33f4-ebf8-ef9a-cba7f9c2c579] +to choose which emails you get or unsubscribe +[https://www.airbnb.co.uk/account-settings/email-unsubscribe?email_type=3Df= +alse&mac=3DQJmdxe1CU5PXPvaEGjcsQ6TT5b4%3D&token=] +from this type of email. + +=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 +--49a8ec9b277e6a96e7373b3e4727df74d25ab6158dd0a8fb1221118a1304 +Content-Transfer-Encoding: quoted-printable +Content-Type: text/html; charset=iso-8859-1 +Mime-Version: 1.0 + +
3D""
<= +/tbody>
3D"Airbnb"

RE: Reservation at Luxurious 5B/3BA home Nob Hill! for 22 September= + 2024 - 22 October 2024

For= + your protection and safety, always communicate through Airbnb.

= +
3D"Isabella"

Isabella= +

= +

Hello guys! I need to let you know that the owner has scheduled a FaceT= +ime tour with a long term group this Saturday at 1:30pm.
I apologize for= + the inconvenience and
Thank you for the cooperation.

= +
<= +tr class=3D"_16pg94n" style=3D"margin: 0px !important;">
= +

Respond to Isabella by replying di= +rectly to this email.

Reservation details

<= +/div>

Luxurious 5B/3BA home Nob Hill!

= +

Rental unit - Entire home/flat hosted by Isabella

= +

Guests

10 guests

Check-In

Sunday

22 September 2024

Tuesday

Checkout

22 = +October 2024

= +<= +/tbody>
3D"Airbnb"3D"Twitter"<= +/td>
3D"Facebook"
<= +/tr>
<= +td class>

Airbnb Ireland UC

8 Hanover Quay

= +Dublin 2, Ireland

Get the Air= +bnb app

= +
= +3D"App3D"Google
= +

Update your email preferences to choose which emails you get= + or unsubscribe from this type of email.

= +
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = +=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 +--49a8ec9b277e6a96e7373b3e4727df74d25ab6158dd0a8fb1221118a1304-- +`; diff --git a/packages/apis/tests/extract_substr.test.ts b/packages/apis/tests/extract_substr.test.ts new file mode 100644 index 0000000..028d1e1 --- /dev/null +++ b/packages/apis/tests/extract_substr.test.ts @@ -0,0 +1,180 @@ +import init, { extractSubstrIdxes, extractSubstr } from '../pkg/zk_regex_apis'; +import airbnbEml from './airbnb_eml'; + +console.time('wasm init'); +init() + .then(() => { + console.timeEnd('wasm init'); + }) + .catch(console.error); + +describe('Extract substr test suite', async () => { + // Wait for wasm to init + await new Promise(r => setTimeout(r, 300)); + + test('Should extract indicies from object input', () => { + const parts = { + parts: [ + { + is_public: true, + regex_def: 'Hello' + } + ] + }; + const result = extractSubstrIdxes(airbnbEml, parts, false); + expect(result.length).toBe(1); + expect(result[0].length).toBe(2); + }); + + test('Should extract indicies from object input, hide private', () => { + const parts = { + parts: [ + { + is_public: true, + regex_def: 'Hello ' + }, + { + is_public: false, + regex_def: 'guys!' + } + ] + }; + const result = extractSubstrIdxes(airbnbEml, parts, false); + expect(result.length).toBe(1); + expect(result[0].length).toBe(2); + }); + + test('Should extract indicies from object input, reveal private', () => { + const parts = { + parts: [ + { + is_public: true, + regex_def: 'Hello ' + }, + { + is_public: false, + regex_def: 'guys!' + } + ] + }; + const result = extractSubstrIdxes(airbnbEml, parts, true); + expect(result.length).toBe(2); + expect(result[0].length).toBe(2); + expect(result[1].length).toBe(2); + }); + + test('Should extract indicies from stringified input', () => { + const parts = { + parts: [ + { + is_public: false, + regex_def: 'Hello' + } + ] + }; + const result = extractSubstrIdxes( + airbnbEml, + JSON.stringify(parts), + true + ); + expect(result.length).toBe(1); + expect(result[0].length).toBe(2); + }); + + test('Should throw helpful js error on wrong object input', () => { + const parts = { + wrong: 'input' + }; + try { + extractSubstrIdxes(airbnbEml, parts, false); + } catch (err) { + expect(err).toBe('Error: missing field `parts`'); + return; + } + throw new Error('Did not catch wrong input'); + }); + + test('Should throw helpful js error on wrong stringified input', () => { + const parts = { + wrong: 'input' + }; + try { + extractSubstrIdxes(airbnbEml, JSON.stringify(parts), false); + } catch (err) { + const includesErr = err.includes( + 'Failed to parse JSON string: missing field `parts`' + ); + expect(includesErr).toBe(true); + return; + } + throw new Error('Did not catch wrong input'); + }); + + test('Should throw helpful js error on wrong object input 2', () => { + const parts = { + parts: [ + { + is_public: false + } + ] + }; + try { + extractSubstrIdxes(airbnbEml, parts, false); + } catch (err) { + expect(err).toBe('Error: missing field `regex_def`'); + return; + } + throw new Error('Did not catch wrong input'); + }); + + test('Should throw helpful js error on no found result', () => { + const parts = { + parts: [ + { + is_public: true, + regex_def: 'Hello' + }, + { + is_public: false, + regex_def: 'yall!' + } + ] + }; + try { + extractSubstrIdxes(airbnbEml, parts, false); + } catch (err) { + const includes = err.includes( + 'Failed to extract indxes: Substring of the entire regex (Hello)(yall!) is not found given input_str' + ); + expect(includes).toBe(true); + return; + } + throw new Error('Did not throw an error'); + }); + + test('extractSubstr should return actual matched string', () => { + const parts = { + parts: [ + { + is_public: true, + regex_def: 'Hello' + } + ] + }; + const strs = extractSubstr(airbnbEml, parts, false); + expect(strs[0]).toBe('Hello'); + }); + + test('extractSubstr should return an empty array on all private fields', () => { + const parts = { + parts: [ + { + is_public: false, + regex_def: 'Hello' + } + ] + }; + const strs = extractSubstr(airbnbEml, parts, false); + expect(strs.length).toBe(0); + }); +}); diff --git a/packages/circom/package.json b/packages/circom/package.json index d9996b1..6aa364f 100644 --- a/packages/circom/package.json +++ b/packages/circom/package.json @@ -1,40 +1,40 @@ { - "name": "@zk-email/zk-regex-circom", - "version": "2.2.0", - "license": "MIT", - "description": "regex verification circuits in circom for common regexes, generated with the compiler in [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", - "contributors": [ - "Javier Su ", - "Kata Choi ", - "Sora Suegami ", - "Yush G ", - "Aditya Bisht " - ], - "scripts": { - "test": "jest", - "install": "echo", - "build": "echo", - "upload-binary": "echo" - }, - "dependencies": { - "commander": "^11.0.0", - "snarkjs": "^0.7.0" - }, - "devDependencies": { - "@types/jest": "^29.5.4", - "chai": "^4.3.7", - "circom_tester": "^0.0.20", - "circomlib": "^2.0.5", - "circomlibjs": "^0.1.2", - "ffjavascript": "^0.2.59", - "jest": "^29.5.0", - "mocha": "^10.2.0" - }, - "babel": { - "presets": [ - [ - "@babel/preset-env" - ] - ] - } -} \ No newline at end of file + "name": "@zk-email/zk-regex-circom", + "version": "2.2.0", + "license": "MIT", + "description": "regex verification circuits in circom for common regexes, generated with the compiler in [zk-regex](https://github.com/zkemail/zk-regex/tree/main).", + "contributors": [ + "Javier Su ", + "Kata Choi ", + "Sora Suegami ", + "Yush G ", + "Aditya Bisht " + ], + "scripts": { + "test": "jest tests/email_domain.test.js", + "install": "echo", + "build": "echo", + "upload-binary": "echo" + }, + "dependencies": { + "commander": "^11.0.0", + "snarkjs": "^0.7.0" + }, + "devDependencies": { + "@types/jest": "^29.5.4", + "chai": "^4.3.7", + "circom_tester": "^0.0.20", + "circomlib": "^2.0.5", + "circomlibjs": "^0.1.2", + "ffjavascript": "^0.2.59", + "jest": "^29.5.0", + "mocha": "^10.2.0" + }, + "babel": { + "presets": [ + [ + "@babel/preset-env" + ] + ] + } +}