golgi/src/blobs.rs

85 lines
2.4 KiB
Rust
Raw Normal View History

//! Blob utilities which do not require RPC calls.
//!
//! Offers the following functions:
//!
//! - [`get_blob_path()`]
2022-02-24 17:43:28 +00:00
//! - [`hash_blob()`]
use base64;
use sha2::{Digest, Sha256};
use crate::error::GolgiError;
/// Lookup the filepath for a blob.
///
/// # Example
///
/// ```rust
/// use golgi::blobs;
///
/// fn lookup_blob_path() -> Result<(), GolgiError> {
/// let blob_ref = "&JlJHc9yeG1EpZA9fIPGLzUKDH0FeR39Ai57euhKT1G8=.sha256";
///
/// let blob_path = blobs::get_blob_path(blob_ref)?;
///
/// println!("{}", blob_path);
///
/// // 26/524773dc9e1b5129640f5f20f18bcd42831f415e477f408b9edeba1293d46f
///
/// Ok(())
/// }
/// ```
pub fn get_blob_path(blob_id: &str) -> Result<String, GolgiError> {
let dot_index = blob_id.rfind('.').ok_or_else(|| {
GolgiError::SigilLink(format!(
"Invalid blob ID; no dot index was found: {}",
blob_id
))
})?;
// obtain the base64 portion (substring) of the blob id
let base64_str = &blob_id[1..dot_index];
// decode blob substring from base64 (to bytes)
let blob_bytes = base64::decode_config(base64_str, base64::STANDARD)?;
// represent the blob bytes as hex, removing all unnecessary characters
let blob_hex = format!("{:02x?}", blob_bytes)
.replace('[', "")
.replace(']', "")
.replace(',', "")
.replace(' ', "");
// split the hex representation of the decoded base64
// this is how paths are formatted for the blobstore
// e.g. 26/524773dc9e1b5129640f5f20f18bcd42831f415e477f408b9edeba1293d46f
// full path would be: `/home/user/.ssb-go/blobs/sha256/26/524773dc...`
let blob_path = format!("{}/{}", &blob_hex[..2], &blob_hex[2..]);
Ok(blob_path)
}
2022-02-24 17:43:28 +00:00
/// Hash the given blob byte slice and return the hex representation and
/// blob ID (sigil-link).
///
/// This function can be used when adding a blob to the local blobstore.
pub fn hash_blob(buffer: &[u8]) -> Result<(String, String), GolgiError> {
// hash the bytes
let hash = Sha256::digest(buffer);
// generate a hex representation of the hash
let hex_hash = format!("{:02x?}", hash)
.replace('[', "")
.replace(']', "")
.replace(',', "")
.replace(' ', "");
// encode the hash
let b64_hash = base64::encode(&hash[..]);
// format the base64 encoding as a blob sigil-link (blob id)
let blob_id = format!("&{}.sha256", b64_hash);
Ok((hex_hash, blob_id))
}