mirror of https://github.com/voidlizard/hbs2
small-encrypted-block wip
This commit is contained in:
parent
8bc92062bd
commit
f0d469766e
|
@ -0,0 +1,43 @@
|
||||||
|
TODO: storage-weak-refs
|
||||||
|
Сделать ссылки, которые удаляются по достижению каких-то событий (например, истечение ttl).
|
||||||
|
Полезно, что бы не разрастался периметр к моменту, когда заработает сборка мусора.
|
||||||
|
Нужно, например, что бы кэшировать групповые ключи, так как сейчас сложно
|
||||||
|
сделать чистые (детерминированные) групповые ключи, да это и опасно.
|
||||||
|
|
||||||
|
Кейс: сохраняем ссылку на ключ, как SomeRef например.
|
||||||
|
|
||||||
|
По истечению заданного ttl ссылка должна быть удалена.
|
||||||
|
|
||||||
|
Как, например?
|
||||||
|
|
||||||
|
1. Это свойство hbs2-storage, не hbs2-peer
|
||||||
|
|
||||||
|
2. Поддержать тип --- обёртку?
|
||||||
|
Например, сейчас для любого типа ключа вычисляется хэш,
|
||||||
|
и ссылка пишется.
|
||||||
|
Можно добавить какую-то обёртку с метаданными, что писалась
|
||||||
|
не только ссылка, но и метаданные, например:
|
||||||
|
|
||||||
|
data WithExpiration t a = WithExpiration t a
|
||||||
|
|
||||||
|
instance Hashed (WithExpiration t a) where
|
||||||
|
hash (WithExpiration t a) = hash a
|
||||||
|
|
||||||
|
внутри сторейджа собирать метаданные в формате
|
||||||
|
[(String,String)] и писать в некий файл
|
||||||
|
|
||||||
|
A/X.metadata в виде:
|
||||||
|
|
||||||
|
key: value
|
||||||
|
key: value
|
||||||
|
key: value
|
||||||
|
|
||||||
|
3. Тогда при чтении (?) или время от временени:
|
||||||
|
|
||||||
|
читаем метаданные, смотрим, если ссылка протухла
|
||||||
|
--- то удаляем её.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ library
|
||||||
, HBS2.Data.Types.Refs
|
, HBS2.Data.Types.Refs
|
||||||
, HBS2.Data.Types.SignedBox
|
, HBS2.Data.Types.SignedBox
|
||||||
, HBS2.Data.Types.EncryptedBox
|
, HBS2.Data.Types.EncryptedBox
|
||||||
|
, HBS2.Data.Types.SmallEncryptedBlock
|
||||||
, HBS2.Data.Bundle
|
, HBS2.Data.Bundle
|
||||||
, HBS2.Defaults
|
, HBS2.Defaults
|
||||||
, HBS2.Events
|
, HBS2.Events
|
||||||
|
|
|
@ -2,6 +2,7 @@ module HBS2.Data.Types
|
||||||
( module X
|
( module X
|
||||||
-- , module HBS2.Data.Types.Crypto
|
-- , module HBS2.Data.Types.Crypto
|
||||||
, AsSyntax(..)
|
, AsSyntax(..)
|
||||||
|
, LoadedRef(..)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
|
@ -16,3 +17,4 @@ import HBS2.Data.Types.Peer as X
|
||||||
|
|
||||||
newtype AsSyntax c = AsSyntax c
|
newtype AsSyntax c = AsSyntax c
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,14 @@ import HBS2.Net.Proto.Types
|
||||||
import HBS2.Prelude
|
import HBS2.Prelude
|
||||||
|
|
||||||
import Codec.Serialise(serialise)
|
import Codec.Serialise(serialise)
|
||||||
|
import Data.Map (Map)
|
||||||
|
import Data.Map qualified as Map
|
||||||
import Data.Data
|
import Data.Data
|
||||||
|
|
||||||
|
class RefMetaData a where
|
||||||
|
refMetaData :: a -> [(String, String)]
|
||||||
|
refMetaData = const mempty
|
||||||
|
|
||||||
newtype HashRef = HashRef { fromHashRef :: Hash HbSync }
|
newtype HashRef = HashRef { fromHashRef :: Hash HbSync }
|
||||||
deriving newtype (Eq,Ord,IsString,Pretty,Hashable,Hashed HbSync)
|
deriving newtype (Eq,Ord,IsString,Pretty,Hashable,Hashed HbSync)
|
||||||
deriving stock (Data,Generic,Show)
|
deriving stock (Data,Generic,Show)
|
||||||
|
@ -72,6 +78,8 @@ type ForSomeRefKey a = ( Hashed HbSync a )
|
||||||
|
|
||||||
newtype SomeRefKey a = SomeRefKey a
|
newtype SomeRefKey a = SomeRefKey a
|
||||||
|
|
||||||
|
instance RefMetaData (SomeRefKey a)
|
||||||
|
|
||||||
instance Hashed HbSync (SomeRefKey a) => Pretty (SomeRefKey a) where
|
instance Hashed HbSync (SomeRefKey a) => Pretty (SomeRefKey a) where
|
||||||
pretty a = pretty $ hashObject @HbSync a
|
pretty a = pretty $ hashObject @HbSync a
|
||||||
-- instance Hashed HbSync (SomeRefKey a) => Pretty (AsBase58 (SomeRefKey a)) where
|
-- instance Hashed HbSync (SomeRefKey a) => Pretty (AsBase58 (SomeRefKey a)) where
|
||||||
|
@ -88,8 +96,25 @@ newtype RefAlias = RefAlias { unRefAlias :: HashRef }
|
||||||
instance Hashed HbSync RefAlias where
|
instance Hashed HbSync RefAlias where
|
||||||
hashObject (RefAlias h) = fromHashRef h
|
hashObject (RefAlias h) = fromHashRef h
|
||||||
|
|
||||||
|
refAlias :: (Hashed HbSync ref, RefMetaData ref) => ref -> RefAlias2
|
||||||
|
refAlias x = RefAlias2 (Map.fromList $ refMetaData x) (HashRef $ hashObject @HbSync x)
|
||||||
|
|
||||||
refAlias :: Hashed HbSync ref => ref -> RefAlias
|
data RefAlias2 =
|
||||||
refAlias x = RefAlias (HashRef $ hashObject @HbSync x)
|
RefAlias2 { unRefAliasMeta :: Map String String
|
||||||
|
, unRefAlias2 :: HashRef
|
||||||
|
}
|
||||||
|
deriving stock (Eq,Ord,Show,Generic)
|
||||||
|
|
||||||
|
instance Hashed HbSync RefAlias2 where
|
||||||
|
hashObject (RefAlias2 _ h) = fromHashRef h
|
||||||
|
|
||||||
|
instance Serialise RefAlias2
|
||||||
|
|
||||||
|
instance Pretty RefAlias2 where
|
||||||
|
pretty (RefAlias2 _ h) = pretty h
|
||||||
|
|
||||||
|
instance RefMetaData RefAlias2 where
|
||||||
|
refMetaData x = Map.toList (unRefAliasMeta x)
|
||||||
|
|
||||||
|
type LoadedRef a = Either HashRef a
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
module HBS2.Data.Types.SmallEncryptedBlock where
|
||||||
|
|
||||||
|
|
||||||
|
import HBS2.Prelude.Plated
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
|
import HBS2.Data.Types.EncryptedBox
|
||||||
|
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import Codec.Serialise
|
||||||
|
|
||||||
|
data SmallEncryptedBlock t =
|
||||||
|
SmallEncryptedBlock
|
||||||
|
{ sebGK0 :: HashRef -- ^ gk0
|
||||||
|
, sebNonce :: ByteString
|
||||||
|
, sebBox :: EncryptedBox t
|
||||||
|
}
|
||||||
|
deriving stock (Generic)
|
||||||
|
|
||||||
|
instance Serialise (SmallEncryptedBlock t)
|
||||||
|
|
|
@ -42,7 +42,7 @@ type family HashType ( a :: Type) where
|
||||||
type HbSyncHash = HashType HbSync
|
type HbSyncHash = HashType HbSync
|
||||||
|
|
||||||
newtype instance Hash HbSync =
|
newtype instance Hash HbSync =
|
||||||
HbSyncHash ByteString
|
HbSyncHash { fromHbSyncHash :: ByteString }
|
||||||
deriving stock (Eq,Ord,Data,Generic)
|
deriving stock (Eq,Ord,Data,Generic)
|
||||||
deriving newtype (Hashable,Show)
|
deriving newtype (Hashable,Show)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{-# Language UndecidableInstances #-}
|
{-# Language UndecidableInstances #-}
|
||||||
{-# Language AllowAmbiguousTypes #-}
|
{-# Language AllowAmbiguousTypes #-}
|
||||||
{-# Language ConstraintKinds #-}
|
{-# Language ConstraintKinds #-}
|
||||||
|
{-# Language PatternSynonyms #-}
|
||||||
module HBS2.Net.Auth.Credentials
|
module HBS2.Net.Auth.Credentials
|
||||||
( module HBS2.Net.Auth.Credentials
|
( module HBS2.Net.Auth.Credentials
|
||||||
) where
|
) where
|
||||||
|
@ -55,6 +56,9 @@ data KeyringEntry e =
|
||||||
}
|
}
|
||||||
deriving stock (Generic)
|
deriving stock (Generic)
|
||||||
|
|
||||||
|
pattern KeyringKeys :: forall {s} . PubKey 'Encrypt s -> PrivKey 'Encrypt s -> KeyringEntry s
|
||||||
|
pattern KeyringKeys a b <- KeyringEntry a b _
|
||||||
|
|
||||||
deriving stock instance (Eq (PubKey 'Encrypt e), Eq (PrivKey 'Encrypt e))
|
deriving stock instance (Eq (PubKey 'Encrypt e), Eq (PrivKey 'Encrypt e))
|
||||||
=> Eq (KeyringEntry e)
|
=> Eq (KeyringEntry e)
|
||||||
|
|
||||||
|
@ -72,6 +76,7 @@ makeLenses 'PeerCredentials
|
||||||
type ForHBS2Basic s = ( Signatures s
|
type ForHBS2Basic s = ( Signatures s
|
||||||
, PrivKey 'Sign s ~ Sign.SecretKey
|
, PrivKey 'Sign s ~ Sign.SecretKey
|
||||||
, PubKey 'Sign s ~ Sign.PublicKey
|
, PubKey 'Sign s ~ Sign.PublicKey
|
||||||
|
, Eq (PubKey 'Encrypt HBS2Basic)
|
||||||
, IsEncoding (PubKey 'Encrypt s)
|
, IsEncoding (PubKey 'Encrypt s)
|
||||||
, Eq (PubKey 'Encrypt HBS2Basic)
|
, Eq (PubKey 'Encrypt HBS2Basic)
|
||||||
, s ~ HBS2Basic
|
, s ~ HBS2Basic
|
||||||
|
|
|
@ -11,6 +11,7 @@ module HBS2.Net.Auth.GroupKeySymm
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
import HBS2.Base58
|
import HBS2.Base58
|
||||||
import HBS2.Data.Types.EncryptedBox
|
import HBS2.Data.Types.EncryptedBox
|
||||||
|
import HBS2.Data.Types.SmallEncryptedBlock
|
||||||
import HBS2.Data.Types.Refs
|
import HBS2.Data.Types.Refs
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
import HBS2.Merkle
|
import HBS2.Merkle
|
||||||
|
@ -57,7 +58,7 @@ import System.IO.Unsafe (unsafePerformIO)
|
||||||
|
|
||||||
import Data.Bits (xor)
|
import Data.Bits (xor)
|
||||||
|
|
||||||
type GroupSecretAsymm = Key
|
type GroupSecret = Key
|
||||||
|
|
||||||
|
|
||||||
-- NOTE: breaking-change
|
-- NOTE: breaking-change
|
||||||
|
@ -69,7 +70,7 @@ type GroupSecretAsymm = Key
|
||||||
-- ключ может быть потерян. а что делать-то, с другой стороны?
|
-- ключ может быть потерян. а что делать-то, с другой стороны?
|
||||||
data instance GroupKey 'Symm s =
|
data instance GroupKey 'Symm s =
|
||||||
GroupKeySymm
|
GroupKeySymm
|
||||||
{ recipients :: HashMap (PubKey 'Encrypt s) (EncryptedBox GroupSecretAsymm)
|
{ recipients :: HashMap (PubKey 'Encrypt s) (EncryptedBox GroupSecret)
|
||||||
}
|
}
|
||||||
deriving stock (Generic)
|
deriving stock (Generic)
|
||||||
|
|
||||||
|
@ -85,10 +86,10 @@ instance Serialise SK.Nonce
|
||||||
-- NOTE: hardcoded-hbs2-basic-auth-type
|
-- NOTE: hardcoded-hbs2-basic-auth-type
|
||||||
data instance ToEncrypt 'Symm s LBS.ByteString =
|
data instance ToEncrypt 'Symm s LBS.ByteString =
|
||||||
ToEncryptSymmBS
|
ToEncryptSymmBS
|
||||||
{ toEncryptSecret :: GroupSecretAsymm
|
{ toEncryptSecret :: GroupSecret
|
||||||
|
, toEncryptGroupKey :: LoadedRef (GroupKey 'Symm s)
|
||||||
, toEncryptNonce :: BS.ByteString
|
, toEncryptNonce :: BS.ByteString
|
||||||
, toEncryptData :: Stream (Of LBS.ByteString) IO ()
|
, toEncryptData :: Stream (Of LBS.ByteString) IO ()
|
||||||
, toEncryptGroupKey :: GroupKey 'Symm s
|
|
||||||
, toEncryptMeta :: AnnMetaData
|
, toEncryptMeta :: AnnMetaData
|
||||||
, toEncryptOpts :: Maybe EncryptGroupNaClSymmOpts
|
, toEncryptOpts :: Maybe EncryptGroupNaClSymmOpts
|
||||||
}
|
}
|
||||||
|
@ -98,7 +99,7 @@ type ForGroupKeySymm s = ( Eq (PubKey 'Encrypt s)
|
||||||
, PubKey 'Encrypt s ~ AK.PublicKey
|
, PubKey 'Encrypt s ~ AK.PublicKey
|
||||||
, PrivKey 'Encrypt s ~ AK.SecretKey
|
, PrivKey 'Encrypt s ~ AK.SecretKey
|
||||||
, Serialise (PubKey 'Encrypt s)
|
, Serialise (PubKey 'Encrypt s)
|
||||||
, Serialise GroupSecretAsymm
|
, Serialise GroupSecret
|
||||||
, Serialise SK.Nonce
|
, Serialise SK.Nonce
|
||||||
, FromStringMaybe (PubKey 'Encrypt s)
|
, FromStringMaybe (PubKey 'Encrypt s)
|
||||||
)
|
)
|
||||||
|
@ -139,8 +140,9 @@ instance ( Serialise (GroupKey 'Symm s)
|
||||||
pretty (AsBase58 c) =
|
pretty (AsBase58 c) =
|
||||||
pretty . B8.unpack . toBase58 . LBS.toStrict . serialise $ c
|
pretty . B8.unpack . toBase58 . LBS.toStrict . serialise $ c
|
||||||
|
|
||||||
|
|
||||||
generateGroupKey :: forall s m . (ForGroupKeySymm s, MonadIO m)
|
generateGroupKey :: forall s m . (ForGroupKeySymm s, MonadIO m)
|
||||||
=> Maybe GroupSecretAsymm
|
=> Maybe GroupSecret
|
||||||
-> [PubKey 'Encrypt s]
|
-> [PubKey 'Encrypt s]
|
||||||
-> m (GroupKey 'Symm s)
|
-> m (GroupKey 'Symm s)
|
||||||
|
|
||||||
|
@ -152,11 +154,30 @@ generateGroupKey mbk pks = GroupKeySymm <$> create
|
||||||
box <- liftIO $ AK.boxSeal pk (LBS.toStrict $ serialise sk) <&> EncryptedBox
|
box <- liftIO $ AK.boxSeal pk (LBS.toStrict $ serialise sk) <&> EncryptedBox
|
||||||
pure (pk, box)
|
pure (pk, box)
|
||||||
|
|
||||||
|
|
||||||
|
generateGroupKeyPure :: forall s nonce . (ForGroupKeySymm s, NonceFrom SK.Nonce nonce)
|
||||||
|
=> GroupSecret
|
||||||
|
-> nonce
|
||||||
|
-> [PubKey 'Encrypt s]
|
||||||
|
-> GroupKey 'Symm s
|
||||||
|
|
||||||
|
generateGroupKeyPure sec nonce pks = GroupKeySymm gk0
|
||||||
|
where
|
||||||
|
nonce0 = nonceFrom @SK.Nonce nonce
|
||||||
|
gk0 = undefined
|
||||||
|
-- gk0 = [ AK.box
|
||||||
|
-- HashMap.fromList <$> do
|
||||||
|
-- sk <- maybe1 mbk (liftIO SK.newKey) pure
|
||||||
|
-- forM pks $ \pk -> do
|
||||||
|
-- box <- liftIO $ AK.boxSeal pk (LBS.toStrict $ serialise sk) <&> EncryptedBox
|
||||||
|
-- pure (pk, box)
|
||||||
|
|
||||||
|
|
||||||
lookupGroupKey :: ForGroupKeySymm s
|
lookupGroupKey :: ForGroupKeySymm s
|
||||||
=> PrivKey 'Encrypt s
|
=> PrivKey 'Encrypt s
|
||||||
-> PubKey 'Encrypt s
|
-> PubKey 'Encrypt s
|
||||||
-> GroupKey 'Symm s
|
-> GroupKey 'Symm s
|
||||||
-> Maybe GroupSecretAsymm
|
-> Maybe GroupSecret
|
||||||
|
|
||||||
lookupGroupKey sk pk gk = runIdentity $ runMaybeT do
|
lookupGroupKey sk pk gk = runIdentity $ runMaybeT do
|
||||||
(EncryptedBox bs) <- MaybeT $ pure $ HashMap.lookup pk (recipients gk)
|
(EncryptedBox bs) <- MaybeT $ pure $ HashMap.lookup pk (recipients gk)
|
||||||
|
@ -216,7 +237,7 @@ instance ( MonadIO m
|
||||||
|
|
||||||
let nonce0 = nonceFrom @SK.Nonce (toEncryptNonce source)
|
let nonce0 = nonceFrom @SK.Nonce (toEncryptNonce source)
|
||||||
|
|
||||||
gkh <- writeAsMerkle sto (serialise gk) <&> HashRef
|
gkh <- either pure (\k -> HashRef <$> writeAsMerkle sto (serialise k)) gk
|
||||||
|
|
||||||
let prk = HKDF.extractSkip @_ @HbSyncHash (Saltine.encode key)
|
let prk = HKDF.extractSkip @_ @HbSyncHash (Saltine.encode key)
|
||||||
|
|
||||||
|
@ -351,3 +372,74 @@ instance ( MonadIO m
|
||||||
|
|
||||||
pure (keys, gk, nonceS, tree)
|
pure (keys, gk, nonceS, tree)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encryptBlock :: ( MonadIO m
|
||||||
|
, Storage sto h ByteString m
|
||||||
|
, ForGroupKeySymm s
|
||||||
|
, Serialise t
|
||||||
|
, h ~ HbSync
|
||||||
|
)
|
||||||
|
=> sto
|
||||||
|
-> GroupSecret
|
||||||
|
-> LoadedRef (GroupKey 'Symm s)
|
||||||
|
-> Maybe BS.ByteString -- ^ nonce
|
||||||
|
-> t
|
||||||
|
-> m (SmallEncryptedBlock t)
|
||||||
|
|
||||||
|
encryptBlock sto gks gk mnonce x = do
|
||||||
|
|
||||||
|
nonceS <- maybe (liftIO AK.newNonce <&> Saltine.encode) pure mnonce
|
||||||
|
|
||||||
|
let nonce0 = nonceFrom @SK.Nonce nonceS
|
||||||
|
|
||||||
|
gkh <- either pure (\k -> HashRef <$> writeAsMerkle sto (serialise k)) gk
|
||||||
|
|
||||||
|
let prk = HKDF.extractSkip @_ @HbSyncHash (Saltine.encode gks)
|
||||||
|
|
||||||
|
let key0 = HKDF.expand prk nonceS typicalKeyLength & Saltine.decode & fromJust
|
||||||
|
|
||||||
|
let encrypted = SK.secretbox key0 nonce0 (serialise x & LBS.toStrict)
|
||||||
|
|
||||||
|
pure $ SmallEncryptedBlock gkh nonceS (EncryptedBox encrypted)
|
||||||
|
|
||||||
|
decryptBlock :: forall t s sto h m . ( MonadIO m
|
||||||
|
, MonadError OperationError m
|
||||||
|
, Storage sto h ByteString m
|
||||||
|
, ForGroupKeySymm s
|
||||||
|
, h ~ HbSync
|
||||||
|
, Serialise t
|
||||||
|
)
|
||||||
|
|
||||||
|
=> sto
|
||||||
|
-> [KeyringEntry s]
|
||||||
|
-> SmallEncryptedBlock t
|
||||||
|
-> m t
|
||||||
|
|
||||||
|
decryptBlock sto keys (SmallEncryptedBlock{..}) = do
|
||||||
|
|
||||||
|
gkbs <- readFromMerkle sto (SimpleKey (fromHashRef sebGK0))
|
||||||
|
gk <- either (const $ throwError (GroupKeyNotFound 1)) pure (deserialiseOrFail @(GroupKey 'Symm s) gkbs)
|
||||||
|
|
||||||
|
let gksec' = [ lookupGroupKey sk pk gk | KeyringKeys pk sk <- keys ] & catMaybes & headMay
|
||||||
|
|
||||||
|
gksec <- maybe1 gksec' (throwError (GroupKeyNotFound 2)) pure
|
||||||
|
|
||||||
|
let prk = HKDF.extractSkip @_ @HbSyncHash (Saltine.encode gksec)
|
||||||
|
let key0 = HKDF.expand prk sebNonce typicalKeyLength & Saltine.decode & fromJust
|
||||||
|
let nonce0 = nonceFrom @SK.Nonce sebNonce
|
||||||
|
|
||||||
|
let unboxed = SK.secretboxOpen key0 nonce0 (unEncryptedBox sebBox)
|
||||||
|
|
||||||
|
lbs <- maybe1 unboxed (throwError DecryptionError) (pure . LBS.fromStrict)
|
||||||
|
|
||||||
|
either (const $ throwError UnsupportedFormat) pure (deserialiseOrFail lbs)
|
||||||
|
|
||||||
|
|
||||||
|
deriveGroupSecret :: NonceFrom SK.Nonce n => n -> BS.ByteString -> GroupSecret
|
||||||
|
deriveGroupSecret n bs = key0
|
||||||
|
where
|
||||||
|
nonceS = nonceFrom @SK.Nonce n & Saltine.encode & hashObject @HbSync & fromHbSyncHash
|
||||||
|
prk = HKDF.extractSkip @_ @HbSyncHash bs
|
||||||
|
key0 = HKDF.expand prk nonceS typicalKeyLength & Saltine.decode & fromJust
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import Data.Hashable hiding (Hashed)
|
||||||
|
|
||||||
newtype AnyRefKey t s = AnyRefKey (PubKey 'Sign s)
|
newtype AnyRefKey t s = AnyRefKey (PubKey 'Sign s)
|
||||||
|
|
||||||
|
instance RefMetaData (AnyRefKey t s)
|
||||||
|
|
||||||
deriving stock instance IsRefPubKey s => Eq (AnyRefKey n s)
|
deriving stock instance IsRefPubKey s => Eq (AnyRefKey n s)
|
||||||
|
|
||||||
instance (IsRefPubKey s) => Hashable (AnyRefKey t s) where
|
instance (IsRefPubKey s) => Hashable (AnyRefKey t s) where
|
||||||
|
|
|
@ -124,6 +124,8 @@ instance Expires (SessionKey L4Proto (RefChanHeadBlock L4Proto)) where
|
||||||
|
|
||||||
newtype RefChanHeadKey s = RefChanHeadKey (PubKey 'Sign s)
|
newtype RefChanHeadKey s = RefChanHeadKey (PubKey 'Sign s)
|
||||||
|
|
||||||
|
instance RefMetaData (RefChanHeadKey s)
|
||||||
|
|
||||||
deriving stock instance IsRefPubKey s => Eq (RefChanHeadKey s)
|
deriving stock instance IsRefPubKey s => Eq (RefChanHeadKey s)
|
||||||
|
|
||||||
instance IsRefPubKey s => Hashable (RefChanHeadKey s) where
|
instance IsRefPubKey s => Hashable (RefChanHeadKey s) where
|
||||||
|
@ -147,6 +149,8 @@ instance Pretty (AsBase58 (PubKey 'Sign s )) => Pretty (RefChanHeadKey s) where
|
||||||
|
|
||||||
newtype RefChanLogKey s = RefChanLogKey { fromRefChanLogKey :: PubKey 'Sign s }
|
newtype RefChanLogKey s = RefChanLogKey { fromRefChanLogKey :: PubKey 'Sign s }
|
||||||
|
|
||||||
|
instance RefMetaData (RefChanLogKey s)
|
||||||
|
|
||||||
deriving stock instance IsRefPubKey s => Eq (RefChanLogKey s)
|
deriving stock instance IsRefPubKey s => Eq (RefChanLogKey s)
|
||||||
|
|
||||||
instance IsRefPubKey s => Hashable (RefChanLogKey s) where
|
instance IsRefPubKey s => Hashable (RefChanLogKey s) where
|
||||||
|
|
|
@ -27,6 +27,8 @@ import Lens.Micro.Platform
|
||||||
newtype RefLogKey s = RefLogKey { fromRefLogKey :: PubKey 'Sign s }
|
newtype RefLogKey s = RefLogKey { fromRefLogKey :: PubKey 'Sign s }
|
||||||
deriving stock Generic
|
deriving stock Generic
|
||||||
|
|
||||||
|
instance RefMetaData (RefLogKey s)
|
||||||
|
|
||||||
instance Serialise (PubKey 'Sign s) => Serialise (RefLogKey s)
|
instance Serialise (PubKey 'Sign s) => Serialise (RefLogKey s)
|
||||||
|
|
||||||
deriving stock instance IsRefPubKey s => Eq (RefLogKey s)
|
deriving stock instance IsRefPubKey s => Eq (RefLogKey s)
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
module HBS2.OrDie where
|
module HBS2.OrDie
|
||||||
|
( module HBS2.OrDie
|
||||||
|
) where
|
||||||
|
|
||||||
import Data.Kind
|
import Data.Kind
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import System.Exit
|
import System.Exit
|
||||||
|
import Prettyprinter
|
||||||
|
import UnliftIO
|
||||||
|
|
||||||
class OrDie m a where
|
class OrDie m a where
|
||||||
type family OrDieResult a :: Type
|
type family OrDieResult a :: Type
|
||||||
|
@ -28,3 +32,31 @@ instance MonadIO m => OrDie m ExitCode where
|
||||||
orDie mv err = mv >>= \case
|
orDie mv err = mv >>= \case
|
||||||
ExitSuccess -> pure ()
|
ExitSuccess -> pure ()
|
||||||
ExitFailure{} -> liftIO $ die err
|
ExitFailure{} -> liftIO $ die err
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: move-to-library
|
||||||
|
class OrThrow a where
|
||||||
|
type family OrThrowResult a :: Type
|
||||||
|
orThrow :: forall e m . (MonadIO m, Exception e) => e -> a -> m (OrThrowResult a)
|
||||||
|
|
||||||
|
instance OrThrow (Maybe a) where
|
||||||
|
type instance OrThrowResult (Maybe a) = a
|
||||||
|
orThrow e a = case a of
|
||||||
|
Nothing -> throwIO e
|
||||||
|
Just x -> pure x
|
||||||
|
|
||||||
|
|
||||||
|
instance OrThrow (Either b a) where
|
||||||
|
type instance OrThrowResult (Either b a) = a
|
||||||
|
orThrow e a = case a of
|
||||||
|
Left{} -> throwIO e
|
||||||
|
Right x -> pure x
|
||||||
|
|
||||||
|
orThrowUser :: (OrThrow a1, MonadIO m)
|
||||||
|
=> Doc ann
|
||||||
|
-> a1
|
||||||
|
-> m (OrThrowResult a1)
|
||||||
|
|
||||||
|
orThrowUser p = orThrow (userError (show p))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
{-# Language FunctionalDependencies #-}
|
{-# Language FunctionalDependencies #-}
|
||||||
|
{-# Language DefaultSignatures #-}
|
||||||
module HBS2.Storage where
|
module HBS2.Storage where
|
||||||
|
|
||||||
import HBS2.Hash
|
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
|
import HBS2.Hash
|
||||||
|
import HBS2.Data.Types.Refs (RefMetaData(..))
|
||||||
|
|
||||||
import Data.Kind
|
import Data.Kind
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
import Data.ByteString.Lazy (ByteString)
|
import Data.ByteString.Lazy (ByteString)
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Data.Word
|
||||||
|
|
||||||
import Codec.Serialise()
|
import Codec.Serialise()
|
||||||
|
|
||||||
|
@ -29,6 +32,12 @@ newtype Size = Size Integer
|
||||||
deriving newtype (Eq,Ord,Enum,Num,Real,Integral,Hashable,Pretty,Serialise)
|
deriving newtype (Eq,Ord,Enum,Num,Real,Integral,Hashable,Pretty,Serialise)
|
||||||
deriving stock (Show)
|
deriving stock (Show)
|
||||||
|
|
||||||
|
data ExpiredAfter a = ExpiredAfter Word64 a
|
||||||
|
deriving stock (Generic)
|
||||||
|
|
||||||
|
instance Serialise a => Serialise (ExpiredAfter a)
|
||||||
|
|
||||||
|
|
||||||
class ( Monad m
|
class ( Monad m
|
||||||
, IsKey h
|
, IsKey h
|
||||||
, Hashed h block
|
, Hashed h block
|
||||||
|
@ -46,11 +55,11 @@ class ( Monad m
|
||||||
|
|
||||||
hasBlock :: a -> Key h -> m (Maybe Integer)
|
hasBlock :: a -> Key h -> m (Maybe Integer)
|
||||||
|
|
||||||
updateRef :: Hashed h k => a -> k -> Key h -> m ()
|
updateRef :: (Hashed h k, RefMetaData k) => a -> k -> Key h -> m ()
|
||||||
|
|
||||||
getRef :: (Hashed h k, Pretty k) => a -> k -> m (Maybe (Key h))
|
getRef :: (Hashed h k, Pretty k, RefMetaData k) => a -> k -> m (Maybe (Key h))
|
||||||
|
|
||||||
delRef :: Hashed h k => a -> k -> m ()
|
delRef :: (Hashed h k, RefMetaData k) => a -> k -> m ()
|
||||||
|
|
||||||
|
|
||||||
data AnyStorage = forall zu . ( Storage zu HbSync ByteString IO
|
data AnyStorage = forall zu . ( Storage zu HbSync ByteString IO
|
||||||
|
@ -59,10 +68,14 @@ data AnyStorage = forall zu . ( Storage zu HbSync ByteString IO
|
||||||
class HasStorage m where
|
class HasStorage m where
|
||||||
getStorage :: m AnyStorage
|
getStorage :: m AnyStorage
|
||||||
|
|
||||||
|
|
||||||
instance (Monad m, HasStorage m) => HasStorage (MaybeT m) where
|
instance (Monad m, HasStorage m) => HasStorage (MaybeT m) where
|
||||||
getStorage = lift getStorage
|
getStorage = lift getStorage
|
||||||
|
|
||||||
|
instance Hashed h a => Hashed h (ExpiredAfter a) where
|
||||||
|
hashObject (ExpiredAfter _ a) = hashObject a
|
||||||
|
|
||||||
|
instance RefMetaData a => RefMetaData (ExpiredAfter a) where
|
||||||
|
refMetaData (ExpiredAfter t x) = [("expires", show t)] <> refMetaData x
|
||||||
|
|
||||||
instance (IsKey HbSync, MonadIO m) => Storage AnyStorage HbSync ByteString m where
|
instance (IsKey HbSync, MonadIO m) => Storage AnyStorage HbSync ByteString m where
|
||||||
putBlock (AnyStorage s) = liftIO . putBlock s
|
putBlock (AnyStorage s) = liftIO . putBlock s
|
||||||
|
|
|
@ -22,7 +22,6 @@ class (MonadIO m, Storage storage hash (ToBlockW s) m) => MerkleWriter s hash st
|
||||||
type family ToBlockW s :: Type
|
type family ToBlockW s :: Type
|
||||||
writeAsMerkle :: storage -> s -> m (Hash hash)
|
writeAsMerkle :: storage -> s -> m (Hash hash)
|
||||||
|
|
||||||
|
|
||||||
class (MonadIO m, Storage storage h (ToBlockR s) m) => MerkleReader s storage h m where
|
class (MonadIO m, Storage storage h (ToBlockR s) m) => MerkleReader s storage h m where
|
||||||
data family TreeKey s :: Type
|
data family TreeKey s :: Type
|
||||||
type family ToBlockR s :: Type
|
type family ToBlockR s :: Type
|
||||||
|
|
|
@ -453,7 +453,13 @@ storeObjectRPC True repo meta bs = do
|
||||||
& LBS.toStrict
|
& LBS.toStrict
|
||||||
|
|
||||||
let bsStream = readChunkedBS bs defBlockSize
|
let bsStream = readChunkedBS bs defBlockSize
|
||||||
let source = ToEncryptSymmBS gks nonce bsStream gk0 (ShortMetadata txt) Nothing
|
|
||||||
|
let source = ToEncryptSymmBS gks
|
||||||
|
(Left gkh0 :: LoadedRef (GroupKey 'Symm HBS2Basic))
|
||||||
|
nonce
|
||||||
|
bsStream
|
||||||
|
(ShortMetadata txt)
|
||||||
|
Nothing
|
||||||
|
|
||||||
h <- runExceptT (writeAsMerkle sto source) >>= either (const cantWriteMerkle) pure
|
h <- runExceptT (writeAsMerkle sto source) >>= either (const cantWriteMerkle) pure
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,10 @@ import UnliftIO (MonadUnliftIO(..),async,race)
|
||||||
data PeerBrainsDb
|
data PeerBrainsDb
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: refactor-brains
|
||||||
|
-- переключить на db-pipe
|
||||||
|
-- асинки - в runContT
|
||||||
|
|
||||||
-- FIXME: move-that-orphans-somewhere
|
-- FIXME: move-that-orphans-somewhere
|
||||||
|
|
||||||
instance ToField HashRef where
|
instance ToField HashRef where
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{-# Language TemplateHaskell #-}
|
{-# Language TemplateHaskell #-}
|
||||||
module CLI.Common where
|
module CLI.Common where
|
||||||
|
|
||||||
|
import HBS2.Clock
|
||||||
import HBS2.Net.Messaging.Unix
|
import HBS2.Net.Messaging.Unix
|
||||||
import HBS2.Net.Proto
|
import HBS2.Net.Proto
|
||||||
import HBS2.Net.Proto.Service
|
import HBS2.Net.Proto.Service
|
||||||
|
@ -33,4 +34,15 @@ withMyRPC o m = do
|
||||||
let soname = getRpcSocketName conf
|
let soname = getRpcSocketName conf
|
||||||
withRPC2 @api @UNIX soname m
|
withRPC2 @api @UNIX soname m
|
||||||
|
|
||||||
|
withRPCMessaging :: MonadIO m => RPCOpt -> (MessagingUnix -> m ()) -> m ()
|
||||||
|
withRPCMessaging o action = do
|
||||||
|
conf <- peerConfigRead (view rpcOptConf o)
|
||||||
|
let soname = getRpcSocketName conf
|
||||||
|
client1 <- newMessagingUnix False 1.0 soname
|
||||||
|
m1 <- liftIO $ async $ runMessagingUnix client1
|
||||||
|
link m1
|
||||||
|
action client1
|
||||||
|
pause @'Seconds 0.05
|
||||||
|
cancel m1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,15 +2,26 @@ module CLI.RefChan where
|
||||||
|
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
|
|
||||||
|
import HBS2.Hash
|
||||||
|
import HBS2.Clock
|
||||||
import HBS2.Net.Auth.Credentials
|
import HBS2.Net.Auth.Credentials
|
||||||
|
import HBS2.Net.Auth.Credentials.Sigil
|
||||||
import HBS2.Net.Proto.Definition()
|
import HBS2.Net.Proto.Definition()
|
||||||
import HBS2.Net.Proto.RefChan
|
import HBS2.Net.Proto.RefChan
|
||||||
import HBS2.Net.Proto.Types
|
import HBS2.Net.Proto.Types
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
|
import HBS2.Merkle
|
||||||
|
import HBS2.Actors.Peer.Types
|
||||||
import HBS2.Data.Types.SignedBox
|
import HBS2.Data.Types.SignedBox
|
||||||
import HBS2.Net.Proto.Service
|
import HBS2.Net.Proto.Service
|
||||||
import HBS2.Data.Detect
|
import HBS2.Data.Detect
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
|
import HBS2.Storage.Operations.ByteString
|
||||||
import HBS2.Data.Types.Refs
|
import HBS2.Data.Types.Refs
|
||||||
|
import HBS2.Net.Messaging.Unix
|
||||||
|
import HBS2.Net.Auth.GroupKeySymm
|
||||||
|
|
||||||
|
import HBS2.KeyMan.Keys.Direct
|
||||||
|
|
||||||
import HBS2.OrDie
|
import HBS2.OrDie
|
||||||
|
|
||||||
|
@ -22,13 +33,27 @@ import HBS2.Peer.RefChanNotifyLog
|
||||||
import CLI.Common
|
import CLI.Common
|
||||||
import RPC2()
|
import RPC2()
|
||||||
|
|
||||||
import Options.Applicative
|
import HBS2.System.Logger.Simple hiding (info)
|
||||||
import Data.ByteString qualified as BS
|
import HBS2.System.Logger.Simple qualified as Log
|
||||||
import Data.ByteString.Lazy qualified as LBS
|
|
||||||
import Lens.Micro.Platform
|
import Control.Monad.Cont
|
||||||
import Data.Maybe
|
import Control.Monad.Reader
|
||||||
import System.Exit
|
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
|
import Data.ByteString qualified as BS
|
||||||
|
import Data.HashSet qualified as HashSet
|
||||||
|
import Data.Maybe
|
||||||
|
import Lens.Micro.Platform
|
||||||
|
import Options.Applicative
|
||||||
|
import System.Exit
|
||||||
|
import Data.Time.Clock (getCurrentTime)
|
||||||
|
import Data.Time.Clock.POSIX (getPOSIXTime)
|
||||||
|
import Control.Monad.Except (runExceptT)
|
||||||
|
import Data.Word
|
||||||
|
import Codec.Serialise
|
||||||
|
import UnliftIO
|
||||||
|
import Streaming.Prelude qualified as S
|
||||||
|
|
||||||
|
|
||||||
pRefChan :: Parser (IO ())
|
pRefChan :: Parser (IO ())
|
||||||
pRefChan = hsubparser ( command "head" (info pRefChanHead (progDesc "head commands" ))
|
pRefChan = hsubparser ( command "head" (info pRefChanHead (progDesc "head commands" ))
|
||||||
|
@ -36,6 +61,7 @@ pRefChan = hsubparser ( command "head" (info pRefChanHead (progDesc "head comm
|
||||||
<> command "notify" (info pRefChanNotify (progDesc "post notify message"))
|
<> command "notify" (info pRefChanNotify (progDesc "post notify message"))
|
||||||
<> command "fetch" (info pRefChanFetch (progDesc "fetch and sync refchan value"))
|
<> command "fetch" (info pRefChanFetch (progDesc "fetch and sync refchan value"))
|
||||||
<> command "get" (info pRefChanGet (progDesc "get refchan value"))
|
<> command "get" (info pRefChanGet (progDesc "get refchan value"))
|
||||||
|
<> command "gk" (info pRefChanGK (progDesc "generate a group key"))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,19 +164,150 @@ pRefChanNotify =
|
||||||
<> command "tail" (info pRefChanNotifyLogTail (progDesc "output last messages"))
|
<> command "tail" (info pRefChanNotifyLogTail (progDesc "output last messages"))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data EncMethod = EncryptWithSigil FilePath
|
||||||
|
| NoEncryption
|
||||||
|
|
||||||
pRefChanNotifyPost :: Parser (IO ())
|
pRefChanNotifyPost :: Parser (IO ())
|
||||||
pRefChanNotifyPost = do
|
pRefChanNotifyPost = do
|
||||||
opts <- pRpcCommon
|
opts <- pRpcCommon
|
||||||
kra <- strOption (long "author" <> short 'a' <> help "author credentials")
|
|
||||||
fn <- optional $ strOption (long "file" <> short 'f' <> help "file")
|
|
||||||
puk <- argument pRefChanId (metavar "REFCHAH-REF")
|
|
||||||
pure $ withMyRPC @RefChanAPI opts $ \caller -> do
|
|
||||||
sc <- BS.readFile kra
|
|
||||||
creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile sc)) `orDie` "bad keyring file"
|
|
||||||
lbs <- maybe1 fn LBS.getContents LBS.readFile
|
|
||||||
let box = makeSignedBox @L4Proto @BS.ByteString (view peerSignPk creds) (view peerSignSk creds) (LBS.toStrict lbs)
|
|
||||||
void $ callService @RpcRefChanNotify caller (puk, box)
|
|
||||||
|
|
||||||
|
si <- strOption (long "sigil" <> short 's' <> help "sigil file")
|
||||||
|
fn <- optional $ strOption (long "file" <> short 'f' <> help "file")
|
||||||
|
|
||||||
|
encrypt <- encryptOpt
|
||||||
|
-- EncMethod <$> optional (switch (long "encrypt" <> help "encrypt transaction"))
|
||||||
|
-- <*> optional (strOption (long "sigil" <> help "using sigil"))
|
||||||
|
|
||||||
|
puk <- argument pRefChanId (metavar "REFCHAH-REF")
|
||||||
|
|
||||||
|
pure $ flip runContT pure do
|
||||||
|
|
||||||
|
client <- ContT $ withRPCMessaging opts
|
||||||
|
|
||||||
|
self <- runReaderT (ownPeer @UNIX) client
|
||||||
|
refChanAPI <- makeServiceCaller @RefChanAPI self
|
||||||
|
storageAPI <- makeServiceCaller @StorageAPI self
|
||||||
|
|
||||||
|
let endpoints = [ Endpoint @UNIX refChanAPI
|
||||||
|
, Endpoint @UNIX storageAPI
|
||||||
|
]
|
||||||
|
|
||||||
|
void $ ContT $ bracket (async $ runReaderT (runServiceClientMulti endpoints) client) cancel
|
||||||
|
|
||||||
|
-- caller <- ContT $ withMyRPC @RefChanAPI opts
|
||||||
|
|
||||||
|
sigil <- liftIO $ (BS.readFile si <&> parseSerialisableFromBase58 @(Sigil L4Proto))
|
||||||
|
`orDie` "parse sigil failed"
|
||||||
|
|
||||||
|
(auPk, sd) <- pure (unboxSignedBox0 @(SigilData L4Proto) (sigilData sigil))
|
||||||
|
>>= orThrowUser "malformed sigil/bad signature"
|
||||||
|
|
||||||
|
keys <- liftIO $ runKeymanClient do
|
||||||
|
creds <- loadCredentials auPk >>= orThrowUser "can't load credentials"
|
||||||
|
encKey <- loadKeyRingEntry (sigilDataEncKey sd)
|
||||||
|
pure (creds,encKey)
|
||||||
|
|
||||||
|
let creds = view _1 keys
|
||||||
|
|
||||||
|
lbs <- liftIO $ maybe1 fn LBS.getContents LBS.readFile
|
||||||
|
|
||||||
|
let sto = AnyStorage (StorageClient storageAPI)
|
||||||
|
|
||||||
|
ss <- if not encrypt then do
|
||||||
|
pure lbs
|
||||||
|
else do
|
||||||
|
-- итак нам тут нужно знать:
|
||||||
|
-- 2. старый gk или новый
|
||||||
|
-- 2.1 если старый - то где взять
|
||||||
|
-- 2.2 стоит обновить gk или нет
|
||||||
|
-- 2.3 стоит сохранять gk или нет
|
||||||
|
--
|
||||||
|
-- допустим так: ключ равно: голова + эпоха + enc SigilData
|
||||||
|
--
|
||||||
|
-- тогда: 1) где его хранить? в кеймане или в стейте?
|
||||||
|
--
|
||||||
|
-- + в кеймане, допустим?
|
||||||
|
-- в кеймане может быть блокировка sqlite, нехорошо
|
||||||
|
|
||||||
|
-- можно сохранять в hbs2:
|
||||||
|
-- 1. групповой ключ и так там сохраняется
|
||||||
|
-- 2. ссылок не должно быть много, если
|
||||||
|
-- ссылка ~ hash(канал, ключ пользователя)
|
||||||
|
-- 3. обновление ключа: если явно сказано!
|
||||||
|
-- иначе -- берём существующий
|
||||||
|
-- 4. если голова поменялась -- можем
|
||||||
|
-- удалить ссылку?
|
||||||
|
|
||||||
|
kre@(KeyringKeys pk sk) <- orThrowUser "encryption key not found for given sigil" (view _2 keys)
|
||||||
|
let kreHash = hashObject @HbSync (serialise kre)
|
||||||
|
|
||||||
|
hh <- callService @RpcRefChanHeadGet refChanAPI puk
|
||||||
|
>>= orThrowUser "RPC error"
|
||||||
|
>>= orThrowUser "refchan head not available"
|
||||||
|
|
||||||
|
hd <- getRefChanHead @L4Proto sto (RefChanHeadKey puk)
|
||||||
|
>>= orThrowUser "head block not found"
|
||||||
|
|
||||||
|
let rcpts = view refChanHeadReaders hd
|
||||||
|
|
||||||
|
when ( HashSet.null rcpts ) do
|
||||||
|
throwIO (userError "empty recipients list -- encryption is not possible")
|
||||||
|
|
||||||
|
notice $ "refchan head" <+> pretty hh
|
||||||
|
|
||||||
|
-- FIXME: key-rotation-factor-hardcode
|
||||||
|
-- около раза в месяц. может, нормально и так
|
||||||
|
t <- liftIO $ getPOSIXTime <&> round
|
||||||
|
|
||||||
|
let gkkey0 = SomeRefKey (hh,kreHash)
|
||||||
|
|
||||||
|
notice $ "gkkey0" <+> pretty (hashObject @HbSync gkkey0)
|
||||||
|
|
||||||
|
mgk <- runMaybeT do
|
||||||
|
gkv <- toMPlus =<< getRef sto gkkey0
|
||||||
|
|
||||||
|
notice $ "FOUND REF VAL" <+> pretty gkv
|
||||||
|
|
||||||
|
gks <- runExceptT (readFromMerkle sto (SimpleKey gkv))
|
||||||
|
>>= toMPlus
|
||||||
|
|
||||||
|
gk <- deserialiseOrFail @(GroupKey 'Symm HBS2Basic) gks
|
||||||
|
& toMPlus
|
||||||
|
|
||||||
|
notice $ "found GK0" <+> pretty gkv
|
||||||
|
|
||||||
|
pure gk
|
||||||
|
|
||||||
|
gk <- case mgk of
|
||||||
|
Just x -> pure x
|
||||||
|
Nothing -> do
|
||||||
|
gknew <- generateGroupKey @HBS2Basic Nothing (HashSet.toList rcpts)
|
||||||
|
|
||||||
|
gkh <- writeAsMerkle sto (serialise gknew)
|
||||||
|
|
||||||
|
-- FIXME: key-expiration-hardcode
|
||||||
|
let gkkey1 = ExpiredAfter (t+1209600) gkkey0
|
||||||
|
|
||||||
|
notice $ "UPDATE REF" <+> pretty (hashObject @HbSync gkkey1) <+> pretty gkh
|
||||||
|
updateRef sto gkkey1 gkh
|
||||||
|
|
||||||
|
notice $ "generated! GK0" <+> pretty gkh
|
||||||
|
|
||||||
|
pure gknew
|
||||||
|
|
||||||
|
gks <- orThrowUser "can't decrypt group key" $ lookupGroupKey sk pk gk
|
||||||
|
-- FIXME: use-deterministic-nonce
|
||||||
|
lift $ encryptBlock sto gks (Right gk) Nothing lbs <&> serialise
|
||||||
|
|
||||||
|
let box = makeSignedBox @L4Proto @BS.ByteString (view peerSignPk creds) (view peerSignSk creds) (LBS.toStrict ss)
|
||||||
|
void $ callService @RpcRefChanNotify refChanAPI (puk, box)
|
||||||
|
|
||||||
|
where
|
||||||
|
encryptOpt = do
|
||||||
|
optional (switch (long "encrypt" <> help "post encrypted")) <&> fromMaybe False
|
||||||
|
|
||||||
|
-- noEncryption = pure NoEncryption
|
||||||
|
-- encryptWithSigil = EncryptWithSigil <$> strOption (long "sigil" <> help "sigil file")
|
||||||
|
|
||||||
pRefChanId :: ReadM (RefChanId L4Proto)
|
pRefChanId :: ReadM (RefChanId L4Proto)
|
||||||
pRefChanId = maybeReader (fromStringMay @(RefChanId L4Proto))
|
pRefChanId = maybeReader (fromStringMay @(RefChanId L4Proto))
|
||||||
|
@ -204,3 +361,32 @@ pRefChanFetch = do
|
||||||
void $ callService @RpcRefChanFetch caller href
|
void $ callService @RpcRefChanFetch caller href
|
||||||
|
|
||||||
|
|
||||||
|
pRefChanGK :: Parser (IO ())
|
||||||
|
pRefChanGK = do
|
||||||
|
opts <- pRpcCommon
|
||||||
|
puk <- argument pRefChanId (metavar "REFCHAH-REF")
|
||||||
|
pure $ flip runContT pure do
|
||||||
|
|
||||||
|
client <- ContT $ withRPCMessaging opts
|
||||||
|
|
||||||
|
self <- runReaderT (ownPeer @UNIX) client
|
||||||
|
refChanAPI <- makeServiceCaller @RefChanAPI self
|
||||||
|
storageAPI <- makeServiceCaller @StorageAPI self
|
||||||
|
|
||||||
|
let endpoints = [ Endpoint @UNIX refChanAPI
|
||||||
|
, Endpoint @UNIX storageAPI
|
||||||
|
]
|
||||||
|
|
||||||
|
void $ ContT $ bracket (async $ runReaderT (runServiceClientMulti endpoints) client) cancel
|
||||||
|
|
||||||
|
let sto = AnyStorage (StorageClient storageAPI)
|
||||||
|
|
||||||
|
hd <- getRefChanHead @L4Proto sto (RefChanHeadKey puk)
|
||||||
|
>>= orThrowUser "head block not found"
|
||||||
|
|
||||||
|
let readers = view refChanHeadReaders' hd
|
||||||
|
|
||||||
|
gk <- generateGroupKey @HBS2Basic Nothing (HashSet.toList readers)
|
||||||
|
|
||||||
|
liftIO $ print $ pretty (AsGroupKeyFile gk)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ common warnings
|
||||||
|
|
||||||
common common-deps
|
common common-deps
|
||||||
build-depends:
|
build-depends:
|
||||||
base, hbs2-core, hbs2-storage-simple
|
base, hbs2-core, hbs2-storage-simple, hbs2-keyman
|
||||||
, aeson
|
, aeson
|
||||||
, async
|
, async
|
||||||
, bytestring
|
, bytestring
|
||||||
|
@ -198,7 +198,7 @@ executable hbs2-peer
|
||||||
, CLI.RefChan
|
, CLI.RefChan
|
||||||
|
|
||||||
-- other-extensions:
|
-- other-extensions:
|
||||||
build-depends: base, hbs2-peer
|
build-depends: base, hbs2-peer, hbs2-keyman
|
||||||
|
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
{-# OPTIONS_GHC -fno-warn-orphans #-}
|
||||||
module HBS2.Peer.RPC.API.Storage where
|
module HBS2.Peer.RPC.API.Storage where
|
||||||
|
|
||||||
|
import HBS2.Prelude
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
import HBS2.Actors.Peer
|
import HBS2.Actors.Peer
|
||||||
import HBS2.Net.Proto.Service
|
import HBS2.Net.Proto.Service
|
||||||
import HBS2.Net.Messaging.Unix
|
import HBS2.Net.Messaging.Unix
|
||||||
|
@ -8,6 +10,7 @@ import HBS2.Peer.RPC.Internal.Types
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
import HBS2.Data.Types.Refs (HashRef(..),RefAlias(..))
|
import HBS2.Data.Types.Refs (HashRef(..),RefAlias(..))
|
||||||
|
|
||||||
|
import Control.Applicative
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.ByteString.Lazy (ByteString)
|
import Data.ByteString.Lazy (ByteString)
|
||||||
import Codec.Serialise
|
import Codec.Serialise
|
||||||
|
@ -36,10 +39,9 @@ type StorageAPI = '[ RpcStorageHasBlock
|
||||||
instance HasProtocol UNIX (ServiceProto StorageAPI UNIX) where
|
instance HasProtocol UNIX (ServiceProto StorageAPI UNIX) where
|
||||||
type instance ProtocolId (ServiceProto StorageAPI UNIX) = 0xDA2374610001
|
type instance ProtocolId (ServiceProto StorageAPI UNIX) = 0xDA2374610001
|
||||||
type instance Encoded UNIX = ByteString
|
type instance Encoded UNIX = ByteString
|
||||||
decode = either (const Nothing) Just . deserialiseOrFail
|
decode lbs = eitherToMaybe $ deserialiseOrFail lbs
|
||||||
encode = serialise
|
encode = serialise
|
||||||
|
|
||||||
|
|
||||||
instance (Monad m)
|
instance (Monad m)
|
||||||
=> HasRpcContext StorageAPI RPC2Context (ResponseM UNIX (ReaderT RPC2Context m)) where
|
=> HasRpcContext StorageAPI RPC2Context (ResponseM UNIX (ReaderT RPC2Context m)) where
|
||||||
getRpcContext = lift ask
|
getRpcContext = lift ask
|
||||||
|
@ -65,12 +67,12 @@ type instance Output RpcStorageDelBlock = ()
|
||||||
type instance Input RpcStorageGetChunk = (HashRef, Offset, Size)
|
type instance Input RpcStorageGetChunk = (HashRef, Offset, Size)
|
||||||
type instance Output RpcStorageGetChunk = Maybe ByteString
|
type instance Output RpcStorageGetChunk = Maybe ByteString
|
||||||
|
|
||||||
type instance Input RpcStorageGetRef = RefAlias
|
type instance Input RpcStorageGetRef = RefAlias2
|
||||||
type instance Output RpcStorageGetRef = Maybe HashRef
|
type instance Output RpcStorageGetRef = Maybe HashRef
|
||||||
|
|
||||||
type instance Input RpcStorageUpdateRef = (RefAlias, HashRef)
|
type instance Input RpcStorageUpdateRef = (RefAlias2, HashRef)
|
||||||
type instance Output RpcStorageUpdateRef = ()
|
type instance Output RpcStorageUpdateRef = ()
|
||||||
|
|
||||||
type instance Input RpcStorageDelRef = RefAlias
|
type instance Input RpcStorageDelRef = RefAlias2
|
||||||
type instance Output RpcStorageDelRef = ()
|
type instance Output RpcStorageDelRef = ()
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ module HBS2.Peer.RPC.Client.StorageClient
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
|
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
import HBS2.Data.Types.Refs (HashRef(..),refAlias)
|
import HBS2.Data.Types.Refs (HashRef(..),refAlias,refMetaData)
|
||||||
import HBS2.Net.Proto.Service
|
import HBS2.Net.Proto.Service
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ instance ( MonadIO m
|
||||||
void $ callService @RpcStorageDelBlock (fromStorageClient s) (HashRef h)
|
void $ callService @RpcStorageDelBlock (fromStorageClient s) (HashRef h)
|
||||||
|
|
||||||
updateRef s ref v = liftIO do
|
updateRef s ref v = liftIO do
|
||||||
|
notice $ "metadata!" <+> pretty (refMetaData ref)
|
||||||
void $ callService @RpcStorageUpdateRef (fromStorageClient s) (refAlias ref, HashRef v)
|
void $ callService @RpcStorageUpdateRef (fromStorageClient s) (refAlias ref, HashRef v)
|
||||||
|
|
||||||
getRef s ref = liftIO do
|
getRef s ref = liftIO do
|
||||||
|
|
|
@ -9,7 +9,7 @@ module HBS2.Peer.RPC.Internal.Storage
|
||||||
|
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
import HBS2.Actors.Peer.Types
|
import HBS2.Actors.Peer.Types
|
||||||
import HBS2.Data.Types.Refs (HashRef(..))
|
import HBS2.Data.Types.Refs (HashRef(..),refMetaData)
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
import HBS2.Peer.RPC.Class
|
import HBS2.Peer.RPC.Class
|
||||||
import HBS2.Peer.RPC.API.Storage
|
import HBS2.Peer.RPC.API.Storage
|
||||||
|
@ -73,7 +73,7 @@ instance (StorageContext m) => HandleMethod m RpcStorageGetRef where
|
||||||
instance (StorageContext m) => HandleMethod m RpcStorageUpdateRef where
|
instance (StorageContext m) => HandleMethod m RpcStorageUpdateRef where
|
||||||
|
|
||||||
handleMethod (ref, val) = do
|
handleMethod (ref, val) = do
|
||||||
debug $ "rpc.storage.updateRef" <+> pretty ref
|
debug $ "rpc.storage.updateRef" <+> pretty ref <+> pretty (refMetaData ref)
|
||||||
sto <- getStorage
|
sto <- getStorage
|
||||||
liftIO $ updateRef sto ref (fromHashRef val)
|
liftIO $ updateRef sto ref (fromHashRef val)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
{-# Language TemplateHaskell #-}
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import HBS2.Prelude
|
import HBS2.Prelude
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
import HBS2.Storage.Simple
|
import HBS2.Storage.Simple
|
||||||
|
|
||||||
|
@ -17,13 +19,22 @@ import Control.Monad (replicateM)
|
||||||
import Data.ByteString.Lazy qualified as LBS
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
import Data.Word (Word8)
|
import Data.Word (Word8)
|
||||||
|
|
||||||
|
import Data.Function
|
||||||
import Text.InterpolatedString.Perl6 (qc)
|
import Text.InterpolatedString.Perl6 (qc)
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import UnliftIO
|
import UnliftIO
|
||||||
|
import Data.HashMap.Strict (HashMap)
|
||||||
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
|
import Data.Map (Map)
|
||||||
|
import Data.Map qualified as Map
|
||||||
|
|
||||||
import Streaming.Prelude (Of,Stream)
|
import Streaming.Prelude (Of,Stream)
|
||||||
import Streaming.Prelude qualified as S
|
import Streaming.Prelude qualified as S
|
||||||
|
|
||||||
|
import Control.Concurrent.STM (retry,flushTQueue)
|
||||||
|
|
||||||
|
import Codec.Serialise
|
||||||
|
|
||||||
-- Генерация одного случайного байта
|
-- Генерация одного случайного байта
|
||||||
randomByte :: IO Word8
|
randomByte :: IO Word8
|
||||||
randomByte = randomRIO (0, 255)
|
randomByte = randomRIO (0, 255)
|
||||||
|
@ -41,6 +52,9 @@ randomByteStrings n len = replicateM_ n $ do
|
||||||
bs <- liftIO $ randomByteString len
|
bs <- liftIO $ randomByteString len
|
||||||
S.yield bs
|
S.yield bs
|
||||||
|
|
||||||
|
-- chunkStream :: Monad m => Int -> Stream (Of LBS.ByteString) m r -> Stream (Of [LBS.ByteString]) m r
|
||||||
|
-- chunkStream n = S.mapsM (sequence . take n) . S.chunksOf n
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
(ns:ss:pref:_) <- getArgs
|
(ns:ss:pref:_) <- getArgs
|
||||||
|
@ -49,8 +63,13 @@ main = do
|
||||||
let s = readDef @Int 256 ss
|
let s = readDef @Int 256 ss
|
||||||
let p = pref
|
let p = pref
|
||||||
|
|
||||||
let bss = randomByteStrings n s
|
-- let bss = randomByteStrings n s
|
||||||
let bss2 = randomByteStrings n s
|
let bss2 = randomByteStrings n s
|
||||||
|
let bss3 = randomByteStrings n s
|
||||||
|
-- let bss41 = randomByteStrings (n `div` 2) s
|
||||||
|
-- let bss42 = randomByteStrings (n`div` 2) s
|
||||||
|
-- let bss43 = randomByteStrings (n`div`4) s
|
||||||
|
-- let bss44 = randomByteStrings (n`div`4) s
|
||||||
|
|
||||||
let path = pref </> ".test-storage"
|
let path = pref </> ".test-storage"
|
||||||
|
|
||||||
|
@ -72,8 +91,8 @@ main = do
|
||||||
|
|
||||||
print $ "preparing to write" <+> pretty n <+> "chunks"
|
print $ "preparing to write" <+> pretty n <+> "chunks"
|
||||||
|
|
||||||
timeItNamed "write chunks test" do
|
-- timeItNamed "write chunks test" do
|
||||||
S.mapM_ (enqueueBlock storage) bss
|
-- S.mapM_ (enqueueBlock storage) bss
|
||||||
|
|
||||||
timeItNamed "write chunks to sqlite test" do
|
timeItNamed "write chunks to sqlite test" do
|
||||||
withDB env $ transactional do
|
withDB env $ transactional do
|
||||||
|
@ -81,3 +100,89 @@ main = do
|
||||||
let h = hashObject @HbSync bs & pretty & show
|
let h = hashObject @HbSync bs & pretty & show
|
||||||
insert [qc|insert into wtf (hash,val) values(?,?)|] (h,bs)
|
insert [qc|insert into wtf (hash,val) values(?,?)|] (h,bs)
|
||||||
|
|
||||||
|
timeItNamed "write chunks to log" do
|
||||||
|
fh <- openFile (path </> "lsm") AppendMode
|
||||||
|
flip S.mapM_ bss3 $ \bs -> do
|
||||||
|
let h = hashObject @HbSync bs & pretty & show
|
||||||
|
LBS.hPut fh (serialise (h,bs))
|
||||||
|
hClose fh
|
||||||
|
|
||||||
|
timeItNamed "write chunks to log 2" do
|
||||||
|
buf <- newIORef (mempty, 0 :: Int)
|
||||||
|
fh <- openFile (path </> "lsm2") AppendMode
|
||||||
|
|
||||||
|
flip S.mapM_ bss3 $ \bs -> do
|
||||||
|
let h = hashObject @HbSync bs & pretty & show
|
||||||
|
num <- atomicModifyIORef buf (\(chunks,sz) -> ((serialise (h,bs) : chunks,sz+1),sz+1))
|
||||||
|
|
||||||
|
when (num >= 16) do
|
||||||
|
w <- atomicModifyIORef buf (\(chunks,_) -> ((mempty,0),chunks))
|
||||||
|
LBS.hPut fh (mconcat w)
|
||||||
|
|
||||||
|
(w,_) <- readIORef buf
|
||||||
|
LBS.hPut fh (mconcat w)
|
||||||
|
hClose fh
|
||||||
|
|
||||||
|
|
||||||
|
timeItNamed "write chunks to LSM-mock" do
|
||||||
|
|
||||||
|
if n*s > 1073741824 then do
|
||||||
|
print "too much"
|
||||||
|
else do
|
||||||
|
|
||||||
|
let k = 6
|
||||||
|
let batch = 100
|
||||||
|
|
||||||
|
rem <- newTVarIO n
|
||||||
|
quit <- newTVarIO False
|
||||||
|
out <- newTQueueIO
|
||||||
|
queue <- newTQueueIO
|
||||||
|
|
||||||
|
w1 <- async do
|
||||||
|
fix \next -> do
|
||||||
|
r <- readTVarIO rem
|
||||||
|
when (r > 0) do
|
||||||
|
b <- S.toList_ (randomByteStrings (min r batch) s)
|
||||||
|
atomically $ do
|
||||||
|
writeTQueue queue b
|
||||||
|
modifyTVar rem (+ (-batch))
|
||||||
|
next
|
||||||
|
atomically $ writeTVar quit True
|
||||||
|
|
||||||
|
as <- forM [1..k] \j -> async do
|
||||||
|
mem <- newIORef mempty
|
||||||
|
-- mem <- newTVarIO mempty
|
||||||
|
fix \next -> do
|
||||||
|
|
||||||
|
b <- atomically $ do
|
||||||
|
q <- readTVar quit
|
||||||
|
if q
|
||||||
|
then return Nothing
|
||||||
|
else (Just <$> readTQueue queue)
|
||||||
|
`orElse` (
|
||||||
|
readTVar quit >>= \z -> if z then pure Nothing else retry
|
||||||
|
)
|
||||||
|
case b of
|
||||||
|
Nothing -> pure ()
|
||||||
|
Just bss -> do
|
||||||
|
|
||||||
|
new <- for bss $ \bs -> do
|
||||||
|
let h = hashObject @HbSync bs & HashRef
|
||||||
|
pure $ (h, bs)
|
||||||
|
|
||||||
|
modifyIORef' mem (HashMap.union (HashMap.fromList new))
|
||||||
|
-- atomically $ modifyTVar mem (Map.union (Map.fromList new))
|
||||||
|
next
|
||||||
|
|
||||||
|
co <- readIORef mem
|
||||||
|
-- co <- readTVarIO mem
|
||||||
|
atomically $ writeTQueue out co
|
||||||
|
|
||||||
|
mapM_ wait (w1:as)
|
||||||
|
|
||||||
|
result <- atomically $ flushTQueue out
|
||||||
|
h <- openFile (path </> "lsm3") WriteMode
|
||||||
|
LBS.hPut h (serialise result)
|
||||||
|
hClose h
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,8 @@ library
|
||||||
, stm
|
, stm
|
||||||
, stm-chans
|
, stm-chans
|
||||||
, streaming
|
, streaming
|
||||||
|
, serialise
|
||||||
|
, time
|
||||||
, transformers
|
, transformers
|
||||||
, uniplate
|
, uniplate
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
|
@ -136,7 +138,7 @@ executable hbs2-storage-simple-benchmarks
|
||||||
-- -fno-warn-unused-binds
|
-- -fno-warn-unused-binds
|
||||||
-threaded
|
-threaded
|
||||||
-rtsopts
|
-rtsopts
|
||||||
"-with-rtsopts=-N4 -A64m -AL256m -I0"
|
"-with-rtsopts=-N8 -A64m -AL256m -I0"
|
||||||
|
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
-- other-modules:
|
-- other-modules:
|
||||||
|
@ -172,6 +174,7 @@ executable hbs2-storage-simple-benchmarks
|
||||||
, stm
|
, stm
|
||||||
, unliftio
|
, unliftio
|
||||||
, network-byte-order
|
, network-byte-order
|
||||||
|
, unordered-containers
|
||||||
|
|
||||||
hs-source-dirs: benchmarks
|
hs-source-dirs: benchmarks
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
|
@ -10,6 +10,7 @@ module HBS2.Storage.Simple
|
||||||
import HBS2.Clock
|
import HBS2.Clock
|
||||||
import HBS2.Hash
|
import HBS2.Hash
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
|
import HBS2.Data.Types.Refs (refMetaData)
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
import HBS2.Base58
|
import HBS2.Base58
|
||||||
|
|
||||||
|
@ -27,6 +28,9 @@ import Data.ByteString (ByteString)
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.List qualified as L
|
import Data.List qualified as L
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Data.Map (Map)
|
||||||
|
import Data.Map qualified as Map
|
||||||
|
import Data.Either
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
import Prettyprinter
|
import Prettyprinter
|
||||||
import System.Directory
|
import System.Directory
|
||||||
|
@ -36,6 +40,7 @@ import System.IO.Error
|
||||||
import System.IO.Temp
|
import System.IO.Temp
|
||||||
import System.AtomicWrite.Writer.LazyByteString qualified as AwLBS
|
import System.AtomicWrite.Writer.LazyByteString qualified as AwLBS
|
||||||
import System.AtomicWrite.Writer.ByteString qualified as AwBS
|
import System.AtomicWrite.Writer.ByteString qualified as AwBS
|
||||||
|
import Data.Time.Clock.POSIX (getPOSIXTime)
|
||||||
|
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
import Data.HashMap.Strict (HashMap)
|
import Data.HashMap.Strict (HashMap)
|
||||||
|
@ -48,6 +53,7 @@ import Control.Concurrent.STM.TBMQueue qualified as TBMQ
|
||||||
import Control.Concurrent.STM.TBMQueue (TBMQueue)
|
import Control.Concurrent.STM.TBMQueue (TBMQueue)
|
||||||
import Control.Concurrent.STM.TVar qualified as TV
|
import Control.Concurrent.STM.TVar qualified as TV
|
||||||
|
|
||||||
|
import Codec.Serialise
|
||||||
|
|
||||||
|
|
||||||
-- NOTE: random accessing files in a git-like storage
|
-- NOTE: random accessing files in a git-like storage
|
||||||
|
@ -350,17 +356,30 @@ simpleWriteLinkRawRef :: forall h . ( IsSimpleStorageKey h
|
||||||
, ToByteString (AsBase58 (Hash h))
|
, ToByteString (AsBase58 (Hash h))
|
||||||
)
|
)
|
||||||
=> SimpleStorage h
|
=> SimpleStorage h
|
||||||
|
-> [(String, String)]
|
||||||
-> Hash h
|
-> Hash h
|
||||||
-> Hash h
|
-> Hash h
|
||||||
-> IO ()
|
-> IO ()
|
||||||
|
|
||||||
simpleWriteLinkRawRef ss h ref = do
|
simpleWriteLinkRawRef ss meta h ref = do
|
||||||
let fnr = simpleRefFileName ss h
|
let fnr = simpleRefFileName ss h
|
||||||
void $ spawnAndWait ss $ do
|
void $ spawnAndWait ss $ do
|
||||||
AwBS.atomicWriteFile fnr (toByteString (AsBase58 ref))
|
AwBS.atomicWriteFile fnr (toByteString (AsBase58 ref))
|
||||||
`catchAny` \_ -> do
|
`catchAny` \_ -> do
|
||||||
err $ "simpleWriteLinkRawRef" <+> pretty h <+> pretty ref <+> pretty fnr
|
err $ "simpleWriteLinkRawRef" <+> pretty h <+> pretty ref <+> pretty fnr
|
||||||
|
|
||||||
|
unless (null meta) do
|
||||||
|
let metaname = fnr `addExtension` "metadata"
|
||||||
|
meta0 <- try @IOError (LBS.readFile metaname)
|
||||||
|
<&> fromRight mempty
|
||||||
|
<&> deserialiseOrFail @(Map String String)
|
||||||
|
<&> fromRight mempty
|
||||||
|
let meta1 = meta0 <> Map.fromList meta
|
||||||
|
r <- try @IOError $ AwBS.atomicWriteFile metaname (LBS.toStrict $ serialise meta1)
|
||||||
|
case r of
|
||||||
|
Right{} -> pure ()
|
||||||
|
Left e -> err $ "simpleWriteLinkRawRef" <+> viaShow e
|
||||||
|
|
||||||
simpleReadLinkRaw :: forall r h . ( IsKey h, Hashed h r, Pretty r)
|
simpleReadLinkRaw :: forall r h . ( IsKey h, Hashed h r, Pretty r)
|
||||||
=> SimpleStorage h
|
=> SimpleStorage h
|
||||||
-> r
|
-> r
|
||||||
|
@ -370,14 +389,43 @@ simpleReadLinkRaw ss ref = do
|
||||||
let hash = hashObject @h ref
|
let hash = hashObject @h ref
|
||||||
let fn = simpleRefFileName ss hash
|
let fn = simpleRefFileName ss hash
|
||||||
rs <- spawnAndWait ss $ do
|
rs <- spawnAndWait ss $ do
|
||||||
|
meta <- try @IOError (LBS.readFile (fn `addExtension` "metadata"))
|
||||||
|
>>= \case
|
||||||
|
Left{} -> pure mempty
|
||||||
|
Right sm -> pure $ deserialiseOrFail @(Map String String) sm & fromRight mempty
|
||||||
|
|
||||||
|
deleted <- runMaybeT do
|
||||||
|
ts <- toMPlus $ Map.lookup "expires" meta
|
||||||
|
t0 <- toMPlus $ readMay @Int ts
|
||||||
|
now <- liftIO $ getPOSIXTime <&> round
|
||||||
|
|
||||||
|
if now <= t0 then do
|
||||||
|
pure False
|
||||||
|
else do
|
||||||
|
liftIO $ simpleDelRef ss hash
|
||||||
|
pure True
|
||||||
|
|
||||||
|
if deleted == Just True then do
|
||||||
|
pure Nothing
|
||||||
|
else do
|
||||||
-- FIXME: log-this-situation
|
-- FIXME: log-this-situation
|
||||||
(Just <$> LBS.readFile fn) `catchAny` \e -> do
|
(Just <$> LBS.readFile fn) `catchAny` \e -> do
|
||||||
|
-- TODO: update-stats-instead-of-spamming
|
||||||
err $ "simpleReadLinkRaw" <+> pretty ref <+> pretty fn <+> viaShow e
|
err $ "simpleReadLinkRaw" <+> pretty ref <+> pretty fn <+> viaShow e
|
||||||
pure Nothing
|
pure Nothing
|
||||||
|
|
||||||
pure $ fromMaybe Nothing rs
|
pure $ fromMaybe Nothing rs
|
||||||
|
|
||||||
|
|
||||||
|
simpleDelRef :: IsKey h => SimpleStorage h -> Hash h -> IO ()
|
||||||
|
simpleDelRef ss hash = do
|
||||||
|
let fn = simpleRefFileName ss hash
|
||||||
|
here <- doesFileExist fn
|
||||||
|
when here (removeFile fn)
|
||||||
|
let meta = fn `addExtension` "metadata"
|
||||||
|
mhere <- doesFileExist meta
|
||||||
|
when mhere (removeFile meta)
|
||||||
|
|
||||||
simpleReadLinkVal :: ( IsKey h
|
simpleReadLinkVal :: ( IsKey h
|
||||||
, IsSimpleStorageKey h
|
, IsSimpleStorageKey h
|
||||||
, Hashed h LBS.ByteString
|
, Hashed h LBS.ByteString
|
||||||
|
@ -416,8 +464,9 @@ instance ( MonadIO m, IsKey hash
|
||||||
|
|
||||||
updateRef ss ref v = do
|
updateRef ss ref v = do
|
||||||
let refHash = hashObject @hash ref
|
let refHash = hashObject @hash ref
|
||||||
|
let meta = refMetaData ref
|
||||||
debug $ "updateRef:" <+> pretty refHash
|
debug $ "updateRef:" <+> pretty refHash
|
||||||
void $ liftIO $ simpleWriteLinkRawRef ss refHash v
|
void $ liftIO $ simpleWriteLinkRawRef ss meta refHash v
|
||||||
|
|
||||||
getRef ss ref = do
|
getRef ss ref = do
|
||||||
runMaybeT do
|
runMaybeT do
|
||||||
|
@ -435,8 +484,7 @@ instance ( MonadIO m, IsKey hash
|
||||||
|
|
||||||
delRef ss ref = do
|
delRef ss ref = do
|
||||||
let refHash = hashObject @hash ref
|
let refHash = hashObject @hash ref
|
||||||
let fn = simpleRefFileName ss refHash
|
|
||||||
void $ liftIO $ spawnAndWait ss $ do
|
void $ liftIO $ spawnAndWait ss $ do
|
||||||
here <- doesFileExist fn
|
simpleDelRef ss refHash
|
||||||
when here (removeFile fn)
|
|
||||||
|
|
||||||
|
|
16
hbs2/Main.hs
16
hbs2/Main.hs
|
@ -5,6 +5,7 @@ import HBS2.Data.Detect
|
||||||
import HBS2.Data.Types
|
import HBS2.Data.Types
|
||||||
import HBS2.Data.Types.EncryptedBox
|
import HBS2.Data.Types.EncryptedBox
|
||||||
import HBS2.Data.Types.SignedBox
|
import HBS2.Data.Types.SignedBox
|
||||||
|
import HBS2.Data.KeyRing as KeyRing
|
||||||
import HBS2.Defaults
|
import HBS2.Defaults
|
||||||
import HBS2.Merkle
|
import HBS2.Merkle
|
||||||
import HBS2.Net.Proto.Types
|
import HBS2.Net.Proto.Types
|
||||||
|
@ -380,7 +381,7 @@ runStore opts ss = runResourceT do
|
||||||
|
|
||||||
let segments = readChunked fh (fromIntegral defBlockSize)
|
let segments = readChunked fh (fromIntegral defBlockSize)
|
||||||
|
|
||||||
let source = ToEncryptSymmBS gks nonce segments gk NoMetaData Nothing
|
let source = ToEncryptSymmBS gks (Right gk) nonce segments NoMetaData Nothing
|
||||||
|
|
||||||
r <- runExceptT $ writeAsMerkle ss source
|
r <- runExceptT $ writeAsMerkle ss source
|
||||||
|
|
||||||
|
@ -536,6 +537,7 @@ main = join . customExecParser (prefs showHelpOnError) $
|
||||||
<> command "fsck" (info pFsck (progDesc "check storage constistency"))
|
<> command "fsck" (info pFsck (progDesc "check storage constistency"))
|
||||||
<> command "deps" (info pDeps (progDesc "print dependencies"))
|
<> command "deps" (info pDeps (progDesc "print dependencies"))
|
||||||
<> command "del" (info pDel (progDesc "del block"))
|
<> command "del" (info pDel (progDesc "del block"))
|
||||||
|
<> command "keyring" (info pKeyRing (progDesc "keyring commands"))
|
||||||
<> command "keyring-new" (info pNewKey (progDesc "generates a new keyring"))
|
<> command "keyring-new" (info pNewKey (progDesc "generates a new keyring"))
|
||||||
<> command "keyring-list" (info pKeyList (progDesc "list public keys from keyring"))
|
<> command "keyring-list" (info pKeyList (progDesc "list public keys from keyring"))
|
||||||
<> command "keyring-key-add" (info pKeyAdd (progDesc "adds a new keypair into the keyring"))
|
<> command "keyring-key-add" (info pKeyAdd (progDesc "adds a new keypair into the keyring"))
|
||||||
|
@ -674,6 +676,16 @@ main = join . customExecParser (prefs showHelpOnError) $
|
||||||
f <- strArgument ( metavar "KEYRING-FILE" )
|
f <- strArgument ( metavar "KEYRING-FILE" )
|
||||||
pure (runKeyDel s f)
|
pure (runKeyDel s f)
|
||||||
|
|
||||||
|
pKeyRing = hsubparser ( command "find" (info pKeyRingFind (progDesc "find keyring"))
|
||||||
|
)
|
||||||
|
|
||||||
|
pKeyRingFind = do
|
||||||
|
spk <- option pPubKey ( long "sign-key" <> short 's' <> help "sign-key" )
|
||||||
|
masks <- many (strArgument (metavar "PATHS"))
|
||||||
|
pure do
|
||||||
|
krf <- KeyRing.findKeyRing masks spk
|
||||||
|
print $ vcat (fmap pretty krf)
|
||||||
|
|
||||||
pReflog = hsubparser ( command "get" (info pRefLogGet (progDesc "get reflog root") ) )
|
pReflog = hsubparser ( command "get" (info pRefLogGet (progDesc "get reflog root") ) )
|
||||||
|
|
||||||
-- FIXME: only-for-hbs2-basic-encryption
|
-- FIXME: only-for-hbs2-basic-encryption
|
||||||
|
@ -872,6 +884,8 @@ main = join . customExecParser (prefs showHelpOnError) $
|
||||||
phref = maybeReader fromStringMay
|
phref = maybeReader fromStringMay
|
||||||
|
|
||||||
|
|
||||||
|
pPubKey = maybeReader (fromStringMay @(PubKey 'Sign HBS2Basic))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue