Skip to content

Commit df9b0b6

Browse files
committed
wip: extend client identity
1 parent ca92ae7 commit df9b0b6

17 files changed

Lines changed: 143 additions & 63 deletions

File tree

libs/types-common/src/Data/Id.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ module Data.Id
5858
OAuthRefreshTokenId,
5959
ChallengeId,
6060
MeetingId,
61+
HistoryClientId,
6162

6263
-- * Utils
6364
uuidSchema,
@@ -116,6 +117,7 @@ data IdTag
116117
| Challenge
117118
| Job
118119
| Meeting
120+
| HistoryClient
119121

120122
idTagName :: IdTag -> Text
121123
idTagName Asset = "Asset"
@@ -132,6 +134,7 @@ idTagName OAuthRefreshToken = "OAuthRefreshToken"
132134
idTagName Challenge = "Challenge"
133135
idTagName Job = "Job"
134136
idTagName Meeting = "Meeting"
137+
idTagName HistoryClient = "HistoryClient"
135138

136139
class KnownIdTag (t :: IdTag) where
137140
idTagValue :: IdTag
@@ -162,6 +165,8 @@ instance KnownIdTag 'Job where idTagValue = Job
162165

163166
instance KnownIdTag 'Meeting where idTagValue = Meeting
164167

168+
instance KnownIdTag 'HistoryClient where idTagValue = HistoryClient
169+
165170
type AssetId = Id 'Asset
166171

167172
type InvitationId = Id 'Invitation
@@ -192,6 +197,8 @@ type JobId = Id 'Job
192197

193198
type MeetingId = Id 'Meeting
194199

200+
type HistoryClientId = Id 'HistoryClient
201+
195202
-- Id -------------------------------------------------------------------------
196203

197204
data NoId = NoId deriving (Eq, Show, Generic)

libs/wire-api/src/Wire/API/Error/Galley.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ data GroupInfoDiagnostics = GroupInfoDiagnostics
631631
{ commit :: ByteString,
632632
groupInfo :: ByteString,
633633
groupId :: GroupId,
634-
clients :: [(Int, ClientIdentity)],
634+
clients :: [(Int, GroupMember)],
635635
convId :: ConvOrSubConvId,
636636
domain :: Domain
637637
}
@@ -649,7 +649,7 @@ instance APIError GroupInfoDiagnostics where
649649
headers = []
650650
}
651651

652-
indexedClientSchema :: ValueSchema NamedSwaggerDoc (Int, ClientIdentity)
652+
indexedClientSchema :: ValueSchema NamedSwaggerDoc (Int, GroupMember)
653653
indexedClientSchema =
654654
object $
655655
(,)

libs/wire-api/src/Wire/API/MLS/Credential.hs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# LANGUAGE TemplateHaskell #-}
2+
13
-- This file is part of the Wire Server implementation.
24
--
35
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
@@ -17,7 +19,7 @@
1719

1820
module Wire.API.MLS.Credential where
1921

20-
import Control.Lens ((?~))
22+
import Control.Lens (makePrisms, (?~))
2123
import Data.Aeson (FromJSON (..), ToJSON (..))
2224
import Data.Binary
2325
import Data.Binary.Get
@@ -120,17 +122,30 @@ instance ToHttpApiData ClientIdentity where
120122
toHeader = encodeMLS'
121123
toUrlPiece = T.decodeUtf8 . encodeMLS'
122124

125+
parseId :: Get (Id a)
126+
parseId = maybe (fail "Invalid UUID") (pure . Id) . fromASCIIBytes =<< getByteString 36
127+
123128
instance ParseMLS ClientIdentity where
124129
parseMLS = do
125-
uid <-
126-
maybe (fail "Invalid UUID") (pure . Id) . fromASCIIBytes =<< getByteString 36
130+
uid <- parseId
127131
char ':'
128132
cid <- ClientId <$> hexadecimal
129133
char '@'
130134
dom <-
131135
either fail pure . (mkDomain . T.pack) =<< many' anyChar
132136
pure $ ClientIdentity dom uid cid
133137

