{-# LANGUAGE ScopedTypeVariables #-}
module LibP2P.Switch.CertifiedRecords
(
CertifiedRecord (..)
, verifyPeerRecord
, consumeCertifiedRecord
, lookupCertifiedRecord
) where
import Control.Concurrent.STM (STM, TVar, modifyTVar', readTVar)
import Data.ByteString (ByteString)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Word (Word64)
import LibP2P.Crypto.PeerId (PeerId, fromPublicKey)
import LibP2P.Crypto.PeerRecord (PeerRecord (..), openPeerRecordEnvelope)
import LibP2P.Crypto.SignedEnvelope (SignedEnvelope (..))
data CertifiedRecord = CertifiedRecord
{ CertifiedRecord -> Word64
crSeq :: !Word64
, CertifiedRecord -> ByteString
crEnvelope :: !ByteString
, CertifiedRecord -> [ByteString]
crAddresses :: ![ByteString]
} deriving (Int -> CertifiedRecord -> ShowS
[CertifiedRecord] -> ShowS
CertifiedRecord -> String
(Int -> CertifiedRecord -> ShowS)
-> (CertifiedRecord -> String)
-> ([CertifiedRecord] -> ShowS)
-> Show CertifiedRecord
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CertifiedRecord -> ShowS
showsPrec :: Int -> CertifiedRecord -> ShowS
$cshow :: CertifiedRecord -> String
show :: CertifiedRecord -> String
$cshowList :: [CertifiedRecord] -> ShowS
showList :: [CertifiedRecord] -> ShowS
Show, CertifiedRecord -> CertifiedRecord -> Bool
(CertifiedRecord -> CertifiedRecord -> Bool)
-> (CertifiedRecord -> CertifiedRecord -> Bool)
-> Eq CertifiedRecord
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CertifiedRecord -> CertifiedRecord -> Bool
== :: CertifiedRecord -> CertifiedRecord -> Bool
$c/= :: CertifiedRecord -> CertifiedRecord -> Bool
/= :: CertifiedRecord -> CertifiedRecord -> Bool
Eq)
verifyPeerRecord :: PeerId -> ByteString -> Either String CertifiedRecord
verifyPeerRecord :: PeerId -> ByteString -> Either String CertifiedRecord
verifyPeerRecord PeerId
peer ByteString
envBytes = do
(env, record) <- ByteString -> Either String (SignedEnvelope, PeerRecord)
openPeerRecordEnvelope ByteString
envBytes
if fromPublicKey (sePublicKey env) == peer
then Right CertifiedRecord
{ crSeq = prSeq record
, crEnvelope = envBytes
, crAddresses = prAddresses record
}
else Left "signed peer record was not signed by the authenticated peer"
consumeCertifiedRecord
:: TVar (Map PeerId CertifiedRecord)
-> PeerId
-> CertifiedRecord
-> STM Bool
consumeCertifiedRecord :: TVar (Map PeerId CertifiedRecord)
-> PeerId -> CertifiedRecord -> STM Bool
consumeCertifiedRecord TVar (Map PeerId CertifiedRecord)
recordsVar PeerId
peer CertifiedRecord
record = do
known <- PeerId -> Map PeerId CertifiedRecord -> Maybe CertifiedRecord
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup PeerId
peer (Map PeerId CertifiedRecord -> Maybe CertifiedRecord)
-> STM (Map PeerId CertifiedRecord) -> STM (Maybe CertifiedRecord)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (Map PeerId CertifiedRecord)
-> STM (Map PeerId CertifiedRecord)
forall a. TVar a -> STM a
readTVar TVar (Map PeerId CertifiedRecord)
recordsVar
let fresher = Bool -> (CertifiedRecord -> Bool) -> Maybe CertifiedRecord -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
True ((CertifiedRecord -> Word64
crSeq CertifiedRecord
record Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
>) (Word64 -> Bool)
-> (CertifiedRecord -> Word64) -> CertifiedRecord -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CertifiedRecord -> Word64
crSeq) Maybe CertifiedRecord
known
if fresher
then do
modifyTVar' recordsVar (Map.insert peer record)
pure True
else pure False
lookupCertifiedRecord
:: TVar (Map PeerId CertifiedRecord)
-> PeerId
-> STM (Maybe CertifiedRecord)
lookupCertifiedRecord :: TVar (Map PeerId CertifiedRecord)
-> PeerId -> STM (Maybe CertifiedRecord)
lookupCertifiedRecord TVar (Map PeerId CertifiedRecord)
recordsVar PeerId
peer = PeerId -> Map PeerId CertifiedRecord -> Maybe CertifiedRecord
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup PeerId
peer (Map PeerId CertifiedRecord -> Maybe CertifiedRecord)
-> STM (Map PeerId CertifiedRecord) -> STM (Maybe CertifiedRecord)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar (Map PeerId CertifiedRecord)
-> STM (Map PeerId CertifiedRecord)
forall a. TVar a -> STM a
readTVar TVar (Map PeerId CertifiedRecord)
recordsVar