diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a5a07a8722..c41fb4646a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,6 +65,11 @@ jobs: asset_name: simplex-chat-ubuntu-22_04-x86-64 desktop_asset_name: simplex-desktop-ubuntu-22_04-x86_64.deb - os: macos-latest + ghc: "9.6.3" + cache_path: ~/.cabal/store + asset_name: simplex-chat-macos-aarch64 + desktop_asset_name: simplex-desktop-macos-aarch64.dmg + - os: macos-13 ghc: "9.6.3" cache_path: ~/.cabal/store asset_name: simplex-chat-macos-x86-64 @@ -107,18 +112,36 @@ jobs: if: matrix.os == 'macos-latest' shell: bash run: | - echo "ignore-project: False" >> cabal.project.local - echo "package direct-sqlcipher" >> cabal.project.local - echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local - echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local - echo " flags: +openssl" >> cabal.project.local + echo "ignore-project: False" >> cabal.project.local + echo "package simplexmq" >> cabal.project.local + echo " extra-include-dirs: /opt/homebrew/opt/openssl@1.1/include" >> cabal.project.local + echo " extra-lib-dirs: /opt/homebrew/opt/openssl@1.1/lib" >> cabal.project.local + echo "" >> cabal.project.local + echo "package direct-sqlcipher" >> cabal.project.local + echo " extra-include-dirs: /opt/homebrew/opt/openssl@1.1/include" >> cabal.project.local + echo " extra-lib-dirs: /opt/homebrew/opt/openssl@1.1/lib" >> cabal.project.local + echo " flags: +openssl" >> cabal.project.local + + - name: Unix prepare cabal.project.local for Mac + if: matrix.os == 'macos-13' + shell: bash + run: | + echo "ignore-project: False" >> cabal.project.local + echo "package simplexmq" >> cabal.project.local + echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local + echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local + echo "" >> cabal.project.local + echo "package direct-sqlcipher" >> cabal.project.local + echo " extra-include-dirs: /usr/local/opt/openssl@1.1/include" >> cabal.project.local + echo " extra-lib-dirs: /usr/local/opt/openssl@1.1/lib" >> cabal.project.local + echo " flags: +openssl" >> cabal.project.local - name: Install AppImage dependencies if: startsWith(github.ref, 'refs/tags/v') && matrix.asset_name && matrix.os == 'ubuntu-20.04' run: sudo apt install -y desktop-file-utils - name: Install pkg-config for Mac - if: matrix.os == 'macos-latest' + if: matrix.os == 'macos-latest' || matrix.os == 'macos-13' run: brew install pkg-config - name: Unix prepare cabal.project.local for Ubuntu @@ -190,7 +213,7 @@ jobs: - name: Mac build desktop id: mac_desktop_build - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'macos-latest' + if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13') shell: bash env: APPLE_SIMPLEX_SIGNING_KEYCHAIN: ${{ secrets.APPLE_SIMPLEX_SIGNING_KEYCHAIN }} @@ -241,7 +264,7 @@ jobs: ${{ steps.linux_appimage_build.outputs.appimage_hash }} - name: Mac upload desktop package to release - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'macos-latest' + if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13') uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -250,7 +273,7 @@ jobs: tag: ${{ github.ref }} - name: Mac update desktop package hash - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'macos-latest' + if: startsWith(github.ref, 'refs/tags/v') && (matrix.os == 'macos-latest' || matrix.os == 'macos-13') uses: softprops/action-gh-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift index ed724599be..95c3347f90 100644 --- a/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift +++ b/apps/ios/Shared/Views/Chat/ChatItem/FramedItemView.swift @@ -248,7 +248,10 @@ struct FramedItemView: View { Group { if let sender = qi.getSender(membership()) { VStack(alignment: .leading, spacing: 2) { - Text(sender).font(.caption).foregroundColor(.secondary) + Text(sender) + .font(.caption) + .foregroundColor(.secondary) + .lineLimit(1) ciQuotedMsgTextView(qi, lines: 2) } } else { diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 5ec69412a6..4055ca2b28 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -593,6 +593,7 @@ struct ChatView: View { Text(memberNames(member, prevMember, memCount)) .font(.caption) .foregroundStyle(.secondary) + .lineLimit(2) .padding(.leading, memberImageSize + 14) .padding(.top, 7) } diff --git a/apps/multiplatform/android/build.gradle.kts b/apps/multiplatform/android/build.gradle.kts index e2a5b49d0b..4e279d3ccb 100644 --- a/apps/multiplatform/android/build.gradle.kts +++ b/apps/multiplatform/android/build.gradle.kts @@ -13,7 +13,7 @@ android { defaultConfig { applicationId = "chat.simplex.app" namespace = "chat.simplex.app" - minSdk = 28 + minSdk = 26 //noinspection OldTargetApi targetSdk = 33 // !!! diff --git a/apps/multiplatform/common/build.gradle.kts b/apps/multiplatform/common/build.gradle.kts index 42e4ac2591..1f55a7195c 100644 --- a/apps/multiplatform/common/build.gradle.kts +++ b/apps/multiplatform/common/build.gradle.kts @@ -113,7 +113,7 @@ android { compileSdk = 34 sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") defaultConfig { - minSdk = 28 + minSdk = 26 } testOptions.targetSdk = 33 lint.targetSdk = 33 diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index ff5364adc2..e6f90c1599 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -1003,7 +1003,8 @@ fun BoxWithConstraintsScope.ChatItemsList( Text( memberNames(member, prevMember, memCount), Modifier.padding(start = MEMBER_IMAGE_SIZE + 10.dp), - style = TextStyle(fontSize = 13.5.sp, color = CurrentColors.value.colors.secondary) + style = TextStyle(fontSize = 13.5.sp, color = CurrentColors.value.colors.secondary), + maxLines = 2 ) } Row( diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt index a3b70e65ec..2ac97321c6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/FramedItemView.kt @@ -76,7 +76,8 @@ fun FramedItemView( ) { Text( sender, - style = TextStyle(fontSize = 13.5.sp, color = CurrentColors.value.colors.secondary) + style = TextStyle(fontSize = 13.5.sp, color = CurrentColors.value.colors.secondary), + maxLines = 1 ) ciQuotedMsgTextView(qi, lines = 2) } diff --git a/cabal.project b/cabal.project index e3a7628eb2..a8d751d4b8 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 8d8010a62aef2241fec3876fcfe57d51456b2bc0 + tag: 93fd424f86086c6f378b50e343f32ec47f8b0c3f source-repository-package type: git diff --git a/docs/FAQ.md b/docs/FAQ.md index 2484738808..a9f94b49eb 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -23,6 +23,7 @@ revision: 23.04.2024 - [I see image preview but cannot open the image](#i-see-image-preview-but-cannot-open-the-image) - [I cannot play a voice message](#i-cannot-play-a-voice-message) - [Audio or video calls do not connect](#audio-or-video-calls-do-not-connect) +- [Audio or video calls without e2e encryption](#audio-or-video-calls-without-e2e-encryption) - [I clicked the link to connect, but could not connect](#i-clicked-the-link-to-connect-but-could-not-connect) [Privacy and security](#privacy-and-security) @@ -161,6 +162,21 @@ If you can connect to the server, please report this issue to us privately, incl Thank you for helping us debug and improve calls. +### Audio or video calls without e2e encryption + +During the call, the app indicates whether or not the call has end-to-end encryption. + +If one of the call parties uses Android (or desktop) app, the call would use Android system webview (or browser). Some older systems do not support media stream encryption, in which case the call will connect without it. + +To determine whether it is the limitation of your, your contact's or both devices: +- if some of your calls have e2e encryption but some don't, then it's certainly the old webview version or browser of your contacts - please ask them to upgrade. +- if you are not sure, you can check at what point "no e2e encryption" appears: + - if it is shown when the call rings on your device, then your contact's device does not support call encryption. + - if it is shown on your screen as soon as you start the call, then your device does not support call encryption. + - if in the beginning of the call your device shows "e2e encryption" but when your contact accepts the call it changes to "no e2e encryption", then it is only your contact's device that does not support it. + +You need to upgrade webview (some Android systems allow it), Android system or the device to have support for e2e encryption in the calls - all modern webviews (and browsers) support it. + ### I clicked the link to connect, but could not connect If you confirmed the connection in the app, pending connection will be shown in the list of chats - you can assign the name to it, so you know who it was when your contact is connected (e.g., if they choose some name you don't recognize). diff --git a/package.yaml b/package.yaml index 054cddd9be..7201b664ac 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: simplex-chat -version: 5.7.0.5 +version: 5.7.1.0 #synopsis: #description: homepage: https://github.com/simplex-chat/simplex-chat#readme diff --git a/scripts/desktop/build-desktop-mac-ci.sh b/scripts/desktop/build-desktop-mac-ci.sh index 07a3db9c8e..f4c0bdfb98 100755 --- a/scripts/desktop/build-desktop-mac-ci.sh +++ b/scripts/desktop/build-desktop-mac-ci.sh @@ -8,7 +8,7 @@ echo "desktop.mac.signing.keychain=/tmp/simplex.keychain" >> apps/multiplatform/ echo "desktop.mac.notarization.apple_id=$APPLE_SIMPLEX_NOTARIZATION_APPLE_ID" >> apps/multiplatform/local.properties echo "desktop.mac.notarization.password=$APPLE_SIMPLEX_NOTARIZATION_PASSWORD" >> apps/multiplatform/local.properties echo "desktop.mac.notarization.team_id=5NN7GUYB6T" >> apps/multiplatform/local.properties -echo "$APPLE_SIMPLEX_SIGNING_KEYCHAIN" | base64 --decode - > /tmp/simplex.keychain +echo "$APPLE_SIMPLEX_SIGNING_KEYCHAIN" | base64 --decode -o /tmp/simplex.keychain scripts/desktop/build-lib-mac.sh cd apps/multiplatform diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 0b37e0eb20..995d096223 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."8d8010a62aef2241fec3876fcfe57d51456b2bc0" = "0x7fq33c0x7i9jjp42la3zkha1wk6s3bv7dkz9z39a02s9rfkfla"; + "https://github.com/simplex-chat/simplexmq.git"."93fd424f86086c6f378b50e343f32ec47f8b0c3f" = "1jijzj8k4pxv4ri76n1m1c576w0g78vl39z8x2mhyyfip7zcal4i"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/simplex-chat.cabal b/simplex-chat.cabal index a72b51b82a..e9e1a4a723 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: simplex-chat -version: 5.7.0.5 +version: 5.7.1.0 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index e13dbfcbff..8a3541af0a 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -1494,8 +1494,9 @@ processChatCommand' vr = \case Just (agentV, pqSup') -> do let chatV = agentToChatVersion agentV dm <- encodeConnInfoPQ pqSup' chatV $ XInfo profileToSend - connId <- withAgent $ \a -> joinConnection a (aUserId user) True cReq dm pqSup' subMode + connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq pqSup' conn <- withStore' $ \db -> createDirectConnection db user connId cReq ConnJoined (incognitoProfile $> profileToSend) subMode chatV pqSup' + void . withAgent $ \a -> joinConnection a (aUserId user) (Just connId) True cReq dm pqSup' subMode pure $ CRSentConfirmation user conn APIConnect userId incognito (Just (ACR SCMContact cReq)) -> withUserId userId $ \user -> connectViaContact user incognito cReq APIConnect _ _ Nothing -> throwChatError CEInvalidConnReq @@ -1748,12 +1749,13 @@ processChatCommand' vr = \case Just Connection {peerChatVRange} -> do subMode <- chatReadVar subscriptionMode dm <- encodeConnInfo $ XGrpAcpt membershipMemId - agentConnId <- withAgent $ \a -> joinConnection a (aUserId user) True connRequest dm PQSupportOff subMode + agentConnId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True connRequest PQSupportOff let chatV = vr `peerConnChatVersion` peerChatVRange withStore' $ \db -> do createMemberConnection db userId fromMember agentConnId chatV peerChatVRange subMode updateGroupMemberStatus db userId fromMember GSMemAccepted updateGroupMemberStatus db userId membership GSMemAccepted + void . withAgent $ \a -> joinConnection a (aUserId user) (Just agentConnId) True connRequest dm PQSupportOff subMode updateCIGroupInvitationStatus user g CIGISAccepted `catchChatError` \_ -> pure () pure $ CRUserAcceptedGroupSent user g {membership = membership {memberStatus = GSMemAccepted}} Nothing Nothing -> throwChatError $ CEContactNotActive ct @@ -2278,23 +2280,28 @@ processChatCommand' vr = \case where connect' groupLinkId cReqHash xContactId inGroup = do let pqSup = if inGroup then PQSupportOff else PQSupportOn - (connId, incognitoProfile, subMode, chatV) <- requestContact user incognito cReq xContactId inGroup pqSup + (connId, chatV) <- prepareContact user cReq pqSup + -- [incognito] generate profile to send + incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing + subMode <- chatReadVar subscriptionMode conn <- withStore' $ \db -> createConnReqConnection db userId connId cReqHash xContactId incognitoProfile groupLinkId subMode chatV pqSup + joinContact user connId cReq incognitoProfile xContactId inGroup pqSup chatV pure $ CRSentInvitation user conn incognitoProfile connectContactViaAddress :: User -> IncognitoEnabled -> Contact -> ConnectionRequestUri 'CMContact -> CM ChatResponse connectContactViaAddress user incognito ct cReq = withInvitationLock "connectContactViaAddress" (strEncode cReq) $ do newXContactId <- XContactId <$> drgRandomBytes 16 let pqSup = PQSupportOn - (connId, incognitoProfile, subMode, chatV) <- requestContact user incognito cReq newXContactId False pqSup + (connId, chatV) <- prepareContact user cReq pqSup let cReqHash = ConnReqUriHash . C.sha256Hash $ strEncode cReq + -- [incognito] generate profile to send + incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing + subMode <- chatReadVar subscriptionMode ct' <- withStore $ \db -> createAddressContactConnection db vr user ct connId cReqHash newXContactId incognitoProfile subMode chatV pqSup + joinContact user connId cReq incognitoProfile newXContactId False pqSup chatV pure $ CRSentInvitationToContact user ct' incognitoProfile - requestContact :: User -> IncognitoEnabled -> ConnectionRequestUri 'CMContact -> XContactId -> Bool -> PQSupport -> CM (ConnId, Maybe Profile, SubscriptionMode, VersionChat) - requestContact user incognito cReq xContactId inGroup pqSup = do - -- [incognito] generate profile to send - incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing - let profileToSend = userProfileToSend user incognitoProfile Nothing inGroup + prepareContact :: User -> ConnectionRequestUri 'CMContact -> PQSupport -> CM (ConnId, VersionChat) + prepareContact user cReq pqSup = do -- 0) toggle disabled - PQSupportOff -- 1) toggle enabled, address supports PQ (connRequestPQSupport returns Just True) - PQSupportOn, enable support with compression -- 2) toggle enabled, address doesn't support PQ - PQSupportOn but without compression, with version range indicating support @@ -2302,10 +2309,14 @@ processChatCommand' vr = \case Nothing -> throwChatError CEInvalidConnReq Just (agentV, _) -> do let chatV = agentToChatVersion agentV - dm <- encodeConnInfoPQ pqSup chatV (XContact profileToSend $ Just xContactId) - subMode <- chatReadVar subscriptionMode - connId <- withAgent $ \a -> joinConnection a (aUserId user) True cReq dm pqSup subMode - pure (connId, incognitoProfile, subMode, chatV) + connId <- withAgent $ \a -> prepareConnectionToJoin a (aUserId user) True cReq pqSup + pure (connId, chatV) + joinContact :: User -> ConnId -> ConnectionRequestUri 'CMContact -> Maybe Profile -> XContactId -> Bool -> PQSupport -> VersionChat -> CM () + joinContact user connId cReq incognitoProfile xContactId inGroup pqSup chatV = do + let profileToSend = userProfileToSend user incognitoProfile Nothing inGroup + dm <- encodeConnInfoPQ pqSup chatV (XContact profileToSend $ Just xContactId) + subMode <- chatReadVar subscriptionMode + void . withAgent $ \a -> joinConnection a (aUserId user) (Just connId) True cReq dm pqSup subMode contactMember :: Contact -> [GroupMember] -> Maybe GroupMember contactMember Contact {contactId} = find $ \GroupMember {memberContactId = cId, memberStatus = s} -> @@ -3532,6 +3543,8 @@ processAgentMessage _ connId (DEL_RCVQ srv qId err_) = toView $ CRAgentRcvQueueDeleted (AgentConnId connId) srv (AgentQueueId qId) err_ processAgentMessage _ connId DEL_CONN = toView $ CRAgentConnDeleted (AgentConnId connId) +processAgentMessage _ "" (ERR e) = + toView $ CRChatError Nothing $ ChatErrorAgent e Nothing processAgentMessage corrId connId msg = do lockEntity <- critical (withStore (`getChatLockEntity` AgentConnId connId)) withEntityLock "processAgentMessage" lockEntity $ do