138+
data GroupMember = RegularClient ClientIdentity | HistoryClient HistoryClientId
139+
deriving (Eq, Show)
140+
141+
parseHistoryClient :: Get HistoryClientId
142+
parseHistoryClient = string "history-client:" *> parseId
143+
144+
instance ParseMLS GroupMember where
145+
parseMLS =
146+
(HistoryClient <$> parseHistoryClient)
147+
<|> (RegularClient <$> parseMLS)
148+
134149
-- format of the x509 client identity: {userid}%21{deviceid}@{host}
135150
parseX509ClientIdentity :: Get ClientIdentity
136151
parseX509ClientIdentity = do
@@ -154,3 +169,11 @@ instance SerialiseMLS ClientIdentity where
154169

155170
mkClientIdentity :: Qualified UserId -> ClientId -> ClientIdentity
156171
mkClientIdentity (Qualified uid domain) = ClientIdentity domain uid
172+
173+
makePrisms ''GroupMember
174+
175+
instance ToSchema GroupMember where
176+
schema =
177+
named "GroupMember" $
178+
tag _RegularClient (unnamed schema)
179+
<> tag _HistoryClient (unnamed schema)

libs/wire-api/src/Wire/API/MLS/KeyPackage.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ instance HasField "extensions" KeyPackage [Extension] where
233233
instance HasField "leafNode" KeyPackage LeafNode where
234234
getField = (.tbs.value.leafNode)
235235

236-
credentialIdentityAndKey :: Credential -> Either Text (ClientIdentity, Maybe X509.PubKey)
236+
credentialIdentityAndKey :: Credential -> Either Text (GroupMember, Maybe X509.PubKey)
237237
credentialIdentityAndKey (BasicCredential i) = (,) <$> decodeMLS' i <*> pure Nothing
238238
credentialIdentityAndKey (X509Credential certs) = do
239239
bs <- case certs of
@@ -244,9 +244,9 @@ credentialIdentityAndKey (X509Credential certs) = do
244244
X509.decodeSignedCertificate bs
245245
-- FUTUREWORK: verify signature
246246
let cert = X509.getCertificate signed
247-
certificateIdentityAndKey cert
247+
first RegularClient <$> certificateIdentityAndKey cert
248248

249-
keyPackageIdentity :: KeyPackage -> Either Text ClientIdentity
249+
keyPackageIdentity :: KeyPackage -> Either Text GroupMember
250250
keyPackageIdentity kp = fst <$> credentialIdentityAndKey kp.leafNode.credential
251251

252252
certificateIdentityAndKey :: X509.Certificate -> Either Text (ClientIdentity, Maybe X509.PubKey)

libs/wire-api/src/Wire/API/MLS/Validation.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import Wire.API.MLS.Serialisation
3939
import Wire.API.MLS.Validation.Error
4040

4141
validateKeyPackage ::
42-
Maybe ClientIdentity ->
42+
Maybe GroupMember ->
4343
KeyPackage ->
4444
Either ValidationError (CipherSuiteTag, Lifetime)
4545
validateKeyPackage mIdentity kp = do
@@ -79,7 +79,7 @@ validateKeyPackage mIdentity kp = do
7979

8080
validateLeafNode ::
8181
CipherSuiteTag ->
82-
Maybe ClientIdentity ->
82+
Maybe GroupMember ->
8383
LeafNodeTBSExtra ->
8484
LeafNode ->
8585
Either ValidationError ()
@@ -99,7 +99,12 @@ validateLeafNode cs mIdentity extra leafNode = do
9999
validateSource extra.tag leafNode.source
100100
validateCapabilities (credentialTag leafNode.credential) leafNode.capabilities
101101

102-
validateCredential :: CipherSuiteTag -> ByteString -> Maybe ClientIdentity -> Credential -> Either ValidationError ()
102+
validateCredential ::
103+
CipherSuiteTag ->
104+
ByteString ->
105+
Maybe GroupMember ->
106+
Credential ->
107+
Either ValidationError ()
103108
validateCredential cs pkey mIdentity cred = do
104109
-- FUTUREWORK: check signature in the case of an x509 credential
105110
(identity, mkey) <-

libs/wire-api/test/unit/Test/Wire/API/MLS.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ testParseKeyPackage = do
8989

9090
case keyPackageIdentity kp of
9191
Left err -> assertFailure $ "Failed to parse identity: " <> T.unpack err
92-
Right identity -> identity @?= alice
92+
Right identity -> identity @?= RegularClient alice
9393

9494
testParseKeyPackageWithCapabilities :: IO ()
9595
testParseKeyPackageWithCapabilities = do

