Skip to content

Commit 0099f6d

Browse files
committed
Add mkNamedDigest to parse text digests
1 parent 73b0926 commit 0099f6d

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

hnix-store-core/src/System/Nix/Hash.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module System.Nix.Hash (
1010
, HNix.SomeNamedDigest(..)
1111
, HNix.hash
1212
, HNix.hashLazy
13+
, HNix.mkNamedDigest
1314

1415
, HNix.encodeBase32
1516
, HNix.decodeBase32

hnix-store-core/src/System/Nix/Internal/Hash.hs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ data HashAlgorithm
4444

4545
-- | The result of running a 'HashAlgorithm'.
4646
newtype Digest (a :: HashAlgorithm) =
47-
Digest BS.ByteString deriving (Show, Eq, Ord, DataHashable.Hashable)
47+
Digest BS.ByteString deriving (Eq, Ord, DataHashable.Hashable)
48+
49+
instance Show (Digest a) where
50+
show = ("Digest " ++) . show . encodeBase32
4851

4952
-- | The primitive interface for incremental hashing for a given
5053
-- 'HashAlgorithm'. Every 'HashAlgorithm' should have an instance.
@@ -63,18 +66,52 @@ class ValidAlgo (a :: HashAlgorithm) where
6366
-- purposes (e.g. SRI hashes)
6467
class NamedAlgo (a :: HashAlgorithm) where
6568
algoName :: Text
69+
hashSize :: Int
6670

6771
instance NamedAlgo 'MD5 where
6872
algoName = "md5"
73+
hashSize = 16
6974

7075
instance NamedAlgo 'SHA1 where
7176
algoName = "sha1"
77+
hashSize = 20
7278

7379
instance NamedAlgo 'SHA256 where
7480
algoName = "sha256"
81+
hashSize = 32
82+
83+
{-
84+
instance NamedAlgo 'SHA512 where
85+
algoName = "sha512"
86+
hashSize = 64
87+
-}
7588

7689
-- | A digest whose 'NamedAlgo' is not known at compile time.
77-
data SomeNamedDigest = forall a . NamedAlgo a => SomeDigest (Digest a)
90+
data SomeNamedDigest = forall a . (NamedAlgo a, ValidAlgo a) => SomeDigest (Digest a)
91+
92+
instance Show SomeNamedDigest where
93+
show sd = case sd of
94+
SomeDigest (digest :: Digest hashType) -> T.unpack $ "SomeDigest " <> algoName @hashType <> ":" <> encodeBase32 digest
95+
96+
mkNamedDigest :: Text -> Text -> Either String SomeNamedDigest
97+
mkNamedDigest name hash = case name of
98+
"md5" -> SomeDigest <$> decode @'MD5
99+
"sha1" -> SomeDigest <$> decode @'SHA1
100+
"sha256" -> SomeDigest <$> decode @'SHA256
101+
_ -> Left $ "Unknown hash name: " ++ T.unpack name
102+
where
103+
size = T.length hash
104+
decode :: forall a . (NamedAlgo a, ValidAlgo a) => Either String (Digest a)
105+
decode
106+
| size == base16Len = decodeBase16 hash
107+
| size == base32Len = decodeBase32 hash
108+
-- | size == base64Len = decodeBase64 s -- TODO
109+
| otherwise = Left $ T.unpack hash ++ " is not a valid " ++ T.unpack name ++ " hash."
110+
where
111+
hsize = hashSize @a
112+
base16Len = hsize * 2
113+
base32Len = ((hsize * 8 - 1) `div` 5) + 1;
114+
-- base64Len = ((4 * hsize / 3) + 3) & ~3;
78115

79116
-- | Hash an entire (strict) 'BS.ByteString' as a single call.
80117
--

0 commit comments

Comments
 (0)