content: module Cachix.API.Signing
    ( fingerprint,
      passthroughSizeSink,
      passthroughHashSinkB16,
      passthroughHashSink,
    )
  where
  
  import Crypto.Hash
  import qualified Data.ByteArray as BA
  import Data.ByteArray.Encoding (Base (..), convertToBase)
  import qualified Data.ByteString as BS
  import Data.Conduit
  import qualified Data.Conduit.Combinators as CC
  import Data.IORef
  import qualified Data.Text as T
  import Protolude hiding (toS)
  import Protolude.Conv
  
  -- perl/lib/Nix/Manifest.pm:fingerprintPath
  -- NB: references must be sorted
  fingerprint :: Text -> Text -> Integer -> [Text] -> ByteString
  fingerprint storePath narHash narSize references =
    toS $
      T.intercalate
        ";"
        ["1", storePath, narHash, show narSize, T.intercalate "," references]
  
  -- Useful sinks for streaming nars
  sizeSink :: (MonadIO m) => ConduitT ByteString o m Integer
  sizeSink = CC.foldM (\p n -> return (p + fromIntegral (BS.length n))) 0
  
  hashSink :: (MonadIO m) => ConduitT ByteString o m (Context SHA256)
  hashSink = CC.foldM (\p n -> return (hashUpdate p n)) hashInit
  
  passthroughSizeSink :: (MonadIO m) => IORef Integer -> ConduitT ByteString ByteString m ()
  passthroughSizeSink ioref = passthroughSink sizeSink (liftIO . writeIORef ioref)
  
  passthroughHashSinkBase :: (MonadIO m) => (Digest SHA256 -> ByteString) -> IORef ByteString -> ConduitT ByteString ByteString m ()
  passthroughHashSinkBase f ioref = passthroughSink hashSink (liftIO . writeIORef ioref . f . hashFinalize)
  
  passthroughHashSink :: (MonadIO m) => IORef ByteString -> ConduitT ByteString ByteString m ()
  passthroughHashSink = passthroughHashSinkBase BA.convert
  
  passthroughHashSinkB16 :: (MonadIO m) => IORef ByteString -> ConduitT ByteString ByteString m ()
  passthroughHashSinkB16 = passthroughHashSinkBase (convertToBase Base16)
  