Skip to content

Commit

Permalink
[#500] Trails: Add check to make sure that the timestamps accepted by…
Browse files Browse the repository at this point in the history
… the service are in the past.
  • Loading branch information
a-stacey committed Aug 26, 2019
1 parent 52a8282 commit 6f7dd17
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Mirza.Common.Tests.Utils
, databaseNameToConnectionString
, makeDatabase
, dropTables
, secondsToMicroseconds
)
where

Expand Down Expand Up @@ -178,3 +179,8 @@ dropTables db conn = do
-- investigating.
void $ forM_ tables $ \tableName -> do
execute_ conn $ fromString $ T.unpack $ "DROP TABLE IF EXISTS " <> tableName <> ";"


-- | Converts from number of seconds to the number of microseconds.
secondsToMicroseconds :: (Num a) => a -> a
secondsToMicroseconds = (* 1000000)
1 change: 1 addition & 0 deletions projects/or_scs/test/Mirza/OrgRegistry/Tests/Keys.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Mirza.OrgRegistry.Handlers.Users
import qualified Mirza.OrgRegistry.Tests.Dummies as Dummies
import Mirza.OrgRegistry.Types as ORT

import Mirza.Common.Tests.Utils
import Mirza.OrgRegistry.Tests.Utils

import Data.GS1.EPC (GS1CompanyPrefix (..))
Expand Down
3 changes: 0 additions & 3 deletions projects/or_scs/test/Mirza/OrgRegistry/Tests/Utils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,3 @@ goodRsaPublicKey = readJWK "./test/Mirza/Common/TestData/testKeys/goodJWKs/4096b
goodRsaPrivateKey :: IO (Maybe JWK)
goodRsaPrivateKey = readJWK "./test/Mirza/Common/TestData/testKeys/goodJWKs/4096bit_rsa.json"

-- | Converts from number of seconds to the number of microseconds.
secondsToMicroseconds :: (Num a) => a -> a
secondsToMicroseconds = (* 1000000)
10 changes: 10 additions & 0 deletions projects/trails/src/Mirza/Trails/Handlers/Trails.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import Control.Monad.Identity

import Data.Maybe
import Data.List (nub)
import Data.Time.Clock



Expand Down Expand Up @@ -142,6 +143,9 @@ buildTrailEntry entries previous = TrailEntry 1
addEntryQuery :: (AsTrailsServiceError err)
=> [TrailEntry] -> DB context err ()
addEntryQuery entriesRaw = do
timestampsPast <- liftIO $ allTimestampsPassed entriesRaw
throwing_If _FutureTimestampTSE timestampsPast

let ignoreNotFound = handleError (\err -> if is _SignatureNotFoundTSE err then pure Nothing else throwError err)
existingEntries <- fmap catMaybes $ traverse (ignoreNotFound . (fmap Just <$> getEntryBySignature)) (trailEntrySignature <$> entriesRaw)
-- Note: We only need to check if the signature exists (and not that the full event contents match) since the signature guarantees that they events are the same.
Expand Down Expand Up @@ -205,3 +209,9 @@ trailEntryToEntriesT trailEntry = EntriesT (trailEntrySignature trailEntry)

trailEntryToPreviousT :: TrailEntry -> [PreviousT Identity]
trailEntryToPreviousT trailEntry = (PreviousT (EntriesPrimaryKey $ trailEntrySignature trailEntry)) <$> (trailEntryPreviousSignatures trailEntry)


allTimestampsPassed :: [TrailEntry] -> IO Bool
allTimestampsPassed trail = do
now <- getCurrentTime
pure $ or $ ((> now) . getEntryTime . trailEntryTimestamp) <$> trail
1 change: 1 addition & 0 deletions projects/trails/src/Mirza/Trails/Service.hs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ trailsErrorToHttpError trailsError =
(SignatureNotFoundTSE) -> httpError err404 "A trail with a matching signature was not found."
(EventIdNotFoundTSE) -> httpError err404 "A trail with the matching EventId was not found."
(InvalidEntryVersionTSE) -> httpError err400 "Only version 1 trail entries are currently supported by this service."
(FutureTimestampTSE) -> httpError err400 "Only trails with timestamps that have passed may be added to this service."
(DuplicatePreviousEntriesTSE) -> httpError err400 "Duplicating a signature in the previous signatures of an event is not allowed."
(PreviousEntryNotFoundTSE) -> httpError err400 "It is not possible to add entries with previous signatures that are not present in the current trail or already stored by the service."
(UnmatchedUniqueViolationTSE _) -> unexpectedError trailsError
Expand Down
1 change: 1 addition & 0 deletions projects/trails/src/Mirza/Trails/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ data TrailsServiceError
| SignatureNotFoundTSE
| EventIdNotFoundTSE
| InvalidEntryVersionTSE
| FutureTimestampTSE
| DuplicatePreviousEntriesTSE
| PreviousEntryNotFoundTSE
| UnmatchedUniqueViolationTSE SqlError
Expand Down
28 changes: 27 additions & 1 deletion projects/trails/test/Mirza/Trails/Tests/Client.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Mirza.Common.Tests.ServantUtils

