1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 03:56:01 +01:00

Introduce Hash::parseExplicitFormatUnprefixed

This commit is contained in:
John Ericson 2025-09-12 08:13:45 -04:00
parent c6d06ce486
commit 095ac66d4c
3 changed files with 87 additions and 8 deletions

View file

@ -1,13 +1,17 @@
#include <regex> #include <regex>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <nlohmann/json.hpp>
#include "nix/util/hash.hh" #include "nix/util/hash.hh"
#include "nix/util/tests/characterization.hh"
namespace nix { namespace nix {
class BLAKE3HashTest : public virtual ::testing::Test class HashTest : public CharacterizationTest
{ {
std::filesystem::path unitTestData = getUnitTestData() / "hash";
public: public:
/** /**
@ -16,8 +20,14 @@ public:
*/ */
ExperimentalFeatureSettings mockXpSettings; ExperimentalFeatureSettings mockXpSettings;
private: std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / testStem;
}
};
class BLAKE3HashTest : public HashTest
{
void SetUp() override void SetUp() override
{ {
mockXpSettings.set("experimental-features", "blake3-hashes"); mockXpSettings.set("experimental-features", "blake3-hashes");
@ -137,6 +147,46 @@ TEST(hashString, testKnownSHA512Hashes2)
"c7d329eeb6dd26545e96e55b874be909"); "c7d329eeb6dd26545e96e55b874be909");
} }
/* ----------------------------------------------------------------------------
* parsing hashes
* --------------------------------------------------------------------------*/
TEST(hashParseExplicitFormatUnprefixed, testKnownSHA256Hashes1_correct)
{
// values taken from: https://tools.ietf.org/html/rfc4634
auto s = "abc";
auto hash = hashString(HashAlgorithm::SHA256, s);
ASSERT_EQ(
hash,
Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA256,
HashFormat::Base16));
}
TEST(hashParseExplicitFormatUnprefixed, testKnownSHA256Hashes1_wrongAlgo)
{
// values taken from: https://tools.ietf.org/html/rfc4634
ASSERT_THROW(
Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA1,
HashFormat::Base16),
BadHash);
}
TEST(hashParseExplicitFormatUnprefixed, testKnownSHA256Hashes1_wrongBase)
{
// values taken from: https://tools.ietf.org/html/rfc4634
ASSERT_THROW(
Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA256,
HashFormat::Nix32),
BadHash);
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* parseHashFormat, parseHashFormatOpt, printHashFormat * parseHashFormat, parseHashFormatOpt, printHashFormat
* --------------------------------------------------------------------------*/ * --------------------------------------------------------------------------*/

View file

@ -99,22 +99,37 @@ struct DecodeNamePair
} // namespace } // namespace
static DecodeNamePair baseExplicit(HashFormat format)
{
switch (format) {
case HashFormat::Base16:
return {base16::decode, "base16"};
case HashFormat::Nix32:
return {BaseNix32::decode, "nix32"};
case HashFormat::Base64:
return {base64::decode, "Base64"};
case HashFormat::SRI:
assert(false);
}
}
/** /**
* Given the expected size of the message once decoded it, figure out * Given the expected size of the message once decoded it, figure out
* which encoding we are using by looking at the size of the encoded * which encoding we are using by looking at the size of the encoded
* message. * message.
*/ */
static DecodeNamePair baseFromSize(std::string_view rest, HashAlgorithm algo) static HashFormat baseFromSize(std::string_view rest, HashAlgorithm algo)
{ {
auto hashSize = regularHashSize(algo); auto hashSize = regularHashSize(algo);
if (rest.size() == base16::encodedLength(hashSize)) if (rest.size() == base16::encodedLength(hashSize))
return {base16::decode, "base16"}; return HashFormat::Base16;
if (rest.size() == BaseNix32::encodedLength(hashSize)) if (rest.size() == BaseNix32::encodedLength(hashSize))
return {BaseNix32::decode, "nix32"}; return HashFormat::Nix32;
if (rest.size() == base64::encodedLength(hashSize)) if (rest.size() == base64::encodedLength(hashSize))
return {base64::decode, "Base64"}; return HashFormat::Base64;
throw BadHash("hash '%s' has wrong length for hash algorithm '%s'", rest, printHashAlgo(algo)); throw BadHash("hash '%s' has wrong length for hash algorithm '%s'", rest, printHashAlgo(algo));
} }
@ -190,7 +205,7 @@ static Hash parseAnyHelper(std::string_view rest, auto resolveAlgo)
} else { } else {
/* Otherwise, decide via the length of the hash (for the /* Otherwise, decide via the length of the hash (for the
given algorithm) what base encoding it is. */ given algorithm) what base encoding it is. */
return baseFromSize(rest, algo); return baseExplicit(baseFromSize(rest, algo));
} }
}(); }();
@ -225,7 +240,12 @@ Hash Hash::parseAny(std::string_view original, std::optional<HashAlgorithm> optA
Hash Hash::parseNonSRIUnprefixed(std::string_view s, HashAlgorithm algo) Hash Hash::parseNonSRIUnprefixed(std::string_view s, HashAlgorithm algo)
{ {
return parseLowLevel(s, algo, baseFromSize(s, algo)); return parseExplicitFormatUnprefixed(s, algo, baseFromSize(s, algo));
}
Hash Hash::parseExplicitFormatUnprefixed(std::string_view s, HashAlgorithm algo, HashFormat format)
{
return parseLowLevel(s, algo, baseExplicit(format));
} }
Hash Hash::random(HashAlgorithm algo) Hash Hash::random(HashAlgorithm algo)

View file

@ -90,6 +90,15 @@ struct Hash
*/ */
static Hash parseNonSRIUnprefixed(std::string_view s, HashAlgorithm algo); static Hash parseNonSRIUnprefixed(std::string_view s, HashAlgorithm algo);
/**
* Like `parseNonSRIUnprefixed`, but the hash format has been
* explicitly given.
*
* @param explicitFormat cannot be SRI, but must be one of the
* "bases".
*/
static Hash parseExplicitFormatUnprefixed(std::string_view s, HashAlgorithm algo, HashFormat explicitFormat);
static Hash parseSRI(std::string_view original); static Hash parseSRI(std::string_view original);
public: public: