Skip to main content

snix_store/pathinfoservice/nix_http/
castore_infused.rs

1use nix_compat::{narinfo::NarInfo, nixhash::NixHash};
2use snix_castore::{
3    Node, blobservice::BlobService, directoryservice::DirectoryService,
4    proto::parse_infused_nar_path,
5};
6
7/// Try to parse the NAR URL in the Narinfo as castore-infused,
8/// return the validated root_node if successful.
9/// If the URL is not castore-infused, returns Ok(Some).
10/// The passed blob_service and directory_service need to include the gRPC
11/// castore services, so substitution of new castore data is possible.
12pub async fn try_infused_nar_path<BS, DS>(
13    narinfo: &NarInfo<'_>,
14    blob_service: BS,
15    directory_service: DS,
16) -> Result<Option<Node>, Error>
17where
18    BS: BlobService + 'static,
19    DS: DirectoryService,
20{
21    let (node, nar_size) = match parse_infused_nar_path(narinfo.url) {
22        Some(e) => e,
23        None => return Ok(None),
24    };
25
26    if nar_size != narinfo.nar_size {
27        return Err(Error::InconsistentNarSizeInURL);
28    }
29
30    // Construct a NAR Reader for the given root node
31    let mut r =
32        crate::nar::seekable::Reader::new(node.clone(), blob_service, directory_service).await?;
33
34    // Render the NAR out into a sink, while hashing and calculating nar_size at the same time.
35    let (actual_nar_hash, actual_nar_size) =
36        nix_compat::hashing::hash::<sha2::Sha256>(&mut r, tokio::io::sink()).await?;
37
38    if narinfo.nar_size != actual_nar_size {
39        return Err(Error::WrongNARSize {
40            expected: narinfo.nar_size,
41            actual: actual_nar_size,
42        });
43    }
44    if narinfo.nar_hash != actual_nar_hash.as_slice() {
45        return Err(Error::WrongNARHash {
46            expected: narinfo.nar_hash,
47            actual: actual_nar_hash.into(),
48        });
49    }
50
51    Ok(Some(node))
52}
53
54#[derive(thiserror::Error, Debug)]
55pub enum Error {
56    #[error("found infused NAR path, but with differing nar_size!")]
57    InconsistentNarSizeInURL,
58
59    #[error("failed to render NAR: {0}")]
60    RenderingNAR(#[from] crate::nar::RenderError),
61
62    #[error("failed to read NAR: {0}")]
63    IO(#[from] std::io::Error),
64
65    #[error("got unexpected NAR size while rendering NAR: {actual}, expected {expected}")]
66    WrongNARSize { expected: u64, actual: u64 },
67
68    #[error("got unexpected NAR hash while rendering NAR: {0}, expected {1}",
69        NixHash::Sha256(*actual),
70        NixHash::Sha256(*expected),
71    )]
72    WrongNARHash {
73        expected: [u8; 32],
74        actual: [u8; 32],
75    },
76}