hnix-store-core-0.8.0.0: src/System/Nix/Signature.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NamedFieldPuns #-}
{-|
Description : Nix-relevant interfaces to NaCl signatures.
-}
module System.Nix.Signature
( Signature(..)
, signatureParser
, parseSignature
, signatureToText
, NarSignature(..)
, narSignatureParser
, parseNarSignature
, narSignatureToText
) where
import Crypto.Error (CryptoFailable(..))
import Data.Attoparsec.Text (Parser)
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 as Ed25519
import qualified Data.Attoparsec.Text
import qualified Data.ByteArray
import qualified Data.Char
import qualified Data.Text
-- | An ed25519 signature.
newtype Signature = Signature Ed25519.Signature
deriving (Eq, Generic, Show)
signatureParser :: Parser Signature
signatureParser = do
encodedSig <-
Data.Attoparsec.Text.takeWhile1
(\c -> Data.Char.isAlphaNum c || c == '+' || c == '/' || c == '=')
decodedSig <- case decodeWith Base64 encodedSig of
Left e -> fail e
Right decodedSig -> pure decodedSig
sig <- case Ed25519.signature decodedSig of
CryptoFailed e -> (fail . show) e
CryptoPassed sig -> pure sig
pure $ Signature sig
parseSignature :: Text -> Either String Signature
parseSignature = Data.Attoparsec.Text.parseOnly signatureParser
signatureToText :: Signature -> Text
signatureToText (Signature sig) =
encodeWith Base64 (Data.ByteArray.convert sig :: ByteString)
-- | A detached signature attesting to a nix archive's validity.
data NarSignature = NarSignature
{ -- | The name of the public key used to sign the archive.
publicKey :: !Text
, -- | The archive's signature.
sig :: !Signature
}
deriving (Eq, Generic, Ord)
instance Ord Signature where
compare (Signature x) (Signature y) = let
xBS = Data.ByteArray.convert x :: ByteString
yBS = Data.ByteArray.convert y :: ByteString
in compare xBS yBS
narSignatureParser :: Parser NarSignature
narSignatureParser = do
publicKey <- Data.Attoparsec.Text.takeWhile1 (/= ':')
_ <- Data.Attoparsec.Text.string ":"
sig <- signatureParser
pure $ NarSignature {..}
parseNarSignature :: Text -> Either String NarSignature
parseNarSignature = Data.Attoparsec.Text.parseOnly narSignatureParser
narSignatureToText :: NarSignature -> Text
narSignatureToText NarSignature {..} =
mconcat [ publicKey, ":", signatureToText sig ]
instance Show NarSignature where
show narSig = Data.Text.unpack (narSignatureToText narSig)