{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}

module Simplex.Messaging.Crypto.File
  ( CryptoFile (..),
    CryptoFileArgs (..),
    CryptoFileHandle (..),
    FTCryptoError (..),
    Simplex.Messaging.Crypto.File.readFile,
    Simplex.Messaging.Crypto.File.writeFile,
    withFile,
    hPut,
    hPutTag,
    hGet,
    hGetTag,
    plain,
    randomArgs,
    getFileContentsSize,
  )
where

import Control.Exception
import Control.Monad
import Control.Monad.Except
import Control.Monad.Trans.Except
import Crypto.Random (ChaChaDRG)
import qualified Data.Aeson.TH as J
import qualified Data.ByteArray as BA
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as LB
import Data.List.NonEmpty (NonEmpty (..))
import Data.Maybe (isJust)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.Lazy (LazyByteString)
import qualified Simplex.Messaging.Crypto.Lazy as LC
import Simplex.Messaging.Parsers (defaultJSON)
import Simplex.Messaging.Util (liftEitherWith)
import System.Directory (getFileSize)
import UnliftIO (Handle, IOMode (..), liftIO)
import qualified UnliftIO as IO
import UnliftIO.STM

-- Possibly encrypted local file
data CryptoFile = CryptoFile {CryptoFile -> FilePath
filePath :: FilePath, CryptoFile -> Maybe CryptoFileArgs
cryptoArgs :: Maybe CryptoFileArgs}
  deriving (CryptoFile -> CryptoFile -> Bool
(CryptoFile -> CryptoFile -> Bool)
-> (CryptoFile -> CryptoFile -> Bool) -> Eq CryptoFile
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CryptoFile -> CryptoFile -> Bool
== :: CryptoFile -> CryptoFile -> Bool
$c/= :: CryptoFile -> CryptoFile -> Bool
/= :: CryptoFile -> CryptoFile -> Bool
Eq, Int -> CryptoFile -> ShowS
[CryptoFile] -> ShowS
CryptoFile -> FilePath
(Int -> CryptoFile -> ShowS)
-> (CryptoFile -> FilePath)
-> ([CryptoFile] -> ShowS)
-> Show CryptoFile
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CryptoFile -> ShowS
showsPrec :: Int -> CryptoFile -> ShowS
$cshow :: CryptoFile -> FilePath
show :: CryptoFile -> FilePath
$cshowList :: [CryptoFile] -> ShowS
showList :: [CryptoFile] -> ShowS
Show)

data CryptoFileArgs = CFArgs {CryptoFileArgs -> SbKey
fileKey :: C.SbKey, CryptoFileArgs -> CbNonce
fileNonce :: C.CbNonce}
  deriving (CryptoFileArgs -> CryptoFileArgs -> Bool
(CryptoFileArgs -> CryptoFileArgs -> Bool)
-> (CryptoFileArgs -> CryptoFileArgs -> Bool) -> Eq CryptoFileArgs
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CryptoFileArgs -> CryptoFileArgs -> Bool
== :: CryptoFileArgs -> CryptoFileArgs -> Bool
$c/= :: CryptoFileArgs -> CryptoFileArgs -> Bool
/= :: CryptoFileArgs -> CryptoFileArgs -> Bool
Eq, Int -> CryptoFileArgs -> ShowS
[CryptoFileArgs] -> ShowS
CryptoFileArgs -> FilePath
(Int -> CryptoFileArgs -> ShowS)
-> (CryptoFileArgs -> FilePath)
-> ([CryptoFileArgs] -> ShowS)
-> Show CryptoFileArgs
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CryptoFileArgs -> ShowS
showsPrec :: Int -> CryptoFileArgs -> ShowS
$cshow :: CryptoFileArgs -> FilePath
show :: CryptoFileArgs -> FilePath
$cshowList :: [CryptoFileArgs] -> ShowS
showList :: [CryptoFileArgs] -> ShowS
Show)

