Skip to content

Commit f596df5

Browse files
Merge pull request #15 from theseus-rs/refactor-archive-integrity-checks
refactor!: remove archive hash from the public interface and always calculate/verify the has when requesting an archive
2 parents 8bf1db5 + 7c4bd40 commit f596df5

File tree

15 files changed

+42
-83
lines changed

15 files changed

+42
-83
lines changed

Cargo.lock

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/archive_async/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use postgresql_archive::{extract, get_archive, Result, LATEST};
22

33
#[tokio::main]
44
async fn main() -> Result<()> {
5-
let (archive_version, archive, _hash) = get_archive(&LATEST).await?;
5+
let (archive_version, archive) = get_archive(&LATEST).await?;
66
let out_dir = tempfile::tempdir()?.into_path();
77
extract(&archive, &out_dir).await?;
88
println!(

examples/archive_sync/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use postgresql_archive::blocking::{extract, get_archive};
22
use postgresql_archive::{Result, LATEST};
33

44
fn main() -> Result<()> {
5-
let (archive_version, archive, _hash) = get_archive(&LATEST)?;
5+
let (archive_version, archive) = get_archive(&LATEST)?;
66
let out_dir = tempfile::tempdir()?.into_path();
77
extract(&archive, &out_dir)?;
88
println!(

postgresql_archive/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ version.workspace = true
1313
anyhow = { workspace = true }
1414
bytes = { workspace = true }
1515
flate2 = { workspace = true }
16+
hex = { workspace = true }
1617
human_bytes = { workspace = true }
1718
lazy_static = { workspace = true }
1819
num-format = { workspace = true }

postgresql_archive/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use postgresql_archive::{extract, get_archive, Result, LATEST};
1919

2020
#[tokio::main]
2121
async fn main() -> Result<()> {
22-
let (archive_version, archive, hash) = get_archive(&LATEST).await?;
22+
let (archive_version, archive) = get_archive(&LATEST).await?;
2323
let out_dir = std::env::temp_dir();
2424
extract(&archive, &out_dir).await
2525
}
@@ -31,7 +31,7 @@ use postgresql_archive::{Result, LATEST};
3131
use postgresql_archive::blocking::{extract, get_archive};
3232

3333
fn main() -> Result<()> {
34-
let (archive_version, archive, hash) = get_archive(&LATEST)?;
34+
let (archive_version, archive) = get_archive(&LATEST)?;
3535
let out_dir = std::env::temp_dir();
3636
extract(&archive, &out_dir)
3737
}

postgresql_archive/src/archive.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ use crate::error::Error::{AssetHashNotFound, AssetNotFound, ReleaseNotFound, Une
44
use crate::error::Result;
55
use crate::github::{Asset, Release};
66
use crate::version::Version;
7+
use crate::Error::ArchiveHashMismatch;
78
use bytes::Bytes;
89
use flate2::bufread::GzDecoder;
910
use human_bytes::human_bytes;
1011
use num_format::{Locale, ToFormattedString};
1112
use regex::Regex;
1213
use reqwest::header::HeaderMap;
1314
use reqwest::{header, RequestBuilder};
15+
use sha2::{Digest, Sha256};
1416
use std::fs::{create_dir_all, File};
1517
use std::io::{copy, BufReader, Cursor};
1618
use std::path::Path;
@@ -179,8 +181,8 @@ async fn get_asset<S: AsRef<str>>(version: &Version, target: S) -> Result<(Versi
179181
/// If the [version](Version) is not found for this target, then an
180182
/// [error](crate::error::Error) is returned.
181183
///
182-
/// Returns the archive bytes and the archive hash.
183-
pub async fn get_archive(version: &Version) -> Result<(Version, Bytes, String)> {
184+
/// Returns the archive version and bytes.
185+
pub async fn get_archive(version: &Version) -> Result<(Version, Bytes)> {
184186
get_archive_for_target(version, target_triple::TARGET).await
185187
}
186188

@@ -189,11 +191,11 @@ pub async fn get_archive(version: &Version) -> Result<(Version, Bytes, String)>
189191
/// If the [version](Version) or [target](https://doc.rust-lang.org/nightly/rustc/platform-support.html)
190192
/// is not found, then an [error](crate::error::Error) is returned.
191193
///
192-
/// Returns the archive bytes and the archive hash.
194+
/// Returns the archive version and bytes.
193195
pub async fn get_archive_for_target<S: AsRef<str>>(
194196
version: &Version,
195197
target: S,
196-
) -> Result<(Version, Bytes, String)> {
198+
) -> Result<(Version, Bytes)> {
197199
let (asset_version, asset, asset_hash) = get_asset(version, target).await?;
198200

199201
debug!(
@@ -229,7 +231,15 @@ pub async fn get_archive_for_target<S: AsRef<str>>(
229231
human_bytes(archive.len() as f64)
230232
);
231233

232-
Ok((asset_version, archive, hash))
234+
let mut hasher = Sha256::new();
235+
hasher.update(&archive);
236+
let archive_hash = hex::encode(hasher.finalize());
237+
238+
if archive_hash != hash {
239+
return Err(ArchiveHashMismatch { archive_hash, hash });
240+
}
241+
242+
Ok((asset_version, archive))
233243
}
234244

235245
/// Extracts the compressed tar [bytes](Bytes) to the [out_dir](Path).

postgresql_archive/src/blocking/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pub fn get_version(version: &Version) -> crate::Result<Version> {
2020
/// If the [version](Version) is not found for this target, then an
2121
/// [error](crate::Error) is returned.
2222
///
23-
/// Returns the archive bytes and the archive hash.
24-
pub fn get_archive(version: &Version) -> crate::Result<(Version, Bytes, String)> {
23+
/// Returns the archive version and bytes.
24+
pub fn get_archive(version: &Version) -> crate::Result<(Version, Bytes)> {
2525
RUNTIME
2626
.handle()
2727
.block_on(async move { crate::get_archive(version).await })
@@ -32,11 +32,11 @@ pub fn get_archive(version: &Version) -> crate::Result<(Version, Bytes, String)>
3232
/// If the [version](Version) or [target](https://doc.rust-lang.org/nightly/rustc/platform-support.html)
3333
/// is not found, then an [error](crate::error::Error) is returned.
3434
///
35-
/// Returns the archive bytes and the archive hash.
35+
/// Returns the archive version and bytes.
3636
pub fn get_archive_for_target<S: AsRef<str>>(
3737
version: &Version,
3838
target: S,
39-
) -> crate::Result<(Version, Bytes, String)> {
39+
) -> crate::Result<(Version, Bytes)> {
4040
RUNTIME
4141
.handle()
4242
.block_on(async move { crate::get_archive_for_target(version, target).await })

postgresql_archive/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ pub enum Error {
1010
/// Asset hash not found
1111
#[error("asset hash not found for asset [{0}]")]
1212
AssetHashNotFound(String),
13+
/// Error when the hash of the archive does not match the expected hash
14+
#[error("Archive hash [{archive_hash}] does not match expected hash [{hash}]")]
15+
ArchiveHashMismatch { archive_hash: String, hash: String },
1316
/// Invalid version
1417
#[error("version [{0}] is invalid")]
1518
InvalidVersion(String),

postgresql_archive/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
//!
2525
//! #[tokio::main]
2626
//! async fn main() -> Result<()> {
27-
//! let (archive_version, archive, hash) = get_archive(&LATEST).await?;
27+
//! let (archive_version, archive) = get_archive(&LATEST).await?;
2828
//! let out_dir = std::env::temp_dir();
2929
//! extract(&archive, &out_dir).await
3030
//! }
@@ -36,7 +36,7 @@
3636
//! use postgresql_archive::LATEST;
3737
//! use postgresql_archive::blocking::{extract, get_archive};
3838
//!
39-
//! let (archive_version, archive, hash) = get_archive(&LATEST).unwrap();
39+
//! let (archive_version, archive) = get_archive(&LATEST).unwrap();
4040
//! let out_dir = std::env::temp_dir();
4141
//! let result = extract(&archive, &out_dir).unwrap();
4242
//! }

postgresql_archive/tests/archive.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
#[allow(deprecated)]
22
use postgresql_archive::{extract, Version, LATEST, V12, V13, V14, V15, V16};
33
use postgresql_archive::{get_archive, get_archive_for_target, get_version};
4-
use sha2::{Digest, Sha256};
54
use std::fs::{create_dir_all, remove_dir_all};
65
use test_log::test;
76

87
async fn test_get_archive_for_version_constant(version: Version) -> anyhow::Result<()> {
9-
let (_, archive, hash) = get_archive(&version).await?;
10-
11-
let mut hasher = Sha256::new();
12-
hasher.update(&archive);
13-
let archive_hash = hex::encode(&hasher.finalize());
14-
15-
assert_eq!(archive_hash, hash);
8+
let (_archive_version, _archive) = get_archive(&version).await?;
169
Ok(())
1710
}
1811

@@ -69,13 +62,8 @@ async fn test_get_version() -> anyhow::Result<()> {
6962
#[test(tokio::test)]
7063
async fn test_get_archive_and_extract() -> anyhow::Result<()> {
7164
let version = &LATEST;
72-
let (archive_version, archive, hash) = get_archive(version).await?;
65+
let (archive_version, archive) = get_archive(version).await?;
7366

74-
let mut hasher = Sha256::new();
75-
hasher.update(&archive);
76-
let archive_hash = hex::encode(&hasher.finalize());
77-
78-
assert_eq!(archive_hash, hash);
7967
assert!(archive_version.matches(version));
8068

8169
let out_dir = tempfile::tempdir()?.path().to_path_buf();
@@ -112,14 +100,9 @@ async fn test_get_archive_for_target_target_not_found() -> postgresql_archive::R
112100
#[test(tokio::test)]
113101
async fn test_get_archive_for_target() -> anyhow::Result<()> {
114102
let version = &LATEST;
115-
let (archive_version, archive, hash) =
103+
let (archive_version, _archive) =
116104
get_archive_for_target(version, target_triple::TARGET).await?;
117105

118-
let mut hasher = Sha256::new();
119-
hasher.update(&archive);
120-
let archive_hash = hex::encode(&hasher.finalize());
121-
122-
assert_eq!(archive_hash, hash);
123106
assert!(archive_version.matches(version));
124107

125108
Ok(())

0 commit comments

Comments
 (0)