1use homoglyph_core::{
2 domain::{SentenceDomain, WordDomain},
3 homoglyphs::Homoglyphs,
4 sentence::Sentence,
5 Encodable,
6};
7use homoglyph_driver::{tantivy::*, SearchEngine};
8use std::str::FromStr;
9
10pub fn homoglyphs_to_string(homoglyphs_vec: Vec<Homoglyphs>) -> Vec<Vec<String>> {
11 let mut res_vec = Vec::<Vec<String>>::new();
12 for hs in homoglyphs_vec {
13 let mut h_vec = Vec::<String>::new();
14 for h in hs.0.iter() {
15 h_vec.push(h.to_string());
16 }
17 res_vec.push(h_vec);
18 }
19 res_vec
20}
21
22pub struct ComputeHomoglyphs {
23 search_engine: Tantivy,
24}
25
26impl ComputeHomoglyphs {
27 pub fn new() -> ComputeHomoglyphs {
28 let se = Tantivy::new();
29 ComputeHomoglyphs { search_engine: se }
30 }
31
32 pub fn compute(&mut self, js_sentence: &str) -> Vec<Homoglyphs> {
33 let s = Sentence::from_str(js_sentence).unwrap();
34 let enc_s = s.encode().unwrap();
35 self.search_engine.query(enc_s);
36
37 let sd: SentenceDomain = self.search_engine.search();
38 sd.generate(None)
39 }
40
41 pub fn compute_with_n_permutation(
42 &mut self,
43 js_sentence: &str,
44 n_permutation: usize,
45 ) -> Vec<Homoglyphs> {
46 let s = Sentence::from_str(js_sentence).unwrap();
47 let enc_s = s.encode().unwrap();
48 self.search_engine.query(enc_s);
49
50 let sd: SentenceDomain = self.search_engine.search();
51 sd.generate(Some(n_permutation))
52 }
53
54 pub fn compute_with_n_confusable(
55 &mut self,
56 js_sentence: &str,
57 n_confusable: usize,
58 ) -> Vec<Homoglyphs> {
59 let s = Sentence::from_str(js_sentence).unwrap();
60 let enc_s = s.encode().unwrap();
61 self.search_engine.query(enc_s);
62
63 let sd: SentenceDomain = self.search_engine.search();
64 let wd_custom: Vec<WordDomain> =
65 sd.0.iter()
66 .map(|w| {
67 let ww = w.clone().take(n_confusable);
68 let new_word = WordDomain::new(ww.0);
69 new_word
70 })
71 .collect();
72 let new_sd = SentenceDomain::new(wd_custom);
73 new_sd.generate(None)
74 }
75
76 pub fn compute_with_limit(
77 &mut self,
78 js_sentence: &str,
79 n_permutation: usize,
80 n_confusable: usize,
81 ) -> Vec<Homoglyphs> {
82 let s = Sentence::from_str(js_sentence).unwrap();
83 let enc_s = s.encode().unwrap();
84 self.search_engine.query(enc_s);
85
86 let sd: SentenceDomain = self.search_engine.search();
87 let wd_custom: Vec<WordDomain> =
88 sd.0.iter()
89 .map(|w| {
90 let ww = w.clone().take(n_confusable);
91 let new_word = WordDomain::new(ww.0);
92 new_word
93 })
94 .collect();
95 let new_sd = SentenceDomain::new(wd_custom);
96 new_sd.generate(Some(n_permutation))
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 const PERMUTATION_NUMBER: usize = 5;
105 const CONFUSABLE_NUMBER: usize = 2;
106 const JS_SENTENCE: &str = "rust";
107
108 #[test]
109 fn when_compute_then_compute_all_possible_homoglyphs() {
110 let mut chgs = ComputeHomoglyphs::new();
111 chgs.compute(JS_SENTENCE);
112 }
113
114 #[test]
115 fn when_compute_with_n_permutation_then_compute_n_possible_homoglyphs() {
116 let mut chgs = ComputeHomoglyphs::new();
117 let homoglyphs = chgs.compute_with_n_permutation(JS_SENTENCE, PERMUTATION_NUMBER);
118
119 let size = match homoglyphs.get(0) {
120 Some(h) => h.0.len(),
121 None => 0,
122 };
123
124 assert_eq!(PERMUTATION_NUMBER, size);
125 }
126
127 #[test]
128 fn when_compute_with_n_confusable_then_compute_possible_homoglyphs() {
129 let mut chgs = ComputeHomoglyphs::new();
130 let homoglyphs = chgs.compute_with_n_confusable(JS_SENTENCE, CONFUSABLE_NUMBER);
131
132 let size = match homoglyphs.get(0) {
133 Some(h) => h.0.len(),
134 None => 0,
135 };
136
137 assert_eq!(
138 4_u8.pow(CONFUSABLE_NUMBER.try_into().unwrap()) as usize,
139 size
140 );
141 }
142
143 #[test]
144 fn when_compute_with_limit_then_compute_possible_homoglyphs() {
145 let mut chgs = ComputeHomoglyphs::new();
146 let homoglyphs =
147 chgs.compute_with_limit(JS_SENTENCE, PERMUTATION_NUMBER, CONFUSABLE_NUMBER);
148
149 let size = match homoglyphs.get(0) {
150 Some(h) => h.0.len(),
151 None => 0,
152 };
153
154 assert_eq!(PERMUTATION_NUMBER, size);
155 }
156}