Skip to main content

claw_crypto/
key_service.rs

1use crate::traits::KeyServiceTrait;
2pub use claw_crypto_interface::PrefixedKeySplits;
3use rand::{self, Rng};
4
5pub struct KeyService;
6
7impl KeyService {
8    fn join_digits(&self, digit_vec: &[u8]) -> String {
9        let vec: Vec<String> = digit_vec
10            .into_iter()
11            .map(|digit| digit.to_string())
12            .collect();
13        vec.join("")
14    }
15}
16
17impl KeyServiceTrait for KeyService {
18    fn digit_string(&self, length: usize) -> String {
19        let digit_vec = self.digit_vec(length);
20        let key = self.join_digits(&digit_vec);
21        key
22    }
23
24    fn digit_vec(&self, length: usize) -> Vec<u8> {
25        let mut digits = Vec::with_capacity(length);
26        for _ in 0..length {
27            let digit = rand::thread_rng().gen_range(0..=9);
28            let digit = digit as u8;
29            digits.push(digit);
30        }
31        digits
32    }
33
34    fn secure_string(&self, length: usize) -> String {
35        let random_bytes = rand::thread_rng().gen::<[u8; 32]>();
36        let random_slice = &random_bytes[0..length];
37        let string = self.join_digits(random_slice);
38        string
39    }
40
41    fn split_prefixed_key<'a>(
42        &self,
43        key: &'a str,
44        splitter: &str,
45    ) -> Result<PrefixedKeySplits<'a>, &'static str> {
46        let splits: Vec<&str> = key.split(splitter).collect();
47        let prefix = splits.get(0).ok_or("No prefix found in inputted &str")?;
48        let key = splits.get(1).ok_or("No key found in inputted &str")?;
49
50        Ok(PrefixedKeySplits::<'a> { prefix, key })
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn it_generates_vector_of_correct_length() {
60        let expected = 6usize;
61        let actual = KeyService.digit_vec(expected).len();
62        assert_eq!(actual, expected);
63    }
64
65    #[test]
66    fn it_generates_digit_string_of_correct_length() {
67        let expected = 16usize;
68        let actual = KeyService.digit_string(expected).len();
69        assert_eq!(actual, expected);
70    }
71
72    // NOTE: Not guaranteed, but very unlikely to fail
73    #[test]
74    fn it_generates_random_string() {
75        let strings: Vec<String> = (0..5).map(|_| KeyService.secure_string(32)).collect();
76
77        let first = &strings[0];
78        for (i, other) in strings.iter().skip(1).enumerate() {
79            assert_ne!(
80                first,
81                other,
82                "First string is identical to string at index {}",
83                i + 1
84            );
85        }
86    }
87
88    #[test]
89    fn it_generates_random_string_of_specified_length() {
90        let expected = 10usize;
91        let actual = KeyService.secure_string(expected).len();
92        assert_eq!(actual, expected)
93    }
94}