data CryptoFileHandle = CFHandle Handle (Maybe (TVar LC.SbState))

readFile :: CryptoFile -> ExceptT FTCryptoError IO LazyByteString
readFile :: CryptoFile -> ExceptT FTCryptoError IO LazyByteString
readFile (CryptoFile FilePath
path Maybe CryptoFileArgs
cfArgs) = do
  LazyByteString
s <- IO LazyByteString -> ExceptT FTCryptoError IO LazyByteString
forall a. IO a -> ExceptT FTCryptoError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO LazyByteString -> ExceptT FTCryptoError IO LazyByteString)
-> IO LazyByteString -> ExceptT FTCryptoError IO LazyByteString
forall a b. (a -> b) -> a -> b
$ FilePath -> IO LazyByteString
LB.readFile FilePath
path
  case Maybe CryptoFileArgs
cfArgs of
    Just (CFArgs (C.SbKey ByteString
key) (C.CbNonce ByteString
nonce)) -> do
      let len :: Int64
len = LazyByteString -> Int64
LB.length LazyByteString
s Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
C.authTagSize
      Bool -> ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int64
len Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0) (ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ())
-> ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ()
forall a b. (a -> b) -> a -> b
$ FTCryptoError -> ExceptT FTCryptoError IO ()
forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE FTCryptoError
FTCEInvalidFileSize
      let (LazyByteString
s', LazyByteString
tag') = Int64 -> LazyByteString -> (LazyByteString, LazyByteString)
LB.splitAt Int64
len LazyByteString
s
      (ByteString
tag :| [ByteString]
cs) <- (CryptoError -> FTCryptoError)
-> Either CryptoError (NonEmpty ByteString)
-> ExceptT FTCryptoError IO (NonEmpty ByteString)
forall (m :: * -> *) e e' a.
MonadIO m =>
(e -> e') -> Either e a -> ExceptT e' m a
liftEitherWith CryptoError -> FTCryptoError
FTCECryptoError (Either CryptoError (NonEmpty ByteString)
 -> ExceptT FTCryptoError IO (NonEmpty ByteString))
-> Either CryptoError (NonEmpty ByteString)
-> ExceptT FTCryptoError IO (NonEmpty ByteString)
forall a b. (a -> b) -> a -> b
$ (SbState -> ByteString -> (ByteString, SbState))
-> ByteString
-> ByteString
-> LazyByteString
-> Either CryptoError (NonEmpty ByteString)
forall key.
ByteArrayAccess key =>
(SbState -> ByteString -> (ByteString, SbState))
-> key
-> ByteString
-> LazyByteString
-> Either CryptoError (NonEmpty ByteString)
LC.secretBox SbState -> ByteString -> (ByteString, SbState)
LC.sbDecryptChunk ByteString
key ByteString
nonce LazyByteString
s'
      Bool -> ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ByteString -> ByteString -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
BA.constEq (LazyByteString -> ByteString
LB.toStrict LazyByteString
tag') ByteString
tag) (ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ())
-> ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ()
forall a b. (a -> b) -> a -> b
$ FTCryptoError -> ExceptT FTCryptoError IO ()
forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE FTCryptoError
FTCEInvalidAuthTag
      LazyByteString -> ExceptT FTCryptoError IO LazyByteString
forall a. a -> ExceptT FTCryptoError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LazyByteString -> ExceptT FTCryptoError IO LazyByteString)
-> LazyByteString -> ExceptT FTCryptoError IO LazyByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> LazyByteString
LB.fromChunks [ByteString]
cs
    Maybe CryptoFileArgs
Nothing -> LazyByteString -> ExceptT FTCryptoError IO LazyByteString
forall a. a -> ExceptT FTCryptoError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure LazyByteString
s

writeFile :: CryptoFile -> LazyByteString -> ExceptT FTCryptoError IO ()
writeFile :: CryptoFile -> LazyByteString -> ExceptT FTCryptoError IO ()
writeFile (CryptoFile FilePath
path Maybe CryptoFileArgs
cfArgs) LazyByteString
s = do
  LazyByteString
s' <- case Maybe CryptoFileArgs
cfArgs of
    Just (CFArgs (C.SbKey ByteString
key) (C.CbNonce ByteString
nonce)) ->
      (CryptoError -> FTCryptoError)
-> Either CryptoError LazyByteString
-> ExceptT FTCryptoError IO LazyByteString
forall (m :: * -> *) e e' a.
MonadIO m =>
(e -> e') -> Either e a -> ExceptT e' m a
liftEitherWith CryptoError -> FTCryptoError
FTCECryptoError (Either CryptoError LazyByteString
 -> ExceptT FTCryptoError IO LazyByteString)
-> Either CryptoError LazyByteString
-> ExceptT FTCryptoError IO LazyByteString
forall a b. (a -> b) -> a -> b
$ [ByteString] -> LazyByteString
LB.fromChunks ([ByteString] -> LazyByteString)
-> Either CryptoError [ByteString]
-> Either CryptoError LazyByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (SbState -> ByteString -> (ByteString, SbState))
-> ByteString
-> ByteString
-> LazyByteString
-> Either CryptoError [ByteString]
forall key.
ByteArrayAccess key =>
(SbState -> ByteString -> (ByteString, SbState))
-> key
-> ByteString
-> LazyByteString
-> Either CryptoError [ByteString]
LC.secretBoxTailTag SbState -> ByteString -> (ByteString, SbState)
LC.sbEncryptChunk ByteString
key ByteString
nonce LazyByteString
s
    Maybe CryptoFileArgs
Nothing -> LazyByteString -> ExceptT FTCryptoError IO LazyByteString
forall a. a -> ExceptT FTCryptoError IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure LazyByteString
s
  IO () -> ExceptT FTCryptoError IO ()
forall a. IO a -> ExceptT FTCryptoError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> ExceptT FTCryptoError IO ())
-> IO () -> ExceptT FTCryptoError IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> LazyByteString -> IO ()
LB.writeFile FilePath
path LazyByteString
s'

withFile :: CryptoFile -> IOMode -> (CryptoFileHandle -> ExceptT FTCryptoError IO a) -> ExceptT FTCryptoError IO a
withFile :: forall a.
CryptoFile
-> IOMode
-> (CryptoFileHandle -> ExceptT FTCryptoError IO a)
-> ExceptT FTCryptoError IO a
withFile (CryptoFile FilePath
path Maybe CryptoFileArgs
cfArgs) IOMode
mode CryptoFileHandle -> ExceptT FTCryptoError IO a
action = do
  Maybe (TVar SbState)
sb <- Maybe CryptoFileArgs
-> (CryptoFileArgs -> ExceptT FTCryptoError IO (TVar SbState))
-> ExceptT FTCryptoError IO (Maybe (TVar SbState))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM Maybe CryptoFileArgs
cfArgs ((CryptoFileArgs -> ExceptT FTCryptoError IO (TVar SbState))
 -> ExceptT FTCryptoError IO (Maybe (TVar SbState)))
-> (CryptoFileArgs -> ExceptT FTCryptoError IO (TVar SbState))
-> ExceptT FTCryptoError IO (Maybe (TVar SbState))
forall a b. (a -> b) -> a -> b
$ \(CFArgs SbKey
key CbNonce
nonce) ->
    (CryptoError -> FTCryptoError)
-> Either CryptoError SbState -> ExceptT FTCryptoError IO SbState
forall (m :: * -> *) e e' a.
MonadIO m =>
(e -> e') -> Either e a -> ExceptT e' m a
liftEitherWith CryptoError -> FTCryptoError
FTCECryptoError (SbKey -> CbNonce -> Either CryptoError SbState
LC.sbInit SbKey
key CbNonce
nonce) ExceptT FTCryptoError IO SbState
-> (SbState -> ExceptT FTCryptoError IO (TVar SbState))
-> ExceptT FTCryptoError IO (TVar SbState)
forall a b.
ExceptT FTCryptoError IO a
-> (a -> ExceptT FTCryptoError IO b) -> ExceptT FTCryptoError IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= SbState -> ExceptT FTCryptoError IO (TVar SbState)
forall (m :: * -> *) a. MonadIO m => a -> m (TVar a)
newTVarIO
  IO (Either FTCryptoError a) -> ExceptT FTCryptoError IO a
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either FTCryptoError a) -> ExceptT FTCryptoError IO a)
-> ((Handle -> IO (Either FTCryptoError a))
    -> IO (Either FTCryptoError a))
