remove proof from cards, send owner public key for channel to relay

This commit is contained in:
Evgeny @ SimpleX Chat
2026-09-27 17:00:16 +00:00
parent 867949d2aa
commit 4bdeb68cc5
16 changed files with 155 additions and 233 deletions
+6 -5
View File
@@ -1249,8 +1249,8 @@ processChatCommand cxt nm = \case
ownerSig <-
withAgent (`getConnLinkPrivKey` aConnId conn) $>>= \privKey ->
mkLinkOwnerSig privKey connLink Nothing <$$> shareChatBinding user toSendRef
profile <- presentUserBadge user Nothing (Just $ linkPresHeader connLink) $ userProfileDirect user Nothing Nothing True
let business = businessAddress addressSettings
profile = userProfileDirect user Nothing Nothing True
text = safeDecodeUtf8 $ strEncode connLink
pure $ CRChatMsgContent user MCChat {text, chatLink = MCLContact {connLink, profile, business}, ownerSig}
APIUserRead userId -> withUserId userId $ \user -> withFastStore' (`setUserChatsRead` user) >> ok user
@@ -2197,7 +2197,7 @@ processChatCommand cxt nm = \case
createItem sharedMsgId content = createChatItem user cd True content sharedMsgId Nothing Nothing
cInfo = GroupChat gInfo Nothing
void $ createGroupFeatureItems_ user cd True CIRcvGroupFeature gInfo
aci <- mapM (createItem welcomeSharedMsgId . CIRcvMsgContent <=< chatLinkBadge) message
aci <- mapM (createItem welcomeSharedMsgId . CIRcvMsgContent) message
let chat = case aci of
Just (AChatItem SCTGroup dir _ ci) -> Chat cInfo [CChatItem dir ci] emptyChatStats {unreadCount = 1, minUnreadItemId = chatItemId' ci}
_ -> Chat cInfo [] emptyChatStats
@@ -2210,7 +2210,7 @@ processChatCommand cxt nm = \case
cInfo = DirectChat ct
void $ createItem Nothing $ CIRcvDirectE2EEInfo $ e2eInfoEncrypted $ connRequestPQEncryption cReq
void $ createFeatureEnabledItems_ user ct
aci <- mapM (createItem welcomeSharedMsgId . CIRcvMsgContent <=< chatLinkBadge) message
aci <- mapM (createItem welcomeSharedMsgId . CIRcvMsgContent) message
let chat = case aci of
Just (AChatItem SCTDirect dir _ ci) -> Chat cInfo [CChatItem dir ci] emptyChatStats {unreadCount = 1, minUnreadItemId = chatItemId' ci}
_ -> Chat cInfo [] emptyChatStats
@@ -4324,7 +4324,7 @@ processChatCommand cxt nm = \case
groupRelay <- createGroupRelayRecord db gInfo relayMember relay
conn <- createRelayConnection db cxt user (groupMemberId' relayMember) connId ConnPrepared chatV subMode
pure (relayMember, conn, groupRelay)
let GroupMember {memberRole = userRole, memberId = userMemberId} = membership
let GroupMember {memberRole = userRole, memberId = userMemberId, memberPubKey = userMemberKey} = membership
GroupMember {memberId = relayMemberId} = relayMember
membershipProfile <- presentUserBadge user (incognitoMembershipProfile gInfo) (groupPresHeader gInfo) $ redactedMemberProfile gInfo membership $ fromLocalProfile $ memberProfile membership
let relayInv = GroupRelayInvitation {
@@ -4332,7 +4332,8 @@ processChatCommand cxt nm = \case
fromMemberProfile = membershipProfile,
relayMemberId,
groupLink = groupSLink,
publicGroupId = (\PublicGroupProfile {publicGroupId = gId} -> gId) <$> publicGroup' gInfo
publicGroupId = (\PublicGroupProfile {publicGroupId = gId} -> gId) <$> publicGroup' gInfo,
fromMemberKey = MemberKey <$> userMemberKey
}
dm <- encodeConnInfo $ XGrpRelayInv relayInv
sqSecured <- withAgent $ \a -> joinConnection a nm (aUserId user) (aConnId conn) True cReq dm PQSupportOff subMode
+12 -21
View File
@@ -1338,7 +1338,7 @@ memberInfo g m@GroupMember {memberId, memberRole, memberProfile, memberPubKey, a
{ memberId,
memberRole,
v = ChatVersionRange . peerChatVRange <$> activeConn,
profile = (p :: Profile) {badge = mfilter (acceptedProof $ memberPresHeader g memberId memberPubKey) (unNoJSON memberBadgeProof <|> badge)},
profile = (p :: Profile) {badge = mfilter (acceptedProof $ publicGroup' g *> memberPresHeader g memberId memberPubKey) (unNoJSON memberBadgeProof <|> badge)},
memberKey = MemberKey <$> memberPubKey
}
where
@@ -2255,7 +2255,7 @@ presentsUserBadge User {profile = LocalProfile {localBadge}} = case localBadge o
_ -> False
groupPresHeader :: GroupInfo -> Maybe ProofPresHeader
groupPresHeader gInfo = PHChat <$> sndGroupChatBinding gInfo False
groupPresHeader gInfo@GroupInfo {membership = GroupMember {memberId, memberPubKey}} = memberPresHeader gInfo memberId memberPubKey
directPresHeader :: ContactRequestBinding -> ProofPresHeader
directPresHeader = \case
@@ -2268,8 +2268,8 @@ linkPresHeader = \case
CSLContact _ _ _ (LinkKey key) -> PHLink key
relayInvPresHeader :: GroupRelayInvitation -> Maybe ProofPresHeader
relayInvPresHeader GroupRelayInvitation {fromMember = MemberIdRole {memberId}, publicGroupId} =
(\gId -> PHChat $ encodeChatBinding CBGroup $ smpEncode (gId, memberId)) <$> publicGroupId
relayInvPresHeader GroupRelayInvitation {fromMember = MemberIdRole {memberId}, publicGroupId, fromMemberKey} =
(\gId (MemberKey k) -> PHChat $ encodeChatBinding CBGroup $ smpEncode (gId, memberId, k)) <$> publicGroupId <*> fromMemberKey
sndPresHeader :: Maybe ProofPresHeader -> CM ProofPresHeader
sndPresHeader = maybe (PHTest <$> drgRandomBytes 16) pure
@@ -2291,14 +2291,6 @@ linkDataBadge presHeader cld@ContactShortLinkData {profile = Profile {badge}} =
now <- liftIO getCurrentTime
pure (cld :: ContactShortLinkData) {localBadge = Just $ ShownBadge info (mkBadgeStatus now verified info)}
chatLinkBadge :: MsgContent -> CM MsgContent
chatLinkBadge = \case
MCChat {text, chatLink = chatLink@MCLContact {connLink, profile = p@Profile {badge = Just b@BadgeProof {presHeader = BBSPresHeader ph}}}, ownerSig} -> do
keys <- asks $ badgePublicKeys . config
verified <- if ph == strEncode (linkPresHeader connLink) then liftIO (verifyBadge keys b) else pure Nothing
pure MCChat {text, chatLink = if verified == Just True then chatLink else (chatLink :: MsgChatLink) {profile = (p :: Profile) {badge = Nothing}}, ownerSig}
c -> pure c
sendDirectContactMessage :: MsgEncodingI e => User -> Contact -> ChatMsgEvent e -> CM (SndMessage, Int64)
sendDirectContactMessage user ct chatMsgEvent = do
conn@Connection {connId} <- liftEither $ contactSendConn_ ct
@@ -2379,20 +2371,19 @@ rcvGroupChatBinding gInfo m_ asGroup badge_ =
case (publicGroup' gInfo, asGroup, m_) of
(Just PublicGroupProfile {publicGroupId}, True, _) ->
Just $ encodeChatBinding CBChannel $ smpEncode publicGroupId
(_, False, Just GroupMember {memberId, memberPubKey}) ->
memberChatBinding gInfo memberId (memberPubKey <|> proofMemberKey memberId badge_)
(Just PublicGroupProfile {publicGroupId}, False, Just GroupMember {memberId}) ->
Just $ encodeChatBinding CBGroup $ smpEncode (publicGroupId, memberId)
(Nothing, False, Just GroupMember {memberId, memberPubKey}) ->
(\k -> encodeChatBinding CBGroup $ smpEncode (memberId, k)) <$> (memberPubKey <|> proofMemberKey memberId badge_)
_ -> Nothing
memberChatBinding :: GroupInfo -> MemberId -> Maybe C.PublicKeyEd25519 -> Maybe ByteString
memberChatBinding gInfo memberId key_ = case publicGroup' gInfo of
Just PublicGroupProfile {publicGroupId} -> Just $ encodeChatBinding CBGroup $ smpEncode (publicGroupId, memberId)
Nothing -> (\k -> encodeChatBinding CBGroup $ smpEncode (memberId, k)) <$> key_
memberPresHeader :: GroupInfo -> MemberId -> Maybe C.PublicKeyEd25519 -> Maybe ProofPresHeader
memberPresHeader gInfo memberId = fmap PHChat . memberChatBinding gInfo memberId
memberPresHeader gInfo memberId = fmap $ \k -> PHChat $ encodeChatBinding CBGroup $ case publicGroup' gInfo of
Just PublicGroupProfile {publicGroupId} -> smpEncode (publicGroupId, memberId, k)
Nothing -> smpEncode (memberId, k)
memberInfoPresHeader :: GroupInfo -> MemberInfo -> Maybe ProofPresHeader
memberInfoPresHeader gInfo MemberInfo {memberId, memberKey} = memberPresHeader gInfo memberId ((\(MemberKey k) -> k) <$> memberKey)
memberInfoPresHeader gInfo MemberInfo {memberId, memberKey} = publicGroup' gInfo *> memberPresHeader gInfo memberId ((\(MemberKey k) -> k) <$> memberKey)
proofMemberKey :: MemberId -> Maybe BadgeProof -> Maybe C.PublicKeyEd25519
proofMemberKey memberId badge_ = do
+22 -21
View File
@@ -579,7 +579,7 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
case event of
XMsgNew mc -> newContentMessage ct'' mc msg msgMeta
XMsgFileDescr sharedMsgId fileDescr fileExpires fileBadge -> messageFileDescription ct'' sharedMsgId fileDescr fileExpires fileBadge
XMsgUpdate sharedMsgId mContent _ ttl live _msgScope _ -> chatLinkBadge mContent >>= \mc -> messageUpdate ct'' sharedMsgId mc msg msgMeta ttl live
XMsgUpdate sharedMsgId mContent _ ttl live _msgScope _ -> messageUpdate ct'' sharedMsgId mContent msg msgMeta ttl live
XMsgDel sharedMsgId _ _ _ -> messageDelete ct'' sharedMsgId msg msgMeta
XMsgReact sharedMsgId _ _ reaction add -> directMsgReaction ct'' sharedMsgId reaction add msg msgMeta
-- TODO discontinue XFile
@@ -1081,7 +1081,7 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
XMsgUpdate sharedMsgId mContent mentions ttl live msgScope asGroup_ ->
checkSendAsGroup asGroup_ $
memberCanSend (Just m'') msgScope $
chatLinkBadge mContent >>= \mc -> groupMessageUpdate gInfo' (Just m'') sharedMsgId mc mentions msgScope msg brokerTs ttl live asGroup_
groupMessageUpdate gInfo' (Just m'') sharedMsgId mContent mentions msgScope msg brokerTs ttl live asGroup_
XMsgDel sharedMsgId memberId_ scope_ onlyHistory ->
groupMessageDelete gInfo' (Just m'') sharedMsgId memberId_ scope_ onlyHistory msg brokerTs
XMsgReact sharedMsgId memberId scope_ reaction add -> groupMsgReaction gInfo' m'' sharedMsgId memberId scope_ reaction add msg brokerTs
@@ -1405,7 +1405,7 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
(signedMsg_, ChatMessage {chatVRange, chatMsgEvent}) <- parseChatMessage' conn connInfo
let reqHeader = directPresHeader binding
case chatMsgEvent of
XContact p memberKey_ xContactId_ welcomeMsgId_ requestMsg_ -> mapM (traverse chatLinkBadge) requestMsg_ >>= \requestMsg' -> profileContactRequest invId chatVRange reqHeader p memberKey_ xContactId_ welcomeMsgId_ requestMsg' pqSupport rejectionSupported
XContact p memberKey_ xContactId_ welcomeMsgId_ requestMsg_ -> profileContactRequest invId chatVRange reqHeader p memberKey_ xContactId_ welcomeMsgId_ requestMsg_ pqSupport rejectionSupported
XMember p joiningMemberId joiningMemberKey viaRelay -> memberJoinRequestViaRelay invId chatVRange signedMsg_ p joiningMemberId joiningMemberKey viaRelay
XInfo p _ -> profileContactRequest invId chatVRange reqHeader p Nothing Nothing Nothing Nothing pqSupport rejectionSupported
XGrpRelayInv groupRelayInv -> xGrpRelayInv invId chatVRange groupRelayInv
@@ -1701,7 +1701,8 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
&& viaRelay == Just (memberId' (membership gInfo))
_ -> False
acceptJoin g@(GIK gInfo _) existingMem_ acceptRole = do
mem <- acceptGroupJoinRequestAsync user uclId g invId chatVRange p (memberPresHeader gInfo joiningMemberId Nothing) Nothing (Just joiningMemberId) Nothing GAAccepted acceptRole Nothing (Just joiningMemberKey) existingMem_
let presHeader_ = memberPresHeader gInfo joiningMemberId $ mfilter (\k -> memberSigned gInfo joiningMemberId k signedMsg_) (Just joiningKey)
mem <- acceptGroupJoinRequestAsync user uclId g invId chatVRange p presHeader_ Nothing (Just joiningMemberId) Nothing GAAccepted acceptRole Nothing (Just joiningMemberKey) existingMem_
(gInfo', mem', scopeInfo) <- mkGroupChatScope gInfo mem
createInternalChatItem user (CDGroupRcv gInfo' scopeInfo mem') (CIRcvGroupEvent RGEInvitedViaGroupLink) Nothing
toView $ CEvtAcceptingGroupJoinRequestMember user gInfo' mem'
@@ -1915,7 +1916,7 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
newContentMessage :: Contact -> MsgContainer -> RcvMessage -> MsgMeta -> CM ()
newContentMessage ct mc msg@RcvMessage {sharedMsgId_} msgMeta = do
let MsgContainer {content = c, file = fInv_} = mc
content <- chatLinkBadge =<< case c of
content <- case c of
MCChat {text, chatLink, ownerSig = Just LinkOwnerSig {chatBinding = B64UrlByteString binding}} -> do
keepSig <- case contactConn ct of
Nothing -> pure False
@@ -2265,12 +2266,10 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
-- m' is Maybe GroupMember
createNonLive gInfo' m' scopeInfo file_ = do
let mentions' = if maybe False memberBlocked m' then M.empty else mentions
content' <- chatLinkBadge content
saveRcvCI gInfo' m' scopeInfo (CIRcvMsgContent content', ts) (snd <$> file_) (timed_ gInfo') False mentions'
saveRcvCI gInfo' m' scopeInfo (CIRcvMsgContent content, ts) (snd <$> file_) (timed_ gInfo') False mentions'
createContentItem gInfo' m' scopeInfo = do
file_ <- processFileInv gInfo' m'
content' <- chatLinkBadge content
newChatItem gInfo' m' scopeInfo (CIRcvMsgContent content', ts) (snd <$> file_) (timed_ gInfo') live'
newChatItem gInfo' m' scopeInfo (CIRcvMsgContent content, ts) (snd <$> file_) (timed_ gInfo') live'
unless (maybe False memberBlocked m') $ autoAcceptFile file_
processFileInv gInfo' m' =
let fileMember_ = if sentAsGroup then Nothing else m'
@@ -3954,7 +3953,7 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
(g', m'', scopeInfo) <- mkGroupChatScope g m'
createInternalChatItem user (CDGroupRcv g' scopeInfo m'') (CIRcvGroupEvent RGEMemberCreatedContact) Nothing
toView $ CEvtNewMemberContactReceivedInv user mCt' g' m''
forM_ mContent_ $ chatLinkBadge >=> \mc -> do
forM_ mContent_ $ \mc -> do
(ci, cInfo) <- saveRcvChatItem user (CDDirectRcv mCt') msg brokerTs (CIRcvMsgContent mc, msgContentTexts mc)
toView $ CEvtNewChatItems user [AChatItem SCTDirect SMDRcv cInfo ci]
@@ -4002,7 +4001,7 @@ processAgentMessageConn cxt user@User {userId} entity gks_ corrId agentConnId ag
-- file description is always allowed, to allow sending files to support scope
XMsgFileDescr sharedMsgId fileDescr fileExpires fileBadge -> void $ groupMessageFileDescription gInfo author_ sharedMsgId fileDescr fileExpires fileBadge
XMsgUpdate sharedMsgId mContent mentions ttl live msgScope asGroup_ ->
void $ memberCanSend author_ msgScope $ chatLinkBadge mContent >>= \mc -> groupMessageUpdate gInfo author_ sharedMsgId mc mentions msgScope rcvMsg msgTs ttl live asGroup_
void $ memberCanSend author_ msgScope $ groupMessageUpdate gInfo author_ sharedMsgId mContent mentions msgScope rcvMsg msgTs ttl live asGroup_
XMsgDel sharedMsgId memId scope_ _ -> void $ groupMessageDelete gInfo author_ sharedMsgId memId scope_ False rcvMsg msgTs
XMsgReact sharedMsgId memId scope_ reaction add -> withAuthor XMsgReact_ $ \author -> void $ groupMsgReaction gInfo author sharedMsgId memId scope_ reaction add rcvMsg msgTs
XFileCancel sharedMsgId -> void $ xFileCancelGroup gInfo author_ sharedMsgId
@@ -4523,22 +4522,23 @@ runRelayRequestWorker a Worker {doWork} = do
eToView e
processRelayRequest :: GroupId -> RelayRequestData -> CM ()
processRelayRequest groupId rrd = do
(g@(GIK gInfo _), groupLink_) <- withStore $ \db -> do
(g@(GIK gInfo _), groupLink_, ownerMember) <- withStore $ \db -> do
g@(GIK gInfo _) <- getGroupInfoKeys db cxt user groupId
groupLink_ <- liftIO $ runExceptT $ getGroupLink db user gInfo
pure (g, groupLink_)
ownerMember <- getHostMember db cxt user groupId
pure (g, groupLink_, ownerMember)
-- Check if relay link already exists (recovery case)
case groupLink_ of
Right GroupLink {connLinkContact = CCLink _ sLnk_} ->
case sLnk_ of
Just sLnk -> acceptOwnerConnection rrd gInfo sLnk
Just sLnk -> acceptOwnerConnection rrd gInfo ownerMember sLnk
Nothing -> throwChatError $ CEException "processRelayRequest: relay link doesn't have short link"
Left _ -> do
(gInfo', sLnk) <- getLinkDataCreateRelayLink rrd g
acceptOwnerConnection rrd gInfo' sLnk
(gInfo', sLnk) <- getLinkDataCreateRelayLink rrd g ownerMember
acceptOwnerConnection rrd gInfo' ownerMember sLnk
where
getLinkDataCreateRelayLink :: RelayRequestData -> GroupInfoKeys -> CM (GroupInfo, ShortLinkContact)
getLinkDataCreateRelayLink RelayRequestData {reqGroupLink} (GIK gInfo gks) = do
getLinkDataCreateRelayLink :: RelayRequestData -> GroupInfoKeys -> GroupMember -> CM (GroupInfo, ShortLinkContact)
getLinkDataCreateRelayLink RelayRequestData {reqGroupLink} (GIK gInfo gks) GroupMember {memberId = MemberId ownerMemberId, memberPubKey = claimedOwnerKey_} = do
(memberPrivKey', claimedGroupId_) <- case gks of
GKRelayRequest {memberPrivKey, publicGroupId} -> pure (memberPrivKey, publicGroupId)
_ -> throwChatError $ CEException "getLinkDataCreateRelayLink: group is not a relay request"
@@ -4550,6 +4550,8 @@ runRelayRequestWorker a Worker {doWork} = do
(Just entityId, Just pg@PublicGroupProfile {publicGroupId})
| B64UrlByteString entityId == publicGroupId && all (== publicGroupId) claimedGroupId_ -> pure pg
_ -> throwChatError $ CEException "getLinkDataCreateRelayLink: linkEntityId does not match publicGroupId of profile or invitation"
unless (all (\k -> any (\OwnerAuth {ownerId, ownerKey} -> ownerId == ownerMemberId && ownerKey == k) owners) claimedOwnerKey_) $
throwChatError $ CEException "getLinkDataCreateRelayLink: owner key of invitation does not match link data"
validateGroupProfile gp
sLnk <- createRelayLink gInfo (C.publicKey memberPrivKey', memberPrivKey')
gInfo' <- withStore $ \db -> do
@@ -4584,7 +4586,6 @@ runRelayRequestWorker a Worker {doWork} = do
subRole <- asks $ channelSubscriberRole . config
void $ withFastStore $ \db -> createGroupLink db gVar user gi connId ccLink' groupLinkId subRole subMode
pure sLnk
acceptOwnerConnection :: RelayRequestData -> GroupInfo -> ShortLinkContact -> CM ()
acceptOwnerConnection RelayRequestData {relayInvId, reqChatVRange} gi relayLink = do
ownerMember <- withStore $ \db -> getHostMember db cxt user groupId
acceptOwnerConnection :: RelayRequestData -> GroupInfo -> GroupMember -> ShortLinkContact -> CM ()
acceptOwnerConnection RelayRequestData {relayInvId, reqChatVRange} gi ownerMember relayLink =
void $ acceptRelayJoinRequestAsync user uclId gi ownerMember relayInvId reqChatVRange relayLink
+4 -4
View File
@@ -1898,7 +1898,7 @@ setGroupInProgressDone db GroupInfo {groupId} = do
(currentTs, groupId)
createRelayRequestGroup :: DB.Connection -> StoreCxt -> User -> GroupRelayInvitation -> Maybe ProofPresHeader -> InvitationId -> VersionRangeChat -> Int64 -> GroupMemberStatus -> RelayStatus -> ExceptT StoreError IO (GroupInfo, GroupMember)
createRelayRequestGroup db cxt user@User {userId} GroupRelayInvitation {fromMember, fromMemberProfile, relayMemberId, groupLink, publicGroupId} presHeader_ invId reqChatVRange initialDelay memberStatus relayStatus = do
createRelayRequestGroup db cxt user@User {userId} GroupRelayInvitation {fromMember, fromMemberProfile, relayMemberId, groupLink, publicGroupId, fromMemberKey} presHeader_ invId reqChatVRange initialDelay memberStatus relayStatus = do
currentTs <- liftIO getCurrentTime
-- Create group with placeholder profile
let Profile {displayName = fromMemberLDN} = fromMemberProfile
@@ -1954,12 +1954,12 @@ createRelayRequestGroup db cxt user@User {userId} GroupRelayInvitation {fromMemb
INSERT INTO group_members
( group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector,
user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at,
peer_chat_min_version, peer_chat_max_version)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
peer_chat_min_version, peer_chat_max_version, member_pub_key)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|]
( (groupId, indexInGroup, memberId, memberRole, GCHostMember, memberStatus, Binary B.empty)
:. (userId, localDisplayName, Nothing :: (Maybe Int64), profileId, currentTs, currentTs)
:. (minV, maxV)
:. (minV, maxV, (\(MemberKey k) -> k) <$> fromMemberKey)
)
ownerMemberId <- insertedRowId db
forM_ badge $ createMemberBadgeProof db ownerMemberId
@@ -592,8 +592,8 @@ Query:
INSERT INTO group_members
( group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector,
user_id, local_display_name, contact_id, contact_profile_id, created_at, updated_at,
peer_chat_min_version, peer_chat_max_version)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
peer_chat_min_version, peer_chat_max_version, member_pub_key)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
Plan:
SEARCH file_badge_proofs USING COVERING INDEX idx_file_badge_proofs_group_member_id (group_member_id=?)
+2 -1
View File
@@ -1007,7 +1007,8 @@ data GroupRelayInvitation = GroupRelayInvitation
fromMemberProfile :: Profile,
relayMemberId :: MemberId,
groupLink :: ShortLinkContact,
publicGroupId :: Maybe B64UrlByteString
publicGroupId :: Maybe B64UrlByteString,
fromMemberKey :: Maybe MemberKey
}
deriving (Eq, Show)