From 4fb87c85771bd7bf89e7c8d5e2d18bd743f35ef0 Mon Sep 17 00:00:00 2001 From: Juxhin Dyrmishi Brigjaj Date: Sun, 6 Oct 2024 18:05:28 +0200 Subject: [PATCH] feat(permute): add support for character insertion between two vowels --- README.md | 25 --------------------- twistrs/src/permutate.rs | 48 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 70867a3..a1d868a 100644 --- a/README.md +++ b/README.md @@ -67,31 +67,6 @@ async fn main() { - Exceptionally fast end-to-end results - Core library allowing easy extensions (i.e. CLI, API & streams) -#### Permutation Modes - -- [x] Addition -- [x] Bit Squatting -- [x] Homoglyph -- [x] Hyphenation -- [x] Insertion -- [x] Omission -- [x] Repetition -- [x] Replacement -- [x] Sub-domain -- [x] Transposition -- [x] Vowel-swap -- [x] Dictionary -- [x] TLD addition - -#### Domain Enrichment Features - -- [x] DNS lookup -- [x] MX parsing -- [ ] SMTP Banner -- [x] HTTP Banner -- [x] GeoIP Lookup (Cached) -- [x] WhoIs Lookup - #### Miscellaneous - [x] [Blog post](https://blog.digital-horror.com/twistrs) - [x] [HaveIBeenSquatted](https://haveibeensquatted.com/) diff --git a/twistrs/src/permutate.rs b/twistrs/src/permutate.rs index bdeeb44..1fed030 100644 --- a/twistrs/src/permutate.rs +++ b/twistrs/src/permutate.rs @@ -64,6 +64,7 @@ pub enum PermutationKind { Subdomain, Transposition, VowelSwap, + DoubleVowelInsertion, Keyword, Tld, Homoglyph, @@ -148,6 +149,7 @@ impl Domain { .chain(self.subdomain()) .chain(self.transposition()) .chain(self.vowel_swap()) + .chain(self.double_vowel_insertion()) .chain(self.keyword()) .chain(self.tld()) .chain(self.homoglyph()?)) @@ -496,7 +498,7 @@ impl Domain { .chars() .enumerate() .filter_map(move |(i, c)| { - if VOWELS.contains(&c) { + if VOWELS.contains(&c.to_ascii_lowercase()) { Some(VOWELS.iter().filter_map(move |vowel| { let permutation = format!("{}{}{}", &self.fqdn[..i], vowel, &self.fqdn[i + 1..]); @@ -519,6 +521,37 @@ impl Domain { .flatten() } + /// Permutation method that inserts every lowercase ascii character between + /// two vowels. + pub fn double_vowel_insertion(&self) -> impl Iterator + '_ { + self.fqdn + .chars() + .enumerate() + .tuple_windows() + .filter_map(move |((i1, c1), (i2, c2))| { + if VOWELS.contains(&c1.to_ascii_lowercase()) + && VOWELS.contains(&c2.to_ascii_lowercase()) + { + Some(ASCII_LOWER.iter().filter_map(move |inserted| { + let permutation = + format!("{}{inserted}{}", &self.fqdn[..=i1], &self.fqdn[i2..]); + + if let Ok(domain) = Domain::new(permutation.as_str()) { + Some(Permutation { + domain, + kind: PermutationKind::DoubleVowelInsertion, + }) + } else { + None + } + })) + } else { + None + } + }) + .flatten() + } + /// Permutation mode that appends and prepends common keywords to the /// domain in the following order: /// @@ -770,4 +803,17 @@ mod tests { assert!(!permutations.is_empty()); } } + + #[test] + fn test_domains_double_vowel_insertion() { + let domain = Domain::new("exampleiveus.com").unwrap(); + let expected = Domain::new("exampleivesus.com").unwrap(); + + let results: Vec = domain + .double_vowel_insertion() + .filter(|p| p.domain.fqdn == expected.fqdn) + .collect(); + + assert_eq!(results.len(), 1); + } }