-> (Handle -> IO (Either FTCryptoError a))
-> ExceptT FTCryptoError IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath
-> IOMode
-> (Handle -> IO (Either FTCryptoError a))
-> IO (Either FTCryptoError a)
forall (m :: * -> *) a.
MonadUnliftIO m =>
FilePath -> IOMode -> (Handle -> m a) -> m a
IO.withFile FilePath
path IOMode
mode ((Handle -> IO (Either FTCryptoError a))
 -> ExceptT FTCryptoError IO a)
-> (Handle -> IO (Either FTCryptoError a))
-> ExceptT FTCryptoError IO a
forall a b. (a -> b) -> a -> b
$ \Handle
h -> ExceptT FTCryptoError IO a -> IO (Either FTCryptoError a)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT FTCryptoError IO a -> IO (Either FTCryptoError a))
-> ExceptT FTCryptoError IO a -> IO (Either FTCryptoError a)
forall a b. (a -> b) -> a -> b
$ CryptoFileHandle -> ExceptT FTCryptoError IO a
action (CryptoFileHandle -> ExceptT FTCryptoError IO a)
-> CryptoFileHandle -> ExceptT FTCryptoError IO a
forall a b. (a -> b) -> a -> b
$ Handle -> Maybe (TVar SbState) -> CryptoFileHandle
CFHandle Handle
h Maybe (TVar SbState)
sb

