diff --git a/snix/nix-compat/src/nixhash/mod.rs b/snix/nix-compat/src/nixhash/mod.rs index 2be8caa10..a3c07f9b4 100644 --- a/snix/nix-compat/src/nixhash/mod.rs +++ b/snix/nix-compat/src/nixhash/mod.rs @@ -1,14 +1,13 @@ use crate::nixbase32; use bstr::ByteSlice; use data_encoding::{BASE64, BASE64_NOPAD, HEXLOWER}; -use serde::Deserialize; -use serde::Serialize; use std::cmp::Ordering; use std::fmt::Display; use thiserror; mod algos; mod ca_hash; +pub mod serde; pub use algos::HashAlgo; pub use ca_hash::CAHash; @@ -129,28 +128,6 @@ impl NixHash { } } -impl<'de> Deserialize<'de> for NixHash { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let str: &'de str = Deserialize::deserialize(deserializer)?; - from_str(str, None).map_err(|_| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"NixHash") - }) - } -} - -impl Serialize for NixHash { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let sri = self.to_sri_string(); - sri.serialize(serializer) - } -} - /// Constructs a new [NixHash] by specifying [HashAlgo] and digest. /// It can fail if the passed digest length doesn't match what's expected for /// the passed algo. diff --git a/snix/nix-compat/src/nixhash/serde.rs b/snix/nix-compat/src/nixhash/serde.rs new file mode 100644 index 000000000..8ea2975e7 --- /dev/null +++ b/snix/nix-compat/src/nixhash/serde.rs @@ -0,0 +1,89 @@ +use super::NixHash; +use crate::nixbase32; +use serde::{Deserialize, Serialize}; + +impl<'de> Deserialize<'de> for NixHash { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let str: &'de str = Deserialize::deserialize(deserializer)?; + super::from_str(str, None).map_err(|_| { + serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"NixHash") + }) + } +} + +impl Serialize for NixHash { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let sri = self.to_sri_string(); + sri.serialize(serializer) + } +} + +/// The length of a sha256 digest, nixbase32-encoded. +const NIXBASE32_SHA256_ENCODE_LEN: usize = nixbase32::encode_len(32); + +pub fn from_nix_hash_string<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> +where + D: serde::Deserializer<'de>, +{ + let str: &'de str = Deserialize::deserialize(deserializer)?; + if let Some(digest_str) = str.strip_prefix("sha256:") { + return from_nix_nixbase32_string::(digest_str); + } + if let Some(digest_str) = str.strip_prefix("sha256-") { + return from_sri_string::(digest_str); + } + Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Str(str), + &"extected a valid nixbase32 or sri narHash", + )) +} + +pub fn from_sri_string<'de, D>(str: &str) -> Result<[u8; 32], D::Error> +where + D: serde::Deserializer<'de>, +{ + let digest: [u8; 32] = data_encoding::BASE64 + .decode(str.as_bytes()) + .map_err(|_| { + serde::de::Error::invalid_value( + serde::de::Unexpected::Str(str), + &"valid base64 encoded string", + ) + })? + .try_into() + .map_err(|_| { + serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid digest len") + })?; + + Ok(digest) +} + +pub fn from_nix_nixbase32_string<'de, D>(str: &str) -> Result<[u8; 32], D::Error> +where + D: serde::Deserializer<'de>, +{ + let digest_str: [u8; NIXBASE32_SHA256_ENCODE_LEN] = + str.as_bytes().try_into().map_err(|_| { + serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid digest len") + })?; + + let digest: [u8; 32] = nixbase32::decode_fixed(digest_str).map_err(|_| { + serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid nixbase32") + })?; + + Ok(digest) +} + +pub fn to_nix_nixbase32_string(v: &[u8; 32], serializer: S) -> Result +where + S: serde::Serializer, +{ + let string = NixHash::Sha256(*v).to_nix_nixbase32_string(); + string.serialize(serializer) +} diff --git a/snix/nix-compat/src/path_info.rs b/snix/nix-compat/src/path_info.rs index 63512805f..fce9f2b1e 100644 --- a/snix/nix-compat/src/path_info.rs +++ b/snix/nix-compat/src/path_info.rs @@ -1,4 +1,4 @@ -use crate::{narinfo::SignatureRef, nixbase32, nixhash::NixHash, store_path::StorePathRef}; +use crate::{narinfo::SignatureRef, nixhash, store_path::StorePathRef}; use serde::{Deserialize, Serialize}; use std::collections::BTreeSet; @@ -14,8 +14,8 @@ pub struct ExportedPathInfo<'a> { #[serde( rename = "narHash", - serialize_with = "to_nix_nixbase32_string", - deserialize_with = "from_nix_hash_string" + serialize_with = "nixhash::serde::to_nix_nixbase32_string", + deserialize_with = "nixhash::serde::from_nix_hash_string" )] pub nar_sha256: [u8; 32], @@ -51,70 +51,6 @@ impl PartialOrd for ExportedPathInfo<'_> { } } -fn to_nix_nixbase32_string(v: &[u8; 32], serializer: S) -> Result -where - S: serde::Serializer, -{ - let string = NixHash::Sha256(*v).to_nix_nixbase32_string(); - string.serialize(serializer) -} - -/// The length of a sha256 digest, nixbase32-encoded. -const NIXBASE32_SHA256_ENCODE_LEN: usize = nixbase32::encode_len(32); - -fn from_nix_hash_string<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> -where - D: serde::Deserializer<'de>, -{ - let str: &'de str = Deserialize::deserialize(deserializer)?; - if let Some(digest_str) = str.strip_prefix("sha256:") { - return from_nix_nixbase32_string::(digest_str); - } - if let Some(digest_str) = str.strip_prefix("sha256-") { - return from_sri_string::(digest_str); - } - Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Str(str), - &"extected a valid nixbase32 or sri narHash", - )) -} - -fn from_sri_string<'de, D>(str: &str) -> Result<[u8; 32], D::Error> -where - D: serde::Deserializer<'de>, -{ - let digest: [u8; 32] = data_encoding::BASE64 - .decode(str.as_bytes()) - .map_err(|_| { - serde::de::Error::invalid_value( - serde::de::Unexpected::Str(str), - &"valid base64 encoded string", - ) - })? - .try_into() - .map_err(|_| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid digest len") - })?; - - Ok(digest) -} - -fn from_nix_nixbase32_string<'de, D>(str: &str) -> Result<[u8; 32], D::Error> -where - D: serde::Deserializer<'de>, -{ - let digest_str: [u8; NIXBASE32_SHA256_ENCODE_LEN] = - str.as_bytes().try_into().map_err(|_| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid digest len") - })?; - - let digest: [u8; 32] = nixbase32::decode_fixed(digest_str).map_err(|_| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid nixbase32") - })?; - - Ok(digest) -} - #[cfg(test)] mod tests { use hex_literal::hex;