walker_common/source/
file.rs

1use crate::retrieve::RetrievedDigest;
2use anyhow::anyhow;
3use bytes::Bytes;
4use digest::Digest;
5use futures_util::try_join;
6use sha2::{Sha256, Sha512};
7use std::io::ErrorKind;
8use std::path::{Path, PathBuf};
9use url::Url;
10
11pub async fn read_optional(path: impl AsRef<Path>) -> Result<Option<String>, anyhow::Error> {
12    match tokio::fs::read_to_string(path).await {
13        Ok(data) => Ok(Some(data)),
14        Err(err) if err.kind() == ErrorKind::NotFound => Ok(None),
15        Err(err) => Err(err.into()),
16    }
17}
18
19pub fn to_path(url: &Url) -> Result<PathBuf, anyhow::Error> {
20    url.to_file_path()
21        .map_err(|()| anyhow!("Failed to convert URL to path: {url}"))
22}
23
24/// Read the signature file and digests
25///
26/// The expected locations are:
27/// * `{base}.asc`
28/// * `{base}.sha256`
29/// * `{base}.sha512`
30pub async fn read_sig_and_digests(
31    path: &Path,
32    data: &Bytes,
33) -> anyhow::Result<(
34    Option<String>,
35    Option<RetrievedDigest<Sha256>>,
36    Option<RetrievedDigest<Sha512>>,
37)> {
38    let (signature, sha256, sha512) = try_join!(
39        read_optional(format!("{}.asc", path.display())),
40        read_optional(format!("{}.sha256", path.display())),
41        read_optional(format!("{}.sha512", path.display())),
42    )?;
43
44    let sha256 = sha256
45        // take the first "word" from the line
46        .and_then(|expected| expected.split(' ').next().map(ToString::to_string))
47        .map(|expected| {
48            let mut actual = Sha256::new();
49            actual.update(data);
50            RetrievedDigest::<Sha256> {
51                expected,
52                actual: actual.finalize(),
53            }
54        });
55
56    let sha512 = sha512
57        // take the first "word" from the line
58        .and_then(|expected| expected.split(' ').next().map(ToString::to_string))
59        .map(|expected| {
60            let mut actual = Sha512::new();
61            actual.update(data);
62            RetrievedDigest::<Sha512> {
63                expected,
64                actual: actual.finalize(),
65            }
66        });
67
68    Ok((signature, sha256, sha512))
69}