1use gethostname::gethostname;
2use num_bigint::{self, BigUint};
3use num_integer;
4use std;
5#[cfg(feature = "regex")]
6use regex;
7
8pub fn create_counter(mut count: isize) -> CounterFunctionType {
10 return Box::new(move || {
11 count += 1;
12 return count;
13 });
14}
15
16pub type RandomFunctionType = Box<dyn FnMut() -> f64>;
18pub type CreateCounterFunctionType = Box<dyn Fn(isize) -> CounterFunctionType>;
20pub type CounterFunctionType = Box<dyn FnMut() -> isize>;
22pub type FingerPrintFunctionType =
24 Box<dyn Fn(&mut RandomFunctionType, Option<String>) -> String>;
25
26const BIG_LENGTH: usize = 32;
28const SHENANIGANS: [char; 36] = [
29 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
30 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
31];
32const SHENANIGANS_LENGTH: u128 = SHENANIGANS.len() as u128;
33const SHENANIGANS_LOWERCASE: [char; 26] = [
34 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
35 't', 'u', 'v', 'w', 'x', 'y', 'z',
36];
37
38pub fn create_fingerprint(
40 random_number_generator: &mut RandomFunctionType,
41 fingerprint_data: Option<String>,
42) -> String {
43 let new_fingerprint_data: String;
44 if fingerprint_data.is_none() {
45 let process_id = std::process::id();
46 let host_name = gethostname();
47 let env_vars = std::env::vars()
48 .map(|(k, _)| return k)
49 .collect::<Vec<String>>()
50 .join("");
51 new_fingerprint_data =
52 process_id.to_string() + &host_name.to_string_lossy() + env_vars.as_str();
53 } else {
54 new_fingerprint_data = fingerprint_data.unwrap();
55 }
56 let fingerprint = new_fingerprint_data
57 + create_entropy(random_number_generator, Some(BIG_LENGTH))
58 .unwrap()
59 .as_str();
60 return create_hash(Some(fingerprint))[0..BIG_LENGTH].to_string();
61}
62
63pub fn create_hash(data: Option<String>) -> String {
65 let actual_data = data.unwrap_or("".to_string());
66
67 #[cfg(feature="sha2")]
68 use sha2::{self, Digest};
69 #[cfg(feature="sha2")]
70 let mut hasher = sha2::Sha512::new();
71 #[cfg(feature="sha3")]
72 use sha3::{self, Digest};
73 #[cfg(feature="sha3")]
74 let mut hasher = sha3::Sha3_512::new();
75
76 hasher.update(actual_data);
77 let hashed_value = hasher.finalize();
78
79 let hashed_int = num_bigint::BigUint::from_bytes_be(&hashed_value);
80 return base36_encode(hashed_int);
81}
82
83pub fn create_entropy(
85 random_number_generator: &mut RandomFunctionType,
86 length: Option<usize>,
87) -> Result<String, ()> {
88 let actual_length = length.unwrap_or(4);
89 if actual_length < 1 {
90 return Err(());
91 }
92 let mut entropy = String::new();
93 while entropy.len() < actual_length {
94 entropy += base36_encode(num_bigint::BigUint::from(
95 (random_number_generator() * 36.0).floor() as u128,
96 ))
97 .as_str();
98 }
99 return Ok(entropy);
100}
101
102pub fn base36_encode(mut number: num_bigint::BigUint) -> String {
104 let mut encoded_string = String::new();
105 let mut modular: num_bigint::BigUint;
106 while number != BigUint::from(0 as usize) {
107 (number, modular) = num_integer::div_rem(number, SHENANIGANS_LENGTH.into());
108 encoded_string = SHENANIGANS[modular.to_string().parse::<usize>().unwrap()].to_string()
109 + &encoded_string;
110 }
111 if encoded_string.len() == 0 {
112 return "0".to_string();
113 }
114 return encoded_string;
115}
116
117pub fn create_letter(random_number_generator: &mut RandomFunctionType) -> char {
119 return SHENANIGANS_LOWERCASE
120 [(random_number_generator() * (SHENANIGANS_LOWERCASE.len() as f64)) as usize];
121}
122
123#[cfg(feature = "regex")]
124pub fn is_cuid(id: String, min_length: Option<usize>, max_length: Option<usize>) -> bool {
126 let length = id.len();
127 let re = r"^[0-9a-z]+$";
128 if length >= min_length.unwrap_or(2) && length <= max_length.unwrap_or(crate::generator::MAXIMUM_LENGTH) {
129 return regex::Regex::new(re).unwrap().is_match(&id)
130 }
131 return false;
132}