summaryrefslogtreecommitdiff
path: root/main/State.hs
blob: b8ae418cf285c5883f63293d96cf678a6ab9f827 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
module State (
    loadLocalStateHead,
    createLocalStateHead,
    updateSharedIdentity,
    interactiveIdentityUpdate,
) where

import Control.Monad
import Control.Monad.Except
import Control.Monad.IO.Class

import Data.Foldable
import Data.Proxy
import Data.Text (Text)
import Data.Text qualified as T

import Erebos.Error
import Erebos.Identity
import Erebos.PubKey
import Erebos.State
import Erebos.Storable
import Erebos.Storage

import Terminal


loadLocalStateHead :: MonadIO m => Terminal -> Storage -> m (Head LocalState)
loadLocalStateHead term st = loadHeads st >>= \case
    (h:_) -> return h
    [] -> liftIO $ do
        setPrompt term "Name: "
        name <- getInputLine term $ KeepPrompt . maybe T.empty T.pack

        setPrompt term "Device: "
        devName <- getInputLine term $ KeepPrompt . maybe T.empty T.pack

        ( owner, shared ) <- if
            | T.null name -> do
                return ( Nothing, [] )
            | otherwise -> do
                owner <- createIdentity st (Just name) Nothing
                shared <- wrappedStore st $ SharedState
                    { ssPrev = []
                    , ssType = Just $ sharedTypeID @(Maybe ComposedIdentity) Proxy
                    , ssValue = [ storedRef $ idExtData owner ]
                    }
                return ( Just owner, [ shared ] )

        identity <- createIdentity st (if T.null devName then Nothing else Just devName) owner

        storeHead st $ LocalState
            { lsPrev = Nothing
            , lsIdentity = idExtData identity
            , lsShared = shared
            , lsOther = []
            }

createLocalStateHead :: (MonadIO m, MonadFail m) => Storage -> [ Maybe Text ] -> m (Head LocalState)
createLocalStateHead _ [] = fail "createLocalStateHead: empty name list"
createLocalStateHead st ( ownerName : names ) = liftIO $ do
    owner <- createIdentity st ownerName Nothing
    identity <- foldM createSingleIdentity owner names
    shared <- case names of
        [] -> return []
        _ : _ -> do
            fmap (: []) $ wrappedStore st $ SharedState
                { ssPrev = []
                , ssType = Just $ sharedTypeID @(Maybe ComposedIdentity) Proxy
                , ssValue = [ storedRef $ idExtData owner ]
                }
    storeHead st $ LocalState
        { lsPrev = Nothing
        , lsIdentity = idExtData identity
        , lsShared = shared
        , lsOther = []
        }
  where
    createSingleIdentity owner name = createIdentity st name (Just owner)


updateSharedIdentity :: (MonadHead LocalState m, MonadError e m, FromErebosError e) => Terminal -> m ()
updateSharedIdentity term = updateLocalState_ $ updateSharedState_ $ \case
    Just identity -> do
        Just . toComposedIdentity <$> interactiveIdentityUpdate term identity
    Nothing -> throwOtherError "no existing shared identity"

interactiveIdentityUpdate :: (Foldable f, MonadStorage m, MonadIO m, MonadError e m, FromErebosError e) => Terminal -> Identity f -> m UnifiedIdentity
interactiveIdentityUpdate term fidentity = do
    identity <- mergeIdentity fidentity
    name <- liftIO $ do
        setPrompt term $ T.unpack $ T.concat $ concat
            [ [ T.pack "Name" ]
            , case idName identity of
                   Just name -> [T.pack " [", name, T.pack "]"]
                   Nothing -> []
            , [ T.pack ": " ]
            ]
        getInputLine term $ KeepPrompt . maybe T.empty T.pack

    if  | T.null name -> return identity
        | otherwise -> do
            secret <- loadKey $ idKeyIdentity identity
            maybe (throwOtherError "created invalid identity") return . validateExtendedIdentity =<<
                mstore =<< sign secret =<< mstore . ExtendedIdentityData =<< return (emptyIdentityExtension $ idData identity)
                { idePrev = toList $ idExtDataF identity
                , ideName = Just name
                }