use super::checksum_error::ProtoChecksumError;
use sha2::{Digest, Sha256, Sha512};
use starbase_utils::fs::{self, FsError};
use std::io;
use std::io::{BufRead, BufReader};
use std::path::Path;
use tracing::trace;
pub fn hash_file_contents_sha256<P: AsRef<Path>>(path: P) -> Result<String, FsError> {
let path = path.as_ref();
trace!(file = ?path, "Calculating SHA256 checksum");
let mut file = fs::open_file(path)?;
let mut sha = Sha256::new();
io::copy(&mut file, &mut sha).map_err(|error| FsError::Read {
path: path.to_path_buf(),
error: Box::new(error),
})?;
let hash = format!("{:x}", sha.finalize());
trace!(hash, "Calculated hash");
Ok(hash)
}
pub fn hash_file_contents_sha512<P: AsRef<Path>>(path: P) -> Result<String, FsError> {
let path = path.as_ref();
trace!(file = ?path, "Calculating SHA512 checksum");
let mut file = fs::open_file(path)?;
let mut sha = Sha512::new();
io::copy(&mut file, &mut sha).map_err(|error| FsError::Read {
path: path.to_path_buf(),
error: Box::new(error),
})?;
let hash = format!("{:x}", sha.finalize());
trace!(hash, "Calculated hash");
Ok(hash)
}
#[tracing::instrument(name = "verify_sha_checksum")]
pub fn verify_checksum(
download_file: &Path,
checksum_file: &Path,
checksum_hash: &str,
) -> Result<bool, ProtoChecksumError> {
let download_file_name = fs::file_name(download_file);
for line in
BufReader::new(
fs::open_file(checksum_file).map_err(|error| ProtoChecksumError::Sha {
error: Box::new(error),
})?,
)
.lines()
.map_while(Result::ok)
{
if line.is_empty() {
continue;
}
if line == checksum_hash
|| (line.starts_with(checksum_hash) && line.ends_with(&download_file_name))
{
return Ok(true);
}
if line.starts_with("Hash")
&& let Some((_, hash)) = line.split_once(':')
{
return Ok(hash.trim().to_lowercase() == checksum_hash);
}
}
Ok(false)
}