mirror of https://github.com/voidlizard/hbs2
183 lines
6.9 KiB
Haskell
183 lines
6.9 KiB
Haskell
{-# 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
|
||
|
||
)
|