From 1aef7681082e411c135802881ebcd3ffd0168fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Sat, 12 Oct 2019 21:42:49 +0200 Subject: Shared state and identity update --- src/State.hs | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/State.hs (limited to 'src/State.hs') diff --git a/src/State.hs b/src/State.hs new file mode 100644 index 0000000..272044a --- /dev/null +++ b/src/State.hs @@ -0,0 +1,133 @@ +module State ( + LocalState(..), + SharedState(..), + + loadLocalState, + updateLocalState, updateLocalState_, + updateIdentity, +) where + +import Data.List +import qualified Data.Text as T +import qualified Data.Text.IO as T + +import System.IO + +import Identity +import Message +import PubKey +import Storage +import Util + +data LocalState = LocalState + { lsIdentity :: Stored (Signed IdentityData) + , lsShared :: [Stored SharedState] + , lsMessages :: StoredList DirectMessageThread -- TODO: move to shared + } + +data SharedState = SharedState + { ssPrev :: [Stored SharedState] + , ssIdentity :: [Stored (Signed IdentityData)] + } + +instance Storable LocalState where + store' st = storeRec $ do + storeRef "id" $ lsIdentity st + mapM_ (storeRef "shared") $ lsShared st + storeRef "dmsg" $ lsMessages st + + load' = loadRec $ LocalState + <$> loadRef "id" + <*> loadRefs "shared" + <*> loadRef "dmsg" + +instance Storable SharedState where + store' st = storeRec $ do + mapM_ (storeRef "PREV") $ ssPrev st + mapM_ (storeRef "id") $ ssIdentity st + + load' = loadRec $ SharedState + <$> loadRefs "PREV" + <*> loadRefs "id" + + +loadLocalState :: Storage -> IO Head +loadLocalState st = loadHeadDef st "erebos" $ do + putStr "Name: " + hFlush stdout + name <- T.getLine + + (secret, public) <- generateKeys st + (_secretMsg, publicMsg) <- generateKeys st + (devSecret, devPublic) <- generateKeys st + (_devSecretMsg, devPublicMsg) <- generateKeys st + + owner <- wrappedStore st =<< sign secret =<< wrappedStore st (emptyIdentityData public) + { iddName = Just name, iddKeyMessage = Just publicMsg } + identity <- wrappedStore st =<< signAdd devSecret =<< sign secret =<< wrappedStore st (emptyIdentityData devPublic) + { iddOwner = Just owner, iddKeyMessage = Just devPublicMsg } + + msgs <- emptySList st + + shared <- wrappedStore st $ SharedState + { ssPrev = [] + , ssIdentity = [owner] + } + return $ LocalState + { lsIdentity = identity + , lsShared = [shared] + , lsMessages = msgs + } + +updateLocalState_ :: Storage -> (Stored LocalState -> IO (Stored LocalState)) -> IO () +updateLocalState_ st f = updateLocalState st (fmap (,()) . f) + +updateLocalState :: Storage -> (Stored LocalState -> IO (Stored LocalState, a)) -> IO a +updateLocalState ls f = do + Just erebosHead <- loadHead ls "erebos" + (st, x) <- f $ wrappedLoad (headRef erebosHead) + Right _ <- replaceHead st (Right erebosHead) + return x + +updateSharedState_ :: Storage -> (Stored SharedState -> IO (Stored SharedState)) -> IO () +updateSharedState_ st f = updateSharedState st (fmap (,()) . f) + +updateSharedState :: Storage -> (Stored SharedState -> IO (Stored SharedState, a)) -> IO a +updateSharedState st f = updateLocalState st $ \ls -> do + (shared, x) <- f =<< mergeSharedStates (lsShared $ fromStored ls) + (,x) <$> wrappedStore st (fromStored ls) { lsShared = [shared] } + +mergeSharedStates :: [(Stored SharedState)] -> IO (Stored SharedState) +mergeSharedStates [s] = return s +mergeSharedStates ss@(s:_) = wrappedStore (storedStorage s) $ SharedState + { ssPrev = ss + , ssIdentity = uniq $ sort $ concatMap (ssIdentity . fromStored) $ ss -- TODO: ancestor elimination + } +mergeSharedStates [] = error "mergeSharedStates: empty list" + +updateIdentity :: Storage -> IO () +updateIdentity st = updateSharedState_ st $ \sshared -> do + let shared = fromStored sshared + Just identity = verifyIdentityF $ ssIdentity shared + public = idKeyIdentity identity + + T.putStr $ T.concat $ concat + [ [ T.pack "Name" ] + , case idName identity of + Just name -> [T.pack " [", name, T.pack "]"] + Nothing -> [] + , [ T.pack ": " ] + ] + hFlush stdout + name <- T.getLine + + identity' <- if + | T.null name -> idData <$> mergeIdentity identity + | otherwise -> do + Just secret <- loadKey public + wrappedStore st =<< sign secret =<< wrappedStore st (emptyIdentityData public) + { iddPrev = ssIdentity shared + , iddName = Just name + } + + wrappedStore st shared { ssIdentity = [identity'] } -- cgit v1.2.3