{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
module Simplex.Messaging.Crypto.ShortLink
( contactShortLinkKdf,
invShortLinkKdf,
encodeSignLinkData,
encodeSignFixedData,
encodeSignUserData,
newOwnerAuth,
encryptLinkData,
encryptUserData,
decryptLinkData,
)
where
import Control.Concurrent.STM
import Control.Monad (unless)
import Control.Monad.Except
import Control.Monad.IO.Class
import Crypto.Random (ChaChaDRG)
import Data.Bifunctor (first)
import Data.Bitraversable (bimapM)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import Simplex.Messaging.Agent.Client (cryptoError)
import Simplex.Messaging.Agent.Protocol
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Encoding
import Simplex.Messaging.Protocol (EncDataBytes (..), EntityId (..), LinkId, QueueLinkData)
import Simplex.Messaging.Util (liftEitherWith)
fixedDataPaddedLength :: Int
fixedDataPaddedLength :: Int
fixedDataPaddedLength = Int
2008
userDataPaddedLength :: Int
userDataPaddedLength :: Int
userDataPaddedLength = Int
13784
contactShortLinkKdf :: LinkKey -> (LinkId, C.SbKey)
contactShortLinkKdf :: LinkKey -> (LinkId, SbKey)
contactShortLinkKdf (LinkKey ByteString
k) =
let (ByteString
lnkId, ByteString
sbKey) = Int -> ByteString -> (ByteString, ByteString)
B.splitAt Int
24 (ByteString -> (ByteString, ByteString))
-> ByteString -> (ByteString, ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString -> Int -> ByteString
forall secret.
ByteArrayAccess secret =>
ByteString -> secret -> ByteString -> Int -> ByteString
C.hkdf ByteString
"" ByteString
k ByteString
"SimpleXContactLink" Int
56
in (ByteString -> LinkId
EntityId ByteString
lnkId, ByteString -> SbKey
C.unsafeSbKey ByteString
sbKey)
invShortLinkKdf :: LinkKey -> C.SbKey
invShortLinkKdf :: LinkKey -> SbKey
invShortLinkKdf (LinkKey ByteString
k) = ByteString -> SbKey
C.unsafeSbKey (ByteString -> SbKey) -> ByteString -> SbKey
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString -> Int -> ByteString
forall secret.
ByteArrayAccess secret =>
ByteString -> secret -> ByteString -> Int -> ByteString
C.hkdf ByteString
"" ByteString
k ByteString
"SimpleXInvLink" Int
32
encodeSignLinkData :: forall c. ConnectionModeI c => C.KeyPairEd25519 -> VersionRangeSMPA -> ConnectionRequestUri c -> Maybe ByteString -> UserConnLinkData c -> (LinkKey, (ByteString, ByteString))
encodeSignLinkData :: forall (c :: ConnectionMode).
ConnectionModeI c =>
KeyPairEd25519
-> VersionRangeSMPA
-> ConnectionRequestUri c
-> Maybe ByteString
-> UserConnLinkData c
-> (LinkKey, (ByteString, ByteString))
encodeSignLinkData keys :: KeyPairEd25519
keys@(PublicKeyType (PrivateKey 'Ed25519)
_, PrivateKey 'Ed25519
pk) VersionRangeSMPA
agentVRange ConnectionRequestUri c
linkConnReq Maybe ByteString
linkEntityId UserConnLinkData c
userData =
let (LinkKey
linkKey, ByteString
fd) = KeyPairEd25519
-> VersionRangeSMPA
-> ConnectionRequestUri c
-> Maybe ByteString
-> (LinkKey, ByteString)
forall (c :: ConnectionMode).
ConnectionModeI c =>
KeyPairEd25519
-> VersionRangeSMPA
-> ConnectionRequestUri c
-> Maybe ByteString
-> (LinkKey, ByteString)
encodeSignFixedData KeyPairEd25519
keys VersionRangeSMPA
agentVRange ConnectionRequestUri c
linkConnReq Maybe ByteString
linkEntityId
md :: ByteString
md = SConnectionMode c
-> PrivateKey 'Ed25519
-> VersionRangeSMPA
-> UserConnLinkData c
-> ByteString
forall (c :: ConnectionMode).
ConnectionModeI c =>
SConnectionMode c
-> PrivateKey 'Ed25519
-> VersionRangeSMPA
-> UserConnLinkData c
-> ByteString
encodeSignUserData (forall (m :: ConnectionMode).
ConnectionModeI m =>
SConnectionMode m
sConnectionMode @c) PrivateKey 'Ed25519
pk VersionRangeSMPA
agentVRange UserConnLinkData c
userData
in (LinkKey
linkKey, (ByteString
fd, ByteString
md))
encodeSignFixedData :: ConnectionModeI c => C.KeyPairEd25519 -> VersionRangeSMPA -> ConnectionRequestUri c -> Maybe ByteString -> (LinkKey, ByteString)
encodeSignFixedData :: forall (c :: ConnectionMode).
ConnectionModeI c =>
KeyPairEd25519
-> VersionRangeSMPA
-> ConnectionRequestUri c
-> Maybe ByteString
-> (LinkKey, ByteString)
encodeSignFixedData (PublicKeyType (PrivateKey 'Ed25519)
rootKey, PrivateKey 'Ed25519
pk) VersionRangeSMPA
agentVRange ConnectionRequestUri c
linkConnReq Maybe ByteString
linkEntityId =
let fd :: ByteString
fd = FixedLinkData c -> ByteString
forall a. Encoding a => a -> ByteString
smpEncode FixedLinkData {VersionRangeSMPA
agentVRange :: VersionRangeSMPA
$sel:agentVRange:FixedLinkData :: VersionRangeSMPA
agentVRange, PublicKeyType (PrivateKey 'Ed25519)
PublicKey 'Ed25519
rootKey :: PublicKeyType (PrivateKey 'Ed25519)
$sel:rootKey:FixedLinkData :: PublicKey 'Ed25519
rootKey, ConnectionRequestUri c
linkConnReq :: ConnectionRequestUri c
$sel:linkConnReq:FixedLinkData :: ConnectionRequestUri c
linkConnReq, Maybe ByteString
linkEntityId :: Maybe ByteString
$sel:linkEntityId:FixedLinkData :: Maybe ByteString
linkEntityId}
in (ByteString -> LinkKey
LinkKey (ByteString -> ByteString
C.sha3_256 ByteString
fd), PrivateKey 'Ed25519 -> ByteString -> ByteString
encodeSign PrivateKey 'Ed25519
pk ByteString
fd)
encodeSignUserData :: ConnectionModeI c => SConnectionMode c -> C.PrivateKeyEd25519 -> VersionRangeSMPA -> UserConnLinkData c -> ByteString
encodeSignUserData :: forall (c :: ConnectionMode).
ConnectionModeI c =>
SConnectionMode c
-> PrivateKey 'Ed25519
-> VersionRangeSMPA
-> UserConnLinkData c
-> ByteString
encodeSignUserData SConnectionMode c
_ PrivateKey 'Ed25519
pk VersionRangeSMPA
agentVRange UserConnLinkData c
userLinkData =
PrivateKey 'Ed25519 -> ByteString -> ByteString
encodeSign PrivateKey 'Ed25519
pk (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ ConnLinkData c -> ByteString
forall a. Encoding a => a -> ByteString
smpEncode (ConnLinkData c -> ByteString) -> ConnLinkData c -> ByteString
forall a b. (a -> b) -> a -> b
$ VersionRangeSMPA -> UserConnLinkData c -> ConnLinkData c
forall (c :: ConnectionMode).
VersionRangeSMPA -> UserConnLinkData c -> ConnLinkData c
connLinkData VersionRangeSMPA
agentVRange UserConnLinkData c
userLinkData
connLinkData :: VersionRangeSMPA -> UserConnLinkData c -> ConnLinkData c
connLinkData :: forall (c :: ConnectionMode).
VersionRangeSMPA -> UserConnLinkData c -> ConnLinkData c
connLinkData VersionRangeSMPA
vr = \case
UserInvLinkData UserLinkData
d -> VersionRangeSMPA -> UserLinkData -> ConnLinkData 'CMInvitation
InvitationLinkData VersionRangeSMPA
vr UserLinkData
d
UserContactLinkData UserContactData
d -> VersionRangeSMPA -> UserContactData -> ConnLinkData 'CMContact
ContactLinkData VersionRangeSMPA
vr UserContactData
d
encodeSign :: C.PrivateKeyEd25519 -> ByteString -> ByteString
encodeSign :: PrivateKey 'Ed25519 -> ByteString -> ByteString
encodeSign PrivateKey 'Ed25519
pk ByteString
s = Signature 'Ed25519 -> ByteString
forall a. Encoding a => a -> ByteString
smpEncode (PrivateKey 'Ed25519 -> ByteString -> Signature 'Ed25519
forall (a :: Algorithm).
SignatureAlgorithm a =>
PrivateKey a -> ByteString -> Signature a
C.sign' PrivateKey 'Ed25519
pk ByteString
s) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
s
newOwnerAuth :: TVar ChaChaDRG -> OwnerId -> C.PrivateKeyEd25519 -> IO (C.PrivateKeyEd25519, OwnerAuth)
newOwnerAuth :: TVar ChaChaDRG
-> ByteString
-> PrivateKey 'Ed25519
-> IO (PrivateKey 'Ed25519, OwnerAuth)
newOwnerAuth TVar ChaChaDRG
g ByteString
ownerId PrivateKey 'Ed25519
signingKey = do
(PublicKey 'Ed25519
ownerKey, PrivateKey 'Ed25519
ownerPrivKey) <- STM KeyPairEd25519 -> IO KeyPairEd25519
forall a. STM a -> IO a
atomically (STM KeyPairEd25519 -> IO KeyPairEd25519)
-> STM KeyPairEd25519 -> IO KeyPairEd25519
forall a b. (a -> b) -> a -> b
$ forall (a :: Algorithm).
AlgorithmI a =>
TVar ChaChaDRG -> STM (KeyPair a)
C.generateKeyPair @'C.Ed25519 TVar ChaChaDRG
g
let authOwnerSig :: Signature 'Ed25519
authOwnerSig = PrivateKey 'Ed25519 -> ByteString -> Signature 'Ed25519
forall (a :: Algorithm).
SignatureAlgorithm a =>
PrivateKey a -> ByteString -> Signature a
C.sign' PrivateKey 'Ed25519
signingKey (ByteString -> Signature 'Ed25519)
-> ByteString -> Signature 'Ed25519
forall a b. (a -> b) -> a -> b
$ ByteString
ownerId ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> PublicKey 'Ed25519 -> ByteString
forall k. CryptoPublicKey k => k -> ByteString
C.encodePubKey PublicKey 'Ed25519
ownerKey
(PrivateKey 'Ed25519, OwnerAuth)
-> IO (PrivateKey 'Ed25519, OwnerAuth)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PrivateKey 'Ed25519
ownerPrivKey, OwnerAuth {ByteString
ownerId :: ByteString
$sel:ownerId:OwnerAuth :: ByteString
ownerId, PublicKey 'Ed25519
ownerKey :: PublicKey 'Ed25519
$sel:ownerKey:OwnerAuth :: PublicKey 'Ed25519
ownerKey, Signature 'Ed25519
authOwnerSig :: Signature 'Ed25519
$sel:authOwnerSig:OwnerAuth :: Signature 'Ed25519
authOwnerSig})
encryptLinkData :: TVar ChaChaDRG -> C.SbKey -> (ByteString, ByteString) -> ExceptT AgentErrorType IO QueueLinkData
encryptLinkData :: TVar ChaChaDRG
-> SbKey
-> (ByteString, ByteString)
-> ExceptT AgentErrorType IO QueueLinkData
encryptLinkData TVar ChaChaDRG
g SbKey
k = (ByteString -> ExceptT AgentErrorType IO EncFixedDataBytes)
-> (ByteString -> ExceptT AgentErrorType IO EncFixedDataBytes)
-> (ByteString, ByteString)
-> ExceptT AgentErrorType IO QueueLinkData
forall (t :: * -> * -> *) (f :: * -> *) a c b d.
(Bitraversable t, Applicative f) =>
(a -> f c) -> (b -> f d) -> t a b -> f (t c d)
bimapM (Int -> ByteString -> ExceptT AgentErrorType IO EncFixedDataBytes
encrypt Int
fixedDataPaddedLength) (Int -> ByteString -> ExceptT AgentErrorType IO EncFixedDataBytes
encrypt Int
userDataPaddedLength)
where
encrypt :: Int -> ByteString -> ExceptT AgentErrorType IO EncFixedDataBytes
encrypt Int
len = TVar ChaChaDRG
-> SbKey
-> Int
-> ByteString
-> ExceptT AgentErrorType IO EncFixedDataBytes
encryptData TVar ChaChaDRG
g SbKey
k Int
len
encryptUserData :: TVar ChaChaDRG -> C.SbKey -> ByteString -> ExceptT AgentErrorType IO EncDataBytes
encryptUserData :: TVar ChaChaDRG
-> SbKey
-> ByteString
-> ExceptT AgentErrorType IO EncFixedDataBytes
encryptUserData TVar ChaChaDRG
g SbKey
k ByteString
s = TVar ChaChaDRG
-> SbKey
-> Int
-> ByteString
-> ExceptT AgentErrorType IO EncFixedDataBytes
encryptData TVar ChaChaDRG
g SbKey
k Int
userDataPaddedLength ByteString
s
encryptData :: TVar ChaChaDRG -> C.SbKey -> Int -> ByteString -> ExceptT AgentErrorType IO EncDataBytes
encryptData :: TVar ChaChaDRG
-> SbKey
-> Int
-> ByteString
-> ExceptT AgentErrorType IO EncFixedDataBytes
encryptData TVar ChaChaDRG
g SbKey
k Int
len ByteString
s = do
CbNonce
nonce <- IO CbNonce -> ExceptT AgentErrorType IO CbNonce
forall a. IO a -> ExceptT AgentErrorType IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO CbNonce -> ExceptT AgentErrorType IO CbNonce)
-> IO CbNonce -> ExceptT AgentErrorType IO CbNonce
forall a b. (a -> b) -> a -> b
$ STM CbNonce -> IO CbNonce
forall a. STM a -> IO a
atomically (STM CbNonce -> IO CbNonce) -> STM CbNonce -> IO CbNonce
forall a b. (a -> b) -> a -> b
$ TVar ChaChaDRG -> STM CbNonce
C.randomCbNonce TVar ChaChaDRG
g
ByteString
ct <- (CryptoError -> AgentErrorType)
-> Either CryptoError ByteString
-> ExceptT AgentErrorType IO ByteString
forall (m :: * -> *) e e' a.
MonadIO m =>
(e -> e') -> Either e a -> ExceptT e' m a
liftEitherWith CryptoError -> AgentErrorType
cryptoError (Either CryptoError ByteString
-> ExceptT AgentErrorType IO ByteString)
-> Either CryptoError ByteString
-> ExceptT AgentErrorType IO ByteString
forall a b. (a -> b) -> a -> b
$ SbKey
-> CbNonce -> ByteString -> Int -> Either CryptoError ByteString
C.sbEncrypt SbKey
k CbNonce
nonce ByteString
s Int
len
EncFixedDataBytes -> ExceptT AgentErrorType IO EncFixedDataBytes
forall a. a -> ExceptT AgentErrorType IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (EncFixedDataBytes -> ExceptT AgentErrorType IO EncFixedDataBytes)
-> EncFixedDataBytes -> ExceptT AgentErrorType IO EncFixedDataBytes
forall a b. (a -> b) -> a -> b
$ ByteString -> EncFixedDataBytes
EncDataBytes (ByteString -> EncFixedDataBytes)
-> ByteString -> EncFixedDataBytes
forall a b. (a -> b) -> a -> b
$ CbNonce -> ByteString
forall a. Encoding a => a -> ByteString
smpEncode CbNonce
nonce ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
ct
decryptLinkData :: forall c. ConnectionModeI c => LinkKey -> C.SbKey -> QueueLinkData -> Either AgentErrorType (FixedLinkData c, ConnLinkData c)
decryptLinkData :: forall (c :: ConnectionMode).
ConnectionModeI c =>
LinkKey
-> SbKey
-> QueueLinkData
-> Either AgentErrorType (FixedLinkData c, ConnLinkData c)
decryptLinkData LinkKey
linkKey SbKey
k (EncFixedDataBytes
encFD, EncFixedDataBytes
encMD) = do
(Signature 'Ed25519
sig1, ByteString
fd) <- EncFixedDataBytes
-> Either AgentErrorType (Signature 'Ed25519, ByteString)
decrypt EncFixedDataBytes
encFD
(Signature 'Ed25519
sig2, ByteString
md) <- EncFixedDataBytes
-> Either AgentErrorType (Signature 'Ed25519, ByteString)
decrypt EncFixedDataBytes
encMD
fd' :: FixedLinkData c
fd'@FixedLinkData {PublicKey 'Ed25519
$sel:rootKey:FixedLinkData :: forall (c :: ConnectionMode). FixedLinkData c -> PublicKey 'Ed25519
rootKey :: PublicKey 'Ed25519
rootKey} <- ByteString -> Either AgentErrorType (FixedLinkData c)
forall a. Encoding a => ByteString -> Either AgentErrorType a
decode ByteString
fd
ConnLinkData c
md' <- forall a. Encoding a => ByteString -> Either AgentErrorType a
decode @(ConnLinkData c) ByteString
md
let signedBy :: PublicKey 'Ed25519 -> Bool
signedBy PublicKey 'Ed25519
k' = PublicKey 'Ed25519 -> Signature 'Ed25519 -> ByteString -> Bool
forall (a :: Algorithm).
SignatureAlgorithm a =>
PublicKey a -> Signature a -> ByteString -> Bool
C.verify' PublicKey 'Ed25519
k' Signature 'Ed25519
sig2 ByteString
md
if
| ByteString -> LinkKey
LinkKey (ByteString -> ByteString
C.sha3_256 ByteString
fd) LinkKey -> LinkKey -> Bool
forall a. Eq a => a -> a -> Bool
/= LinkKey
linkKey -> String -> Either AgentErrorType ()
linkErr String
"link data hash"
| Bool -> Bool
not (PublicKey 'Ed25519 -> Signature 'Ed25519 -> ByteString -> Bool
forall (a :: Algorithm).
SignatureAlgorithm a =>
PublicKey a -> Signature a -> ByteString -> Bool
C.verify' PublicKey 'Ed25519
rootKey Signature 'Ed25519
sig1 ByteString
fd) -> String -> Either AgentErrorType ()
linkErr String
"link data signature"
| Bool
otherwise -> case ConnLinkData c
md' of
InvitationLinkData {} -> Bool -> Either AgentErrorType () -> Either AgentErrorType ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (PublicKey 'Ed25519 -> Bool
signedBy PublicKey 'Ed25519
rootKey) (Either AgentErrorType () -> Either AgentErrorType ())
-> Either AgentErrorType () -> Either AgentErrorType ()
forall a b. (a -> b) -> a -> b
$ String -> Either AgentErrorType ()
linkErr String
"user data signature"
ContactLinkData VersionRangeSMPA
_ UserContactData {[OwnerAuth]
owners :: [OwnerAuth]
$sel:owners:UserContactData :: UserContactData -> [OwnerAuth]
owners} -> do
(String -> AgentErrorType)
-> Either String () -> Either AgentErrorType ()
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (SMPAgentError -> AgentErrorType
AGENT (SMPAgentError -> AgentErrorType)
-> (String -> SMPAgentError) -> String -> AgentErrorType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> SMPAgentError
A_LINK) (Either String () -> Either AgentErrorType ())
-> Either String () -> Either AgentErrorType ()
forall a b. (a -> b) -> a -> b
$ PublicKey 'Ed25519 -> [OwnerAuth] -> Either String ()
validateLinkOwners PublicKey 'Ed25519
rootKey [OwnerAuth]
owners
Bool -> Either AgentErrorType () -> Either AgentErrorType ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (PublicKey 'Ed25519 -> Bool
signedBy PublicKey 'Ed25519
rootKey Bool -> Bool -> Bool
|| (OwnerAuth -> Bool) -> [OwnerAuth] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (PublicKey 'Ed25519 -> Bool
signedBy (PublicKey 'Ed25519 -> Bool)
-> (OwnerAuth -> PublicKey 'Ed25519) -> OwnerAuth -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OwnerAuth -> PublicKey 'Ed25519
ownerKey) [OwnerAuth]
owners) (Either AgentErrorType () -> Either AgentErrorType ())
-> Either AgentErrorType () -> Either AgentErrorType ()
forall a b. (a -> b) -> a -> b
$ String -> Either AgentErrorType ()
linkErr String
"user data signature"
(FixedLinkData c, ConnLinkData c)
-> Either AgentErrorType (FixedLinkData c, ConnLinkData c)
forall a b. b -> Either a b
Right (FixedLinkData c
fd', ConnLinkData c
md')
where
decrypt :: EncFixedDataBytes
-> Either AgentErrorType (Signature 'Ed25519, ByteString)
decrypt (EncDataBytes ByteString
d) = do
(CbNonce
nonce, Tail ByteString
ct) <- ByteString -> Either AgentErrorType (CbNonce, Tail)
forall a. Encoding a => ByteString -> Either AgentErrorType a
decode ByteString
d
(Signature 'Ed25519
sig, Tail ByteString
s) <- ByteString -> Either AgentErrorType (Signature 'Ed25519, Tail)
forall a. Encoding a => ByteString -> Either AgentErrorType a
decode (ByteString -> Either AgentErrorType (Signature 'Ed25519, Tail))
-> Either AgentErrorType ByteString
-> Either AgentErrorType (Signature 'Ed25519, Tail)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (CryptoError -> AgentErrorType)
-> Either CryptoError ByteString
-> Either AgentErrorType ByteString
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first CryptoError -> AgentErrorType
cryptoError (SbKey -> CbNonce -> ByteString -> Either CryptoError ByteString
C.sbDecrypt SbKey
k CbNonce
nonce ByteString
ct)
(Signature 'Ed25519, ByteString)
-> Either AgentErrorType (Signature 'Ed25519, ByteString)
forall a. a -> Either AgentErrorType a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Signature 'Ed25519
sig, ByteString
s)
decode :: Encoding a => ByteString -> Either AgentErrorType a
decode :: forall a. Encoding a => ByteString -> Either AgentErrorType a
decode = Either String a -> Either AgentErrorType a
forall {a} {c}. Either a c -> Either AgentErrorType c
msgErr (Either String a -> Either AgentErrorType a)
-> (ByteString -> Either String a)
-> ByteString
-> Either AgentErrorType a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String a
forall a. Encoding a => ByteString -> Either String a
smpDecode
msgErr :: Either a c -> Either AgentErrorType c
msgErr = (a -> AgentErrorType) -> Either a c -> Either AgentErrorType c
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (AgentErrorType -> a -> AgentErrorType
forall a b. a -> b -> a
const (AgentErrorType -> a -> AgentErrorType)
-> AgentErrorType -> a -> AgentErrorType
forall a b. (a -> b) -> a -> b
$ SMPAgentError -> AgentErrorType
AGENT SMPAgentError
A_MESSAGE)
linkErr :: String -> Either AgentErrorType ()
linkErr :: String -> Either AgentErrorType ()
linkErr = AgentErrorType -> Either AgentErrorType ()
forall a b. a -> Either a b
Left (AgentErrorType -> Either AgentErrorType ())
-> (String -> AgentErrorType) -> String -> Either AgentErrorType ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SMPAgentError -> AgentErrorType
AGENT (SMPAgentError -> AgentErrorType)
-> (String -> SMPAgentError) -> String -> AgentErrorType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> SMPAgentError
A_LINK