sylvia_iot_corelib/
strings.rs

1//! String libraries.
2
3use chrono::{DateTime, SecondsFormat, Utc};
4use hex;
5use hmac::Hmac;
6use pbkdf2;
7use rand::{distributions::Alphanumeric, thread_rng, Rng};
8use regex::Regex;
9use sha2::{Digest, Sha256};
10use url::Url;
11
12const PASSWORD_ROUNDS: u32 = 10000;
13
14/// To transfer hex address string to 128-bit integer.
15pub fn hex_addr_to_u128(addr: &str) -> Result<u128, &'static str> {
16    if addr.len() == 0 || addr.len() > 32 || addr.len() % 2 != 0 {
17        return Err("invalid address format");
18    }
19
20    match u128::from_str_radix(addr, 16) {
21        Err(_) => Err("invalid address format"),
22        Ok(value) => Ok(value),
23    }
24}
25
26/// To check if the account is valid.
27pub fn is_account(account: &str) -> bool {
28    let name_regex = Regex::new(r"^[a-z0-9]{1}[a-z0-9_-]*$").unwrap();
29    let email_regex = Regex::new(
30        r"^([a-z0-9_+]([a-z0-9_+.]*[a-z0-9_+])?)@([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6})$",
31    )
32    .unwrap();
33
34    name_regex.is_match(account) || email_regex.is_match(account)
35}
36
37/// To check if the (unit/application/network) code is valid.
38pub fn is_code(code: &str) -> bool {
39    let regex = Regex::new(r"^[a-z0-9]{1}[a-z0-9_-]*$").unwrap();
40    regex.is_match(code)
41}
42
43/// To check if the (client) scope is valid.
44pub fn is_scope(scope: &str) -> bool {
45    let regex = Regex::new(r"^[a-z0-9]+([\.]{1}[a-z0-9]+)*$").unwrap();
46    regex.is_match(scope)
47}
48
49/// To check if the (redirect) URI is valid.
50pub fn is_uri(uri: &str) -> bool {
51    Url::parse(uri).is_ok()
52}
53
54/// To hash the password.
55pub fn password_hash(password: &str, salt: &str) -> String {
56    let mut res: [u8; 32] = [0; 32];
57    let _ = pbkdf2::pbkdf2::<Hmac<Sha256>>(
58        password.as_bytes(),
59        salt.as_bytes(),
60        PASSWORD_ROUNDS,
61        &mut res,
62    );
63    hex::encode(res)
64}
65
66/// To generate item ID in `[timestamp-milliseconds]-[random-alphanumeric]` format.
67pub fn random_id(time: &DateTime<Utc>, len: usize) -> String {
68    format!("{}-{}", time.timestamp_millis(), randomstring(len))
69}
70
71/// To generate hex-string item ID using [`random_id`] and additional hash.
72pub fn random_id_sha(time: &DateTime<Utc>, len: usize) -> String {
73    let str = random_id(time, len);
74    let mut hasher = Sha256::new();
75    hasher.update(str.as_bytes());
76    hex::encode(hasher.finalize())
77}
78
79/// To generate random alphanumeric string with the specified length.
80pub fn randomstring(len: usize) -> String {
81    let mut rng = thread_rng();
82    std::iter::repeat(())
83        .map(|()| rng.sample(Alphanumeric))
84        .map(char::from)
85        .take(len)
86        .collect()
87}
88
89/// To convert time to RFC 3339 format with milliseconds precision (`YYYY-MM-DDThh:mm:ss.SSSZ`).
90pub fn time_str(time: &DateTime<Utc>) -> String {
91    time.to_rfc3339_opts(SecondsFormat::Millis, true)
92}
93
94/// To generate hex address string with the specified length (hex string length).
95pub fn u128_to_addr(value: u128, len: usize) -> String {
96    match len {
97        0 | 1 | 2 => format!("{:02x}", value & 0xff),
98        3 | 4 => format!("{:04x}", value & 0xffff),
99        5 | 6 => format!("{:06x}", value & 0xff_ffff),
100        7 | 8 => format!("{:08x}", value & 0xffff_ffff),
101        9 | 10 => format!("{:010x}", value & 0xff_ffff_ffff),
102        11 | 12 => format!("{:012x}", value & 0xffff_ffff_ffff),
103        13 | 14 => format!("{:014x}", value & 0xff_ffff_ffff_ffff),
104        15 | 16 => format!("{:016x}", value & 0xffff_ffff_ffff_ffff),
105        17 | 18 => format!("{:018x}", value & 0xff_ffff_ffff_ffff_ffff),
106        19 | 20 => format!("{:020x}", value & 0xffff_ffff_ffff_ffff_ffff),
107        21 | 22 => format!("{:022x}", value & 0xff_ffff_ffff_ffff_ffff_ffff),
108        23 | 24 => format!("{:024x}", value & 0xffff_ffff_ffff_ffff_ffff_ffff),
109        25 | 26 => format!("{:026x}", value & 0xff_ffff_ffff_ffff_ffff_ffff_ffff),
110        27 | 28 => format!("{:028x}", value & 0xffff_ffff_ffff_ffff_ffff_ffff_ffff),
111        29 | 30 => format!("{:030x}", value & 0xff_ffff_ffff_ffff_ffff_ffff_ffff_ffff),
112        _ => format!("{:032x}", value),
113    }
114}