use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit, Nonce};
use dusa_collection_utils::{core::logger::LogLevel, core::types::stringy::Stringy, log};
use rand::Rng;
use tokio::sync::Notify;
use dusa_collection_utils::core::errors::{ErrorArrayItem, Errors, UnifiedResult};
#[cfg(target_os = "linux")]
use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
use tokio::time::sleep;
#[cfg(target_os = "linux")]
lazy_static::lazy_static! {
static ref initialized: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
static ref cleaning_loop_initialized: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
static ref cleaning_call: Arc<Notify> = Arc::new(Notify::new());
static ref cleaning_lock: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
}
#[allow(deprecated)]
#[cfg(target_os = "linux")]
#[deprecated(
since = "4.3.0",
note = "Currently unstable. Use `simple_encrypt` if possible."
)]
pub async fn encrypt_text(data: Stringy) -> Result<Stringy, ErrorArrayItem> {
let data_bytes = data.as_bytes().to_vec();
let plain_bytes = encrypt_data(&data_bytes).await.uf_unwrap()?;
let text = Stringy::from(String::from_utf8(plain_bytes)?);
Ok(text)
}
#[allow(deprecated)]
#[cfg(target_os = "linux")]
#[deprecated(
since = "4.3.0",
note = "Currently unstable. Use `simple_decrypt` if possible."
)]
pub async fn decrypt_text(data: Stringy) -> Result<Stringy, ErrorArrayItem> {
let data_bytes: &[u8] = data.as_bytes();
let decrypted_bytes: Vec<u8> = decrypt_data(&data_bytes).await.uf_unwrap()?;
let decrypted_string: String = String::from_utf8(decrypted_bytes)?;
let decrypted_stringy: Stringy = Stringy::Immutable(Arc::<str>::from(decrypted_string));
Ok(decrypted_stringy)
}
#[deprecated(
since = "4.3.0",
note = "Currently unstable. Use `simple_encrypt` if possible."
)]
#[cfg(target_os = "linux")]
pub async fn encrypt_data(_data: &[u8]) -> UnifiedResult<Vec<u8>> {
UnifiedResult::new(Ok(Vec::new()))
}
#[deprecated(
since = "4.3.0",
note = "Currently unstable. Use `simple_decrypt` if possible."
)]
#[cfg(target_os = "linux")]
pub async fn decrypt_data(_data: &[u8]) -> UnifiedResult<Vec<u8>> {
UnifiedResult::new(Ok(Vec::new()))
}
#[cfg(target_os = "linux")]
async fn _execution_locked() -> bool {
false
}
#[cfg(target_os = "linux")]
#[deprecated(
since = "4.3.0",
note = "Currently unstable. Use `simple_*` if possible."
)]
pub async unsafe fn clean_override_op<'a, F, Fut>(
callback: F,
data: &'a [u8],
) -> Result<Vec<u8>, ErrorArrayItem>
where
F: Fn(&'a [u8]) -> Fut,
Fut: std::future::Future<Output = UnifiedResult<Vec<u8>>>,
{
cleaning_loop_initialized.store(true, Ordering::Relaxed);
let result: Vec<u8> = callback(&data).await.uf_unwrap()?;
Ok(result)
}
#[cfg(target_os = "linux")]
async fn _call_clean() {
cleaning_call.notify_one();
log!(LogLevel::Trace, "Recs clean called");
}
#[cfg(target_os = "linux")]
async fn _clean_loop() -> Result<(), ErrorArrayItem> {
cleaning_loop_initialized.store(true, Ordering::Release);
loop {
tokio::select! {
_ = cleaning_call.notified() => {
cleaning_lock.store(true, Ordering::SeqCst);
tokio::time::sleep(Duration::from_millis(300)).await;
cleaning_lock.store(false, Ordering::SeqCst);
}
}
sleep(Duration::from_secs(6)).await;
}
}
#[cfg(target_os = "linux")]
async fn _initialize_locker() -> Result<(), ErrorArrayItem> {
match initialized.load(Ordering::Relaxed) {
true => {
if !cleaning_loop_initialized.load(Ordering::Relaxed) {
}
Ok(())
}
false => {
sleep(Duration::from_nanos(100)).await;
initialized.store(true, Ordering::Relaxed);
cleaning_loop_initialized.store(true, Ordering::Relaxed);
Ok(())
}
}
}
#[allow(unused_assignments)]
const NONCE_SIZE: usize = 12;
const KEY_SIZE: usize = 32;
pub fn generate_key(buffer: &mut [u8]) {
let mut rng = rand::thread_rng(); for byte in buffer.iter_mut() {
*byte = rng.gen(); }
}
pub fn simple_encrypt(data: &[u8]) -> Result<Stringy, ErrorArrayItem> {
let mut key: [u8; 32] = [0u8; 32];
generate_key(&mut key);
let cipher = Aes256Gcm::new(&key.into());
let nonce_bytes = rand::thread_rng().gen::<[u8; NONCE_SIZE]>();
let nonce = Nonce::from_slice(&nonce_bytes);
let ciphertext = cipher
.encrypt(nonce, data)
.map_err(|e| ErrorArrayItem::new(Errors::InvalidBlockData, e.to_string()))?;
let mut result = Vec::with_capacity(KEY_SIZE + NONCE_SIZE + ciphertext.len());
result.extend_from_slice(&key);
result.extend_from_slice(nonce);
result.extend_from_slice(&ciphertext);
let cipher_text = Stringy::from(hex::encode(result));
Ok(cipher_text)
}
pub fn simple_decrypt(encrypted_cipher_data: &[u8]) -> Result<Vec<u8>, ErrorArrayItem> {
let encrypted_data: Vec<u8> =
hex::decode(encrypted_cipher_data).map_err(ErrorArrayItem::from)?;
if encrypted_data.len() <= KEY_SIZE + NONCE_SIZE {
return Err(ErrorArrayItem::new(
Errors::InvalidBlockData,
"Encrypted data is too short",
));
}
let key = Key::<Aes256Gcm>::from_slice(&encrypted_data[..KEY_SIZE]);
let cipher = Aes256Gcm::new(key);
let nonce = Nonce::from_slice(&encrypted_data[KEY_SIZE..KEY_SIZE + NONCE_SIZE]);
let ciphertext = &encrypted_data[KEY_SIZE + NONCE_SIZE..];
cipher
.decrypt(nonce, ciphertext)
.map_err(|err| ErrorArrayItem::new(Errors::InvalidBlockData, err.to_string()))
}