diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index 91c5b1b36..2e724bcd8 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -257,7 +257,7 @@ func setXFTPConfig(_ cfg: XFTPFileConfig?) throws {
throw r
}
-func apiSetEncryptLocalFiles(_ enable: Boolean) throws {
+func apiSetEncryptLocalFiles(_ enable: Bool) throws {
let r = chatSendCmdSync(.apiSetEncryptLocalFiles(enable: enable))
if case .cmdOk = r { return }
throw r
@@ -1158,7 +1158,7 @@ func initializeChat(start: Bool, dbKey: String? = nil, refreshInvitations: Bool
try apiSetTempFolder(tempFolder: getTempFilesDirectory().path)
try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path)
try setXFTPConfig(getXFTPCfg())
- // try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
+ try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
m.chatInitialized = true
m.currentUser = try apiGetActiveUser()
if m.currentUser == nil {
diff --git a/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift b/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift
index 34b6f147b..16555fad3 100644
--- a/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift
+++ b/apps/ios/Shared/Views/UserSettings/PrivacySettings.swift
@@ -66,6 +66,9 @@ struct PrivacySettings: View {
Section {
settingsRow("lock.doc") {
Toggle("Encrypt local files", isOn: $encryptLocalFiles)
+ .onChange(of: encryptLocalFiles) {
+ setEncryptLocalFiles($0)
+ }
}
settingsRow("photo") {
Toggle("Auto-accept images", isOn: $autoAcceptImages)
@@ -183,6 +186,16 @@ struct PrivacySettings: View {
}
}
+ private func setEncryptLocalFiles(_ enable: Bool) {
+ do {
+ try apiSetEncryptLocalFiles(enable)
+ } catch let error {
+ let err = responseError(error)
+ logger.error("apiSetEncryptLocalFiles \(err)")
+ alert = .error(title: "Error", error: "\(err)")
+ }
+ }
+
private func setOrAskSendReceiptsContacts(_ enable: Bool) {
contactReceiptsOverrides = m.chats.reduce(0) { count, chat in
let sendRcpts = chat.chatInfo.contact?.chatSettings.sendRcpts
diff --git a/apps/ios/SimpleX NSE/NotificationService.swift b/apps/ios/SimpleX NSE/NotificationService.swift
index 2fb069a86..ea52f4be8 100644
--- a/apps/ios/SimpleX NSE/NotificationService.swift
+++ b/apps/ios/SimpleX NSE/NotificationService.swift
@@ -216,7 +216,7 @@ func startChat() -> DBMigrationResult? {
try apiSetTempFolder(tempFolder: getTempFilesDirectory().path)
try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path)
try setXFTPConfig(xftpConfig)
- // try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
+ try apiSetEncryptLocalFiles(privacyEncryptLocalFilesGroupDefault.get())
let justStarted = try apiStartChat()
chatStarted = true
if justStarted {
@@ -352,8 +352,8 @@ func setXFTPConfig(_ cfg: XFTPFileConfig?) throws {
throw r
}
-func apiSetEncryptLocalFiles(_ enable: Boolean) throws {
- let r = chatSendCmdSync(.apiSetEncryptLocalFiles(enable: enable))
+func apiSetEncryptLocalFiles(_ enable: Bool) throws {
+ let r = sendSimpleXCmd(.apiSetEncryptLocalFiles(enable: enable))
if case .cmdOk = r { return }
throw r
}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt
index f49984b94..cc8d481b5 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt
@@ -338,7 +338,7 @@ object ChatController {
apiSetTempFolder(coreTmpDir.absolutePath)
apiSetFilesFolder(appFilesDir.absolutePath)
apiSetXFTPConfig(getXFTPCfg())
-// apiSetEncryptLocalFiles(appPrefs.privacyEncryptLocalFiles.get())
+ apiSetEncryptLocalFiles(appPrefs.privacyEncryptLocalFiles.get())
val justStarted = apiStartChat()
val users = listUsers()
chatModel.users.clear()
@@ -1333,7 +1333,7 @@ object ChatController {
private suspend fun sendCommandOkResp(cmd: CC): Boolean {
val r = sendCmd(cmd)
val ok = r is CR.CmdOk
- if (!ok) apiErrorAlert(cmd.cmdType, generalGetString(MR.strings.error), r)
+ if (!ok) apiErrorAlert(cmd.cmdType, generalGetString(MR.strings.error_alert_title), r)
return ok
}
@@ -1942,7 +1942,7 @@ sealed class CC {
class ApiRejectContact(val contactReqId: Long): CC()
class ApiChatRead(val type: ChatType, val id: Long, val range: ItemRange): CC()
class ApiChatUnread(val type: ChatType, val id: Long, val unreadChat: Boolean): CC()
- class ReceiveFile(val fileId: Long, val encrypt: Boolean?, val inline: Boolean?): CC()
+ class ReceiveFile(val fileId: Long, val encrypt: Boolean, val inline: Boolean?): CC()
class CancelFile(val fileId: Long): CC()
class ShowVersion(): CC()
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt
index ef0940b2a..210d3c613 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt
@@ -64,7 +64,9 @@ fun PrivacySettingsView(
SectionDividerSpaced()
SectionView(stringResource(MR.strings.settings_section_title_chats)) {
- SettingsPreferenceItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.encrypt_local_files), chatModel.controller.appPrefs.privacyEncryptLocalFiles)
+ SettingsPreferenceItem(painterResource(MR.images.ic_lock), stringResource(MR.strings.encrypt_local_files), chatModel.controller.appPrefs.privacyEncryptLocalFiles, onChange = { enable ->
+ withBGApi { chatModel.controller.apiSetEncryptLocalFiles(enable) }
+ })
SettingsPreferenceItem(painterResource(MR.images.ic_image), stringResource(MR.strings.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages)
SettingsPreferenceItem(painterResource(MR.images.ic_travel_explore), stringResource(MR.strings.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews)
SettingsPreferenceItem(
diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
index 7912a5ad1..114fe49e9 100644
--- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
+++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
@@ -113,6 +113,7 @@
Server requires authorization to upload, check password
Possibly, certificate fingerprint in server address is incorrect
Error setting address
+ Error
Connect
Disconnect
Create queue
diff --git a/cabal.project b/cabal.project
index 11a597897..8816c4c88 100644
--- a/cabal.project
+++ b/cabal.project
@@ -9,7 +9,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
- tag: 9f0f53d2ec34de09ab684036844578ed5994c24b
+ tag: 2a43717738eaf7a1457f70b48586df19d73a10f3
source-repository-package
type: git
diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix
index 8d722d440..98ed779d6 100644
--- a/scripts/nix/sha256map.nix
+++ b/scripts/nix/sha256map.nix
@@ -1,5 +1,5 @@
{
- "https://github.com/simplex-chat/simplexmq.git"."9f0f53d2ec34de09ab684036844578ed5994c24b" = "0n8as86gaaws3yqy8kvflpqw8jgjzdyrskb59aqs9k4yimg6wk50";
+ "https://github.com/simplex-chat/simplexmq.git"."2a43717738eaf7a1457f70b48586df19d73a10f3" = "1iqaiw48zvk0s9s2dgpmsmi78nw1q6nkmfi0n3xiv6q23l40sf6c";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/kazu-yamamoto/http2.git"."b5a1b7200cf5bc7044af34ba325284271f6dff25" = "0dqb50j57an64nf4qcf5vcz4xkd1vzvghvf8bk529c1k30r9nfzb";
"https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd";
diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs
index a055a7334..16b804471 100644
--- a/src/Simplex/Chat.hs
+++ b/src/Simplex/Chat.hs
@@ -1356,13 +1356,13 @@ processChatCommand = \case
APIConnect _ _ Nothing -> throwChatError CEInvalidConnReq
Connect incognito aCReqUri@(Just cReqUri) -> withUser $ \user@User {userId} -> do
plan <- connectPlan user cReqUri `catchChatError` const (pure $ CPInvitationLink ILPOk)
- unless (connectionPlanOk plan) $ throwChatError (CEConnectionPlan plan)
+ unless (connectionPlanProceed plan) $ throwChatError (CEConnectionPlan plan)
processChatCommand $ APIConnect userId incognito aCReqUri
Connect _ Nothing -> throwChatError CEInvalidConnReq
ConnectSimplex incognito -> withUser $ \user@User {userId} -> do
let cReqUri = ACR SCMContact adminContactReq
plan <- connectPlan user cReqUri `catchChatError` const (pure $ CPInvitationLink ILPOk)
- unless (connectionPlanOk plan) $ throwChatError (CEConnectionPlan plan)
+ unless (connectionPlanProceed plan) $ throwChatError (CEConnectionPlan plan)
processChatCommand $ APIConnect userId incognito (Just cReqUri)
DeleteContact cName -> withContactName cName $ \ctId -> APIDeleteChat (ChatRef CTDirect ctId) True
ClearContact cName -> withContactName cName $ APIClearChat . ChatRef CTDirect
@@ -2214,7 +2214,7 @@ processChatCommand = \case
processChatCommand $ APISetChatSettings (ChatRef cType chatId) $ updateSettings chatSettings
connectPlan :: User -> AConnectionRequestUri -> m ConnectionPlan
connectPlan user (ACR SCMInvitation cReq) = do
- withStore' (\db -> getConnectionEntityByConnReq db user cReq) >>= \case
+ withStore' (\db -> getConnectionEntityByConnReq db user cReqSchemas) >>= \case
Nothing -> pure $ CPInvitationLink ILPOk
Just (RcvDirectMsgConnection conn ct_) -> do
let Connection {connStatus, contactConnInitiated} = conn
@@ -2227,39 +2227,59 @@ processChatCommand = \case
Just ct -> pure $ CPInvitationLink (ILPKnown ct)
Nothing -> throwChatError $ CEInternalError "ready RcvDirectMsgConnection connection should have associated contact"
Just _ -> throwChatError $ CECommandError "found connection entity is not RcvDirectMsgConnection"
+ where
+ cReqSchemas :: (ConnReqInvitation, ConnReqInvitation)
+ cReqSchemas = case cReq of
+ (CRInvitationUri crData e2e) ->
+ ( CRInvitationUri crData {crScheme = CRSSimplex} e2e,
+ CRInvitationUri crData {crScheme = simplexChat} e2e
+ )
connectPlan user (ACR SCMContact cReq) = do
let CRContactUri ConnReqUriData {crClientData} = cReq
groupLinkId = crClientData >>= decodeJSON >>= \(CRDataGroup gli) -> Just gli
case groupLinkId of
-- contact address
Nothing ->
- withStore' (`getUserContactLinkByConnReq` cReq) >>= \case
+ withStore' (`getUserContactLinkByConnReq` cReqSchemas) >>= \case
Just _ -> pure $ CPContactAddress CAPOwnLink
Nothing -> do
- let cReqHash = ConnReqUriHash . C.sha256Hash $ strEncode cReq
- withStore' (\db -> getContactByConnReqHash db user cReqHash) >>= \case
+ withStore' (\db -> getContactConnEntityByConnReqHash db user cReqHashes) >>= \case
Nothing -> pure $ CPContactAddress CAPOk
- Just ct
- | not (contactReady ct) && contactActive ct -> pure $ CPContactAddress (CAPConnecting ct)
+ Just (RcvDirectMsgConnection _conn Nothing) -> pure $ CPContactAddress CAPConnectingConfirmReconnect
+ Just (RcvDirectMsgConnection _ (Just ct))
+ | not (contactReady ct) && contactActive ct -> pure $ CPContactAddress (CAPConnectingProhibit ct)
+ | contactDeleted ct -> pure $ CPContactAddress CAPOk
| otherwise -> pure $ CPContactAddress (CAPKnown ct)
+ Just _ -> throwChatError $ CECommandError "found connection entity is not RcvDirectMsgConnection"
-- group link
Just _ ->
- withStore' (\db -> getGroupInfoByUserContactLinkConnReq db user cReq) >>= \case
+ withStore' (\db -> getGroupInfoByUserContactLinkConnReq db user cReqSchemas) >>= \case
Just g -> pure $ CPGroupLink (GLPOwnLink g)
Nothing -> do
- let cReqHash = ConnReqUriHash . C.sha256Hash $ strEncode cReq
- ct_ <- withStore' $ \db -> getContactByConnReqHash db user cReqHash
- gInfo_ <- withStore' $ \db -> getGroupInfoByGroupLinkHash db user cReqHash
- case (gInfo_, ct_) of
+ connEnt_ <- withStore' $ \db -> getContactConnEntityByConnReqHash db user cReqHashes
+ gInfo_ <- withStore' $ \db -> getGroupInfoByGroupLinkHash db user cReqHashes
+ case (gInfo_, connEnt_) of
(Nothing, Nothing) -> pure $ CPGroupLink GLPOk
- (Nothing, Just ct)
- | not (contactReady ct) && contactActive ct -> pure $ CPGroupLink (GLPConnecting gInfo_)
+ (Nothing, Just (RcvDirectMsgConnection _conn Nothing)) -> pure $ CPGroupLink GLPConnectingConfirmReconnect
+ (Nothing, Just (RcvDirectMsgConnection _ (Just ct)))
+ | not (contactReady ct) && contactActive ct -> pure $ CPGroupLink (GLPConnectingProhibit gInfo_)
| otherwise -> pure $ CPGroupLink GLPOk
+ (Nothing, Just _) -> throwChatError $ CECommandError "found connection entity is not RcvDirectMsgConnection"
(Just gInfo@GroupInfo {membership}, _)
| not (memberActive membership) && not (memberRemoved membership) ->
- pure $ CPGroupLink (GLPConnecting gInfo_)
+ pure $ CPGroupLink (GLPConnectingProhibit gInfo_)
| memberActive membership -> pure $ CPGroupLink (GLPKnown gInfo)
| otherwise -> pure $ CPGroupLink GLPOk
+ where
+ cReqSchemas :: (ConnReqContact, ConnReqContact)
+ cReqSchemas = case cReq of
+ (CRContactUri crData) ->
+ ( CRContactUri crData {crScheme = CRSSimplex},
+ CRContactUri crData {crScheme = simplexChat}
+ )
+ cReqHashes :: (ConnReqUriHash, ConnReqUriHash)
+ cReqHashes = bimap hash hash cReqSchemas
+ hash = ConnReqUriHash . C.sha256Hash . strEncode
assertDirectAllowed :: ChatMonad m => User -> MsgDirection -> Contact -> CMEventTag e -> m ()
assertDirectAllowed user dir ct event =
@@ -5907,7 +5927,7 @@ chatCommandP =
adminContactReq :: ConnReqContact
adminContactReq =
- either error id $ strDecode "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D"
+ either error id $ strDecode "simplex:/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D"
timeItToView :: ChatMonad' m => String -> m a -> m a
timeItToView s action = do
diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs
index 0a9b88694..d8851ad87 100644
--- a/src/Simplex/Chat/Controller.hs
+++ b/src/Simplex/Chat/Controller.hs
@@ -647,7 +647,8 @@ instance ToJSON InvitationLinkPlan where
data ContactAddressPlan
= CAPOk
| CAPOwnLink
- | CAPConnecting {contact :: Contact}
+ | CAPConnectingConfirmReconnect
+ | CAPConnectingProhibit {contact :: Contact}
| CAPKnown {contact :: Contact}
deriving (Show, Generic)
@@ -658,7 +659,8 @@ instance ToJSON ContactAddressPlan where
data GroupLinkPlan
= GLPOk
| GLPOwnLink {groupInfo :: GroupInfo}
- | GLPConnecting {groupInfo_ :: Maybe GroupInfo}
+ | GLPConnectingConfirmReconnect
+ | GLPConnectingProhibit {groupInfo_ :: Maybe GroupInfo}
| GLPKnown {groupInfo :: GroupInfo}
deriving (Show, Generic)
@@ -666,8 +668,8 @@ instance ToJSON GroupLinkPlan where
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "GLP"
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "GLP"
-connectionPlanOk :: ConnectionPlan -> Bool
-connectionPlanOk = \case
+connectionPlanProceed :: ConnectionPlan -> Bool
+connectionPlanProceed = \case
CPInvitationLink ilp -> case ilp of
ILPOk -> True
ILPOwnLink -> True
@@ -675,10 +677,12 @@ connectionPlanOk = \case
CPContactAddress cap -> case cap of
CAPOk -> True
CAPOwnLink -> True
+ CAPConnectingConfirmReconnect -> True
_ -> False
CPGroupLink glp -> case glp of
GLPOk -> True
GLPOwnLink _ -> True
+ GLPConnectingConfirmReconnect -> True
_ -> False
newtype UserPwd = UserPwd {unUserPwd :: Text}
diff --git a/src/Simplex/Chat/Markdown.hs b/src/Simplex/Chat/Markdown.hs
index d18f28db3..30990f225 100644
--- a/src/Simplex/Chat/Markdown.hs
+++ b/src/Simplex/Chat/Markdown.hs
@@ -32,7 +32,7 @@ import Simplex.Chat.Types.Util
import Simplex.Messaging.Agent.Protocol (AConnectionRequestUri (..), ConnReqScheme (..), ConnReqUriData (..), ConnectionRequestUri (..), SMPQueue (..))
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, fstToLower, sumTypeJSON)
-import Simplex.Messaging.Protocol (ProtocolServer (..), SrvLoc (..))
+import Simplex.Messaging.Protocol (ProtocolServer (..))
import Simplex.Messaging.Util (safeDecodeUtf8)
import System.Console.ANSI.Types
import qualified Text.Email.Validate as Email
@@ -48,7 +48,7 @@ data Format
| Secret
| Colored {color :: FormatColor}
| Uri
- | SimplexLink {linkType :: SimplexLinkType, simplexUri :: Text, trustedUri :: Bool, smpHosts :: NonEmpty Text}
+ | SimplexLink {linkType :: SimplexLinkType, simplexUri :: Text, smpHosts :: NonEmpty Text}
| Email
| Phone
deriving (Eq, Show, Generic)
@@ -229,15 +229,12 @@ markdownP = mconcat <$> A.many' fragmentP
simplexUriFormat = \case
ACR _ (CRContactUri crData) ->
let uri = safeDecodeUtf8 . strEncode $ CRContactUri crData {crScheme = CRSSimplex}
- in SimplexLink (linkType' crData) uri (trustedUri' crData) $ uriHosts crData
+ in SimplexLink (linkType' crData) uri $ uriHosts crData
ACR _ (CRInvitationUri crData e2e) ->
let uri = safeDecodeUtf8 . strEncode $ CRInvitationUri crData {crScheme = CRSSimplex} e2e
- in SimplexLink XLInvitation uri (trustedUri' crData) $ uriHosts crData
+ in SimplexLink XLInvitation uri $ uriHosts crData
where
uriHosts ConnReqUriData {crSmpQueues} = L.map (safeDecodeUtf8 . strEncode) $ sconcat $ L.map (host . qServer) crSmpQueues
- trustedUri' ConnReqUriData {crScheme} = case crScheme of
- CRSSimplex -> True
- CRSAppServer (SrvLoc host _) -> host == "simplex.chat"
linkType' ConnReqUriData {crClientData} = case crClientData >>= decodeJSON of
Just (CRDataGroup _) -> XLGroup
Nothing -> XLContact
diff --git a/src/Simplex/Chat/Store/Connections.hs b/src/Simplex/Chat/Store/Connections.hs
index d47d9c3ab..4f468b0d6 100644
--- a/src/Simplex/Chat/Store/Connections.hs
+++ b/src/Simplex/Chat/Store/Connections.hs
@@ -8,6 +8,7 @@
module Simplex.Chat.Store.Connections
( getConnectionEntity,
getConnectionEntityByConnReq,
+ getContactConnEntityByConnReqHash,
getConnectionsToSubscribe,
unsetConnectionToSubscribe,
)
@@ -150,10 +151,33 @@ getConnectionEntity db user@User {userId, userContactId} agentConnId = do
userContact_ [(cReq, groupId)] = Right UserContact {userContactLinkId, connReqContact = cReq, groupId}
userContact_ _ = Left SEUserContactLinkNotFound
-getConnectionEntityByConnReq :: DB.Connection -> User -> ConnReqInvitation -> IO (Maybe ConnectionEntity)
-getConnectionEntityByConnReq db user cReq = do
+getConnectionEntityByConnReq :: DB.Connection -> User -> (ConnReqInvitation, ConnReqInvitation) -> IO (Maybe ConnectionEntity)
+getConnectionEntityByConnReq db user (cReqSchema1, cReqSchema2) = do
connId_ <- maybeFirstRow fromOnly $
- DB.query db "SELECT agent_conn_id FROM connections WHERE conn_req_inv = ? LIMIT 1" (Only cReq)
+ DB.query db "SELECT agent_conn_id FROM connections WHERE conn_req_inv IN (?,?) LIMIT 1" (cReqSchema1, cReqSchema2)
+ maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getConnectionEntity db user) connId_
+
+-- search connection for connection plan:
+-- multiple connections can have same via_contact_uri_hash if request was repeated;
+-- this function searches for latest connection with contact so that "known contact" plan would be chosen;
+-- deleted connections are filtered out to allow re-connecting via same contact address
+getContactConnEntityByConnReqHash :: DB.Connection -> User -> (ConnReqUriHash, ConnReqUriHash) -> IO (Maybe ConnectionEntity)
+getContactConnEntityByConnReqHash db user (cReqHash1, cReqHash2) = do
+ connId_ <- maybeFirstRow fromOnly $
+ DB.query
+ db
+ [sql|
+ SELECT agent_conn_id FROM (
+ SELECT
+ agent_conn_id,
+ (CASE WHEN contact_id IS NOT NULL THEN 1 ELSE 0 END) AS conn_ord
+ FROM connections
+ WHERE via_contact_uri_hash IN (?,?) AND conn_status != ?
+ ORDER BY conn_ord DESC, created_at DESC
+ LIMIT 1
+ )
+ |]
+ (cReqHash1, cReqHash2, ConnDeleted)
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getConnectionEntity db user) connId_
getConnectionsToSubscribe :: DB.Connection -> IO ([ConnId], [ConnectionEntity])
diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs
index 3184dea52..c5fd442ce 100644
--- a/src/Simplex/Chat/Store/Groups.hs
+++ b/src/Simplex/Chat/Store/Groups.hs
@@ -1116,21 +1116,21 @@ getGroupInfo db User {userId, userContactId} groupId =
|]
(groupId, userId, userContactId)
-getGroupInfoByUserContactLinkConnReq :: DB.Connection -> User -> ConnReqContact -> IO (Maybe GroupInfo)
-getGroupInfoByUserContactLinkConnReq db user cReq = do
+getGroupInfoByUserContactLinkConnReq :: DB.Connection -> User -> (ConnReqContact, ConnReqContact) -> IO (Maybe GroupInfo)
+getGroupInfoByUserContactLinkConnReq db user (cReqSchema1, cReqSchema2) = do
groupId_ <- maybeFirstRow fromOnly $
DB.query
db
[sql|
SELECT group_id
FROM user_contact_links
- WHERE conn_req_contact = ?
+ WHERE conn_req_contact IN (?,?)
|]
- (Only cReq)
+ (cReqSchema1, cReqSchema2)
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getGroupInfo db user) groupId_
-getGroupInfoByGroupLinkHash :: DB.Connection -> User -> ConnReqUriHash -> IO (Maybe GroupInfo)
-getGroupInfoByGroupLinkHash db user@User {userId, userContactId} groupLinkHash = do
+getGroupInfoByGroupLinkHash :: DB.Connection -> User -> (ConnReqUriHash, ConnReqUriHash) -> IO (Maybe GroupInfo)
+getGroupInfoByGroupLinkHash db user@User {userId, userContactId} (groupLinkHash1, groupLinkHash2) = do
groupId_ <- maybeFirstRow fromOnly $
DB.query
db
@@ -1138,11 +1138,11 @@ getGroupInfoByGroupLinkHash db user@User {userId, userContactId} groupLinkHash =
SELECT g.group_id
FROM groups g
JOIN group_members mu ON mu.group_id = g.group_id
- WHERE g.user_id = ? AND g.via_group_link_uri_hash = ?
+ WHERE g.user_id = ? AND g.via_group_link_uri_hash IN (?,?)
AND mu.contact_id = ? AND mu.member_status NOT IN (?,?,?)
LIMIT 1
|]
- (userId, groupLinkHash, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
+ (userId, groupLinkHash1, groupLinkHash2, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getGroupInfo db user) groupId_
getGroupIdByName :: DB.Connection -> User -> GroupName -> ExceptT StoreError IO GroupId
diff --git a/src/Simplex/Chat/Store/Profiles.hs b/src/Simplex/Chat/Store/Profiles.hs
index 704774f8d..6eb210bd5 100644
--- a/src/Simplex/Chat/Store/Profiles.hs
+++ b/src/Simplex/Chat/Store/Profiles.hs
@@ -437,17 +437,17 @@ getUserContactLinkById db userId userContactLinkId =
|]
(userId, userContactLinkId)
-getUserContactLinkByConnReq :: DB.Connection -> ConnReqContact -> IO (Maybe UserContactLink)
-getUserContactLinkByConnReq db cReq =
+getUserContactLinkByConnReq :: DB.Connection -> (ConnReqContact, ConnReqContact) -> IO (Maybe UserContactLink)
+getUserContactLinkByConnReq db (cReqSchema1, cReqSchema2) =
maybeFirstRow toUserContactLink $
DB.query
db
[sql|
SELECT conn_req_contact, auto_accept, auto_accept_incognito, auto_reply_msg_content
FROM user_contact_links
- WHERE conn_req_contact = ?
+ WHERE conn_req_contact IN (?,?)
|]
- (Only cReq)
+ (cReqSchema1, cReqSchema2)
updateUserAddressAutoAccept :: DB.Connection -> User -> Maybe AutoAccept -> ExceptT StoreError IO UserContactLink
updateUserAddressAutoAccept db user@User {userId} autoAccept = do
diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs
index 24a224b11..f89864fb9 100644
--- a/src/Simplex/Chat/Types.hs
+++ b/src/Simplex/Chat/Types.hs
@@ -217,6 +217,9 @@ contactReady Contact {activeConn} = connReady activeConn
contactActive :: Contact -> Bool
contactActive Contact {contactStatus} = contactStatus == CSActive
+contactDeleted :: Contact -> Bool
+contactDeleted Contact {contactStatus} = contactStatus == CSDeleted
+
contactSecurityCode :: Contact -> Maybe SecurityCode
contactSecurityCode Contact {activeConn} = connectionCode activeConn
diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs
index 212ceeff2..f85e27d12 100644
--- a/src/Simplex/Chat/View.hs
+++ b/src/Simplex/Chat/View.hs
@@ -692,11 +692,14 @@ viewConnReqInvitation :: ConnReqInvitation -> [StyledString]
viewConnReqInvitation cReq =
[ "pass this invitation link to your contact (via another channel): ",
"",
- (plain . strEncode) cReq,
+ (plain . strEncode) (simplexChatInvitation cReq),
"",
"and ask them to connect: " <> highlight' "/c "
]
+simplexChatInvitation :: ConnReqInvitation -> ConnReqInvitation
+simplexChatInvitation (CRInvitationUri crData e2e) = CRInvitationUri crData {crScheme = simplexChat} e2e
+
viewContactNotFound :: ContactName -> Maybe (GroupInfo, GroupMember) -> [StyledString]
viewContactNotFound cName suspectedMember =
["no contact " <> ttyContact cName <> useMessageMember]
@@ -733,7 +736,7 @@ connReqContact_ :: StyledString -> ConnReqContact -> [StyledString]
connReqContact_ intro cReq =
[ intro,
"",
- (plain . strEncode) cReq,
+ (plain . strEncode) (simplexChatContact cReq),
"",
"Anybody can send you contact requests with: " <> highlight' "/c ",
"to show it again: " <> highlight' "/sa",
@@ -741,6 +744,9 @@ connReqContact_ intro cReq =
"to delete it: " <> highlight' "/da" <> " (accepted contacts will remain connected)"
]
+simplexChatContact :: ConnReqContact -> ConnReqContact
+simplexChatContact (CRContactUri crData) = CRContactUri crData {crScheme = simplexChat}
+
autoAcceptStatus_ :: Maybe AutoAccept -> [StyledString]
autoAcceptStatus_ = \case
Just AutoAccept {acceptIncognito, autoReply} ->
@@ -752,7 +758,7 @@ groupLink_ :: StyledString -> GroupInfo -> ConnReqContact -> GroupMemberRole ->
groupLink_ intro g cReq mRole =
[ intro,
"",
- (plain . strEncode) cReq,
+ (plain . strEncode) (simplexChatContact cReq),
"",
"Anybody can connect to you and join group as " <> showRole mRole <> " with: " <> highlight' "/c ",
"to show it again: " <> highlight ("/show link #" <> viewGroupName g),
@@ -1019,7 +1025,7 @@ viewContactInfo :: Contact -> ConnectionStats -> Maybe Profile -> [StyledString]
viewContactInfo ct@Contact {contactId, profile = LocalProfile {localAlias, contactLink}, activeConn} stats incognitoProfile =
["contact ID: " <> sShow contactId]
<> viewConnectionStats stats
- <> maybe [] (\l -> ["contact address: " <> (plain . strEncode) l]) contactLink
+ <> maybe [] (\l -> ["contact address: " <> (plain . strEncode) (simplexChatContact l)]) contactLink
<> maybe
["you've shared main profile with this contact"]
(\p -> ["you've shared incognito profile with this contact: " <> incognitoProfile' p])
@@ -1278,7 +1284,8 @@ viewConnectionPlan = \case
CPContactAddress cap -> case cap of
CAPOk -> [ctAddr "ok to connect"]
CAPOwnLink -> [ctAddr "own address"]
- CAPConnecting ct -> [ctAddr ("connecting to contact " <> ttyContact' ct)]
+ CAPConnectingConfirmReconnect -> [ctAddr "connecting, allowed to reconnect"]
+ CAPConnectingProhibit ct -> [ctAddr ("connecting to contact " <> ttyContact' ct)]
CAPKnown ct ->
[ ctAddr ("known contact " <> ttyContact' ct),
"use " <> ttyToContact' ct <> highlight' "" <> " to send messages"
@@ -1288,8 +1295,9 @@ viewConnectionPlan = \case
CPGroupLink glp -> case glp of
GLPOk -> [grpLink "ok to connect"]
GLPOwnLink g -> [grpLink "own link for group " <> ttyGroup' g]
- GLPConnecting Nothing -> [grpLink "connecting"]
- GLPConnecting (Just g) -> [grpLink ("connecting to group " <> ttyGroup' g)]
+ GLPConnectingConfirmReconnect -> [grpLink "connecting, allowed to reconnect"]
+ GLPConnectingProhibit Nothing -> [grpLink "connecting"]
+ GLPConnectingProhibit (Just g) -> [grpLink ("connecting to group " <> ttyGroup' g)]
GLPKnown g ->
[ grpLink ("known group " <> ttyGroup' g),
"use " <> ttyToGroup g <> highlight' "" <> " to send messages"
diff --git a/stack.yaml b/stack.yaml
index 2d63fdfa2..92489001d 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -49,7 +49,7 @@ extra-deps:
# - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561
# - ../simplexmq
- github: simplex-chat/simplexmq
- commit: 9f0f53d2ec34de09ab684036844578ed5994c24b
+ commit: 2a43717738eaf7a1457f70b48586df19d73a10f3
- github: kazu-yamamoto/http2
commit: b5a1b7200cf5bc7044af34ba325284271f6dff25
# - ../direct-sqlcipher
diff --git a/tests/ChatTests/Direct.hs b/tests/ChatTests/Direct.hs
index 677bc4c09..1a133fd8e 100644
--- a/tests/ChatTests/Direct.hs
+++ b/tests/ChatTests/Direct.hs
@@ -270,6 +270,10 @@ testPlanInvitationLinkOwn tmp =
alice ##> ("/_connect plan 1 " <> inv)
alice <## "invitation link: own link"
+ let invSchema2 = linkAnotherSchema inv
+ alice ##> ("/_connect plan 1 " <> invSchema2)
+ alice <## "invitation link: own link"
+
alice ##> ("/c " <> inv)
alice <## "confirmation sent!"
alice
@@ -305,6 +309,10 @@ testPlanInvitationLinkConnecting tmp = do
bob ##> ("/_connect plan 1 " <> inv)
bob <## "invitation link: connecting"
+ let invSchema2 = linkAnotherSchema inv
+ bob ##> ("/_connect plan 1 " <> invSchema2)
+ bob <## "invitation link: connecting"
+
testContactClear :: HasCallStack => FilePath -> IO ()
testContactClear =
testChat2 aliceProfile bobProfile $
diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs
index 4c3180526..7a8b1368b 100644
--- a/tests/ChatTests/Groups.hs
+++ b/tests/ChatTests/Groups.hs
@@ -2290,6 +2290,11 @@ testPlanGroupLinkOkKnown =
bob <## "group link: known group #team"
bob <## "use #team to send messages"
+ let gLinkSchema2 = linkAnotherSchema gLink
+ bob ##> ("/_connect plan 1 " <> gLinkSchema2)
+ bob <## "group link: known group #team"
+ bob <## "use #team to send messages"
+
bob ##> ("/c " <> gLink)
bob <## "group link: known group #team"
bob <## "use #team to send messages"
@@ -2331,6 +2336,11 @@ testPlanHostContactDeletedGroupLinkKnown =
bob <## "group link: known group #team"
bob <## "use #team to send messages"
+ let gLinkSchema2 = linkAnotherSchema gLink
+ bob ##> ("/_connect plan 1 " <> gLinkSchema2)
+ bob <## "group link: known group #team"
+ bob <## "use #team to send messages"
+
bob ##> ("/c " <> gLink)
bob <## "group link: known group #team"
bob <## "use #team to send messages"
@@ -2347,6 +2357,10 @@ testPlanGroupLinkOwn tmp =
alice ##> ("/_connect plan 1 " <> gLink)
alice <## "group link: own link for group #team"
+ let gLinkSchema2 = linkAnotherSchema gLink
+ alice ##> ("/_connect plan 1 " <> gLinkSchema2)
+ alice <## "group link: own link for group #team"
+
alice ##> ("/c " <> gLink)
alice <## "connection request sent!"
alice <## "alice_1 (Alice): accepting request to join group #team..."
@@ -2373,6 +2387,9 @@ testPlanGroupLinkOwn tmp =
alice ##> ("/_connect plan 1 " <> gLink)
alice <## "group link: own link for group #team"
+ alice ##> ("/_connect plan 1 " <> gLinkSchema2)
+ alice <## "group link: own link for group #team"
+
-- group works if merged contact is deleted
alice ##> "/d alice_1"
alice <## "alice_1: contact is deleted"
@@ -2397,8 +2414,19 @@ testPlanGroupLinkConnecting tmp = do
alice ##> "/create link #team"
getGroupLink alice "team" GRMember True
withNewTestChat tmp "bob" bobProfile $ \bob -> do
+ threadDelay 100000
+
bob ##> ("/c " <> gLink)
bob <## "connection request sent!"
+
+ bob ##> ("/_connect plan 1 " <> gLink)
+ bob <## "group link: connecting, allowed to reconnect"
+
+ let gLinkSchema2 = linkAnotherSchema gLink
+ bob ##> ("/_connect plan 1 " <> gLinkSchema2)
+ bob <## "group link: connecting, allowed to reconnect"
+
+ threadDelay 100000
withTestChat tmp "alice" $ \alice -> do
alice
<### [ "1 group links active",
@@ -2410,6 +2438,10 @@ testPlanGroupLinkConnecting tmp = do
bob ##> ("/_connect plan 1 " <> gLink)
bob <## "group link: connecting"
+ let gLinkSchema2 = linkAnotherSchema gLink
+ bob ##> ("/_connect plan 1 " <> gLinkSchema2)
+ bob <## "group link: connecting"
+
bob ##> ("/c " <> gLink)
bob <## "group link: connecting"
@@ -2455,6 +2487,10 @@ testPlanGroupLinkLeaveRejoin =
bob ##> ("/_connect plan 1 " <> gLink)
bob <## "group link: ok to connect"
+ let gLinkSchema2 = linkAnotherSchema gLink
+ bob ##> ("/_connect plan 1 " <> gLinkSchema2)
+ bob <## "group link: ok to connect"
+
bob ##> ("/c " <> gLink)
bob <## "connection request sent!"
alice <## "bob_1 (Bob): accepting request to join group #team..."
@@ -2483,6 +2519,10 @@ testPlanGroupLinkLeaveRejoin =
bob <## "group link: known group #team_1"
bob <## "use #team_1 to send messages"
+ bob ##> ("/_connect plan 1 " <> gLinkSchema2)
+ bob <## "group link: known group #team_1"
+ bob <## "use #team_1 to send messages"
+
bob ##> ("/c " <> gLink)
bob <## "group link: known group #team_1"
bob <## "use #team_1 to send messages"
diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs
index 80e170922..68b925342 100644
--- a/tests/ChatTests/Profiles.hs
+++ b/tests/ChatTests/Profiles.hs
@@ -599,6 +599,11 @@ testPlanAddressOkKnown =
bob <## "contact address: known contact alice"
bob <## "use @alice to send messages"
+ let cLinkSchema2 = linkAnotherSchema cLink
+ bob ##> ("/_connect plan 1 " <> cLinkSchema2)
+ bob <## "contact address: known contact alice"
+ bob <## "use @alice to send messages"
+
bob ##> ("/c " <> cLink)
bob <## "contact address: known contact alice"
bob <## "use @alice to send messages"
@@ -612,11 +617,15 @@ testPlanAddressOwn tmp =
alice ##> ("/_connect plan 1 " <> cLink)
alice <## "contact address: own address"
+ let cLinkSchema2 = linkAnotherSchema cLink
+ alice ##> ("/_connect plan 1 " <> cLinkSchema2)
+ alice <## "contact address: own address"
+
alice ##> ("/c " <> cLink)
alice <## "connection request sent!"
alice <## "alice_1 (Alice) wants to connect to you!"
alice <## "to accept: /ac alice_1"
- alice <## ("to reject: /rc alice_1 (the sender will NOT be notified)")
+ alice <## "to reject: /rc alice_1 (the sender will NOT be notified)"
alice @@@ [("<@alice_1", ""), (":2","")]
alice ##> "/ac alice_1"
alice <## "alice_1 (Alice): accepting contact request..."
@@ -651,8 +660,17 @@ testPlanAddressConnecting tmp = do
getContactLink alice True
withNewTestChat tmp "bob" bobProfile $ \bob -> do
threadDelay 100000
+
bob ##> ("/c " <> cLink)
bob <## "connection request sent!"
+
+ bob ##> ("/_connect plan 1 " <> cLink)
+ bob <## "contact address: connecting, allowed to reconnect"
+
+ let cLinkSchema2 = linkAnotherSchema cLink
+ bob ##> ("/_connect plan 1 " <> cLinkSchema2)
+ bob <## "contact address: connecting, allowed to reconnect"
+
threadDelay 100000
withTestChat tmp "alice" $ \alice -> do
alice <## "Your address is active! To show: /sa"
@@ -667,6 +685,10 @@ testPlanAddressConnecting tmp = do
bob ##> ("/_connect plan 1 " <> cLink)
bob <## "contact address: connecting to contact alice"
+ let cLinkSchema2 = linkAnotherSchema cLink
+ bob ##> ("/_connect plan 1 " <> cLinkSchema2)
+ bob <## "contact address: connecting to contact alice"
+
bob ##> ("/c " <> cLink)
bob <## "contact address: connecting to contact alice"
@@ -701,6 +723,10 @@ testPlanAddressContactDeletedReconnected =
bob ##> ("/_connect plan 1 " <> cLink)
bob <## "contact address: ok to connect"
+ let cLinkSchema2 = linkAnotherSchema cLink
+ bob ##> ("/_connect plan 1 " <> cLinkSchema2)
+ bob <## "contact address: ok to connect"
+
bob ##> ("/c " <> cLink)
bob <## "connection request sent!"
alice <## "bob (Bob) wants to connect to you!"
@@ -721,6 +747,10 @@ testPlanAddressContactDeletedReconnected =
bob <## "contact address: known contact alice_1"
bob <## "use @alice_1 to send messages"
+ bob ##> ("/_connect plan 1 " <> cLinkSchema2)
+ bob <## "contact address: known contact alice_1"
+ bob <## "use @alice_1 to send messages"
+
bob ##> ("/c " <> cLink)
bob <## "contact address: known contact alice_1"
bob <## "use @alice_1 to send messages"
diff --git a/tests/ChatTests/Utils.hs b/tests/ChatTests/Utils.hs
index d98431e81..fcb6b65e4 100644
--- a/tests/ChatTests/Utils.hs
+++ b/tests/ChatTests/Utils.hs
@@ -559,3 +559,11 @@ currentChatVRangeInfo =
vRangeStr :: VersionRange -> String
vRangeStr (VersionRange minVer maxVer) = "(" <> show minVer <> ", " <> show maxVer <> ")"
+
+linkAnotherSchema :: String -> String
+linkAnotherSchema link
+ | "https://simplex.chat/" `isPrefixOf` link =
+ T.unpack $ T.replace "https://simplex.chat/" "simplex:/" $ T.pack link
+ | "simplex:/" `isPrefixOf` link =
+ T.unpack $ T.replace "simplex:/" "https://simplex.chat/" $ T.pack link
+ | otherwise = error "link starts with neither https://simplex.chat/ nor simplex:/"
diff --git a/tests/MarkdownTests.hs b/tests/MarkdownTests.hs
index 837849d7e..83a180c74 100644
--- a/tests/MarkdownTests.hs
+++ b/tests/MarkdownTests.hs
@@ -137,8 +137,8 @@ textColor = describe "text color (red)" do
uri :: Text -> Markdown
uri = Markdown $ Just Uri
-simplexLink :: SimplexLinkType -> Text -> Bool -> NonEmpty Text -> Text -> Markdown
-simplexLink linkType simplexUri trustedUri smpHosts = Markdown $ Just SimplexLink {linkType, simplexUri, trustedUri, smpHosts}
+simplexLink :: SimplexLinkType -> Text -> NonEmpty Text -> Text -> Markdown
+simplexLink linkType simplexUri smpHosts = Markdown $ Just SimplexLink {linkType, simplexUri, smpHosts}
textWithUri :: Spec
textWithUri = describe "text with Uri" do
@@ -152,13 +152,13 @@ textWithUri = describe "text with Uri" do
parseMarkdown "this is _https://simplex.chat" `shouldBe` "this is _https://simplex.chat"
it "SimpleX links" do
let inv = "/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D"
- parseMarkdown ("https://simplex.chat" <> inv) `shouldBe` simplexLink XLInvitation ("simplex:" <> inv) True ["smp.simplex.im"] ("https://simplex.chat" <> inv)
- parseMarkdown ("simplex:" <> inv) `shouldBe` simplexLink XLInvitation ("simplex:" <> inv) True ["smp.simplex.im"] ("simplex:" <> inv)
- parseMarkdown ("https://example.com" <> inv) `shouldBe` simplexLink XLInvitation ("simplex:" <> inv) False ["smp.simplex.im"] ("https://example.com" <> inv)
+ parseMarkdown ("https://simplex.chat" <> inv) `shouldBe` simplexLink XLInvitation ("simplex:" <> inv) ["smp.simplex.im"] ("https://simplex.chat" <> inv)
+ parseMarkdown ("simplex:" <> inv) `shouldBe` simplexLink XLInvitation ("simplex:" <> inv) ["smp.simplex.im"] ("simplex:" <> inv)
+ parseMarkdown ("https://example.com" <> inv) `shouldBe` simplexLink XLInvitation ("simplex:" <> inv) ["smp.simplex.im"] ("https://example.com" <> inv)
let ct = "/contact#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D"
- parseMarkdown ("https://simplex.chat" <> ct) `shouldBe` simplexLink XLContact ("simplex:" <> ct) True ["smp.simplex.im"] ("https://simplex.chat" <> ct)
+ parseMarkdown ("https://simplex.chat" <> ct) `shouldBe` simplexLink XLContact ("simplex:" <> ct) ["smp.simplex.im"] ("https://simplex.chat" <> ct)
let gr = "/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2FWHV0YU1sYlU7NqiEHkHDB6gxO1ofTync%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAWbebOqVYuBXaiqHcXYjEHCpYi6VzDlu6CVaijDTmsQU%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22mL-7Divb94GGmGmRBef5Dg%3D%3D%22%7D"
- parseMarkdown ("https://simplex.chat" <> gr) `shouldBe` simplexLink XLGroup ("simplex:" <> gr) True ["smp4.simplex.im", "o5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion"] ("https://simplex.chat" <> gr)
+ parseMarkdown ("https://simplex.chat" <> gr) `shouldBe` simplexLink XLGroup ("simplex:" <> gr) ["smp4.simplex.im", "o5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion"] ("https://simplex.chat" <> gr)
email :: Text -> Markdown
email = Markdown $ Just Email
diff --git a/tests/ProtocolTests.hs b/tests/ProtocolTests.hs
index d62d7a470..0b99c5a4d 100644
--- a/tests/ProtocolTests.hs
+++ b/tests/ProtocolTests.hs
@@ -39,7 +39,7 @@ queue =
connReqData :: ConnReqUriData
connReqData =
ConnReqUriData
- { crScheme = simplexChat,
+ { crScheme = CRSSimplex,
crAgentVRange = mkVersionRange 1 1,
crSmpQueues = [queue],
crClientData = Nothing
@@ -184,7 +184,7 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
"{\"v\":\"1\",\"event\":\"x.msg.deleted\",\"params\":{}}"
#==# XMsgDeleted
it "x.file" $
- "{\"v\":\"1\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}"
+ "{\"v\":\"1\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}"
#==# XFile FileInvitation {fileName = "photo.jpg", fileSize = 12345, fileDigest = Nothing, fileConnReq = Just testConnReq, fileInline = Nothing, fileDescr = Nothing}
it "x.file without file invitation" $
"{\"v\":\"1\",\"event\":\"x.file\",\"params\":{\"file\":{\"fileSize\":12345,\"fileName\":\"photo.jpg\"}}}"
@@ -193,7 +193,7 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
"{\"v\":\"1\",\"event\":\"x.file.acpt\",\"params\":{\"fileName\":\"photo.jpg\"}}"
#==# XFileAcpt "photo.jpg"
it "x.file.acpt.inv" $
- "{\"v\":\"1\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\",\"fileConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}"
+ "{\"v\":\"1\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\",\"fileConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}"
#==# XFileAcptInv (SharedMsgId "\1\2\3\4") (Just testConnReq) "photo.jpg"
it "x.file.acpt.inv" $
"{\"v\":\"1\",\"event\":\"x.file.acpt.inv\",\"params\":{\"msgId\":\"AQIDBA==\",\"fileName\":\"photo.jpg\"}}"
@@ -220,10 +220,10 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
"{\"v\":\"1\",\"event\":\"x.contact\",\"params\":{\"content\":{\"text\":\"hello\",\"type\":\"text\"},\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}"
==# XContact testProfile Nothing
it "x.grp.inv" $
- "{\"v\":\"1\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}}}}"
#==# XGrpInv GroupInvitation {fromMember = MemberIdRole (MemberId "\1\2\3\4") GRAdmin, invitedMember = MemberIdRole (MemberId "\5\6\7\8") GRMember, connRequest = testConnReq, groupProfile = testGroupProfile, groupLinkId = Nothing}
it "x.grp.inv with group link id" $
- "{\"v\":\"1\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}, \"groupLinkId\":\"AQIDBA==\"}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.inv\",\"params\":{\"groupInvitation\":{\"connRequest\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"invitedMember\":{\"memberRole\":\"member\",\"memberId\":\"BQYHCA==\"},\"groupProfile\":{\"fullName\":\"Team\",\"displayName\":\"team\",\"groupPreferences\":{\"reactions\":{\"enable\":\"on\"},\"voice\":{\"enable\":\"on\"}}},\"fromMember\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\"}, \"groupLinkId\":\"AQIDBA==\"}}}"
#==# XGrpInv GroupInvitation {fromMember = MemberIdRole (MemberId "\1\2\3\4") GRAdmin, invitedMember = MemberIdRole (MemberId "\5\6\7\8") GRMember, connRequest = testConnReq, groupProfile = testGroupProfile, groupLinkId = Just $ GroupLinkId "\1\2\3\4"}
it "x.grp.acpt without incognito profile" $
"{\"v\":\"1\",\"event\":\"x.grp.acpt\",\"params\":{\"memberId\":\"AQIDBA==\"}}"
@@ -241,16 +241,16 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
"{\"v\":\"1\",\"event\":\"x.grp.mem.intro\",\"params\":{\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-2\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}"
#==# XGrpMemIntro MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Just $ ChatVersionRange supportedChatVRange, profile = testProfile}
it "x.grp.mem.inv" $
- "{\"v\":\"1\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"directConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"directConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}"
#==# XGrpMemInv (MemberId "\1\2\3\4") IntroInvitation {groupConnReq = testConnReq, directConnReq = Just testConnReq}
it "x.grp.mem.inv w/t directConnReq" $
- "{\"v\":\"1\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"groupConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.mem.inv\",\"params\":{\"memberId\":\"AQIDBA==\",\"memberIntro\":{\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}}"
#==# XGrpMemInv (MemberId "\1\2\3\4") IntroInvitation {groupConnReq = testConnReq, directConnReq = Nothing}
it "x.grp.mem.fwd" $
- "{\"v\":\"1\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"directConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"directConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\",\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}"
#==# XGrpMemFwd MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Nothing, profile = testProfile} IntroInvitation {groupConnReq = testConnReq, directConnReq = Just testConnReq}
it "x.grp.mem.fwd with member chat version range and w/t directConnReq" $
- "{\"v\":\"1\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"groupConnReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-2\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.mem.fwd\",\"params\":{\"memberIntro\":{\"groupConnReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"},\"memberInfo\":{\"memberRole\":\"admin\",\"memberId\":\"AQIDBA==\",\"v\":\"1-2\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}}"
#==# XGrpMemFwd MemberInfo {memberId = MemberId "\1\2\3\4", memberRole = GRAdmin, v = Just $ ChatVersionRange supportedChatVRange, profile = testProfile} IntroInvitation {groupConnReq = testConnReq, directConnReq = Nothing}
it "x.grp.mem.info" $
"{\"v\":\"1\",\"event\":\"x.grp.mem.info\",\"params\":{\"memberId\":\"AQIDBA==\",\"profile\":{\"fullName\":\"Alice\",\"displayName\":\"alice\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\",\"preferences\":{\"reactions\":{\"allow\":\"yes\"},\"voice\":{\"allow\":\"yes\"}}}}}"
@@ -271,10 +271,10 @@ decodeChatMessageTest = describe "Chat message encoding/decoding" $ do
"{\"v\":\"1\",\"event\":\"x.grp.del\",\"params\":{}}"
==# XGrpDel
it "x.grp.direct.inv" $
- "{\"v\":\"1\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\", \"content\":{\"text\":\"hello\",\"type\":\"text\"}}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\", \"content\":{\"text\":\"hello\",\"type\":\"text\"}}}"
#==# XGrpDirectInv testConnReq (Just $ MCText "hello")
it "x.grp.direct.inv without content" $
- "{\"v\":\"1\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"https://simplex.chat/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}"
+ "{\"v\":\"1\",\"event\":\"x.grp.direct.inv\",\"params\":{\"connReq\":\"simplex:/invitation#/?v=1&smp=smp%3A%2F%2F1234-w%3D%3D%40smp.simplex.im%3A5223%2F3456-w%3D%3D%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAjiswwI3O_NlS8Fk3HJUW870EY2bAwmttMBsvRB9eV3o%253D&e2e=v%3D1-2%26x3dh%3DMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D%2CMEIwBQYDK2VvAzkAmKuSYeQ_m0SixPDS8Wq8VBaTS1cW-Lp0n0h4Diu-kUpR-qXx4SDJ32YGEFoGFGSbGPry5Ychr6U%3D\"}}"
#==# XGrpDirectInv testConnReq Nothing
it "x.info.probe" $
"{\"v\":\"1\",\"event\":\"x.info.probe\",\"params\":{\"probe\":\"AQIDBA==\"}}"