hPut :: CryptoFileHandle -> LazyByteString -> IO ()
hPut :: CryptoFileHandle -> LazyByteString -> IO ()
hPut (CFHandle Handle
h Maybe (TVar SbState)
sb_) LazyByteString
s = Handle -> LazyByteString -> IO ()
LB.hPut Handle
h (LazyByteString -> IO ()) -> IO LazyByteString -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO LazyByteString
-> (TVar SbState -> IO LazyByteString)
-> Maybe (TVar SbState)
-> IO LazyByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (LazyByteString -> IO LazyByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure LazyByteString
s) TVar SbState -> IO LazyByteString
forall {m :: * -> *}. MonadIO m => TVar SbState -> m LazyByteString
encrypt Maybe (TVar SbState)
sb_
  where
    encrypt :: TVar SbState -> m LazyByteString
encrypt TVar SbState
sb = STM LazyByteString -> m LazyByteString
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM LazyByteString -> m LazyByteString)
-> STM LazyByteString -> m LazyByteString
forall a b. (a -> b) -> a -> b
$ TVar SbState
-> (SbState -> (LazyByteString, SbState)) -> STM LazyByteString
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar SbState
sb (SbState -> LazyByteString -> (LazyByteString, SbState)
`LC.sbEncryptChunkLazy` LazyByteString
s)

