diff --git a/src/Simplex/FileTransfer/Server.hs b/src/Simplex/FileTransfer/Server.hs index 031879eee..16a705690 100644 --- a/src/Simplex/FileTransfer/Server.hs +++ b/src/Simplex/FileTransfer/Server.hs @@ -25,7 +25,6 @@ import Control.Monad.Reader import Control.Monad.Trans.Except import qualified Data.Aeson as J import Data.Bifunctor (first) -import qualified Data.ByteString.Base64.URL as B64 import Data.ByteString.Builder (Builder, byteString) import Data.ByteString.Char8 (ByteString) import qualified Data.ByteString.Char8 as B @@ -594,7 +593,7 @@ processXFTPRequest ent HTTP2Body {bodyPart} = \case \used -> let used' = used + fromIntegral size in if used' <= quota then (True, used') else (False, used) receive = do path <- asks $ filesPath . config - let fPath = path B.unpack (B64.encode $ unEntityId senderId) + let fPath = path serverFileName senderId receiveChunk (XFTPRcvChunkSpec fPath size digest) >>= \case Right () -> do stats <- asks serverStats diff --git a/src/Simplex/FileTransfer/Server/StoreLog.hs b/src/Simplex/FileTransfer/Server/StoreLog.hs index fe731ee2c..5a6d99c7a 100644 --- a/src/Simplex/FileTransfer/Server/StoreLog.hs +++ b/src/Simplex/FileTransfer/Server/StoreLog.hs @@ -17,6 +17,7 @@ module Simplex.FileTransfer.Server.StoreLog logDeleteFile, logBlockFile, logAckFile, + serverFileName, ) where @@ -24,6 +25,7 @@ import Control.Applicative (optional, (<|>)) import Control.Concurrent.STM import Control.Monad.Except import qualified Data.Attoparsec.ByteString.Char8 as A +import qualified Data.ByteString.Base64.URL as B64 import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as LB import Data.Composition ((.:), (.::.)) @@ -35,10 +37,11 @@ import Simplex.FileTransfer.Protocol (FileInfo (..)) import Simplex.FileTransfer.Server.Store import Simplex.FileTransfer.Transport (XFTPErrorType (..)) import Simplex.Messaging.Encoding.String -import Simplex.Messaging.Protocol (BlockingInfo, RcvPublicAuthKey, RecipientId, SenderId) +import Simplex.Messaging.Protocol (BlockingInfo, EntityId (..), RcvPublicAuthKey, RecipientId, SenderId) import Simplex.Messaging.Server.QueueStore (ServerEntityStatus (..)) import Simplex.Messaging.Server.StoreLog import Simplex.Messaging.Util (bshow) +import System.FilePath (takeFileName) import System.IO data FileStoreLogRecord @@ -99,6 +102,9 @@ logBlockFile s fId = logFileStoreRecord s . BlockFile fId logAckFile :: StoreLog 'WriteMode -> RecipientId -> IO () logAckFile s = logFileStoreRecord s . AckFile +serverFileName :: SenderId -> FilePath +serverFileName = B.unpack . B64.encode . unEntityId + readWriteFileStore :: FilePath -> STMFileStore -> IO (StoreLog 'WriteMode) readWriteFileStore = readWriteStoreLog readFileStore writeFileStore @@ -115,7 +121,9 @@ readFileStore f st = mapM_ (addFileLogRecord . LB.toStrict) . LB.lines =<< LB.re AddFile sId file createdAt expiresAt status | size file > 0 -> addFile st sId file createdAt expiresAt status | otherwise -> pure $ Left SIZE - PutFile qId path -> setFilePath st qId path + PutFile qId path + | takeFileName path == serverFileName qId -> setFilePath st qId path + | otherwise -> pure $ Left AUTH AddRecipients sId rcps -> runExceptT $ addRecipients sId rcps DeleteFile sId -> deleteFile st sId BlockFile sId info -> blockFile st sId info True diff --git a/tests/CoreTests/StoreLogTests.hs b/tests/CoreTests/StoreLogTests.hs index 13d831fe1..81a0535d5 100644 --- a/tests/CoreTests/StoreLogTests.hs +++ b/tests/CoreTests/StoreLogTests.hs @@ -22,7 +22,7 @@ import qualified Data.X509.Validation as XV import SMPClient import Simplex.FileTransfer.Protocol (FileInfo (..)) import Simplex.FileTransfer.Server.Store (FileRec (..), FileRecipient (..), FileStoreClass (..), RoundedFileTime, STMFileStore (..)) -import Simplex.FileTransfer.Server.StoreLog (FileStoreLogRecord (..), readWriteFileStore) +import Simplex.FileTransfer.Server.StoreLog (FileStoreLogRecord (..), readWriteFileStore, serverFileName) import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Encoding.String import Simplex.Messaging.Protocol @@ -37,6 +37,7 @@ import Simplex.Messaging.Server.StoreLog import Simplex.Messaging.SystemTime import Simplex.Messaging.Transport (SMPServiceRole (..)) import Simplex.Messaging.Transport.Credentials (genCredentials) +import System.FilePath (()) import Test.Hspec hiding (fit, it) import Util @@ -269,6 +270,18 @@ fileStoreLogTests = do saved = [AddFile sId file createdAt Nothing EntityActive, BlockFile sId blockedWithNotice], compacted = [AddFile sId file createdAt Nothing (EntityBlocked blockedWithNotice)], state = M.fromList [(sId, (file, createdAt, Nothing, EntityBlocked blockedWithNotice))] + }, + SLTC + { name = "put file with wrong file name", + saved = [AddFile sId file createdAt (Just expiresAt) EntityActive, PutFile sId "/etc/passwd"], + compacted = [AddFile sId file createdAt (Just expiresAt) EntityActive], + state = M.fromList [(sId, (file, createdAt, Just expiresAt, EntityActive))] + }, + SLTC + { name = "put file in another directory", + saved = [AddFile sId file createdAt (Just expiresAt) EntityActive, PutFile sId ("/srv/xftp" serverFileName sId)], + compacted = [AddFile sId file createdAt (Just expiresAt) EntityActive, PutFile sId ("/srv/xftp" serverFileName sId)], + state = M.fromList [(sId, (file, createdAt, Just expiresAt, EntityActive))] } ] diff --git a/tests/CoreTests/XFTPStoreTests.hs b/tests/CoreTests/XFTPStoreTests.hs index 9f980b4ea..52c7cedfa 100644 --- a/tests/CoreTests/XFTPStoreTests.hs +++ b/tests/CoreTests/XFTPStoreTests.hs @@ -9,7 +9,7 @@ import Data.Word (Word32) import Simplex.FileTransfer.Protocol (FileInfo (..), SFileParty (..)) import Simplex.FileTransfer.Server.Store import Simplex.FileTransfer.Server.Store.Postgres (PostgresFileStore, importFileStore, exportFileStore) -import Simplex.FileTransfer.Server.StoreLog (closeStoreLog, readWriteFileStore, writeFileStore) +import Simplex.FileTransfer.Server.StoreLog (closeStoreLog, readWriteFileStore, serverFileName, writeFileStore) import Simplex.FileTransfer.Transport (XFTPErrorType (..)) import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Protocol (BlockingInfo (..), BlockingReason (..), EntityId (..)) @@ -17,6 +17,7 @@ import Simplex.Messaging.Server.QueueStore (ServerEntityStatus (..)) import Simplex.Messaging.Server.StoreLog (openWriteStoreLog) import Simplex.Messaging.SystemTime (RoundedSystemTime (..)) import System.Directory (doesFileExist, removeFile) +import System.FilePath (()) import Test.Hspec hiding (fit, it) import UnliftIO.STM import Util @@ -265,7 +266,7 @@ testMigrationRoundTrip = do sId2 = EntityId "migration_file_2" rId1 = EntityId "migration_rcp_1_" addFile stmStore sId1 fileInfo1 testCreatedAt (Just testExpiresAt) EntityActive `shouldReturn` Right () - void $ setFilePath stmStore sId1 "/tmp/file1" + void $ setFilePath stmStore sId1 ("/tmp" serverFileName sId1) addRecipient stmStore sId1 (FileRecipient rId1 rcpKey1) `shouldReturn` Right () let testBlockInfo = BlockingInfo {reason = BRSpam, notice = Nothing} addFile stmStore sId2 fileInfo2 testCreatedAt Nothing (EntityBlocked testBlockInfo) `shouldReturn` Right () @@ -289,7 +290,7 @@ testMigrationRoundTrip = do case result1 of Right (FileRec {fileInfo = fi, filePath, expiresAt, fileStatus}, _) -> do size fi `shouldBe` 128000 - readTVarIO filePath `shouldReturn` Just "/tmp/file1" + readTVarIO filePath `shouldReturn` Just ("/tmp" serverFileName sId1) expiresAt `shouldBe` Just testExpiresAt readTVarIO fileStatus `shouldReturn` EntityActive Left e -> expectationFailure $ "getFile sId1 failed: " <> show e