libs/wire-subsystems/src/Wire/ConversationStore/Cassandra.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,9 @@ addBotMember s bot cnv = do
768768
lookupMLSClientLeafIndices :: GroupId -> Client (ClientMap LeafIndex, IndexMap)
769769
lookupMLSClientLeafIndices groupId = do
770770
entries <- retry x5 (query Cql.lookupMLSClients (params LocalQuorum (Identity groupId)))
771-
pure $ (mkClientMap &&& mkIndexMap) entries
771+
-- TODO: (leif) lookup history client
772+
historyClientEntries <- todo
773+
pure $ (mkClientMap entries, mkIndexMapFromParts entries historyClientEntries )
772774

773775
lookupMLSClients :: GroupId -> Client (ClientMap LeafIndex)
774776
lookupMLSClients = fmap fst . lookupMLSClientLeafIndices

libs/wire-subsystems/src/Wire/ConversationStore/MLS/Types.hs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ import Wire.API.MLS.LeafNode
5454
import Wire.API.MLS.SubConversation
5555
import Wire.StoredConversation
5656

57+
mkGroupMember ::
58+
Maybe Domain ->
59+
Maybe UserId ->
60+
Maybe ClientId ->
61+
Maybe HistoryClientId ->
62+
Maybe GroupMember
63+
mkGroupMember (Just dom) (Just uid) (Just cid) Nothing =
64+
Just (RegularClient (ClientIdentity dom uid cid))
65+
mkGroupMember Nothing Nothing Nothing (Just hid) = Just (HistoryClient hid)
66+
mkGroupMember _ _ _ _ = Nothing
67+
5768
-- | A map of leaf index to members.
5869
--
5970
-- This is used to reconstruct client
@@ -63,31 +74,40 @@ import Wire.StoredConversation
6374
-- Note that clients that are in the process of being removed from a group
6475
-- (i.e. there is a pending remove proposals for them) are included in this
6576
-- mapping.
66-
newtype IndexMap = IndexMap {unIndexMap :: IntMap ClientIdentity}
77+
newtype IndexMap = IndexMap {unIndexMap :: IntMap GroupMember}
6778
deriving (Eq, Show)
6879
deriving newtype (Semigroup, Monoid)
6980

70-
mkIndexMap :: [(Domain, UserId, ClientId, Int32, Bool)] -> IndexMap
71-
mkIndexMap = IndexMap . foldr addEntry mempty
81+
mkIndexMapFromParts ::
82+
[(Domain, UserId, ClientId, Int32, Bool)] ->
83+
[(HistoryClientId, Int32, Bool)] ->
84+
IndexMap
85+
mkIndexMapFromParts rows1 rows2 =
86+
IndexMap
87+
. flip (foldr addHistoryClient) rows2
88+
. flip (foldr addRegularClient) rows1
89+
$ mempty
7290
where
73-
addEntry (dom, usr, c, leafidx, _pending_removal) =
74-
IntMap.insert (fromIntegral leafidx) (ClientIdentity dom usr c)
91+
addHistoryClient (h, leafidx, _) =
92+
IntMap.insert (fromIntegral leafidx) (HistoryClient h)
93+
addRegularClient (dom, usr, c, leafidx, _) =
94+
IntMap.insert (fromIntegral leafidx) (RegularClient (ClientIdentity dom usr c))
7595

76-
imLookup :: IndexMap -> LeafIndex -> Maybe ClientIdentity
96+
imLookup :: IndexMap -> LeafIndex -> Maybe GroupMember
7797
imLookup m i = IntMap.lookup (fromIntegral i) (unIndexMap m)
7898

79-
imFromList :: [(LeafIndex, ClientIdentity)] -> IndexMap
99+
imFromList :: [(LeafIndex, GroupMember)] -> IndexMap
80100
imFromList = IndexMap . IntMap.fromList . map (first fromIntegral)
81101

82102
imNextIndex :: IndexMap -> LeafIndex
83103
imNextIndex im =
84104
fromIntegral . fromJust $
85105
find (\n -> not $ IntMap.member n (unIndexMap im)) [0 ..]
86106

87-
imAddClient :: IndexMap -> ClientIdentity -> (LeafIndex, IndexMap)
107+
imAddClient :: IndexMap -> GroupMember -> (LeafIndex, IndexMap)
88108
imAddClient im cid = let idx = imNextIndex im in (idx, IndexMap $ IntMap.insert (fromIntegral idx) cid $ unIndexMap im)
89109

