homoglyph_service/
lib.rs

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}