use argon2::password_hash::{Salt, SaltString};
use argon2::{Algorithm, Argon2, Params, PasswordHash, PasswordHasher, PasswordVerifier, Version};
use base64::{engine::general_purpose, Engine as _};
use hmac::{Hmac, Mac};
use rand::RngCore;
use sha3::Digest;
use crate::core::error2::Error;
use crate::core::error2::Result;
pub fn base64encode(s: &str) -> String {
general_purpose::STANDARD.encode(s)
}
pub fn base64decode(s: &str) -> Result<String> {
let decoded_bytes = general_purpose::STANDARD
.decode(s)
.map_err(Error::run_time)?;
let s = String::from_utf8(decoded_bytes).map_err(Error::run_time)?;
Ok(s)
}
pub fn urlencoded<T>(s: &T) -> String
where
T: serde::Serialize,
{
serde_urlencoded::to_string(s).unwrap()
}
pub fn sha3_256(s: String) -> String {
let password_hash = sha3::Sha3_256::digest(s.as_bytes());
format!("{:x}", password_hash)
}
pub fn encrypt_sha_256(key: &str, plaintext: &str) -> String {
let mut mac = hmac::Hmac::<sha2::Sha256>::new_from_slice(key.as_bytes()).unwrap();
mac.update(plaintext.as_bytes());
general_purpose::STANDARD.encode(mac.finalize().into_bytes())
}
pub fn compute_password_hash(password: &str) -> Result<String> {
let mut bytes = [0u8; Salt::RECOMMENDED_LENGTH];
let mut rng = rand::rng();
rng.fill_bytes(&mut bytes);
let salt = SaltString::encode_b64(&bytes).expect("Invalid salt encoding");
let password_hash = Argon2::new(
Algorithm::Argon2id,
Version::V0x13,
Params::new(15000, 2, 1, None).unwrap(),
)
.hash_password(password.as_bytes(), &salt)
.map_err(Error::run_time)?
.to_string();
Ok(password_hash)
}
pub fn verify_password(password: String, expected_password_hash: String) -> Result<bool> {
let expected_password_hash =
PasswordHash::new(expected_password_hash.as_str()).map_err(Error::run_time)?;
if Argon2::default()
.verify_password(password.as_bytes(), &expected_password_hash)
.is_ok()
{
return Ok(true);
}
Ok(false)
}
pub fn html_escape(s: &str) -> String {
htmlescape::encode_minimal(s)
}
#[rustfmt::skip]
pub fn hmac_tag(query_string: &str, secret: &str) -> Result<String> {
let mut mac = Hmac::<sha2::Sha256>::new_from_slice(secret.as_bytes()).map_err(Error::run_time)?;
mac.update(query_string.as_bytes());
Ok(hex::encode(mac.finalize().into_bytes()))
}
#[rustfmt::skip]
pub fn hmac_tag_verify(query_string: &str, secret: &str, tag: &str) -> Result<bool> {
let _tag = hex::decode(tag).map_err(Error::run_time)?;
let mut mac = Hmac::<sha2::Sha256>::new_from_slice(secret.as_bytes()).map_err(Error::run_time)?;
mac.update(query_string.as_bytes());
mac.verify_slice(&_tag).map_err(Error::run_time)?;
Ok(true)
}