fake_torrent_client/
algorithm.rs

1use rand::Rng;
2use std::convert::TryFrom;
3
4use crate::{KEY_LENGTH, PEER_ID_LENGTH};
5
6#[derive(Debug, Clone)]
7pub(crate) enum Algorithm {
8    Regex,
9    Hash,
10    HashNoLeadingZero,
11    ///inclusive bounds: from 1 to 2147483647
12    DigitRangeTransformedToHexWithoutLeadingZeroes,
13    RandomPoolWithChecksum,
14}
15
16const HASH_SYMBOLS: &str = "abcdef0123456789ABCDEF";
17
18pub(crate) fn hash(no_leading_zero: bool, uppercase: Option<bool>) -> String {
19    let mut rng = rand::thread_rng();
20    let mut h = String::with_capacity(KEY_LENGTH);
21    while h.len() < KEY_LENGTH {
22        let i: usize = rng.gen_range(0usize..15usize);
23        if i == 0 && no_leading_zero {
24            continue;
25        }
26        if uppercase == None || uppercase.unwrap() {
27            h.push(HASH_SYMBOLS.chars().nth(i + 6).unwrap());
28        } else {
29            h.push(HASH_SYMBOLS.chars().nth(i).unwrap());
30        }
31    }
32    h
33}
34/// Generate a string from a regex pattern
35pub(crate) fn regex(pattern: String) -> String {
36    let mut rng = rand::thread_rng();
37    let gen = rand_regex::Regex::compile(&pattern, 64).unwrap();
38    (&mut rng).sample_iter(&gen).nth(64).unwrap()
39}
40/// Return a hex string from a random integer between 1 and 2147483647
41pub(crate) fn digit_range_transformed_to_hex_without_leading_zero() -> String {
42    let mut rng = rand::thread_rng();
43    format!("{:x}", rng.gen_range(1u32..2147483647u32)).to_uppercase()
44}
45/// Used for some peer ID generation
46pub(crate) fn random_pool_with_checksum(prefix: &str, characters_pool: &str) -> String {
47    //println!("random_pool_with_checksum: prefix={}, \t characters_pool: {}", prefix, characters_pool);
48    if prefix.is_empty() {
49        panic!("algorithm prefix must not be null or empty.");
50    }
51    if characters_pool.is_empty() {
52        panic!("algorithm character pool must not be null or empty.");
53    }
54    let mut out = String::with_capacity(PEER_ID_LENGTH);
55    out.push_str(prefix);
56    //TODO:
57    let random_bytes = rand::thread_rng().gen::<[u8; PEER_ID_LENGTH]>();
58    let base = characters_pool.chars().count();
59    for b in random_bytes {
60        out.push(characters_pool.chars().nth(usize::try_from(b).unwrap() % base).expect("Cannot get char in characters pool"));
61        if out.len() == PEER_ID_LENGTH {break;}
62    }
63    out
64}
65//******************************************* TESTS
66#[cfg(test)]
67mod tests {
68    use super::*;
69    use regex::Regex;
70    #[test]
71    fn is_hash_ok() {
72        for _ in 0usize..16usize {
73            assert_eq!(hash(false, None).len(), 8usize);
74            let h = hash(true, None);
75            assert_eq!(h.len(), 8usize);
76            assert!(!h.starts_with('0'));
77        }
78    }
79    #[test]
80    fn is_hash_case_ok() {
81        let re_uc = Regex::new(r"[A-Z0-9]{8}").unwrap();
82        let re_lc = Regex::new(r"[a-z0-9]{8}").unwrap();
83        for _ in 0usize..16usize {
84            assert!(re_uc.is_match(&hash(false, None)));
85            assert!(re_uc.is_match(&hash(false, Some(true))));
86            assert!(re_lc.is_match(&hash(false, Some(false))));
87        }
88    }
89    #[test]
90    fn is_regex_ok() {
91        let mut re = Regex::new("-lt0D60-[\u{0001}-\u{00ff}]{12}").unwrap();
92        assert!(re.is_match(&regex("-lt0D60-[\u{0001}-\u{00ff}]{12}".to_owned())));
93        re = Regex::new("-AZ5750-[a-zA-Z0-9]{12}").unwrap();
94        assert!(re.is_match(&regex("-AZ5750-[a-zA-Z0-9]{12}".to_owned())));
95    }
96
97    #[test]
98    fn is_regex_ok_2() {
99        let s = String::from(r"-DE13D0-[A-Za-z0-9_~\\(\\)\\!\\.\\*-]{12}");
100        let re = Regex::new(&s).unwrap();
101        assert!(re.is_match(&regex(s)));
102    }
103
104    #[test]
105    fn is_digit_range_to_hex_ok() {
106        let re = Regex::new(r"[A-Z0-9]+").unwrap();
107        for _ in 0usize..16usize {
108            assert!(re.is_match(&digit_range_transformed_to_hex_without_leading_zero()));
109        }
110    }
111}