Skip to main content

snix_store/pathinfoservice/nix_http/
castore_infused.rs

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