|
| 1 | +{-# LANGUAGE OverloadedStrings #-} |
| 2 | +-- Test case from https://code.tvl.fyi/commit/tvix/nix-compat/src/narinfo/fingerprint.rs?id=a834966efd64c1b2306241c3ef20f4258f6b9c4e |
| 3 | + |
| 4 | +module Fingerprint where |
| 5 | + |
| 6 | +import Crypto.Error (CryptoFailable(..)) |
| 7 | +import Data.Default.Class |
| 8 | +import System.Nix.Base (decodeWith, BaseEncoding(Base64)) |
| 9 | +import System.Nix.Fingerprint |
| 10 | +import System.Nix.Signature |
| 11 | +import System.Nix.StorePath |
| 12 | +import System.Nix.StorePath.Metadata |
| 13 | +import System.Nix.Hash (mkNamedDigest) |
| 14 | +import Data.Text (Text) |
| 15 | +import Data.Time.Clock (UTCTime(..)) |
| 16 | +import Data.Time.Calendar.OrdinalDate (fromOrdinalDate) |
| 17 | +import Test.Hspec |
| 18 | + |
| 19 | +import qualified Crypto.PubKey.Ed25519 as Ed25519 |
| 20 | +import qualified Data.HashSet as HashSet |
| 21 | +import qualified Data.Set as Set |
| 22 | +import qualified Data.Text.Encoding as Text |
| 23 | + |
| 24 | +spec_fingerprint :: Spec |
| 25 | +spec_fingerprint = do |
| 26 | + |
| 27 | + describe "fingerprint" $ do |
| 28 | + |
| 29 | + it "is valid for example metadata" $ |
| 30 | + metadataFingerprint def exampleStorePath exampleMetadata `shouldBe` exampleFingerprint |
| 31 | + |
| 32 | + it "allows a successful signature verification" $ do |
| 33 | + let msg = Text.encodeUtf8 $ metadataFingerprint def exampleStorePath exampleMetadata |
| 34 | + Signature sig' = head $ sig <$> filter (\(NarSignature publicKey _) -> publicKey == "cache.nixos.org-1") (Set.toList (sigs exampleMetadata)) |
| 35 | + sig' `shouldSatisfy` Ed25519.verify pubkey msg |
| 36 | + |
| 37 | +exampleFingerprint :: Text |
| 38 | +exampleFingerprint = "1;/nix/store/syd87l2rxw8cbsxmxl853h0r6pdwhwjr-curl-7.82.0-bin;sha256:1b4sb93wp679q4zx9k1ignby1yna3z7c4c2ri3wphylbc2dwsys0;196040;/nix/store/0jqd0rlxzra1rs38rdxl43yh6rxchgc6-curl-7.82.0,/nix/store/6w8g7njm4mck5dmjxws0z1xnrxvl81xa-glibc-2.34-115,/nix/store/j5jxw3iy7bbz4a57fh9g2xm2gxmyal8h-zlib-1.2.12,/nix/store/yxvjs9drzsphm9pcf42a4byzj1kb9m7k-openssl-1.1.1n"; |
| 39 | + |
| 40 | +exampleStorePath :: StorePath |
| 41 | +exampleStorePath = forceRight $ parsePath def "/nix/store/syd87l2rxw8cbsxmxl853h0r6pdwhwjr-curl-7.82.0-bin" |
| 42 | + |
| 43 | +exampleMetadata :: Metadata StorePath |
| 44 | +exampleMetadata = Metadata |
| 45 | + { deriverPath = Just $ forceRight $ parsePath def "/nix/store/5rwxzi7pal3qhpsyfc16gzkh939q1np6-curl-7.82.0.drv" |
| 46 | + , narHash = forceRight $ mkNamedDigest "sha256" "1b4sb93wp679q4zx9k1ignby1yna3z7c4c2ri3wphylbc2dwsys0" |
| 47 | + , references = HashSet.fromList $ forceRight . parsePath def <$> ["/nix/store/0jqd0rlxzra1rs38rdxl43yh6rxchgc6-curl-7.82.0","/nix/store/6w8g7njm4mck5dmjxws0z1xnrxvl81xa-glibc-2.34-115","/nix/store/j5jxw3iy7bbz4a57fh9g2xm2gxmyal8h-zlib-1.2.12","/nix/store/yxvjs9drzsphm9pcf42a4byzj1kb9m7k-openssl-1.1.1n"] |
| 48 | + , registrationTime = UTCTime (fromOrdinalDate 0 0) 0 |
| 49 | + , narBytes = Just 196040 |
| 50 | + , trust = BuiltElsewhere |
| 51 | + , sigs = Set.fromList $ forceRight . parseSignature <$> ["cache.nixos.org-1:TsTTb3WGTZKphvYdBHXwo6weVILmTytUjLB+vcX89fOjjRicCHmKA4RCPMVLkj6TMJ4GMX3HPVWRdD1hkeKZBQ==", "test1:519iiVLx/c4Rdt5DNt6Y2Jm6hcWE9+XY69ygiWSZCNGVcmOcyL64uVAJ3cV8vaTusIZdbTnYo9Y7vDNeTmmMBQ=="] |
| 52 | + , contentAddress = Nothing |
| 53 | + } |
| 54 | + |
| 55 | +pubkey :: Ed25519.PublicKey |
| 56 | +pubkey = forceDecodeB64Pubkey "6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" |
| 57 | + |
| 58 | +forceDecodeB64Pubkey :: Text -> Ed25519.PublicKey |
| 59 | +forceDecodeB64Pubkey b64EncodedPubkey = let |
| 60 | + decoded = forceRight $ decodeWith Base64 b64EncodedPubkey |
| 61 | + in case Ed25519.publicKey decoded of |
| 62 | + CryptoFailed err -> (error . show) err |
| 63 | + CryptoPassed x -> x |
| 64 | + |
| 65 | +forceRight :: Either a b -> b |
| 66 | +forceRight = \case |
| 67 | + Right x -> x |
| 68 | + _ -> error "fromRight failed" |
| 69 | + |
0 commit comments