mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-23 10:43:05 +00:00
core: chat relays announce new members to owners (with keys); forward x.grp.mem.restrict; sign and verify x.grp.leave and x.info (member profile update) (#6690)
This commit is contained in:
1 parent
74fe5340f7
commit
b38fc62281
15 files changed
+579
-293
No files matched your search
@@ -179,7 +179,7 @@ createConnReqConnection db userId acId preparedEntity_ cReq cReqHash sLnk xConta
|
||||
)
|
||||
connId <- insertedRowId db
|
||||
case preparedEntity_ of
|
||||
-- For relay groups, setPreparedGroupLinkInfo is called before the relay loop
|
||||
-- For relay groups, setPreparedGroupLinkInfo_ is called via updatePreparedRelayedGroup before the relay loop
|
||||
Just (PCEGroup gInfo _) | not (useRelays' gInfo) ->
|
||||
setPreparedGroupLinkInfo_ db gInfo cReq cReqHash customUserProfileId currentTs
|
||||
_ -> pure ()
|
||||
|
||||
@@ -100,6 +100,7 @@ module Simplex.Chat.Store.Groups
|
||||
getMemberInvitation,
|
||||
createMemberConnection,
|
||||
createMemberConnectionAsync,
|
||||
updatePreparedRelayedGroup,
|
||||
updateGroupMemberKeys,
|
||||
updateRelayGroupKeys,
|
||||
updateGroupMemberStatus,
|
||||
@@ -151,7 +152,7 @@ module Simplex.Chat.Store.Groups
|
||||
setXGrpLinkMemReceived,
|
||||
createNewUnknownGroupMember,
|
||||
createLinkOwnerMember,
|
||||
updateIntroducedMember,
|
||||
updatePreparedChannelMember,
|
||||
updateUnknownMemberAnnounced,
|
||||
updateUserMemberProfileSentAt,
|
||||
setGroupCustomData,
|
||||
@@ -1090,14 +1091,16 @@ getGroupMemberByMemberId db vr user GroupInfo {groupId} memberId =
|
||||
(groupMemberQuery <> " WHERE m.group_id = ? AND m.member_id = ?")
|
||||
(groupId, memberId)
|
||||
|
||||
getCreateUnknownGMByMemberId :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> MemberId -> ContactName -> GroupMemberRole -> ExceptT StoreError IO (GroupMember, Bool)
|
||||
getCreateUnknownGMByMemberId db vr user gInfo memberId memberName unknownMemberRole = do
|
||||
getCreateUnknownGMByMemberId :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> MemberId -> ContactName -> GroupMemberRole -> Bool -> ExceptT StoreError IO (Maybe (GroupMember, Bool))
|
||||
getCreateUnknownGMByMemberId db vr user gInfo memberId memberName unknownMemberRole allowCreate = do
|
||||
liftIO (runExceptT $ getGroupMemberByMemberId db vr user gInfo memberId) >>= \case
|
||||
Right m -> pure (m, False)
|
||||
Left (SEGroupMemberNotFoundByMemberId _) -> do
|
||||
let name = if T.null memberName then nameFromMemberId memberId else memberName
|
||||
m <- createNewUnknownGroupMember db vr user gInfo memberId name unknownMemberRole
|
||||
pure (m, True)
|
||||
Right m -> pure $ Just (m, False)
|
||||
Left (SEGroupMemberNotFoundByMemberId _)
|
||||
| allowCreate -> do
|
||||
let name = if T.null memberName then nameFromMemberId memberId else memberName
|
||||
m <- createNewUnknownGroupMember db vr user gInfo memberId name unknownMemberRole
|
||||
pure $ Just (m, True)
|
||||
| otherwise -> pure Nothing
|
||||
Left e -> throwError e
|
||||
|
||||
getScopeMemberIdViaMemberId :: DB.Connection -> User -> GroupInfo -> GroupMember -> MemberId -> ExceptT StoreError IO GroupMemberId
|
||||
@@ -1522,7 +1525,7 @@ createNewContactMemberAsync db gVar user@User {userId, userContactId} GroupInfo
|
||||
:. (minV, maxV)
|
||||
)
|
||||
|
||||
createJoiningMember :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> VersionRangeChat -> Profile -> Maybe XContactId -> Maybe MemberId -> Maybe SharedMsgId -> GroupMemberRole -> GroupMemberStatus -> ExceptT StoreError IO (GroupMemberId, MemberId)
|
||||
createJoiningMember :: DB.Connection -> TVar ChaChaDRG -> User -> GroupInfo -> VersionRangeChat -> Profile -> Maybe XContactId -> Maybe MemberId -> Maybe SharedMsgId -> GroupMemberRole -> GroupMemberStatus -> Maybe MemberKey -> ExceptT StoreError IO (GroupMemberId, MemberId)
|
||||
createJoiningMember
|
||||
db
|
||||
gVar
|
||||
@@ -1534,7 +1537,8 @@ createJoiningMember
|
||||
cReqMemberId_
|
||||
welcomeMsgId_
|
||||
memberRole
|
||||
memberStatus = do
|
||||
memberStatus
|
||||
memberKey_ = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
ExceptT . withLocalDisplayName db userId displayName $ \ldn -> runExceptT $ do
|
||||
liftIO $
|
||||
@@ -1561,6 +1565,7 @@ createJoiningMember
|
||||
checkMemberNotExists memberId = do
|
||||
exists <- liftIO $ fromOnly . head <$> DB.query db "SELECT EXISTS (SELECT 1 FROM group_members WHERE group_id = ? AND member_id = ?)" (groupId, memberId)
|
||||
when exists $ throwError SEDuplicateMemberId
|
||||
memberPubKey_ = (\(MemberKey k) -> k) <$> memberKey_
|
||||
insertMember_ ldn profileId memberId currentTs = do
|
||||
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
|
||||
liftIO $
|
||||
@@ -1569,12 +1574,12 @@ createJoiningMember
|
||||
[sql|
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector, invited_by, invited_by_group_member_id,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, member_xcontact_id, member_welcome_shared_msg_id, created_at, updated_at,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, member_pub_key, member_xcontact_id, member_welcome_shared_msg_id, created_at, updated_at,
|
||||
peer_chat_min_version, peer_chat_max_version)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
( (groupId, indexInGroup, memberId, memberRole, GCInviteeMember, memberStatus, Binary B.empty, fromInvitedBy userContactId IBUser, groupMemberId' membership)
|
||||
:. (userId, ldn, Nothing :: (Maybe Int64), profileId, cReqXContactId_, welcomeMsgId_, currentTs, currentTs)
|
||||
:. (userId, ldn, Nothing :: (Maybe Int64), profileId, memberPubKey_, cReqXContactId_, welcomeMsgId_, currentTs, currentTs)
|
||||
:. (minV, maxV)
|
||||
)
|
||||
|
||||
@@ -1698,13 +1703,27 @@ createMemberConnectionAsync db user@User {userId} groupMemberId (cmdId, agentCon
|
||||
Connection {connId} <- createMemberConnection_ db userId groupMemberId agentConnId chatV peerChatVRange Nothing 0 currentTs subMode
|
||||
setCommandConnId db user cmdId connId
|
||||
|
||||
updateGroupMemberKeys :: DB.Connection -> GroupId -> ByteString -> C.PublicKeyEd25519 -> C.PrivateKeyEd25519 -> GroupMemberId -> IO ()
|
||||
updateGroupMemberKeys db groupId sharedGroupId rootPubKey memberPrivKey membershipGMId = do
|
||||
-- Set group link info, incognito profile, membership keys before connecting to relays.
|
||||
-- This is called once before connecting to relays, unlike createConnReqConnection -> setPreparedGroupLinkInfo_,
|
||||
-- which is used in single-connection flows.
|
||||
updatePreparedRelayedGroup ::
|
||||
DB.Connection -> VersionRangeChat -> User -> GroupInfo -> ConnReqContact -> ConnReqUriHash -> Maybe Profile ->
|
||||
Maybe ByteString -> C.PublicKeyEd25519 -> C.PrivateKeyEd25519 ->
|
||||
ExceptT StoreError IO GroupInfo
|
||||
updatePreparedRelayedGroup db vr user@User {userId} gInfo cReq cReqHash incognitoProfile linkEntityId rootPubKey memberPrivKey = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
customUserProfileId <- liftIO $ mapM (createIncognitoProfile_ db userId currentTs) incognitoProfile
|
||||
liftIO $ setPreparedGroupLinkInfo_ db gInfo cReq cReqHash customUserProfileId currentTs
|
||||
liftIO $ updateGroupMemberKeys db (groupId' gInfo) linkEntityId rootPubKey memberPrivKey (groupMemberId' $ membership gInfo)
|
||||
getGroupInfo db vr user (groupId' gInfo)
|
||||
|
||||
updateGroupMemberKeys :: DB.Connection -> GroupId -> Maybe ByteString -> C.PublicKeyEd25519 -> C.PrivateKeyEd25519 -> GroupMemberId -> IO ()
|
||||
updateGroupMemberKeys db groupId linkEntityId rootPubKey memberPrivKey membershipGMId = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE groups SET shared_group_id = ?, root_pub_key = ?, member_priv_key = ?, updated_at = ? WHERE group_id = ?"
|
||||
(Binary sharedGroupId, rootPubKey, memberPrivKey, currentTs, groupId)
|
||||
(Binary <$> linkEntityId, rootPubKey, memberPrivKey, currentTs, groupId)
|
||||
DB.execute
|
||||
db
|
||||
"UPDATE group_members SET member_pub_key = ?, updated_at = ? WHERE group_member_id = ?"
|
||||
@@ -2851,8 +2870,11 @@ createLinkOwnerMember db vr user@User {userId, userContactId} GroupInfo {groupId
|
||||
where
|
||||
VersionRange minV maxV = vr
|
||||
|
||||
updateIntroducedMember :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> MemberInfo -> ExceptT StoreError IO GroupMember
|
||||
updateIntroducedMember db vr user@User {userId} member@GroupMember {groupMemberId, memberChatVRange} MemberInfo {memberRole, v, profile} = do
|
||||
-- member_pub_key is not updated here — introduced members are owners
|
||||
-- whose keys are loaded from link data (trusted out-of-band).
|
||||
-- Updating from an in-band message would allow a compromised relay to substitute keys.
|
||||
updatePreparedChannelMember :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> MemberInfo -> ExceptT StoreError IO GroupMember
|
||||
updatePreparedChannelMember db vr user@User {userId} member@GroupMember {groupMemberId, memberChatVRange} MemberInfo {memberRole, v, profile} = do
|
||||
_ <- updateMemberProfile db user member profile
|
||||
currentTs <- liftIO getCurrentTime
|
||||
liftIO $
|
||||
@@ -2873,7 +2895,7 @@ updateIntroducedMember db vr user@User {userId} member@GroupMember {groupMemberI
|
||||
VersionRange minV maxV = maybe memberChatVRange fromChatVRange v
|
||||
|
||||
updateUnknownMemberAnnounced :: DB.Connection -> VersionRangeChat -> User -> GroupMember -> GroupMember -> MemberInfo -> GroupMemberStatus -> ExceptT StoreError IO GroupMember
|
||||
updateUnknownMemberAnnounced db vr user@User {userId} invitingMember unknownMember@GroupMember {groupMemberId, memberChatVRange} MemberInfo {memberRole, v, profile} status = do
|
||||
updateUnknownMemberAnnounced db vr user@User {userId} invitingMember unknownMember@GroupMember {groupMemberId, memberChatVRange} MemberInfo {memberRole, v, profile, memberKey} status = do
|
||||
_ <- updateMemberProfile db user unknownMember profile
|
||||
currentTs <- liftIO getCurrentTime
|
||||
liftIO $
|
||||
@@ -2887,15 +2909,17 @@ updateUnknownMemberAnnounced db vr user@User {userId} invitingMember unknownMemb
|
||||
invited_by_group_member_id = ?,
|
||||
peer_chat_min_version = ?,
|
||||
peer_chat_max_version = ?,
|
||||
member_pub_key = ?,
|
||||
updated_at = ?
|
||||
WHERE user_id = ? AND group_member_id = ?
|
||||
|]
|
||||
( (memberRole, GCPostMember, status, groupMemberId' invitingMember)
|
||||
:. (minV, maxV, currentTs, userId, groupMemberId)
|
||||
:. (minV, maxV, memberPubKey_, currentTs, userId, groupMemberId)
|
||||
)
|
||||
getGroupMemberById db vr user groupMemberId
|
||||
where
|
||||
VersionRange minV maxV = maybe memberChatVRange fromChatVRange v
|
||||
memberPubKey_ = (\(MemberKey k) -> k) <$> memberKey
|
||||
|
||||
updateUserMemberProfileSentAt :: DB.Connection -> User -> GroupInfo -> UTCTime -> IO ()
|
||||
updateUserMemberProfileSentAt db User {userId} GroupInfo {groupId} sentTs =
|
||||
|
||||
@@ -273,16 +273,6 @@ Query:
|
||||
Plan:
|
||||
SEARCH connections USING PRIMARY KEY (conn_id=?)
|
||||
|
||||
Query:
|
||||
SELECT user_id FROM users u
|
||||
WHERE u.deleted = ?
|
||||
AND NOT EXISTS (SELECT c.conn_id FROM connections c WHERE c.user_id = u.user_id)
|
||||
|
||||
Plan:
|
||||
SCAN u
|
||||
CORRELATED SCALAR SUBQUERY 1
|
||||
SEARCH c USING COVERING INDEX idx_connections_user (user_id=?)
|
||||
|
||||
Query:
|
||||
SELECT user_id FROM users u
|
||||
WHERE u.user_id = ?
|
||||
@@ -535,54 +525,6 @@ Query:
|
||||
Plan:
|
||||
SEARCH conn_confirmations USING COVERING INDEX idx_conn_confirmations_conn_id (conn_id=?)
|
||||
|
||||
Query:
|
||||
DELETE FROM encrypted_rcv_message_hashes
|
||||
WHERE encrypted_rcv_message_hash_id IN (
|
||||
SELECT encrypted_rcv_message_hash_id
|
||||
FROM encrypted_rcv_message_hashes
|
||||
WHERE created_at < ?
|
||||
ORDER BY created_at ASC
|
||||
LIMIT ?
|
||||
)
|
||||
|
||||
Plan:
|
||||
SEARCH encrypted_rcv_message_hashes USING INTEGER PRIMARY KEY (rowid=?)
|
||||
LIST SUBQUERY 1
|
||||
SEARCH encrypted_rcv_message_hashes USING COVERING INDEX idx_encrypted_rcv_message_hashes_created_at (created_at<?)
|
||||
|
||||
Query:
|
||||
DELETE FROM messages
|
||||
WHERE (conn_id, internal_id) IN (
|
||||
SELECT conn_id, internal_id
|
||||
FROM messages
|
||||
WHERE internal_ts < ? AND internal_snd_id IS NOT NULL
|
||||
ORDER BY internal_ts ASC
|
||||
LIMIT ?
|
||||
)
|
||||
|
||||
Plan:
|
||||
SEARCH messages USING COVERING INDEX idx_messages_conn_id (conn_id=? AND internal_id=?)
|
||||
LIST SUBQUERY 1
|
||||
SEARCH messages USING INDEX idx_messages_internal_ts (internal_ts<?)
|
||||
SEARCH snd_message_deliveries USING COVERING INDEX idx_snd_message_deliveries_conn_id_internal_id (conn_id=? AND internal_id=?)
|
||||
SEARCH snd_messages USING COVERING INDEX idx_snd_messages_conn_id_internal_id (conn_id=? AND internal_id=?)
|
||||
SEARCH rcv_messages USING COVERING INDEX idx_rcv_messages_conn_id_internal_id (conn_id=? AND internal_id=?)
|
||||
|
||||
Query:
|
||||
DELETE FROM processed_ratchet_key_hashes
|
||||
WHERE processed_ratchet_key_hash_id IN (
|
||||
SELECT processed_ratchet_key_hash_id
|
||||
FROM processed_ratchet_key_hashes
|
||||
WHERE created_at < ?
|
||||
ORDER BY created_at ASC
|
||||
LIMIT ?
|
||||
)
|
||||
|
||||
Plan:
|
||||
SEARCH processed_ratchet_key_hashes USING INTEGER PRIMARY KEY (rowid=?)
|
||||
LIST SUBQUERY 1
|
||||
SEARCH processed_ratchet_key_hashes USING COVERING INDEX idx_processed_ratchet_key_hashes_created_at (created_at<?)
|
||||
|
||||
Query:
|
||||
INSERT INTO connections
|
||||
(user_id, conn_id, conn_mode, smp_agent_version, enable_ntfs, pq_support, duplex_handshake) VALUES (?,?,?,?,?,?,?)
|
||||
@@ -707,30 +649,6 @@ Query:
|
||||
|
||||
Plan:
|
||||
|
||||
Query:
|
||||
SELECT rcv_file_id, rcv_file_entity_id, prefix_path
|
||||
FROM rcv_files
|
||||
WHERE created_at < ?
|
||||
|
||||
Plan:
|
||||
SCAN rcv_files
|
||||
|
||||
Query:
|
||||
SELECT rcv_file_id, rcv_file_entity_id, prefix_path
|
||||
FROM rcv_files
|
||||
WHERE deleted = 1
|
||||
|
||||
Plan:
|
||||
SCAN rcv_files
|
||||
|
||||
Query:
|
||||
SELECT rcv_file_id, rcv_file_entity_id, tmp_path
|
||||
FROM rcv_files
|
||||
WHERE status IN (?,?) AND tmp_path IS NOT NULL
|
||||
|
||||
Plan:
|
||||
SEARCH rcv_files USING INDEX idx_rcv_files_status_created_at (status=?)
|
||||
|
||||
Query:
|
||||
SELECT rcv_replica_id, rcv_replica_key
|
||||
FROM snd_file_chunk_replica_recipients
|
||||
@@ -739,30 +657,6 @@ Query:
|
||||
Plan:
|
||||
SEARCH snd_file_chunk_replica_recipients USING INDEX idx_snd_file_chunk_replica_recipients_snd_file_chunk_replica_id (snd_file_chunk_replica_id=?)
|
||||
|
||||
Query:
|
||||
SELECT snd_file_id, snd_file_entity_id, prefix_path
|
||||
FROM snd_files
|
||||
WHERE created_at < ?
|
||||
|
||||
Plan:
|
||||
SCAN snd_files
|
||||
|
||||
Query:
|
||||
SELECT snd_file_id, snd_file_entity_id, prefix_path
|
||||
FROM snd_files
|
||||
WHERE deleted = 1
|
||||
|
||||
Plan:
|
||||
SCAN snd_files
|
||||
|
||||
Query:
|
||||
SELECT snd_file_id, snd_file_entity_id, prefix_path
|
||||
FROM snd_files
|
||||
WHERE status IN (?,?) AND prefix_path IS NOT NULL
|
||||
|
||||
Plan:
|
||||
SEARCH snd_files USING INDEX idx_snd_files_status_created_at (status=?)
|
||||
|
||||
Query:
|
||||
UPDATE conn_confirmations
|
||||
SET accepted = 1,
|
||||
@@ -1054,10 +948,6 @@ SEARCH messages USING COVERING INDEX idx_messages_conn_id (conn_id=?)
|
||||
SEARCH snd_queues USING COVERING INDEX idx_snd_queue_id (conn_id=?)
|
||||
SEARCH rcv_queues USING COVERING INDEX idx_rcv_queue_id (conn_id=?)
|
||||
|
||||
Query: DELETE FROM deleted_snd_chunk_replicas WHERE created_at < ?
|
||||
Plan:
|
||||
SEARCH deleted_snd_chunk_replicas USING COVERING INDEX idx_deleted_snd_chunk_replicas_pending (created_at<?)
|
||||
|
||||
Query: DELETE FROM deleted_snd_chunk_replicas WHERE deleted_snd_chunk_replica_id = ?
|
||||
Plan:
|
||||
SEARCH deleted_snd_chunk_replicas USING INTEGER PRIMARY KEY (rowid=?)
|
||||
@@ -1077,10 +967,6 @@ Query: DELETE FROM ntf_subscriptions WHERE conn_id = ?
|
||||
Plan:
|
||||
SEARCH ntf_subscriptions USING PRIMARY KEY (conn_id=?)
|
||||
|
||||
Query: DELETE FROM ntf_tokens_to_delete WHERE created_at < ?
|
||||
Plan:
|
||||
SCAN ntf_tokens_to_delete
|
||||
|
||||
Query: DELETE FROM ratchets WHERE conn_id = ?
|
||||
Plan:
|
||||
SEARCH ratchets USING PRIMARY KEY (conn_id=?)
|
||||
@@ -1199,14 +1085,6 @@ Query: SELECT conn_id FROM connections WHERE deleted = 0
|
||||
Plan:
|
||||
SCAN connections
|
||||
|
||||
Query: SELECT conn_id FROM connections WHERE deleted = ?
|
||||
Plan:
|
||||
SCAN connections
|
||||
|
||||
Query: SELECT conn_id FROM connections WHERE deleted_at_wait_delivery IS NOT NULL
|
||||
Plan:
|
||||
SCAN connections
|
||||
|
||||
Query: SELECT conn_id FROM connections WHERE user_id = ?
|
||||
Plan:
|
||||
SEARCH connections USING COVERING INDEX idx_connections_user (user_id=?)
|
||||
|
||||
@@ -349,9 +349,9 @@ SEARCH contacts USING COVERING INDEX idx_contacts_contact_group_member_id (conta
|
||||
Query:
|
||||
INSERT INTO group_members
|
||||
( group_id, index_in_group, member_id, member_role, member_category, member_status, member_relations_vector, invited_by, invited_by_group_member_id,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, member_xcontact_id, member_welcome_shared_msg_id, created_at, updated_at,
|
||||
user_id, local_display_name, contact_id, contact_profile_id, member_pub_key, member_xcontact_id, member_welcome_shared_msg_id, created_at, updated_at,
|
||||
peer_chat_min_version, peer_chat_max_version)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
Plan:
|
||||
SEARCH group_relays USING COVERING INDEX idx_group_relays_group_member_id (group_member_id=?)
|
||||
@@ -6659,6 +6659,10 @@ Query: SELECT member_relations_vector FROM group_members WHERE group_member_id =
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
Query: SELECT member_status FROM group_members WHERE local_display_name = ?
|
||||
Plan:
|
||||
SCAN group_members
|
||||
|
||||
Query: SELECT member_xcontact_id, member_welcome_shared_msg_id FROM group_members WHERE user_id = ? AND group_id = ? AND group_member_id = ?
|
||||
Plan:
|
||||
SEARCH group_members USING INTEGER PRIMARY KEY (rowid=?)
|
||||
|
||||
@@ -861,16 +861,6 @@ getGroupInfo db vr User {userId, userContactId} groupId = ExceptT $ do
|
||||
(groupInfoQuery <> " WHERE g.group_id = ? AND g.user_id = ? AND mu.contact_id = ?")
|
||||
(groupId, userId, userContactId)
|
||||
|
||||
-- Set group link info and optionally incognito profile before connecting to relays.
|
||||
-- This is called once before connecting to relays, unlike createConnReqConnection -> setPreparedGroupLinkInfo_,
|
||||
-- which is used in single-connection flows.
|
||||
setPreparedGroupLinkInfo :: DB.Connection -> VersionRangeChat -> User -> GroupInfo -> ConnReqContact -> ConnReqUriHash -> Maybe Profile -> ExceptT StoreError IO GroupInfo
|
||||
setPreparedGroupLinkInfo db vr user@User {userId} gInfo@GroupInfo {groupId} cReq cReqHash incognitoProfile = do
|
||||
currentTs <- liftIO getCurrentTime
|
||||
customUserProfileId <- liftIO $ mapM (createIncognitoProfile_ db userId currentTs) incognitoProfile
|
||||
liftIO $ setPreparedGroupLinkInfo_ db gInfo cReq cReqHash customUserProfileId currentTs
|
||||
getGroupInfo db vr user groupId
|
||||
|
||||
setPreparedGroupLinkInfo_ :: DB.Connection -> GroupInfo -> ConnReqContact -> ConnReqUriHash -> Maybe Int64 -> UTCTime -> IO ()
|
||||
setPreparedGroupLinkInfo_ db GroupInfo {groupId, membership} cReq cReqHash customUserProfileId currentTs = do
|
||||
DB.execute
|
||||
|
||||
Reference in new issue
Block a user