module Cachix.Api.Signing ( fingerprint , passthroughSizeSink , passthroughHashSink ) where import Crypto.Hash import Control.Monad.IO.Class (MonadIO, liftIO) import qualified Data.ByteArray as BA import qualified Data.ByteString as BS import Data.ByteString (ByteString) import qualified Data.ByteString.Base16 as B16 import Data.Conduit import qualified Data.Conduit.Combinators as CC import Data.IORef import Data.String.Conv (toS) import qualified Data.Text as T import Data.Text (Text) -- perl/lib/Nix/Manifest.pm:fingerprintPath -- TODO: Either Text ByteString: assert values -- NB: references must be sorted fingerprint :: Text -> Text -> Int -> [Text] -> ByteString fingerprint storePath narHash narSize references = toS $ T.intercalate ";" ["1", storePath, narHash, T.pack (show narSize), T.intercalate "," references] -- Useful sinks for streaming nars sizeSink :: MonadIO m => Consumer ByteString m Int sizeSink = CC.foldM (\p n -> return (p + BS.length n)) 0 hashSink :: MonadIO m => Consumer ByteString m (Context SHA256) hashSink = CC.foldM (\p n -> return (hashUpdate p n)) hashInit passthroughSizeSink :: MonadIO m => IORef Int -> Conduit ByteString m ByteString passthroughSizeSink ioref = passthroughSink sizeSink (liftIO . writeIORef ioref) passthroughHashSink :: MonadIO m => IORef Text -> Conduit ByteString m ByteString passthroughHashSink ioref = passthroughSink hashSink (liftIO . writeIORef ioref . transf) where -- TODO: use cryptonite B16 to get rid of extra dep and simplify transf = toS . B16.encode . BS.pack . BA.unpack . hashFinalize