From adbdf80c0e9e3b4bc44a9e08eb9f8c1d40048a4b Mon Sep 17 00:00:00 2001 From: SFG545 Date: Tue, 10 Mar 2026 14:00:03 -0500 Subject: [PATCH] feat: update package dependencies and enhance checksum verification with b2 and b2sum support --- Cargo.lock | 63 ++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- meson.build | 2 +- src/package/interactive.rs | 4 +-- src/package/spec.rs | 2 +- src/source/fetcher.rs | 8 ++++- src/source/mod.rs | 12 +++++++- 7 files changed, 85 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e66ad33..6b0e48f 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,15 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -117,6 +126,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "b2sum-rust" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb61f898a93d8be6d66a811812e9c12671e662910daf0e83aa15899f656260d" +dependencies = [ + "blake2-rfc", + "filebuffer", + "hex", +] + [[package]] name = "base64" version = "0.22.1" @@ -129,6 +149,16 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +dependencies = [ + "arrayvec", + "constant_time_eq 0.1.5", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -282,6 +312,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -382,10 +418,11 @@ checksum = "807800ff3288b621186fe0a8f3392c4652068257302709c24efd918c3dffcdc2" [[package]] name = "depot" -version = "0.13.0" +version = "0.13.1" dependencies = [ "anyhow", "ar", + "b2sum-rust", "bzip2", "clap", "clap_complete", @@ -548,6 +585,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "filebuffer" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b41bfe1d74263ea9d084be951077614b3b98b4e59a9dafab1467645a9e52305" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "filetime" version = "0.2.27" @@ -774,6 +821,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hmac" version = "0.12.1" @@ -1340,6 +1393,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + [[package]] name = "num-conv" version = "0.2.0" @@ -3012,7 +3071,7 @@ checksum = "b680f2a0cd479b4cff6e1233c483fdead418106eae419dc60200ae9850f6d004" dependencies = [ "aes", "bzip2", - "constant_time_eq", + "constant_time_eq 0.4.2", "crc32fast", "deflate64", "flate2", diff --git a/Cargo.toml b/Cargo.toml index eacd939..60f9972 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "depot" -version = "0.13.0" +version = "0.13.1" edition = "2024" [lints.rust] @@ -41,6 +41,7 @@ clap_complete = "4.5.66" clap_mangen = "0.2.31" sys-mount = { version = "3.1.0", default-features = false } time = { version = "0.3.47", features = ["formatting", "parsing"] } +b2sum-rust = "0.3.0" [dev-dependencies] tempfile = "=3.26.0" diff --git a/meson.build b/meson.build index 472982b..e01cbc9 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'depot', - version: '0.13.0', + version: '0.13.1', meson_version: '>=0.60.0', ) diff --git a/src/package/interactive.rs b/src/package/interactive.rs index 62cc86e..4650a60 100644 --- a/src/package/interactive.rs +++ b/src/package/interactive.rs @@ -217,7 +217,7 @@ fn prompt_manual_sources() -> Result> { if single_entry { let checksum = prompt_optional_text( "Manual source checksum (optional):", - "sha256:/sha512:/md5:, raw SHA256 hex, or 'skip' (empty omits field)", + "sha256:/sha512:/md5:/b2:/b2sum:, raw SHA256 hex, or 'skip' (empty omits field)", )?; if !checksum.is_empty() { manual.sha256 = Some(checksum); @@ -411,7 +411,7 @@ pub fn create_interactive() -> Result { let source_sha256 = Text::new("Source checksum:") .with_help_message( - "Accepts sha256:, sha512:, md5:, or raw SHA256 hex (use 'skip' to bypass)", + "Accepts sha256:, sha512:, md5:, b2:, b2sum:, or raw SHA256 hex (use 'skip' to bypass)", ) .with_default(computed_sha_default.as_str()) .prompt()?; diff --git a/src/package/spec.rs b/src/package/spec.rs index 44a4ed1..77735a2 100755 --- a/src/package/spec.rs +++ b/src/package/spec.rs @@ -3078,7 +3078,7 @@ pub struct Alternatives { #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct Source { pub url: String, - /// Checksum for the source (e.g. `sha256:...`, `sha512:...`, `md5:...`, or raw SHA256 hex). + /// Checksum for the source (e.g. `sha256:...`, `sha512:...`, `md5:...`, `b2:...`, `b2sum:...`, or raw SHA256 hex). /// Defaults to `skip` when omitted. #[serde(default = "default_source_sha256")] pub sha256: String, diff --git a/src/source/fetcher.rs b/src/source/fetcher.rs index 2b10675..6ff9b15 100755 --- a/src/source/fetcher.rs +++ b/src/source/fetcher.rs @@ -290,6 +290,7 @@ pub fn fetch_archive(spec: &PackageSpec, source: &Source, cache_dir: &Path) -> R /// - `sha256:` (or just `` — default) /// - `sha512:` /// - `md5:` +/// - `b2:` / `b2sum:` /// - `skip` to bypass verification fn verify_checksum(path: &Path, expected: &str) -> Result { // Delegate to the shared checker in the parent `source` module. @@ -731,7 +732,7 @@ mod tests { } #[test] - fn verify_checksum_accepts_md5_sha512_and_default_sha256() { + fn verify_checksum_accepts_md5_sha512_b2sum_and_default_sha256() { use sha2::Digest; use sha2::Sha256; use sha2::Sha512; @@ -753,6 +754,9 @@ mod tests { }; let md5_hex = format!("{:x}", md5::compute(b"abc")); + let b2_hex = b2sum_rust::Blake2bSum::new(64) + .read(tmp.path()) + .to_ascii_lowercase(); // unprefixed should default to sha256 assert!(verify_checksum(tmp.path(), &sha256_hex).unwrap()); @@ -760,6 +764,8 @@ mod tests { assert!(verify_checksum(tmp.path(), &format!("sha256:{}", sha256_hex)).unwrap()); assert!(verify_checksum(tmp.path(), &format!("sha512:{}", sha512_hex)).unwrap()); assert!(verify_checksum(tmp.path(), &format!("md5:{}", md5_hex)).unwrap()); + assert!(verify_checksum(tmp.path(), &format!("b2:{}", b2_hex)).unwrap()); + assert!(verify_checksum(tmp.path(), &format!("b2sum:{}", b2_hex)).unwrap()); // empty algorithm before colon -> assume sha256 assert!(verify_checksum(tmp.path(), &format!(":{}", sha256_hex)).unwrap()); // negative: wrong value fails diff --git a/src/source/mod.rs b/src/source/mod.rs index fa3f595..02e9b27 100755 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -181,7 +181,8 @@ fn copy_manual_source_file( /// Verify a file against an `expected` checksum string. /// -/// Formats accepted: `sha256:HEX`, `sha512:HEX`, `md5:HEX`, or plain `HEX` (assumed sha256). +/// Formats accepted: `sha256:HEX`, `sha512:HEX`, `md5:HEX`, `b2:HEX`, +/// `b2sum:HEX`, or plain `HEX` (assumed sha256). fn verify_file_hash(path: &Path, expected: &str) -> Result { use anyhow::bail; use std::io::Read; @@ -251,6 +252,10 @@ fn verify_file_hash(path: &Path, expected: &str) -> Result { let actual = format!("{:x}", digest); Ok(actual == hex) } + "b2" | "b2sum" => { + let actual = b2sum_rust::Blake2bSum::new(64).read(path); + Ok(actual.eq_ignore_ascii_case(&hex)) + } _ => bail!("Unsupported checksum algorithm: {}", alg), } } @@ -716,11 +721,16 @@ mod tests { format!("{:x}", h.finalize()) }; let md5_hex = format!("{:x}", md5::compute(b"abc")); + let b2_hex = b2sum_rust::Blake2bSum::new(64) + .read(tmp.path()) + .to_ascii_lowercase(); assert!(verify_file_hash(tmp.path(), &sha256_hex).unwrap()); assert!(verify_file_hash(tmp.path(), &format!("sha256:{}", sha256_hex)).unwrap()); assert!(verify_file_hash(tmp.path(), &format!("sha512:{}", sha512_hex)).unwrap()); assert!(verify_file_hash(tmp.path(), &format!("md5:{}", md5_hex)).unwrap()); + assert!(verify_file_hash(tmp.path(), &format!("b2:{}", b2_hex)).unwrap()); + assert!(verify_file_hash(tmp.path(), &format!("b2sum:{}", b2_hex)).unwrap()); assert!(verify_file_hash(tmp.path(), &format!(":{}", sha256_hex)).unwrap()); assert!(!verify_file_hash(tmp.path(), "md5:deadbeef").unwrap()); }