mirror of https://github.com/voidlizard/hbs2
set policy for mailbox
This commit is contained in:
parent
6962b7412e
commit
d3d295d599
|
@ -50,7 +50,7 @@ fixme-comments ";" "--"
|
||||||
(align 8 $class) " "
|
(align 8 $class) " "
|
||||||
(align 12 $assigned) " "
|
(align 12 $assigned) " "
|
||||||
(align 20 (trim 20 $committer-name)) " "
|
(align 20 (trim 20 $committer-name)) " "
|
||||||
(trim 50 ($fixme-title)) " "
|
(trim 40 ($fixme-title)) " "
|
||||||
(nl))
|
(nl))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,9 +6,5 @@ module HBS2.Net.Proto
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
import HBS2.Net.Proto.Types
|
import HBS2.Net.Proto.Types
|
||||||
|
|
||||||
|
|
||||||
dontHandle :: Applicative f => a -> f ()
|
|
||||||
dontHandle = const $ pure ()
|
|
||||||
|
|
||||||
type GetBlockSize h m = Hash h -> m (Maybe Integer)
|
type GetBlockSize h m = Hash h -> m (Maybe Integer)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ module HBS2.Prelude
|
||||||
, HasErrorStatus(..), ErrorStatus(..), SomeError(..), WithSomeError(..), mayE, someE
|
, HasErrorStatus(..), ErrorStatus(..), SomeError(..), WithSomeError(..), mayE, someE
|
||||||
, ByFirst(..)
|
, ByFirst(..)
|
||||||
, whenTrue, whenFalse
|
, whenTrue, whenFalse
|
||||||
|
, dontHandle
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import HBS2.Clock
|
import HBS2.Clock
|
||||||
|
@ -174,11 +175,10 @@ instance Eq a => Eq (ByFirst a b) where
|
||||||
instance Hashable a => Hashable (ByFirst a b) where
|
instance Hashable a => Hashable (ByFirst a b) where
|
||||||
hashWithSalt s (ByFirst a _) = hashWithSalt s a
|
hashWithSalt s (ByFirst a _) = hashWithSalt s a
|
||||||
|
|
||||||
|
dontHandle :: Applicative f => a -> f ()
|
||||||
|
dontHandle = const $ pure ()
|
||||||
|
|
||||||
-- asyncLinked :: forall m . MonadUnliftIO m =>
|
-- asyncLinked :: forall m . MonadUnliftIO m =>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
module CLI.Mailbox (pMailBox) where
|
module CLI.Mailbox (pMailBox) where
|
||||||
|
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
|
import HBS2.Base58
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
import HBS2.OrDie
|
import HBS2.OrDie
|
||||||
import HBS2.Merkle
|
import HBS2.Merkle
|
||||||
|
@ -10,6 +11,7 @@ import HBS2.Data.Types.Refs
|
||||||
import HBS2.Net.Proto.Service
|
import HBS2.Net.Proto.Service
|
||||||
import HBS2.Net.Auth.Credentials
|
import HBS2.Net.Auth.Credentials
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
|
import HBS2.Storage.Operations.ByteString
|
||||||
import HBS2.Data.Types.SignedBox
|
import HBS2.Data.Types.SignedBox
|
||||||
import HBS2.Peer.Proto.Mailbox
|
import HBS2.Peer.Proto.Mailbox
|
||||||
import HBS2.Peer.Proto.Mailbox.Types
|
import HBS2.Peer.Proto.Mailbox.Types
|
||||||
|
@ -28,6 +30,8 @@ import Codec.Serialise
|
||||||
import Control.Monad.Trans.Cont
|
import Control.Monad.Trans.Cont
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Data.ByteString.Lazy qualified as LBS
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
|
import Data.ByteString.Lazy.Char8 qualified as LBS8
|
||||||
|
import Data.Either
|
||||||
import Data.Coerce
|
import Data.Coerce
|
||||||
import Data.Config.Suckless.Script
|
import Data.Config.Suckless.Script
|
||||||
import Data.HashSet (HashSet)
|
import Data.HashSet (HashSet)
|
||||||
|
@ -150,6 +154,59 @@ runMailboxCLI rpc s = do
|
||||||
_ -> throwIO $ BadFormException @C nil
|
_ -> throwIO $ BadFormException @C nil
|
||||||
|
|
||||||
|
|
||||||
|
brief "set mailbox policy" $
|
||||||
|
desc setPolicyDesc
|
||||||
|
-- $ examples setPolicyExamples
|
||||||
|
$ entry $ bindMatch "set-policy" $ nil_ $ \case
|
||||||
|
[ SignPubKeyLike m, LitIntVal v, StringLike fn ] -> lift do
|
||||||
|
|
||||||
|
mstatus <- callRpcWaitMay @RpcMailboxGetStatus t api m
|
||||||
|
>>= orThrowUser "rpc call timeout"
|
||||||
|
>>= orThrowPassIO
|
||||||
|
|
||||||
|
s <- liftIO $ readFile fn
|
||||||
|
<&> parseTop
|
||||||
|
>>= either (error . show) pure
|
||||||
|
|
||||||
|
pv <- fromMaybe 0 <$> runMaybeT do
|
||||||
|
MailBoxStatusPayload{..} <- toMPlus mstatus
|
||||||
|
pbox <- toMPlus mbsMailboxPolicy
|
||||||
|
(who, SetPolicyPayload{..}) <- unboxSignedBox0 pbox & toMPlus
|
||||||
|
|
||||||
|
guard ( m == who )
|
||||||
|
|
||||||
|
pure sppPolicyVersion
|
||||||
|
|
||||||
|
-- TODO: validate-policy
|
||||||
|
|
||||||
|
creds <- runKeymanClientRO (loadCredentials m)
|
||||||
|
>>= orThrowUser ("can't load credentials for" <+> pretty (AsBase58 m))
|
||||||
|
|
||||||
|
let normalized = show $ vcat (fmap pretty s)
|
||||||
|
|
||||||
|
notice $ "policy" <> line <> pretty normalized
|
||||||
|
|
||||||
|
notice $ "okay" <+> pretty pv <+> "->" <+> pretty v <+> pretty fn
|
||||||
|
|
||||||
|
hash <- writeAsMerkle sto (LBS8.pack normalized)
|
||||||
|
|
||||||
|
notice $ "stored policy as" <+> pretty hash
|
||||||
|
|
||||||
|
let spp = SetPolicyPayload @HBS2Basic m (fromIntegral v) (HashRef hash)
|
||||||
|
|
||||||
|
let box = makeSignedBox @HBS2Basic (view peerSignPk creds) (view peerSignSk creds) spp
|
||||||
|
|
||||||
|
notice $ "signed policy payload done okay"
|
||||||
|
|
||||||
|
r <- callRpcWaitMay @RpcMailboxSetPolicy t api (m,box)
|
||||||
|
>>= orThrowUser "rpc call timeout"
|
||||||
|
>>= orThrowPassIO
|
||||||
|
|
||||||
|
liftIO $ print $ pretty r
|
||||||
|
|
||||||
|
_ -> throwIO $ BadFormException @C nil
|
||||||
|
|
||||||
|
|
||||||
brief "list mailboxes"
|
brief "list mailboxes"
|
||||||
$ entry $ bindMatch "list" $ nil_ $ const do
|
$ entry $ bindMatch "list" $ nil_ $ const do
|
||||||
|
|
||||||
|
@ -283,3 +340,12 @@ SEE ALSO
|
||||||
|
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
|
||||||
|
setPolicyDesc :: Doc a
|
||||||
|
setPolicyDesc = [qc|
|
||||||
|
set-policy (MAILBOX-KEY :: PUBKEY) (VERSION :: INT) FILENAME
|
||||||
|
|]
|
||||||
|
|
||||||
|
setPolicyExamples :: ManExamples
|
||||||
|
setPolicyExamples = mempty
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||||
|
{-# Language MultiWayIf #-}
|
||||||
{-# Language AllowAmbiguousTypes #-}
|
{-# Language AllowAmbiguousTypes #-}
|
||||||
{-# Language UndecidableInstances #-}
|
{-# Language UndecidableInstances #-}
|
||||||
module MailboxProtoWorker ( mailboxProtoWorker
|
module MailboxProtoWorker ( mailboxProtoWorker
|
||||||
|
@ -20,6 +21,7 @@ import HBS2.Storage
|
||||||
import HBS2.Storage.Operations.Missed
|
import HBS2.Storage.Operations.Missed
|
||||||
import HBS2.Merkle
|
import HBS2.Merkle
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
|
import HBS2.Data.Types.SignedBox
|
||||||
import HBS2.Peer.Proto
|
import HBS2.Peer.Proto
|
||||||
import HBS2.Peer.Proto.Mailbox
|
import HBS2.Peer.Proto.Mailbox
|
||||||
import HBS2.Peer.Proto.Mailbox.Entry
|
import HBS2.Peer.Proto.Mailbox.Entry
|
||||||
|
@ -35,22 +37,34 @@ import PeerConfig
|
||||||
import PeerTypes
|
import PeerTypes
|
||||||
import BlockDownload()
|
import BlockDownload()
|
||||||
|
|
||||||
import DBPipe.SQLite
|
import DBPipe.SQLite as Q
|
||||||
|
|
||||||
import Control.Concurrent.STM qualified as STM
|
import Control.Concurrent.STM qualified as STM
|
||||||
-- import Control.Concurrent.STM.TBQueue
|
-- import Control.Concurrent.STM.TBQueue
|
||||||
import Control.Monad.Trans.Cont
|
import Control.Monad.Trans.Cont
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Control.Monad.Trans.Except
|
||||||
|
import Control.Monad.Except (throwError)
|
||||||
import Data.Coerce
|
import Data.Coerce
|
||||||
import Data.HashMap.Strict (HashMap)
|
import Data.HashMap.Strict (HashMap)
|
||||||
import Data.HashMap.Strict qualified as HM
|
import Data.HashMap.Strict qualified as HM
|
||||||
import Data.HashSet (HashSet)
|
import Data.HashSet (HashSet)
|
||||||
import Data.HashSet qualified as HS
|
import Data.HashSet qualified as HS
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Codec.Serialise
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
import Text.InterpolatedString.Perl6 (qc)
|
import Text.InterpolatedString.Perl6 (qc)
|
||||||
import UnliftIO
|
import UnliftIO
|
||||||
|
|
||||||
|
newtype PolicyHash = PolicyHash HashRef
|
||||||
|
deriving newtype (Eq,Ord,Show,Hashable,Pretty)
|
||||||
|
|
||||||
|
instance FromField PolicyHash where
|
||||||
|
fromField s = PolicyHash . fromString <$> fromField @String s
|
||||||
|
|
||||||
|
instance ToField PolicyHash where
|
||||||
|
toField f = toField (show $ pretty f)
|
||||||
|
|
||||||
data MailboxProtoException =
|
data MailboxProtoException =
|
||||||
MailboxProtoWorkerTerminatedException
|
MailboxProtoWorkerTerminatedException
|
||||||
| MailboxProtoCantAccessMailboxes FilePath
|
| MailboxProtoCantAccessMailboxes FilePath
|
||||||
|
@ -116,9 +130,54 @@ instance ( s ~ Encryption e, e ~ L4Proto
|
||||||
Right{} -> pure $ Right ()
|
Right{} -> pure $ Right ()
|
||||||
Left{} -> pure $ Left (MailboxCreateFailed "database operation")
|
Left{} -> pure $ Left (MailboxCreateFailed "database operation")
|
||||||
|
|
||||||
|
mailboxSetPolicy MailboxProtoWorker{..} sbox = do
|
||||||
|
-- check policy version
|
||||||
|
-- check policy has peers
|
||||||
|
-- write policy block
|
||||||
|
-- update reference to policy block
|
||||||
|
--
|
||||||
|
-- test: write policy, check mailboxGetStatus
|
||||||
|
|
||||||
|
debug $ red "mailboxSetPolicy"
|
||||||
|
|
||||||
|
runExceptT do
|
||||||
|
|
||||||
|
-- check policy signature
|
||||||
|
(who, spp) <- unboxSignedBox0 sbox
|
||||||
|
& orThrowError (MailboxAuthError "invalid signature")
|
||||||
|
|
||||||
|
dbe <- readTVarIO mailboxDB
|
||||||
|
>>= orThrowError (MailboxSetPolicyFailed "database not ready")
|
||||||
|
|
||||||
|
loaded <- loadPolicyPayloadFor dbe mpwStorage (MailboxRefKey @s who)
|
||||||
|
<&> fmap ( unboxSignedBox0 @(SetPolicyPayload s) @s . snd )
|
||||||
|
<&> join
|
||||||
|
|
||||||
|
what <- case loaded of
|
||||||
|
Nothing -> do
|
||||||
|
err $ red "mailboxSetPolicy FUCKED"
|
||||||
|
putBlock mpwStorage (serialise sbox)
|
||||||
|
>>= orThrowError (MailboxSetPolicyFailed "storage error")
|
||||||
|
<&> HashRef
|
||||||
|
|
||||||
|
Just (k, spp0) | sppPolicyVersion spp > sppPolicyVersion spp0 || k /= who -> do
|
||||||
|
putBlock mpwStorage (serialise sbox)
|
||||||
|
>>= orThrowError (MailboxSetPolicyFailed "storage error")
|
||||||
|
<&> HashRef
|
||||||
|
|
||||||
|
_ -> do
|
||||||
|
throwError (MailboxSetPolicyFailed "too old")
|
||||||
|
|
||||||
|
liftIO $ withDB dbe $ Q.transactional do
|
||||||
|
insert [qc| insert into policy (mailbox,hash) values(?,?)
|
||||||
|
on conflict (mailbox) do update set hash = excluded.hash
|
||||||
|
|] (MailboxRefKey @s who, PolicyHash what)
|
||||||
|
|
||||||
|
pure what
|
||||||
|
|
||||||
mailboxDelete MailboxProtoWorker{..} mbox = do
|
mailboxDelete MailboxProtoWorker{..} mbox = do
|
||||||
|
|
||||||
flip runContT pure $ callCC \exit -> do
|
flip runContT pure do
|
||||||
|
|
||||||
mdbe <- readTVarIO mailboxDB
|
mdbe <- readTVarIO mailboxDB
|
||||||
|
|
||||||
|
@ -163,6 +222,11 @@ instance ( s ~ Encryption e, e ~ L4Proto
|
||||||
|
|
||||||
pure $ Right r
|
pure $ Right r
|
||||||
|
|
||||||
|
mailboxAcceptStatus MailboxProtoWorker{..} ref who MailBoxStatusPayload{..} = do
|
||||||
|
-- TODO: implement-policy-first
|
||||||
|
-- итак, мы не можем двигаться, пока не будет реализована policy.
|
||||||
|
pure $ Right ()
|
||||||
|
|
||||||
mailboxGetStatus MailboxProtoWorker{..} ref = do
|
mailboxGetStatus MailboxProtoWorker{..} ref = do
|
||||||
-- TODO: support-policy-ASAP
|
-- TODO: support-policy-ASAP
|
||||||
|
|
||||||
|
@ -180,7 +244,30 @@ instance ( s ~ Encryption e, e ~ L4Proto
|
||||||
|
|
||||||
v <- getRef mpwStorage ref <&> fmap HashRef
|
v <- getRef mpwStorage ref <&> fmap HashRef
|
||||||
|
|
||||||
pure $ Right $ Just $ MailBoxStatusPayload @s now (coerce ref) t v mzero mzero
|
spp <- loadPolicyPayloadFor dbe mpwStorage ref
|
||||||
|
<&> fmap snd
|
||||||
|
|
||||||
|
pure $ Right $ Just $ MailBoxStatusPayload @s now (coerce ref) t v spp
|
||||||
|
|
||||||
|
loadPolicyPayloadFor :: forall s m . (ForMailbox s, MonadIO m)
|
||||||
|
=> DBPipeEnv
|
||||||
|
-> AnyStorage
|
||||||
|
-> MailboxRefKey s
|
||||||
|
-> m (Maybe (HashRef, SignedBox (SetPolicyPayload s) s))
|
||||||
|
loadPolicyPayloadFor dbe sto who = do
|
||||||
|
phash <- withDB dbe do
|
||||||
|
select @(Only PolicyHash) [qc|select hash from policy where mailbox = ?|] (Only who)
|
||||||
|
<&> fmap (coerce @_ @HashRef . fromOnly)
|
||||||
|
<&> headMay
|
||||||
|
|
||||||
|
runMaybeT do
|
||||||
|
ha <- toMPlus phash
|
||||||
|
what <- getBlock sto (coerce ha)
|
||||||
|
>>= toMPlus
|
||||||
|
<&> deserialiseOrFail
|
||||||
|
>>= toMPlus
|
||||||
|
pure (ha, what)
|
||||||
|
|
||||||
|
|
||||||
getMailboxType_ :: (ForMailbox s, MonadIO m) => DBPipeEnv -> MailboxRefKey s -> m (Maybe MailboxType)
|
getMailboxType_ :: (ForMailbox s, MonadIO m) => DBPipeEnv -> MailboxRefKey s -> m (Maybe MailboxType)
|
||||||
getMailboxType_ d r = do
|
getMailboxType_ d r = do
|
||||||
|
@ -316,7 +403,10 @@ mailboxProtoWorker readConf me@MailboxProtoWorker{..} = do
|
||||||
-- NOTE: reliability
|
-- NOTE: reliability
|
||||||
-- в случае отказа сторейджа все эти сообщения будут потеряны
|
-- в случае отказа сторейджа все эти сообщения будут потеряны
|
||||||
-- однако, ввиду дублирования -- они рано или поздно будут
|
-- однако, ввиду дублирования -- они рано или поздно будут
|
||||||
-- восстановлены с других реплик, если таковые имеются
|
-- восстановлены с других реплик, если таковые имеются.
|
||||||
|
--
|
||||||
|
-- Кроме того, мы можем писать WAL.
|
||||||
|
--
|
||||||
newTx <- atomically do
|
newTx <- atomically do
|
||||||
n <- readTVar inMessageMergeQueue
|
n <- readTVar inMessageMergeQueue
|
||||||
<&> fromMaybe mempty . HM.lookup r
|
<&> fromMaybe mempty . HM.lookup r
|
||||||
|
@ -363,7 +453,7 @@ mailboxStateEvolve readConf MailboxProtoWorker{..} = do
|
||||||
|
|
||||||
atomically $ writeTVar mailboxDB (Just dbe)
|
atomically $ writeTVar mailboxDB (Just dbe)
|
||||||
|
|
||||||
withDB dbe do
|
withDB dbe $ Q.transactional do
|
||||||
ddl [qc|create table if not exists
|
ddl [qc|create table if not exists
|
||||||
mailbox ( recipient text not null
|
mailbox ( recipient text not null
|
||||||
, type text not null
|
, type text not null
|
||||||
|
@ -371,6 +461,13 @@ mailboxStateEvolve readConf MailboxProtoWorker{..} = do
|
||||||
)
|
)
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
ddl [qc|create table if not exists
|
||||||
|
policy ( mailbox text not null
|
||||||
|
, hash text not null
|
||||||
|
, primary key (mailbox)
|
||||||
|
)
|
||||||
|
|]
|
||||||
|
|
||||||
pure dbe
|
pure dbe
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,12 @@ instance (ForMailboxRPC m) => HandleMethod m RpcMailboxCreate where
|
||||||
void $ mailboxCreate @HBS2Basic mbs t puk
|
void $ mailboxCreate @HBS2Basic mbs t puk
|
||||||
debug $ "rpc.RpcMailboxCreate" <+> pretty (AsBase58 puk) <+> pretty t
|
debug $ "rpc.RpcMailboxCreate" <+> pretty (AsBase58 puk) <+> pretty t
|
||||||
|
|
||||||
|
instance (ForMailboxRPC m) => HandleMethod m RpcMailboxSetPolicy where
|
||||||
|
|
||||||
|
handleMethod (puk, sbox) = do
|
||||||
|
AnyMailboxService mbs <- getRpcContext @MailboxAPI @RPC2Context <&> rpcMailboxService
|
||||||
|
debug $ "rpc.RpcMailboxSetPolicy" <+> pretty (AsBase58 puk)
|
||||||
|
mailboxSetPolicy @HBS2Basic mbs sbox
|
||||||
|
|
||||||
instance (ForMailboxRPC m) => HandleMethod m RpcMailboxGetStatus where
|
instance (ForMailboxRPC m) => HandleMethod m RpcMailboxGetStatus where
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,12 @@ import HBS2.Data.Types.Refs
|
||||||
import HBS2.Data.Types.SignedBox
|
import HBS2.Data.Types.SignedBox
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
import HBS2.Actors.Peer.Types
|
import HBS2.Actors.Peer.Types
|
||||||
|
import HBS2.Data.Types.Peer
|
||||||
import HBS2.Net.Auth.Credentials
|
import HBS2.Net.Auth.Credentials
|
||||||
|
|
||||||
|
|
||||||
|
import HBS2.Net.Proto.Sessions
|
||||||
|
import HBS2.Peer.Proto.Peer
|
||||||
import HBS2.Peer.Proto.Mailbox.Types
|
import HBS2.Peer.Proto.Mailbox.Types
|
||||||
import HBS2.Peer.Proto.Mailbox.Message
|
import HBS2.Peer.Proto.Mailbox.Message
|
||||||
import HBS2.Peer.Proto.Mailbox.Entry
|
import HBS2.Peer.Proto.Mailbox.Entry
|
||||||
|
@ -29,22 +33,21 @@ import Data.Maybe
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
|
|
||||||
|
data SetPolicyPayload s =
|
||||||
|
SetPolicyPayload
|
||||||
|
{ sppMailboxKey :: MailboxKey s
|
||||||
|
, sppPolicyVersion :: PolicyVersion
|
||||||
|
, sppPolicyRef :: HashRef -- ^ merkle tree hash of policy description file
|
||||||
|
}
|
||||||
|
deriving stock (Generic)
|
||||||
|
|
||||||
data MailBoxStatusPayload s =
|
data MailBoxStatusPayload s =
|
||||||
MailBoxStatusPayload
|
MailBoxStatusPayload
|
||||||
{ mbsMailboxPayloadNonce :: Word64
|
{ mbsMailboxPayloadNonce :: Word64
|
||||||
, mbsMailboxKey :: MailboxKey s
|
, mbsMailboxKey :: MailboxKey s
|
||||||
, mbsMailboxType :: MailboxType
|
, mbsMailboxType :: MailboxType
|
||||||
, mbsMailboxHash :: Maybe HashRef
|
, mbsMailboxHash :: Maybe HashRef
|
||||||
, mbsMailboxPolicyVersion :: Maybe PolicyVersion
|
, mbsMailboxPolicy :: Maybe (SignedBox (SetPolicyPayload s) s)
|
||||||
, mbsMailboxPolicyHash :: Maybe HashRef
|
|
||||||
}
|
|
||||||
deriving stock (Generic)
|
|
||||||
|
|
||||||
data SetPolicyPayload s =
|
|
||||||
SetPolicyPayload
|
|
||||||
{ sppMailboxKey :: MailboxKey s
|
|
||||||
, sppPolicyVersion :: PolicyVersion
|
|
||||||
, sppPolicyRef :: HashRef
|
|
||||||
}
|
}
|
||||||
deriving stock (Generic)
|
deriving stock (Generic)
|
||||||
|
|
||||||
|
@ -57,7 +60,7 @@ data DeleteMessagesPayload s =
|
||||||
|
|
||||||
data MailBoxProtoMessage s e =
|
data MailBoxProtoMessage s e =
|
||||||
SendMessage (Message s) -- already has signed box
|
SendMessage (Message s) -- already has signed box
|
||||||
| CheckMailbox (MailboxKey s)
|
| CheckMailbox (Maybe Word64) (MailboxKey s)
|
||||||
| MailboxStatus (SignedBox (MailBoxStatusPayload s) s) -- signed by peer
|
| MailboxStatus (SignedBox (MailBoxStatusPayload s) s) -- signed by peer
|
||||||
| SetPolicy (SignedBox (SetPolicyPayload s) s)
|
| SetPolicy (SignedBox (SetPolicyPayload s) s)
|
||||||
| DeleteMessages (SignedBox (DeleteMessagesPayload s) s)
|
| DeleteMessages (SignedBox (DeleteMessagesPayload s) s)
|
||||||
|
@ -94,6 +97,11 @@ class ForMailbox s => IsMailboxService s a where
|
||||||
-> Recipient s
|
-> Recipient s
|
||||||
-> m (Either MailboxServiceError ())
|
-> m (Either MailboxServiceError ())
|
||||||
|
|
||||||
|
mailboxSetPolicy :: forall m . MonadIO m
|
||||||
|
=> a
|
||||||
|
-> SignedBox (SetPolicyPayload s) s
|
||||||
|
-> m (Either MailboxServiceError HashRef)
|
||||||
|
|
||||||
mailboxDelete :: forall m . MonadIO m
|
mailboxDelete :: forall m . MonadIO m
|
||||||
=> a
|
=> a
|
||||||
-> Recipient s
|
-> Recipient s
|
||||||
|
@ -120,6 +128,12 @@ class ForMailbox s => IsMailboxService s a where
|
||||||
-> MailboxRefKey s
|
-> MailboxRefKey s
|
||||||
-> m (Either MailboxServiceError (Maybe (MailBoxStatusPayload s)))
|
-> m (Either MailboxServiceError (Maybe (MailBoxStatusPayload s)))
|
||||||
|
|
||||||
|
mailboxAcceptStatus :: forall m . MonadIO m
|
||||||
|
=> a
|
||||||
|
-> MailboxRefKey s
|
||||||
|
-> PubKey 'Sign s -- ^ peer's key
|
||||||
|
-> MailBoxStatusPayload s
|
||||||
|
-> m (Either MailboxServiceError ())
|
||||||
|
|
||||||
data AnyMailboxService s =
|
data AnyMailboxService s =
|
||||||
forall a . (IsMailboxService s a) => AnyMailboxService { mailboxService :: a }
|
forall a . (IsMailboxService s a) => AnyMailboxService { mailboxService :: a }
|
||||||
|
@ -129,11 +143,13 @@ data AnyMailboxAdapter s =
|
||||||
|
|
||||||
instance ForMailbox s => IsMailboxService s (AnyMailboxService s) where
|
instance ForMailbox s => IsMailboxService s (AnyMailboxService s) where
|
||||||
mailboxCreate (AnyMailboxService a) = mailboxCreate @s a
|
mailboxCreate (AnyMailboxService a) = mailboxCreate @s a
|
||||||
|
mailboxSetPolicy (AnyMailboxService a) = mailboxSetPolicy @s a
|
||||||
mailboxDelete (AnyMailboxService a) = mailboxDelete @s a
|
mailboxDelete (AnyMailboxService a) = mailboxDelete @s a
|
||||||
mailboxSendMessage (AnyMailboxService a) = mailboxSendMessage @s a
|
mailboxSendMessage (AnyMailboxService a) = mailboxSendMessage @s a
|
||||||
mailboxSendDelete (AnyMailboxService a) = mailboxSendDelete @s a
|
mailboxSendDelete (AnyMailboxService a) = mailboxSendDelete @s a
|
||||||
mailboxListBasic (AnyMailboxService a) = mailboxListBasic @s a
|
mailboxListBasic (AnyMailboxService a) = mailboxListBasic @s a
|
||||||
mailboxGetStatus (AnyMailboxService a) = mailboxGetStatus @s a
|
mailboxGetStatus (AnyMailboxService a) = mailboxGetStatus @s a
|
||||||
|
mailboxAcceptStatus (AnyMailboxService a) = mailboxAcceptStatus @s a
|
||||||
|
|
||||||
instance IsMailboxProtoAdapter s (AnyMailboxAdapter s) where
|
instance IsMailboxProtoAdapter s (AnyMailboxAdapter s) where
|
||||||
mailboxGetCredentials (AnyMailboxAdapter a) = mailboxGetCredentials @s a
|
mailboxGetCredentials (AnyMailboxAdapter a) = mailboxGetCredentials @s a
|
||||||
|
@ -146,22 +162,35 @@ instance ForMailbox s => Pretty (MailBoxStatusPayload s) where
|
||||||
where
|
where
|
||||||
st = indent 2 $
|
st = indent 2 $
|
||||||
brackets $
|
brackets $
|
||||||
vcat [ parens ("nonce" <+> pretty mbsMailboxPayloadNonce)
|
align $ vcat
|
||||||
|
[ parens ("nonce" <+> pretty mbsMailboxPayloadNonce)
|
||||||
, parens ("key" <+> pretty (AsBase58 mbsMailboxKey))
|
, parens ("key" <+> pretty (AsBase58 mbsMailboxKey))
|
||||||
, parens ("type" <+> pretty mbsMailboxType)
|
, parens ("type" <+> pretty mbsMailboxType)
|
||||||
, element "mailbox-tree" mbsMailboxHash
|
, element "mailbox-tree" mbsMailboxHash
|
||||||
, element "policy-version" mbsMailboxPolicyVersion
|
, element "set-policy-payload-hash" (HashRef . hashObject . serialise <$> mbsMailboxPolicy)
|
||||||
, element "policy-tree" mbsMailboxPolicyHash
|
, maybe mempty pretty spp
|
||||||
]
|
]
|
||||||
|
|
||||||
element el = maybe mempty ( \v -> parens (el <+> pretty v) )
|
element el = maybe mempty ( \v -> parens (el <+> pretty v) )
|
||||||
|
|
||||||
|
spp = mbsMailboxPolicy >>= unboxSignedBox0 <&> snd
|
||||||
|
|
||||||
|
|
||||||
|
instance ForMailbox s => Pretty (SetPolicyPayload s) where
|
||||||
|
pretty SetPolicyPayload{..} = parens ( "set-policy-payload" <> line <> indent 2 (brackets w) )
|
||||||
|
where
|
||||||
|
w = align $
|
||||||
|
vcat [ parens ( "version" <+> pretty sppPolicyVersion )
|
||||||
|
, parens ( "ref" <+> pretty sppPolicyRef )
|
||||||
|
]
|
||||||
|
|
||||||
mailboxProto :: forall e s m p a . ( MonadIO m
|
mailboxProto :: forall e s m p a . ( MonadIO m
|
||||||
, Response e p m
|
, Response e p m
|
||||||
, HasDeferred p e m
|
, HasDeferred p e m
|
||||||
, HasGossip e p m
|
, HasGossip e p m
|
||||||
, IsMailboxProtoAdapter s a
|
, IsMailboxProtoAdapter s a
|
||||||
, IsMailboxService s a
|
, IsMailboxService s a
|
||||||
|
, Sessions e (KnownPeer e) m
|
||||||
, p ~ MailBoxProto s e
|
, p ~ MailBoxProto s e
|
||||||
, s ~ Encryption e
|
, s ~ Encryption e
|
||||||
, ForMailbox s
|
, ForMailbox s
|
||||||
|
@ -174,23 +203,13 @@ mailboxProto :: forall e s m p a . ( MonadIO m
|
||||||
mailboxProto inner adapter mess = deferred @p do
|
mailboxProto inner adapter mess = deferred @p do
|
||||||
-- common stuff
|
-- common stuff
|
||||||
|
|
||||||
sto <- mailboxGetStorage @s adapter
|
sto <- mailboxGetStorage @s adapter
|
||||||
now <- liftIO $ getPOSIXTime <&> round
|
now <- liftIO $ getPOSIXTime <&> round
|
||||||
|
that <- thatPeer @p
|
||||||
|
se <- find (KnownPeerKey that) id
|
||||||
|
|
||||||
case mailBoxProtoPayload mess of
|
case mailBoxProtoPayload mess of
|
||||||
SendMessage msg -> deferred @p do
|
SendMessage msg -> deferred @p do
|
||||||
-- TODO: implement-SendMessage
|
|
||||||
-- [ ] check-if-mailbox-exists
|
|
||||||
-- [ ] check-message-signature
|
|
||||||
-- [ ] if-already-processed-then-skip
|
|
||||||
-- [ ] store-message-hash-block-with-ttl
|
|
||||||
-- [ ] if-message-to-this-mailbox-then store-message
|
|
||||||
-- [ ] gossip-message
|
|
||||||
|
|
||||||
-- проверяем, что еще не обрабатывали?
|
|
||||||
-- если обрабатывали -- то дропаем
|
|
||||||
-- что мы пишем в сторейдж?
|
|
||||||
-- кто потом это дропает?
|
|
||||||
|
|
||||||
flip runContT pure $ callCC \exit -> do
|
flip runContT pure $ callCC \exit -> do
|
||||||
|
|
||||||
|
@ -249,7 +268,7 @@ mailboxProto inner adapter mess = deferred @p do
|
||||||
-- и так и известен в протоколе)
|
-- и так и известен в протоколе)
|
||||||
--
|
--
|
||||||
|
|
||||||
CheckMailbox k -> deferred @p do
|
CheckMailbox _ k -> deferred @p do
|
||||||
creds <- mailboxGetCredentials @s adapter
|
creds <- mailboxGetCredentials @s adapter
|
||||||
|
|
||||||
void $ runMaybeT do
|
void $ runMaybeT do
|
||||||
|
@ -264,18 +283,47 @@ mailboxProto inner adapter mess = deferred @p do
|
||||||
|
|
||||||
lift $ response @_ @p (MailBoxProtoV1 (MailboxStatus box))
|
lift $ response @_ @p (MailBoxProtoV1 (MailboxStatus box))
|
||||||
|
|
||||||
MailboxStatus{} -> do
|
MailboxStatus box -> deferred @p do
|
||||||
-- TODO: implement-MailboxStatus
|
|
||||||
--
|
flip runContT pure $ callCC \exit -> do
|
||||||
-- [ ] if-do-gossip-setting-then
|
|
||||||
-- [ ] gossip-MailboxStatus
|
let r = unboxSignedBox0 @(MailBoxStatusPayload s) box
|
||||||
--
|
|
||||||
-- [ ] check-signed-box-or-drop
|
PeerData{..} <- ContT $ maybe1 se none
|
||||||
-- [ ] if-client-has-mailbox-then
|
|
||||||
-- [ ] get-mailbox-status
|
(who, content@MailBoxStatusPayload{..}) <- ContT $ maybe1 r none
|
||||||
-- [ ] answer-MailboxStatus
|
|
||||||
--
|
unless ( who == _peerSignKey ) $ exit ()
|
||||||
none
|
|
||||||
|
-- FIXME: timeout-hardcode
|
||||||
|
-- может быть вообще не очень хорошо
|
||||||
|
-- авторизовываться по времени.
|
||||||
|
-- возможно, надо слать нонс в CheckMailbox
|
||||||
|
-- и тут его проверять
|
||||||
|
unless ( abs (now - mbsMailboxPayloadNonce) < 3 ) $ exit ()
|
||||||
|
|
||||||
|
-- NOTE: possible-poisoning-attack
|
||||||
|
-- левый пир генерирует merkle tree сообщений и посылает его.
|
||||||
|
-- чего он может добиться: добавить "валидных" сообщений, которых не было
|
||||||
|
-- в ящике изначально. (зашифрованных, подписанных).
|
||||||
|
--
|
||||||
|
-- можно рассылать спам, ведь каждое спам-сообщение
|
||||||
|
-- будет валидно.
|
||||||
|
-- мы не можем подписывать что-либо подписью владельца ящика,
|
||||||
|
-- ведь мы не владеем его ключом.
|
||||||
|
--
|
||||||
|
-- как бороться: в policy ограничивать число пиров, которые
|
||||||
|
-- могут отдавать статус и игнорировать статусы от прочих пиров.
|
||||||
|
--
|
||||||
|
-- другой вариант -- каким-то образом публикуется подтверждение
|
||||||
|
-- от автора, что пир X владеет почтовым ящиком R.
|
||||||
|
--
|
||||||
|
-- собственно, это и есть policy.
|
||||||
|
--
|
||||||
|
-- а вот policy мы как раз можем публиковать с подписью автора,
|
||||||
|
-- он участвует в процессе обновления policy.
|
||||||
|
|
||||||
|
void $ mailboxAcceptStatus adapter (MailboxRefKey mbsMailboxKey) who content
|
||||||
|
|
||||||
SetPolicy{} -> do
|
SetPolicy{} -> do
|
||||||
none
|
none
|
||||||
|
|
|
@ -30,7 +30,9 @@ import Data.Maybe
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
|
|
||||||
data MailboxServiceError =
|
data MailboxServiceError =
|
||||||
MailboxCreateFailed String
|
MailboxCreateFailed String
|
||||||
|
| MailboxSetPolicyFailed String
|
||||||
|
| MailboxAuthError String
|
||||||
deriving stock (Typeable,Show,Generic)
|
deriving stock (Typeable,Show,Generic)
|
||||||
|
|
||||||
instance Serialise MailboxServiceError
|
instance Serialise MailboxServiceError
|
||||||
|
|
|
@ -16,6 +16,7 @@ import Codec.Serialise
|
||||||
|
|
||||||
data RpcMailboxPoke
|
data RpcMailboxPoke
|
||||||
data RpcMailboxCreate
|
data RpcMailboxCreate
|
||||||
|
data RpcMailboxSetPolicy
|
||||||
data RpcMailboxDelete
|
data RpcMailboxDelete
|
||||||
data RpcMailboxGetStatus
|
data RpcMailboxGetStatus
|
||||||
data RpcMailboxList
|
data RpcMailboxList
|
||||||
|
@ -24,6 +25,7 @@ data RpcMailboxGet
|
||||||
|
|
||||||
type MailboxAPI = '[ RpcMailboxPoke
|
type MailboxAPI = '[ RpcMailboxPoke
|
||||||
, RpcMailboxCreate
|
, RpcMailboxCreate
|
||||||
|
, RpcMailboxSetPolicy
|
||||||
, RpcMailboxDelete
|
, RpcMailboxDelete
|
||||||
, RpcMailboxGetStatus
|
, RpcMailboxGetStatus
|
||||||
, RpcMailboxList
|
, RpcMailboxList
|
||||||
|
@ -46,10 +48,12 @@ type instance Output RpcMailboxPoke = ()
|
||||||
type instance Input RpcMailboxCreate = (PubKey 'Sign HBS2Basic, MailboxType)
|
type instance Input RpcMailboxCreate = (PubKey 'Sign HBS2Basic, MailboxType)
|
||||||
type instance Output RpcMailboxCreate = ()
|
type instance Output RpcMailboxCreate = ()
|
||||||
|
|
||||||
|
type instance Input RpcMailboxSetPolicy = (PubKey 'Sign HBS2Basic, SignedBox (SetPolicyPayload HBS2Basic) HBS2Basic)
|
||||||
|
type instance Output RpcMailboxSetPolicy = Either MailboxServiceError HashRef
|
||||||
|
|
||||||
type instance Input RpcMailboxDelete = (PubKey 'Sign HBS2Basic)
|
type instance Input RpcMailboxDelete = (PubKey 'Sign HBS2Basic)
|
||||||
type instance Output RpcMailboxDelete = ()
|
type instance Output RpcMailboxDelete = ()
|
||||||
|
|
||||||
|
|
||||||
type instance Input RpcMailboxGetStatus = (PubKey 'Sign HBS2Basic)
|
type instance Input RpcMailboxGetStatus = (PubKey 'Sign HBS2Basic)
|
||||||
type instance Output RpcMailboxGetStatus = Either MailboxServiceError (Maybe (MailBoxStatusPayload 'HBS2Basic))
|
type instance Output RpcMailboxGetStatus = Either MailboxServiceError (Maybe (MailBoxStatusPayload 'HBS2Basic))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue