diff --git a/src/Simplex/Chat/Store/Direct.hs b/src/Simplex/Chat/Store/Direct.hs index 79cb352299..2eeb81c2d0 100644 --- a/src/Simplex/Chat/Store/Direct.hs +++ b/src/Simplex/Chat/Store/Direct.hs @@ -232,8 +232,7 @@ deleteContactConnectionsAndFiles db userId Contact {contactId} = do deleteContact :: DB.Connection -> User -> Contact -> ExceptT StoreError IO () deleteContact db user@User {userId} ct@Contact {contactId, localDisplayName, activeConn} = do - whenM (liftIO $ checkContactIsUser db user ct) $ throwError (SEProhibitedDeleteUserContact contactId) - whenM (liftIO $ checkLDNIsUser db user localDisplayName) $ throwError (SEProhibitedDeleteUserName localDisplayName) + whenM (liftIO $ checkContactIsUser db user ct) $ throwError (SEProhibitedDeleteUser userId) liftIO $ do DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId) ctMember :: (Maybe ContactId) <- maybeFirstRow fromOnly $ DB.query db "SELECT contact_id FROM group_members WHERE user_id = ? AND contact_id = ? LIMIT 1" (userId, contactId) @@ -252,8 +251,7 @@ deleteContact db user@User {userId} ct@Contact {contactId, localDisplayName, act -- should only be used if contact is not member of any groups deleteContactWithoutGroups :: DB.Connection -> User -> Contact -> ExceptT StoreError IO () deleteContactWithoutGroups db user@User {userId} ct@Contact {contactId, localDisplayName, activeConn} = do - whenM (liftIO $ checkContactIsUser db user ct) $ throwError (SEProhibitedDeleteUserContact contactId) - whenM (liftIO $ checkLDNIsUser db user localDisplayName) $ throwError (SEProhibitedDeleteUserName localDisplayName) + whenM (liftIO $ checkContactIsUser db user ct) $ throwError (SEProhibitedDeleteUser userId) liftIO $ do DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId) deleteContactProfile_ db userId contactId @@ -264,9 +262,8 @@ deleteContactWithoutGroups db user@User {userId} ct@Contact {contactId, localDis deleteUnusedIncognitoProfileById_ db user profileId setContactDeleted :: DB.Connection -> User -> Contact -> ExceptT StoreError IO () -setContactDeleted db user@User {userId} ct@Contact {contactId, localDisplayName} = do - whenM (liftIO $ checkContactIsUser db user ct) $ throwError (SEProhibitedDeleteUserContact contactId) - whenM (liftIO $ checkLDNIsUser db user localDisplayName) $ throwError (SEProhibitedDeleteUserName localDisplayName) +setContactDeleted db user@User {userId} ct@Contact {contactId} = do + whenM (liftIO $ checkContactIsUser db user ct) $ throwError (SEProhibitedDeleteUser userId) liftIO $ do currentTs <- getCurrentTime DB.execute db "UPDATE contacts SET deleted = 1, updated_at = ? WHERE user_id = ? AND contact_id = ?" (currentTs, userId, contactId) diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index 1fdd9b0808..cc476544c7 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -142,7 +142,7 @@ import Simplex.Messaging.Agent.Store.SQLite (firstRow, maybeFirstRow) import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Protocol (SubscriptionMode (..)) -import Simplex.Messaging.Util (eitherToMaybe, unlessM, whenM, ($>>=), (<$$>)) +import Simplex.Messaging.Util (eitherToMaybe, whenM, ($>>=), (<$$>)) import Simplex.Messaging.Version import UnliftIO.STM @@ -587,8 +587,7 @@ deleteGroup :: DB.Connection -> User -> GroupInfo -> IO () deleteGroup db user@User {userId} g@GroupInfo {groupId, localDisplayName} = do deleteGroupProfile_ db userId groupId DB.execute db "DELETE FROM groups WHERE user_id = ? AND group_id = ?" (userId, groupId) - unlessM (checkLDNIsUser db user localDisplayName) $ - DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName) + deleteLDNCheckNotUser db user localDisplayName forM_ (incognitoMembershipProfile g) $ deleteUnusedIncognitoProfileById_ db user . localProfileId deleteGroupProfile_ :: DB.Connection -> UserId -> GroupId -> IO () @@ -1053,8 +1052,7 @@ cleanupMemberProfileAndName_ db user@User {userId} GroupMember {groupMemberId, m sameProfileMember :: (Maybe GroupMemberId) <- maybeFirstRow fromOnly $ DB.query db "SELECT group_member_id FROM group_members WHERE user_id = ? AND contact_profile_id = ? AND group_member_id != ? LIMIT 1" (userId, memberContactProfileId, groupMemberId) when (isNothing sameProfileMember) $ do DB.execute db "DELETE FROM contact_profiles WHERE user_id = ? AND contact_profile_id = ?" (userId, memberContactProfileId) - unlessM (checkLDNIsUser db user localDisplayName) $ - DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName) + deleteLDNCheckNotUser db user localDisplayName deleteGroupMemberConnection :: DB.Connection -> User -> GroupMember -> IO () deleteGroupMemberConnection db User {userId} GroupMember {groupMemberId} = @@ -1364,8 +1362,7 @@ updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, db "UPDATE groups SET local_display_name = ?, updated_at = ? WHERE user_id = ? AND group_id = ?" (ldn, currentTs, userId, groupId) - unlessM (checkLDNIsUser db user localDisplayName) $ - DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (localDisplayName, userId) + deleteLDNCheckNotUser db user localDisplayName getGroupInfo :: DB.Connection -> VersionRange -> User -> Int64 -> ExceptT StoreError IO GroupInfo getGroupInfo db vr User {userId, userContactId} groupId = @@ -1619,10 +1616,8 @@ mergeContactRecords db user@User {userId} to@Contact {localDisplayName = keepLDN let (toCt, fromCt) = toFromContacts to from Contact {contactId = toContactId, localDisplayName = toLDN} = toCt Contact {contactId = fromContactId, localDisplayName = fromLDN} = fromCt - whenM (liftIO $ checkContactIsUser db user toCt) $ throwError (SEProhibitedDeleteUserContact toContactId) - whenM (liftIO $ checkLDNIsUser db user toLDN) $ throwError (SEProhibitedDeleteUserName toLDN) - whenM (liftIO $ checkContactIsUser db user fromCt) $ throwError (SEProhibitedDeleteUserContact fromContactId) - whenM (liftIO $ checkLDNIsUser db user fromLDN) $ throwError (SEProhibitedDeleteUserName fromLDN) + whenM (liftIO $ checkContactIsUser db user toCt) $ throwError (SEProhibitedDeleteUser userId) + whenM (liftIO $ checkContactIsUser db user fromCt) $ throwError (SEProhibitedDeleteUser userId) liftIO $ do currentTs <- getCurrentTime -- next query fixes incorrect unused contacts deletion @@ -2038,8 +2033,7 @@ updateMemberProfile db user@User {userId} m p' db "UPDATE group_members SET local_display_name = ?, updated_at = ? WHERE user_id = ? AND group_member_id = ?" (ldn, currentTs, userId, groupMemberId) - unlessM (checkLDNIsUser db user localDisplayName) $ - DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (localDisplayName, userId) + deleteLDNCheckNotUser db user localDisplayName pure $ Right m {localDisplayName = ldn, memberProfile = profile} where GroupMember {groupMemberId, localDisplayName, memberProfile = LocalProfile {profileId, displayName, localAlias}} = m diff --git a/src/Simplex/Chat/Store/Shared.hs b/src/Simplex/Chat/Store/Shared.hs index 798720d551..eacb269082 100644 --- a/src/Simplex/Chat/Store/Shared.hs +++ b/src/Simplex/Chat/Store/Shared.hs @@ -110,8 +110,7 @@ data StoreError | SERemoteHostDuplicateCA | SERemoteCtrlNotFound {remoteCtrlId :: RemoteCtrlId} | SERemoteCtrlDuplicateCA - | SEProhibitedDeleteUserContact {contactId :: ContactId} - | SEProhibitedDeleteUserName {localDisplayName :: ContactName} + | SEProhibitedDeleteUser {userId :: UserId} deriving (Show, Exception) $(J.deriveJSON (sumTypeJSON $ dropPrefix "SE") ''StoreError) @@ -405,15 +404,27 @@ encodedRandomBytes :: TVar ChaChaDRG -> Int -> IO ByteString encodedRandomBytes gVar n = atomically $ B64.encode <$> C.randomBytes n gVar checkContactIsUser :: DB.Connection -> User -> Contact -> IO Bool -checkContactIsUser db User {userContactId} Contact {contactId} = do - isUser_ <- - maybeFirstRow fromOnly $ - DB.query db "SELECT is_user FROM contacts WHERE contact_id = ?" (Only contactId) - pure $ fromMaybe False isUser_ || contactId == userContactId - -checkLDNIsUser :: DB.Connection -> User -> ContactName -> IO Bool -checkLDNIsUser db User {userId} ldn = do +checkContactIsUser db User {userId} Contact {contactId, localDisplayName} = do r :: (Maybe Int64) <- maybeFirstRow fromOnly $ - DB.query db "SELECT 1 FROM users WHERE user_id = ? AND local_display_name = ? LIMIT 1" (userId, ldn) + DB.query + db + [sql| + SELECT 1 FROM users + WHERE (user_id = ? AND local_display_name = ?) + OR (contact_id = ?) + LIMIT 1 + |] + (userId, localDisplayName, contactId) pure $ isJust r + +deleteLDNCheckNotUser :: DB.Connection -> User -> ContactName -> IO () +deleteLDNCheckNotUser db User {userId} localDisplayName = do + DB.execute + db + [sql| + DELETE FROM display_names + WHERE user_id = ? AND local_display_name = ? + AND local_display_name NOT IN (SELECT local_display_name FROM users WHERE user_id = ?) + |] + (userId, localDisplayName)