core, ui: create all links with short links, config parameter to use large link data, use short link as address in user profile (#5991)

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
This commit is contained in:
Evgeny
2025-06-17 15:56:33 +04:00
committed by spaced4ndy
co-authored by spaced4ndy
parent c08a3e7c4a
commit e3e9ae2ffd
46 changed files with 413 additions and 323 deletions
+8 -8
View File
@@ -23,7 +23,7 @@ enum ChatCommand: ChatCmdProtocol {
case apiMuteUser(userId: Int64)
case apiUnmuteUser(userId: Int64)
case apiDeleteUser(userId: Int64, delSMPQueues: Bool, viewPwd: String?)
case startChat(mainApp: Bool, enableSndFiles: Bool)
case startChat(mainApp: Bool, enableSndFiles: Bool, largeLinkData: Bool)
case checkChatRunning
case apiStopChat
case apiActivateChat(restoreChat: Bool)
@@ -76,7 +76,7 @@ enum ChatCommand: ChatCmdProtocol {
case apiLeaveGroup(groupId: Int64)
case apiListMembers(groupId: Int64)
case apiUpdateGroupProfile(groupId: Int64, groupProfile: GroupProfile)
case apiCreateGroupLink(groupId: Int64, memberRole: GroupMemberRole, short: Bool)
case apiCreateGroupLink(groupId: Int64, memberRole: GroupMemberRole)
case apiGroupLinkMemberRole(groupId: Int64, memberRole: GroupMemberRole)
case apiDeleteGroupLink(groupId: Int64)
case apiGetGroupLink(groupId: Int64)
@@ -116,7 +116,7 @@ enum ChatCommand: ChatCmdProtocol {
case apiGetGroupMemberCode(groupId: Int64, groupMemberId: Int64)
case apiVerifyContact(contactId: Int64, connectionCode: String?)
case apiVerifyGroupMember(groupId: Int64, groupMemberId: Int64, connectionCode: String?)
case apiAddContact(userId: Int64, short: Bool, incognito: Bool)
case apiAddContact(userId: Int64, incognito: Bool)
case apiSetConnectionIncognito(connId: Int64, incognito: Bool)
case apiChangeConnectionUser(connId: Int64, userId: Int64)
case apiConnectPlan(userId: Int64, connLink: String)
@@ -138,7 +138,7 @@ enum ChatCommand: ChatCmdProtocol {
case apiSetConnectionAlias(connId: Int64, localAlias: String)
case apiSetUserUIThemes(userId: Int64, themes: ThemeModeOverrides?)
case apiSetChatUIThemes(chatId: String, themes: ThemeModeOverrides?)
case apiCreateMyAddress(userId: Int64, short: Bool)
case apiCreateMyAddress(userId: Int64)
case apiDeleteMyAddress(userId: Int64)
case apiShowMyAddress(userId: Int64)
case apiAddMyAddressShortLink(userId: Int64)
@@ -203,7 +203,7 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiMuteUser(userId): return "/_mute user \(userId)"
case let .apiUnmuteUser(userId): return "/_unmute user \(userId)"
case let .apiDeleteUser(userId, delSMPQueues, viewPwd): return "/_delete user \(userId) del_smp=\(onOff(delSMPQueues))\(maybePwd(viewPwd))"
case let .startChat(mainApp, enableSndFiles): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles))"
case let .startChat(mainApp, enableSndFiles, largeLinkData): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles)) large_link_data=\(onOff(largeLinkData))"
case .checkChatRunning: return "/_check running"
case .apiStopChat: return "/_stop"
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
@@ -266,7 +266,7 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiLeaveGroup(groupId): return "/_leave #\(groupId)"
case let .apiListMembers(groupId): return "/_members #\(groupId)"
case let .apiUpdateGroupProfile(groupId, groupProfile): return "/_group_profile #\(groupId) \(encodeJSON(groupProfile))"
case let .apiCreateGroupLink(groupId, memberRole, short): return "/_create link #\(groupId) \(memberRole) short=\(onOff(short))"
case let .apiCreateGroupLink(groupId, memberRole): return "/_create link #\(groupId) \(memberRole)"
case let .apiGroupLinkMemberRole(groupId, memberRole): return "/_set link role #\(groupId) \(memberRole)"
case let .apiDeleteGroupLink(groupId): return "/_delete link #\(groupId)"
case let .apiGetGroupLink(groupId): return "/_get link #\(groupId)"
@@ -316,7 +316,7 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiVerifyContact(contactId, .none): return "/_verify code @\(contactId)"
case let .apiVerifyGroupMember(groupId, groupMemberId, .some(connectionCode)): return "/_verify code #\(groupId) \(groupMemberId) \(connectionCode)"
case let .apiVerifyGroupMember(groupId, groupMemberId, .none): return "/_verify code #\(groupId) \(groupMemberId)"
case let .apiAddContact(userId, short, incognito): return "/_connect \(userId) short=\(onOff(short)) incognito=\(onOff(incognito))"
case let .apiAddContact(userId, incognito): return "/_connect \(userId) incognito=\(onOff(incognito))"
case let .apiSetConnectionIncognito(connId, incognito): return "/_set incognito :\(connId) \(onOff(incognito))"
case let .apiChangeConnectionUser(connId, userId): return "/_set conn user :\(connId) \(userId)"
case let .apiConnectPlan(userId, connLink): return "/_connect plan \(userId) \(connLink)"
@@ -338,7 +338,7 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiSetConnectionAlias(connId, localAlias): return "/_set alias :\(connId) \(localAlias.trimmingCharacters(in: .whitespaces))"
case let .apiSetUserUIThemes(userId, themes): return "/_set theme user \(userId) \(themes != nil ? encodeJSON(themes) : "")"
case let .apiSetChatUIThemes(chatId, themes): return "/_set theme \(chatId) \(themes != nil ? encodeJSON(themes) : "")"
case let .apiCreateMyAddress(userId, short): return "/_address \(userId) short=\(onOff(short))"
case let .apiCreateMyAddress(userId): return "/_address \(userId)"
case let .apiDeleteMyAddress(userId): return "/_delete_address \(userId)"
case let .apiShowMyAddress(userId): return "/_show_address \(userId)"
case let .apiAddMyAddressShortLink(userId): return "/_short_link_address \(userId)"
+5 -7
View File
@@ -227,7 +227,7 @@ func apiDeleteUser(_ userId: Int64, _ delSMPQueues: Bool, viewPwd: String?) asyn
}
func apiStartChat(ctrl: chat_ctrl? = nil) throws -> Bool {
let r: ChatResponse0 = try chatSendCmdSync(.startChat(mainApp: true, enableSndFiles: true), ctrl: ctrl)
let r: ChatResponse0 = try chatSendCmdSync(.startChat(mainApp: true, enableSndFiles: true, largeLinkData: false), ctrl: ctrl)
switch r {
case .chatStarted: return true
case .chatRunning: return false
@@ -874,8 +874,7 @@ func apiAddContact(incognito: Bool) async -> ((CreatedConnLink, PendingContactCo
logger.error("apiAddContact: no current user")
return (nil, nil)
}
let short = UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_SHORT_LINKS)
let r: APIResult<ChatResponse1> = await chatApiSendCmd(.apiAddContact(userId: userId, short: short, incognito: incognito), bgTask: false)
let r: APIResult<ChatResponse1> = await chatApiSendCmd(.apiAddContact(userId: userId, incognito: incognito), bgTask: false)
if case let .result(.invitation(_, connLinkInv, connection)) = r { return ((connLinkInv, connection), nil) }
let alert = connectionErrorAlert(r)
return (nil, alert)
@@ -1215,9 +1214,9 @@ func apiSetChatUIThemes(chatId: ChatId, themes: ThemeModeOverrides?) async -> Bo
}
func apiCreateUserAddress(short: Bool) async throws -> CreatedConnLink {
func apiCreateUserAddress() async throws -> CreatedConnLink {
let userId = try currentUserId("apiCreateUserAddress")
let r: ChatResponse1 = try await chatSendCmd(.apiCreateMyAddress(userId: userId, short: short))
let r: ChatResponse1 = try await chatSendCmd(.apiCreateMyAddress(userId: userId))
if case let .userContactLinkCreated(_, connLink) = r { return connLink }
throw r.unexpected
}
@@ -1770,8 +1769,7 @@ func apiUpdateGroup(_ groupId: Int64, _ groupProfile: GroupProfile) async throws
}
func apiCreateGroupLink(_ groupId: Int64, memberRole: GroupMemberRole = .member) async throws -> GroupLink {
let short = UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_SHORT_LINKS)
let r: ChatResponse2 = try await chatSendCmd(.apiCreateGroupLink(groupId: groupId, memberRole: memberRole, short: short))
let r: ChatResponse2 = try await chatSendCmd(.apiCreateGroupLink(groupId: groupId, memberRole: memberRole))
if case let .groupLinkCreated(_, _, groupLink) = r { return groupLink }
throw r.unexpected
}
@@ -86,19 +86,17 @@ struct GroupLinkView: View {
Label("Share link", systemImage: "square.and.arrow.up")
}
if UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_SHORT_LINKS) {
if groupLink.connLinkContact.connShortLink == nil {
Button {
addShortLink()
} label: {
Label("Add short link", systemImage: "plus")
}
} else if !groupLink.shortLinkDataSet {
Button {
addShortLink()
} label: {
Label("Share group profile via link", systemImage: "plus")
}
if groupLink.connLinkContact.connShortLink == nil {
Button {
addShortLink()
} label: {
Label("Add short link", systemImage: "plus")
}
} else if !groupLink.shortLinkDataSet {
Button {
addShortLink()
} label: {
Label("Share group profile via link", systemImage: "plus")
}
}
@@ -77,10 +77,9 @@ struct CreateSimpleXAddress: View {
progressIndicator = true
Task {
do {
let short = false
let connLinkContact = try await apiCreateUserAddress(short: short)
let connLinkContact = try await apiCreateUserAddress()
DispatchQueue.main.async {
m.userAddress = UserContactLink(connLinkContact: connLinkContact, shortLinkDataSet: short)
m.userAddress = UserContactLink(connLinkContact: connLinkContact, shortLinkDataSet: connLinkContact.connShortLink != nil)
}
await MainActor.run { progressIndicator = false }
} catch let error {
@@ -20,7 +20,6 @@ struct PrivacySettings: View {
@AppStorage(GROUP_DEFAULT_PRIVACY_ASK_TO_APPROVE_RELAYS, store: groupDefaults) private var askToApproveRelays = true
@State private var simplexLinkMode = privacySimplexLinkModeDefault.get()
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@AppStorage(DEFAULT_PRIVACY_SHORT_LINKS) private var shortSimplexLinks = false
@AppStorage(DEFAULT_PRIVACY_PROTECT_SCREEN) private var protectScreen = false
@AppStorage(DEFAULT_PERFORM_LA) private var prefPerformLA = false
@State private var currentLAMode = privacyLocalAuthModeDefault.get()
@@ -101,11 +100,6 @@ struct PrivacySettings: View {
.onChange(of: simplexLinkMode) { mode in
privacySimplexLinkModeDefault.set(mode)
}
if developerTools {
settingsRow("link.badge.plus", color: theme.colors.secondary) {
Toggle("Use short links (BETA)", isOn: $shortSimplexLinks)
}
}
} header: {
Text("Chats")
.foregroundColor(theme.colors.secondary)
@@ -32,7 +32,6 @@ let DEFAULT_PRIVACY_LINK_PREVIEWS = "privacyLinkPreviews" // deprecated, moved t
let DEFAULT_PRIVACY_SIMPLEX_LINK_MODE = "privacySimplexLinkMode"
let DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS = "privacyShowChatPreviews"
let DEFAULT_PRIVACY_SAVE_LAST_DRAFT = "privacySaveLastDraft"
let DEFAULT_PRIVACY_SHORT_LINKS = "privacyShortLinks"
let DEFAULT_PRIVACY_PROTECT_SCREEN = "privacyProtectScreen"
let DEFAULT_PRIVACY_DELIVERY_RECEIPTS_SET = "privacyDeliveryReceiptsSet"
let DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS = "privacyMediaBlurRadius"
@@ -100,7 +99,6 @@ let appDefaults: [String: Any] = [
DEFAULT_PRIVACY_SIMPLEX_LINK_MODE: SimpleXLinkMode.description.rawValue,
DEFAULT_PRIVACY_SHOW_CHAT_PREVIEWS: true,
DEFAULT_PRIVACY_SAVE_LAST_DRAFT: true,
DEFAULT_PRIVACY_SHORT_LINKS: false,
DEFAULT_PRIVACY_PROTECT_SCREEN: false,
DEFAULT_PRIVACY_DELIVERY_RECEIPTS_SET: false,
DEFAULT_PRIVACY_MEDIA_BLUR_RADIUS: 0,
@@ -153,12 +153,10 @@ struct UserAddressView: View {
}
}
addressSettingsButton(userAddress)
if UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_SHORT_LINKS) {
if userAddress.connLinkContact.connShortLink == nil {
addShortLinkButton()
} else if !userAddress.shortLinkDataSet {
addProfileToShortLinkButton()
}
if userAddress.connLinkContact.connShortLink == nil {
addShortLinkButton()
} else if !userAddress.shortLinkDataSet {
addProfileToShortLinkButton()
}
} header: {
ToggleShortLinkHeader(text: Text("For social media"), link: userAddress.connLinkContact, short: $showShortLink)
@@ -200,10 +198,9 @@ struct UserAddressView: View {
progressIndicator = true
Task {
do {
let short = UserDefaults.standard.bool(forKey: DEFAULT_PRIVACY_SHORT_LINKS)
let connLinkContact = try await apiCreateUserAddress(short: short)
let connLinkContact = try await apiCreateUserAddress()
DispatchQueue.main.async {
chatModel.userAddress = UserContactLink(connLinkContact: connLinkContact, shortLinkDataSet: short)
chatModel.userAddress = UserContactLink(connLinkContact: connLinkContact, shortLinkDataSet: connLinkContact.connShortLink != nil)
alert = .shareOnCreate
progressIndicator = false
}
-3
View File
@@ -5551,9 +5551,6 @@ report reason */
/* No comment provided by engineer. */
"Use servers" = "Verwende Server";
/* No comment provided by engineer. */
"Use short links (BETA)" = "Kurze Links verwenden (BETA)";
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Verwenden Sie SimpleX-Chat-Server?";
-3
View File
@@ -5551,9 +5551,6 @@ report reason */
/* No comment provided by engineer. */
"Use servers" = "Usar servidores";
/* No comment provided by engineer. */
"Use short links (BETA)" = "Usar enlaces cortos (BETA)";
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "¿Usar servidores SimpleX Chat?";
-3
View File
@@ -5551,9 +5551,6 @@ report reason */
/* No comment provided by engineer. */
"Use servers" = "Kiszolgálók használata";
/* No comment provided by engineer. */
"Use short links (BETA)" = "Rövid hivatkozások használata (béta)";
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "SimpleX Chat kiszolgálók használata?";
-3
View File
@@ -5551,9 +5551,6 @@ report reason */
/* No comment provided by engineer. */
"Use servers" = "Usa i server";
/* No comment provided by engineer. */
"Use short links (BETA)" = "Usa link brevi (BETA)";
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Usare i server di SimpleX Chat?";
-3
View File
@@ -5551,9 +5551,6 @@ report reason */
/* No comment provided by engineer. */
"Use servers" = "Gebruik servers";
/* No comment provided by engineer. */
"Use short links (BETA)" = "Gebruik korte links (BETA)";
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "SimpleX Chat servers gebruiken?";
-3
View File
@@ -5551,9 +5551,6 @@ report reason */
/* No comment provided by engineer. */
"Use servers" = "Использовать серверы";
/* No comment provided by engineer. */
"Use short links (BETA)" = "Короткие ссылки (БЕТА)";
/* No comment provided by engineer. */
"Use SimpleX Chat servers?" = "Использовать серверы предосталенные SimpleX Chat?";
@@ -107,7 +107,6 @@ class AppPreferences {
val simplexLinkMode: SharedPreference<SimplexLinkMode> = mkSafeEnumPreference(SHARED_PREFS_PRIVACY_SIMPLEX_LINK_MODE, SimplexLinkMode.default)
val privacyShowChatPreviews = mkBoolPreference(SHARED_PREFS_PRIVACY_SHOW_CHAT_PREVIEWS, true)
val privacySaveLastDraft = mkBoolPreference(SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT, true)
val privacyShortLinks = mkBoolPreference(SHARED_PREFS_PRIVACY_SHORT_LINKS, false)
val privacyDeliveryReceiptsSet = mkBoolPreference(SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET, false)
val privacyEncryptLocalFiles = mkBoolPreference(SHARED_PREFS_PRIVACY_ENCRYPT_LOCAL_FILES, true)
val privacyAskToApproveRelays = mkBoolPreference(SHARED_PREFS_PRIVACY_ASK_TO_APPROVE_RELAYS, true)
@@ -370,7 +369,6 @@ class AppPreferences {
private const val SHARED_PREFS_PRIVACY_SIMPLEX_LINK_MODE = "PrivacySimplexLinkMode"
private const val SHARED_PREFS_PRIVACY_SHOW_CHAT_PREVIEWS = "PrivacyShowChatPreviews"
private const val SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT = "PrivacySaveLastDraft"
private const val SHARED_PREFS_PRIVACY_SHORT_LINKS = "PrivacyShortLinks"
private const val SHARED_PREFS_PRIVACY_DELIVERY_RECEIPTS_SET = "PrivacyDeliveryReceiptsSet"
private const val SHARED_PREFS_PRIVACY_ENCRYPT_LOCAL_FILES = "PrivacyEncryptLocalFiles"
private const val SHARED_PREFS_PRIVACY_ASK_TO_APPROVE_RELAYS = "PrivacyAskToApproveRelays"
@@ -795,7 +793,7 @@ object ChatController {
}
suspend fun apiStartChat(ctrl: ChatCtrl? = null): Boolean {
val r = sendCmd(null, CC.StartChat(mainApp = true), ctrl)
val r = sendCmd(null, CC.StartChat(mainApp = true, largeLinkData = false), ctrl)
when (r.result) {
is CR.ChatStarted -> return true
is CR.ChatRunning -> return false
@@ -1295,8 +1293,7 @@ object ChatController {
suspend fun apiAddContact(rh: Long?, incognito: Boolean): Pair<Pair<CreatedConnLink, PendingContactConnection>?, (() -> Unit)?> {
val userId = try { currentUserId("apiAddContact") } catch (e: Exception) { return null to null }
val short = appPrefs.privacyShortLinks.get()
val r = sendCmd(rh, CC.APIAddContact(userId, short = short, incognito = incognito))
val r = sendCmd(rh, CC.APIAddContact(userId, incognito = incognito))
return when {
r is API.Result && r.res is CR.Invitation -> (r.res.connLinkInvitation to r.res.connection) to null
!(networkErrorAlert(r)) -> null to { apiErrorAlert("apiAddContact", generalGetString(MR.strings.connection_error), r) }
@@ -1539,9 +1536,9 @@ object ChatController {
return false
}
suspend fun apiCreateUserAddress(rh: Long?, short: Boolean): CreatedConnLink? {
suspend fun apiCreateUserAddress(rh: Long?): CreatedConnLink? {
val userId = kotlin.runCatching { currentUserId("apiCreateUserAddress") }.getOrElse { return null }
val r = sendCmd(rh, CC.ApiCreateMyAddress(userId, short))
val r = sendCmd(rh, CC.ApiCreateMyAddress(userId))
if (r is API.Result && r.res is CR.UserContactLinkCreated) return r.res.connLinkContact
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiCreateUserAddress", generalGetString(MR.strings.error_creating_address), r)
@@ -1992,8 +1989,7 @@ object ChatController {
}
suspend fun apiCreateGroupLink(rh: Long?, groupId: Long, memberRole: GroupMemberRole = GroupMemberRole.Member): Pair<CreatedConnLink, GroupMemberRole>? {
val short = appPrefs.privacyShortLinks.get()
val r = sendCmd(rh, CC.APICreateGroupLink(groupId, memberRole, short))
val r = sendCmd(rh, CC.APICreateGroupLink(groupId, memberRole))
if (r is API.Result && r.res is CR.GroupLinkCreated) return r.res.connLinkContact to r.res.memberRole
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiCreateGroupLink", generalGetString(MR.strings.error_creating_link_for_group), r)
@@ -3338,7 +3334,7 @@ sealed class CC {
class ApiMuteUser(val userId: Long): CC()
class ApiUnmuteUser(val userId: Long): CC()
class ApiDeleteUser(val userId: Long, val delSMPQueues: Boolean, val viewPwd: String?): CC()
class StartChat(val mainApp: Boolean): CC()
class StartChat(val mainApp: Boolean, val largeLinkData: Boolean): CC()
class CheckChatRunning: CC()
class ApiStopChat: CC()
@Serializable
@@ -3383,7 +3379,7 @@ sealed class CC {
class ApiLeaveGroup(val groupId: Long): CC()
class ApiListMembers(val groupId: Long): CC()
class ApiUpdateGroupProfile(val groupId: Long, val groupProfile: GroupProfile): CC()
class APICreateGroupLink(val groupId: Long, val memberRole: GroupMemberRole, val short: Boolean): CC()
class APICreateGroupLink(val groupId: Long, val memberRole: GroupMemberRole): CC()
class APIGroupLinkMemberRole(val groupId: Long, val memberRole: GroupMemberRole): CC()
class APIDeleteGroupLink(val groupId: Long): CC()
class APIGetGroupLink(val groupId: Long): CC()
@@ -3423,7 +3419,7 @@ sealed class CC {
class APIGetGroupMemberCode(val groupId: Long, val groupMemberId: Long): CC()
class APIVerifyContact(val contactId: Long, val connectionCode: String?): CC()
class APIVerifyGroupMember(val groupId: Long, val groupMemberId: Long, val connectionCode: String?): CC()
class APIAddContact(val userId: Long, val short: Boolean, val incognito: Boolean): CC()
class APIAddContact(val userId: Long, val incognito: Boolean): CC()
class ApiSetConnectionIncognito(val connId: Long, val incognito: Boolean): CC()
class ApiChangeConnectionUser(val connId: Long, val userId: Long): CC()
class APIConnectPlan(val userId: Long, val connLink: String): CC()
@@ -3439,7 +3435,7 @@ sealed class CC {
class ApiSetConnectionAlias(val connId: Long, val localAlias: String): CC()
class ApiSetUserUIThemes(val userId: Long, val themes: ThemeModeOverrides?): CC()
class ApiSetChatUIThemes(val chatId: String, val themes: ThemeModeOverrides?): CC()
class ApiCreateMyAddress(val userId: Long, val short: Boolean): CC()
class ApiCreateMyAddress(val userId: Long): CC()
class ApiDeleteMyAddress(val userId: Long): CC()
class ApiShowMyAddress(val userId: Long): CC()
class ApiAddMyAddressShortLink(val userId: Long): CC()
@@ -3509,7 +3505,7 @@ sealed class CC {
is ApiMuteUser -> "/_mute user $userId"
is ApiUnmuteUser -> "/_unmute user $userId"
is ApiDeleteUser -> "/_delete user $userId del_smp=${onOff(delSMPQueues)}${maybePwd(viewPwd)}"
is StartChat -> "/_start main=${onOff(mainApp)}"
is StartChat -> "/_start main=${onOff(mainApp)} large_link_data=${onOff(largeLinkData)}"
is CheckChatRunning -> "/_check running"
is ApiStopChat -> "/_stop"
is ApiSetAppFilePaths -> "/set file paths ${json.encodeToString(this)}"
@@ -3572,7 +3568,7 @@ sealed class CC {
is ApiLeaveGroup -> "/_leave #$groupId"
is ApiListMembers -> "/_members #$groupId"
is ApiUpdateGroupProfile -> "/_group_profile #$groupId ${json.encodeToString(groupProfile)}"
is APICreateGroupLink -> "/_create link #$groupId ${memberRole.name.lowercase()} short=${onOff(short)}"
is APICreateGroupLink -> "/_create link #$groupId ${memberRole.name.lowercase()}"
is APIGroupLinkMemberRole -> "/_set link role #$groupId ${memberRole.name.lowercase()}"
is APIDeleteGroupLink -> "/_delete link #$groupId"
is APIGetGroupLink -> "/_get link #$groupId"
@@ -3612,7 +3608,7 @@ sealed class CC {
is APIGetGroupMemberCode -> "/_get code #$groupId $groupMemberId"
is APIVerifyContact -> "/_verify code @$contactId" + if (connectionCode != null) " $connectionCode" else ""
is APIVerifyGroupMember -> "/_verify code #$groupId $groupMemberId" + if (connectionCode != null) " $connectionCode" else ""
is APIAddContact -> "/_connect $userId short=${onOff(short)} incognito=${onOff(incognito)}"
is APIAddContact -> "/_connect $userId incognito=${onOff(incognito)}"
is ApiSetConnectionIncognito -> "/_set incognito :$connId ${onOff(incognito)}"
is ApiChangeConnectionUser -> "/_set conn user :$connId $userId"
is APIConnectPlan -> "/_connect plan $userId $connLink"
@@ -3628,7 +3624,7 @@ sealed class CC {
is ApiSetConnectionAlias -> "/_set alias :$connId ${localAlias.trim()}"
is ApiSetUserUIThemes -> "/_set theme user $userId ${if (themes != null) json.encodeToString(themes) else ""}"
is ApiSetChatUIThemes -> "/_set theme $chatId ${if (themes != null) json.encodeToString(themes) else ""}"
is ApiCreateMyAddress -> "/_address $userId short=${onOff(short)}"
is ApiCreateMyAddress -> "/_address $userId"
is ApiDeleteMyAddress -> "/_delete_address $userId"
is ApiShowMyAddress -> "/_show_address $userId"
is ApiAddMyAddressShortLink -> "/_short_link_address $userId"
@@ -196,7 +196,7 @@ fun GroupLinkLayout(
)
}
}
if (groupLink.connShortLink == null && appPreferences.privacyShortLinks.get()) {
if (groupLink.connShortLink == null) {
AddShortLinkButton(addShortLink)
}
}
@@ -88,13 +88,6 @@ fun PrivacySettingsView(
simplexLinkMode.set(it)
chatModel.simplexLinkMode.value = it
})
if (appPrefs.developerTools.get()) {
SettingsPreferenceItem(
null,
stringResource(MR.strings.privacy_short_links),
chatModel.controller.appPrefs.privacyShortLinks
)
}
}
SectionDividerSpaced()
@@ -63,8 +63,7 @@ fun UserAddressView(
fun createAddress() {
withBGApi {
progressIndicator = true
val short = appPreferences.privacyShortLinks.get()
val connReqContact = chatModel.controller.apiCreateUserAddress(user.value?.remoteHostId, short = short)
val connReqContact = chatModel.controller.apiCreateUserAddress(user.value?.remoteHostId)
if (connReqContact != null) {
chatModel.userAddress.value = UserContactLinkRec(connReqContact)
@@ -225,7 +224,7 @@ private fun UserAddressLayout(
// ShareViaEmailButton { sendEmail(userAddress) }
BusinessAddressToggle(autoAcceptState) { saveAas(autoAcceptState.value, autoAcceptStateSaved) }
AddressSettingsButton(user, userAddress, shareViaProfile, setProfileAddress, saveAas)
if (userAddress.connLinkContact.connShortLink == null && appPreferences.privacyShortLinks.get()) {
if (userAddress.connLinkContact.connShortLink == null) {
AddShortLinkButton(addShortLink)
}
@@ -2362,7 +2362,6 @@
<string name="onboarding_conditions_private_chats_not_accessible">لا يمكن الوصول إلى الدردشات الخاصة والمجموعات وجهات اتصالك لمشغلي الخادم.</string>
<string name="onboarding_conditions_by_using_you_agree">باستخدام SimpleX Chat، توافق على:\n- إرسال المحتوى القانوني فقط في المجموعات العامة.\n- احترام المستخدمين الآخرين – لا سبام.</string>
<string name="onboarding_conditions_accept">اقبل</string>
<string name="privacy_short_links">استخدم روابط قصيرة (تجريبي)</string>
<string name="link_requires_newer_app_version_please_upgrade">يتطلب هذا الرابط إصدار تطبيق أحدث. يُرجى ترقية التطبيق أو اطلب من جهة اتصالك إرسال رابط متوافق.</string>
<string name="full_link_button_text">رابط كامل</string>
<string name="short_link_button_text">رابط قصير</string>
@@ -98,7 +98,6 @@
<string name="simplex_link_mode_full">Full link</string>
<string name="simplex_link_mode_browser">Via browser</string>
<string name="simplex_link_mode_browser_warning">Opening the link in the browser may reduce connection privacy and security. Untrusted SimpleX links will be red.</string>
<string name="privacy_short_links">Use short links (BETA)</string>
<!-- Reports - ChatModel.kt -->
<string name="report_reason_spam">Spam</string>
@@ -2346,7 +2346,6 @@
<string name="simplex_link_channel">Enllaç al canal SimpleX</string>
<string name="link_requires_newer_app_version_please_upgrade">Aquest enllaç requereix una versió de l\'aplicació més recent. Actualitzeu l\'aplicació o demaneu al vostre contacte que enviï un enllaç compatible.</string>
<string name="unsupported_connection_link">Enllaç de connexió no compatible</string>
<string name="privacy_short_links">Emprar enllaços curts (BETA)</string>
<string name="full_link_button_text">Enllaç complet</string>
<string name="short_link_button_text">Enllaç curt</string>
<string name="network_smp_web_port_all">Tots els servidors</string>
@@ -2371,7 +2371,6 @@
<string name="onboarding_conditions_privacy_policy_and_conditions_of_use">Zásady ochrany soukromí a podmínky používání.</string>
<string name="onboarding_conditions_private_chats_not_accessible">Soukromé konverzace, skupiny a kontakty nejsou přístupné provozovatelům serverů.</string>
<string name="unsupported_connection_link">Nepodporovaný odkaz k připojení</string>
<string name="privacy_short_links">Používejte krátké odkazy (BETA)</string>
<string name="link_requires_newer_app_version_please_upgrade">Tento odkaz vyžaduje novější verzi aplikace. Prosím aktualizujte aplikaci nebo požádejte kontakt o odeslání kompatibilního odkazu.</string>
<string name="simplex_link_channel">odkaz SimpleX kanálu</string>
<string name="full_link_button_text">Úplný odkaz</string>
@@ -2453,7 +2453,6 @@
<string name="onboarding_conditions_configure_server_operators">Server-Betreiber konfigurieren</string>
<string name="onboarding_conditions_private_chats_not_accessible">Private Chats, Gruppen und Ihre Kontakte sind für Server-Betreiber nicht zugänglich.</string>
<string name="unsupported_connection_link">Verbindungs-Link wird nicht unterstützt</string>
<string name="privacy_short_links">Kurze Links verwenden (BETA)</string>
<string name="short_link_button_text">Verkürzter Link</string>
<string name="full_link_button_text">Vollständiger Link</string>
<string name="simplex_link_channel">SimpleX-Kanal-Link</string>
@@ -2382,7 +2382,6 @@
<string name="short_link_button_text">Enlace corto</string>
<string name="link_requires_newer_app_version_please_upgrade">Este enlace requiere una versión más reciente de la aplicación. Por favor, actualiza la aplicación o pide a tu contacto un enlace compatible.</string>
<string name="unsupported_connection_link">Enlace de conexión no compatible</string>
<string name="privacy_short_links">Usar enlaces cortos (BETA)</string>
<string name="network_smp_web_port_preset_footer">Usar puerto TCP 443 solo en servidores predefinidos.</string>
<string name="network_smp_web_port_all">Todos los servidores</string>
<string name="network_smp_web_port_preset">Servidores predefinidos</string>
@@ -2345,7 +2345,6 @@
<string name="onboarding_conditions_private_chats_not_accessible">A privát csevegések, a csoportok és a partnerek nem érhetők el a szerver üzemeltetői számára.</string>
<string name="onboarding_conditions_configure_server_operators">Kiszolgálóüzemeltetők beállítása</string>
<string name="unsupported_connection_link">Nem támogatott kapcsolattartási hivatkozás</string>
<string name="privacy_short_links">Rövid hivatkozások használata (béta)</string>
<string name="short_link_button_text">Rövid hivatkozás</string>
<string name="full_link_button_text">Teljes hivatkozás</string>
<string name="link_requires_newer_app_version_please_upgrade">Ez a hivatkozás újabb alkalmazásverziót igényel. Frissítse az alkalmazást vagy kérjen egy kompatibilis hivatkozást a partnerétől.</string>
@@ -105,7 +105,7 @@
<string name="error_parsing_uri_desc">Periksa apakah tautan SimpleX sudah benar.</string>
<string name="connected_to_server_to_receive_messages_from_contact">Anda terhubung ke server yang digunakan untuk menerima pesan dari kontak ini.</string>
<string name="trying_to_connect_to_server_to_receive_messages_with_error">Mencoba menyambung ke server yang digunakan untuk menerima pesan dari kontak ini (error: %1$s).</string>
<string name="database_migration_in_progress">Migrasi basis data sedang berlangsung,
<string name="database_migration_in_progress">Migrasi basis data sedang berlangsung,
\nmemerlukan waktu beberapa menit.</string>
<string name="server_connecting">menghubungkan</string>
<string name="non_content_uri_alert_title">Lokasi file tidak valid</string>
@@ -2356,7 +2356,6 @@
<string name="full_link_button_text">Tautan lengkap</string>
<string name="link_requires_newer_app_version_please_upgrade">Tautan ini perlu versi aplikasi yang baru. Harap perbarui aplikasi atau minta kontak untuk kirim tautan kompatibel.</string>
<string name="simplex_link_channel">Tautan saluran SimpleX</string>
<string name="privacy_short_links">Gunakan tautan singkat (BETA)</string>
<string name="unsupported_connection_link">Tautan koneksi tidak didukung</string>
<string name="short_link_button_text">Tautan singkat</string>
<string name="cant_send_message_generic">gagal mengirim pesan</string>
@@ -2386,7 +2386,6 @@
<string name="short_link_button_text">Link breve</string>
<string name="simplex_link_channel">Link del canale SimpleX</string>
<string name="unsupported_connection_link">Link di connessione non supportato</string>
<string name="privacy_short_links">Usa link brevi (BETA)</string>
<string name="network_smp_web_port_all">Tutti i server</string>
<string name="network_smp_web_port_off">Off</string>
<string name="network_smp_web_port_preset">Server preimpostati</string>
@@ -2379,7 +2379,6 @@
<string name="link_requires_newer_app_version_please_upgrade">Voor deze link is een nieuwere app-versie vereist. Werk de app bij of vraag je contactpersoon om een compatibele link te sturen.</string>
<string name="full_link_button_text">Volledige link</string>
<string name="unsupported_connection_link">Niet-ondersteunde verbindingslink</string>
<string name="privacy_short_links">Gebruik korte links (BETA)</string>
<string name="short_link_button_text">Korte link</string>
<string name="onboarding_conditions_configure_server_operators">Serveroperators configureren</string>
<string name="onboarding_conditions_privacy_policy_and_conditions_of_use">Privacybeleid en gebruiksvoorwaarden.</string>
@@ -2215,7 +2215,6 @@
<string name="blocking_reason_spam">Spam</string>
<string name="link_requires_newer_app_version_please_upgrade">Acest link necesită o versiune mai nouă a aplicației. Vă rugăm să actualizați aplicația sau să solicitați persoanei de contact să vă trimită un link compatibil.</string>
<string name="unsupported_connection_link">Legătură de conexiune neacceptată</string>
<string name="privacy_short_links">Utilizați linkuri scurte (BETA)</string>
<string name="network_smp_web_port_toggle">Utilizați portul web</string>
<string name="operator_conditions_will_be_accepted_for_some"><![CDATA[Condițiile vor fi acceptate pentru operatorul(ii): <b>%s</b>.]]></string>
<string name="remote_host_error_timeout"><![CDATA[S-a atins timeout-ul la conectarea la telefonul mobil <b>%s</b>]]></string>
@@ -2520,6 +2520,5 @@
<string name="rcv_group_event_user_accepted">Вы приняты</string>
<string name="group_new_support_chat_one">1 чат с членом группы</string>
<string name="simplex_link_channel">SimpleX ссылка канала</string>
<string name="privacy_short_links">Короткие ссылки (БЕТА)</string>
<string name="add_short_link">добавить короткую ссылку</string>
</resources>
@@ -2378,7 +2378,6 @@
<string name="onboarding_conditions_by_using_you_agree">Використовуючи SimpleX Chat, ви погоджуєтесь на:\n- надсилати тільки легальний контент у публічних групах.\n- поважати інших користувачів – без спаму.</string>
<string name="onboarding_conditions_configure_server_operators">Налаштувати операторів сервера</string>
<string name="onboarding_conditions_privacy_policy_and_conditions_of_use">Політика конфіденційності та умови використання</string>
<string name="privacy_short_links">Використовувати короткі посилання (BETA)</string>
<string name="link_requires_newer_app_version_please_upgrade">Це посилання вимагає новішої версії додатку. Будь ласка, оновіть додаток або попросіть вашого контакту надіслати сумісне посилання.</string>
<string name="full_link_button_text">Повне посилання</string>
<string name="short_link_button_text">Коротке посилання</string>
@@ -2355,7 +2355,6 @@
<string name="link_requires_newer_app_version_please_upgrade">Đường dẫn này yêu cầu một phiên bản ứng dụng mới hơn. Vui lòng nâng cấp ứng dụng hoặc yêu cầu liên hệ của một gửi cho một đường dẫn tương thích.</string>
<string name="simplex_link_channel">Đường dẫn kênh SimpleX</string>
<string name="unsupported_connection_link">Đường dẫn kết nối không được hỗ trợ</string>
<string name="privacy_short_links">Sử dụng đường dẫn ngắn (BETA)</string>
<string name="full_link_button_text">Toàn bộ đường dẫn</string>
<string name="short_link_button_text">Đường dẫn ngắn</string>
<string name="network_smp_web_port_off">Tắt</string>
@@ -2366,7 +2366,6 @@
<string name="onboarding_conditions_private_chats_not_accessible">服务器运营方无法访问私密聊天、群组和你的联系人。</string>
<string name="onboarding_conditions_configure_server_operators">配置服务器运营方</string>
<string name="unsupported_connection_link">不支持的连接链接</string>
<string name="privacy_short_links">使用短链接(测试)</string>
<string name="simplex_link_channel">SimpleX 频道链接</string>
<string name="short_link_button_text">短链接</string>
<string name="link_requires_newer_app_version_please_upgrade">此链接需要更新的应用版本。请升级应用或请求你的联系人发送相容的链接。</string>
@@ -189,7 +189,7 @@ useMemberFilter img_ = \case
readBlockedWordsConfig :: DirectoryOpts -> IO BlockedWordsConfig
readBlockedWordsConfig DirectoryOpts {blockedFragmentsFile, blockedWordsFile, nameSpellingFile, blockedExtensionRules, testing} = do
extensionRules <- maybe (pure []) (fmap read . readFile) blockedExtensionRules
extensionRules <- maybe (pure []) (fmap read . readFile) blockedExtensionRules
spelling <- maybe (pure M.empty) (fmap (M.fromList . read) . readFile) nameSpellingFile
blockedFragments <- S.fromList <$> maybe (pure []) (fmap T.lines . T.readFile) blockedFragmentsFile
bws <- maybe (pure []) (fmap lines . readFile) blockedWordsFile
@@ -348,7 +348,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
setGroupRegOwner st gr owner
let GroupInfo {groupId, groupProfile = GroupProfile {displayName}} = g
notifyOwner gr $ "Joined the group " <> displayName <> ", creating the link…"
sendChatCmd cc (APICreateGroupLink groupId GRMember False) >>= \case
sendChatCmd cc (APICreateGroupLink groupId GRMember) >>= \case
Right CRGroupLinkCreated {groupLink = GroupLink {connLinkContact = CCLink gLink _}} -> do
setGroupStatus st gr GRSPendingUpdate
notifyOwner
@@ -489,7 +489,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
Nothing -> pure textMsg
Just script -> content <$> readProcess script [s] ""
where
textMsg = MCText $ T.pack s
textMsg = MCText $ T.pack s
content r = case T.lines $ T.pack r of
[] -> textMsg
"" : _ -> textMsg
+3 -1
View File
@@ -173,6 +173,7 @@ newChatController
tempDirectory <- newTVarIO optTempDirectory
assetsDirectory <- newTVarIO Nothing
contactMergeEnabled <- newTVarIO True
useLargeLinkData <- newTVarIO True
pure
ChatController
{ firstTime,
@@ -213,7 +214,8 @@ newChatController
tempDirectory,
assetsDirectory,
logFilePath = logFile,
contactMergeEnabled
contactMergeEnabled,
useLargeLinkData
}
where
presetServers' :: PresetServers
+4 -3
View File
@@ -55,14 +55,15 @@ initializeBotAddress' logAddress cc = do
Left (ChatErrorStore SEUserContactLinkNotFound) -> do
when logAddress $ putStrLn "No bot address, creating..."
-- TODO [short links] create short link by default
sendChatCmd cc (CreateMyAddress False) >>= \case
sendChatCmd cc CreateMyAddress >>= \case
Right (CRUserContactLinkCreated _ ccLink) -> showBotAddress ccLink
_ -> putStrLn "can't create bot address" >> exitFailure
_ -> putStrLn "unexpected response" >> exitFailure
where
showBotAddress (CCLink uri shortUri) = do
when logAddress $ putStrLn $ "Bot's contact address is: " <> B.unpack (maybe (strEncode uri) strEncode shortUri)
when (isJust shortUri) $ putStrLn $ "Full contact address for old clients: " <> B.unpack (strEncode uri)
when logAddress $ do
putStrLn $ "Bot's contact address is: " <> B.unpack (maybe (strEncode uri) strEncode shortUri)
when (isJust shortUri) $ putStrLn $ "Full contact address for old clients: " <> B.unpack (strEncode uri)
void $ sendChatCmd cc $ AddressAutoAccept $ Just AutoAccept {businessAddress = False, acceptIncognito = False, autoReply = Nothing}
sendMessage :: ChatController -> Contact -> Text -> IO ()
+9 -8
View File
@@ -249,7 +249,8 @@ data ChatController = ChatController
tempDirectory :: TVar (Maybe FilePath),
assetsDirectory :: TVar (Maybe FilePath),
logFilePath :: Maybe FilePath,
contactMergeEnabled :: TVar Bool
contactMergeEnabled :: TVar Bool,
useLargeLinkData :: TVar Bool
}
data HelpSection = HSMain | HSFiles | HSGroups | HSContacts | HSMyAddress | HSIncognito | HSMarkdown | HSMessages | HSRemote | HSSettings | HSDatabase
@@ -276,7 +277,7 @@ data ChatCommand
| UnmuteUser
| APIDeleteUser UserId Bool (Maybe UserPwd)
| DeleteUser UserName Bool (Maybe UserPwd)
| StartChat {mainApp :: Bool, enableSndFiles :: Bool} -- enableSndFiles has no effect when mainApp is True
| StartChat {mainApp :: Bool, enableSndFiles :: Bool, largeLinkData :: Bool} -- enableSndFiles has no effect when mainApp is True
| CheckChatRunning
| APIStopChat
| APIActivateChat {restoreChat :: Bool}
@@ -369,7 +370,7 @@ data ChatCommand
-- | APIDeleteGroupConversations GroupId (NonEmpty GroupConversationId)
-- | APIArchiveGroupConversations GroupId (NonEmpty GroupConversationId)
| APIUpdateGroupProfile GroupId GroupProfile
| APICreateGroupLink GroupId GroupMemberRole CreateShortLink
| APICreateGroupLink GroupId GroupMemberRole
| APIGroupLinkMemberRole GroupId GroupMemberRole
| APIDeleteGroupLink GroupId
| APIGetGroupLink GroupId
@@ -443,8 +444,8 @@ data ChatCommand
| EnableGroupMember GroupName ContactName
| ChatHelp HelpSection
| Welcome
| APIAddContact UserId CreateShortLink IncognitoEnabled
| AddContact CreateShortLink IncognitoEnabled
| APIAddContact UserId IncognitoEnabled
| AddContact IncognitoEnabled
| APISetConnectionIncognito Int64 IncognitoEnabled
| APIChangeConnectionUser Int64 UserId -- new user id to switch connection to
| APIConnectPlan UserId AConnectionLink
@@ -462,8 +463,8 @@ data ChatCommand
| ClearContact ContactName
| APIListContacts UserId
| ListContacts
| APICreateMyAddress UserId CreateShortLink
| CreateMyAddress CreateShortLink
| APICreateMyAddress UserId
| CreateMyAddress
| APIDeleteMyAddress UserId
| DeleteMyAddress
| APIShowMyAddress UserId
@@ -507,7 +508,7 @@ data ChatCommand
| ShowGroupProfile GroupName
| UpdateGroupDescription GroupName (Maybe Text)
| ShowGroupDescription GroupName
| CreateGroupLink GroupName GroupMemberRole CreateShortLink
| CreateGroupLink GroupName GroupMemberRole
| GroupLinkMemberRole GroupName GroupMemberRole
| DeleteGroupLink GroupName
| ShowGroupLink GroupName
+63 -50
View File
@@ -413,7 +413,8 @@ processChatCommand' vr = \case
checkDeleteChatUser user'
withChatLock "deleteUser" . procCmd $ deleteChatUser user' delSMPQueues
DeleteUser uName delSMPQueues viewPwd_ -> withUserName uName $ \userId -> APIDeleteUser userId delSMPQueues viewPwd_
StartChat {mainApp, enableSndFiles} -> withUser' $ \_ ->
StartChat {mainApp, enableSndFiles, largeLinkData} -> withUser' $ \_ -> do
chatWriteVar useLargeLinkData largeLinkData
asks agentAsync >>= readTVarIO >>= \case
Just _ -> pure CRChatRunning
_ -> checkStoreNotChanged . lift $ startChatController mainApp enableSndFiles $> CRChatStarted
@@ -1671,21 +1672,19 @@ processChatCommand' vr = \case
EnableGroupMember gName mName -> withMemberName gName mName $ \gId mId -> APIEnableGroupMember gId mId
ChatHelp section -> pure $ CRChatHelp section
Welcome -> withUser $ pure . CRWelcome
APIAddContact userId short incognito -> withUserId userId $ \user -> procCmd $ do
APIAddContact userId incognito -> withUserId userId $ \user -> procCmd $ do
-- [incognito] generate profile for connection
incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing
subMode <- chatReadVar subscriptionMode
let userData
| short = Just $ shortLinkUserData $ userProfileToSend user incognitoProfile Nothing False
| otherwise = Nothing
userData <- contactShortLinkData (userProfileToSend user incognitoProfile Nothing False) Nothing
-- TODO [certs rcv]
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation userData Nothing IKPQOn subMode
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation (Just userData) Nothing IKPQOn subMode
ccLink' <- shortenCreatedLink ccLink
-- TODO PQ pass minVersion from the current range
conn <- withFastStore' $ \db -> createDirectConnection db user connId ccLink' Nothing ConnNew incognitoProfile subMode initialChatVersion PQSupportOn
pure $ CRInvitation user ccLink' conn
AddContact short incognito -> withUser $ \User {userId} ->
processChatCommand $ APIAddContact userId short incognito
AddContact incognito -> withUser $ \User {userId} ->
processChatCommand $ APIAddContact userId incognito
APISetConnectionIncognito connId incognito -> withUser $ \user@User {userId} -> do
conn <- withFastStore $ \db -> getPendingContactConnection db userId connId
let PendingContactConnection {pccConnStatus, customUserProfileId} = conn
@@ -1717,11 +1716,12 @@ processChatCommand' vr = \case
recreateConn user conn@PendingContactConnection {customUserProfileId, connLinkInv} newUser = do
subMode <- chatReadVar subscriptionMode
let short = isJust $ connShortLink =<< connLinkInv
userData
| short = Just $ shortLinkUserData $ userProfileToSend newUser Nothing Nothing False
| otherwise = Nothing
userData_ <-
if short
then Just <$> contactShortLinkData (userProfileToSend newUser Nothing Nothing False) Nothing
else pure Nothing
-- TODO [certs rcv]
(agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation userData Nothing IKPQOn subMode
(agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation userData_ Nothing IKPQOn subMode
ccLink' <- shortenCreatedLink ccLink
conn' <- withFastStore' $ \db -> do
deleteConnectionRecord db user connId
@@ -1824,18 +1824,16 @@ processChatCommand' vr = \case
CRContactsList user <$> withFastStore' (\db -> getUserContacts db vr user)
ListContacts -> withUser $ \User {userId} ->
processChatCommand $ APIListContacts userId
APICreateMyAddress userId short -> withUserId userId $ \user -> procCmd $ do
APICreateMyAddress userId -> withUserId userId $ \user -> procCmd $ do
subMode <- chatReadVar subscriptionMode
let userData
| short = Just $ shortLinkUserData $ userProfileToSend user Nothing Nothing False
| otherwise = Nothing
userData <- contactShortLinkData (userProfileToSend user Nothing Nothing False) Nothing
-- TODO [certs rcv]
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact userData Nothing IKPQOn subMode
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact (Just userData) Nothing IKPQOn subMode
ccLink' <- shortenCreatedLink ccLink
withFastStore $ \db -> createUserContactLink db user connId ccLink' short subMode
withFastStore $ \db -> createUserContactLink db user connId ccLink' subMode
pure $ CRUserContactLinkCreated user ccLink'
CreateMyAddress short -> withUser $ \User {userId} ->
processChatCommand $ APICreateMyAddress userId short
CreateMyAddress -> withUser $ \User {userId} ->
processChatCommand $ APICreateMyAddress userId
APIDeleteMyAddress userId -> withUserId userId $ \user@User {profile = p} -> do
conn <- withFastStore $ \db -> getUserAddressConnection db vr user
withChatLock "deleteMyAddress" $ do
@@ -1860,9 +1858,9 @@ processChatCommand' vr = \case
let p' = (fromLocalProfile p :: Profile) {contactLink = Nothing}
updateProfile_ user p' True $ withFastStore' $ \db -> setUserProfileContactLink db user Nothing
APISetProfileAddress userId True -> withUserId userId $ \user@User {profile = p} -> do
ucl@UserContactLink {connLinkContact = CCLink cReq _} <- withFastStore (`getUserAddress` user)
ucl <- withFastStore (`getUserAddress` user)
-- TODO [short links] replace with short links
let p' = (fromLocalProfile p :: Profile) {contactLink = Just $ CLFull cReq}
let p' = (fromLocalProfile p :: Profile) {contactLink = Just $ profileContactLink ucl}
updateProfile_ user p' True $ withFastStore' $ \db -> setUserProfileContactLink db user $ Just ucl
SetProfileAddress onOff -> withUser $ \User {userId} ->
processChatCommand $ APISetProfileAddress userId onOff
@@ -2435,20 +2433,18 @@ processChatCommand' vr = \case
updateGroupProfileByName gName $ \p -> p {description}
ShowGroupDescription gName -> withUser $ \user ->
CRGroupDescription user <$> withFastStore (\db -> getGroupInfoByName db vr user gName)
APICreateGroupLink groupId mRole short -> withUser $ \user -> withGroupLock "createGroupLink" groupId $ do
APICreateGroupLink groupId mRole -> withUser $ \user -> withGroupLock "createGroupLink" groupId $ do
gInfo@GroupInfo {groupProfile} <- withFastStore $ \db -> getGroupInfo db vr user groupId
assertUserGroupRole gInfo GRAdmin
when (mRole > GRMember) $ throwChatError $ CEGroupMemberInitialRole gInfo mRole
groupLinkId <- GroupLinkId <$> drgRandomBytes 16
subMode <- chatReadVar subscriptionMode
let userData
| short = Just $ UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData groupProfile
| otherwise = Nothing
crClientData = encodeJSON $ CRDataGroup groupLinkId
userData <- groupShortLinkData groupProfile
let crClientData = encodeJSON $ CRDataGroup groupLinkId
-- TODO [certs rcv]
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact userData (Just crClientData) IKPQOff subMode
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact (Just userData) (Just crClientData) IKPQOff subMode
ccLink' <- createdGroupLink <$> shortenCreatedLink ccLink
gLink <- withFastStore $ \db -> createGroupLink db user gInfo connId ccLink' groupLinkId mRole short subMode
gLink <- withFastStore $ \db -> createGroupLink db user gInfo connId ccLink' groupLinkId mRole subMode
pure $ CRGroupLinkCreated user gInfo gLink
APIGroupLinkMemberRole groupId mRole' -> withUser $ \user -> withGroupLock "groupLinkMemberRole" groupId $ do
gInfo <- withFastStore $ \db -> getGroupInfo db vr user groupId
@@ -2507,9 +2503,9 @@ processChatCommand' vr = \case
toView $ CEvtNewChatItems user [AChatItem SCTDirect SMDSnd (DirectChat ct') ci]
pure $ CRNewMemberContactSentInv user ct' g m
_ -> throwChatError CEGroupMemberNotActive
CreateGroupLink gName mRole short -> withUser $ \user -> do
CreateGroupLink gName mRole -> withUser $ \user -> do
groupId <- withFastStore $ \db -> getGroupIdByName db user gName
processChatCommand $ APICreateGroupLink groupId mRole short
processChatCommand $ APICreateGroupLink groupId mRole
GroupLinkMemberRole gName mRole -> withUser $ \user -> do
groupId <- withFastStore $ \db -> getGroupIdByName db user gName
processChatCommand $ APIGroupLinkMemberRole groupId mRole
@@ -3030,7 +3026,7 @@ processChatCommand' vr = \case
conn <- withFastStore $ \db -> getUserAddressConnection db vr user
let shortLinkProfile = userProfileToSend user Nothing Nothing False
shortLinkMsg = autoAccept >>= autoReply >>= (Just . msgContentText)
userData = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData shortLinkProfile shortLinkMsg
userData <- 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}
@@ -3089,8 +3085,8 @@ 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 = UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData groupProfile
crClientData = encodeJSON $ CRDataGroup groupLinkId
userData <- groupShortLinkData groupProfile
let crClientData = encodeJSON $ CRDataGroup groupLinkId
sLnk <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a (aConnId conn) SCMContact userData (Just crClientData))
gLink' <- withFastStore' $ \db -> setGroupLinkShortLink db gLink sLnk
pure $ CRGroupLink user gInfo gLink'
@@ -3316,9 +3312,13 @@ 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_ = J.decodeStrict $ linkUserData' cData
plan <- contactRequestPlan user cReq contactSLinkData_
pure (ACCL SCMContact $ CCLink cReq (Just l'), plan)
let cl = ACCL SCMContact $ CCLink cReq (Just l')
withFastStore' (\db -> getContactWithoutConnViaShortAddress db vr user l') >>= \case
Just ct -> pure (cl, CPContactAddress (CAPContactViaAddress ct))
Nothing -> do
let contactSLinkData_ = J.decodeStrict $ linkUserData' cData
plan <- contactRequestPlan user cReq contactSLinkData_
pure (cl, plan)
CCTGroup ->
withFastStore' (\db -> getGroupInfoViaUserShortLink db vr user l') >>= \case
Just (cReq, g) -> pure (ACCL SCMContact $ CCLink cReq (Just l'), CPGroupLink (GLPOwnLink g))
@@ -3434,12 +3434,26 @@ 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)
shortLinkUserData :: Profile -> UserLinkData
shortLinkUserData profile = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData profile Nothing
contactShortLinkData :: Profile -> Maybe Text -> CM UserLinkData
contactShortLinkData p msg = do
largeLinkData <- chatReadVar useLargeLinkData
let contactData
| largeLinkData = ContactShortLinkData p msg
| otherwise = ContactShortLinkData p {fullName = "", image = Nothing, contactLink = Nothing} Nothing
-- TODO [short links] compress
pure $ UserLinkData $ LB.toStrict $ J.encode contactData
groupShortLinkData :: GroupProfile -> CM UserLinkData
groupShortLinkData gp = do
largeLinkData <- chatReadVar useLargeLinkData
let gp'
| largeLinkData = gp
| otherwise = gp {fullName = "", description = Nothing, image = Nothing, memberAdmission = Nothing}
-- TODO [short links] compress
pure $ UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData gp'
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
userData <- 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)
@@ -4180,8 +4194,9 @@ chatCommandP =
"/_start " *> do
mainApp <- "main=" *> onOffP
enableSndFiles <- " snd_files=" *> onOffP <|> pure mainApp
pure StartChat {mainApp, enableSndFiles},
"/_start" $> StartChat True True,
largeLinkData <- " large_link_data=" *> onOffP <|> pure False
pure StartChat {mainApp, enableSndFiles, largeLinkData},
"/_start" $> StartChat {mainApp = True, enableSndFiles = True, largeLinkData = False},
"/_check running" $> CheckChatRunning,
"/_stop" $> APIStopChat,
"/_app activate restore=" *> (APIActivateChat <$> onOffP),
@@ -4388,12 +4403,12 @@ chatCommandP =
"/set welcome " *> char_ '#' *> (UpdateGroupDescription <$> displayNameP <* A.space <*> (Just <$> msgTextP)),
"/delete welcome " *> char_ '#' *> (UpdateGroupDescription <$> displayNameP <*> pure Nothing),
"/show welcome " *> char_ '#' *> (ShowGroupDescription <$> displayNameP),
"/_create link #" *> (APICreateGroupLink <$> A.decimal <*> (memberRole <|> pure GRMember) <*> shortOnOffP),
"/_create link #" *> (APICreateGroupLink <$> A.decimal <*> (memberRole <|> pure GRMember)),
"/_set link role #" *> (APIGroupLinkMemberRole <$> A.decimal <*> memberRole),
"/_delete link #" *> (APIDeleteGroupLink <$> A.decimal),
"/_get link #" *> (APIGetGroupLink <$> A.decimal),
"/_short link #" *> (APIAddGroupShortLink <$> A.decimal),
"/create link #" *> (CreateGroupLink <$> displayNameP <*> (memberRole <|> pure GRMember) <*> shortP),
"/create link #" *> (CreateGroupLink <$> displayNameP <*> (memberRole <|> pure GRMember)),
"/set link role #" *> (GroupLinkMemberRole <$> displayNameP <*> memberRole),
"/delete link #" *> (DeleteGroupLink <$> displayNameP),
"/show link #" *> (ShowGroupLink <$> displayNameP),
@@ -4410,11 +4425,11 @@ chatCommandP =
"/_set group user #" *> (APIChangePreparedGroupUser <$> A.decimal <* A.space <*> A.decimal),
"/_connect contact @" *> (APIConnectPreparedContact <$> A.decimal <*> incognitoOnOffP <*> optional (A.space *> msgContentP)),
"/_connect group #" *> (APIConnectPreparedGroup <$> A.decimal <*> incognitoOnOffP),
"/_connect " *> (APIAddContact <$> A.decimal <*> shortOnOffP <*> incognitoOnOffP),
"/_connect " *> (APIAddContact <$> A.decimal <*> incognitoOnOffP),
"/_connect " *> (APIConnect <$> A.decimal <*> incognitoOnOffP <* A.space <*> connLinkP_ <*> optional (A.space *> msgContentP)),
"/_set incognito :" *> (APISetConnectionIncognito <$> A.decimal <* A.space <*> onOffP),
"/_set conn user :" *> (APIChangeConnectionUser <$> A.decimal <* A.space <*> A.decimal),
("/connect" <|> "/c") *> (AddContact <$> shortP <*> incognitoP),
("/connect" <|> "/c") *> (AddContact <$> incognitoP),
("/connect" <|> "/c") *> (Connect <$> incognitoP <* A.space <*> ((Just <$> strP) <|> A.takeTill isSpace $> Nothing)),
ForwardMessage <$> chatNameP <* " <- @" <*> displayNameP <* A.space <*> msgTextP,
ForwardGroupMessage <$> chatNameP <* " <- #" <*> displayNameP <* A.space <* A.char '@' <*> (Just <$> displayNameP) <* A.space <*> msgTextP,
@@ -4448,8 +4463,8 @@ chatCommandP =
("/fstatus " <|> "/fs ") *> (FileStatus <$> A.decimal),
"/_connect contact " *> (APIConnectContactViaAddress <$> A.decimal <*> incognitoOnOffP <* A.space <*> A.decimal),
"/simplex" *> (ConnectSimplex <$> incognitoP),
"/_address " *> (APICreateMyAddress <$> A.decimal <*> shortOnOffP),
("/address" <|> "/ad") *> (CreateMyAddress <$> shortP),
"/_address " *> (APICreateMyAddress <$> A.decimal),
("/address" <|> "/ad") $> CreateMyAddress,
"/_delete_address " *> (APIDeleteMyAddress <$> A.decimal),
("/delete_address" <|> "/da") $> DeleteMyAddress,
"/_show_address " *> (APIShowMyAddress <$> A.decimal),
@@ -4527,9 +4542,7 @@ chatCommandP =
pure $ ACCL m (CCLink cReq sLink_)
connLinkP_ =
((Just <$> connLinkP) <|> A.takeTill (== ' ') $> Nothing)
shortP = (A.space *> ("short" <|> "s")) $> True <|> pure False
incognitoP = (A.space *> ("incognito" <|> "i")) $> True <|> pure False
shortOnOffP = (A.space *> "short=" *> onOffP) <|> pure False
incognitoOnOffP = (A.space *> "incognito=" *> onOffP) <|> pure False
imagePrefix = (<>) <$> "data:" <*> ("image/png;base64," <|> "image/jpg;base64,")
imageP = safeDecodeUtf8 <$> ((<>) <$> imagePrefix <*> (B64.encode <$> base64P))
+4 -4
View File
@@ -200,14 +200,14 @@ toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, Just member
Just $ toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, showMessages, memberBlocked) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId, profileId, displayName, fullName, image, contactLink, localAlias, contactPreferences) :. (createdAt, updatedAt) :. (supportChatTs, supportChatUnread, supportChatUnanswered, supportChatMentions, supportChatLastMsgFromMemberTs))
toMaybeGroupMember _ _ = Nothing
createGroupLink :: DB.Connection -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> Bool -> SubscriptionMode -> ExceptT StoreError IO GroupLink
createGroupLink db user@User {userId} groupInfo@GroupInfo {groupId, localDisplayName} agentConnId (CCLink cReq shortLink) groupLinkId memberRole shortLinkDataSet subMode = do
createGroupLink :: DB.Connection -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> SubscriptionMode -> ExceptT StoreError IO GroupLink
createGroupLink db user@User {userId} groupInfo@GroupInfo {groupId, localDisplayName} agentConnId (CCLink cReq shortLink) groupLinkId memberRole subMode = do
checkConstraint (SEDuplicateGroupLink groupInfo) . liftIO $ do
currentTs <- getCurrentTime
DB.execute
db
"INSERT INTO user_contact_links (user_id, group_id, group_link_id, local_display_name, conn_req_contact, short_link_contact, short_link_data_set, group_link_member_role, auto_accept, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
((userId, groupId, groupLinkId, "group_link_" <> localDisplayName, cReq, shortLink, BI shortLinkDataSet) :. (memberRole, BI True, currentTs, currentTs))
((userId, groupId, groupLinkId, "group_link_" <> localDisplayName, cReq, shortLink, BI (isJust shortLink)) :. (memberRole, BI True, currentTs, currentTs))
userContactLinkId <- insertedRowId db
void $ createConnection_ db userId ConnUserContact (Just userContactLinkId) agentConnId ConnNew initialChatVersion chatInitialVRange Nothing Nothing Nothing 0 currentTs subMode PQSupportOff
getGroupLink db user groupInfo
@@ -2032,7 +2032,7 @@ getGroupInfoViaUserShortLink db vr user@User {userId} shortLink = fmap eitherToM
(cReq, groupId) <- ExceptT getConnReqGroup
(cReq,) <$> getGroupInfo db vr user groupId
where
getConnReqGroup =
getConnReqGroup =
firstRow' toConnReqGroupId (SEInternalError "group link not found") $
DB.query
db
+26 -9
View File
@@ -53,6 +53,7 @@ module Simplex.Chat.Store.Profiles
getUserContactLinkViaShortLink,
setUserContactLinkShortLink,
getContactWithoutConnViaAddress,
getContactWithoutConnViaShortAddress,
updateUserAddressAutoAccept,
getProtocolServers,
insertProtocolServer,
@@ -75,6 +76,7 @@ module Simplex.Chat.Store.Profiles
updateCommandStatus,
getCommandDataByCorrId,
setUserUIThemes,
profileContactLink,
)
where
@@ -86,7 +88,7 @@ import Data.Functor (($>))
import Data.Int (Int64)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as L
import Data.Maybe (catMaybes, fromMaybe)
import Data.Maybe (catMaybes, fromMaybe, isJust)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
@@ -332,11 +334,7 @@ setUserProfileContactLink db user@User {userId, profile = p@LocalProfile {profil
(contactLink, ts, userId, profileId)
pure (user :: User) {profile = p {contactLink}}
where
-- TODO [short links] this should be replaced with short links once they are supported by all clients.
-- Or, maybe, we want to allow both, when both are optional.
contactLink = case ucl_ of
Just UserContactLink {connLinkContact = CCLink cReq _} -> Just $ CLFull cReq
_ -> Nothing
contactLink = profileContactLink <$> ucl_
-- only used in tests
getUserContactProfiles :: DB.Connection -> User -> IO [Profile]
@@ -354,14 +352,14 @@ getUserContactProfiles db User {userId} =
toContactProfile :: (ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, Maybe Preferences) -> Profile
toContactProfile (displayName, fullName, image, contactLink, preferences) = Profile {displayName, fullName, image, contactLink, preferences}
createUserContactLink :: DB.Connection -> User -> ConnId -> CreatedLinkContact -> Bool -> SubscriptionMode -> ExceptT StoreError IO ()
createUserContactLink db User {userId} agentConnId (CCLink cReq shortLink) shortLinkDataSet subMode =
createUserContactLink :: DB.Connection -> User -> ConnId -> CreatedLinkContact -> SubscriptionMode -> ExceptT StoreError IO ()
createUserContactLink db User {userId} agentConnId (CCLink cReq shortLink) subMode =
checkConstraint SEDuplicateContactLink . liftIO $ do
currentTs <- getCurrentTime
DB.execute
db
"INSERT INTO user_contact_links (user_id, conn_req_contact, short_link_contact, short_link_data_set, created_at, updated_at) VALUES (?,?,?,?,?,?)"
(userId, cReq, shortLink, BI shortLinkDataSet, currentTs, currentTs)
(userId, cReq, shortLink, BI (isJust shortLink), currentTs, currentTs)
userContactLinkId <- insertedRowId db
void $ createConnection_ db userId ConnUserContact (Just userContactLinkId) agentConnId ConnNew initialChatVersion chatInitialVRange Nothing Nothing Nothing 0 currentTs subMode CR.PQSupportOff
@@ -457,6 +455,9 @@ data UserContactLink = UserContactLink
}
deriving (Show)
profileContactLink :: UserContactLink -> ConnLinkContact
profileContactLink UserContactLink {connLinkContact = CCLink cReq sLink} = maybe (CLFull cReq) CLShort sLink
data GroupLinkInfo = GroupLinkInfo
{ groupId :: GroupId,
memberRole :: GroupMemberRole
@@ -559,6 +560,22 @@ getContactWithoutConnViaAddress db vr user@User {userId} (cReqSchema1, cReqSchem
(userId, cReqSchema1, cReqSchema2)
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db vr user) ctId_
getContactWithoutConnViaShortAddress :: DB.Connection -> VersionRangeChat -> User -> ShortLinkContact -> IO (Maybe Contact)
getContactWithoutConnViaShortAddress db vr user@User {userId} shortLink = do
ctId_ <-
maybeFirstRow fromOnly $
DB.query
db
[sql|
SELECT ct.contact_id
FROM contacts ct
JOIN contact_profiles cp ON cp.contact_profile_id = ct.contact_profile_id
LEFT JOIN connections c ON c.contact_id = ct.contact_id
WHERE cp.user_id = ? AND cp.contact_link = ? AND c.connection_id IS NULL
|]
(userId, shortLink)
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db vr user) ctId_
updateUserAddressAutoAccept :: DB.Connection -> Int64 -> Maybe AutoAccept -> IO ()
updateUserAddressAutoAccept db userContactLinkId autoAccept =
DB.execute
@@ -1178,6 +1178,18 @@ Plan:
SEARCH g USING INTEGER PRIMARY KEY (rowid=?)
SEARCH m USING INDEX sqlite_autoindex_group_members_1 (group_id=?)
Query:
SELECT ct.contact_id
FROM contacts ct
JOIN contact_profiles cp ON cp.contact_profile_id = ct.contact_profile_id
LEFT JOIN connections c ON c.contact_id = ct.contact_id
WHERE cp.user_id = ? AND cp.contact_link = ? AND c.connection_id IS NULL
Plan:
SEARCH cp USING COVERING INDEX idx_contact_profiles_contact_link (user_id=? AND contact_link=?)
SEARCH ct USING COVERING INDEX idx_contacts_contact_profile_id (contact_profile_id=?)
SEARCH c USING COVERING INDEX idx_connections_contact_id (contact_id=?) LEFT-JOIN
Query:
SELECT ct.contact_id
FROM contacts ct
-2
View File
@@ -222,8 +222,6 @@ contactConnId c = aConnId <$> contactConn c
type IncognitoEnabled = Bool
type CreateShortLink = Bool
contactConnIncognito :: Contact -> IncognitoEnabled
contactConnIncognito = maybe False connIncognito . contactConn
+11 -1
View File
@@ -53,7 +53,7 @@ import Simplex.Messaging.Client (ProtocolClientConfig (..))
import Simplex.Messaging.Client.Agent (defaultSMPClientAgentConfig)
import Simplex.Messaging.Crypto.Ratchet (supportedE2EEncryptVRange)
import qualified Simplex.Messaging.Crypto.Ratchet as CR
import Simplex.Messaging.Protocol (srvHostnamesSMPClientVersion)
import Simplex.Messaging.Protocol (srvHostnamesSMPClientVersion, sndAuthKeySMPClientVersion)
import Simplex.Messaging.Server (runSMPServerBlocking)
import Simplex.Messaging.Server.Env.STM (ServerConfig (..), ServerStoreCfg (..), StartOptions (..), StorePaths (..), defaultMessageExpiration, defaultIdleQueueInterval, defaultNtfExpiration, defaultInactiveClientExpiration)
import Simplex.Messaging.Server.MsgStore.STM (STMMsgStore)
@@ -182,6 +182,13 @@ testAgentCfgSlow =
smpCfg = (smpCfg testAgentCfg) {serverVRange = mkVersionRange minClientSMPRelayVersion sendingProxySMPVersion} -- v8
}
testAgentCfgNoShortLinks :: AgentConfig
testAgentCfgNoShortLinks =
testAgentCfg
{ smpClientVRange = mkVersionRange (Version 1) sndAuthKeySMPClientVersion, -- v3
smpCfg = (smpCfg testAgentCfg) {serverVRange = mkVersionRange minClientSMPRelayVersion (Version 14)} -- before shortLinksSMPVersion
}
testCfg :: ChatConfig
testCfg =
defaultChatConfig
@@ -195,6 +202,9 @@ testCfg =
testCfgSlow :: ChatConfig
testCfgSlow = testCfg {agentConfig = testAgentCfgSlow}
testCfgNoShortLinks :: ChatConfig
testCfgNoShortLinks = testCfg {agentConfig = testAgentCfgNoShortLinks}
testAgentCfgVPrev :: AgentConfig
testAgentCfgVPrev =
testAgentCfg
+22 -22
View File
@@ -94,21 +94,21 @@ chatDirectTests = do
it "get and enable operators, accept conditions" testOperators
describe "async connection handshake" $ do
describe "connect when initiating client goes offline" $ do
it "curr" $ testAsyncInitiatingOffline testCfg testCfg
it "v5" $ testAsyncInitiatingOffline testCfgSlow testCfgSlow
it "v5/curr" $ testAsyncInitiatingOffline testCfgSlow testCfg
it "curr/v5" $ testAsyncInitiatingOffline testCfg testCfgSlow
it "curr" $ testAsyncInitiatingOffline True testCfg testCfg
it "v5" $ testAsyncInitiatingOffline False testCfgSlow testCfgSlow
it "v5/curr" $ testAsyncInitiatingOffline False testCfgSlow testCfg
it "curr/v5" $ testAsyncInitiatingOffline True testCfg testCfgSlow
describe "connect when accepting client goes offline" $ do
it "curr" $ testAsyncAcceptingOffline testCfg testCfg
it "v5" $ testAsyncAcceptingOffline testCfgSlow testCfgSlow
it "v5/curr" $ testAsyncAcceptingOffline testCfgSlow testCfg
it "curr/v5" $ testAsyncAcceptingOffline testCfg testCfgSlow
it "curr" $ testAsyncAcceptingOffline True testCfg testCfg
it "v5" $ testAsyncAcceptingOffline False testCfgSlow testCfgSlow
it "v5/curr" $ testAsyncAcceptingOffline False testCfgSlow testCfg
it "curr/v5" $ testAsyncAcceptingOffline True testCfg testCfgSlow
describe "connect, fully asynchronous (when clients are never simultaneously online)" $ do
it "curr" testFullAsyncFast
-- fails in CI
xit'' "v5" $ testFullAsyncSlow testCfgSlow testCfgSlow
xit'' "v5/curr" $ testFullAsyncSlow testCfgSlow testCfg
xit'' "curr/v5" $ testFullAsyncSlow testCfg testCfgSlow
xit'' "v5" $ testFullAsyncSlow False testCfgSlow testCfgSlow
xit'' "v5/curr" $ testFullAsyncSlow False testCfgSlow testCfg
xit'' "curr/v5" $ testFullAsyncSlow True testCfg testCfgSlow
describe "webrtc calls api" $ do
it "negotiate call" testNegotiateCall
#if !defined(dbPostgres)
@@ -183,9 +183,9 @@ chatDirectTests = do
testAddContact :: HasCallStack => SpecWith TestParams
testAddContact = versionTestMatrix2 runTestAddContact
where
runTestAddContact pqExpected alice bob = do
runTestAddContact pqExpected withShortLink alice bob = do
alice ##> "/_connect 1"
inv <- getInvitation alice
inv <- (if withShortLink then getInvitation else getInvitationNoShortLink) alice
bob ##> ("/_connect 1 " <> inv)
bob <## "confirmation sent!"
concurrently_
@@ -1237,12 +1237,12 @@ testOperators =
where
opts' = testOpts {coreOptions = testCoreOpts {smpServers = [], xftpServers = []}}
testAsyncInitiatingOffline :: HasCallStack => ChatConfig -> ChatConfig -> TestParams -> IO ()
testAsyncInitiatingOffline aliceCfg bobCfg ps = do
testAsyncInitiatingOffline :: HasCallStack => Bool -> ChatConfig -> ChatConfig -> TestParams -> IO ()
testAsyncInitiatingOffline withShortLink aliceCfg bobCfg ps = do
inv <- withNewTestChatCfg ps aliceCfg "alice" aliceProfile $ \alice -> do
threadDelay 250000
alice ##> "/c"
getInvitation alice
(if withShortLink then getInvitation else getInvitationNoShortLink) alice
withNewTestChatCfg ps bobCfg "bob" bobProfile $ \bob -> do
threadDelay 250000
bob ##> ("/c " <> inv)
@@ -1252,11 +1252,11 @@ testAsyncInitiatingOffline aliceCfg bobCfg ps = do
(bob <## "alice (Alice): contact is connected")
(alice <## "bob (Bob): contact is connected")
testAsyncAcceptingOffline :: HasCallStack => ChatConfig -> ChatConfig -> TestParams -> IO ()
testAsyncAcceptingOffline aliceCfg bobCfg ps = do
testAsyncAcceptingOffline :: HasCallStack => Bool -> ChatConfig -> ChatConfig -> TestParams -> IO ()
testAsyncAcceptingOffline withShortLink aliceCfg bobCfg ps = do
inv <- withNewTestChatCfg ps aliceCfg "alice" aliceProfile $ \alice -> do
alice ##> "/c"
getInvitation alice
(if withShortLink then getInvitation else getInvitationNoShortLink) alice
withNewTestChatCfg ps bobCfg "bob" bobProfile $ \bob -> do
threadDelay 250000
bob ##> ("/c " <> inv)
@@ -1283,12 +1283,12 @@ testFullAsyncFast ps = do
withTestChat ps "bob" $ \bob ->
bob <## "alice (Alice): contact is connected"
testFullAsyncSlow :: HasCallStack => ChatConfig -> ChatConfig -> TestParams -> IO ()
testFullAsyncSlow aliceCfg bobCfg ps = do
testFullAsyncSlow :: HasCallStack => Bool -> ChatConfig -> ChatConfig -> TestParams -> IO ()
testFullAsyncSlow withShortLink aliceCfg bobCfg ps = do
inv <- withNewTestChatCfg ps aliceCfg "alice" aliceProfile $ \alice -> do
threadDelay 250000
alice ##> "/c"
getInvitation alice
(if withShortLink then getInvitation else getInvitationNoShortLink) alice
withNewTestChatCfg ps bobCfg "bob" bobProfile $ \bob -> do
threadDelay 250000
bob ##> ("/c " <> inv)
+7 -7
View File
@@ -3442,7 +3442,7 @@ testPlanGroupLinkConnectingSlow ps = do
alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team"
alice ##> "/create link #team"
getGroupLink alice "team" GRMember True
getGroupLinkNoShortLink alice "team" GRMember True
withNewTestChatCfg ps testCfgSlow "bob" bobProfile $ \bob -> do
threadDelay 100000
@@ -5865,13 +5865,13 @@ testMembershipProfileUpdateContactActive =
checkItems bob
alice ##> "/ad"
cLink <- getContactLink alice True
(sLink, _cLink) <- getContactLinks alice True
alice ##> "/pa on"
alice <## "new contact address set"
bob <## "alisa set new contact address, use /info alisa to view"
bob `hasContactProfiles` ["alisa", "bob"]
checkAliceProfileLink bob "alisa" cLink
checkAliceProfileLink bob "alisa" sLink
-- profile update does not remove contact address from profile
alice ##> "/p 'Alice Smith'"
@@ -5880,14 +5880,14 @@ testMembershipProfileUpdateContactActive =
bob <## "use @'Alice Smith' <message> to send messages"
bob `hasContactProfiles` ["Alice Smith", "bob"]
checkAliceProfileLink bob "'Alice Smith'" cLink
checkAliceProfileLink bob "'Alice Smith'" sLink
-- receiving group message does not remove contact address from profile
alice #> "#team team 2"
bob <# "#team 'Alice Smith'> team 2"
bob `hasContactProfiles` ["Alice Smith", "bob"]
checkAliceProfileLink bob "'Alice Smith'" cLink
checkAliceProfileLink bob "'Alice Smith'" sLink
checkItems bob
where
@@ -5899,13 +5899,13 @@ testMembershipProfileUpdateContactActive =
bob ##> "/_get chat #1 count=100"
rGrp <- chat <$> getTermLine bob
rGrp `shouldNotContain` [(0, "updated profile")]
checkAliceProfileLink bob name cLink = do
checkAliceProfileLink bob name sLink = do
bob ##> ("/info #team " <> name)
bob <## "group ID: 1"
bob <## "member ID: 1"
bob <##. "receiving messages via"
bob <##. "sending messages via"
bob <## ("contact address: " <> cLink)
bob <## ("contact address: " <> sLink)
bob <## "connection not verified, use /code command to see security code"
bob <## currentChatVRangeInfo
+141 -69
View File
@@ -48,10 +48,12 @@ chatProfileTests = do
it "deduplicate contact requests with profile change" testDeduplicateContactRequestsProfileChange
it "reject contact and delete contact link" testRejectContactAndDeleteUserContact
it "delete connection requests when contact link deleted" testDeleteConnectionRequests
-- TODO [short links] test auto-reply with current version, with connecting client not preparing contact
it "auto-reply message" testAutoReplyMessage
it "auto-reply message in incognito" testAutoReplyMessageInIncognito
describe "business address" $ do
it "create and connect via business address" testBusinessAddress
-- TODO [short links] test business auto-reply with current version, with connecting client not preparing contact
it "update profiles with business address" testBusinessUpdateProfiles
describe "contact address connection plan" $ do
it "contact address ok to connect; known contact" testPlanAddressOkKnown
@@ -60,6 +62,7 @@ chatProfileTests = do
it "connecting via contact address (slow handshake)" testPlanAddressConnectingSlow
it "re-connect with deleted contact" testPlanAddressContactDeletedReconnected
it "contact via address" testPlanAddressContactViaAddress
it "contact via short address" testPlanAddressContactViaShortAddress
describe "incognito" $ do
it "connect incognito via invitation link" testConnectIncognitoInvitationLink
it "connect incognito via contact address" testConnectIncognitoContactAddress
@@ -357,9 +360,9 @@ testProfileLink =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
alice ##> "/ad"
cLink <- getContactLink alice True
(sLink, _cLink) <- getContactLinks alice True
bob ##> ("/c " <> cLink)
bob ##> ("/c " <> sLink)
alice <#? bob
alice ##> "/ac bob"
alice <## "bob (Bob): accepting contact request, you can send messages to contact"
@@ -372,9 +375,9 @@ testProfileLink =
alice <## "new contact address set"
bob <## "alice set new contact address, use /info alice to view"
checkAliceProfileLink bob cLink
checkAliceProfileLink bob sLink
cath ##> ("/c " <> cLink)
cath ##> ("/c " <> sLink)
alice <#? cath
alice ##> "/ac cath"
alice <## "cath (Catherine): accepting contact request, you can send messages to contact"
@@ -383,7 +386,7 @@ testProfileLink =
(alice <## "cath (Catherine): contact is connected")
alice <##> cath
checkAliceProfileLink cath cLink
checkAliceProfileLink cath sLink
alice ##> "/pa off"
alice <## "contact address removed"
@@ -398,10 +401,10 @@ testProfileLink =
alice <## "new contact address set"
bob <## "alice set new contact address, use /info alice to view"
checkAliceProfileLink bob cLink
checkAliceProfileLink bob sLink
cath <## "alice set new contact address, use /info alice to view"
checkAliceProfileLink cath cLink
checkAliceProfileLink cath sLink
alice ##> "/da"
alice <## "Your chat address is deleted - accepted contacts will remain connected."
@@ -413,12 +416,12 @@ testProfileLink =
cath <## "alice removed contact address"
checkAliceNoProfileLink cath
where
checkAliceProfileLink cc cLink = do
checkAliceProfileLink cc sLink = do
cc ##> "/info alice"
cc <## "contact ID: 2"
cc <##. "receiving messages via"
cc <##. "sending messages via"
cc <## ("contact address: " <> cLink)
cc <## ("contact address: " <> sLink)
cc <## "you've shared main profile with this contact"
cc <## "connection not verified, use /code command to see security code"
cc <## "quantum resistant end-to-end encryption"
@@ -666,10 +669,10 @@ testDeleteConnectionRequests = testChat3 aliceProfile bobProfile cathProfile $
alice <#? cath
testAutoReplyMessage :: HasCallStack => TestParams -> IO ()
testAutoReplyMessage = testChat2 aliceProfile bobProfile $
testAutoReplyMessage = testChatCfg2 testCfgNoShortLinks aliceProfile bobProfile $
\alice bob -> do
alice ##> "/ad"
cLink <- getContactLink alice True
cLink <- getContactLinkNoShortLink alice True
alice ##> "/_auto_accept 1 on incognito=off text hello!"
alice <## "auto_accept on"
alice <## "auto reply:"
@@ -688,10 +691,10 @@ testAutoReplyMessage = testChat2 aliceProfile bobProfile $
]
testAutoReplyMessageInIncognito :: HasCallStack => TestParams -> IO ()
testAutoReplyMessageInIncognito = testChat2 aliceProfile bobProfile $
testAutoReplyMessageInIncognito = testChatCfg2 testCfgNoShortLinks aliceProfile bobProfile $
\alice bob -> do
alice ##> "/ad"
cLink <- getContactLink alice True
cLink <- getContactLinkNoShortLink alice True
alice ##> "/auto_accept on incognito=on text hello!"
alice <## "auto_accept on, incognito"
alice <## "auto reply:"
@@ -767,10 +770,10 @@ testBusinessAddress = testChat3 businessProfile aliceProfile {fullName = "Alice
(biz <# "#bob bob_1> hey there")
testBusinessUpdateProfiles :: HasCallStack => TestParams -> IO ()
testBusinessUpdateProfiles = testChat4 businessProfile aliceProfile bobProfile cathProfile $
testBusinessUpdateProfiles = testChatCfg4 testCfgNoShortLinks businessProfile aliceProfile bobProfile cathProfile $
\biz alice bob cath -> do
biz ##> "/ad"
cLink <- getContactLink biz True
cLink <- getContactLinkNoShortLink biz True
biz ##> "/auto_accept on business text Welcome"
biz <## "auto_accept on, business"
biz <## "auto reply:"
@@ -800,7 +803,7 @@ testBusinessUpdateProfiles = testChat4 businessProfile aliceProfile bobProfile c
biz ##> "/mr alisa alisa_1 admin"
biz <## "#alisa: you changed the role of alisa_1 to admin"
alice <## "#biz: biz_1 changed your role from member to admin"
connectUsers alice bob
connectUsersNoShortLink alice bob
alice ##> "/a #biz bob"
alice <## "invitation to join the group #biz sent to bob"
bob <## "#biz (Biz Inc): alisa invites you to join the group as member"
@@ -831,7 +834,7 @@ testBusinessUpdateProfiles = testChat4 businessProfile aliceProfile bobProfile c
alice <# "#biz robert> hi there"
biz <# "#alisa robert> hi there"
-- add business team member
connectUsers biz cath
connectUsersNoShortLink biz cath
biz ##> "/a #alisa cath"
biz <## "invitation to join the group #alisa sent to cath"
cath <## "#alisa: biz invites you to join the group as member"
@@ -1025,7 +1028,7 @@ testPlanAddressConnectingSlow :: HasCallStack => TestParams -> IO ()
testPlanAddressConnectingSlow ps = do
cLink <- withNewTestChatCfg ps testCfgSlow "alice" aliceProfile $ \alice -> do
alice ##> "/ad"
getContactLink alice True
getContactLinkNoShortLink alice True
withNewTestChatCfg ps testCfgSlow "bob" bobProfile $ \bob -> do
threadDelay 100000
@@ -1130,7 +1133,7 @@ testPlanAddressContactViaAddress =
testChat2 aliceProfile bobProfile $
\alice bob -> do
alice ##> "/ad"
cLink <- getContactLink alice True
(_sLink, cLink) <- getContactLinks alice True
alice ##> "/pa on" -- not necessary, without it bob would receive profile update removing contact link
alice <## "new contact address set"
@@ -1151,10 +1154,6 @@ testPlanAddressContactViaAddress =
bob ##> ("/_connect plan 1 " <> cLink)
bob <## "contact address: known contact without connection alice"
let cLinkSchema2 = linkAnotherSchema cLink
bob ##> ("/_connect plan 1 " <> cLinkSchema2)
bob <## "contact address: known contact without connection alice"
-- terminal api
bob ##> ("/c " <> cLink)
connecting alice bob
@@ -1175,6 +1174,68 @@ testPlanAddressContactViaAddress =
#endif
connecting alice bob
where
connecting alice bob = do
bob <## "connection request sent!"
alice <## "bob (Bob) wants to connect to you!"
alice <## "to accept: /ac bob"
alice <## "to reject: /rc bob (the sender will NOT be notified)"
alice ##> "/ac bob"
alice <## "bob (Bob): accepting contact request, you can send messages to contact"
concurrentlyN_
[ do
bob <## "alice set new contact address, use /info alice to view"
bob <## "alice (Alice): contact is connected",
alice <## "bob (Bob): contact is connected"
]
alice <##> bob
bob @@@ [("@alice", "hey")]
testPlanAddressContactViaShortAddress :: HasCallStack => TestParams -> IO ()
testPlanAddressContactViaShortAddress =
testChat2 aliceProfile bobProfile $
\alice bob -> do
alice ##> "/ad"
(sLink, _) <- getContactLinks alice True
alice ##> "/pa on" -- not necessary, without it bob would receive profile update removing contact link
alice <## "new contact address set"
case A.parseOnly strP (B.pack sLink) of
Left _ -> error "error parsing contact link"
Right shortLink -> do
let profile = aliceProfile {contactLink = Just shortLink}
void $ withCCUser bob $ \user -> withCCTransaction bob $ \db -> runExceptT $ createContact db user profile
bob @@@ [("@alice", "")]
bob ##> "/delete @alice"
bob <## "alice: contact is deleted"
void $ withCCUser bob $ \user -> withCCTransaction bob $ \db -> runExceptT $ createContact db user profile
bob @@@ [("@alice", "")]
bob ##> ("/_connect plan 1 " <> sLink)
bob <## "contact address: known contact without connection alice"
-- terminal api
bob ##> ("/c " <> sLink)
connecting alice bob
bob ##> "/delete @alice"
bob <## "alice: contact is deleted"
alice ##> "/delete @bob"
alice <## "bob: contact is deleted"
void $ withCCUser bob $ \user -> withCCTransaction bob $ \db -> runExceptT $ createContact db user profile
bob @@@ [("@alice", "")]
-- GUI api
#if defined(dbPostgres)
bob ##> "/_connect contact 1 4"
#else
bob ##> "/_connect contact 1 2"
#endif
connecting alice bob
where
connecting alice bob = do
bob <## "connection request sent!"
alice <## "bob (Bob) wants to connect to you!"
@@ -1185,7 +1246,6 @@ testPlanAddressContactViaAddress =
concurrently_
(bob <## "alice (Alice): contact is connected")
(alice <## "bob (Bob): contact is connected")
alice <##> bob
bob @@@ [("@alice", "hey")]
@@ -1302,10 +1362,10 @@ testConnectIncognitoContactAddress = testChat2 aliceProfile bobProfile $
bob `hasContactProfiles` ["bob"]
testAcceptContactRequestIncognito :: HasCallStack => TestParams -> IO ()
testAcceptContactRequestIncognito = testChat3 aliceProfile bobProfile cathProfile $
testAcceptContactRequestIncognito = testChatCfg3 testCfgNoShortLinks aliceProfile bobProfile cathProfile $
\alice bob cath -> do
alice ##> "/ad"
cLink <- getContactLink alice True
cLink <- getContactLinkNoShortLink alice True
-- GUI /_accept api
bob ##> ("/c " <> cLink)
alice <#? bob
@@ -1415,7 +1475,7 @@ testSetConnectionIncognitoProhibitedDuringNegotiationSlow ps = do
inv <- withNewTestChatCfg ps testCfgSlow "alice" aliceProfile $ \alice -> do
threadDelay 250000
alice ##> "/connect"
getInvitation alice
getInvitationNoShortLink alice
withNewTestChatCfg ps testCfgSlow "bob" bobProfile $ \bob -> do
threadDelay 250000
bob ##> ("/c " <> inv)
@@ -1869,14 +1929,18 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $
alice <## ""
_ <- getTermLine alice
alice <## ""
alice <## "The invitation link for old clients:"
_ <- getTermLine alice
alice ##> "/user alisa"
showActiveUser alice "alisa"
-- Change connection back to other user
alice ##> "/_set conn user :1 3"
alice <## "connection 1 changed from user alisa to user alisa2, new link:"
alice <## ""
inv <- getTermLine alice
_shortInv <- getTermLine alice
alice <## ""
alice <## "The invitation link for old clients:"
inv <- getTermLine alice
alice ##> "/user alisa2"
showActiveUser alice "alisa2"
-- Connect
@@ -1907,6 +1971,8 @@ testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $
alice <## ""
_ <- getTermLine alice
alice <## ""
alice <## "The invitation link for old clients:"
_ <- getTermLine alice
alice `hasContactProfiles` ["alice"]
alice ##> "/user alisa"
showActiveUser alice "alisa"
@@ -1914,8 +1980,10 @@ testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $
alice ##> "/_set conn user :1 1"
alice <## "connection 1 changed from user alisa to user alice, new link:"
alice <## ""
inv <- getTermLine alice
_shortInv <- getTermLine alice
alice <## ""
alice <## "The invitation link for old clients:"
inv <- getTermLine alice
alice ##> "/user alice"
showActiveUser alice "alice (Alice)"
-- Connect
@@ -1941,8 +2009,10 @@ testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $
alice ##> "/_set conn user :1 2"
alice <## "connection 1 changed from user alice to user alisa, new link:"
alice <## ""
inv <- getTermLine alice
_shortInv <- getTermLine alice
alice <## ""
alice <## "The invitation link for old clients:"
inv <- getTermLine alice
alice ##> "/user alisa"
showActiveUser alice "alisa"
-- Change connection to incognito and make sure it's attached to the newly created user profile
@@ -1992,8 +2062,10 @@ testChangePCCUserDiffSrv ps = do
alice ##> "/_set conn user :1 2"
alice <## "connection 1 changed from user alice to user alisa, new link:"
alice <## ""
inv <- getTermLine alice
_shortInv <- getTermLine alice
alice <## ""
alice <## "The invitation link for old clients:"
inv <- getTermLine alice
alice `hasContactProfiles` ["alice"]
alice ##> "/user alisa"
showActiveUser alice "alisa"
@@ -2645,8 +2717,8 @@ testSetUITheme =
testShortLinkInvitation :: HasCallStack => TestParams -> IO ()
testShortLinkInvitation =
testChat2 aliceProfile bobProfile $ \alice bob -> do
alice ##> "/c short"
(inv, _) <- getShortInvitation alice
alice ##> "/c"
(inv, _) <- getInvitations alice
bob ##> ("/c " <> inv)
bob <## "confirmation sent!"
concurrently_
@@ -2660,8 +2732,8 @@ testShortLinkInvitation =
testPlanShortLinkInvitation :: HasCallStack => TestParams -> IO ()
testPlanShortLinkInvitation =
testChat3 aliceProfile bobProfile cathProfile $ \alice bob cath -> do
alice ##> "/c short"
(inv, _) <- getShortInvitation alice
alice ##> "/c"
(inv, _) <- getInvitations alice
alice ##> ("/_connect plan 1 " <> inv)
alice <## "invitation link: own link"
alice ##> ("/_connect plan 1 " <> slSimplexScheme inv)
@@ -2702,8 +2774,8 @@ slSimplexScheme sl = T.unpack $ T.replace "https://localhost/" "simplex:/" (T.pa
testShortLinkContactAddress :: HasCallStack => TestParams -> IO ()
testShortLinkContactAddress =
testChat4 aliceProfile bobProfile cathProfile danProfile $ \alice bob cath dan -> do
alice ##> "/ad short"
(shortLink, fullLink) <- getShortContactLink alice True
alice ##> "/ad"
(shortLink, fullLink) <- getContactLinks alice True
alice ##> ("/_connect plan 1 " <> shortLink)
alice <## "contact address: own address"
alice ##> ("/_connect plan 1 " <> slSimplexScheme shortLink)
@@ -2741,13 +2813,13 @@ testShortLinkJoinGroup :: HasCallStack => TestParams -> IO ()
testShortLinkJoinGroup =
testChat4 aliceProfile bobProfile cathProfile danProfile $ \alice bob cath dan -> do
threadDelay 100000
alice ##> "/ad short" -- create the address to test that it can co-exist with group link
_ <- getShortContactLink alice True
alice ##> "/ad" -- create the address to test that it can co-exist with group link
_ <- getContactLinks alice True
alice ##> "/g team"
alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team"
alice ##> "/create link #team short"
(shortLink, fullLink) <- getShortGroupLink alice "team" GRMember True
alice ##> "/create link #team"
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
alice ##> ("/_connect plan 1 " <> shortLink)
alice <## "group link: own link for group #team"
alice ##> ("/_connect plan 1 " <> slSimplexScheme shortLink)
@@ -2810,8 +2882,8 @@ testShortLinkInvitationPrepareContact :: HasCallStack => TestParams -> IO ()
testShortLinkInvitationPrepareContact =
testChat2 aliceProfile bobProfile $
\alice bob -> do
alice ##> "/_connect 1 short=on"
(shortLink, fullLink) <- getShortInvitation alice
alice ##> "/_connect 1"
(shortLink, fullLink) <- getInvitations alice
bob ##> ("/_connect plan 1 " <> shortLink)
bob <## "invitation link: ok to connect"
contactSLinkData <- getTermLine bob
@@ -2830,8 +2902,8 @@ testShortLinkInvitationPrepareContact =
testShortLinkInvitationImage :: HasCallStack => TestParams -> IO ()
testShortLinkInvitationImage = testChat2 aliceProfile bobProfile $ \alice bob -> do
bob ##> "/_connect 1 short=on"
(shortLink, fullLink) <- getShortInvitation bob
bob ##> "/_connect 1"
(shortLink, fullLink) <- getInvitations bob
alice ##> ("/_connect plan 1 " <> shortLink)
alice <## "invitation link: ok to connect"
contactSLinkData <- getTermLine alice
@@ -2852,8 +2924,8 @@ testShortLinkAddressPrepareContact :: HasCallStack => TestParams -> IO ()
testShortLinkAddressPrepareContact =
testChat2 aliceProfile bobProfile $
\alice bob -> do
alice ##> "/ad short"
(shortLink, fullLink) <- getShortContactLink alice True
alice ##> "/ad"
(shortLink, fullLink) <- getContactLinks alice True
bob ##> ("/_connect plan 1 " <> shortLink)
bob <## "contact address: ok to connect"
contactSLinkData <- getTermLine bob
@@ -2884,8 +2956,8 @@ testShortLinkPrepareGroup =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup2 "team" alice cath
alice ##> "/create link #team short"
(shortLink, fullLink) <- getShortGroupLink alice "team" GRMember True
alice ##> "/create link #team"
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
bob ##> ("/_connect plan 1 " <> shortLink)
bob <## "group link: ok to connect"
groupSLinkData <- getTermLine bob
@@ -2916,8 +2988,8 @@ testShortLinkPrepareGroupReject =
testChatCfg3 cfg aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup2 "team" alice cath
alice ##> "/create link #team short"
(shortLink, fullLink) <- getShortGroupLink alice "team" GRMember True
alice ##> "/create link #team"
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
bob ##> ("/_connect plan 1 " <> shortLink)
bob <## "group link: ok to connect"
groupSLinkData <- getTermLine bob
@@ -2949,8 +3021,8 @@ testShortLinkChangePreparedContactUser =
bob ##> "/user bob"
showActiveUser bob "bob (Bob)"
alice ##> "/_connect 1 short=on"
(shortLink, fullLink) <- getShortInvitation alice
alice ##> "/_connect 1"
(shortLink, fullLink) <- getInvitations alice
bob ##> ("/_connect plan 1 " <> shortLink)
bob <## "invitation link: ok to connect"
contactSLinkData <- getTermLine bob
@@ -2998,8 +3070,8 @@ testShortLinkChangePreparedContactUserDuplicate =
bob ##> "/user bob"
showActiveUser bob "bob (Bob)"
alice ##> "/_connect 1 short=on"
(shortLink, fullLink) <- getShortInvitation alice
alice ##> "/_connect 1"
(shortLink, fullLink) <- getInvitations alice
bob ##> ("/_connect plan 1 " <> shortLink)
bob <## "invitation link: ok to connect"
contactSLinkData <- getTermLine bob
@@ -3047,8 +3119,8 @@ testShortLinkChangePreparedGroupUser =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup2 "team" alice cath
alice ##> "/create link #team short"
(shortLink, fullLink) <- getShortGroupLink alice "team" GRMember True
alice ##> "/create link #team"
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
bob ##> "/create user robert"
showActiveUser bob "robert"
@@ -3105,8 +3177,8 @@ testShortLinkChangePreparedGroupUserDuplicate =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup2 "team" alice cath
alice ##> "/create link #team short"
(shortLink, fullLink) <- getShortGroupLink alice "team" GRMember True
alice ##> "/create link #team"
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
bob ##> "/create user robert"
showActiveUser bob "robert"
@@ -3217,8 +3289,8 @@ testShortLinkInvitationSetIncognito :: HasCallStack => TestParams -> IO ()
testShortLinkInvitationSetIncognito =
testChat2 aliceProfile bobProfile $
\alice bob -> do
alice ##> "/_connect 1 short=on"
(shortLink, fullLink) <- getShortInvitation alice
alice ##> "/_connect 1"
(shortLink, fullLink) <- getInvitations alice
alice ##> "/_set incognito :1 on"
aliceIncognito <- getTermLine alice
@@ -3256,8 +3328,8 @@ testShortLinkInvitationChangeUser =
alice ##> "/user alice"
showActiveUser alice "alice (Alice)"
alice ##> "/_connect 1 short=on"
_ <- getShortInvitation alice
alice ##> "/_connect 1"
_ <- getInvitations alice
alice ##> "/_set conn user :1 2"
alice <## "connection 1 changed from user alice to user alisa, new link:"
@@ -3289,8 +3361,8 @@ testShortLinkAddressChangeProfile :: HasCallStack => TestParams -> IO ()
testShortLinkAddressChangeProfile =
testChat2 aliceProfile bobProfile $
\alice bob -> do
alice ##> "/ad short"
(shortLink, fullLink) <- getShortContactLink alice True
alice ##> "/ad"
(shortLink, fullLink) <- getContactLinks alice True
alice ##> "/p alisa"
alice <## "user profile is changed to alisa (your 0 contacts are notified)"
@@ -3324,8 +3396,8 @@ testShortLinkAddressChangeAutoReply :: HasCallStack => TestParams -> IO ()
testShortLinkAddressChangeAutoReply =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
alice ##> "/ad short"
(shortLink, fullLink) <- getShortContactLink alice True
alice ##> "/ad"
(shortLink, fullLink) <- getContactLinks alice True
alice ##> "/_auto_accept 1 on incognito=off text welcome!"
alice <## "auto_accept on"
@@ -3378,8 +3450,8 @@ testShortLinkGroupChangeProfile =
testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup2 "team" alice cath
alice ##> "/create link #team short"
(shortLink, fullLink) <- getShortGroupLink alice "team" GRMember True
alice ##> "/create link #team"
(shortLink, fullLink) <- getGroupLinks alice "team" GRMember True
alice ##> "/gp team club"
alice <## "changed to #club"
+59 -34
View File
@@ -101,15 +101,15 @@ skip :: String -> SpecWith a -> SpecWith a
skip = before_ . pendingWith
-- Bool is pqExpected - see testAddContact
versionTestMatrix2 :: (HasCallStack => Bool -> TestCC -> TestCC -> IO ()) -> SpecWith TestParams
versionTestMatrix2 :: (HasCallStack => Bool -> Bool -> TestCC -> TestCC -> IO ()) -> SpecWith TestParams
versionTestMatrix2 runTest = do
it "current" $ testChat2 aliceProfile bobProfile (runTest True)
it "prev" $ testChatCfg2 testCfgVPrev aliceProfile bobProfile (runTest False)
it "prev to curr" $ runTestCfg2 testCfg testCfgVPrev (runTest False)
it "curr to prev" $ runTestCfg2 testCfgVPrev testCfg (runTest False)
it "old (1st supported)" $ testChatCfg2 testCfgV1 aliceProfile bobProfile (runTest False)
it "old to curr" $ runTestCfg2 testCfg testCfgV1 (runTest False)
it "curr to old" $ runTestCfg2 testCfgV1 testCfg (runTest False)
it "current" $ testChat2 aliceProfile bobProfile (runTest True True)
it "prev" $ testChatCfg2 testCfgVPrev aliceProfile bobProfile (runTest False True)
it "prev to curr" $ runTestCfg2 testCfg testCfgVPrev (runTest False True)
it "curr to prev" $ runTestCfg2 testCfgVPrev testCfg (runTest False True)
it "old (1st supported)" $ testChatCfg2 testCfgV1 aliceProfile bobProfile (runTest False False)
it "old to curr" $ runTestCfg2 testCfg testCfgV1 (runTest False True)
it "curr to old" $ runTestCfg2 testCfgV1 testCfg (runTest False False)
versionTestMatrix3 :: (HasCallStack => TestCC -> TestCC -> TestCC -> IO ()) -> SpecWith TestParams
versionTestMatrix3 runTest = do
@@ -506,35 +506,44 @@ dropPartialReceipt_ msg = case splitAt 2 msg of
getInvitation :: HasCallStack => TestCC -> IO String
getInvitation cc = do
(inv, _) <- getInvitation_ False cc
pure inv
(_, fullInv) <- getInvitations cc
pure fullInv
getShortInvitation :: HasCallStack => TestCC -> IO (String, String)
getShortInvitation = getInvitation_ True
getInvitations :: HasCallStack => TestCC -> IO (String, String)
getInvitations cc = do
shortInv <- getInvitation_ cc
cc <##. "The invitation link for old clients:"
fullInv <- getTermLine cc
pure (shortInv, fullInv)
getInvitation_ :: HasCallStack => Bool -> TestCC -> IO (String, String)
getInvitation_ short cc = do
getInvitationNoShortLink :: HasCallStack => TestCC -> IO String
getInvitationNoShortLink = getInvitation_
getInvitation_ :: HasCallStack => TestCC -> IO String
getInvitation_ cc = do
cc <## "pass this invitation link to your contact (via another channel):"
cc <## ""
inv <- getTermLine cc
cc <## ""
cc <## "and ask them to connect: /c <invitation_link_above>"
fullLink <-
if short
then do
cc <##. "The invitation link for old clients:"
getTermLine cc
else pure ""
pure (inv, fullLink)
getShortContactLink :: HasCallStack => TestCC -> Bool -> IO (String, String)
getShortContactLink cc created = do
shortLink <- getContactLink cc created
fullLink <- dropLinePrefix "The contact link for old clients: " =<< getTermLine cc
pure (shortLink, fullLink)
pure inv
getContactLink :: HasCallStack => TestCC -> Bool -> IO String
getContactLink cc created = do
(_shortLink, fullLink) <- getContactLinks cc created
pure fullLink
getContactLinks :: HasCallStack => TestCC -> Bool -> IO (String, String)
getContactLinks cc created = do
shortLink <- getContactLink_ cc created
fullLink <- dropLinePrefix "The contact link for old clients: " =<< getTermLine cc
pure (shortLink, fullLink)
getContactLinkNoShortLink :: HasCallStack => TestCC -> Bool -> IO String
getContactLinkNoShortLink = getContactLink_
getContactLink_ :: HasCallStack => TestCC -> Bool -> IO String
getContactLink_ cc created = do
cc <## if created then "Your new chat address is created!" else "Your chat address:"
cc <## ""
link <- getTermLine cc
@@ -550,14 +559,22 @@ dropLinePrefix line s
| line `isPrefixOf` s = pure $ drop (length line) s
| otherwise = error $ "expected to start from: " <> line <> ", got: " <> s
getShortGroupLink :: HasCallStack => TestCC -> String -> GroupMemberRole -> Bool -> IO (String, String)
getShortGroupLink cc gName mRole created = do
shortLink <- getGroupLink cc gName mRole created
getGroupLink :: HasCallStack => TestCC -> String -> GroupMemberRole -> Bool -> IO String
getGroupLink cc gName mRole created = do
(_shortLink, fullLink) <- getGroupLinks cc gName mRole created
pure fullLink
getGroupLinks :: HasCallStack => TestCC -> String -> GroupMemberRole -> Bool -> IO (String, String)
getGroupLinks cc gName mRole created = do
shortLink <- getGroupLink_ cc gName mRole created
fullLink <- dropLinePrefix "The group link for old clients: " =<< getTermLine cc
pure (shortLink, fullLink)
getGroupLink :: HasCallStack => TestCC -> String -> GroupMemberRole -> Bool -> IO String
getGroupLink cc gName mRole created = do
getGroupLinkNoShortLink :: HasCallStack => TestCC -> String -> GroupMemberRole -> Bool -> IO String
getGroupLinkNoShortLink = getGroupLink_
getGroupLink_ :: HasCallStack => TestCC -> String -> GroupMemberRole -> Bool -> IO String
getGroupLink_ cc gName mRole created = do
cc <## if created then "Group link is created!" else "Group link:"
cc <## ""
link <- getTermLine cc
@@ -646,12 +663,20 @@ showActiveUser cc name = do
cc <## "use /p <display name> to change it"
cc <## "(the updated profile will be sent to all your contacts)"
connectUsersNoShortLink :: HasCallStack => TestCC -> TestCC -> IO ()
connectUsersNoShortLink cc1 cc2 = connectUsers_ cc1 cc2 True
connectUsers :: HasCallStack => TestCC -> TestCC -> IO ()
connectUsers cc1 cc2 = do
connectUsers cc1 cc2 = connectUsers_ cc1 cc2 False
connectUsers_ :: HasCallStack => TestCC -> TestCC -> Bool -> IO ()
connectUsers_ cc1 cc2 noShortLink = do
name1 <- showName cc1
name2 <- showName cc2
cc1 ##> "/c"
inv <- getInvitation cc1
inv <- if noShortLink
then getInvitationNoShortLink cc1
else getInvitation cc1
cc2 ##> ("/c " <> inv)
cc2 <## "confirmation sent!"
concurrently_