Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: add signatureToText function and tests #257

Merged
merged 1 commit into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions hnix-store-core/src/System/Nix/Signature.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NamedFieldPuns #-}
{-|
Description : Nix-relevant interfaces to NaCl signatures.
-}
Expand All @@ -8,22 +9,23 @@ module System.Nix.Signature
, NarSignature(..)
, signatureParser
, parseSignature
, signatureToText
) where

import Crypto.Error (CryptoFailable(..))
import Data.ByteString (ByteString)
import Data.Text (Text)
import GHC.Generics (Generic)
import System.Nix.Base (decodeWith, encodeWith, BaseEncoding(Base64))

import qualified Crypto.PubKey.Ed25519
import Crypto.Error (CryptoFailable(..))
import qualified Crypto.PubKey.Ed25519 as Ed25519
import qualified Data.Attoparsec.Text
import qualified Data.Char
import qualified Data.ByteArray
import qualified Data.ByteString as BS
import Data.Text (Text)
import qualified System.Nix.Base
import System.Nix.Base (BaseEncoding(Base64))
import qualified Data.Char
import qualified Data.Text

-- | An ed25519 signature.
newtype Signature = Signature Crypto.PubKey.Ed25519.Signature
newtype Signature = Signature Ed25519.Signature
deriving (Eq, Generic, Show)

-- | A detached signature attesting to a nix archive's validity.
Expand All @@ -33,29 +35,34 @@ data NarSignature = NarSignature
, -- | The archive's signature.
sig :: !Signature
}
deriving (Eq, Generic, Ord, Show)
deriving (Eq, Generic, Ord)

instance Ord Signature where
compare (Signature x) (Signature y) = let
xBS = Data.ByteArray.convert x :: BS.ByteString
yBS = Data.ByteArray.convert y :: BS.ByteString
xBS = Data.ByteArray.convert x :: ByteString
yBS = Data.ByteArray.convert y :: ByteString
in compare xBS yBS

signatureParser :: Data.Attoparsec.Text.Parser NarSignature
signatureParser = do
publicKey <- Data.Attoparsec.Text.takeWhile1 (/= ':')
_ <- Data.Attoparsec.Text.string ":"
encodedSig <- Data.Attoparsec.Text.takeWhile1 (\c -> Data.Char.isAlphaNum c || c == '+' || c == '/' || c == '=')
decodedSig <- case System.Nix.Base.decodeWith Base64 encodedSig of
decodedSig <- case decodeWith Base64 encodedSig of
Left e -> fail e
Right decodedSig -> pure decodedSig
sig <- case Crypto.PubKey.Ed25519.signature decodedSig of
sig <- case Ed25519.signature decodedSig of
CryptoFailed e -> (fail . show) e
CryptoPassed sig -> pure sig
pure $ NarSignature publicKey (Signature sig)

parseSignature
:: Text -> Either String NarSignature
parseSignature =
Data.Attoparsec.Text.parseOnly signatureParser
parseSignature :: Text -> Either String NarSignature
parseSignature = Data.Attoparsec.Text.parseOnly signatureParser

signatureToText :: NarSignature -> Text
signatureToText NarSignature {publicKey, sig=Signature sig'} = let
b64Encoded = encodeWith Base64 (Data.ByteArray.convert sig' :: ByteString)
in mconcat [ publicKey, ":", b64Encoded ]

instance Show NarSignature where
show narSig = Data.Text.unpack (signatureToText narSig)
2 changes: 2 additions & 0 deletions hnix-store-tests/hnix-store-tests.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ library
, System.Nix.Arbitrary.Derivation
, System.Nix.Arbitrary.DerivedPath
, System.Nix.Arbitrary.Hash
, System.Nix.Arbitrary.Signature
, System.Nix.Arbitrary.Store.Types
, System.Nix.Arbitrary.StorePath
, Test.Hspec.Nix
Expand All @@ -67,6 +68,7 @@ test-suite props
DerivationSpec
DerivedPathSpec
StorePathSpec
SignatureSpec
hs-source-dirs:
tests
build-tool-depends:
Expand Down
1 change: 1 addition & 0 deletions hnix-store-tests/src/System/Nix/Arbitrary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import System.Nix.Arbitrary.ContentAddress ()
import System.Nix.Arbitrary.Derivation ()
import System.Nix.Arbitrary.DerivedPath ()
import System.Nix.Arbitrary.Hash ()
import System.Nix.Arbitrary.Signature ()
import System.Nix.Arbitrary.Store.Types ()
import System.Nix.Arbitrary.StorePath ()
36 changes: 36 additions & 0 deletions hnix-store-tests/src/System/Nix/Arbitrary/Signature.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- due to recent generic-arbitrary
{-# OPTIONS_GHC -fconstraint-solver-iterations=0 #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE OverloadedStrings #-}
module System.Nix.Arbitrary.Signature where

import qualified Crypto.PubKey.Ed25519
import Crypto.Random (drgNewTest, withDRG)
import qualified Data.ByteString as BS
import qualified Data.Text as Text
import Test.QuickCheck.Arbitrary.Generic (GenericArbitrary(..))
import Test.QuickCheck.Instances ()
import Test.QuickCheck

import System.Nix.Signature

instance Arbitrary Crypto.PubKey.Ed25519.Signature where
arbitrary = do
seeds <- (,,,,) <$> arbitraryBoundedRandom <*> arbitraryBoundedRandom <*> arbitraryBoundedRandom <*> arbitraryBoundedRandom <*> arbitraryBoundedRandom
let drg = drgNewTest seeds
(secretKey, _) = withDRG drg Crypto.PubKey.Ed25519.generateSecretKey
publicKey = Crypto.PubKey.Ed25519.toPublic secretKey
msg :: BS.ByteString = "msg"
pure $ Crypto.PubKey.Ed25519.sign secretKey publicKey msg

deriving via GenericArbitrary Signature
instance Arbitrary Signature

instance Arbitrary NarSignature where
arbitrary = do
name <- Text.pack . getPrintableString <$> suchThat arbitrary (\(PrintableString str) -> validName str)
NarSignature name <$> arbitrary

validName :: String -> Bool
validName txt = not (null txt) && not (elem ':' txt)

13 changes: 13 additions & 0 deletions hnix-store-tests/tests/SignatureSpec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module SignatureSpec where

import Test.Hspec (Spec, describe)
import Test.Hspec.Nix (roundtrips)
import Test.Hspec.QuickCheck (prop)

import System.Nix.Signature (signatureToText, parseSignature)
import System.Nix.Arbitrary ()

spec :: Spec
spec = do
describe "Signature" $ do
prop "roundtrips" $ roundtrips signatureToText parseSignature