refactor: improve cryptoid caching

This commit is contained in:
Gregor Kleen 2021-03-30 20:02:16 +02:00
parent f155a4bf08
commit d65bd6889b
9 changed files with 68 additions and 36 deletions

View File

@ -3,6 +3,7 @@
module CryptoID module CryptoID
( module CryptoID ( module CryptoID
, module CryptoID.Cached
, module Data.CryptoID.Poly.ImplicitNamespace , module Data.CryptoID.Poly.ImplicitNamespace
, module Data.UUID.Cryptographic.ImplicitNamespace , module Data.UUID.Cryptographic.ImplicitNamespace
, module System.FilePath.Cryptographic.ImplicitNamespace , module System.FilePath.Cryptographic.ImplicitNamespace
@ -18,6 +19,7 @@ import qualified Data.CryptoID as E
import Data.CryptoID.Poly.ImplicitNamespace hiding (decrypt, encrypt) import Data.CryptoID.Poly.ImplicitNamespace hiding (decrypt, encrypt)
import Data.UUID.Cryptographic.ImplicitNamespace hiding (decrypt, encrypt) import Data.UUID.Cryptographic.ImplicitNamespace hiding (decrypt, encrypt)
import System.FilePath.Cryptographic.ImplicitNamespace hiding (decrypt, encrypt) import System.FilePath.Cryptographic.ImplicitNamespace hiding (decrypt, encrypt)
import CryptoID.Cached
import qualified Data.Text as Text import qualified Data.Text as Text
@ -28,28 +30,6 @@ import Data.Aeson.Encoding (text)
import Text.Blaze (ToMarkup(..)) import Text.Blaze (ToMarkup(..))
import qualified Data.CryptoID.Class.ImplicitNamespace as I
encrypt :: forall plaintext ciphertext m.
( I.HasCryptoID ciphertext plaintext m
, KnownSymbol (CryptoIDNamespace ciphertext plaintext)
, MonadHandler m
, Typeable ciphertext
, PathPiece plaintext
)
=> plaintext -> m (I.CryptoID ciphertext plaintext)
encrypt plain = $cachedHereBinary (toPathPiece plain) $ I.encrypt plain
decrypt :: forall plaintext ciphertext m.
( I.HasCryptoID ciphertext plaintext m
, MonadHandler m
, Typeable plaintext
, PathPiece ciphertext
)
=> I.CryptoID ciphertext plaintext -> m plaintext
decrypt cipher = $cachedHereBinary (toPathPiece $ ciphertext cipher) $ I.decrypt cipher
instance {-# OVERLAPPING #-} MonadThrow m => MonadCrypto (ReaderT CryptoIDKey m) where instance {-# OVERLAPPING #-} MonadThrow m => MonadCrypto (ReaderT CryptoIDKey m) where
type MonadCryptoKey (ReaderT CryptoIDKey m) = CryptoIDKey type MonadCryptoKey (ReaderT CryptoIDKey m) = CryptoIDKey

51
src/CryptoID/Cached.hs Normal file
View File

@ -0,0 +1,51 @@
module CryptoID.Cached
( encrypt, decrypt
) where
import Import.NoModel
import qualified Data.Binary as Binary
import qualified Data.CryptoID.Class.ImplicitNamespace as I
newtype CryptoIDDecryption ciphertext plaintext = CryptoIDDecryption plaintext
deriving (Typeable)
newtype CryptoIDEncryption ciphertext plaintext = CryptoIDEncryption ciphertext
deriving (Typeable)
encrypt :: forall plaintext ciphertext m.
( I.HasCryptoID ciphertext plaintext (HandlerFor (HandlerSite m))
, Typeable plaintext, Typeable ciphertext
, Binary plaintext, Binary ciphertext
, MonadHandler m
)
=> plaintext -> m (I.CryptoID ciphertext plaintext)
encrypt plain = liftHandler $ do
(cachedEnc :: Maybe (CryptoIDEncryption ciphertext plaintext)) <- cacheByGet cacheKey
case cachedEnc of
Nothing -> do
cID@(I.CryptoID crypt) <- I.encrypt plain
cacheBySet cacheKey (CryptoIDEncryption crypt :: CryptoIDEncryption ciphertext plaintext)
cacheBySet (toStrict $ Binary.encode crypt) (CryptoIDDecryption plain :: CryptoIDDecryption ciphertext plaintext)
return cID
Just (CryptoIDEncryption crypt) -> return $ I.CryptoID crypt
where cacheKey = toStrict $ Binary.encode plain
decrypt :: forall plaintext ciphertext m.
( I.HasCryptoID ciphertext plaintext (HandlerFor (HandlerSite m))
, Typeable plaintext, Typeable ciphertext
, Binary plaintext, Binary ciphertext
, MonadHandler m
)
=> I.CryptoID ciphertext plaintext -> m plaintext
decrypt cID@(I.CryptoID crypt) = liftHandler $ do
(cachedDec :: Maybe (CryptoIDDecryption ciphertext plaintext)) <- cacheByGet cacheKey
case cachedDec of
Nothing -> do
plain <- I.decrypt cID
cacheBySet (toStrict $ Binary.encode plain) (CryptoIDEncryption crypt :: CryptoIDEncryption ciphertext plaintext)
cacheBySet cacheKey (CryptoIDDecryption plain :: CryptoIDDecryption ciphertext plaintext)
return plain
Just (CryptoIDDecryption plain) -> return plain
where cacheKey = toStrict $ Binary.encode crypt

View File

@ -321,7 +321,7 @@ routeNormalizers = map (hoist (hoist liftHandler . withReaderT projectBackend) .
& typesUsing @RouteChildren @WorkflowPayloadLabel . filtered (== wpl) .~ wpl' & typesUsing @RouteChildren @WorkflowPayloadLabel . filtered (== wpl) .~ wpl'
verifySubmission = maybeOrig $ \route -> do verifySubmission = maybeOrig $ \route -> do
CSubmissionR _tid _ssh _csh _shn cID sr <- return route CSubmissionR _tid _ssh _csh _shn cID sr <- return route
sId <- $cachedHereBinary cID $ decrypt cID sId <- decrypt cID
Submission{submissionSheet} <- MaybeT . $cachedHereBinary cID . lift $ get sId Submission{submissionSheet} <- MaybeT . $cachedHereBinary cID . lift $ get sId
Sheet{sheetCourse, sheetName} <- MaybeT . $cachedHereBinary submissionSheet . lift $ get submissionSheet Sheet{sheetCourse, sheetName} <- MaybeT . $cachedHereBinary submissionSheet . lift $ get submissionSheet
Course{courseTerm, courseSchool, courseShorthand} <- MaybeT . $cachedHereBinary sheetCourse . lift $ get sheetCourse Course{courseTerm, courseSchool, courseShorthand} <- MaybeT . $cachedHereBinary sheetCourse . lift $ get sheetCourse

View File

@ -57,7 +57,7 @@ getCAppsFilesR tid ssh csh = do
E.&&. course E.^. CourseShorthand E.==. E.val csh E.&&. course E.^. CourseShorthand E.==. E.val csh
return (allocation, user, courseApplication) return (allocation, user, courseApplication)
apps' <- flip filterM apps $ \(_, _, Entity appId _) -> do apps' <- flip filterM apps $ \(_, _, Entity appId _) -> do
cID <- cachedByBinary appId $ encrypt appId cID <- encrypt appId
lift . hasReadAccessTo $ CApplicationR tid ssh csh cID CAFilesR lift . hasReadAccessTo $ CApplicationR tid ssh csh cID CAFilesR
let let
applicationAllocs = setOf (folded . _1) apps' applicationAllocs = setOf (folded . _1) apps'
@ -87,7 +87,7 @@ getCAppsFilesR tid ssh csh = do
= id = id
forM_ apps' $ \(mbAlloc, Entity _ User{..}, Entity appId CourseApplication{..}) -> do forM_ apps' $ \(mbAlloc, Entity _ User{..}, Entity appId CourseApplication{..}) -> do
cID <- cachedByBinary appId $ encrypt appId :: _ CryptoFileNameCourseApplication cID <- encrypt appId :: _ CryptoFileNameCourseApplication
let mkAppDir = mkAllocationDir (entityVal <$> mbAlloc) . (</>) (unpack [st|#{CI.foldedCase $ ciphertext cID}-#{CI.foldCase userSurname}|]) let mkAppDir = mkAllocationDir (entityVal <$> mbAlloc) . (</>) (unpack [st|#{CI.foldedCase $ ciphertext cID}-#{CI.foldCase userSurname}|])
fileEntitySource = E.selectSource . E.from $ \courseApplicationFile -> do fileEntitySource = E.selectSource . E.from $ \courseApplicationFile -> do
E.where_ $ courseApplicationFile E.^. CourseApplicationFileApplication E.==. E.val appId E.where_ $ courseApplicationFile E.^. CourseApplicationFileApplication E.==. E.val appId

View File

@ -421,7 +421,6 @@ examTemplate cid = runMaybeT $ do
validateExam :: forall m. validateExam :: forall m.
( MonadHandler m ( MonadHandler m
, HandlerSite m ~ UniWorX , HandlerSite m ~ UniWorX
, MonadThrow m
) )
=> CourseId -> Maybe (Entity Exam) -> FormValidator ExamForm (SqlPersistT m) () => CourseId -> Maybe (Entity Exam) -> FormValidator ExamForm (SqlPersistT m) ()
validateExam cId oldExam = do validateExam cId oldExam = do

View File

@ -1502,11 +1502,10 @@ fsUniq mkUnique seed = "" { fsName = Just $ mkUnique seed }
optionsPersistCryptoId :: forall backend a msg. optionsPersistCryptoId :: forall backend a msg.
( HasCryptoUUID (Key a) (HandlerFor UniWorX) ( HasCryptoUUID (Key a) (HandlerFor UniWorX)
, KnownSymbol (CryptoIDNamespace UUID (Key a))
, RenderMessage UniWorX msg , RenderMessage UniWorX msg
, YesodPersistBackend UniWorX ~ backend , YesodPersistBackend UniWorX ~ backend
, PersistRecordBackend a backend , PersistRecordBackend a backend
, PathPiece (Key a) , Binary (Key a), Typeable a
) )
=> [Filter a] => [Filter a]
-> [SelectOpt a] -> [SelectOpt a]
@ -1518,11 +1517,10 @@ optionsPersistCryptoId filts ords toDisplay = do
optionsCryptoIdE :: forall backend a msg. optionsCryptoIdE :: forall backend a msg.
( HasCryptoUUID (Key a) (HandlerFor UniWorX) ( HasCryptoUUID (Key a) (HandlerFor UniWorX)
, KnownSymbol (CryptoIDNamespace UUID (Key a))
, RenderMessage UniWorX msg , RenderMessage UniWorX msg
, YesodPersistBackend UniWorX ~ backend , YesodPersistBackend UniWorX ~ backend
, PersistRecordBackend a backend , PersistRecordBackend a backend
, PathPiece (Key a) , Binary (Key a), Typeable a
) )
=> E.SqlQuery (E.SqlExpr (Entity a)) => E.SqlQuery (E.SqlExpr (Entity a))
-> (a -> msg) -> (a -> msg)
@ -1532,12 +1530,11 @@ optionsCryptoIdE query toDisplay = do
optionsCryptoIdF ents (return . entityKey) (return . toDisplay . entityVal) optionsCryptoIdF ents (return . entityKey) (return . toDisplay . entityVal)
optionsCryptoIdF :: forall m mono k msg. optionsCryptoIdF :: forall m mono k msg.
( HasCryptoUUID k m ( HasCryptoUUID k (HandlerFor (HandlerSite m))
, KnownSymbol (CryptoIDNamespace UUID k)
, RenderMessage (HandlerSite m) msg , RenderMessage (HandlerSite m) msg
, MonoFoldable mono , MonoFoldable mono
, MonadHandler m , MonadHandler m, HandlerSite m ~ UniWorX
, PathPiece k , Binary k, Typeable k
) )
=> mono => mono
-> (Element mono -> m k) -> (Element mono -> m k)

View File

@ -72,7 +72,6 @@ workflowEdgeForm :: ( MonadHandler m
, HandlerSite m ~ UniWorX , HandlerSite m ~ UniWorX
, MonadHandler m' , MonadHandler m'
, HandlerSite m' ~ UniWorX , HandlerSite m' ~ UniWorX
, MonadCatch m'
, MonadUnliftIO m' , MonadUnliftIO m'
) )
=> Either WorkflowInstanceId WorkflowWorkflowId => Either WorkflowInstanceId WorkflowWorkflowId

View File

@ -966,6 +966,12 @@ foreverBreak :: Monad m
foreverBreak cont = evalContT . callCC $ forever . cont foreverBreak cont = evalContT . callCC $ forever . cont
sortOnM :: (Ord b, Monad m)
=> (a -> m b)
-> [a]
-> m [a]
sortOnM f = fmap (map snd . sortBy (comparing fst)) . mapM (\x -> (\y -> y `seq` (y, x)) <$> f x)
-------------- --------------
-- Foldable -- -- Foldable --
-------------- --------------

View File

@ -22,7 +22,7 @@ deriveJSON defaultOptions
{ fieldLabelModifier = camelToPathPiece' 1 { fieldLabelModifier = camelToPathPiece' 1
} ''CorrectInterfaceUser } ''CorrectInterfaceUser
userToResponse :: (MonadHandler m, MonadCrypto m, MonadCryptoKey m ~ CryptoIDKey) => Entity User -> m CorrectInterfaceUser userToResponse :: (MonadHandler m, MonadCrypto (HandlerFor (HandlerSite m)), MonadCryptoKey (HandlerFor (HandlerSite m)) ~ CryptoIDKey) => Entity User -> m CorrectInterfaceUser
userToResponse (Entity uid User{..}) = do userToResponse (Entity uid User{..}) = do
uuid <- encrypt uid uuid <- encrypt uid
return CorrectInterfaceUser return CorrectInterfaceUser