diff --git a/snix/castore/src/digests.rs b/snix/castore/src/digests.rs index 9f94c811c..4ce14c26c 100644 --- a/snix/castore/src/digests.rs +++ b/snix/castore/src/digests.rs @@ -1,5 +1,6 @@ use bytes::Bytes; use data_encoding::BASE64; +use std::str::FromStr; use thiserror::Error; #[derive(PartialEq, Eq, Hash)] @@ -15,6 +16,8 @@ impl B3Digest { pub enum Error { #[error("invalid digest length: {0}")] InvalidDigestLen(usize), + #[error("invalid hash type: expected a 'blake3-' prefixed digest")] + InvalidHashType, } impl AsRef<[u8; B3Digest::LENGTH]> for B3Digest { @@ -109,3 +112,18 @@ impl std::fmt::Debug for B3Digest { BASE64.encode_write(&self.0, f) } } + +impl FromStr for B3Digest { + type Err = Error; + + fn from_str(s: &str) -> Result { + if !s.starts_with("blake3-") { + return Err(Error::InvalidHashType); + } + let encoded = &s[7..]; + let decoded = BASE64 + .decode(encoded.as_bytes()) + .map_err(|_| Error::InvalidDigestLen(s.len()))?; + decoded.as_slice().try_into() + } +} diff --git a/snix/castore/src/errors.rs b/snix/castore/src/errors.rs index 23b4822bf..912bf22c3 100644 --- a/snix/castore/src/errors.rs +++ b/snix/castore/src/errors.rs @@ -27,12 +27,16 @@ pub enum ValidateNodeError { /// Invalid symlink target #[error("Invalid symlink target: {0}")] InvalidSymlinkTarget(SymlinkTargetError), + /// Invalid hash type encountered + #[error("invalid hash type: expected a 'blake3-' prefixed digest")] + InvalidHashType, } impl From for ValidateNodeError { fn from(e: crate::digests::Error) -> Self { match e { crate::digests::Error::InvalidDigestLen(n) => ValidateNodeError::InvalidDigestLen(n), + crate::digests::Error::InvalidHashType => ValidateNodeError::InvalidHashType, } } }