Skip to content

Commit

Permalink
Convert FileDigest to struct to simplify implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
dralley committed Oct 30, 2023
1 parent 13ef6f4 commit 30ce4b3
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 50 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Bumped MSRV to 1.67

### Changed

- Converted support for validating file capabilities with `capctl` into an optional feature `validate_caps`.

### Removed

- Removed `Package::get_file_checksums` and `Package::get_file_ima_signatures` functions, the same information is now retrievable using `Package::get_file_entries`.
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ itertools = "0.11"
hex = { version = "0.4", features = ["std"] }
zstd = "0.13"
xz2 = "0.1"
capctl = "0.2.3"
capctl = { version = "0.2.3", optional = true }

[dev-dependencies]
env_logger = "0.10.0"
Expand All @@ -67,6 +67,7 @@ default = ["signature-pgp"]

signature-pgp = ["signature-meta", "pgp", "chrono"]
signature-meta = []
validate_caps = ["capctl"]

# Segregate tests that require podman to be installed
test-with-podman = ["signature-pgp"]
2 changes: 1 addition & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ bitflags! {
// should be equivalent the value mapping used by `pgp::crypto::hash::HashAlgorithm`
// but we have to copy it as not everyone uses the `signature` feature
#[repr(u32)]
#[derive(Debug, Clone, Copy, enum_primitive_derive::Primitive)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, enum_primitive_derive::Primitive)]
pub enum DigestAlgorithm {
Md5 = 1,
Sha2_256 = 8,
Expand Down
54 changes: 21 additions & 33 deletions src/rpm/headers/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,56 +383,44 @@ pub struct FileOwnership {
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum FileDigest {
Md5(Vec<u8>),
Sha2_224(Vec<u8>),
Sha2_256(Vec<u8>),
Sha2_384(Vec<u8>),
Sha2_512(Vec<u8>),
// @todo unsupported other types for now
pub struct FileDigest {
digest: String,
algo: DigestAlgorithm,
}

impl FileDigest {
pub fn load_from_str(
algorithm: DigestAlgorithm,
stringly_data: impl AsRef<str>,
) -> Result<Self, Error> {
let hex: Vec<u8> = hex::decode(stringly_data.as_ref())?;
pub(crate) fn new(algorithm: DigestAlgorithm, hex_digest: impl Into<String>) -> Result<Self, Error> {
let hex = hex_digest.into();
let digest = FileDigest {
digest: hex,
algo: algorithm,
};

Ok(match algorithm {
DigestAlgorithm::Md5 if hex.len() == 16 => FileDigest::Md5(hex),
DigestAlgorithm::Sha2_256 if hex.len() == 32 => FileDigest::Sha2_256(hex),
DigestAlgorithm::Sha2_224 if hex.len() == 30 => FileDigest::Sha2_224(hex),
DigestAlgorithm::Sha2_384 if hex.len() == 48 => FileDigest::Sha2_384(hex),
DigestAlgorithm::Sha2_512 if hex.len() == 64 => FileDigest::Sha2_512(hex),
DigestAlgorithm::Md5 if digest.digest.len() == 32 => digest,
DigestAlgorithm::Sha2_256 if digest.digest.len() == 64 => digest,
DigestAlgorithm::Sha2_224 if digest.digest.len() == 60 => digest,
DigestAlgorithm::Sha2_384 if digest.digest.len() == 96 => digest,
DigestAlgorithm::Sha2_512 if digest.digest.len() == 128 => digest,
// @todo disambiguate mismatch of length from unsupported algorithm
digest_algo => return Err(Error::UnsupportedDigestAlgorithm(digest_algo)),
})
}

/// Return the algorithm that was used for this digest.
pub fn algorithm(&self) -> DigestAlgorithm {
match self {
Self::Md5(_) => DigestAlgorithm::Md5,
Self::Sha2_224(_) => DigestAlgorithm::Sha2_224,
Self::Sha2_256(_) => DigestAlgorithm::Sha2_256,
Self::Sha2_384(_) => DigestAlgorithm::Sha2_384,
Self::Sha2_512(_) => DigestAlgorithm::Sha2_512,
}
self.algo
}

pub fn as_hex(&self) -> String {
match self {
Self::Md5(d) => hex::encode(d),
Self::Sha2_224(d) => hex::encode(d),
Self::Sha2_256(d) => hex::encode(d),
Self::Sha2_384(d) => hex::encode(d),
Self::Sha2_512(d) => hex::encode(d),
}
/// Return the digest
pub fn as_hex(&self) -> &str {
self.digest.as_str()
}
}

impl Display for FileDigest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.as_hex())
f.write_str(self.as_hex())
}
}

Expand Down
27 changes: 15 additions & 12 deletions src/rpm/headers/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! A collection of types used in various header records.
use std::str::FromStr;

use crate::{constants::*, errors, Timestamp};
#[cfg(feature = "validate_caps")]
use capctl::FileCaps;
use digest::Digest;

Expand All @@ -28,7 +27,7 @@ pub struct PackageFileEntry {
pub group: String,
pub base_name: String,
pub dir: String,
pub caps: Option<FileCaps>,
pub caps: Option<String>,
pub(crate) content: Vec<u8>,
}

Expand Down Expand Up @@ -198,7 +197,7 @@ pub struct FileOptions {
pub(crate) mode: FileMode,
pub(crate) flag: FileFlags,
pub(crate) inherit_permissions: bool,
pub(crate) caps: Option<FileCaps>,
pub(crate) caps: Option<String>,
}

impl FileOptions {
Expand Down Expand Up @@ -247,15 +246,19 @@ impl FileOptionsBuilder {
}

pub fn caps(mut self, caps: impl Into<String>) -> Result<Self, errors::Error> {
let caps = caps.into();

// verify capabilities
self.inner.caps = match FileCaps::from_str(&caps.into()) {
Ok(caps) => Some(caps),
Err(e) => {
return Err(errors::Error::InvalidCapabilities {
caps: e.to_string(),
})
}
};
#[cfg(feature = "validate_caps")]
if FileCaps::from_str(&caps).is_err() {
use std::str::FromStr;

return Err(errors::Error::InvalidCapabilities {
caps: e.to_string(),
});
}

self.inner.caps = Some(caps);
Ok(self)
}

Expand Down
2 changes: 1 addition & 1 deletion src/rpm/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ impl PackageMetadata {
let digest = if digest.is_empty() {
None
} else {
Some(FileDigest::load_from_str(algorithm, digest)?)
Some(FileDigest::new(algorithm, digest)?)
};
let cap = match caps {
Some(caps) => caps.get(idx).map(|x| x.to_owned()),
Expand Down
8 changes: 6 additions & 2 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,12 @@ fn test_rpm_header() -> Result<(), Box<dyn std::error::Error>> {
let checksums: Vec<_> = metadata
.get_file_entries()?
.iter()
.map(|e| e.digest.as_ref().map(|d| d.to_string()))
.map(|d| d.unwrap_or("".to_owned()))
.map(|e| {
e.digest
.as_ref()
.map(|d| d.to_string())
.unwrap_or("".to_owned())
})
.collect();
assert_eq!(expected_file_checksums, checksums);

Expand Down

0 comments on commit 30ce4b3

Please sign in to comment.