1use chrono::{Utc, Duration}; use smcrypto::sm2; use base64; use std::fs;
11use smcrypto::sm3::sm3_hash; use rand::Rng;
13use std::str;
14pub fn generate_code(email: &str, days: i64, public_key: &str) -> String {
24 let enc_ctx = sm2::Encrypt::new(public_key);
25
26 let now = Utc::now();
28 let expire_time = now + Duration::days(days);
29
30 let data = format!("{}|{}", email, expire_time.to_rfc3339());
32
33 let encrypted_data = enc_ctx.encrypt(data.as_bytes());
35
36 let encrypted_hex = hex::encode(encrypted_data);
38
39 let code = base64::encode(encrypted_hex);
41
42 code
43}
44
45pub fn decode_code(code: &str, private_key: &str) -> (String, chrono::DateTime<Utc>) {
54 let dec_ctx = sm2::Decrypt::new(private_key);
55
56 let encrypted_hex = base64::decode(code).expect("Decoding base64 failed");
58
59 let encrypted_data = hex::decode(String::from_utf8(encrypted_hex).expect("Invalid UTF-8")).expect("Decoding hex failed");
61
62 let decrypted_data = dec_ctx.decrypt(&encrypted_data);
64 let data = String::from_utf8(decrypted_data).expect("Invalid UTF-8");
65
66 let parts: Vec<&str> = data.split('|').collect();
68 if parts.len() == 2 {
69 let email = parts[0].to_string();
70 let expire_time = chrono::DateTime::parse_from_rfc3339(parts[1])
71 .expect("Invalid expire time format")
72 .with_timezone(&Utc); (email, expire_time)
74 } else {
75 panic!("Invalid code format");
76 }
77}
78
79pub fn read_key_file(key_path: String) -> String {
80 let hex = fs::read_to_string(key_path).expect("Reading key failed");
81
82 let bytes = hex::decode(hex).expect("Decoding key failed");
83
84 String::from_utf8(bytes).expect("Invalid UTF-8")
85}
86
87
88
89
90#[cfg(feature = "password")]
92pub fn generate_random_string(length: usize) -> String {
93 let charset: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
94 let mut rng = rand::thread_rng();
95 let random_string: String = (0..length)
96 .map(|_| {
97 let idx = rng.gen_range(0..charset.len());
98 charset[idx] as char
99 })
100 .collect();
101 random_string
102}
103
104#[cfg(feature = "password")]
106pub fn encrypt_password(password: &str, salt: &str) -> String {
107 let data = format!("{}{}", password, salt);
109
110 let hash_result = sm3_hash(data.as_bytes());
112
113 base64::encode(hash_result)
115}
116
117#[cfg(feature = "password")]
119pub fn verify_password(password: &str, salt: &str, encrypted_password: &str) -> bool {
120 let new_encrypted_password = encrypt_password(password, salt);
122
123 new_encrypted_password == encrypted_password
125}
126
127use time::{OffsetDateTime, format_description};
128
129#[cfg(feature = "code-utils")]
130pub fn generate_task_number() -> String {
131 let now = OffsetDateTime::now_utc();
133 let timestamp = now.unix_timestamp(); let format = format_description::parse("[year][month][day]_[hour][minute][second]").unwrap();
137 let time_str = now.format(&format).unwrap();
138
139 let mut rng = rand::thread_rng();
141 let random_part: String = (0..4)
142 .map(|_| {
143 let num = rng.gen_range(0..36); if num < 10 {
145 (b'0' + num) as char } else {
147 (b'a' + (num - 10)) as char }
149 })
150 .collect();
151
152 format!("{}_{}", time_str, random_part)
154}