hPutTag :: CryptoFileHandle -> IO ()
hPutTag :: CryptoFileHandle -> IO ()
hPutTag (CFHandle Handle
h Maybe (TVar SbState)
sb_) = Maybe (TVar SbState) -> (TVar SbState -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ Maybe (TVar SbState)
sb_ ((TVar SbState -> IO ()) -> IO ())
-> (TVar SbState -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ Handle -> ByteString -> IO ()
B.hPut Handle
h (ByteString -> IO ())
-> (SbState -> ByteString) -> SbState -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Auth -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
BA.convert (Auth -> ByteString) -> (SbState -> Auth) -> SbState -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SbState -> Auth
LC.sbAuth (SbState -> IO ())
-> (TVar SbState -> IO SbState) -> TVar SbState -> IO ()
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< TVar SbState -> IO SbState
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO

hGet :: CryptoFileHandle -> Int -> IO ByteString
hGet :: CryptoFileHandle -> Int -> IO ByteString
hGet (CFHandle Handle
h Maybe (TVar SbState)
sb_) Int
n = Handle -> Int -> IO ByteString
B.hGet Handle
h Int
n IO ByteString -> (ByteString -> IO ByteString) -> IO ByteString
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ByteString -> IO ByteString)
-> (TVar SbState -> ByteString -> IO ByteString)
-> Maybe (TVar SbState)
-> ByteString
-> IO ByteString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ByteString -> IO ByteString
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure TVar SbState -> ByteString -> IO ByteString
forall {m :: * -> *}.
MonadIO m =>
TVar SbState -> ByteString -> m ByteString
decrypt Maybe (TVar SbState)
sb_
  where
    decrypt :: TVar SbState -> ByteString -> m ByteString
decrypt TVar SbState
sb ByteString
s = STM ByteString -> m ByteString
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM ByteString -> m ByteString) -> STM ByteString -> m ByteString
forall a b. (a -> b) -> a -> b
$ TVar SbState
-> (SbState -> (ByteString, SbState)) -> STM ByteString
forall s a. TVar s -> (s -> (a, s)) -> STM a
stateTVar TVar SbState
sb (SbState -> ByteString -> (ByteString, SbState)
`LC.sbDecryptChunk` ByteString
s)

-- | Read and validate the auth tag.
-- This function should be called after reading the whole file, it assumes you know the file size and read only the needed bytes.
hGetTag :: CryptoFileHandle -> ExceptT FTCryptoError IO ()
hGetTag :: CryptoFileHandle -> ExceptT FTCryptoError IO ()
hGetTag (CFHandle Handle
h Maybe (TVar SbState)
sb_) = Maybe (TVar SbState)
-> (TVar SbState -> ExceptT FTCryptoError IO ())
-> ExceptT FTCryptoError IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ Maybe (TVar SbState)
sb_ ((TVar SbState -> ExceptT FTCryptoError IO ())
 -> ExceptT FTCryptoError IO ())
-> (TVar SbState -> ExceptT FTCryptoError IO ())
-> ExceptT FTCryptoError IO ()
forall a b. (a -> b) -> a -> b
$ \TVar SbState
sb -> do
  ByteString
tag <- IO ByteString -> ExceptT FTCryptoError IO ByteString
forall a. IO a -> ExceptT FTCryptoError IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> ExceptT FTCryptoError IO ByteString)
-> IO ByteString -> ExceptT FTCryptoError IO ByteString
forall a b. (a -> b) -> a -> b
$ Handle -> Int -> IO ByteString
B.hGet Handle
h Int
C.authTagSize
  Auth
tag' <- SbState -> Auth
LC.sbAuth (SbState -> Auth)
-> ExceptT FTCryptoError IO SbState
-> ExceptT FTCryptoError IO Auth
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar SbState -> ExceptT FTCryptoError IO SbState
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar SbState
sb
  Bool -> ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ByteString -> Auth -> Bool
forall bs1 bs2.
(ByteArrayAccess bs1, ByteArrayAccess bs2) =>
bs1 -> bs2 -> Bool
BA.constEq ByteString
tag Auth
tag') (ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ())
-> ExceptT FTCryptoError IO () -> ExceptT FTCryptoError IO ()
forall a b. (a -> b) -> a -> b
$ FTCryptoError -> ExceptT FTCryptoError IO ()
forall (m :: * -> *) e a. Monad m => e -> ExceptT e m a
throwE FTCryptoError
FTCEInvalidAuthTag

