Skip to content

Commit b6780ba

Browse files
author
Robert 'Probie' Offner
committed
Use openFileBlocking for reading signing keys
When reading a key from a file, `readFile` from ByteString was used. Unfortunately this operation doesn't play nicely with pipes. We now use `openFileBlocking` so that we can wait for data which comes from a pipe. Fixes #4101
1 parent 47247f6 commit b6780ba

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

cardano-cli/ChangeLog.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog for cardano-cli
22

3+
## vNext
4+
5+
### Bugs
6+
7+
- Allow reading signing keys from a pipe ([PR 4342](https://github.com/input-output-hk/cardano-node/pull/4342))
8+
39
## 1.33.0 -- December 2021
410
## 1.32.1 -- November 2021
511

cardano-cli/src/Cardano/CLI/Shelley/Key.hs

+24-2
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@ import Cardano.Prelude
4343
import Control.Monad.Trans.Except.Extra (firstExceptT, handleIOExceptT, hoistEither)
4444
import qualified Data.Aeson as Aeson
4545
import qualified Data.ByteString as BS
46+
import qualified Data.ByteString.Lazy as LBS
47+
import qualified Data.ByteString.Builder as Builder
4648
import qualified Data.ByteString.Char8 as BSC
4749
import qualified Data.List.NonEmpty as NE
4850
import qualified Data.Text as Text
4951
import qualified Data.Text.Encoding as Text
52+
import GHC.IO.Handle (hClose)
53+
import GHC.IO.Handle.FD (openFileBlocking)
5054

5155
import Cardano.Api
5256

@@ -239,6 +243,24 @@ deserialiseInputAnyOf bech32Types textEnvTypes inputBs =
239243
-- Cryptographic key deserialisation
240244
------------------------------------------------------------------------------
241245

246+
-- It's possible a user might be supplying keys via a pipe that may
247+
-- not yet have data by the time we want to read, so we need to make
248+
-- sure we support that.
249+
readFileBlocking :: FilePath -> IO ByteString
250+
readFileBlocking path = bracket
251+
(openFileBlocking path ReadMode)
252+
hClose
253+
(\fp -> do
254+
-- An arbitrary block size.
255+
let blockSize = 4096
256+
let go acc = do
257+
next <- BS.hGet fp blockSize
258+
if BS.null next
259+
then pure acc
260+
else go (acc <> Builder.byteString next)
261+
contents <- go mempty
262+
pure $ LBS.toStrict $ Builder.toLazyByteString contents)
263+
242264
-- | Read a cryptographic key from a file.
243265
--
244266
-- The contents of the file can either be Bech32-encoded, hex-encoded, or in
@@ -250,7 +272,7 @@ readKeyFile
250272
-> IO (Either (FileError InputDecodeError) a)
251273
readKeyFile asType acceptedFormats path =
252274
runExceptT $ do
253-
content <- handleIOExceptT (FileIOError path) $ BS.readFile path
275+
content <- handleIOExceptT (FileIOError path) $ readFileBlocking path
254276
firstExceptT (FileError path) $ hoistEither $
255277
deserialiseInput asType acceptedFormats content
256278

@@ -289,7 +311,7 @@ readKeyFileAnyOf
289311
-> IO (Either (FileError InputDecodeError) b)
290312
readKeyFileAnyOf bech32Types textEnvTypes path =
291313
runExceptT $ do
292-
content <- handleIOExceptT (FileIOError path) $ BS.readFile path
314+
content <- handleIOExceptT (FileIOError path) $ readFileBlocking path
293315
firstExceptT (FileError path) $ hoistEither $
294316
deserialiseInputAnyOf bech32Types textEnvTypes content
295317

0 commit comments

Comments
 (0)