import Mirza.Common.Tests.Utils (checkFailureMessage,
checkFailureStatus,
secondsToMicroseconds,
within1Second)

import Mirza.Common.Types
Expand All @@ -34,6 +35,7 @@ import Crypto.Hash

import System.Random

import Control.Concurrent (threadDelay)
import Control.Exception (bracket)
import Control.Monad
import Data.Aeson
Expand Down Expand Up @@ -296,6 +298,27 @@ clientSpec = do
zeroVersionEntryResult `shouldSatisfy` isLeft
zeroVersionEntryResult `shouldSatisfy` (checkFailureStatus NS.badRequest400)
zeroVersionEntryResult `shouldSatisfy` (checkFailureMessage "Only version 1 trail entries are currently supported by this service.")
zeroVersionEntryGetResult <- http $ getTrailByEventId (trailEntryEventId zeroVersionEntry)
zeroVersionEntryGetResult `shouldSatisfy` isLeft

step "That adding an entry with a future timestamp fails"
let futureDelay = 1
futureTime <- (addUTCTime (fromInteger futureDelay)) <$> getCurrentTime
let setFutureTimestamp entry = resign $ entry{trailEntryTimestamp = EntryTime futureTime}
futureTimestampEntry <- setFutureTimestamp <$> buildEntry
verifyValidTrailTestIntegrityCheck [futureTimestampEntry]
futureTimestampEntryResult <- http $ addTrail [futureTimestampEntry]
futureTimestampEntryResult `shouldSatisfy` isLeft
futureTimestampEntryResult `shouldSatisfy` (checkFailureStatus NS.badRequest400)
futureTimestampEntryResult `shouldSatisfy` (checkFailureMessage "Only trails with timestamps that have passed may be added to this service.")
futureTimestampEntryGetResult <- http $ getTrailByEventId (trailEntryEventId futureTimestampEntry)
futureTimestampEntryGetResult `shouldSatisfy` isLeft
-- Integrity Check: That after the timestamp deplay has elapsed that the entry can be entered.
threadDelay $ fromIntegral $ secondsToMicroseconds futureDelay
futureTimestampEntryElapsedResult <- http $ addTrail [futureTimestampEntry]
futureTimestampEntryElapsedResult `shouldBe` Right NoContent
futureTimestampEntryElapsedGetResult <- http $ getTrailByEventId (trailEntryEventId futureTimestampEntry)
futureTimestampEntryElapsedGetResult `shouldMatchTrail` [futureTimestampEntry]

step "That adding a trail with a failing entry causes the rest of the trail not to be added"
invalidMiddleEntryTrail <- addNextEntryIO $ fmap (applyHead setVersionZero) $ addNextEntryIO $ buildSingleEntryTrail
Expand Down Expand Up @@ -330,6 +353,8 @@ clientSpec = do
duplicatePreviousSignaturesTrailResult `shouldSatisfy` isLeft
duplicatePreviousSignaturesTrailResult `shouldSatisfy` (checkFailureStatus NS.badRequest400)
duplicatePreviousSignaturesTrailResult `shouldSatisfy` (checkFailureMessage "Duplicating a signature in the previous signatures of an event is not allowed.")
duplicatePreviousSignaturesTrailGetResult <- http $ getTrailByEventId (trailEntryEventId $ head duplicatePreviousSignaturesTrail)
duplicatePreviousSignaturesTrailGetResult `shouldSatisfy` isLeft

step "That adding an entry with the previous signature not in the trail, but already stored by the service succeeds"
multiPhaseAddFirst <- buildEntry
Expand All @@ -351,9 +376,10 @@ clientSpec = do
noPreviousAddResult `shouldSatisfy` isLeft
noPreviousAddResult `shouldSatisfy` (checkFailureStatus NS.badRequest400)
noPreviousAddResult `shouldSatisfy` (checkFailureMessage "It is not possible to add entries with previous signatures that are not present in the current trail or already stored by the service.")
noPreviousAddGetResult <- http $ getTrailByEventId (trailEntryEventId noPreviousEntry)
noPreviousAddGetResult `shouldSatisfy` isLeft

-- TODO: Test that invalid signature fails.
-- TODO: Test that timestamp in the future is invalid.


let healthTests = testCaseSteps "Provides health status" $ \step ->
Expand Down

0 comments on commit 6f7dd17

Please sign in to comment.