From 90f5424aae73b51bd4c7049509b65e5716fe2e98 Mon Sep 17 00:00:00 2001 From: otsmr Date: Thu, 12 Mar 2026 22:45:09 +0100 Subject: [PATCH] fix issue with contact request --- ios/Podfile.lock | 16 ------ lib/src/database/daos/contacts.dao.dart | 2 +- .../api/client2client/contact.c2c.dart | 52 ++++++++++++------- lib/src/services/api/server_messages.dart | 6 +++ lib/src/views/chats/chat_list.view.dart | 2 +- .../views/groups/group_member.context.dart | 4 +- pubspec.lock | 16 ++---- pubspec.yaml | 4 +- 8 files changed, 49 insertions(+), 53 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fd0ae16..765da3f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -131,10 +131,6 @@ PODS: - google_mlkit_commons (0.11.1): - Flutter - MLKitVision (~> 10.0.0) - - google_mlkit_face_detection (0.13.2): - - Flutter - - google_mlkit_commons - - GoogleMLKit/FaceDetection (~> 9.0.0) - GoogleAdsOnDeviceConversion (3.2.0): - GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Logger (~> 8.1) @@ -168,9 +164,6 @@ PODS: - GoogleMLKit/BarcodeScanning (9.0.0): - GoogleMLKit/MLKitCore - MLKitBarcodeScanning (~> 8.0.0) - - GoogleMLKit/FaceDetection (9.0.0): - - GoogleMLKit/MLKitCore - - MLKitFaceDetection (~> 8.0.0) - GoogleMLKit/MLKitCore (9.0.0): - MLKitCommon (~> 14.0.0) - GoogleToolboxForMac/Defines (4.2.1) @@ -253,9 +246,6 @@ PODS: - GoogleUtilities/Logger (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0) - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) - - MLKitFaceDetection (8.0.0): - - MLKitCommon (~> 14.0) - - MLKitVision (~> 10.0) - MLKitVision (10.0.0): - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" @@ -360,7 +350,6 @@ DEPENDENCIES: - gal (from `.symlinks/plugins/gal/darwin`) - google_mlkit_barcode_scanning (from `.symlinks/plugins/google_mlkit_barcode_scanning/ios`) - google_mlkit_commons (from `.symlinks/plugins/google_mlkit_commons/ios`) - - google_mlkit_face_detection (from `.symlinks/plugins/google_mlkit_face_detection/ios`) - GoogleUtilities - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`) @@ -403,7 +392,6 @@ SPEC REPOS: - MLImage - MLKitBarcodeScanning - MLKitCommon - - MLKitFaceDetection - MLKitVision - nanopb - PromisesObjC @@ -457,8 +445,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/google_mlkit_barcode_scanning/ios" google_mlkit_commons: :path: ".symlinks/plugins/google_mlkit_commons/ios" - google_mlkit_face_detection: - :path: ".symlinks/plugins/google_mlkit_face_detection/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" in_app_purchase_storekit: @@ -524,7 +510,6 @@ SPEC CHECKSUMS: gal: baecd024ebfd13c441269ca7404792a7152fde89 google_mlkit_barcode_scanning: 12d8422d8f7b00726dedf9cac00188a2b98750c2 google_mlkit_commons: a5e4ffae5bc59ea4c7b9025dc72cb6cb79dc1166 - google_mlkit_face_detection: ee4b72cfae062b4c972204be955d83055a4bfd36 GoogleAdsOnDeviceConversion: d68c69dd9581a0f5da02617b6f377e5be483970f GoogleAppMeasurement: fce7c1c90640d2f9f5c56771f71deacb2ba3f98c GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 @@ -540,7 +525,6 @@ SPEC CHECKSUMS: MLImage: 0de5c6c2bf9e93b80ef752e2797f0836f03b58c0 MLKitBarcodeScanning: 39de223e7b1b8a8fbf10816a536dd292d8a39343 MLKitCommon: 47d47b50a031d00db62f1b0efe5a1d8b09a3b2e6 - MLKitFaceDetection: 32549f1e70e6e7731261bf9cea2b74095e2531cb MLKitVision: 39a5a812db83c4a0794445088e567f3631c11961 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 no_screenshot: 5e345998c43ffcad5d6834f249590483fcc037bd diff --git a/lib/src/database/daos/contacts.dao.dart b/lib/src/database/daos/contacts.dao.dart index e1de840..912c4eb 100644 --- a/lib/src/database/daos/contacts.dao.dart +++ b/lib/src/database/daos/contacts.dao.dart @@ -110,7 +110,7 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { return query.map((row) => row.read(count)).watchSingle(); } - Stream watchContactsRequested() { + Stream watchContactsRequestedCount() { final count = contacts.requested.count(distinct: true); final query = selectOnly(contacts) ..where( diff --git a/lib/src/services/api/client2client/contact.c2c.dart b/lib/src/services/api/client2client/contact.c2c.dart index 83233a1..e9581ce 100644 --- a/lib/src/services/api/client2client/contact.c2c.dart +++ b/lib/src/services/api/client2client/contact.c2c.dart @@ -18,7 +18,15 @@ Future handleNewContactRequest(int fromUserId) async { .getContactByUserId(fromUserId) .getSingleOrNull(); if (contact != null) { - if (contact.accepted) { + // Either the contact has accepted the fromUserId already: Then just blindly accept the request. + // Or the user has also requested fromUserId. This means that both user have requested each other (while been + // offline for example): In this case the contact can also be accepted blindly. + if (contact.accepted || (!contact.requested && !contact.deletedByUser)) { + if (!contact.accepted) { + // User has also requested the fromUserId, so mark the user as accepted. + await handleContactAccept(fromUserId); + } + // contact was already accepted, so just accept the request in the background. await sendCipherText( contact.userId, @@ -50,6 +58,28 @@ Future handleNewContactRequest(int fromUserId) async { return true; } +Future handleContactAccept(int fromUserId) async { + await twonlyDB.contactsDao.updateContact( + fromUserId, + const ContactsCompanion( + requested: Value(false), + accepted: Value(true), + deletedByUser: Value(false), + ), + ); + final contact = await twonlyDB.contactsDao + .getContactByUserId(fromUserId) + .getSingleOrNull(); + if (contact != null) { + await twonlyDB.groupsDao.createNewDirectChat( + fromUserId, + GroupsCompanion( + groupName: Value(getContactDisplayName(contact)), + ), + ); + } +} + Future handleContactRequest( int fromUserId, EncryptedContent_ContactRequest contactRequest, @@ -60,25 +90,7 @@ Future handleContactRequest( return handleNewContactRequest(fromUserId); case EncryptedContent_ContactRequest_Type.ACCEPT: Log.info('Got a contact accept from $fromUserId'); - await twonlyDB.contactsDao.updateContact( - fromUserId, - const ContactsCompanion( - requested: Value(false), - accepted: Value(true), - deletedByUser: Value(false), - ), - ); - final contact = await twonlyDB.contactsDao - .getContactByUserId(fromUserId) - .getSingleOrNull(); - if (contact != null) { - await twonlyDB.groupsDao.createNewDirectChat( - fromUserId, - GroupsCompanion( - groupName: Value(getContactDisplayName(contact)), - ), - ); - } + await handleContactAccept(fromUserId); case EncryptedContent_ContactRequest_Type.REJECT: Log.info('Got a contact reject from $fromUserId'); await twonlyDB.contactsDao.updateContact( diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index 3f88459..af5bbd3 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -26,6 +26,7 @@ import 'package:twonly/src/services/api/client2client/text_message.c2c.dart'; import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/services/group.services.dart'; import 'package:twonly/src/services/signal/encryption.signal.dart'; +import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -94,6 +95,11 @@ Future handleClient2ClientMessage(NewMessage newMessage) async { var retry = false; if (message.hasPlaintextContent()) { if (message.plaintextContent.hasDecryptionErrorMessage()) { + if (message.plaintextContent.decryptionErrorMessage.type == + PlaintextContent_DecryptionErrorMessage_Type.PREKEY_UNKNOWN) { + // Get a new prekey from the server, and establish a new signal session. + await handleSessionResync(fromUserId); + } Log.info( 'Got decryption error: ${message.plaintextContent.decryptionErrorMessage.type} for $receiptId', ); diff --git a/lib/src/views/chats/chat_list.view.dart b/lib/src/views/chats/chat_list.view.dart index d49791b..5501361 100644 --- a/lib/src/views/chats/chat_list.view.dart +++ b/lib/src/views/chats/chat_list.view.dart @@ -138,7 +138,7 @@ class _ChatListViewState extends State { actions: [ const FeedbackIconButton(), StreamBuilder( - stream: twonlyDB.contactsDao.watchContactsRequested(), + stream: twonlyDB.contactsDao.watchContactsRequestedCount(), builder: (context, snapshot) { var count = 0; if (snapshot.hasData && snapshot.data != null) { diff --git a/lib/src/views/groups/group_member.context.dart b/lib/src/views/groups/group_member.context.dart index 543e0c8..974a584 100644 --- a/lib/src/views/groups/group_member.context.dart +++ b/lib/src/views/groups/group_member.context.dart @@ -93,7 +93,9 @@ class GroupMemberContextMenu extends StatelessWidget { await twonlyDB.contactsDao.updateContact( member.contactId, const ContactsCompanion( - requested: Value(true), + accepted: Value(false), + requested: Value(false), + deletedByUser: Value(false), ), ); await sendCipherText( diff --git a/pubspec.lock b/pubspec.lock index da0924f..ac5cb25 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -341,18 +341,18 @@ packages: dependency: "direct main" description: name: cryptography_flutter_plus - sha256: "35a8c270aae0abaac7125a6b6b33c2b3daa0ea90d85320aa7d588b6dd6c2edc9" + sha256: "65bc0a78c2104cdb02f4b69e3a03abef093e660d9d9208bc81942b058b49deb2" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "3.0.0" cryptography_plus: dependency: "direct main" description: name: cryptography_plus - sha256: "34db787df4f4740a39474b6fb0a610aa6dc13a5b5b68754b4787a79939ac0454" + sha256: edf96fc96518368b11bb1ba33b515f59aa5a55b0aa7533c0e1813399cf81130e url: "https://pub.dev" source: hosted - version: "2.7.1" + version: "3.0.0" csslib: dependency: transitive description: @@ -1080,14 +1080,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.14.2" - js: - dependency: transitive - description: - name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" - source: hosted - version: "0.7.2" json_annotation: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e2f2654..770e795 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -98,8 +98,8 @@ dependencies: avatar_maker: ^0.4.0 background_downloader: ^9.4.0 cached_network_image: ^3.4.1 - cryptography_flutter_plus: ^2.3.4 - cryptography_plus: ^2.7.0 + cryptography_flutter_plus: ^3.0.0 + cryptography_plus: ^3.0.0 flutter_android_volume_keydown: ^1.0.1 flutter_image_compress: ^2.4.0 flutter_volume_controller: ^1.3.4