90-
imRemoveClient :: IndexMap -> LeafIndex -> Maybe (ClientIdentity, IndexMap)
110+
imRemoveClient :: IndexMap -> LeafIndex -> Maybe (GroupMember, IndexMap)
91111
imRemoveClient im idx = do
92112
cid <- imLookup im idx
93113
pure (cid, IndexMap . IntMap.delete (fromIntegral idx) $ unIndexMap im)
@@ -98,7 +118,7 @@ imRemoveIndices keys =
98118
. flip IntMap.withoutKeys (IntSet.fromList (map fromIntegral keys))
99119
. unIndexMap
100120

101-
imAssocs :: IndexMap -> [(Int, ClientIdentity)]
121+
imAssocs :: IndexMap -> [(Int, GroupMember)]
102122
imAssocs = IntMap.assocs . unIndexMap
103123

104124
-- | A two-level map of users to clients to leaf indices.
@@ -111,6 +131,7 @@ imAssocs = IntMap.assocs . unIndexMap
111131
-- this mapping.
112132
newtype ClientMap a = ClientMap
113133
{ unClientMap :: Map (Qualified UserId) (Map ClientId a)
134+
-- TODO: add historyClients
114135
}
115136
deriving (Show, Eq, Functor)
116137

libs/wire-subsystems/src/Wire/ConversationStore/Migration.hs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ deleteConvFromCassandra allConvData = withCassandra $ do
237237
Nothing -> deleteConversation allConvData.conv.id_
238238
Just tid -> deleteTeamConversation tid allConvData.conv.id_
239239

240+
-- TODO: (leif) migrate history client data
240241
saveConvToPostgres :: (PGConstraints r) => AllConvData -> Sem r ()
241242
saveConvToPostgres allConvData = do
242243
let meta = storedConv.metadata
@@ -384,11 +385,12 @@ saveConvToPostgres allConvData = do
384385

385386
mlsClientRows :: GroupId -> ClientMap LeafIndex -> IndexMap -> [(GroupId, Domain, UserId, ClientId, Int32, Bool)]
386387
mlsClientRows gid clientMap indexMap =
387-
let clients :: [(LeafIndex, ClientIdentity, Bool)] =
388-
IntMap.elems $
389-
IntMap.mapWithKey
390-
(\idx ci -> (fromIntegral idx, ci, isNothing (cmLookupIndex ci clientMap)))
391-
indexMap.unIndexMap
388+
let clients :: [(LeafIndex, ClientIdentity, Bool)] = do
389+
(idx, element) <- IntMap.assocs indexMap.unIndexMap
390+
case element of
391+
RegularClient ci ->
392+
pure (fromIntegral idx, ci, isNothing (cmLookupIndex ci clientMap))
393+
HistoryClient _ -> []
392394
in flip map clients $ \(idx, ci, removalPending) ->
393395
(gid, ci.ciDomain, ci.ciUser, ci.ciClient, fromIntegral idx, removalPending)
394396

libs/wire-subsystems/src/Wire/ConversationStore/Postgres.hs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,10 +1065,19 @@ selectMLSClients =
10651065
WHERE group_id = ($1 :: bytea)
10661066
|]
10671067

1068+
selectHistoryClients :: Hasql.Statement GroupId [(HistoryClientId, Int32, Bool)]
1069+
selectHistoryClients =
1070+
dimapPG
1071+
[vectorStatement|SELECT (id :: uuid), (leaf_node_index :: integer), (removal_pending :: bool)
1072+
FROM mls_history_client
1073+
WHERE group_id = ($1 :: bytea)
1074+
|]
1075+
10681076
lookupMLSClientLeafIndicesImpl :: (PGConstraints r) => GroupId -> Sem r (ClientMap LeafIndex, IndexMap)
10691077
lookupMLSClientLeafIndicesImpl gid = do
1070-
rows <- runStatement gid selectMLSClients
1071-
pure (mkClientMap rows, mkIndexMap rows)
1078+
rows1 <- runStatement gid selectMLSClients
1079+
rows2 <- runStatement gid selectHistoryClients
1080+
pure (mkClientMap rows1, mkIndexMapFromParts rows1 rows2)
10721081

10731082
-- SUB CONVERSATION OPERATIONS
10741083
createSubConversationImpl :: (PGConstraints r) => ConvId -> SubConvId -> GroupId -> Sem r SubConversation

0 commit comments

Comments
 (0)