From fe7e4f238cdcdc2773965fbb6dc2f21537f536fc Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Fri, 26 May 2023 16:55:45 -0400 Subject: [PATCH] write some more of the mutable download property test --- gbs-downloader.cabal | 1 + src/Tahoe/Download.hs | 5 +++++ test/Spec.hs | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/gbs-downloader.cabal b/gbs-downloader.cabal index e2ae392..c6a8896 100644 --- a/gbs-downloader.cabal +++ b/gbs-downloader.cabal @@ -107,6 +107,7 @@ library , servant-client-core , tahoe-chk , tahoe-great-black-swamp >=0.2 && <0.3 + , tahoe-ssk , text , yaml diff --git a/src/Tahoe/Download.hs b/src/Tahoe/Download.hs index e957769..a9f31a4 100644 --- a/src/Tahoe/Download.hs +++ b/src/Tahoe/Download.hs @@ -8,6 +8,7 @@ module Tahoe.Download ( DiscoverError (..), discoverShares, download, + downloadMutable, announcementToStorageServer, ) where @@ -37,6 +38,7 @@ import Tahoe.CHK.Capability (Reader (..), Verifier (..)) import qualified Tahoe.CHK.Encrypt import Tahoe.CHK.Server (StorageServer (..), StorageServerID) import Tahoe.CHK.Types (ShareNum, StorageIndex) +import qualified Tahoe.SDMF as SDMF import TahoeLAFS.Storage.API (CBORSet (..), ShareNumber (ShareNumber)) import TahoeLAFS.Storage.Client (getImmutableShareNumbers, readImmutableShare) import Text.Read (readMaybe) @@ -100,6 +102,9 @@ data DiscoverError -} type LookupServer m = StorageServerAnnouncement -> m (Either LookupError StorageServer) +downloadMutable :: MonadIO m => Map.Map StorageServerID StorageServerAnnouncement -> SDMF.Reader -> LookupServer m -> m (Either DownloadError LB.ByteString) +downloadMutable = undefined + {- | Recover the application data associated with a given capability from the given servers, if possible. -} diff --git a/test/Spec.hs b/test/Spec.hs index 73bb09a..727b068 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -3,6 +3,7 @@ module Main where import Control.Exception (Exception, throwIO) import Control.Monad (replicateM, zipWithM_) import Control.Monad.IO.Class (liftIO) +import Crypto.Cipher.Types (nullIV) import Crypto.Classes (buildKey) import qualified Data.Binary as Binary import qualified Data.ByteString as B @@ -40,9 +41,9 @@ import Tahoe.Download ( LookupError (..), LookupServer, download, + downloadMutable, ) import qualified Tahoe.SDMF as SDMF -import Tahoe.SDMF.Internal.Capability (deriveReader) import qualified Tahoe.SDMF.Keys as SDMF.Keys import Tahoe.Server (memoryStorageServer) import Test.Tasty (TestTree, defaultMain, testGroup) @@ -294,7 +295,7 @@ tests = -- Recover the plaintext from the servers. result <- liftIO $ download serverAnnouncements cap lookupServer diff (Right plaintext) (==) result - , testCase "ssk success" $ + , testProperty "ssk success" $ property $ do -- Like "chk success" above, but for SDMF (a case of SSK). plaintext <- forAll $ BL.fromStrict <$> Gen.bytes (Range.exponential 56 1024) @@ -302,18 +303,42 @@ tests = keypair <- SDMF.Keys.KeyPair <$> forAll genRSAKeys Parameters{paramRequiredShares = required, paramTotalShares = total} <- forAll genParameters - let ciphertext = SDMF.encrypt dataKey plaintext + -- Since multiple shares can be placed on a single server, as long + -- as we have one server we have a valid case. Since some shares + -- might be placed non-optimally it is also nice to allow for some + -- empty servers so allow for that as well. + let numServers = Range.linear 1 (fromIntegral total + 1) + serverIDs = Gen.text (Range.singleton 2) Gen.ascii + serverIDs' <- forAll $ Gen.set numServers serverIDs + + perServerShareCount <- + forAll $ + genListWithSum (length serverIDs') (fromIntegral total) + + -- Make the servers. + servers <- liftIO $ replicateM (length serverIDs') memoryStorageServer + + -- Derive the keys, encode the data. + let -- Not a very good IV choice in reality but it's okay for + -- this test where confidentiality and key secrecy is not + -- particularly a concern. + iv = SDMF.Keys.SDMF_IV nullIV + signatureKey = SDMF.Keys.toSignatureKey keypair + (Just writeKey) = SDMF.Keys.deriveWriteKey signatureKey + (Just readKey) = SDMF.Keys.deriveReadKey writeKey + (Just dataKey) = SDMF.Keys.deriveDataKey iv readKey + ciphertext = SDMF.encrypt dataKey plaintext (shares, writeCap) <- liftIO $ SDMF.encode keypair sequenceNumber required total ciphertext - let (Just readCap) = deriveReader + let readCap = SDMF.writerReader writeCap -- Distribute the shares. - liftIO $ placeShares cap (Binary.encode <$> shares) perServerShareCount servers 0 + liftIO $ placeMutable writeCap (Binary.encode <$> shares) perServerShareCount servers 0 let serverMap = Map.fromList $ zip (Set.toList serverIDs') servers lookupServer = someServers serverMap serverAnnouncements = Map.fromSet makeAnn serverIDs' -- Recover the plaintext from the servers. - result <- liftIO $ downloadMutable serverAnnouncements cap lookupServer + result <- liftIO $ downloadMutable serverAnnouncements readCap lookupServer diff (Right plaintext) (==) result , testCase "immutable upload/download to using Great Black Swamp" $ do pure () @@ -347,6 +372,9 @@ tests = -- Exactly match the nonsense makeAnn spits out parseURL = T.take 2 . T.drop 5 + placeMutable :: SDMF.Writer -> [BL.ByteString] -> [Int] -> [StorageServer] -> Int -> IO () + placeMutable = undefined + --- PHILOSOFY -- We wish that share numbers were an opaque type instead of a -- numeric/integral type. This is not the place to argue the point -- GitLab