data FTCryptoError
  = FTCECryptoError C.CryptoError
  | FTCEInvalidHeader String
  | FTCEInvalidFileSize
  | FTCEInvalidAuthTag
  | FTCEFileIOError String
  deriving (Int -> FTCryptoError -> ShowS
[FTCryptoError] -> ShowS
FTCryptoError -> FilePath
(Int -> FTCryptoError -> ShowS)
-> (FTCryptoError -> FilePath)
-> ([FTCryptoError] -> ShowS)
-> Show FTCryptoError
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> FTCryptoError -> ShowS
showsPrec :: Int -> FTCryptoError -> ShowS
$cshow :: FTCryptoError -> FilePath
show :: FTCryptoError -> FilePath
$cshowList :: [FTCryptoError] -> ShowS
showList :: [FTCryptoError] -> ShowS
Show, FTCryptoError -> FTCryptoError -> Bool
(FTCryptoError -> FTCryptoError -> Bool)
-> (FTCryptoError -> FTCryptoError -> Bool) -> Eq FTCryptoError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: FTCryptoError -> FTCryptoError -> Bool
== :: FTCryptoError -> FTCryptoError -> Bool
$c/= :: FTCryptoError -> FTCryptoError -> Bool
/= :: FTCryptoError -> FTCryptoError -> Bool
Eq, Show FTCryptoError
Typeable FTCryptoError
(Typeable FTCryptoError, Show FTCryptoError) =>
(FTCryptoError -> SomeException)
-> (SomeException -> Maybe FTCryptoError)
-> (FTCryptoError -> FilePath)
-> Exception FTCryptoError
SomeException -> Maybe FTCryptoError
FTCryptoError -> FilePath
FTCryptoError -> SomeException
forall e.
(Typeable e, Show e) =>
(e -> SomeException)
-> (SomeException -> Maybe e) -> (e -> FilePath) -> Exception e
$ctoException :: FTCryptoError -> SomeException
toException :: FTCryptoError -> SomeException
$cfromException :: SomeException -> Maybe FTCryptoError
fromException :: SomeException -> Maybe FTCryptoError
$cdisplayException :: FTCryptoError -> FilePath
displayException :: FTCryptoError -> FilePath
Exception)

plain :: FilePath -> CryptoFile
plain :: FilePath -> CryptoFile
plain = (FilePath -> Maybe CryptoFileArgs -> CryptoFile
`CryptoFile` Maybe CryptoFileArgs
forall a. Maybe a
Nothing)

randomArgs :: TVar ChaChaDRG -> STM CryptoFileArgs
randomArgs :: TVar ChaChaDRG -> STM CryptoFileArgs
randomArgs TVar ChaChaDRG
g = SbKey -> CbNonce -> CryptoFileArgs
CFArgs (SbKey -> CbNonce -> CryptoFileArgs)
-> STM SbKey -> STM (CbNonce -> CryptoFileArgs)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar ChaChaDRG -> STM SbKey
C.randomSbKey TVar ChaChaDRG
g STM (CbNonce -> CryptoFileArgs)
-> STM CbNonce -> STM CryptoFileArgs
forall a b. STM (a -> b) -> STM a -> STM b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> TVar ChaChaDRG -> STM CbNonce
C.randomCbNonce TVar ChaChaDRG
g

getFileContentsSize :: CryptoFile -> IO Integer
getFileContentsSize :: CryptoFile -> IO Integer
getFileContentsSize (CryptoFile FilePath
path Maybe CryptoFileArgs
cfArgs) = do
  Integer
size <- FilePath -> IO Integer
getFileSize FilePath
path
  Integer -> IO Integer
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Integer -> IO Integer) -> Integer -> IO Integer
forall a b. (a -> b) -> a -> b
$ if Maybe CryptoFileArgs -> Bool
forall a. Maybe a -> Bool
isJust Maybe CryptoFileArgs
cfArgs then Integer
size Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
C.authTagSize else Integer
size

$(J.deriveJSON defaultJSON ''CryptoFileArgs)

$(J.deriveJSON defaultJSON ''CryptoFile)