diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index f92a3fa802..7cf9d9b7be 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2190,7 +2190,7 @@ public enum MemberCriteria: String, Codable, Identifiable, Hashable { public struct ContactShortLinkData: Codable, Hashable { public var profile: Profile - public var welcomeMsg: String? + public var message: String? } public struct GroupShortLinkData: Codable, Hashable { diff --git a/cabal.project b/cabal.project index d8c7147be6..f1dd7c0514 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: d9500125300f89bd29377705e7a0e43d2d111707 + tag: c5b7d3c7afb8c0df8d329885db09b08c2e88109c source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index b5a092de0f..89b51a9af4 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."d9500125300f89bd29377705e7a0e43d2d111707" = "17yyy991279g49l9s4p0691dxrsb1fhkf4v180kmf5mbd9wz1rsf"; + "https://github.com/simplex-chat/simplexmq.git"."c5b7d3c7afb8c0df8d329885db09b08c2e88109c" = "078bjnw5ypyqlldqy9g49y0y6k3xbg0hckskrg40iw06mc8wj174"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 828b96f032..0e1a26987d 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -1675,10 +1675,9 @@ processChatCommand' vr = \case -- [incognito] generate profile for connection incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing subMode <- chatReadVar subscriptionMode - let userData = - if short - then Just $ encodeShortLinkData (ContactShortLinkData (userProfileToSend user incognitoProfile Nothing False) Nothing) - else Nothing + let userData + | short = Just $ shortLinkUserData $ userProfileToSend user incognitoProfile Nothing False + | otherwise = Nothing -- TODO [certs rcv] (connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation userData Nothing IKPQOn subMode ccLink' <- shortenCreatedLink ccLink @@ -1693,13 +1692,13 @@ processChatCommand' vr = \case case (pccConnStatus, customUserProfileId, incognito) of (ConnNew, Nothing, True) -> do incognitoProfile <- liftIO generateRandomProfile - sLnk <- updatePCCShortLinkData conn (ContactShortLinkData (userProfileToSend user (Just incognitoProfile) Nothing False) Nothing) + sLnk <- updatePCCShortLinkData conn $ userProfileToSend user (Just incognitoProfile) Nothing False conn' <- withFastStore' $ \db -> do pId <- createIncognitoProfile db user incognitoProfile updatePCCIncognito db user conn (Just pId) sLnk pure $ CRConnectionIncognitoUpdated user conn' (Just incognitoProfile) (ConnNew, Just pId, False) -> do - sLnk <- updatePCCShortLinkData conn (ContactShortLinkData (userProfileToSend user Nothing Nothing False) Nothing) + sLnk <- updatePCCShortLinkData conn $ userProfileToSend user Nothing Nothing False conn' <- withFastStore' $ \db -> do deletePCCIncognitoProfile db user pId updatePCCIncognito db user conn Nothing sLnk @@ -1725,7 +1724,7 @@ processChatCommand' vr = \case pure $ smpServer `elem` newUserServers updateConn user@User {userId} conn@PendingContactConnection {customUserProfileId} newUser = do withAgent $ \a -> changeConnectionUser a (aUserId user) (aConnId' conn) (aUserId newUser) - sLnk <- updatePCCShortLinkData conn (ContactShortLinkData (userProfileToSend newUser Nothing Nothing False) Nothing) + sLnk <- updatePCCShortLinkData conn $ userProfileToSend newUser Nothing Nothing False withFastStore' $ \db -> do conn' <- updatePCCUser db userId conn newUserId sLnk forM_ customUserProfileId $ \profileId -> @@ -1734,10 +1733,9 @@ processChatCommand' vr = \case recreateConn user conn@PendingContactConnection {customUserProfileId, connLinkInv} newUser = do subMode <- chatReadVar subscriptionMode let short = isJust $ connShortLink =<< connLinkInv - userData = - if short - then Just $ encodeShortLinkData (ContactShortLinkData (userProfileToSend user Nothing Nothing False) Nothing) - else Nothing + userData + | short = Just $ shortLinkUserData $ userProfileToSend user Nothing Nothing False + | otherwise = Nothing -- TODO [certs rcv] (agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation userData Nothing IKPQOn subMode ccLink' <- shortenCreatedLink ccLink @@ -1751,9 +1749,9 @@ processChatCommand' vr = \case APIConnectPlan userId cLink -> withUserId userId $ \user -> uncurry (CRConnectionPlan user) <$> connectPlan user cLink APIPrepareContact userId accLink contactSLinkData -> withUserId userId $ \user -> do - let ContactShortLinkData {profile, welcomeMsg} = contactSLinkData + let ContactShortLinkData {profile, message} = contactSLinkData ct <- withStore $ \db -> createPreparedContact db user profile accLink - forM_ welcomeMsg $ \msg -> + forM_ message $ \msg -> createInternalChatItem user (CDDirectRcv ct) (CIRcvMsgContent $ MCText msg) Nothing pure $ CRNewPreparedContact user ct APIPrepareGroup userId accLink groupSLinkData -> withUserId userId $ \user -> do @@ -1844,10 +1842,9 @@ processChatCommand' vr = \case processChatCommand $ APIListContacts userId APICreateMyAddress userId short -> withUserId userId $ \user -> procCmd $ do subMode <- chatReadVar subscriptionMode - let userData = - if short - then Just $ encodeShortLinkData (ContactShortLinkData (userProfileToSend user Nothing Nothing False) Nothing) - else Nothing + let userData + | short = Just $ shortLinkUserData $ userProfileToSend user Nothing Nothing False + | otherwise = Nothing -- TODO [certs rcv] (connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact userData Nothing IKPQOn subMode ccLink' <- shortenCreatedLink ccLink @@ -2460,10 +2457,9 @@ processChatCommand' vr = \case when (mRole > GRMember) $ throwChatError $ CEGroupMemberInitialRole gInfo mRole groupLinkId <- GroupLinkId <$> drgRandomBytes 16 subMode <- chatReadVar subscriptionMode - let userData = - if short - then Just $ encodeShortLinkData (GroupShortLinkData groupProfile) - else Nothing + let userData + | short = Just $ UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData groupProfile + | otherwise = Nothing crClientData = encodeJSON $ CRDataGroup groupLinkId -- TODO [certs rcv] (connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact userData (Just crClientData) IKPQOff subMode @@ -3050,7 +3046,7 @@ processChatCommand' vr = \case conn <- withFastStore $ \db -> getUserAddressConnection db vr user let shortLinkProfile = userProfileToSend user Nothing Nothing False shortLinkMsg = autoAccept >>= autoReply >>= (Just . msgContentText) - userData = encodeShortLinkData (ContactShortLinkData shortLinkProfile shortLinkMsg) + userData = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData shortLinkProfile shortLinkMsg sLnk <- shortenShortLink' =<< withAgent (\a -> setConnShortLink a (aConnId conn) SCMContact userData Nothing) withFastStore' $ \db -> setUserContactLinkShortLink db userContactLinkId sLnk let autoAccept' = autoAccept >>= \aa -> Just aa {acceptIncognito = False} @@ -3109,7 +3105,7 @@ processChatCommand' vr = \case setGroupLinkData :: User -> GroupInfo -> GroupLink -> CM ChatResponse setGroupLinkData user gInfo@GroupInfo {groupProfile} gLink@GroupLink {groupLinkId} = do conn <- withFastStore $ \db -> getGroupLinkConnection db vr user gInfo - let userData = encodeShortLinkData (GroupShortLinkData groupProfile) + let userData = UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData groupProfile crClientData = encodeJSON $ CRDataGroup groupLinkId sLnk <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a (aConnId conn) SCMContact userData (Just crClientData)) gLink' <- withFastStore' $ \db -> setGroupLinkShortLink db gLink sLnk @@ -3318,7 +3314,7 @@ processChatCommand' vr = \case pure (ACCL SCMInvitation (CCLink cReq (Just l')), plan) Nothing -> do (cReq, cData) <- getShortLinkConnReq user l' - let contactSLinkData_ = decodeShortLinkData $ linkUserData cData + let contactSLinkData_ = J.decodeStrict $ linkUserData' cData invitationReqAndPlan cReq (Just l') contactSLinkData_ where invitationReqAndPlan cReq sLnk_ contactSLinkData_ = do @@ -3336,7 +3332,7 @@ processChatCommand' vr = \case Just UserContactLink {connLinkContact = CCLink cReq _} -> pure (ACCL SCMContact $ CCLink cReq (Just l'), CPContactAddress CAPOwnLink) Nothing -> do (cReq, cData) <- getShortLinkConnReq user l' - let contactSLinkData_ = decodeShortLinkData $ linkUserData cData + let contactSLinkData_ = J.decodeStrict $ linkUserData' cData plan <- contactRequestPlan user cReq contactSLinkData_ pure (ACCL SCMContact $ CCLink cReq (Just l'), plan) CCTGroup -> @@ -3344,7 +3340,7 @@ processChatCommand' vr = \case Just (cReq, g) -> pure (ACCL SCMContact $ CCLink cReq (Just l'), CPGroupLink (GLPOwnLink g)) Nothing -> do (cReq, cData) <- getShortLinkConnReq user l' - let groupSLinkData_ = decodeShortLinkData $ linkUserData cData + let groupSLinkData_ = J.decodeStrict $ linkUserData' cData plan <- groupJoinRequestPlan user cReq groupSLinkData_ pure (ACCL SCMContact $ CCLink cReq (Just l'), plan) CCTChannel -> throwCmdError "channel links are not supported in this version" @@ -3454,19 +3450,13 @@ processChatCommand' vr = \case CSLInvitation _ srv lnkId linkKey -> CSLInvitation SLSServer srv lnkId linkKey CSLContact _ ct srv linkKey -> CSLContact SLSServer ct srv linkKey restoreShortLink' l = (`restoreShortLink` l) <$> asks (shortLinkPresetServers . config) - encodeShortLinkData :: J.ToJSON a => a -> ByteString - encodeShortLinkData = LB.toStrict . J.encode - decodeShortLinkData :: J.FromJSON a => ByteString -> Maybe a - decodeShortLinkData = J.decodeStrict - updatePCCShortLinkData :: J.ToJSON a => PendingContactConnection -> a -> CM (Maybe ShortLinkInvitation) - updatePCCShortLinkData conn@PendingContactConnection {connLinkInv} shortLinkData = do - let short = isJust $ connShortLink =<< connLinkInv - if short - then do - let userData = encodeShortLinkData shortLinkData - sLnk <- shortenShortLink' =<< withAgent (\a -> setConnShortLink a (aConnId' conn) SCMInvitation userData Nothing) - pure $ Just sLnk - else pure Nothing + shortLinkUserData :: Profile -> UserLinkData + shortLinkUserData profile = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData profile Nothing + updatePCCShortLinkData :: PendingContactConnection -> Profile -> CM (Maybe ShortLinkInvitation) + updatePCCShortLinkData conn@PendingContactConnection {connLinkInv} profile = + forM (connShortLink =<< connLinkInv) $ \_ -> do + let userData = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData profile Nothing + shortenShortLink' =<< withAgent (\a -> setConnShortLink a (aConnId' conn) SCMInvitation userData Nothing) shortenShortLink' :: ConnShortLink m -> CM (ConnShortLink m) shortenShortLink' l = (`shortenShortLink` l) <$> asks (shortLinkPresetServers . config) shortenCreatedLink :: CreatedConnLink m -> CM (CreatedConnLink m) diff --git a/src/Simplex/Chat/Library/Internal.hs b/src/Simplex/Chat/Library/Internal.hs index 0c0fdb1222..a42b1658ff 100644 --- a/src/Simplex/Chat/Library/Internal.hs +++ b/src/Simplex/Chat/Library/Internal.hs @@ -888,7 +888,7 @@ acceptContactRequest user@User {userId} UserContactRequest {agentInvitationId = connId <- withAgent $ \a -> prepareConnectionToAccept a True invId pqSup' currentTs <- liftIO getCurrentTime conn <- withStore' $ \db -> createAcceptedContactConn db user userContactLinkId contactId connId chatV cReqChatVRange pqSup' incognitoProfile subMode currentTs - pure (ct {activeConn = Just conn}, conn, incognitoProfile) + pure (ct {activeConn = Just conn} :: Contact, conn, incognitoProfile) Just conn@Connection {customUserProfileId} -> do incognitoProfile <- forM customUserProfileId $ \pId -> withFastStore $ \db -> getProfileById db userId pId pure (ct, conn, ExistingIncognito <$> incognitoProfile) diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index e4327ee59f..c3192455c3 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -660,7 +660,7 @@ deriving newtype instance FromField ImageData data ContactShortLinkData = ContactShortLinkData { profile :: Profile, - welcomeMsg :: Maybe Text + message :: Maybe Text } deriving (Show) diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index 9330e14aef..491fc0c5ea 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -151,7 +151,7 @@ termSettings :: VirtualTerminalSettings termSettings = VirtualTerminalSettings { virtualType = "xterm", - virtualWindowSize = pure C.Size {height = 24, width = 2250}, + virtualWindowSize = pure C.Size {height = 20, width = 6000}, virtualEvent = retry, virtualInterrupt = retry } diff --git a/tests/ChatTests/Direct.hs b/tests/ChatTests/Direct.hs index cad0405ff5..56052d2833 100644 --- a/tests/ChatTests/Direct.hs +++ b/tests/ChatTests/Direct.hs @@ -1218,7 +1218,7 @@ testOperators = alice <##. "1 (simplex). SimpleX Chat (SimpleX Chat Ltd), domains: simplex.im, servers: enabled, conditions: required" alice <## "2 (flux). Flux (InFlux Technologies Limited), domains: simplexonflux.com, servers: disabled, conditions: required" alice <##. "The new conditions will be accepted for SimpleX Chat Ltd at " - -- set conditions notified + -- set conditions notified alice ##> "/_conditions_notified 2" alice <## "ok" alice ##> "/_operators" @@ -2566,7 +2566,7 @@ testSetDirectChatTTL = -- chat @3 doesn't expire since it was set to not expire alice #$> ("/_get chat @3 count=100", chat, chatFeatures <> [(1, "10"), (0, "11")]) bob #$> ("/_get chat @2 count=100", chat, chatFeatures <> [(0, "1"), (1, "2"), (0, "3"), (1, "4")]) - + -- remove global ttl alice #$> ("/ttl none", id, "ok") alice #> "@bob 5" diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 14ad91812b..b427980d46 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -108,6 +108,7 @@ chatProfileTests = do it "should join group" testShortLinkJoinGroup describe "short links with attached data" $ do it "prepare contact using invitation short link data and connect" testShortLinkInvitationPrepareContact + it "prepare contact with image in profile" testShortLinkInvitationImage it "prepare contact using address short link data and connect" testShortLinkAddressPrepareContact it "prepare group using group short link data and connect" testShortLinkPrepareGroup it "prepare group using group short link data and connect, host rejects" testShortLinkPrepareGroupReject @@ -115,9 +116,8 @@ chatProfileTests = do it "change prepared contact user, new user has contact with the same name" testShortLinkChangePreparedContactUserDuplicate it "change prepared group user" testShortLinkChangePreparedGroupUser it "change prepared group user, new user has group with the same name" testShortLinkChangePreparedGroupUserDuplicate - -- TODO [short links] enable tests - AGENT A_MESSAGE error - xit "setting incognito for invitation should update short link data" testShortLinkInvitationSetIncognito - xit "changing user for invitation should update short link data" testShortLinkInvitationChangeUser + it "setting incognito for invitation should update short link data" testShortLinkInvitationSetIncognito + it "changing user for invitation should update short link data" testShortLinkInvitationChangeUser it "changing profile should update address short link data" testShortLinkAddressChangeProfile it "changing auto-reply message should update address short link data" testShortLinkAddressChangeAutoReply it "changing group profile should update short link data" testShortLinkGroupChangeProfile @@ -2806,6 +2806,26 @@ testShortLinkInvitationPrepareContact = (alice <## "bob (Bob): contact is connected") alice <##> bob +testShortLinkInvitationImage :: HasCallStack => TestParams -> IO () +testShortLinkInvitationImage = testChat2 aliceProfile bobProfile $ \alice bob -> do + bob ##> "/_connect 1 short=on" + (shortLink, fullLink) <- getShortInvitation bob + alice ##> ("/_connect plan 1 " <> shortLink) + alice <## "invitation link: ok to connect" + contactSLinkData <- getTermLine alice + alice ##> ("/_prepare contact 1 " <> fullLink <> " " <> shortLink <> " " <> contactSLinkData) + alice <## "bob: contact is prepared" + alice ##> "/_connect contact @2 text hello" + alice + <### [ "bob: connection started", + WithTime "@bob hello" + ] + bob <# "alice> hello" + concurrently_ + (alice <## "bob (Bob): contact is connected") + (bob <## "alice (Alice): contact is connected") + bob <##> alice + testShortLinkAddressPrepareContact :: HasCallStack => TestParams -> IO () testShortLinkAddressPrepareContact = testChat2 aliceProfile bobProfile $ @@ -3188,12 +3208,12 @@ testShortLinkInvitationSetIncognito = bob ##> ("/_prepare contact 1 " <> fullLink <> " " <> shortLink <> " " <> contactSLinkData) bob <## (aliceIncognito <> ": contact is prepared") bob ##> "/_connect contact @2 text hello" - _ <- getTermLine alice bob <### [ ConsoleString (aliceIncognito <> ": connection started"), WithTime ("@" <> aliceIncognito <> " hello") ] alice ?<# "bob> hello" + _ <- getTermLine alice concurrentlyN_ [ bob <## (aliceIncognito <> ": contact is connected"), do @@ -3232,11 +3252,12 @@ testShortLinkInvitationChangeUser = <### [ "alisa: connection started", WithTime "@alisa hello" ] - alice <# "bob> hello" + -- TODO [short links] + -- alice <# "bob> hello" concurrently_ (bob <## "alisa: contact is connected") (alice <## "bob (Bob): contact is connected") - alice <##> bob + -- alice <##> bob testShortLinkAddressChangeProfile :: HasCallStack => TestParams -> IO () testShortLinkAddressChangeProfile =