1use std::sync::OnceLock;
2use aes_gcm::aead::{Aead, OsRng};
3use aes_gcm::aes::Aes256;
4use aes_gcm::{AeadCore, Aes256Gcm, Key, KeyInit, Nonce};
5use lz4_flex;
6use tokio::fs::{File, OpenOptions};
7use tokio::io::{AsyncReadExt, AsyncWriteExt};
8use tokio::sync::RwLock;
9use rayon::prelude::*;
10
11static PASSWORD: OnceLock<RwLock<String>> = OnceLock::new();
12
13pub async fn set_password(pw: &str) {
14 let lock = PASSWORD.get_or_init(|| RwLock::new(String::new()));
15 let mut write_guard = lock.write().await;
16 *write_guard = pw.to_string();
17}
18
19async fn get_password() -> String {
20 let lock = PASSWORD.get_or_init(|| RwLock::new(String::new()));
21 let read_guard = lock.read().await;
22 read_guard.clone()
23}
24
25fn fix_key(key: &[u8]) -> [u8; 32] {
26 let mut fixed_key = [0u8; 32];
27 let len = key.len().min(32);
28 fixed_key[..len].copy_from_slice(&key[..len]);
29 fixed_key
30}
31
32async fn aes_256_encode(data: Vec<u8>) -> (Vec<u8>, Vec<u8>) {
33 let fixed_key = fix_key(get_password().await.as_bytes());
34
35 tokio::task::spawn_blocking(move || {
36 let key = Key::<Aes256>::from_slice(&fixed_key);
37 let cipher = Aes256Gcm::new(&key);
38 let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
39
40 let encoded_data = cipher.encrypt(&nonce, &*data).expect("There was an error while Encoding");
41
42 (encoded_data, nonce.as_slice().to_vec())
43 }).await.unwrap()
44}
45
46async fn aes_256_decode(data: Vec<u8>, nonce: Vec<u8>) -> Vec<u8> {
47 let fixed_key = fix_key(get_password().await.as_bytes());
48
49 tokio::task::spawn_blocking(move || {
50 let key = Key::<Aes256>::from_slice(&fixed_key);
51 let cipher = Aes256Gcm::new(&key);
52 let nonce_from_slice = Nonce::from_slice(nonce.as_slice());
53
54 cipher.decrypt(nonce_from_slice, &*data).unwrap()
55 }).await.unwrap()
56}
57
58async fn lz4_compress(data: Vec<u8>) -> Vec<u8> {
59 tokio::task::spawn_blocking(move || {
60 lz4_flex::compress_prepend_size(&data)
61 }).await.unwrap_or_else(|e1| panic!("There was an error while Compression task: {e1}"))
62}
63
64async fn lz4_decompress(data: Vec<u8>) -> Vec<u8> {
65 tokio::task::spawn_blocking(move || {
66 lz4_flex::decompress_size_prepended(data.as_slice()).unwrap_or_else(|e| panic!("There was an error while decompressing file: {e}"))
67 }).await.unwrap_or_else(|e1| panic!("There was an error while Compression task: {e1}"))
68}
69
70pub async fn write_structure(name: &str, hpa_file: &str, encrypt: bool) {
71 let mut file = File::open(name).await.expect("Error opening file");
72 let mut file_data = Vec::new();
73 file.read_to_end(&mut file_data).await.expect("There was an error while reading Data");
74
75 if tokio::fs::metadata(hpa_file).await.is_ok() {
76 println!("File is already exist");
77 return;
78 }
79
80 let mut data = Vec::new();
81 let compressed_data = lz4_compress(file_data).await;
82
83 tokio::join!(async {
84 if encrypt {
85 let encrypted_data = aes_256_encode(compressed_data).await;
86
87 let ln = encrypted_data.0.len();
88 let wrs = format!("{name}.hpa: {ln}|");
89 data.extend_from_slice(wrs.as_bytes());
90 if ln > 16384 {
91 data.par_extend(encrypted_data.0);
92 } else {
93 data.extend(encrypted_data.0);
94 }
95 data.extend_from_slice(";".as_bytes());
96
97 let ln = encrypted_data.1.len();
98 let wrs = format!("{name}.nonce.hpa: {ln}|");
99 data.extend_from_slice(wrs.as_bytes());
100 data.extend_from_slice(encrypted_data.1.as_slice());
101 data.extend_from_slice(";".as_bytes());
102 } else {
103 let ln = compressed_data.len();
104 let wrs = format!("{name}.hpa: {ln}|");
105 data.extend_from_slice(wrs.as_bytes());
106 if ln > 16384 {
107 data.par_extend(compressed_data);
108 } else {
109 data.extend(compressed_data);
110 }
111 data.extend_from_slice(";".as_bytes());
112
113 }
114
115 let mut file = File::create(hpa_file).await.expect("There was an error while Creating file");
116 let _ = file.write_all(data.as_slice()).await;
117 });
118}
119
120pub async fn find_line(line_to_find: &[u8], content: &[u8]) -> Vec<u8> {
121 let mut search_pattern = Vec::from(line_to_find);
122 search_pattern.extend_from_slice(&[b':', b' ']);
123
124 let content = content.to_vec();
125
126 tokio::task::spawn_blocking(move || {
127 if let Some(start) = memchr::memmem::find(content.as_slice(), &search_pattern) {
128 let start_index = start + search_pattern.len();
129
130 if let Some(pipe_index) = memchr::memmem::find(&content.as_slice()[start_index..], b"|") {
131 let len_bytes = &content.as_slice()[start_index..start_index + pipe_index];
132 let len = len_bytes.iter().fold(0usize, |acc, &b| acc * 10 + (b - b'0') as usize);
133 let value_start = start_index + pipe_index + 1;
134 return content.as_slice()[value_start..value_start + len].to_vec();
135 }
136 }
137
138 Vec::new()
139 }).await.unwrap_or_else(|e| panic!("There was an error while finding line: {e}"))
140}
141
142pub async fn read_structure(name: &str, hpa_file: &str, is_encrypted: bool) -> Vec<u8> {
143 let mut file = File::open(hpa_file).await.expect("There was an error while opening File");
144 let mut file_data = Vec::new();
145 file.read_to_end(&mut file_data).await.expect("There was an error while reading File");
146
147 let final_data = find_line(format!("{name}.hpa").as_bytes(), file_data.as_slice()).await;
148
149 tokio::join!(async {
150 if is_encrypted {
151 let nonce = find_line(format!("{name}.nonce.hpa").as_bytes(), file_data.as_slice()).await;
152 let decrypted = aes_256_decode(final_data, nonce).await;
153 lz4_decompress(decrypted).await
154 } else {
155 lz4_decompress(final_data).await
156 }
157 }).0
158}
159
160pub async fn add_structure(data_file_name: &str, hpa_file_name: &str, encrypt: bool) {
161 let mut data_file = File::open(data_file_name).await.expect("Failed to open data file");
162 let mut data_file_data = Vec::new();
163 data_file.read_to_end(&mut data_file_data).await.expect("Failed to read data file");
164
165 let compressed_data = lz4_compress(data_file_data).await;
166
167 let mut hpa_file = OpenOptions::new().read(true).write(true).open(hpa_file_name).await.unwrap();
168 let mut hpa_file_data = Vec::new();
169 hpa_file.read_to_end(&mut hpa_file_data).await.expect("Failed to read HPA file");
170
171 let line_to_find = format!("{data_file_name}.hpa: ");
172 if hpa_file_data.windows(line_to_find.len()).any(|window| window == line_to_find.as_bytes()) && find_line(line_to_find.as_bytes(), hpa_file_data.as_slice()).await.is_empty() {
173 println!("{} already exists. Did you mean to update?", data_file_name);
174 return;
175 }
176
177 tokio::join!(async {
178 let mut content = Vec::new();
179 if encrypt {
180 let encrypted_data = aes_256_encode(compressed_data).await;
181
182 let ln = encrypted_data.0.len();
183 let wrs = format!("{data_file_name}.hpa: {ln}|");
184 content.extend_from_slice(wrs.as_bytes());
185 if ln > 16384 {
186 content.par_extend(encrypted_data.0);
187 } else {
188 content.extend(encrypted_data.0)
189 }
190 content.extend_from_slice(";".as_bytes());
191
192 let ln = encrypted_data.1.len();
193 let wrs = format!("{data_file_name}.nonce.hpa: {ln}|");
194 content.extend_from_slice(wrs.as_bytes());
195 content.extend_from_slice(encrypted_data.1.as_slice());
196 content.extend_from_slice(";".as_bytes());
197 } else {
198 let ln = compressed_data.len();
199 let wrs = format!("{data_file_name}.hpa: {ln}|");
200 content.extend_from_slice(wrs.as_bytes());
201 if ln > 16384 {
202 content.par_extend(compressed_data)
203 } else {
204 content.extend(compressed_data)
205 }
206 content.extend_from_slice(";".as_bytes());
207 }
208
209 hpa_file.write(content.as_slice()).await.expect("Failed to write to HPA file");
210 });
211}
212
213pub async fn remove_structure(name: &str, hpa_file: &str, is_encrypted: bool) {
214 let mut file = File::open(hpa_file).await.expect("Failed to open HPA file");
215 let mut data = Vec::new();
216 file.read_to_end(&mut data).await.expect("Failed to read HPA file");
217
218 let name = format!("{name}.hpa");
219
220 let remove_entry = |entry_name: &str, file_data: &mut Vec<u8>| {
221 let mut search_pattern = Vec::from(entry_name.as_bytes());
222 search_pattern.extend_from_slice(&[b':', b' ']);
223
224 if let Some(start) = file_data.windows(search_pattern.len()).position(|window| window == search_pattern) {
225 let start_index = start + search_pattern.len();
226
227 if let Some(pipe_index) = file_data[start_index..].iter().position(|&b| b == b'|') {
228 let len_bytes = &file_data[start_index..start_index + pipe_index];
229 let len = len_bytes.iter().fold(0usize, |acc, &b| acc * 10 + (b - b'0') as usize);
230 let value_start = start_index + pipe_index + 1;
231 let value_end = value_start + len;
232
233 if value_end < file_data.len() {
234 let end = file_data[value_end..].iter().position(|&b| b == b';').map(|e| value_end + e).unwrap_or(file_data.len());
235
236 file_data.par_drain(start..=end);
237 }
238 }
239 }
240 };
241
242 tokio::join!(async {
243 if is_encrypted {
244 remove_entry(name.as_str(), &mut data);
245 let nonce_name = format!("{name}.nonce.hpa");
246 remove_entry(&nonce_name, &mut data);
247 } else {
248 let name_2 = format!("{name}.hpa");
249 if data.windows(data.len()).any(|window| window == name_2.as_bytes()) {
250 println!("{} already exists. Did you mean to update?", name_2);
251 return;
252 }
253
254 remove_entry(name.as_str(), &mut data);
255 }
256
257 let mut file = OpenOptions::new().write(true).truncate(true).open(hpa_file).await.expect("Failed to open HPA file for writing");
258 file.write_all(&data).await.expect("Failed to write to HPA file");
259 });
260}
261
262
263pub async fn update_structure(data_file_name: &str, hpa_file_name: &str, is_encrypted: bool) {
264 tokio::join!(async {
265 remove_structure(data_file_name, hpa_file_name, is_encrypted).await;
266 add_structure(data_file_name, hpa_file_name, is_encrypted).await
267 });
268}
269
270pub async fn export_structure(name: &str, hpa_file: &str, is_encrypted: bool) {
271 tokio::join!(async {
272 let read = read_structure(name, hpa_file, is_encrypted).await;
273
274 let file = File::create(name).await;
275 let _ = file.unwrap().write_all(read.as_slice()).await;
276 });
277}