dynamic_token/
utils.rs

1use std::str::{self};
2use rand::Rng;
3use utcnow::utcnow;
4use base64::{Engine as _, engine::general_purpose};
5use crate::constants::*;
6
7/// Fetch the current timestamp in milliseconds with the standard library
8pub(crate) fn milliseconds_now() -> i64 {
9  let ts = utcnow().unwrap().as_millis();
10  let max = i64::MAX;
11  if ts <= max as i128 {
12    ts as i64
13  } else {
14    max
15  }
16}
17
18pub(crate) fn from_base_36(sample: &str) -> Option<Vec<u8>> {
19  if sample.len() > 0 {
20    base_encode::from_str(sample, 36, BASE_36_CHARS)
21  } else {
22    None
23  }
24}
25
26pub(crate) fn from_base_16(sample: &str) -> Option<Vec<u8>> {
27  base_encode::from_str(sample, 16, HEX_CHARS)
28}
29
30pub(crate) fn base_36_parts_to_hex_dec(sample: &str) -> Option<String> {
31    if let Some(values) = from_base_36(sample) {
32      base_encode::to_string(&values, 16, HEX_CHARS)
33    } else {
34      None
35    }
36}
37
38pub(crate) fn hex_dec_to_base_36(sample: &str) -> Option<String> {
39    if let Some(values) = from_base_16(sample) {
40      base_encode::to_string(&values, 36, BASE_36_CHARS)
41    } else {
42      None
43    }
44}
45
46/// Convert a base-10 integer to a base-36 string
47pub(crate) fn dec_to_base_36(value: u32) -> Option<String> {
48  let buf = value.to_be_bytes();
49  base_encode::to_string(&buf, 36, BASE_36_CHARS)
50}
51
52/// Convert a large integer to a shorter sequence of letters and numerals
53pub(crate) fn i64_to_base_36(value: i64) -> Option<String> {
54  let buf = value.to_be_bytes();
55  base_encode::to_string(&buf, 36, BASE_36_CHARS)
56}
57
58/// Convert a base-36 digit to u8 integer.
59pub(crate) fn base_36_to_u8(letter: &char) -> Option<u8> {
60  if let Some(values) = from_base_36(&letter.to_string()) {
61    if values.len() > 0 {
62      if let Some(value) = values.last() {
63        Some(*value)
64      } else {
65          None
66      }
67    } else {
68      None
69    }
70  } else {
71    None
72  }
73}
74
75pub(crate) fn base_36_str_to_u64(sample: &str) -> Option<u64> {
76  if let Some(values) = from_base_36(sample) {
77    let radix: u64 = 256;
78    let num_values = values.len();
79    let max_36_pow = 12;
80    if num_values > 0 {
81      let max_pow = if num_values < max_36_pow { values.len() - 1 } else { max_36_pow };
82      let mut curr_pow = max_pow as u32;
83      let mut sum: u64 = 0;
84      for v in values {
85        let multiplier = if curr_pow > 0 { radix.pow(curr_pow) } else { 1u64 };
86        sum += v as u64 * multiplier;
87        if curr_pow > 0 { 
88          curr_pow -= 1;
89        }
90      }
91      Some(sum)
92    } else {
93        None
94    }
95  } else {
96    None
97  }
98}
99
100pub(crate) fn random_int(max: u32) -> u32 {
101  let mut rng = rand::thread_rng();
102  rng.gen::<u32>() % max
103}
104
105pub(crate) fn rand_char(characters: &[char]) -> char {
106  let len = characters.len();
107  let rand_index = random_int(len as u32) as usize;
108  characters.get(rand_index).unwrap_or(&' ').to_owned()
109}
110
111pub(crate) fn rand_char_as_string(rand_chars: &[char]) -> String{
112  rand_char(rand_chars).to_string()
113}
114
115pub(crate) fn rand_int_36(power: u8) -> String {
116  let max = 10u32.pow(power as u32);
117  let rand_int = random_int(max);
118  dec_to_base_36(rand_int).unwrap_or("".to_string())
119}
120
121/// Convert a hexadecimal string first into integers (0-15) and then into base-36
122pub(crate) fn hex_string_to_base36_parts(hex_str: &str) -> Option<String> {
123  if hex_str.len() >= MIN_VALID_UUID_LENGTH {
124    let base36_str = vec![&hex_str[..12],&hex_str[12..]].into_iter()
125      .map(|hd| hex_dec_to_base_36(hd).unwrap_or("".to_string()))
126      .collect::<Vec<String>>()
127      .join("_");
128    Some(base36_str)
129  } else {
130    None
131  }
132}
133
134/// base-64-encode with standard options
135pub fn encode_base64(key_str: &str) -> String {
136  general_purpose::STANDARD.encode(key_str)
137}
138
139/// base-64-decode with standard options
140pub fn decode_base64(sample: &str) -> String {
141  let decoded = general_purpose::STANDARD.decode(sample).unwrap_or(vec![]);
142  str::from_utf8(&decoded).unwrap_or("").to_string()
143}