1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
extern crate base64;
extern crate sha2;

use base64::{Engine as _, engine::general_purpose::URL_SAFE};
use rand::{Rng, thread_rng};
use sha2::{Digest, Sha512};

/// Calculates the SHA-512 hash value for the given payload.
///
/// # Arguments
///
/// * `value` - The payload for which the hash is to be calculated.
///
/// # Returns
///
/// A hexadecimal string representing the SHA-512 hash value.
///
/// ## References
/// - [Official docs](https://docs.rs/sha2/latest/sha2/#usage)
pub fn calculate_hash(value: String) -> String {
    let mut hasher = Sha512::new();
    hasher.update(value);
    let result = hasher.finalize();
    format!("{:x}", result)
}

/// Encodes a binary string to a Base64-encoded ASCII string.
///
/// This function is similar to the built-in `btoa` function in native JavaScript,
/// treating each character in the input string as a byte of binary data.
///
/// # Arguments
///
/// * `value` - The binary string to be encoded.
///
/// # Returns
///
/// A Base64-encoded ASCII string.
///
/// ## References
/// - [Official docs](https://docs.rs/base64/latest/base64/#url-safe-alphabet)
#[allow(dead_code)]  // Just for reference
pub fn base64_encode(value: &str) -> String {
    URL_SAFE.encode(value.as_bytes())
}

/// Decodes a Base64-encoded string to its original binary representation.
///
/// This function is similar to the built-in `atob` function in native JavaScript.
///
/// # Arguments
///
/// * `value` - The Base64-encoded string to be decoded.
///
/// # Returns
///
/// A `Result` containing the decoded string or an error message.
///
/// ## References
/// - [Official Docs](https://docs.rs/base64/latest/base64/#url-safe-alphabet)
pub fn base64_decode(value: &str) -> Result<String, &'static str> {
    if let Ok(decoded_bytes) = URL_SAFE.decode(value) {
        if let Ok(decoded_str) = String::from_utf8(decoded_bytes) {
            return Ok(decoded_str);
        } else {
            log::error!("Error decoding UTF-8");
        }
    } else {
        log::error!("Error decoding Base64");
    }
    Err("Server was unable to decrypt the credentials")
}

/// Encodes a string value into a hexadecimal representation.
///
/// # Arguments
///
/// * `value` - The string value to be encoded.
///
/// # Returns
///
/// A string representing the hexadecimal encoding of the input.
pub fn hex_encode(value: &str) -> String {
    let mut hex_values: Vec<String> = Vec::new();
    for ch in value.chars() {
        let hex_value = format!("{:04x}", ch as u32);
        hex_values.push(hex_value);
    }
    format!("\\u{}", hex_values.join("\\u"))
}

/// Decodes a hexadecimal-encoded string into its original string representation.
///
/// # Arguments
///
/// * `value` - The hexadecimal-encoded string to be decoded.
///
/// # Returns
///
/// A string representing the decoded content.
pub fn hex_decode(value: &str) -> String {
    let mut result = String::new();
    let hex_values: Vec<&str> = value.split("\\u").skip(1).collect();
    for hex_value in hex_values {
        if let Ok(code_point) = u32::from_str_radix(hex_value, 16) {
            if let Some(ch) = char::from_u32(code_point) {
                result.push(ch);
            }
        }
    }
    result
}

/// Generates a random key with a length of 64 characters from the specified character set.
///
/// # Returns
///
/// A randomly generated key.
pub fn keygen() -> String {
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
    let mut rng = thread_rng();
    let token: String = (0..64)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();
    token
}