hbs2/hbs2-peer/app/ProxyMessaging.hs

183 lines
6.9 KiB
Haskell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{-# Language TemplateHaskell #-}
module ProxyMessaging
( ProxyMessaging
, PlainProxyMessaging(..)
, newProxyMessaging
, runProxyMessaging
, proxyEncryptionKeys
, sendToPlainProxyMessaging
) where
import HBS2.Prelude.Plated
import HBS2.Net.Messaging
import HBS2.Clock
import HBS2.Crypto
import HBS2.Net.Auth.Credentials
import HBS2.Net.Proto.Definition ()
import HBS2.Net.Proto.Peer
import HBS2.Net.Proto.Types
import HBS2.Net.Messaging.UDP
import HBS2.Net.Messaging.TCP
import HBS2.System.Logger.Simple
import Crypto.Saltine.Class as SCl
import Crypto.Saltine.Core.Box qualified as Encrypt
import Codec.Serialise
import Control.Applicative
import Control.Arrow hiding ((<+>))
import Control.Concurrent.Async
import Control.Concurrent.STM
import Control.Concurrent.STM.TQueue
import Control.Monad.Trans.Maybe
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as LBS
import Data.Maybe
import Data.String.Conversions (cs)
import Data.List qualified as L
import Data.Map (Map)
import Data.Map qualified as Map
import Lens.Micro.Platform as Lens
import Control.Monad
-- TODO: protocol-encryption-goes-here
data ProxyMessaging =
ProxyMessaging
{ _proxyUDP :: MessagingUDP
, _proxyTCP :: Maybe MessagingTCP
, _proxyAnswers :: TQueue (From L4Proto, LBS.ByteString)
, _proxyEncryptionKeys :: TVar (Map (Peer L4Proto) (CommonSecret (Encryption L4Proto)))
}
newtype PlainProxyMessaging = PlainProxyMessaging ProxyMessaging
-- 1 нода X создаёт себе Encrypt.Keypair
-- 2 подписывает из него публичный ключ ключом подписи ноды X и отправляет ноде Y
-- 3 нода Y получила Публичный ключ ноды X, создала симметричный Key,
-- зашифровала его для полученного Публичного ключа ноды X и отравила ей
makeLenses 'ProxyMessaging
newProxyMessaging :: forall m . MonadIO m
=> MessagingUDP
-> Maybe MessagingTCP
-> m ProxyMessaging
newProxyMessaging u t = liftIO do
ProxyMessaging u t
<$> newTQueueIO
<*> newTVarIO mempty
runProxyMessaging :: forall m . MonadIO m
=> ProxyMessaging
-> m ()
runProxyMessaging env = liftIO do
let udp = view proxyUDP env
let answ = view proxyAnswers env
let udpPeer = getOwnPeer udp
u <- async $ forever do
msgs <- receive udp (To udpPeer)
atomically $ do
forM_ msgs $ writeTQueue answ
t <- async $ maybe1 (view proxyTCP env) none $ \tcp -> do
forever do
msgs <- receive tcp (To $ view tcpOwnPeer tcp)
atomically $ do
forM_ msgs $ writeTQueue answ
liftIO $ mapM_ waitCatch [u,t]
instance Messaging PlainProxyMessaging L4Proto LBS.ByteString where
sendTo = sendToPlainProxyMessaging
receive (PlainProxyMessaging bus) = receive bus
sendToPlainProxyMessaging :: (MonadIO m)
=> PlainProxyMessaging
-> To L4Proto
-> From L4Proto
-> LBS.ByteString
-- -> AnyMessage LBS.ByteString L4Proto
-> m ()
sendToPlainProxyMessaging (PlainProxyMessaging bus) t@(To whom) proto msg = do
let udp = view proxyUDP bus
case view sockType whom of
UDP -> sendTo udp t proto msg
TCP -> maybe1 (view proxyTCP bus) none $ \tcp -> do
sendTo tcp t proto msg
instance Messaging ProxyMessaging L4Proto LBS.ByteString where
sendTo = sendToProxyMessaging
receive = receiveFromProxyMessaging
sendToProxyMessaging bus t@(To whom) proto msg = do
-- sendTo (view proxyUDP bus) t proto msg
-- trace $ "PROXY: SEND" <+> pretty whom
encKey <- Map.lookup whom <$> (liftIO . readTVarIO) (view proxyEncryptionKeys bus)
cf <- case encKey of
Nothing -> do
trace $ "ENCRYPTION SEND: sending plain message to" <+> pretty whom
pure id
Just k -> do
trace $ "ENCRYPTION SEND: sending encrypted message to" <+> pretty whom <+> "with key" <+> viaShow k
boxAfterNMLazy k <$> liftIO Encrypt.newNonce
sendTo (PlainProxyMessaging bus) t proto (cf msg)
receiveFromProxyMessaging :: MonadIO m
=> ProxyMessaging -> To L4Proto -> m [(From L4Proto, LBS.ByteString)]
receiveFromProxyMessaging bus _ = liftIO do
-- trace "PROXY: RECEIVE"
-- receive (view proxyUDP bus) w
let answ = view proxyAnswers bus
rs <- atomically $ liftM2 (:) (readTQueue answ) (flushTQueue answ)
fmap catMaybes $ forM rs \(w@(From whom), msg) -> do
encKeys <- (liftIO . readTVarIO) (view proxyEncryptionKeys bus)
fmap (w, ) <$> dfm whom (Map.lookup whom encKeys) msg
where
dfm :: Peer L4Proto -> Maybe Encrypt.CombinedKey -> LBS.ByteString -> IO (Maybe LBS.ByteString)
dfm = \whom mk msg -> case mk of
Nothing -> do
trace $ "ENCRYPTION RECEIVE: we do not have a key to decode" <+> pretty whom
pure (Just msg)
Just k -> runMaybeT $
-- А будем-ка мы просто передавать сообщение дальше как есть, если не смогли расшифровать
(<|> (do
-- И сотрём ключ из памяти
liftIO $ atomically $ modifyTVar' (view proxyEncryptionKeys bus) $ Lens.at whom .~ Nothing
trace $ "ENCRYPTION RECEIVE: got plain message. clearing key of" <+> pretty whom
pure msg
)) $
do
trace $ "ENCRYPTION RECEIVE: we have a key to decode from" <+> pretty whom <+> ":" <+> viaShow k
case ((extractNonce . cs) msg) of
Nothing -> do
trace $ "ENCRYPTION RECEIVE: can not extract nonce from" <+> pretty whom <+> "message" <+> viaShow msg
fail ""
Just (nonce, msg') ->
((MaybeT . pure) (boxOpenAfterNMLazy k nonce msg')
<* (trace $ "ENCRYPTION RECEIVE: message successfully decoded from" <+> pretty whom)
)
<|>
(do
(trace $ "ENCRYPTION RECEIVE: can not decode message from" <+> pretty whom)
fail ""
-- -- Попытаться десериализовать сообщение как PeerPing или PeerPingCrypted
-- case deserialiseOrFail msg of
-- Right (_ :: PeerHandshake L4Proto) -> do
-- trace $ "ENCRYPTION RECEIVE: plain message decoded as PeerHandshake" <+> pretty whom
-- fail ""
-- Left _ -> do
-- trace $ "ENCRYPTION RECEIVE: failed" <+> pretty whom
-- mzero
)