use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use base64ct::{Base64UrlUnpadded, Encoding};
use sentc_crypto_common::content_searchable::{SearchCreateData, SearchCreateDataLight};
use sentc_crypto_core::getting_alg_from_hmac_key;
use crate::entities::keys::HmacKeyFormatInt;
use crate::SdkError;
#[cfg(not(feature = "rust"))]
mod crypto_searchable;
#[cfg(feature = "rust")]
mod crypto_searchable_rust;
#[cfg(not(feature = "rust"))]
pub use self::crypto_searchable::{create_searchable, prepare_create_searchable, prepare_create_searchable_light, search};
#[cfg(feature = "rust")]
pub use self::crypto_searchable_rust::{create_searchable, prepare_create_searchable, prepare_create_searchable_light, search};
fn search_internally(key: &HmacKeyFormatInt, data: &str) -> Result<String, SdkError>
{
hash_value_internally(key, data.as_bytes())
}
fn create_searchable_internally(
key: &HmacKeyFormatInt,
item_ref: &str,
category: Option<&str>,
data: &str,
full: bool,
limit: Option<usize>,
) -> Result<String, SdkError>
{
let out = prepare_create_searchable_internally(key, item_ref, category, data, full, limit)?;
serde_json::to_string(&out).map_err(|_| SdkError::JsonToStringFailed)
}
fn prepare_create_searchable_internally(
key: &HmacKeyFormatInt,
item_ref: &str,
category: Option<&str>,
data: &str,
full: bool,
limit: Option<usize>,
) -> Result<SearchCreateData, SdkError>
{
let hashes = hash_full_internally(key, data, full, limit)?;
let category = if let Some(c) = category { Some(c.to_string()) } else { None };
Ok(SearchCreateData {
category,
item_ref: item_ref.to_string(),
hashes,
alg: getting_alg_from_hmac_key(&key.key).to_string(),
key_id: key.key_id.to_string(),
})
}
fn prepare_create_searchable_light_internally(
key: &HmacKeyFormatInt,
data: &str,
full: bool,
limit: Option<usize>,
) -> Result<SearchCreateDataLight, SdkError>
{
let hashes = hash_full_internally(key, data, full, limit)?;
Ok(SearchCreateDataLight {
hashes,
alg: getting_alg_from_hmac_key(&key.key).to_string(),
key_id: key.key_id.to_string(),
})
}
fn hash_full_internally(key: &HmacKeyFormatInt, data: &str, full: bool, limit: Option<usize>) -> Result<Vec<String>, SdkError>
{
if data.is_empty() {
return Err(SdkError::SearchableEncryptionDataNotFound);
}
if full {
let hash = hash_value_internally(key, data.as_bytes())?;
return Ok(vec![hash]);
}
let limit_length = if let Some(l) = limit {
if l > data.len() {
data.len()
} else {
l
}
} else {
data.len()
};
if limit_length > 200 {
return Err(SdkError::SearchableEncryptionDataTooLong);
}
let mut word_to_hash = Vec::with_capacity(limit_length);
let mut hashed = Vec::with_capacity(limit_length);
for (i, datum) in data.bytes().enumerate() {
if i > limit_length {
break;
}
word_to_hash.push(datum);
hashed.push(hash_value_internally(key, &word_to_hash)?);
}
Ok(hashed)
}
fn hash_value_internally(key: &HmacKeyFormatInt, data: &[u8]) -> Result<String, SdkError>
{
let hash = sentc_crypto_core::crypto::encrypt_searchable(&key.key, data)?;
Ok(Base64UrlUnpadded::encode_string(&hash))
}