From e43169c2d23e00976224dad8d03eefbe7b1c48e3 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 29 Aug 2026 13:44:10 +0200 Subject: [PATCH] remove legacy signal encryption --- dependencies.yaml | 19 - integration_test/api_service.test.dart | 16 +- lib/core/bridge/api.dart | 20 +- lib/core/bridge/callbacks.dart | 66 +- lib/core/bridge/wrapper/key_manager.dart | 30 - lib/core/bridge/wrapper/signal.dart | 10 + lib/core/frb_generated.dart | 994 ++----- lib/core/frb_generated.io.dart | 174 +- lib/core/frb_generated.web.dart | 174 +- lib/locator.dart | 3 - lib/src/callbacks/callbacks.dart | 5 - .../callbacks/legacy_signal.callbacks.dart | 67 - lib/src/database/daos/groups.dao.dart | 9 +- .../database/daos/key_verification.dao.dart | 56 +- lib/src/database/daos/signal.dao.g.dart | 31 - lib/src/database/signal.db.dart | 47 - lib/src/database/signal.db.g.dart | 2383 ----------------- .../signal/signal_identity_key_store.dart | 81 - .../database/signal/signal_pre_key_store.dart | 52 - .../signal/signal_protocol_store.dart | 122 - .../signal/signal_sender_key_store.dart | 35 - .../database/signal/signal_session_store.dart | 87 - .../signal/signal_signed_pre_key_store.dart | 84 - .../signal_identity_key_store.table.dart | 12 - .../tables/signal_pre_key_store.table.dart | 11 - .../tables/signal_sender_key_store.table.dart | 10 - .../tables/signal_session_store.table.dart | 12 - .../signal_signed_pre_key_store.table.dart | 11 - lib/src/model/json/signal_identity.model.dart | 35 - .../model/json/signal_identity.model.g.dart | 23 - lib/src/services/api/api.service.dart | 2 - lib/src/services/api/utils.api.dart | 39 +- lib/src/services/group.service.dart | 3 +- lib/src/services/intent/links.intent.dart | 9 +- .../services/key_verification.service.dart | 16 +- lib/src/services/migrations.service.dart | 89 +- .../passwordless_recovery.service.dart | 6 +- lib/src/services/signal/consts.signal.dart | 2 - .../services/signal/encryption.signal.dart | 159 -- lib/src/services/signal/identity.signal.dart | 72 - .../signal/protocol_state.signal.dart | 38 - lib/src/services/signal/session.signal.dart | 219 -- lib/src/services/signal/utils.signal.dart | 26 - lib/src/services/user.service.dart | 6 +- lib/src/utils/qr.utils.dart | 83 +- .../main_camera_controller.dart | 24 +- .../link_preview/parser/twitter.parser.dart | 4 + .../empty_chat_list.comp.dart | 4 +- .../views/contact/add_new_contact.view.dart | 4 +- .../visual/views/contact/contact.view.dart | 19 +- lib/src/visual/views/groups/group.view.dart | 17 +- .../views/onboarding/register.view.dart | 3 - lib/src/visual/views/public_profile.view.dart | 4 +- .../developer/automated_testing.view.dart | 53 - pubspec.lock | 42 - pubspec.yaml | 18 - rust/Cargo.toml | 12 +- rust/src/api/messages/incoming.rs | 73 +- rust/src/api/messages/incoming/messages.rs | 244 +- .../api/websocket/client_to_server.proto | 37 +- rust/src/api/runtime/auth.rs | 34 +- rust/src/api/runtime/client.rs | 2 - rust/src/api/runtime/request.rs | 56 +- rust/src/api/server/account.rs | 113 +- rust/src/api/server/prekeys.rs | 22 +- rust/src/api/server/transport.rs | 7 + rust/src/backup/backup_identity.rs | 5 +- rust/src/bridge/api.rs | 41 +- rust/src/bridge/callbacks.rs | 20 - rust/src/bridge/wrapper/key_manager.rs | 63 +- rust/src/bridge/wrapper/signal.rs | 12 + rust/src/context.rs | 4 +- rust/src/frb_generated.rs | 744 ++--- rust/src/keys/backup_password_keys.rs | 2 +- .../keys/identity_key/signal_identity_key.rs | 22 +- rust/src/keys/mod.rs | 134 +- rust/src/sealed_sender.rs | 5 +- rust/src/services/contacts.rs | 32 +- rust/src/services/groups/mod.rs | 8 + rust/src/signal/engine.rs | 62 +- rust/tests/api/group_resilience.rs | 127 + rust/tests/api/tester.rs | 35 +- test/features/flame_counter_test.dart | 2 +- test/features/link_parser_test.dart | 4 +- test/mocks/test_client.dart | 48 +- test/mocks/user_environment.dart | 10 - test/rust/create_db_for_rust_testing.dart | 2 +- test/services/api_and_c2c_test.dart | 4 +- test/services/cloud_backup_test.dart | 2 + .../key_verification_service_test.dart | 20 +- .../passwordless_recovery_service_test.dart | 51 +- test/signal/key_generation.dart | 25 - test/signal/pqc_c2c_test.dart | 220 -- test/signal/pqc_migration_test.dart | 182 -- 94 files changed, 1625 insertions(+), 6501 deletions(-) delete mode 100644 lib/src/callbacks/legacy_signal.callbacks.dart delete mode 100644 lib/src/database/daos/signal.dao.g.dart delete mode 100644 lib/src/database/signal.db.dart delete mode 100644 lib/src/database/signal.db.g.dart delete mode 100644 lib/src/database/signal/signal_identity_key_store.dart delete mode 100644 lib/src/database/signal/signal_pre_key_store.dart delete mode 100644 lib/src/database/signal/signal_protocol_store.dart delete mode 100644 lib/src/database/signal/signal_sender_key_store.dart delete mode 100644 lib/src/database/signal/signal_session_store.dart delete mode 100644 lib/src/database/signal/signal_signed_pre_key_store.dart delete mode 100644 lib/src/database/tables/signal_identity_key_store.table.dart delete mode 100644 lib/src/database/tables/signal_pre_key_store.table.dart delete mode 100644 lib/src/database/tables/signal_sender_key_store.table.dart delete mode 100644 lib/src/database/tables/signal_session_store.table.dart delete mode 100644 lib/src/database/tables/signal_signed_pre_key_store.table.dart delete mode 100644 lib/src/model/json/signal_identity.model.dart delete mode 100644 lib/src/model/json/signal_identity.model.g.dart delete mode 100644 lib/src/services/signal/consts.signal.dart delete mode 100644 lib/src/services/signal/encryption.signal.dart delete mode 100644 lib/src/services/signal/identity.signal.dart delete mode 100644 lib/src/services/signal/protocol_state.signal.dart delete mode 100644 lib/src/services/signal/session.signal.dart delete mode 100644 lib/src/services/signal/utils.signal.dart delete mode 100644 test/signal/key_generation.dart delete mode 100644 test/signal/pqc_c2c_test.dart delete mode 100644 test/signal/pqc_migration_test.dart diff --git a/dependencies.yaml b/dependencies.yaml index f2430ae9..065c637b 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -63,25 +63,6 @@ dependencies: git: https://github.com/Pyozer/dots_indicator.git commit: 508f5883ac79bdbc10254092de3f28f571d261cd commit: 4a90e557630b28834479ed9c64a9d2d0185d8e48 - libsignal_protocol_dart: - git: https://github.com/MixinNetwork/libsignal_protocol_dart.git - dependencies: - adaptive_number: - git: https://github.com/lemoony/adaptive_number_dart - commit: ea9178fdd4d82ac45cf0ec966ac870dae661124f - ed25519_edwards: - git: https://github.com/Tougee/ed25519.git - commit: 7353ba759ea9f4646cbf481c2ef949625c8ce4cf - optional: - git: https://github.com/tonio-ramirez/optional.dart.git - commit: 71c638891ce4f2aff35c7387727989f31f9d877d - pointycastle: - git: https://github.com/bcgit/pc-dart.git - commit: bbd8569f68a7fccbdf0b92d0b44a9219c126c8dd - x25519: - git: https://github.com/Tougee/curve25519.git - commit: ecb1d357714537bba6e276ef45f093846d4beaee - commit: c95a1586057022acdbb9c76b1692d94cc549bcc7 lottie: git: https://github.com/xvrh/lottie-flutter.git commit: 127bc29f2c6bd8b32ec4064a09e54e6b31cd0a88 diff --git a/integration_test/api_service.test.dart b/integration_test/api_service.test.dart index 3b65146f..bd351b66 100644 --- a/integration_test/api_service.test.dart +++ b/integration_test/api_service.test.dart @@ -12,20 +12,10 @@ void main() { // Initialize global variables await initBackgroundExecution(); - // Try to connect to the API server - final connected = await apiService.connect(); + // Check the API connection state + final state = await RustApi.connectionState(); // Print out the result or test it - expect(connected, isA()); - - // We can also check if it's connected - // Depending on your test environment, this might be true or false - // if the server is unreachable without further setup - // expect(apiService.isConnected, isA()); - - // Close the connection after the test - if (apiService.isConnected) { - await apiService.close(() {}); - } + expect(state, isA()); }); } diff --git a/lib/core/bridge/api.dart b/lib/core/bridge/api.dart index 0e7909e5..f6816b08 100644 --- a/lib/core/bridge/api.dart +++ b/lib/core/bridge/api.dart @@ -122,6 +122,14 @@ class RustApi { static Future downloadPendingMedia() => RustLib.instance.api.crateBridgeApiRustApiDownloadPendingMedia(); + static Future establishSignalSession({ + required PlatformInt64 contactId, + Uint8List? expectedPublicKey, + }) => RustLib.instance.api.crateBridgeApiRustApiEstablishSignalSession( + contactId: contactId, + expectedPublicKey: expectedPublicKey, + ); + static Stream events() => RustLib.instance.api.crateBridgeApiRustApiEvents(); @@ -330,9 +338,9 @@ class RustApi { required PlatformInt64 contactId, required List content, String? messageId, - required bool onlySendIfNoReceiptsAreOpen, - required bool onlyReturnEncryptedData, - required bool blocking, + bool? onlySendIfNoReceiptsAreOpen, + bool? onlyReturnEncryptedData, + bool? blocking, }) => RustLib.instance.api.crateBridgeApiRustApiSendEncryptedContent( contactId: contactId, content: content, @@ -346,7 +354,7 @@ class RustApi { required String groupId, required List content, String? messageId, - required bool onlySendIfNoReceiptsAreOpen, + bool? onlySendIfNoReceiptsAreOpen, }) => RustLib.instance.api.crateBridgeApiRustApiSendEncryptedContentToGroup( groupId: groupId, content: content, @@ -410,6 +418,8 @@ class RustApi { ); static Future uploadPqcPreKeys({ + required List publicIdentityKey, + required PlatformInt64 registrationId, required PlatformInt64 eccSignedPrekeyId, required List eccSignedPrekey, required List eccSignedPrekeySignature, @@ -418,6 +428,8 @@ class RustApi { required List kyberSignedPrekeySignature, required List prekeys, }) => RustLib.instance.api.crateBridgeApiRustApiUploadPqcPreKeys( + publicIdentityKey: publicIdentityKey, + registrationId: registrationId, eccSignedPrekeyId: eccSignedPrekeyId, eccSignedPrekey: eccSignedPrekey, eccSignedPrekeySignature: eccSignedPrekeySignature, diff --git a/lib/core/bridge/callbacks.dart b/lib/core/bridge/callbacks.dart index af332b33..071b9676 100644 --- a/lib/core/bridge/callbacks.dart +++ b/lib/core/bridge/callbacks.dart @@ -8,24 +8,12 @@ import '../user_config.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; // These functions are ignored because they are not marked as `pub`: `get_callbacks` -// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Api`, `FlutterCallbacks`, `LegacySignal`, `Logging` -// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `Api`, `FlutterCallbacks`, `Logging` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone` Future initFlutterCallbacks({ required int callbackId, required FutureOr> Function() loggingGetStreamSink, - required FutureOr Function( - PlatformInt64, - Uint8List, - int, - ) - legacySignalDecrypt, - required FutureOr Function( - PlatformInt64, - Uint8List, - ) - legacySignalEncrypt, - required FutureOr Function(PlatformInt64) apiResyncSignalSession, required FutureOr Function(String, String, PlatformInt64, String) apiMediaAction, required FutureOr Function(PlatformInt64, Uint8List) @@ -36,59 +24,9 @@ Future initFlutterCallbacks({ }) => RustLib.instance.api.crateBridgeCallbacksInitFlutterCallbacks( callbackId: callbackId, loggingGetStreamSink: loggingGetStreamSink, - legacySignalDecrypt: legacySignalDecrypt, - legacySignalEncrypt: legacySignalEncrypt, - apiResyncSignalSession: apiResyncSignalSession, apiMediaAction: apiMediaAction, apiVerificationProof: apiVerificationProof, apiCreatePushAvatars: apiCreatePushAvatars, apiMediaReceived: apiMediaReceived, apiUserConfigChanged: apiUserConfigChanged, ); - -class LegacySignalDecryptResult { - /// Serialized `EncryptedContent` when legacy Signal decryption succeeded. - final Uint8List? plaintext; - - /// Serialized protobuf enum value for `DecryptionErrorMessage.Type`. - final int? decryptionErrorType; - - const LegacySignalDecryptResult({ - this.plaintext, - this.decryptionErrorType, - }); - - @override - int get hashCode => plaintext.hashCode ^ decryptionErrorType.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is LegacySignalDecryptResult && - runtimeType == other.runtimeType && - plaintext == other.plaintext && - decryptionErrorType == other.decryptionErrorType; -} - -class LegacySignalEncryptResult { - final Uint8List ciphertext; - - /// `Message.Type.CIPHERTEXT` or `Message.Type.PREKEY_BUNDLE`. - final int messageType; - - const LegacySignalEncryptResult({ - required this.ciphertext, - required this.messageType, - }); - - @override - int get hashCode => ciphertext.hashCode ^ messageType.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is LegacySignalEncryptResult && - runtimeType == other.runtimeType && - ciphertext == other.ciphertext && - messageType == other.messageType; -} diff --git a/lib/core/bridge/wrapper/key_manager.dart b/lib/core/bridge/wrapper/key_manager.dart index f5f2592d..e1b4bf0f 100644 --- a/lib/core/bridge/wrapper/key_manager.dart +++ b/lib/core/bridge/wrapper/key_manager.dart @@ -47,36 +47,15 @@ class RustKeyManager { static Future importSignalIdentity({ required List identityKeyPairStructure, required PlatformInt64 registrationId, - required Map signedPreKeyStore, }) => RustLib.instance.api .crateBridgeWrapperKeyManagerRustKeyManagerImportSignalIdentity( identityKeyPairStructure: identityKeyPairStructure, registrationId: registrationId, - signedPreKeyStore: signedPreKeyStore, ); - static Future loadSignedPrekey({ - required PlatformInt64 signedPreKeyId, - }) => RustLib.instance.api - .crateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekey( - signedPreKeyId: signedPreKeyId, - ); - - static Future> loadSignedPrekeys() => RustLib - .instance - .api - .crateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeys(); - static Future removeKeyManager() => RustLib.instance.api .crateBridgeWrapperKeyManagerRustKeyManagerRemoveKeyManager(); - static Future removeSignedPrekey({ - required PlatformInt64 signedPreKeyId, - }) => RustLib.instance.api - .crateBridgeWrapperKeyManagerRustKeyManagerRemoveSignedPrekey( - signedPreKeyId: signedPreKeyId, - ); - /// Serialize the key_manager. Needed for the passwordless_recovery feature. static Future serialize() => RustLib.instance.api .crateBridgeWrapperKeyManagerRustKeyManagerSerialize(); @@ -86,15 +65,6 @@ class RustKeyManager { .api .crateBridgeWrapperKeyManagerRustKeyManagerSetUserId(userId: userId); - static Future storeSignedPrekey({ - required PlatformInt64 signedPreKeyId, - required List record, - }) => RustLib.instance.api - .crateBridgeWrapperKeyManagerRustKeyManagerStoreSignedPrekey( - signedPreKeyId: signedPreKeyId, - record: record, - ); - @override int get hashCode => 0; diff --git a/lib/core/bridge/wrapper/signal.dart b/lib/core/bridge/wrapper/signal.dart index 6aaf439a..9979fd0f 100644 --- a/lib/core/bridge/wrapper/signal.dart +++ b/lib/core/bridge/wrapper/signal.dart @@ -36,6 +36,16 @@ class RustSignal { static Future> generatePqcPrekeys() => RustLib.instance.api .crateBridgeWrapperSignalRustSignalGeneratePqcPrekeys(); + static Future getContactPublicKey({ + required PlatformInt64 contactId, + }) => RustLib.instance.api + .crateBridgeWrapperSignalRustSignalGetContactPublicKey( + contactId: contactId, + ); + + static Future getUserPublicKey() => + RustLib.instance.api.crateBridgeWrapperSignalRustSignalGetUserPublicKey(); + static Future processPrekeyBundle({ required String name, required int deviceId, diff --git a/lib/core/frb_generated.dart b/lib/core/frb_generated.dart index 53f742e3..50106c3c 100644 --- a/lib/core/frb_generated.dart +++ b/lib/core/frb_generated.dart @@ -84,7 +84,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.12.0'; @override - int get rustContentHash => -937778436; + int get rustContentHash => -1286774374; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -138,18 +138,6 @@ abstract class RustLibApi extends BaseApi { Future crateBridgeCallbacksInitFlutterCallbacks({ required int callbackId, required FutureOr> Function() loggingGetStreamSink, - required FutureOr Function( - PlatformInt64, - Uint8List, - int, - ) - legacySignalDecrypt, - required FutureOr Function( - PlatformInt64, - Uint8List, - ) - legacySignalEncrypt, - required FutureOr Function(PlatformInt64) apiResyncSignalSession, required FutureOr Function(String, String, PlatformInt64, String) apiMediaAction, required FutureOr Function(PlatformInt64, Uint8List) @@ -220,6 +208,11 @@ abstract class RustLibApi extends BaseApi { Future crateBridgeApiRustApiDownloadPendingMedia(); + Future crateBridgeApiRustApiEstablishSignalSession({ + required PlatformInt64 contactId, + Uint8List? expectedPublicKey, + }); + Stream crateBridgeApiRustApiEvents(); Future crateBridgeApiRustApiForceIpaCheck(); @@ -356,16 +349,16 @@ abstract class RustLibApi extends BaseApi { required PlatformInt64 contactId, required List content, String? messageId, - required bool onlySendIfNoReceiptsAreOpen, - required bool onlyReturnEncryptedData, - required bool blocking, + bool? onlySendIfNoReceiptsAreOpen, + bool? onlyReturnEncryptedData, + bool? blocking, }); Future crateBridgeApiRustApiSendEncryptedContentToGroup({ required String groupId, required List content, String? messageId, - required bool onlySendIfNoReceiptsAreOpen, + bool? onlySendIfNoReceiptsAreOpen, }); Future crateBridgeApiRustApiSendQueuedMessage({ @@ -404,6 +397,8 @@ abstract class RustLibApi extends BaseApi { }); Future crateBridgeApiRustApiUploadPqcPreKeys({ + required List publicIdentityKey, + required PlatformInt64 registrationId, required PlatformInt64 eccSignedPrekeyId, required List eccSignedPrekey, required List eccSignedPrekeySignature, @@ -493,34 +488,16 @@ abstract class RustLibApi extends BaseApi { Future crateBridgeWrapperKeyManagerRustKeyManagerImportSignalIdentity({ required List identityKeyPairStructure, required PlatformInt64 registrationId, - required Map signedPreKeyStore, }); - Future - crateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekey({ - required PlatformInt64 signedPreKeyId, - }); - - Future> - crateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeys(); - Future crateBridgeWrapperKeyManagerRustKeyManagerRemoveKeyManager(); - Future crateBridgeWrapperKeyManagerRustKeyManagerRemoveSignedPrekey({ - required PlatformInt64 signedPreKeyId, - }); - Future crateBridgeWrapperKeyManagerRustKeyManagerSerialize(); Future crateBridgeWrapperKeyManagerRustKeyManagerSetUserId({ required PlatformInt64 userId, }); - Future crateBridgeWrapperKeyManagerRustKeyManagerStoreSignedPrekey({ - required PlatformInt64 signedPreKeyId, - required List record, - }); - Future crateBridgeWrapperSignalRustSignalDecrypt({ required String name, required int deviceId, @@ -538,6 +515,12 @@ abstract class RustLibApi extends BaseApi { Future> crateBridgeWrapperSignalRustSignalGeneratePqcPrekeys(); + Future crateBridgeWrapperSignalRustSignalGetContactPublicKey({ + required PlatformInt64 contactId, + }); + + Future crateBridgeWrapperSignalRustSignalGetUserPublicKey(); + Future crateBridgeWrapperSignalRustSignalProcessPrekeyBundle({ required String name, required int deviceId, @@ -919,18 +902,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { Future crateBridgeCallbacksInitFlutterCallbacks({ required int callbackId, required FutureOr> Function() loggingGetStreamSink, - required FutureOr Function( - PlatformInt64, - Uint8List, - int, - ) - legacySignalDecrypt, - required FutureOr Function( - PlatformInt64, - Uint8List, - ) - legacySignalEncrypt, - required FutureOr Function(PlatformInt64) apiResyncSignalSession, required FutureOr Function(String, String, PlatformInt64, String) apiMediaAction, required FutureOr Function(PlatformInt64, Uint8List) @@ -948,18 +919,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { loggingGetStreamSink, serializer, ); - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - legacySignalDecrypt, - serializer, - ); - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - legacySignalEncrypt, - serializer, - ); - sse_encode_DartFn_Inputs_i_64_Output_unit_AnyhowException( - apiResyncSignalSession, - serializer, - ); sse_encode_DartFn_Inputs_String_String_i_64_String_Output_unit_AnyhowException( apiMediaAction, serializer, @@ -995,9 +954,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argValues: [ callbackId, loggingGetStreamSink, - legacySignalDecrypt, - legacySignalEncrypt, - apiResyncSignalSession, apiMediaAction, apiVerificationProof, apiCreatePushAvatars, @@ -1015,9 +971,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: [ "callbackId", "loggingGetStreamSink", - "legacySignalDecrypt", - "legacySignalEncrypt", - "apiResyncSignalSession", "apiMediaAction", "apiVerificationProof", "apiCreatePushAvatars", @@ -1704,6 +1657,41 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: [], ); + @override + Future crateBridgeApiRustApiEstablishSignalSession({ + required PlatformInt64 contactId, + Uint8List? expectedPublicKey, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_i_64(contactId, serializer); + sse_encode_opt_list_prim_u_8_strict(expectedPublicKey, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 32, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_unit, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: kCrateBridgeApiRustApiEstablishSignalSessionConstMeta, + argValues: [contactId, expectedPublicKey], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateBridgeApiRustApiEstablishSignalSessionConstMeta => + const TaskConstMeta( + debugName: "rust_api_establish_signal_session", + argNames: ["contactId", "expectedPublicKey"], + ); + @override Stream crateBridgeApiRustApiEvents() { final sink = RustStreamSink(); @@ -1716,7 +1704,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 32, + funcId: 33, port: port_, ); }, @@ -1748,7 +1736,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 33, + funcId: 34, port: port_, ); }, @@ -1783,7 +1771,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 34, + funcId: 35, port: port_, ); }, @@ -1813,7 +1801,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 35, + funcId: 36, port: port_, ); }, @@ -1843,7 +1831,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 36, + funcId: 37, port: port_, ); }, @@ -1873,7 +1861,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 37, + funcId: 38, port: port_, ); }, @@ -1914,7 +1902,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 38, + funcId: 39, port: port_, ); }, @@ -1961,7 +1949,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 39, + funcId: 40, port: port_, ); }, @@ -1994,7 +1982,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 40, + funcId: 41, port: port_, ); }, @@ -2027,7 +2015,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 41, + funcId: 42, port: port_, ); }, @@ -2064,7 +2052,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 42, + funcId: 43, port: port_, ); }, @@ -2100,7 +2088,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 43, + funcId: 44, port: port_, ); }, @@ -2135,7 +2123,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 44, + funcId: 45, port: port_, ); }, @@ -2172,7 +2160,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 45, + funcId: 46, port: port_, ); }, @@ -2209,7 +2197,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 46, + funcId: 47, port: port_, ); }, @@ -2239,7 +2227,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 47, + funcId: 48, port: port_, ); }, @@ -2274,7 +2262,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 48, + funcId: 49, port: port_, ); }, @@ -2304,7 +2292,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 49, + funcId: 50, port: port_, ); }, @@ -2339,7 +2327,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 50, + funcId: 51, port: port_, ); }, @@ -2378,7 +2366,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 51, + funcId: 52, port: port_, ); }, @@ -2417,7 +2405,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 52, + funcId: 53, port: port_, ); }, @@ -2459,7 +2447,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 53, + funcId: 54, port: port_, ); }, @@ -2490,7 +2478,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 54, + funcId: 55, port: port_, ); }, @@ -2523,7 +2511,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 55, + funcId: 56, port: port_, ); }, @@ -2558,7 +2546,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 56, + funcId: 57, port: port_, ); }, @@ -2591,7 +2579,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 57, + funcId: 58, port: port_, ); }, @@ -2624,7 +2612,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 58, + funcId: 59, port: port_, ); }, @@ -2657,7 +2645,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 59, + funcId: 60, port: port_, ); }, @@ -2694,7 +2682,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 60, + funcId: 61, port: port_, ); }, @@ -2724,7 +2712,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 61, + funcId: 62, port: port_, ); }, @@ -2755,7 +2743,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 62, + funcId: 63, port: port_, ); }, @@ -2788,7 +2776,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 63, + funcId: 64, port: port_, ); }, @@ -2814,9 +2802,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { required PlatformInt64 contactId, required List content, String? messageId, - required bool onlySendIfNoReceiptsAreOpen, - required bool onlyReturnEncryptedData, - required bool blocking, + bool? onlySendIfNoReceiptsAreOpen, + bool? onlyReturnEncryptedData, + bool? blocking, }) { return handler.executeNormal( NormalTask( @@ -2825,13 +2813,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_i_64(contactId, serializer); sse_encode_list_prim_u_8_loose(content, serializer); sse_encode_opt_String(messageId, serializer); - sse_encode_bool(onlySendIfNoReceiptsAreOpen, serializer); - sse_encode_bool(onlyReturnEncryptedData, serializer); - sse_encode_bool(blocking, serializer); + sse_encode_opt_box_autoadd_bool( + onlySendIfNoReceiptsAreOpen, + serializer, + ); + sse_encode_opt_box_autoadd_bool(onlyReturnEncryptedData, serializer); + sse_encode_opt_box_autoadd_bool(blocking, serializer); pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 64, + funcId: 65, port: port_, ); }, @@ -2871,7 +2862,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { required String groupId, required List content, String? messageId, - required bool onlySendIfNoReceiptsAreOpen, + bool? onlySendIfNoReceiptsAreOpen, }) { return handler.executeNormal( NormalTask( @@ -2880,11 +2871,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_String(groupId, serializer); sse_encode_list_prim_u_8_loose(content, serializer); sse_encode_opt_String(messageId, serializer); - sse_encode_bool(onlySendIfNoReceiptsAreOpen, serializer); + sse_encode_opt_box_autoadd_bool( + onlySendIfNoReceiptsAreOpen, + serializer, + ); pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 65, + funcId: 66, port: port_, ); }, @@ -2923,7 +2917,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 66, + funcId: 67, port: port_, ); }, @@ -2958,7 +2952,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 67, + funcId: 68, port: port_, ); }, @@ -2993,7 +2987,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 68, + funcId: 69, port: port_, ); }, @@ -3026,7 +3020,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 69, + funcId: 70, port: port_, ); }, @@ -3057,7 +3051,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 70, + funcId: 71, port: port_, ); }, @@ -3090,7 +3084,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 71, + funcId: 72, port: port_, ); }, @@ -3125,7 +3119,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 72, + funcId: 73, port: port_, ); }, @@ -3156,7 +3150,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 73, + funcId: 74, port: port_, ); }, @@ -3193,7 +3187,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 74, + funcId: 75, port: port_, ); }, @@ -3216,6 +3210,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @override Future crateBridgeApiRustApiUploadPqcPreKeys({ + required List publicIdentityKey, + required PlatformInt64 registrationId, required PlatformInt64 eccSignedPrekeyId, required List eccSignedPrekey, required List eccSignedPrekeySignature, @@ -3228,6 +3224,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { NormalTask( callFfi: (port_) { final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_list_prim_u_8_loose(publicIdentityKey, serializer); + sse_encode_i_64(registrationId, serializer); sse_encode_i_64(eccSignedPrekeyId, serializer); sse_encode_list_prim_u_8_loose(eccSignedPrekey, serializer); sse_encode_list_prim_u_8_loose(eccSignedPrekeySignature, serializer); @@ -3241,7 +3239,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 75, + funcId: 76, port: port_, ); }, @@ -3251,6 +3249,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ), constMeta: kCrateBridgeApiRustApiUploadPqcPreKeysConstMeta, argValues: [ + publicIdentityKey, + registrationId, eccSignedPrekeyId, eccSignedPrekey, eccSignedPrekeySignature, @@ -3268,6 +3268,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { const TaskConstMeta( debugName: "rust_api_upload_pqc_pre_keys", argNames: [ + "publicIdentityKey", + "registrationId", "eccSignedPrekeyId", "eccSignedPrekey", "eccSignedPrekeySignature", @@ -3293,7 +3295,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 76, + funcId: 77, port: port_, ); }, @@ -3326,7 +3328,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 77, + funcId: 78, port: port_, ); }, @@ -3359,7 +3361,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 78, + funcId: 79, port: port_, ); }, @@ -3396,7 +3398,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 79, + funcId: 80, port: port_, ); }, @@ -3428,7 +3430,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 80, + funcId: 81, port: port_, ); }, @@ -3461,7 +3463,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 81, + funcId: 82, port: port_, ); }, @@ -3496,7 +3498,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 82, + funcId: 83, port: port_, ); }, @@ -3528,7 +3530,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 83, + funcId: 84, port: port_, ); }, @@ -3566,7 +3568,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 84, + funcId: 85, port: port_, ); }, @@ -3599,7 +3601,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 85, + funcId: 86, port: port_, ); }, @@ -3637,7 +3639,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 86, + funcId: 87, port: port_, ); }, @@ -3674,7 +3676,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 87, + funcId: 88, port: port_, ); }, @@ -3711,7 +3713,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 88, + funcId: 89, port: port_, ); }, @@ -3749,7 +3751,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 89, + funcId: 90, port: port_, ); }, @@ -3787,7 +3789,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 90, + funcId: 91, port: port_, ); }, @@ -3819,7 +3821,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 91, + funcId: 92, port: port_, ); }, @@ -3852,7 +3854,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 92, + funcId: 93, port: port_, ); }, @@ -3884,7 +3886,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 93, + funcId: 94, port: port_, ); }, @@ -3919,7 +3921,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 94, + funcId: 95, port: port_, ); }, @@ -3946,7 +3948,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { Future crateBridgeWrapperKeyManagerRustKeyManagerImportSignalIdentity({ required List identityKeyPairStructure, required PlatformInt64 registrationId, - required Map signedPreKeyStore, }) { return handler.executeNormal( NormalTask( @@ -3954,14 +3955,10 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { final serializer = SseSerializer(generalizedFrbRustBinding); sse_encode_list_prim_u_8_loose(identityKeyPairStructure, serializer); sse_encode_i_64(registrationId, serializer); - sse_encode_Map_i_64_list_prim_u_8_strict_None( - signedPreKeyStore, - serializer, - ); pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 95, + funcId: 96, port: port_, ); }, @@ -3971,11 +3968,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ), constMeta: kCrateBridgeWrapperKeyManagerRustKeyManagerImportSignalIdentityConstMeta, - argValues: [ - identityKeyPairStructure, - registrationId, - signedPreKeyStore, - ], + argValues: [identityKeyPairStructure, registrationId], apiImpl: this, ), ); @@ -3985,80 +3978,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { get kCrateBridgeWrapperKeyManagerRustKeyManagerImportSignalIdentityConstMeta => const TaskConstMeta( debugName: "rust_key_manager_import_signal_identity", - argNames: [ - "identityKeyPairStructure", - "registrationId", - "signedPreKeyStore", - ], - ); - - @override - Future - crateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekey({ - required PlatformInt64 signedPreKeyId, - }) { - return handler.executeNormal( - NormalTask( - callFfi: (port_) { - final serializer = SseSerializer(generalizedFrbRustBinding); - sse_encode_i_64(signedPreKeyId, serializer); - pdeCallFfi( - generalizedFrbRustBinding, - serializer, - funcId: 96, - port: port_, - ); - }, - codec: SseCodec( - decodeSuccessData: sse_decode_opt_list_prim_u_8_strict, - decodeErrorData: sse_decode_AnyhowException, - ), - constMeta: - kCrateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeyConstMeta, - argValues: [signedPreKeyId], - apiImpl: this, - ), - ); - } - - TaskConstMeta - get kCrateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeyConstMeta => - const TaskConstMeta( - debugName: "rust_key_manager_load_signed_prekey", - argNames: ["signedPreKeyId"], - ); - - @override - Future> - crateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeys() { - return handler.executeNormal( - NormalTask( - callFfi: (port_) { - final serializer = SseSerializer(generalizedFrbRustBinding); - pdeCallFfi( - generalizedFrbRustBinding, - serializer, - funcId: 97, - port: port_, - ); - }, - codec: SseCodec( - decodeSuccessData: sse_decode_Map_i_64_list_prim_u_8_strict_None, - decodeErrorData: sse_decode_AnyhowException, - ), - constMeta: - kCrateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeysConstMeta, - argValues: [], - apiImpl: this, - ), - ); - } - - TaskConstMeta - get kCrateBridgeWrapperKeyManagerRustKeyManagerLoadSignedPrekeysConstMeta => - const TaskConstMeta( - debugName: "rust_key_manager_load_signed_prekeys", - argNames: [], + argNames: ["identityKeyPairStructure", "registrationId"], ); @override @@ -4070,7 +3990,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 98, + funcId: 97, port: port_, ); }, @@ -4093,41 +4013,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: [], ); - @override - Future crateBridgeWrapperKeyManagerRustKeyManagerRemoveSignedPrekey({ - required PlatformInt64 signedPreKeyId, - }) { - return handler.executeNormal( - NormalTask( - callFfi: (port_) { - final serializer = SseSerializer(generalizedFrbRustBinding); - sse_encode_i_64(signedPreKeyId, serializer); - pdeCallFfi( - generalizedFrbRustBinding, - serializer, - funcId: 99, - port: port_, - ); - }, - codec: SseCodec( - decodeSuccessData: sse_decode_unit, - decodeErrorData: sse_decode_AnyhowException, - ), - constMeta: - kCrateBridgeWrapperKeyManagerRustKeyManagerRemoveSignedPrekeyConstMeta, - argValues: [signedPreKeyId], - apiImpl: this, - ), - ); - } - - TaskConstMeta - get kCrateBridgeWrapperKeyManagerRustKeyManagerRemoveSignedPrekeyConstMeta => - const TaskConstMeta( - debugName: "rust_key_manager_remove_signed_prekey", - argNames: ["signedPreKeyId"], - ); - @override Future crateBridgeWrapperKeyManagerRustKeyManagerSerialize() { return handler.executeNormal( @@ -4137,7 +4022,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 100, + funcId: 98, port: port_, ); }, @@ -4172,7 +4057,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 101, + funcId: 99, port: port_, ); }, @@ -4195,43 +4080,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: ["userId"], ); - @override - Future crateBridgeWrapperKeyManagerRustKeyManagerStoreSignedPrekey({ - required PlatformInt64 signedPreKeyId, - required List record, - }) { - return handler.executeNormal( - NormalTask( - callFfi: (port_) { - final serializer = SseSerializer(generalizedFrbRustBinding); - sse_encode_i_64(signedPreKeyId, serializer); - sse_encode_list_prim_u_8_loose(record, serializer); - pdeCallFfi( - generalizedFrbRustBinding, - serializer, - funcId: 102, - port: port_, - ); - }, - codec: SseCodec( - decodeSuccessData: sse_decode_unit, - decodeErrorData: sse_decode_AnyhowException, - ), - constMeta: - kCrateBridgeWrapperKeyManagerRustKeyManagerStoreSignedPrekeyConstMeta, - argValues: [signedPreKeyId, record], - apiImpl: this, - ), - ); - } - - TaskConstMeta - get kCrateBridgeWrapperKeyManagerRustKeyManagerStoreSignedPrekeyConstMeta => - const TaskConstMeta( - debugName: "rust_key_manager_store_signed_prekey", - argNames: ["signedPreKeyId", "record"], - ); - @override Future crateBridgeWrapperSignalRustSignalDecrypt({ required String name, @@ -4248,7 +4096,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 103, + funcId: 100, port: port_, ); }, @@ -4285,7 +4133,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 104, + funcId: 101, port: port_, ); }, @@ -4315,7 +4163,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 105, + funcId: 102, port: port_, ); }, @@ -4347,7 +4195,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 106, + funcId: 103, port: port_, ); }, @@ -4370,6 +4218,72 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: [], ); + @override + Future crateBridgeWrapperSignalRustSignalGetContactPublicKey({ + required PlatformInt64 contactId, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_i_64(contactId, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 104, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_opt_list_prim_u_8_strict, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: + kCrateBridgeWrapperSignalRustSignalGetContactPublicKeyConstMeta, + argValues: [contactId], + apiImpl: this, + ), + ); + } + + TaskConstMeta + get kCrateBridgeWrapperSignalRustSignalGetContactPublicKeyConstMeta => + const TaskConstMeta( + debugName: "rust_signal_get_contact_public_key", + argNames: ["contactId"], + ); + + @override + Future crateBridgeWrapperSignalRustSignalGetUserPublicKey() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 105, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_prim_u_8_strict, + decodeErrorData: sse_decode_AnyhowException, + ), + constMeta: kCrateBridgeWrapperSignalRustSignalGetUserPublicKeyConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta + get kCrateBridgeWrapperSignalRustSignalGetUserPublicKeyConstMeta => + const TaskConstMeta( + debugName: "rust_signal_get_user_public_key", + argNames: [], + ); + @override Future crateBridgeWrapperSignalRustSignalProcessPrekeyBundle({ required String name, @@ -4386,7 +4300,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 107, + funcId: 106, port: port_, ); }, @@ -4425,7 +4339,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 108, + funcId: 107, port: port_, ); }, @@ -4460,7 +4374,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 109, + funcId: 108, port: port_, ); }, @@ -4495,7 +4409,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 110, + funcId: 109, port: port_, ); }, @@ -4530,7 +4444,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 111, + funcId: 110, port: port_, ); }, @@ -4563,7 +4477,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 112, + funcId: 111, )!; }, codec: SseCodec( @@ -4603,7 +4517,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 113, + funcId: 112, port: port_, ); }, @@ -4648,7 +4562,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 114, + funcId: 113, port: port_, ); }, @@ -4678,7 +4592,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 115, + funcId: 114, port: port_, ); }, @@ -4711,7 +4625,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 116, + funcId: 115, port: port_, ); }, @@ -4746,7 +4660,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { pdeCallFfi( generalizedFrbRustBinding, serializer, - funcId: 117, + funcId: 116, port: port_, ); }, @@ -4913,45 +4827,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }; } - Future Function(int, dynamic, dynamic) - encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List) raw, - ) { - return (callId, rawArg0, rawArg1) async { - final arg0 = dco_decode_i_64(rawArg0); - final arg1 = dco_decode_list_prim_u_8_strict(rawArg1); - - Box? rawOutput; - Box? rawError; - try { - rawOutput = Box(await raw(arg0, arg1)); - } catch (e, s) { - rawError = Box(AnyhowException("$e\n\n$s")); - } - - final serializer = SseSerializer(generalizedFrbRustBinding); - assert((rawOutput != null) ^ (rawError != null)); - if (rawOutput != null) { - serializer.buffer.putUint8(0); - sse_encode_opt_box_autoadd_legacy_signal_encrypt_result( - rawOutput.value, - serializer, - ); - } else { - serializer.buffer.putUint8(1); - sse_encode_AnyhowException(rawError!.value, serializer); - } - final output = serializer.intoRaw(); - - generalizedFrbRustBinding.dartFnDeliverOutput( - callId: callId, - ptr: output.ptr, - rustVecLen: output.rustVecLen, - dataLen: output.dataLen, - ); - }; - } - Future Function(int, dynamic, dynamic) encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( FutureOr Function(PlatformInt64, Uint8List) raw, @@ -4988,44 +4863,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }; } - Future Function(int, dynamic, dynamic, dynamic) - encode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List, int) - raw, - ) { - return (callId, rawArg0, rawArg1, rawArg2) async { - final arg0 = dco_decode_i_64(rawArg0); - final arg1 = dco_decode_list_prim_u_8_strict(rawArg1); - final arg2 = dco_decode_i_32(rawArg2); - - Box? rawOutput; - Box? rawError; - try { - rawOutput = Box(await raw(arg0, arg1, arg2)); - } catch (e, s) { - rawError = Box(AnyhowException("$e\n\n$s")); - } - - final serializer = SseSerializer(generalizedFrbRustBinding); - assert((rawOutput != null) ^ (rawError != null)); - if (rawOutput != null) { - serializer.buffer.putUint8(0); - sse_encode_legacy_signal_decrypt_result(rawOutput.value, serializer); - } else { - serializer.buffer.putUint8(1); - sse_encode_AnyhowException(rawError!.value, serializer); - } - final output = serializer.intoRaw(); - - generalizedFrbRustBinding.dartFnDeliverOutput( - callId: callId, - ptr: output.ptr, - rustVecLen: output.rustVecLen, - dataLen: output.dataLen, - ); - }; - } - Future Function(int, dynamic) encode_DartFn_Inputs_user_config_Output_unit_AnyhowException( FutureOr Function(UserConfig) raw, @@ -5107,15 +4944,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { throw UnimplementedError(''); } - @protected - FutureOr Function(PlatformInt64, Uint8List) - dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - throw UnimplementedError(''); - } - @protected FutureOr Function(PlatformInt64, Uint8List) dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( @@ -5125,15 +4953,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { throw UnimplementedError(''); } - @protected - FutureOr Function(PlatformInt64, Uint8List, int) - dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - throw UnimplementedError(''); - } - @protected FutureOr Function(UserConfig) dco_decode_DartFn_Inputs_user_config_Output_unit_AnyhowException( @@ -5161,18 +4980,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - Map dco_decode_Map_i_64_list_prim_u_8_strict_None( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return Map.fromEntries( - dco_decode_list_record_i_64_list_prim_u_8_strict( - raw, - ).map((e) => MapEntry(e.$1, e.$2)), - ); - } - @protected RustStreamSink dco_decode_StreamSink_String_Sse(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -5252,6 +5059,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return dco_decode_backup_password_keys(raw); } + @protected + bool dco_decode_box_autoadd_bool(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as bool; + } + @protected double dco_decode_box_autoadd_f_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -5264,12 +5077,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return dco_decode_frb_pre_key_bundle(raw); } - @protected - int dco_decode_box_autoadd_i_32(dynamic raw) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return raw as int; - } - @protected PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -5282,14 +5089,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return dco_decode_init_config(raw); } - @protected - LegacySignalEncryptResult dco_decode_box_autoadd_legacy_signal_encrypt_result( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return dco_decode_legacy_signal_encrypt_result(raw); - } - @protected PasswordlessRecoveryConfig dco_decode_box_autoadd_passwordless_recovery_config(dynamic raw) { @@ -5414,34 +5213,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - LegacySignalDecryptResult dco_decode_legacy_signal_decrypt_result( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - final arr = raw as List; - if (arr.length != 2) - throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); - return LegacySignalDecryptResult( - plaintext: dco_decode_opt_list_prim_u_8_strict(arr[0]), - decryptionErrorType: dco_decode_opt_box_autoadd_i_32(arr[1]), - ); - } - - @protected - LegacySignalEncryptResult dco_decode_legacy_signal_encrypt_result( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - final arr = raw as List; - if (arr.length != 2) - throw Exception('unexpected arr length: expect 2 but see ${arr.length}'); - return LegacySignalEncryptResult( - ciphertext: dco_decode_list_prim_u_8_strict(arr[0]), - messageType: dco_decode_i_32(arr[1]), - ); - } - @protected LegacyTableMigrationCount dco_decode_legacy_table_migration_count( dynamic raw, @@ -5508,15 +5279,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as Uint8List; } - @protected - List<(PlatformInt64, Uint8List)> - dco_decode_list_record_i_64_list_prim_u_8_strict(dynamic raw) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return (raw as List) - .map(dco_decode_record_i_64_list_prim_u_8_strict) - .toList(); - } - @protected List<(String, List)> dco_decode_list_record_string_list_string( dynamic raw, @@ -5569,33 +5331,24 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { : dco_decode_box_autoadd_api_connection_state(raw); } + @protected + bool? dco_decode_opt_box_autoadd_bool(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw == null ? null : dco_decode_box_autoadd_bool(raw); + } + @protected double? dco_decode_opt_box_autoadd_f_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs return raw == null ? null : dco_decode_box_autoadd_f_64(raw); } - @protected - int? dco_decode_opt_box_autoadd_i_32(dynamic raw) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return raw == null ? null : dco_decode_box_autoadd_i_32(raw); - } - @protected PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs return raw == null ? null : dco_decode_box_autoadd_i_64(raw); } - @protected - LegacySignalEncryptResult? - dco_decode_opt_box_autoadd_legacy_signal_encrypt_result(dynamic raw) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return raw == null - ? null - : dco_decode_box_autoadd_legacy_signal_encrypt_result(raw); - } - @protected PasswordlessRecoveryConfig? dco_decode_opt_box_autoadd_passwordless_recovery_config(dynamic raw) { @@ -5669,21 +5422,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - (PlatformInt64, Uint8List) dco_decode_record_i_64_list_prim_u_8_strict( - dynamic raw, - ) { - // Codec=Dco (DartCObject based), see doc to use other codecs - final arr = raw as List; - if (arr.length != 2) { - throw Exception('Expected 2 elements, got ${arr.length}'); - } - return ( - dco_decode_i_64(arr[0]), - dco_decode_list_prim_u_8_strict(arr[1]), - ); - } - @protected (Uint8List, PlatformInt64) dco_decode_record_list_prim_u_8_strict_i_64( dynamic raw, @@ -6013,15 +5751,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return Map.fromEntries(inner.map((e) => MapEntry(e.$1, e.$2))); } - @protected - Map sse_decode_Map_i_64_list_prim_u_8_strict_None( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - var inner = sse_decode_list_record_i_64_list_prim_u_8_strict(deserializer); - return Map.fromEntries(inner.map((e) => MapEntry(e.$1, e.$2))); - } - @protected RustStreamSink sse_decode_StreamSink_String_Sse( SseDeserializer deserializer, @@ -6113,6 +5842,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return (sse_decode_backup_password_keys(deserializer)); } + @protected + bool sse_decode_box_autoadd_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return (sse_decode_bool(deserializer)); + } + @protected double sse_decode_box_autoadd_f_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -6127,12 +5862,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return (sse_decode_frb_pre_key_bundle(deserializer)); } - @protected - int sse_decode_box_autoadd_i_32(SseDeserializer deserializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - return (sse_decode_i_32(deserializer)); - } - @protected PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -6145,14 +5874,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return (sse_decode_init_config(deserializer)); } - @protected - LegacySignalEncryptResult sse_decode_box_autoadd_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - return (sse_decode_legacy_signal_encrypt_result(deserializer)); - } - @protected PasswordlessRecoveryConfig sse_decode_box_autoadd_passwordless_recovery_config( @@ -6296,32 +6017,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - LegacySignalDecryptResult sse_decode_legacy_signal_decrypt_result( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - var var_plaintext = sse_decode_opt_list_prim_u_8_strict(deserializer); - var var_decryptionErrorType = sse_decode_opt_box_autoadd_i_32(deserializer); - return LegacySignalDecryptResult( - plaintext: var_plaintext, - decryptionErrorType: var_decryptionErrorType, - ); - } - - @protected - LegacySignalEncryptResult sse_decode_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - var var_ciphertext = sse_decode_list_prim_u_8_strict(deserializer); - var var_messageType = sse_decode_i_32(deserializer); - return LegacySignalEncryptResult( - ciphertext: var_ciphertext, - messageType: var_messageType, - ); - } - @protected LegacyTableMigrationCount sse_decode_legacy_table_migration_count( SseDeserializer deserializer, @@ -6421,21 +6116,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return deserializer.buffer.getUint8List(len_); } - @protected - List<(PlatformInt64, Uint8List)> - sse_decode_list_record_i_64_list_prim_u_8_strict( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - - var len_ = sse_decode_i_32(deserializer); - var ans_ = <(PlatformInt64, Uint8List)>[]; - for (var idx_ = 0; idx_ < len_; ++idx_) { - ans_.add(sse_decode_record_i_64_list_prim_u_8_strict(deserializer)); - } - return ans_; - } - @protected List<(String, List)> sse_decode_list_record_string_list_string( SseDeserializer deserializer, @@ -6524,6 +6204,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + bool? sse_decode_opt_box_autoadd_bool(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + if (sse_decode_bool(deserializer)) { + return (sse_decode_box_autoadd_bool(deserializer)); + } else { + return null; + } + } + @protected double? sse_decode_opt_box_autoadd_f_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -6535,17 +6226,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } - @protected - int? sse_decode_opt_box_autoadd_i_32(SseDeserializer deserializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - - if (sse_decode_bool(deserializer)) { - return (sse_decode_box_autoadd_i_32(deserializer)); - } else { - return null; - } - } - @protected PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -6557,22 +6237,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } - @protected - LegacySignalEncryptResult? - sse_decode_opt_box_autoadd_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - - if (sse_decode_bool(deserializer)) { - return (sse_decode_box_autoadd_legacy_signal_encrypt_result( - deserializer, - )); - } else { - return null; - } - } - @protected PasswordlessRecoveryConfig? sse_decode_opt_box_autoadd_passwordless_recovery_config( @@ -6698,16 +6362,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - (PlatformInt64, Uint8List) sse_decode_record_i_64_list_prim_u_8_strict( - SseDeserializer deserializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - var var_field0 = sse_decode_i_64(deserializer); - var var_field1 = sse_decode_list_prim_u_8_strict(deserializer); - return (var_field0, var_field1); - } - @protected (Uint8List, PlatformInt64) sse_decode_record_list_prim_u_8_strict_i_64( SseDeserializer deserializer, @@ -7112,22 +6766,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - void - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List) - self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_DartOpaque( - encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - self, - ), - serializer, - ); - } - @protected void sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( @@ -7143,22 +6781,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - void - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List, int) - self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_DartOpaque( - encode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - self, - ), - serializer, - ); - } - @protected void sse_encode_DartFn_Inputs_user_config_Output_unit_AnyhowException( FutureOr Function(UserConfig) self, @@ -7198,18 +6820,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } - @protected - void sse_encode_Map_i_64_list_prim_u_8_strict_None( - Map self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_list_record_i_64_list_prim_u_8_strict( - self.entries.map((e) => (e.key, e.value)).toList(), - serializer, - ); - } - @protected void sse_encode_StreamSink_String_Sse( RustStreamSink self, @@ -7316,6 +6926,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_backup_password_keys(self, serializer); } + @protected + void sse_encode_box_autoadd_bool(bool self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_bool(self, serializer); + } + @protected void sse_encode_box_autoadd_f_64(double self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -7331,12 +6947,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_frb_pre_key_bundle(self, serializer); } - @protected - void sse_encode_box_autoadd_i_32(int self, SseSerializer serializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_i_32(self, serializer); - } - @protected void sse_encode_box_autoadd_i_64( PlatformInt64 self, @@ -7355,15 +6965,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_init_config(self, serializer); } - @protected - void sse_encode_box_autoadd_legacy_signal_encrypt_result( - LegacySignalEncryptResult self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_legacy_signal_encrypt_result(self, serializer); - } - @protected void sse_encode_box_autoadd_passwordless_recovery_config( PasswordlessRecoveryConfig self, @@ -7484,26 +7085,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_list_legacy_table_migration_count(self.tables, serializer); } - @protected - void sse_encode_legacy_signal_decrypt_result( - LegacySignalDecryptResult self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_opt_list_prim_u_8_strict(self.plaintext, serializer); - sse_encode_opt_box_autoadd_i_32(self.decryptionErrorType, serializer); - } - - @protected - void sse_encode_legacy_signal_encrypt_result( - LegacySignalEncryptResult self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_list_prim_u_8_strict(self.ciphertext, serializer); - sse_encode_i_32(self.messageType, serializer); - } - @protected void sse_encode_legacy_table_migration_count( LegacyTableMigrationCount self, @@ -7603,18 +7184,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { serializer.buffer.putUint8List(self); } - @protected - void sse_encode_list_record_i_64_list_prim_u_8_strict( - List<(PlatformInt64, Uint8List)> self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_i_32(self.length, serializer); - for (final item in self) { - sse_encode_record_i_64_list_prim_u_8_strict(item, serializer); - } - } - @protected void sse_encode_list_record_string_list_string( List<(String, List)> self, @@ -7697,6 +7266,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + void sse_encode_opt_box_autoadd_bool(bool? self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + sse_encode_bool(self != null, serializer); + if (self != null) { + sse_encode_box_autoadd_bool(self, serializer); + } + } + @protected void sse_encode_opt_box_autoadd_f_64(double? self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -7707,16 +7286,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } - @protected - void sse_encode_opt_box_autoadd_i_32(int? self, SseSerializer serializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - - sse_encode_bool(self != null, serializer); - if (self != null) { - sse_encode_box_autoadd_i_32(self, serializer); - } - } - @protected void sse_encode_opt_box_autoadd_i_64( PlatformInt64? self, @@ -7730,19 +7299,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } - @protected - void sse_encode_opt_box_autoadd_legacy_signal_encrypt_result( - LegacySignalEncryptResult? self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - - sse_encode_bool(self != null, serializer); - if (self != null) { - sse_encode_box_autoadd_legacy_signal_encrypt_result(self, serializer); - } - } - @protected void sse_encode_opt_box_autoadd_passwordless_recovery_config( PasswordlessRecoveryConfig? self, @@ -7849,16 +7405,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_list_prim_u_8_strict(self.kyberPreKeySignature, serializer); } - @protected - void sse_encode_record_i_64_list_prim_u_8_strict( - (PlatformInt64, Uint8List) self, - SseSerializer serializer, - ) { - // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_i_64(self.$1, serializer); - sse_encode_list_prim_u_8_strict(self.$2, serializer); - } - @protected void sse_encode_record_list_prim_u_8_strict_i_64( (Uint8List, PlatformInt64) self, diff --git a/lib/core/frb_generated.io.dart b/lib/core/frb_generated.io.dart index cd38253a..f9d106e5 100644 --- a/lib/core/frb_generated.io.dart +++ b/lib/core/frb_generated.io.dart @@ -60,24 +60,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { FutureOr Function(PlatformInt64) dco_decode_DartFn_Inputs_i_64_Output_unit_AnyhowException(dynamic raw); - @protected - FutureOr Function(PlatformInt64, Uint8List) - dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - dynamic raw, - ); - @protected FutureOr Function(PlatformInt64, Uint8List) dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( dynamic raw, ); - @protected - FutureOr Function(PlatformInt64, Uint8List, int) - dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - dynamic raw, - ); - @protected FutureOr Function(UserConfig) dco_decode_DartFn_Inputs_user_config_Output_unit_AnyhowException(dynamic raw); @@ -88,11 +76,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Map> dco_decode_Map_String_list_String_None(dynamic raw); - @protected - Map dco_decode_Map_i_64_list_prim_u_8_strict_None( - dynamic raw, - ); - @protected RustStreamSink dco_decode_StreamSink_String_Sse(dynamic raw); @@ -126,26 +109,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected BackupPasswordKeys dco_decode_box_autoadd_backup_password_keys(dynamic raw); + @protected + bool dco_decode_box_autoadd_bool(dynamic raw); + @protected double dco_decode_box_autoadd_f_64(dynamic raw); @protected FrbPreKeyBundle dco_decode_box_autoadd_frb_pre_key_bundle(dynamic raw); - @protected - int dco_decode_box_autoadd_i_32(dynamic raw); - @protected PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw); @protected InitConfig dco_decode_box_autoadd_init_config(dynamic raw); - @protected - LegacySignalEncryptResult dco_decode_box_autoadd_legacy_signal_encrypt_result( - dynamic raw, - ); - @protected PasswordlessRecoveryConfig dco_decode_box_autoadd_passwordless_recovery_config(dynamic raw); @@ -189,16 +167,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected LegacyMigrationReport dco_decode_legacy_migration_report(dynamic raw); - @protected - LegacySignalDecryptResult dco_decode_legacy_signal_decrypt_result( - dynamic raw, - ); - - @protected - LegacySignalEncryptResult dco_decode_legacy_signal_encrypt_result( - dynamic raw, - ); - @protected LegacyTableMigrationCount dco_decode_legacy_table_migration_count( dynamic raw, @@ -230,10 +198,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); - @protected - List<(PlatformInt64, Uint8List)> - dco_decode_list_record_i_64_list_prim_u_8_strict(dynamic raw); - @protected List<(String, List)> dco_decode_list_record_string_list_string( dynamic raw, @@ -261,19 +225,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { dynamic raw, ); + @protected + bool? dco_decode_opt_box_autoadd_bool(dynamic raw); + @protected double? dco_decode_opt_box_autoadd_f_64(dynamic raw); - @protected - int? dco_decode_opt_box_autoadd_i_32(dynamic raw); - @protected PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw); - @protected - LegacySignalEncryptResult? - dco_decode_opt_box_autoadd_legacy_signal_encrypt_result(dynamic raw); - @protected PasswordlessRecoveryConfig? dco_decode_opt_box_autoadd_passwordless_recovery_config(dynamic raw); @@ -301,11 +261,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected PqcPreKeyInput dco_decode_pqc_pre_key_input(dynamic raw); - @protected - (PlatformInt64, Uint8List) dco_decode_record_i_64_list_prim_u_8_strict( - dynamic raw, - ); - @protected (Uint8List, PlatformInt64) dco_decode_record_list_prim_u_8_strict_i_64( dynamic raw, @@ -397,11 +352,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); - @protected - Map sse_decode_Map_i_64_list_prim_u_8_strict_None( - SseDeserializer deserializer, - ); - @protected RustStreamSink sse_decode_StreamSink_String_Sse( SseDeserializer deserializer, @@ -447,6 +397,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); + @protected + bool sse_decode_box_autoadd_bool(SseDeserializer deserializer); + @protected double sse_decode_box_autoadd_f_64(SseDeserializer deserializer); @@ -455,20 +408,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); - @protected - int sse_decode_box_autoadd_i_32(SseDeserializer deserializer); - @protected PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer); @protected InitConfig sse_decode_box_autoadd_init_config(SseDeserializer deserializer); - @protected - LegacySignalEncryptResult sse_decode_box_autoadd_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ); - @protected PasswordlessRecoveryConfig sse_decode_box_autoadd_passwordless_recovery_config( @@ -522,16 +467,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); - @protected - LegacySignalDecryptResult sse_decode_legacy_signal_decrypt_result( - SseDeserializer deserializer, - ); - - @protected - LegacySignalEncryptResult sse_decode_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ); - @protected LegacyTableMigrationCount sse_decode_legacy_table_migration_count( SseDeserializer deserializer, @@ -569,12 +504,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); - @protected - List<(PlatformInt64, Uint8List)> - sse_decode_list_record_i_64_list_prim_u_8_strict( - SseDeserializer deserializer, - ); - @protected List<(String, List)> sse_decode_list_record_string_list_string( SseDeserializer deserializer, @@ -602,21 +531,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); + @protected + bool? sse_decode_opt_box_autoadd_bool(SseDeserializer deserializer); + @protected double? sse_decode_opt_box_autoadd_f_64(SseDeserializer deserializer); - @protected - int? sse_decode_opt_box_autoadd_i_32(SseDeserializer deserializer); - @protected PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer); - @protected - LegacySignalEncryptResult? - sse_decode_opt_box_autoadd_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ); - @protected PasswordlessRecoveryConfig? sse_decode_opt_box_autoadd_passwordless_recovery_config( @@ -650,11 +573,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected PqcPreKeyInput sse_decode_pqc_pre_key_input(SseDeserializer deserializer); - @protected - (PlatformInt64, Uint8List) sse_decode_record_i_64_list_prim_u_8_strict( - SseDeserializer deserializer, - ); - @protected (Uint8List, PlatformInt64) sse_decode_record_list_prim_u_8_strict_i_64( SseDeserializer deserializer, @@ -776,14 +694,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List) - self, - SseSerializer serializer, - ); - @protected void sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( @@ -791,14 +701,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List, int) - self, - SseSerializer serializer, - ); - @protected void sse_encode_DartFn_Inputs_user_config_Output_unit_AnyhowException( FutureOr Function(UserConfig) self, @@ -814,12 +716,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_Map_i_64_list_prim_u_8_strict_None( - Map self, - SseSerializer serializer, - ); - @protected void sse_encode_StreamSink_String_Sse( RustStreamSink self, @@ -874,6 +770,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_box_autoadd_bool(bool self, SseSerializer serializer); + @protected void sse_encode_box_autoadd_f_64(double self, SseSerializer serializer); @@ -883,9 +782,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_box_autoadd_i_32(int self, SseSerializer serializer); - @protected void sse_encode_box_autoadd_i_64( PlatformInt64 self, @@ -898,12 +794,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_box_autoadd_legacy_signal_encrypt_result( - LegacySignalEncryptResult self, - SseSerializer serializer, - ); - @protected void sse_encode_box_autoadd_passwordless_recovery_config( PasswordlessRecoveryConfig self, @@ -967,18 +857,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_legacy_signal_decrypt_result( - LegacySignalDecryptResult self, - SseSerializer serializer, - ); - - @protected - void sse_encode_legacy_signal_encrypt_result( - LegacySignalEncryptResult self, - SseSerializer serializer, - ); - @protected void sse_encode_legacy_table_migration_count( LegacyTableMigrationCount self, @@ -1027,12 +905,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_list_record_i_64_list_prim_u_8_strict( - List<(PlatformInt64, Uint8List)> self, - SseSerializer serializer, - ); - @protected void sse_encode_list_record_string_list_string( List<(String, List)> self, @@ -1067,10 +939,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - void sse_encode_opt_box_autoadd_f_64(double? self, SseSerializer serializer); + void sse_encode_opt_box_autoadd_bool(bool? self, SseSerializer serializer); @protected - void sse_encode_opt_box_autoadd_i_32(int? self, SseSerializer serializer); + void sse_encode_opt_box_autoadd_f_64(double? self, SseSerializer serializer); @protected void sse_encode_opt_box_autoadd_i_64( @@ -1078,12 +950,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_opt_box_autoadd_legacy_signal_encrypt_result( - LegacySignalEncryptResult? self, - SseSerializer serializer, - ); - @protected void sse_encode_opt_box_autoadd_passwordless_recovery_config( PasswordlessRecoveryConfig? self, @@ -1126,12 +992,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_record_i_64_list_prim_u_8_strict( - (PlatformInt64, Uint8List) self, - SseSerializer serializer, - ); - @protected void sse_encode_record_list_prim_u_8_strict_i_64( (Uint8List, PlatformInt64) self, diff --git a/lib/core/frb_generated.web.dart b/lib/core/frb_generated.web.dart index 462b9958..8f9863f4 100644 --- a/lib/core/frb_generated.web.dart +++ b/lib/core/frb_generated.web.dart @@ -62,24 +62,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { FutureOr Function(PlatformInt64) dco_decode_DartFn_Inputs_i_64_Output_unit_AnyhowException(dynamic raw); - @protected - FutureOr Function(PlatformInt64, Uint8List) - dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - dynamic raw, - ); - @protected FutureOr Function(PlatformInt64, Uint8List) dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( dynamic raw, ); - @protected - FutureOr Function(PlatformInt64, Uint8List, int) - dco_decode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - dynamic raw, - ); - @protected FutureOr Function(UserConfig) dco_decode_DartFn_Inputs_user_config_Output_unit_AnyhowException(dynamic raw); @@ -90,11 +78,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Map> dco_decode_Map_String_list_String_None(dynamic raw); - @protected - Map dco_decode_Map_i_64_list_prim_u_8_strict_None( - dynamic raw, - ); - @protected RustStreamSink dco_decode_StreamSink_String_Sse(dynamic raw); @@ -128,26 +111,21 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected BackupPasswordKeys dco_decode_box_autoadd_backup_password_keys(dynamic raw); + @protected + bool dco_decode_box_autoadd_bool(dynamic raw); + @protected double dco_decode_box_autoadd_f_64(dynamic raw); @protected FrbPreKeyBundle dco_decode_box_autoadd_frb_pre_key_bundle(dynamic raw); - @protected - int dco_decode_box_autoadd_i_32(dynamic raw); - @protected PlatformInt64 dco_decode_box_autoadd_i_64(dynamic raw); @protected InitConfig dco_decode_box_autoadd_init_config(dynamic raw); - @protected - LegacySignalEncryptResult dco_decode_box_autoadd_legacy_signal_encrypt_result( - dynamic raw, - ); - @protected PasswordlessRecoveryConfig dco_decode_box_autoadd_passwordless_recovery_config(dynamic raw); @@ -191,16 +169,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected LegacyMigrationReport dco_decode_legacy_migration_report(dynamic raw); - @protected - LegacySignalDecryptResult dco_decode_legacy_signal_decrypt_result( - dynamic raw, - ); - - @protected - LegacySignalEncryptResult dco_decode_legacy_signal_encrypt_result( - dynamic raw, - ); - @protected LegacyTableMigrationCount dco_decode_legacy_table_migration_count( dynamic raw, @@ -232,10 +200,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); - @protected - List<(PlatformInt64, Uint8List)> - dco_decode_list_record_i_64_list_prim_u_8_strict(dynamic raw); - @protected List<(String, List)> dco_decode_list_record_string_list_string( dynamic raw, @@ -263,19 +227,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { dynamic raw, ); + @protected + bool? dco_decode_opt_box_autoadd_bool(dynamic raw); + @protected double? dco_decode_opt_box_autoadd_f_64(dynamic raw); - @protected - int? dco_decode_opt_box_autoadd_i_32(dynamic raw); - @protected PlatformInt64? dco_decode_opt_box_autoadd_i_64(dynamic raw); - @protected - LegacySignalEncryptResult? - dco_decode_opt_box_autoadd_legacy_signal_encrypt_result(dynamic raw); - @protected PasswordlessRecoveryConfig? dco_decode_opt_box_autoadd_passwordless_recovery_config(dynamic raw); @@ -303,11 +263,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected PqcPreKeyInput dco_decode_pqc_pre_key_input(dynamic raw); - @protected - (PlatformInt64, Uint8List) dco_decode_record_i_64_list_prim_u_8_strict( - dynamic raw, - ); - @protected (Uint8List, PlatformInt64) dco_decode_record_list_prim_u_8_strict_i_64( dynamic raw, @@ -399,11 +354,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); - @protected - Map sse_decode_Map_i_64_list_prim_u_8_strict_None( - SseDeserializer deserializer, - ); - @protected RustStreamSink sse_decode_StreamSink_String_Sse( SseDeserializer deserializer, @@ -449,6 +399,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); + @protected + bool sse_decode_box_autoadd_bool(SseDeserializer deserializer); + @protected double sse_decode_box_autoadd_f_64(SseDeserializer deserializer); @@ -457,20 +410,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); - @protected - int sse_decode_box_autoadd_i_32(SseDeserializer deserializer); - @protected PlatformInt64 sse_decode_box_autoadd_i_64(SseDeserializer deserializer); @protected InitConfig sse_decode_box_autoadd_init_config(SseDeserializer deserializer); - @protected - LegacySignalEncryptResult sse_decode_box_autoadd_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ); - @protected PasswordlessRecoveryConfig sse_decode_box_autoadd_passwordless_recovery_config( @@ -524,16 +469,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); - @protected - LegacySignalDecryptResult sse_decode_legacy_signal_decrypt_result( - SseDeserializer deserializer, - ); - - @protected - LegacySignalEncryptResult sse_decode_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ); - @protected LegacyTableMigrationCount sse_decode_legacy_table_migration_count( SseDeserializer deserializer, @@ -571,12 +506,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); - @protected - List<(PlatformInt64, Uint8List)> - sse_decode_list_record_i_64_list_prim_u_8_strict( - SseDeserializer deserializer, - ); - @protected List<(String, List)> sse_decode_list_record_string_list_string( SseDeserializer deserializer, @@ -604,21 +533,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseDeserializer deserializer, ); + @protected + bool? sse_decode_opt_box_autoadd_bool(SseDeserializer deserializer); + @protected double? sse_decode_opt_box_autoadd_f_64(SseDeserializer deserializer); - @protected - int? sse_decode_opt_box_autoadd_i_32(SseDeserializer deserializer); - @protected PlatformInt64? sse_decode_opt_box_autoadd_i_64(SseDeserializer deserializer); - @protected - LegacySignalEncryptResult? - sse_decode_opt_box_autoadd_legacy_signal_encrypt_result( - SseDeserializer deserializer, - ); - @protected PasswordlessRecoveryConfig? sse_decode_opt_box_autoadd_passwordless_recovery_config( @@ -652,11 +575,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected PqcPreKeyInput sse_decode_pqc_pre_key_input(SseDeserializer deserializer); - @protected - (PlatformInt64, Uint8List) sse_decode_record_i_64_list_prim_u_8_strict( - SseDeserializer deserializer, - ); - @protected (Uint8List, PlatformInt64) sse_decode_record_list_prim_u_8_strict_i_64( SseDeserializer deserializer, @@ -778,14 +696,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List) - self, - SseSerializer serializer, - ); - @protected void sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( @@ -793,14 +703,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void - sse_encode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - FutureOr Function(PlatformInt64, Uint8List, int) - self, - SseSerializer serializer, - ); - @protected void sse_encode_DartFn_Inputs_user_config_Output_unit_AnyhowException( FutureOr Function(UserConfig) self, @@ -816,12 +718,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_Map_i_64_list_prim_u_8_strict_None( - Map self, - SseSerializer serializer, - ); - @protected void sse_encode_StreamSink_String_Sse( RustStreamSink self, @@ -876,6 +772,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_box_autoadd_bool(bool self, SseSerializer serializer); + @protected void sse_encode_box_autoadd_f_64(double self, SseSerializer serializer); @@ -885,9 +784,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_box_autoadd_i_32(int self, SseSerializer serializer); - @protected void sse_encode_box_autoadd_i_64( PlatformInt64 self, @@ -900,12 +796,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_box_autoadd_legacy_signal_encrypt_result( - LegacySignalEncryptResult self, - SseSerializer serializer, - ); - @protected void sse_encode_box_autoadd_passwordless_recovery_config( PasswordlessRecoveryConfig self, @@ -969,18 +859,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_legacy_signal_decrypt_result( - LegacySignalDecryptResult self, - SseSerializer serializer, - ); - - @protected - void sse_encode_legacy_signal_encrypt_result( - LegacySignalEncryptResult self, - SseSerializer serializer, - ); - @protected void sse_encode_legacy_table_migration_count( LegacyTableMigrationCount self, @@ -1029,12 +907,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_list_record_i_64_list_prim_u_8_strict( - List<(PlatformInt64, Uint8List)> self, - SseSerializer serializer, - ); - @protected void sse_encode_list_record_string_list_string( List<(String, List)> self, @@ -1069,10 +941,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - void sse_encode_opt_box_autoadd_f_64(double? self, SseSerializer serializer); + void sse_encode_opt_box_autoadd_bool(bool? self, SseSerializer serializer); @protected - void sse_encode_opt_box_autoadd_i_32(int? self, SseSerializer serializer); + void sse_encode_opt_box_autoadd_f_64(double? self, SseSerializer serializer); @protected void sse_encode_opt_box_autoadd_i_64( @@ -1080,12 +952,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_opt_box_autoadd_legacy_signal_encrypt_result( - LegacySignalEncryptResult? self, - SseSerializer serializer, - ); - @protected void sse_encode_opt_box_autoadd_passwordless_recovery_config( PasswordlessRecoveryConfig? self, @@ -1128,12 +994,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_record_i_64_list_prim_u_8_strict( - (PlatformInt64, Uint8List) self, - SseSerializer serializer, - ); - @protected void sse_encode_record_list_prim_u_8_strict_i_64( (Uint8List, PlatformInt64) self, diff --git a/lib/locator.dart b/lib/locator.dart index 82659962..f11fdf72 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,5 +1,4 @@ import 'package:get_it/get_it.dart'; -import 'package:twonly/src/database/signal.db.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/api/api.service.dart'; import 'package:twonly/src/services/news.service.dart'; @@ -16,12 +15,10 @@ void setupLocator() { ..registerLazySingleton(UserService.new) ..registerLazySingleton(ApiService.new) ..registerLazySingleton(TwonlyDB.new) - ..registerLazySingleton(SignalDB.new) ..registerLazySingleton(NewsService.new); } UserService get userService => locator(); ApiService get apiService => locator(); TwonlyDB get twonlyDB => locator(); -SignalDB get signalDB => locator(); NewsService get newsService => locator(); diff --git a/lib/src/callbacks/callbacks.dart b/lib/src/callbacks/callbacks.dart index 7980053d..a831f7c4 100644 --- a/lib/src/callbacks/callbacks.dart +++ b/lib/src/callbacks/callbacks.dart @@ -1,13 +1,11 @@ import 'package:twonly/core/bridge/callbacks.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; -import 'package:twonly/src/callbacks/legacy_signal.callbacks.dart'; import 'package:twonly/src/callbacks/logging.callbacks.dart'; import 'package:twonly/src/services/api/mediafiles/upload.api.dart'; import 'package:twonly/src/services/flame.service.dart'; import 'package:twonly/src/services/key_verification.service.dart'; import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/services/user.service.dart'; import 'package:twonly/src/utils/avatars.dart'; @@ -31,9 +29,6 @@ Future initFlutterCallbacksForRust() async { await initFlutterCallbacks( callbackId: isolateCallbackId, loggingGetStreamSink: LoggingCallbacks.getStreamSink, - legacySignalDecrypt: LegacySignalCallbacks.decrypt, - legacySignalEncrypt: LegacySignalCallbacks.encrypt, - apiResyncSignalSession: handleSessionResync, apiMediaAction: _apiMediaAction, apiVerificationProof: KeyVerificationService.handleVerificationProof, apiCreatePushAvatars: (contactId) => diff --git a/lib/src/callbacks/legacy_signal.callbacks.dart b/lib/src/callbacks/legacy_signal.callbacks.dart deleted file mode 100644 index 72bc6d1d..00000000 --- a/lib/src/callbacks/legacy_signal.callbacks.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -import 'package:twonly/core/bridge/callbacks.dart'; -import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart' - as pb; -import 'package:twonly/src/services/signal/encryption.signal.dart'; -import 'package:twonly/src/utils/log.dart'; - -/// Flutter boundary for the legacy libsignal_protocol_dart implementation. -/// -/// Only V1 CIPHERTEXT and PREKEY_BUNDLE messages may cross this boundary. -/// CIPHERTEXT_V2 remains fully Rust-owned. -abstract final class LegacySignalCallbacks { - static Future decrypt( - PlatformInt64 fromUserId, - Uint8List ciphertext, - int messageType, - ) async { - if (!_isLegacyMessageType(messageType)) { - return const LegacySignalDecryptResult( - decryptionErrorType: 0, - ); - } - - try { - final (content, errorType) = await signalDecryptMessageV1( - fromUserId, - ciphertext, - messageType, - ); - return LegacySignalDecryptResult( - plaintext: content == null - ? null - : Uint8List.fromList(content.writeToBuffer()), - decryptionErrorType: errorType?.value, - ); - } catch (error) { - Log.error('Legacy Signal decryption callback failed: $error'); - return const LegacySignalDecryptResult(decryptionErrorType: 0); - } - } - - static Future encrypt( - PlatformInt64 targetUserId, - Uint8List plaintext, - ) async { - try { - final encrypted = await signalEncryptMessage( - targetUserId, - plaintext, - ); - if (encrypted == null || !_isLegacyMessageType(encrypted.type.value)) { - return null; - } - return LegacySignalEncryptResult( - ciphertext: encrypted.ciphertext, - messageType: encrypted.type.value, - ); - } catch (error) { - Log.error('Legacy Signal encryption callback failed: $error'); - return null; - } - } - - static bool _isLegacyMessageType(int messageType) => - messageType == pb.Message_Type.CIPHERTEXT.value || - messageType == pb.Message_Type.PREKEY_BUNDLE.value; -} diff --git a/lib/src/database/daos/groups.dao.dart b/lib/src/database/daos/groups.dao.dart index 6bac7608..dec08fab 100644 --- a/lib/src/database/daos/groups.dao.dart +++ b/lib/src/database/daos/groups.dao.dart @@ -49,10 +49,15 @@ Future deleteGroup(String groupId) async { groupMembers, )..where((t) => t.groupId.equals(groupId))).get(); } -Future createNewGroup(GroupsCompanion group) async { + Future createNewGroup(GroupsCompanion group) async { return _insertGroup(group); } -Future insertGroupAction(GroupHistoriesCompanion action) async { + + Future insertOrUpdateGroupMember(GroupMembersCompanion members) async { + await into(groupMembers).insertOnConflictUpdate(members); + } + + Future insertGroupAction(GroupHistoriesCompanion action) async { var insertAction = action; if (!action.groupHistoryId.present) { insertAction = action.copyWith( diff --git a/lib/src/database/daos/key_verification.dao.dart b/lib/src/database/daos/key_verification.dao.dart index cdcdebff..b6f81f14 100644 --- a/lib/src/database/daos/key_verification.dao.dart +++ b/lib/src/database/daos/key_verification.dao.dart @@ -43,7 +43,42 @@ class KeyVerificationDao extends DatabaseAccessor /// Returns a map of contactId → the verification type of the earliest /// [KeyVerification] row for that contact. -Stream> watchContactVerification( + Future> + getFirstVerificationTypeByContacts() async { + final rows = await (select( + keyVerifications, + )..orderBy([(kv) => OrderingTerm.asc(kv.createdAt)])).get(); + + final result = {}; + for (final row in rows) { + result.putIfAbsent(row.contactId, () => row.type); + } + return result; + } + + Future isContactVerified(int contactId) async { + final verifierKv = alias(keyVerifications, 'verifierKv'); + final query = select(keyVerifications).join([ + leftOuterJoin( + verifierKv, + verifierKv.contactId.equalsExp(keyVerifications.verifiedBy), + ), + ])..where(keyVerifications.contactId.equals(contactId)); + + final rows = await query.get(); + for (final row in rows) { + final kv = row.readTable(keyVerifications); + final hasVerifierKv = row.readTableOrNull(verifierKv) != null; + if (kv.type == VerificationType.contactSharedByVerified) { + if (hasVerifierKv) return true; + } else { + return true; + } + } + return false; + } + + Stream> watchContactVerification( int contactId, ) { final verifier = alias(contacts, 'verifier'); @@ -291,7 +326,24 @@ Stream watchAllGroupMembersVerified(String groupId) { Log.error(e); } } -Future deleteKeyVerificationById( + + Future deleteKeyVerification(int contactId) async { + try { + await (delete( + keyVerifications, + )..where((kv) => kv.contactId.equals(contactId))).go(); + if (userService.currentUser.isUserDiscoveryEnabled) { + await FlutterUserDiscovery.updateVerificationStateForUser( + callbackId: isolateCallbackId, + contactId: contactId, + ); + } + } catch (e) { + Log.error(e); + } + } + + Future deleteKeyVerificationById( int verificationId, int contactId, ) async { diff --git a/lib/src/database/daos/signal.dao.g.dart b/lib/src/database/daos/signal.dao.g.dart deleted file mode 100644 index 8cba9e44..00000000 --- a/lib/src/database/daos/signal.dao.g.dart +++ /dev/null @@ -1,31 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'signal.dao.dart'; - -// ignore_for_file: type=lint -mixin _$SignalDaoMixin on DatabaseAccessor { - $ContactsTable get contacts => attachedDatabase.contacts; - $SignalContactPreKeysTable get signalContactPreKeys => - attachedDatabase.signalContactPreKeys; - $SignalContactSignedPreKeysTable get signalContactSignedPreKeys => - attachedDatabase.signalContactSignedPreKeys; - SignalDaoManager get managers => SignalDaoManager(this); -} - -class SignalDaoManager { - final _$SignalDaoMixin _db; - SignalDaoManager(this._db); - $$ContactsTableTableManager get contacts => - $$ContactsTableTableManager(_db.attachedDatabase, _db.contacts); - $$SignalContactPreKeysTableTableManager get signalContactPreKeys => - $$SignalContactPreKeysTableTableManager( - _db.attachedDatabase, - _db.signalContactPreKeys, - ); - $$SignalContactSignedPreKeysTableTableManager - get signalContactSignedPreKeys => - $$SignalContactSignedPreKeysTableTableManager( - _db.attachedDatabase, - _db.signalContactSignedPreKeys, - ); -} diff --git a/lib/src/database/signal.db.dart b/lib/src/database/signal.db.dart deleted file mode 100644 index ec0ec17f..00000000 --- a/lib/src/database/signal.db.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:drift_flutter/drift_flutter.dart' - show DriftNativeOptions, driftDatabase; -import 'package:path_provider/path_provider.dart'; -import 'package:twonly/src/database/tables/signal_identity_key_store.table.dart'; -import 'package:twonly/src/database/tables/signal_pre_key_store.table.dart'; -import 'package:twonly/src/database/tables/signal_sender_key_store.table.dart'; -import 'package:twonly/src/database/tables/signal_session_store.table.dart'; -import 'package:twonly/src/database/tables/signal_signed_pre_key_store.table.dart'; - -part 'signal.db.g.dart'; - -@DriftDatabase( - tables: [ - SignalIdentityKeyStores, - SignalPreKeyStores, - SignalSenderKeyStores, - SignalSessionStores, - SignalSignedPreKeyStores, - ], -) -class SignalDB extends _$SignalDB { - SignalDB([QueryExecutor? executor]) : super(executor ?? _openConnection()); - - @override - // This database shares the legacy twonly.sqlite file, whose user_version is - // already 25. Keeping that version avoids a false downgrade while only the - // Signal tables remain owned by Drift. - int get schemaVersion => 25; - - static QueryExecutor _openConnection() { - return driftDatabase( - name: 'twonly', - native: DriftNativeOptions( - databaseDirectory: getApplicationSupportDirectory, - shareAcrossIsolates: true, - setup: (database) { - database - ..execute('PRAGMA journal_mode=DELETE;') - ..execute('PRAGMA synchronous=FULL;') - ..execute('PRAGMA busy_timeout=5000;') - ..execute('PRAGMA foreign_keys=ON;'); - }, - ), - ); - } -} diff --git a/lib/src/database/signal.db.g.dart b/lib/src/database/signal.db.g.dart deleted file mode 100644 index 10d790fc..00000000 --- a/lib/src/database/signal.db.g.dart +++ /dev/null @@ -1,2383 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'signal.db.dart'; - -// ignore_for_file: type=lint -class $SignalIdentityKeyStoresTable extends SignalIdentityKeyStores - with TableInfo<$SignalIdentityKeyStoresTable, SignalIdentityKeyStore> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $SignalIdentityKeyStoresTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _deviceIdMeta = const VerificationMeta( - 'deviceId', - ); - @override - late final GeneratedColumn deviceId = GeneratedColumn( - 'device_id', - aliasedName, - false, - type: DriftSqlType.int, - requiredDuringInsert: true, - ); - static const VerificationMeta _nameMeta = const VerificationMeta('name'); - @override - late final GeneratedColumn name = GeneratedColumn( - 'name', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - ); - static const VerificationMeta _identityKeyMeta = const VerificationMeta( - 'identityKey', - ); - @override - late final GeneratedColumn identityKey = - GeneratedColumn( - 'identity_key', - aliasedName, - false, - type: DriftSqlType.blob, - requiredDuringInsert: true, - ); - static const VerificationMeta _createdAtMeta = const VerificationMeta( - 'createdAt', - ); - @override - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', - aliasedName, - false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: currentDateAndTime, - ); - @override - List get $columns => [ - deviceId, - name, - identityKey, - createdAt, - ]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'signal_identity_key_stores'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('device_id')) { - context.handle( - _deviceIdMeta, - deviceId.isAcceptableOrUnknown(data['device_id']!, _deviceIdMeta), - ); - } else if (isInserting) { - context.missing(_deviceIdMeta); - } - if (data.containsKey('name')) { - context.handle( - _nameMeta, - name.isAcceptableOrUnknown(data['name']!, _nameMeta), - ); - } else if (isInserting) { - context.missing(_nameMeta); - } - if (data.containsKey('identity_key')) { - context.handle( - _identityKeyMeta, - identityKey.isAcceptableOrUnknown( - data['identity_key']!, - _identityKeyMeta, - ), - ); - } else if (isInserting) { - context.missing(_identityKeyMeta); - } - if (data.containsKey('created_at')) { - context.handle( - _createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), - ); - } - return context; - } - - @override - Set get $primaryKey => {deviceId, name}; - @override - SignalIdentityKeyStore map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return SignalIdentityKeyStore( - deviceId: attachedDatabase.typeMapping.read( - DriftSqlType.int, - data['${effectivePrefix}device_id'], - )!, - name: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}name'], - )!, - identityKey: attachedDatabase.typeMapping.read( - DriftSqlType.blob, - data['${effectivePrefix}identity_key'], - )!, - createdAt: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, - data['${effectivePrefix}created_at'], - )!, - ); - } - - @override - $SignalIdentityKeyStoresTable createAlias(String alias) { - return $SignalIdentityKeyStoresTable(attachedDatabase, alias); - } -} - -class SignalIdentityKeyStore extends DataClass - implements Insertable { - final int deviceId; - final String name; - final Uint8List identityKey; - final DateTime createdAt; - const SignalIdentityKeyStore({ - required this.deviceId, - required this.name, - required this.identityKey, - required this.createdAt, - }); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['device_id'] = Variable(deviceId); - map['name'] = Variable(name); - map['identity_key'] = Variable(identityKey); - map['created_at'] = Variable(createdAt); - return map; - } - - SignalIdentityKeyStoresCompanion toCompanion(bool nullToAbsent) { - return SignalIdentityKeyStoresCompanion( - deviceId: Value(deviceId), - name: Value(name), - identityKey: Value(identityKey), - createdAt: Value(createdAt), - ); - } - - factory SignalIdentityKeyStore.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return SignalIdentityKeyStore( - deviceId: serializer.fromJson(json['deviceId']), - name: serializer.fromJson(json['name']), - identityKey: serializer.fromJson(json['identityKey']), - createdAt: serializer.fromJson(json['createdAt']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'deviceId': serializer.toJson(deviceId), - 'name': serializer.toJson(name), - 'identityKey': serializer.toJson(identityKey), - 'createdAt': serializer.toJson(createdAt), - }; - } - - SignalIdentityKeyStore copyWith({ - int? deviceId, - String? name, - Uint8List? identityKey, - DateTime? createdAt, - }) => SignalIdentityKeyStore( - deviceId: deviceId ?? this.deviceId, - name: name ?? this.name, - identityKey: identityKey ?? this.identityKey, - createdAt: createdAt ?? this.createdAt, - ); - SignalIdentityKeyStore copyWithCompanion( - SignalIdentityKeyStoresCompanion data, - ) { - return SignalIdentityKeyStore( - deviceId: data.deviceId.present ? data.deviceId.value : this.deviceId, - name: data.name.present ? data.name.value : this.name, - identityKey: data.identityKey.present - ? data.identityKey.value - : this.identityKey, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - ); - } - - @override - String toString() { - return (StringBuffer('SignalIdentityKeyStore(') - ..write('deviceId: $deviceId, ') - ..write('name: $name, ') - ..write('identityKey: $identityKey, ') - ..write('createdAt: $createdAt') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash( - deviceId, - name, - $driftBlobEquality.hash(identityKey), - createdAt, - ); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is SignalIdentityKeyStore && - other.deviceId == this.deviceId && - other.name == this.name && - $driftBlobEquality.equals(other.identityKey, this.identityKey) && - other.createdAt == this.createdAt); -} - -class SignalIdentityKeyStoresCompanion - extends UpdateCompanion { - final Value deviceId; - final Value name; - final Value identityKey; - final Value createdAt; - final Value rowid; - const SignalIdentityKeyStoresCompanion({ - this.deviceId = const Value.absent(), - this.name = const Value.absent(), - this.identityKey = const Value.absent(), - this.createdAt = const Value.absent(), - this.rowid = const Value.absent(), - }); - SignalIdentityKeyStoresCompanion.insert({ - required int deviceId, - required String name, - required Uint8List identityKey, - this.createdAt = const Value.absent(), - this.rowid = const Value.absent(), - }) : deviceId = Value(deviceId), - name = Value(name), - identityKey = Value(identityKey); - static Insertable custom({ - Expression? deviceId, - Expression? name, - Expression? identityKey, - Expression? createdAt, - Expression? rowid, - }) { - return RawValuesInsertable({ - if (deviceId != null) 'device_id': deviceId, - if (name != null) 'name': name, - if (identityKey != null) 'identity_key': identityKey, - if (createdAt != null) 'created_at': createdAt, - if (rowid != null) 'rowid': rowid, - }); - } - - SignalIdentityKeyStoresCompanion copyWith({ - Value? deviceId, - Value? name, - Value? identityKey, - Value? createdAt, - Value? rowid, - }) { - return SignalIdentityKeyStoresCompanion( - deviceId: deviceId ?? this.deviceId, - name: name ?? this.name, - identityKey: identityKey ?? this.identityKey, - createdAt: createdAt ?? this.createdAt, - rowid: rowid ?? this.rowid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (deviceId.present) { - map['device_id'] = Variable(deviceId.value); - } - if (name.present) { - map['name'] = Variable(name.value); - } - if (identityKey.present) { - map['identity_key'] = Variable(identityKey.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('SignalIdentityKeyStoresCompanion(') - ..write('deviceId: $deviceId, ') - ..write('name: $name, ') - ..write('identityKey: $identityKey, ') - ..write('createdAt: $createdAt, ') - ..write('rowid: $rowid') - ..write(')')) - .toString(); - } -} - -class $SignalPreKeyStoresTable extends SignalPreKeyStores - with TableInfo<$SignalPreKeyStoresTable, SignalPreKeyStore> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $SignalPreKeyStoresTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _preKeyIdMeta = const VerificationMeta( - 'preKeyId', - ); - @override - late final GeneratedColumn preKeyId = GeneratedColumn( - 'pre_key_id', - aliasedName, - false, - type: DriftSqlType.int, - requiredDuringInsert: false, - ); - static const VerificationMeta _preKeyMeta = const VerificationMeta('preKey'); - @override - late final GeneratedColumn preKey = GeneratedColumn( - 'pre_key', - aliasedName, - false, - type: DriftSqlType.blob, - requiredDuringInsert: true, - ); - static const VerificationMeta _createdAtMeta = const VerificationMeta( - 'createdAt', - ); - @override - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', - aliasedName, - false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: currentDateAndTime, - ); - @override - List get $columns => [preKeyId, preKey, createdAt]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'signal_pre_key_stores'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('pre_key_id')) { - context.handle( - _preKeyIdMeta, - preKeyId.isAcceptableOrUnknown(data['pre_key_id']!, _preKeyIdMeta), - ); - } - if (data.containsKey('pre_key')) { - context.handle( - _preKeyMeta, - preKey.isAcceptableOrUnknown(data['pre_key']!, _preKeyMeta), - ); - } else if (isInserting) { - context.missing(_preKeyMeta); - } - if (data.containsKey('created_at')) { - context.handle( - _createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), - ); - } - return context; - } - - @override - Set get $primaryKey => {preKeyId}; - @override - SignalPreKeyStore map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return SignalPreKeyStore( - preKeyId: attachedDatabase.typeMapping.read( - DriftSqlType.int, - data['${effectivePrefix}pre_key_id'], - )!, - preKey: attachedDatabase.typeMapping.read( - DriftSqlType.blob, - data['${effectivePrefix}pre_key'], - )!, - createdAt: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, - data['${effectivePrefix}created_at'], - )!, - ); - } - - @override - $SignalPreKeyStoresTable createAlias(String alias) { - return $SignalPreKeyStoresTable(attachedDatabase, alias); - } -} - -class SignalPreKeyStore extends DataClass - implements Insertable { - final int preKeyId; - final Uint8List preKey; - final DateTime createdAt; - const SignalPreKeyStore({ - required this.preKeyId, - required this.preKey, - required this.createdAt, - }); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['pre_key_id'] = Variable(preKeyId); - map['pre_key'] = Variable(preKey); - map['created_at'] = Variable(createdAt); - return map; - } - - SignalPreKeyStoresCompanion toCompanion(bool nullToAbsent) { - return SignalPreKeyStoresCompanion( - preKeyId: Value(preKeyId), - preKey: Value(preKey), - createdAt: Value(createdAt), - ); - } - - factory SignalPreKeyStore.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return SignalPreKeyStore( - preKeyId: serializer.fromJson(json['preKeyId']), - preKey: serializer.fromJson(json['preKey']), - createdAt: serializer.fromJson(json['createdAt']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'preKeyId': serializer.toJson(preKeyId), - 'preKey': serializer.toJson(preKey), - 'createdAt': serializer.toJson(createdAt), - }; - } - - SignalPreKeyStore copyWith({ - int? preKeyId, - Uint8List? preKey, - DateTime? createdAt, - }) => SignalPreKeyStore( - preKeyId: preKeyId ?? this.preKeyId, - preKey: preKey ?? this.preKey, - createdAt: createdAt ?? this.createdAt, - ); - SignalPreKeyStore copyWithCompanion(SignalPreKeyStoresCompanion data) { - return SignalPreKeyStore( - preKeyId: data.preKeyId.present ? data.preKeyId.value : this.preKeyId, - preKey: data.preKey.present ? data.preKey.value : this.preKey, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - ); - } - - @override - String toString() { - return (StringBuffer('SignalPreKeyStore(') - ..write('preKeyId: $preKeyId, ') - ..write('preKey: $preKey, ') - ..write('createdAt: $createdAt') - ..write(')')) - .toString(); - } - - @override - int get hashCode => - Object.hash(preKeyId, $driftBlobEquality.hash(preKey), createdAt); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is SignalPreKeyStore && - other.preKeyId == this.preKeyId && - $driftBlobEquality.equals(other.preKey, this.preKey) && - other.createdAt == this.createdAt); -} - -class SignalPreKeyStoresCompanion extends UpdateCompanion { - final Value preKeyId; - final Value preKey; - final Value createdAt; - const SignalPreKeyStoresCompanion({ - this.preKeyId = const Value.absent(), - this.preKey = const Value.absent(), - this.createdAt = const Value.absent(), - }); - SignalPreKeyStoresCompanion.insert({ - this.preKeyId = const Value.absent(), - required Uint8List preKey, - this.createdAt = const Value.absent(), - }) : preKey = Value(preKey); - static Insertable custom({ - Expression? preKeyId, - Expression? preKey, - Expression? createdAt, - }) { - return RawValuesInsertable({ - if (preKeyId != null) 'pre_key_id': preKeyId, - if (preKey != null) 'pre_key': preKey, - if (createdAt != null) 'created_at': createdAt, - }); - } - - SignalPreKeyStoresCompanion copyWith({ - Value? preKeyId, - Value? preKey, - Value? createdAt, - }) { - return SignalPreKeyStoresCompanion( - preKeyId: preKeyId ?? this.preKeyId, - preKey: preKey ?? this.preKey, - createdAt: createdAt ?? this.createdAt, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (preKeyId.present) { - map['pre_key_id'] = Variable(preKeyId.value); - } - if (preKey.present) { - map['pre_key'] = Variable(preKey.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('SignalPreKeyStoresCompanion(') - ..write('preKeyId: $preKeyId, ') - ..write('preKey: $preKey, ') - ..write('createdAt: $createdAt') - ..write(')')) - .toString(); - } -} - -class $SignalSenderKeyStoresTable extends SignalSenderKeyStores - with TableInfo<$SignalSenderKeyStoresTable, SignalSenderKeyStore> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $SignalSenderKeyStoresTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _senderKeyNameMeta = const VerificationMeta( - 'senderKeyName', - ); - @override - late final GeneratedColumn senderKeyName = GeneratedColumn( - 'sender_key_name', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - ); - static const VerificationMeta _senderKeyMeta = const VerificationMeta( - 'senderKey', - ); - @override - late final GeneratedColumn senderKey = GeneratedColumn( - 'sender_key', - aliasedName, - false, - type: DriftSqlType.blob, - requiredDuringInsert: true, - ); - @override - List get $columns => [senderKeyName, senderKey]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'signal_sender_key_stores'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('sender_key_name')) { - context.handle( - _senderKeyNameMeta, - senderKeyName.isAcceptableOrUnknown( - data['sender_key_name']!, - _senderKeyNameMeta, - ), - ); - } else if (isInserting) { - context.missing(_senderKeyNameMeta); - } - if (data.containsKey('sender_key')) { - context.handle( - _senderKeyMeta, - senderKey.isAcceptableOrUnknown(data['sender_key']!, _senderKeyMeta), - ); - } else if (isInserting) { - context.missing(_senderKeyMeta); - } - return context; - } - - @override - Set get $primaryKey => {senderKeyName}; - @override - SignalSenderKeyStore map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return SignalSenderKeyStore( - senderKeyName: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}sender_key_name'], - )!, - senderKey: attachedDatabase.typeMapping.read( - DriftSqlType.blob, - data['${effectivePrefix}sender_key'], - )!, - ); - } - - @override - $SignalSenderKeyStoresTable createAlias(String alias) { - return $SignalSenderKeyStoresTable(attachedDatabase, alias); - } -} - -class SignalSenderKeyStore extends DataClass - implements Insertable { - final String senderKeyName; - final Uint8List senderKey; - const SignalSenderKeyStore({ - required this.senderKeyName, - required this.senderKey, - }); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['sender_key_name'] = Variable(senderKeyName); - map['sender_key'] = Variable(senderKey); - return map; - } - - SignalSenderKeyStoresCompanion toCompanion(bool nullToAbsent) { - return SignalSenderKeyStoresCompanion( - senderKeyName: Value(senderKeyName), - senderKey: Value(senderKey), - ); - } - - factory SignalSenderKeyStore.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return SignalSenderKeyStore( - senderKeyName: serializer.fromJson(json['senderKeyName']), - senderKey: serializer.fromJson(json['senderKey']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'senderKeyName': serializer.toJson(senderKeyName), - 'senderKey': serializer.toJson(senderKey), - }; - } - - SignalSenderKeyStore copyWith({ - String? senderKeyName, - Uint8List? senderKey, - }) => SignalSenderKeyStore( - senderKeyName: senderKeyName ?? this.senderKeyName, - senderKey: senderKey ?? this.senderKey, - ); - SignalSenderKeyStore copyWithCompanion(SignalSenderKeyStoresCompanion data) { - return SignalSenderKeyStore( - senderKeyName: data.senderKeyName.present - ? data.senderKeyName.value - : this.senderKeyName, - senderKey: data.senderKey.present ? data.senderKey.value : this.senderKey, - ); - } - - @override - String toString() { - return (StringBuffer('SignalSenderKeyStore(') - ..write('senderKeyName: $senderKeyName, ') - ..write('senderKey: $senderKey') - ..write(')')) - .toString(); - } - - @override - int get hashCode => - Object.hash(senderKeyName, $driftBlobEquality.hash(senderKey)); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is SignalSenderKeyStore && - other.senderKeyName == this.senderKeyName && - $driftBlobEquality.equals(other.senderKey, this.senderKey)); -} - -class SignalSenderKeyStoresCompanion - extends UpdateCompanion { - final Value senderKeyName; - final Value senderKey; - final Value rowid; - const SignalSenderKeyStoresCompanion({ - this.senderKeyName = const Value.absent(), - this.senderKey = const Value.absent(), - this.rowid = const Value.absent(), - }); - SignalSenderKeyStoresCompanion.insert({ - required String senderKeyName, - required Uint8List senderKey, - this.rowid = const Value.absent(), - }) : senderKeyName = Value(senderKeyName), - senderKey = Value(senderKey); - static Insertable custom({ - Expression? senderKeyName, - Expression? senderKey, - Expression? rowid, - }) { - return RawValuesInsertable({ - if (senderKeyName != null) 'sender_key_name': senderKeyName, - if (senderKey != null) 'sender_key': senderKey, - if (rowid != null) 'rowid': rowid, - }); - } - - SignalSenderKeyStoresCompanion copyWith({ - Value? senderKeyName, - Value? senderKey, - Value? rowid, - }) { - return SignalSenderKeyStoresCompanion( - senderKeyName: senderKeyName ?? this.senderKeyName, - senderKey: senderKey ?? this.senderKey, - rowid: rowid ?? this.rowid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (senderKeyName.present) { - map['sender_key_name'] = Variable(senderKeyName.value); - } - if (senderKey.present) { - map['sender_key'] = Variable(senderKey.value); - } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('SignalSenderKeyStoresCompanion(') - ..write('senderKeyName: $senderKeyName, ') - ..write('senderKey: $senderKey, ') - ..write('rowid: $rowid') - ..write(')')) - .toString(); - } -} - -class $SignalSessionStoresTable extends SignalSessionStores - with TableInfo<$SignalSessionStoresTable, SignalSessionStore> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $SignalSessionStoresTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _deviceIdMeta = const VerificationMeta( - 'deviceId', - ); - @override - late final GeneratedColumn deviceId = GeneratedColumn( - 'device_id', - aliasedName, - false, - type: DriftSqlType.int, - requiredDuringInsert: true, - ); - static const VerificationMeta _nameMeta = const VerificationMeta('name'); - @override - late final GeneratedColumn name = GeneratedColumn( - 'name', - aliasedName, - false, - type: DriftSqlType.string, - requiredDuringInsert: true, - ); - static const VerificationMeta _sessionRecordMeta = const VerificationMeta( - 'sessionRecord', - ); - @override - late final GeneratedColumn sessionRecord = - GeneratedColumn( - 'session_record', - aliasedName, - false, - type: DriftSqlType.blob, - requiredDuringInsert: true, - ); - static const VerificationMeta _createdAtMeta = const VerificationMeta( - 'createdAt', - ); - @override - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', - aliasedName, - false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: currentDateAndTime, - ); - @override - List get $columns => [ - deviceId, - name, - sessionRecord, - createdAt, - ]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'signal_session_stores'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('device_id')) { - context.handle( - _deviceIdMeta, - deviceId.isAcceptableOrUnknown(data['device_id']!, _deviceIdMeta), - ); - } else if (isInserting) { - context.missing(_deviceIdMeta); - } - if (data.containsKey('name')) { - context.handle( - _nameMeta, - name.isAcceptableOrUnknown(data['name']!, _nameMeta), - ); - } else if (isInserting) { - context.missing(_nameMeta); - } - if (data.containsKey('session_record')) { - context.handle( - _sessionRecordMeta, - sessionRecord.isAcceptableOrUnknown( - data['session_record']!, - _sessionRecordMeta, - ), - ); - } else if (isInserting) { - context.missing(_sessionRecordMeta); - } - if (data.containsKey('created_at')) { - context.handle( - _createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), - ); - } - return context; - } - - @override - Set get $primaryKey => {deviceId, name}; - @override - SignalSessionStore map(Map data, {String? tablePrefix}) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return SignalSessionStore( - deviceId: attachedDatabase.typeMapping.read( - DriftSqlType.int, - data['${effectivePrefix}device_id'], - )!, - name: attachedDatabase.typeMapping.read( - DriftSqlType.string, - data['${effectivePrefix}name'], - )!, - sessionRecord: attachedDatabase.typeMapping.read( - DriftSqlType.blob, - data['${effectivePrefix}session_record'], - )!, - createdAt: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, - data['${effectivePrefix}created_at'], - )!, - ); - } - - @override - $SignalSessionStoresTable createAlias(String alias) { - return $SignalSessionStoresTable(attachedDatabase, alias); - } -} - -class SignalSessionStore extends DataClass - implements Insertable { - final int deviceId; - final String name; - final Uint8List sessionRecord; - final DateTime createdAt; - const SignalSessionStore({ - required this.deviceId, - required this.name, - required this.sessionRecord, - required this.createdAt, - }); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['device_id'] = Variable(deviceId); - map['name'] = Variable(name); - map['session_record'] = Variable(sessionRecord); - map['created_at'] = Variable(createdAt); - return map; - } - - SignalSessionStoresCompanion toCompanion(bool nullToAbsent) { - return SignalSessionStoresCompanion( - deviceId: Value(deviceId), - name: Value(name), - sessionRecord: Value(sessionRecord), - createdAt: Value(createdAt), - ); - } - - factory SignalSessionStore.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return SignalSessionStore( - deviceId: serializer.fromJson(json['deviceId']), - name: serializer.fromJson(json['name']), - sessionRecord: serializer.fromJson(json['sessionRecord']), - createdAt: serializer.fromJson(json['createdAt']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'deviceId': serializer.toJson(deviceId), - 'name': serializer.toJson(name), - 'sessionRecord': serializer.toJson(sessionRecord), - 'createdAt': serializer.toJson(createdAt), - }; - } - - SignalSessionStore copyWith({ - int? deviceId, - String? name, - Uint8List? sessionRecord, - DateTime? createdAt, - }) => SignalSessionStore( - deviceId: deviceId ?? this.deviceId, - name: name ?? this.name, - sessionRecord: sessionRecord ?? this.sessionRecord, - createdAt: createdAt ?? this.createdAt, - ); - SignalSessionStore copyWithCompanion(SignalSessionStoresCompanion data) { - return SignalSessionStore( - deviceId: data.deviceId.present ? data.deviceId.value : this.deviceId, - name: data.name.present ? data.name.value : this.name, - sessionRecord: data.sessionRecord.present - ? data.sessionRecord.value - : this.sessionRecord, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - ); - } - - @override - String toString() { - return (StringBuffer('SignalSessionStore(') - ..write('deviceId: $deviceId, ') - ..write('name: $name, ') - ..write('sessionRecord: $sessionRecord, ') - ..write('createdAt: $createdAt') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash( - deviceId, - name, - $driftBlobEquality.hash(sessionRecord), - createdAt, - ); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is SignalSessionStore && - other.deviceId == this.deviceId && - other.name == this.name && - $driftBlobEquality.equals(other.sessionRecord, this.sessionRecord) && - other.createdAt == this.createdAt); -} - -class SignalSessionStoresCompanion extends UpdateCompanion { - final Value deviceId; - final Value name; - final Value sessionRecord; - final Value createdAt; - final Value rowid; - const SignalSessionStoresCompanion({ - this.deviceId = const Value.absent(), - this.name = const Value.absent(), - this.sessionRecord = const Value.absent(), - this.createdAt = const Value.absent(), - this.rowid = const Value.absent(), - }); - SignalSessionStoresCompanion.insert({ - required int deviceId, - required String name, - required Uint8List sessionRecord, - this.createdAt = const Value.absent(), - this.rowid = const Value.absent(), - }) : deviceId = Value(deviceId), - name = Value(name), - sessionRecord = Value(sessionRecord); - static Insertable custom({ - Expression? deviceId, - Expression? name, - Expression? sessionRecord, - Expression? createdAt, - Expression? rowid, - }) { - return RawValuesInsertable({ - if (deviceId != null) 'device_id': deviceId, - if (name != null) 'name': name, - if (sessionRecord != null) 'session_record': sessionRecord, - if (createdAt != null) 'created_at': createdAt, - if (rowid != null) 'rowid': rowid, - }); - } - - SignalSessionStoresCompanion copyWith({ - Value? deviceId, - Value? name, - Value? sessionRecord, - Value? createdAt, - Value? rowid, - }) { - return SignalSessionStoresCompanion( - deviceId: deviceId ?? this.deviceId, - name: name ?? this.name, - sessionRecord: sessionRecord ?? this.sessionRecord, - createdAt: createdAt ?? this.createdAt, - rowid: rowid ?? this.rowid, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (deviceId.present) { - map['device_id'] = Variable(deviceId.value); - } - if (name.present) { - map['name'] = Variable(name.value); - } - if (sessionRecord.present) { - map['session_record'] = Variable(sessionRecord.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - if (rowid.present) { - map['rowid'] = Variable(rowid.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('SignalSessionStoresCompanion(') - ..write('deviceId: $deviceId, ') - ..write('name: $name, ') - ..write('sessionRecord: $sessionRecord, ') - ..write('createdAt: $createdAt, ') - ..write('rowid: $rowid') - ..write(')')) - .toString(); - } -} - -class $SignalSignedPreKeyStoresTable extends SignalSignedPreKeyStores - with TableInfo<$SignalSignedPreKeyStoresTable, SignalSignedPreKeyStore> { - @override - final GeneratedDatabase attachedDatabase; - final String? _alias; - $SignalSignedPreKeyStoresTable(this.attachedDatabase, [this._alias]); - static const VerificationMeta _signedPreKeyIdMeta = const VerificationMeta( - 'signedPreKeyId', - ); - @override - late final GeneratedColumn signedPreKeyId = GeneratedColumn( - 'signed_pre_key_id', - aliasedName, - false, - type: DriftSqlType.int, - requiredDuringInsert: false, - ); - static const VerificationMeta _signedPreKeyMeta = const VerificationMeta( - 'signedPreKey', - ); - @override - late final GeneratedColumn signedPreKey = - GeneratedColumn( - 'signed_pre_key', - aliasedName, - false, - type: DriftSqlType.blob, - requiredDuringInsert: true, - ); - static const VerificationMeta _createdAtMeta = const VerificationMeta( - 'createdAt', - ); - @override - late final GeneratedColumn createdAt = GeneratedColumn( - 'created_at', - aliasedName, - false, - type: DriftSqlType.dateTime, - requiredDuringInsert: false, - defaultValue: currentDateAndTime, - ); - @override - List get $columns => [ - signedPreKeyId, - signedPreKey, - createdAt, - ]; - @override - String get aliasedName => _alias ?? actualTableName; - @override - String get actualTableName => $name; - static const String $name = 'signal_signed_pre_key_stores'; - @override - VerificationContext validateIntegrity( - Insertable instance, { - bool isInserting = false, - }) { - final context = VerificationContext(); - final data = instance.toColumns(true); - if (data.containsKey('signed_pre_key_id')) { - context.handle( - _signedPreKeyIdMeta, - signedPreKeyId.isAcceptableOrUnknown( - data['signed_pre_key_id']!, - _signedPreKeyIdMeta, - ), - ); - } - if (data.containsKey('signed_pre_key')) { - context.handle( - _signedPreKeyMeta, - signedPreKey.isAcceptableOrUnknown( - data['signed_pre_key']!, - _signedPreKeyMeta, - ), - ); - } else if (isInserting) { - context.missing(_signedPreKeyMeta); - } - if (data.containsKey('created_at')) { - context.handle( - _createdAtMeta, - createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta), - ); - } - return context; - } - - @override - Set get $primaryKey => {signedPreKeyId}; - @override - SignalSignedPreKeyStore map( - Map data, { - String? tablePrefix, - }) { - final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; - return SignalSignedPreKeyStore( - signedPreKeyId: attachedDatabase.typeMapping.read( - DriftSqlType.int, - data['${effectivePrefix}signed_pre_key_id'], - )!, - signedPreKey: attachedDatabase.typeMapping.read( - DriftSqlType.blob, - data['${effectivePrefix}signed_pre_key'], - )!, - createdAt: attachedDatabase.typeMapping.read( - DriftSqlType.dateTime, - data['${effectivePrefix}created_at'], - )!, - ); - } - - @override - $SignalSignedPreKeyStoresTable createAlias(String alias) { - return $SignalSignedPreKeyStoresTable(attachedDatabase, alias); - } -} - -class SignalSignedPreKeyStore extends DataClass - implements Insertable { - final int signedPreKeyId; - final Uint8List signedPreKey; - final DateTime createdAt; - const SignalSignedPreKeyStore({ - required this.signedPreKeyId, - required this.signedPreKey, - required this.createdAt, - }); - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - map['signed_pre_key_id'] = Variable(signedPreKeyId); - map['signed_pre_key'] = Variable(signedPreKey); - map['created_at'] = Variable(createdAt); - return map; - } - - SignalSignedPreKeyStoresCompanion toCompanion(bool nullToAbsent) { - return SignalSignedPreKeyStoresCompanion( - signedPreKeyId: Value(signedPreKeyId), - signedPreKey: Value(signedPreKey), - createdAt: Value(createdAt), - ); - } - - factory SignalSignedPreKeyStore.fromJson( - Map json, { - ValueSerializer? serializer, - }) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return SignalSignedPreKeyStore( - signedPreKeyId: serializer.fromJson(json['signedPreKeyId']), - signedPreKey: serializer.fromJson(json['signedPreKey']), - createdAt: serializer.fromJson(json['createdAt']), - ); - } - @override - Map toJson({ValueSerializer? serializer}) { - serializer ??= driftRuntimeOptions.defaultSerializer; - return { - 'signedPreKeyId': serializer.toJson(signedPreKeyId), - 'signedPreKey': serializer.toJson(signedPreKey), - 'createdAt': serializer.toJson(createdAt), - }; - } - - SignalSignedPreKeyStore copyWith({ - int? signedPreKeyId, - Uint8List? signedPreKey, - DateTime? createdAt, - }) => SignalSignedPreKeyStore( - signedPreKeyId: signedPreKeyId ?? this.signedPreKeyId, - signedPreKey: signedPreKey ?? this.signedPreKey, - createdAt: createdAt ?? this.createdAt, - ); - SignalSignedPreKeyStore copyWithCompanion( - SignalSignedPreKeyStoresCompanion data, - ) { - return SignalSignedPreKeyStore( - signedPreKeyId: data.signedPreKeyId.present - ? data.signedPreKeyId.value - : this.signedPreKeyId, - signedPreKey: data.signedPreKey.present - ? data.signedPreKey.value - : this.signedPreKey, - createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt, - ); - } - - @override - String toString() { - return (StringBuffer('SignalSignedPreKeyStore(') - ..write('signedPreKeyId: $signedPreKeyId, ') - ..write('signedPreKey: $signedPreKey, ') - ..write('createdAt: $createdAt') - ..write(')')) - .toString(); - } - - @override - int get hashCode => Object.hash( - signedPreKeyId, - $driftBlobEquality.hash(signedPreKey), - createdAt, - ); - @override - bool operator ==(Object other) => - identical(this, other) || - (other is SignalSignedPreKeyStore && - other.signedPreKeyId == this.signedPreKeyId && - $driftBlobEquality.equals(other.signedPreKey, this.signedPreKey) && - other.createdAt == this.createdAt); -} - -class SignalSignedPreKeyStoresCompanion - extends UpdateCompanion { - final Value signedPreKeyId; - final Value signedPreKey; - final Value createdAt; - const SignalSignedPreKeyStoresCompanion({ - this.signedPreKeyId = const Value.absent(), - this.signedPreKey = const Value.absent(), - this.createdAt = const Value.absent(), - }); - SignalSignedPreKeyStoresCompanion.insert({ - this.signedPreKeyId = const Value.absent(), - required Uint8List signedPreKey, - this.createdAt = const Value.absent(), - }) : signedPreKey = Value(signedPreKey); - static Insertable custom({ - Expression? signedPreKeyId, - Expression? signedPreKey, - Expression? createdAt, - }) { - return RawValuesInsertable({ - if (signedPreKeyId != null) 'signed_pre_key_id': signedPreKeyId, - if (signedPreKey != null) 'signed_pre_key': signedPreKey, - if (createdAt != null) 'created_at': createdAt, - }); - } - - SignalSignedPreKeyStoresCompanion copyWith({ - Value? signedPreKeyId, - Value? signedPreKey, - Value? createdAt, - }) { - return SignalSignedPreKeyStoresCompanion( - signedPreKeyId: signedPreKeyId ?? this.signedPreKeyId, - signedPreKey: signedPreKey ?? this.signedPreKey, - createdAt: createdAt ?? this.createdAt, - ); - } - - @override - Map toColumns(bool nullToAbsent) { - final map = {}; - if (signedPreKeyId.present) { - map['signed_pre_key_id'] = Variable(signedPreKeyId.value); - } - if (signedPreKey.present) { - map['signed_pre_key'] = Variable(signedPreKey.value); - } - if (createdAt.present) { - map['created_at'] = Variable(createdAt.value); - } - return map; - } - - @override - String toString() { - return (StringBuffer('SignalSignedPreKeyStoresCompanion(') - ..write('signedPreKeyId: $signedPreKeyId, ') - ..write('signedPreKey: $signedPreKey, ') - ..write('createdAt: $createdAt') - ..write(')')) - .toString(); - } -} - -abstract class _$SignalDB extends GeneratedDatabase { - _$SignalDB(QueryExecutor e) : super(e); - $SignalDBManager get managers => $SignalDBManager(this); - late final $SignalIdentityKeyStoresTable signalIdentityKeyStores = - $SignalIdentityKeyStoresTable(this); - late final $SignalPreKeyStoresTable signalPreKeyStores = - $SignalPreKeyStoresTable(this); - late final $SignalSenderKeyStoresTable signalSenderKeyStores = - $SignalSenderKeyStoresTable(this); - late final $SignalSessionStoresTable signalSessionStores = - $SignalSessionStoresTable(this); - late final $SignalSignedPreKeyStoresTable signalSignedPreKeyStores = - $SignalSignedPreKeyStoresTable(this); - @override - Iterable> get allTables => - allSchemaEntities.whereType>(); - @override - List get allSchemaEntities => [ - signalIdentityKeyStores, - signalPreKeyStores, - signalSenderKeyStores, - signalSessionStores, - signalSignedPreKeyStores, - ]; -} - -typedef $$SignalIdentityKeyStoresTableCreateCompanionBuilder = - SignalIdentityKeyStoresCompanion Function({ - required int deviceId, - required String name, - required Uint8List identityKey, - Value createdAt, - Value rowid, - }); -typedef $$SignalIdentityKeyStoresTableUpdateCompanionBuilder = - SignalIdentityKeyStoresCompanion Function({ - Value deviceId, - Value name, - Value identityKey, - Value createdAt, - Value rowid, - }); - -class $$SignalIdentityKeyStoresTableFilterComposer - extends Composer<_$SignalDB, $SignalIdentityKeyStoresTable> { - $$SignalIdentityKeyStoresTableFilterComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnFilters get deviceId => $composableBuilder( - column: $table.deviceId, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get name => $composableBuilder( - column: $table.name, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get identityKey => $composableBuilder( - column: $table.identityKey, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnFilters(column), - ); -} - -class $$SignalIdentityKeyStoresTableOrderingComposer - extends Composer<_$SignalDB, $SignalIdentityKeyStoresTable> { - $$SignalIdentityKeyStoresTableOrderingComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnOrderings get deviceId => $composableBuilder( - column: $table.deviceId, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get name => $composableBuilder( - column: $table.name, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get identityKey => $composableBuilder( - column: $table.identityKey, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnOrderings(column), - ); -} - -class $$SignalIdentityKeyStoresTableAnnotationComposer - extends Composer<_$SignalDB, $SignalIdentityKeyStoresTable> { - $$SignalIdentityKeyStoresTableAnnotationComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - GeneratedColumn get deviceId => - $composableBuilder(column: $table.deviceId, builder: (column) => column); - - GeneratedColumn get name => - $composableBuilder(column: $table.name, builder: (column) => column); - - GeneratedColumn get identityKey => $composableBuilder( - column: $table.identityKey, - builder: (column) => column, - ); - - GeneratedColumn get createdAt => - $composableBuilder(column: $table.createdAt, builder: (column) => column); -} - -class $$SignalIdentityKeyStoresTableTableManager - extends - RootTableManager< - _$SignalDB, - $SignalIdentityKeyStoresTable, - SignalIdentityKeyStore, - $$SignalIdentityKeyStoresTableFilterComposer, - $$SignalIdentityKeyStoresTableOrderingComposer, - $$SignalIdentityKeyStoresTableAnnotationComposer, - $$SignalIdentityKeyStoresTableCreateCompanionBuilder, - $$SignalIdentityKeyStoresTableUpdateCompanionBuilder, - ( - SignalIdentityKeyStore, - BaseReferences< - _$SignalDB, - $SignalIdentityKeyStoresTable, - SignalIdentityKeyStore - >, - ), - SignalIdentityKeyStore, - PrefetchHooks Function() - > { - $$SignalIdentityKeyStoresTableTableManager( - _$SignalDB db, - $SignalIdentityKeyStoresTable table, - ) : super( - TableManagerState( - db: db, - table: table, - createFilteringComposer: () => - $$SignalIdentityKeyStoresTableFilterComposer( - $db: db, - $table: table, - ), - createOrderingComposer: () => - $$SignalIdentityKeyStoresTableOrderingComposer( - $db: db, - $table: table, - ), - createComputedFieldComposer: () => - $$SignalIdentityKeyStoresTableAnnotationComposer( - $db: db, - $table: table, - ), - updateCompanionCallback: - ({ - Value deviceId = const Value.absent(), - Value name = const Value.absent(), - Value identityKey = const Value.absent(), - Value createdAt = const Value.absent(), - Value rowid = const Value.absent(), - }) => SignalIdentityKeyStoresCompanion( - deviceId: deviceId, - name: name, - identityKey: identityKey, - createdAt: createdAt, - rowid: rowid, - ), - createCompanionCallback: - ({ - required int deviceId, - required String name, - required Uint8List identityKey, - Value createdAt = const Value.absent(), - Value rowid = const Value.absent(), - }) => SignalIdentityKeyStoresCompanion.insert( - deviceId: deviceId, - name: name, - identityKey: identityKey, - createdAt: createdAt, - rowid: rowid, - ), - withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$SignalIdentityKeyStoresTableProcessedTableManager = - ProcessedTableManager< - _$SignalDB, - $SignalIdentityKeyStoresTable, - SignalIdentityKeyStore, - $$SignalIdentityKeyStoresTableFilterComposer, - $$SignalIdentityKeyStoresTableOrderingComposer, - $$SignalIdentityKeyStoresTableAnnotationComposer, - $$SignalIdentityKeyStoresTableCreateCompanionBuilder, - $$SignalIdentityKeyStoresTableUpdateCompanionBuilder, - ( - SignalIdentityKeyStore, - BaseReferences< - _$SignalDB, - $SignalIdentityKeyStoresTable, - SignalIdentityKeyStore - >, - ), - SignalIdentityKeyStore, - PrefetchHooks Function() - >; -typedef $$SignalPreKeyStoresTableCreateCompanionBuilder = - SignalPreKeyStoresCompanion Function({ - Value preKeyId, - required Uint8List preKey, - Value createdAt, - }); -typedef $$SignalPreKeyStoresTableUpdateCompanionBuilder = - SignalPreKeyStoresCompanion Function({ - Value preKeyId, - Value preKey, - Value createdAt, - }); - -class $$SignalPreKeyStoresTableFilterComposer - extends Composer<_$SignalDB, $SignalPreKeyStoresTable> { - $$SignalPreKeyStoresTableFilterComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnFilters get preKeyId => $composableBuilder( - column: $table.preKeyId, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get preKey => $composableBuilder( - column: $table.preKey, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnFilters(column), - ); -} - -class $$SignalPreKeyStoresTableOrderingComposer - extends Composer<_$SignalDB, $SignalPreKeyStoresTable> { - $$SignalPreKeyStoresTableOrderingComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnOrderings get preKeyId => $composableBuilder( - column: $table.preKeyId, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get preKey => $composableBuilder( - column: $table.preKey, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnOrderings(column), - ); -} - -class $$SignalPreKeyStoresTableAnnotationComposer - extends Composer<_$SignalDB, $SignalPreKeyStoresTable> { - $$SignalPreKeyStoresTableAnnotationComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - GeneratedColumn get preKeyId => - $composableBuilder(column: $table.preKeyId, builder: (column) => column); - - GeneratedColumn get preKey => - $composableBuilder(column: $table.preKey, builder: (column) => column); - - GeneratedColumn get createdAt => - $composableBuilder(column: $table.createdAt, builder: (column) => column); -} - -class $$SignalPreKeyStoresTableTableManager - extends - RootTableManager< - _$SignalDB, - $SignalPreKeyStoresTable, - SignalPreKeyStore, - $$SignalPreKeyStoresTableFilterComposer, - $$SignalPreKeyStoresTableOrderingComposer, - $$SignalPreKeyStoresTableAnnotationComposer, - $$SignalPreKeyStoresTableCreateCompanionBuilder, - $$SignalPreKeyStoresTableUpdateCompanionBuilder, - ( - SignalPreKeyStore, - BaseReferences< - _$SignalDB, - $SignalPreKeyStoresTable, - SignalPreKeyStore - >, - ), - SignalPreKeyStore, - PrefetchHooks Function() - > { - $$SignalPreKeyStoresTableTableManager( - _$SignalDB db, - $SignalPreKeyStoresTable table, - ) : super( - TableManagerState( - db: db, - table: table, - createFilteringComposer: () => - $$SignalPreKeyStoresTableFilterComposer($db: db, $table: table), - createOrderingComposer: () => - $$SignalPreKeyStoresTableOrderingComposer($db: db, $table: table), - createComputedFieldComposer: () => - $$SignalPreKeyStoresTableAnnotationComposer( - $db: db, - $table: table, - ), - updateCompanionCallback: - ({ - Value preKeyId = const Value.absent(), - Value preKey = const Value.absent(), - Value createdAt = const Value.absent(), - }) => SignalPreKeyStoresCompanion( - preKeyId: preKeyId, - preKey: preKey, - createdAt: createdAt, - ), - createCompanionCallback: - ({ - Value preKeyId = const Value.absent(), - required Uint8List preKey, - Value createdAt = const Value.absent(), - }) => SignalPreKeyStoresCompanion.insert( - preKeyId: preKeyId, - preKey: preKey, - createdAt: createdAt, - ), - withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$SignalPreKeyStoresTableProcessedTableManager = - ProcessedTableManager< - _$SignalDB, - $SignalPreKeyStoresTable, - SignalPreKeyStore, - $$SignalPreKeyStoresTableFilterComposer, - $$SignalPreKeyStoresTableOrderingComposer, - $$SignalPreKeyStoresTableAnnotationComposer, - $$SignalPreKeyStoresTableCreateCompanionBuilder, - $$SignalPreKeyStoresTableUpdateCompanionBuilder, - ( - SignalPreKeyStore, - BaseReferences<_$SignalDB, $SignalPreKeyStoresTable, SignalPreKeyStore>, - ), - SignalPreKeyStore, - PrefetchHooks Function() - >; -typedef $$SignalSenderKeyStoresTableCreateCompanionBuilder = - SignalSenderKeyStoresCompanion Function({ - required String senderKeyName, - required Uint8List senderKey, - Value rowid, - }); -typedef $$SignalSenderKeyStoresTableUpdateCompanionBuilder = - SignalSenderKeyStoresCompanion Function({ - Value senderKeyName, - Value senderKey, - Value rowid, - }); - -class $$SignalSenderKeyStoresTableFilterComposer - extends Composer<_$SignalDB, $SignalSenderKeyStoresTable> { - $$SignalSenderKeyStoresTableFilterComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnFilters get senderKeyName => $composableBuilder( - column: $table.senderKeyName, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get senderKey => $composableBuilder( - column: $table.senderKey, - builder: (column) => ColumnFilters(column), - ); -} - -class $$SignalSenderKeyStoresTableOrderingComposer - extends Composer<_$SignalDB, $SignalSenderKeyStoresTable> { - $$SignalSenderKeyStoresTableOrderingComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnOrderings get senderKeyName => $composableBuilder( - column: $table.senderKeyName, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get senderKey => $composableBuilder( - column: $table.senderKey, - builder: (column) => ColumnOrderings(column), - ); -} - -class $$SignalSenderKeyStoresTableAnnotationComposer - extends Composer<_$SignalDB, $SignalSenderKeyStoresTable> { - $$SignalSenderKeyStoresTableAnnotationComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - GeneratedColumn get senderKeyName => $composableBuilder( - column: $table.senderKeyName, - builder: (column) => column, - ); - - GeneratedColumn get senderKey => - $composableBuilder(column: $table.senderKey, builder: (column) => column); -} - -class $$SignalSenderKeyStoresTableTableManager - extends - RootTableManager< - _$SignalDB, - $SignalSenderKeyStoresTable, - SignalSenderKeyStore, - $$SignalSenderKeyStoresTableFilterComposer, - $$SignalSenderKeyStoresTableOrderingComposer, - $$SignalSenderKeyStoresTableAnnotationComposer, - $$SignalSenderKeyStoresTableCreateCompanionBuilder, - $$SignalSenderKeyStoresTableUpdateCompanionBuilder, - ( - SignalSenderKeyStore, - BaseReferences< - _$SignalDB, - $SignalSenderKeyStoresTable, - SignalSenderKeyStore - >, - ), - SignalSenderKeyStore, - PrefetchHooks Function() - > { - $$SignalSenderKeyStoresTableTableManager( - _$SignalDB db, - $SignalSenderKeyStoresTable table, - ) : super( - TableManagerState( - db: db, - table: table, - createFilteringComposer: () => - $$SignalSenderKeyStoresTableFilterComposer( - $db: db, - $table: table, - ), - createOrderingComposer: () => - $$SignalSenderKeyStoresTableOrderingComposer( - $db: db, - $table: table, - ), - createComputedFieldComposer: () => - $$SignalSenderKeyStoresTableAnnotationComposer( - $db: db, - $table: table, - ), - updateCompanionCallback: - ({ - Value senderKeyName = const Value.absent(), - Value senderKey = const Value.absent(), - Value rowid = const Value.absent(), - }) => SignalSenderKeyStoresCompanion( - senderKeyName: senderKeyName, - senderKey: senderKey, - rowid: rowid, - ), - createCompanionCallback: - ({ - required String senderKeyName, - required Uint8List senderKey, - Value rowid = const Value.absent(), - }) => SignalSenderKeyStoresCompanion.insert( - senderKeyName: senderKeyName, - senderKey: senderKey, - rowid: rowid, - ), - withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$SignalSenderKeyStoresTableProcessedTableManager = - ProcessedTableManager< - _$SignalDB, - $SignalSenderKeyStoresTable, - SignalSenderKeyStore, - $$SignalSenderKeyStoresTableFilterComposer, - $$SignalSenderKeyStoresTableOrderingComposer, - $$SignalSenderKeyStoresTableAnnotationComposer, - $$SignalSenderKeyStoresTableCreateCompanionBuilder, - $$SignalSenderKeyStoresTableUpdateCompanionBuilder, - ( - SignalSenderKeyStore, - BaseReferences< - _$SignalDB, - $SignalSenderKeyStoresTable, - SignalSenderKeyStore - >, - ), - SignalSenderKeyStore, - PrefetchHooks Function() - >; -typedef $$SignalSessionStoresTableCreateCompanionBuilder = - SignalSessionStoresCompanion Function({ - required int deviceId, - required String name, - required Uint8List sessionRecord, - Value createdAt, - Value rowid, - }); -typedef $$SignalSessionStoresTableUpdateCompanionBuilder = - SignalSessionStoresCompanion Function({ - Value deviceId, - Value name, - Value sessionRecord, - Value createdAt, - Value rowid, - }); - -class $$SignalSessionStoresTableFilterComposer - extends Composer<_$SignalDB, $SignalSessionStoresTable> { - $$SignalSessionStoresTableFilterComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnFilters get deviceId => $composableBuilder( - column: $table.deviceId, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get name => $composableBuilder( - column: $table.name, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get sessionRecord => $composableBuilder( - column: $table.sessionRecord, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnFilters(column), - ); -} - -class $$SignalSessionStoresTableOrderingComposer - extends Composer<_$SignalDB, $SignalSessionStoresTable> { - $$SignalSessionStoresTableOrderingComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnOrderings get deviceId => $composableBuilder( - column: $table.deviceId, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get name => $composableBuilder( - column: $table.name, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get sessionRecord => $composableBuilder( - column: $table.sessionRecord, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnOrderings(column), - ); -} - -class $$SignalSessionStoresTableAnnotationComposer - extends Composer<_$SignalDB, $SignalSessionStoresTable> { - $$SignalSessionStoresTableAnnotationComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - GeneratedColumn get deviceId => - $composableBuilder(column: $table.deviceId, builder: (column) => column); - - GeneratedColumn get name => - $composableBuilder(column: $table.name, builder: (column) => column); - - GeneratedColumn get sessionRecord => $composableBuilder( - column: $table.sessionRecord, - builder: (column) => column, - ); - - GeneratedColumn get createdAt => - $composableBuilder(column: $table.createdAt, builder: (column) => column); -} - -class $$SignalSessionStoresTableTableManager - extends - RootTableManager< - _$SignalDB, - $SignalSessionStoresTable, - SignalSessionStore, - $$SignalSessionStoresTableFilterComposer, - $$SignalSessionStoresTableOrderingComposer, - $$SignalSessionStoresTableAnnotationComposer, - $$SignalSessionStoresTableCreateCompanionBuilder, - $$SignalSessionStoresTableUpdateCompanionBuilder, - ( - SignalSessionStore, - BaseReferences< - _$SignalDB, - $SignalSessionStoresTable, - SignalSessionStore - >, - ), - SignalSessionStore, - PrefetchHooks Function() - > { - $$SignalSessionStoresTableTableManager( - _$SignalDB db, - $SignalSessionStoresTable table, - ) : super( - TableManagerState( - db: db, - table: table, - createFilteringComposer: () => - $$SignalSessionStoresTableFilterComposer($db: db, $table: table), - createOrderingComposer: () => - $$SignalSessionStoresTableOrderingComposer( - $db: db, - $table: table, - ), - createComputedFieldComposer: () => - $$SignalSessionStoresTableAnnotationComposer( - $db: db, - $table: table, - ), - updateCompanionCallback: - ({ - Value deviceId = const Value.absent(), - Value name = const Value.absent(), - Value sessionRecord = const Value.absent(), - Value createdAt = const Value.absent(), - Value rowid = const Value.absent(), - }) => SignalSessionStoresCompanion( - deviceId: deviceId, - name: name, - sessionRecord: sessionRecord, - createdAt: createdAt, - rowid: rowid, - ), - createCompanionCallback: - ({ - required int deviceId, - required String name, - required Uint8List sessionRecord, - Value createdAt = const Value.absent(), - Value rowid = const Value.absent(), - }) => SignalSessionStoresCompanion.insert( - deviceId: deviceId, - name: name, - sessionRecord: sessionRecord, - createdAt: createdAt, - rowid: rowid, - ), - withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$SignalSessionStoresTableProcessedTableManager = - ProcessedTableManager< - _$SignalDB, - $SignalSessionStoresTable, - SignalSessionStore, - $$SignalSessionStoresTableFilterComposer, - $$SignalSessionStoresTableOrderingComposer, - $$SignalSessionStoresTableAnnotationComposer, - $$SignalSessionStoresTableCreateCompanionBuilder, - $$SignalSessionStoresTableUpdateCompanionBuilder, - ( - SignalSessionStore, - BaseReferences< - _$SignalDB, - $SignalSessionStoresTable, - SignalSessionStore - >, - ), - SignalSessionStore, - PrefetchHooks Function() - >; -typedef $$SignalSignedPreKeyStoresTableCreateCompanionBuilder = - SignalSignedPreKeyStoresCompanion Function({ - Value signedPreKeyId, - required Uint8List signedPreKey, - Value createdAt, - }); -typedef $$SignalSignedPreKeyStoresTableUpdateCompanionBuilder = - SignalSignedPreKeyStoresCompanion Function({ - Value signedPreKeyId, - Value signedPreKey, - Value createdAt, - }); - -class $$SignalSignedPreKeyStoresTableFilterComposer - extends Composer<_$SignalDB, $SignalSignedPreKeyStoresTable> { - $$SignalSignedPreKeyStoresTableFilterComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnFilters get signedPreKeyId => $composableBuilder( - column: $table.signedPreKeyId, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get signedPreKey => $composableBuilder( - column: $table.signedPreKey, - builder: (column) => ColumnFilters(column), - ); - - ColumnFilters get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnFilters(column), - ); -} - -class $$SignalSignedPreKeyStoresTableOrderingComposer - extends Composer<_$SignalDB, $SignalSignedPreKeyStoresTable> { - $$SignalSignedPreKeyStoresTableOrderingComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - ColumnOrderings get signedPreKeyId => $composableBuilder( - column: $table.signedPreKeyId, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get signedPreKey => $composableBuilder( - column: $table.signedPreKey, - builder: (column) => ColumnOrderings(column), - ); - - ColumnOrderings get createdAt => $composableBuilder( - column: $table.createdAt, - builder: (column) => ColumnOrderings(column), - ); -} - -class $$SignalSignedPreKeyStoresTableAnnotationComposer - extends Composer<_$SignalDB, $SignalSignedPreKeyStoresTable> { - $$SignalSignedPreKeyStoresTableAnnotationComposer({ - required super.$db, - required super.$table, - super.joinBuilder, - super.$addJoinBuilderToRootComposer, - super.$removeJoinBuilderFromRootComposer, - }); - GeneratedColumn get signedPreKeyId => $composableBuilder( - column: $table.signedPreKeyId, - builder: (column) => column, - ); - - GeneratedColumn get signedPreKey => $composableBuilder( - column: $table.signedPreKey, - builder: (column) => column, - ); - - GeneratedColumn get createdAt => - $composableBuilder(column: $table.createdAt, builder: (column) => column); -} - -class $$SignalSignedPreKeyStoresTableTableManager - extends - RootTableManager< - _$SignalDB, - $SignalSignedPreKeyStoresTable, - SignalSignedPreKeyStore, - $$SignalSignedPreKeyStoresTableFilterComposer, - $$SignalSignedPreKeyStoresTableOrderingComposer, - $$SignalSignedPreKeyStoresTableAnnotationComposer, - $$SignalSignedPreKeyStoresTableCreateCompanionBuilder, - $$SignalSignedPreKeyStoresTableUpdateCompanionBuilder, - ( - SignalSignedPreKeyStore, - BaseReferences< - _$SignalDB, - $SignalSignedPreKeyStoresTable, - SignalSignedPreKeyStore - >, - ), - SignalSignedPreKeyStore, - PrefetchHooks Function() - > { - $$SignalSignedPreKeyStoresTableTableManager( - _$SignalDB db, - $SignalSignedPreKeyStoresTable table, - ) : super( - TableManagerState( - db: db, - table: table, - createFilteringComposer: () => - $$SignalSignedPreKeyStoresTableFilterComposer( - $db: db, - $table: table, - ), - createOrderingComposer: () => - $$SignalSignedPreKeyStoresTableOrderingComposer( - $db: db, - $table: table, - ), - createComputedFieldComposer: () => - $$SignalSignedPreKeyStoresTableAnnotationComposer( - $db: db, - $table: table, - ), - updateCompanionCallback: - ({ - Value signedPreKeyId = const Value.absent(), - Value signedPreKey = const Value.absent(), - Value createdAt = const Value.absent(), - }) => SignalSignedPreKeyStoresCompanion( - signedPreKeyId: signedPreKeyId, - signedPreKey: signedPreKey, - createdAt: createdAt, - ), - createCompanionCallback: - ({ - Value signedPreKeyId = const Value.absent(), - required Uint8List signedPreKey, - Value createdAt = const Value.absent(), - }) => SignalSignedPreKeyStoresCompanion.insert( - signedPreKeyId: signedPreKeyId, - signedPreKey: signedPreKey, - createdAt: createdAt, - ), - withReferenceMapper: (p0) => p0 - .map((e) => (e.readTable(table), BaseReferences(db, table, e))) - .toList(), - prefetchHooksCallback: null, - ), - ); -} - -typedef $$SignalSignedPreKeyStoresTableProcessedTableManager = - ProcessedTableManager< - _$SignalDB, - $SignalSignedPreKeyStoresTable, - SignalSignedPreKeyStore, - $$SignalSignedPreKeyStoresTableFilterComposer, - $$SignalSignedPreKeyStoresTableOrderingComposer, - $$SignalSignedPreKeyStoresTableAnnotationComposer, - $$SignalSignedPreKeyStoresTableCreateCompanionBuilder, - $$SignalSignedPreKeyStoresTableUpdateCompanionBuilder, - ( - SignalSignedPreKeyStore, - BaseReferences< - _$SignalDB, - $SignalSignedPreKeyStoresTable, - SignalSignedPreKeyStore - >, - ), - SignalSignedPreKeyStore, - PrefetchHooks Function() - >; - -class $SignalDBManager { - final _$SignalDB _db; - $SignalDBManager(this._db); - $$SignalIdentityKeyStoresTableTableManager get signalIdentityKeyStores => - $$SignalIdentityKeyStoresTableTableManager( - _db, - _db.signalIdentityKeyStores, - ); - $$SignalPreKeyStoresTableTableManager get signalPreKeyStores => - $$SignalPreKeyStoresTableTableManager(_db, _db.signalPreKeyStores); - $$SignalSenderKeyStoresTableTableManager get signalSenderKeyStores => - $$SignalSenderKeyStoresTableTableManager(_db, _db.signalSenderKeyStores); - $$SignalSessionStoresTableTableManager get signalSessionStores => - $$SignalSessionStoresTableTableManager(_db, _db.signalSessionStores); - $$SignalSignedPreKeyStoresTableTableManager get signalSignedPreKeyStores => - $$SignalSignedPreKeyStoresTableTableManager( - _db, - _db.signalSignedPreKeyStores, - ); -} diff --git a/lib/src/database/signal/signal_identity_key_store.dart b/lib/src/database/signal/signal_identity_key_store.dart deleted file mode 100644 index e251ba23..00000000 --- a/lib/src/database/signal/signal_identity_key_store.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:drift/drift.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/database/signal.db.dart'; - -class SignalIdentityKeyStore extends IdentityKeyStore { - SignalIdentityKeyStore(this.identityKeyPair, this.localRegistrationId); - - final IdentityKeyPair identityKeyPair; - final int localRegistrationId; - - @override - Future getIdentity(SignalProtocolAddress address) async { - final identity = - await (signalDB.select(signalDB.signalIdentityKeyStores)..where( - (t) => - t.deviceId.equals(address.getDeviceId()) & - t.name.equals(address.getName()), - )) - .getSingleOrNull(); - if (identity == null) return null; - return IdentityKey.fromBytes(identity.identityKey, 0); - } - - @override - Future getIdentityKeyPair() async => identityKeyPair; - - @override - Future getLocalRegistrationId() async => localRegistrationId; - - @override - Future isTrustedIdentity( - SignalProtocolAddress address, - IdentityKey? identityKey, - Direction? direction, - ) async { - final trusted = await getIdentity(address); - if (identityKey == null) { - return false; - } - return trusted == null || - const ListEquality().equals( - trusted.serialize(), - identityKey.serialize(), - ); - } - - @override - Future saveIdentity( - SignalProtocolAddress address, - IdentityKey? identityKey, - ) async { - if (identityKey == null) { - return false; - } - if (await getIdentity(address) == null) { - await signalDB - .into(signalDB.signalIdentityKeyStores) - .insert( - SignalIdentityKeyStoresCompanion( - deviceId: Value(address.getDeviceId()), - name: Value(address.getName()), - identityKey: Value(identityKey.serialize()), - ), - ); - } else { - await (signalDB.update(signalDB.signalIdentityKeyStores)..where( - (t) => - t.deviceId.equals(address.getDeviceId()) & - t.name.equals(address.getName()), - )) - .write( - SignalIdentityKeyStoresCompanion( - identityKey: Value(identityKey.serialize()), - ), - ); - } - return true; - } -} diff --git a/lib/src/database/signal/signal_pre_key_store.dart b/lib/src/database/signal/signal_pre_key_store.dart deleted file mode 100644 index e6dd00a9..00000000 --- a/lib/src/database/signal/signal_pre_key_store.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/database/signal.db.dart'; -import 'package:twonly/src/utils/log.dart'; - -class SignalPreKeyStore extends PreKeyStore { - @override - Future containsPreKey(int preKeyId) async { - final preKeyRecord = await (signalDB.select( - signalDB.signalPreKeyStores, - )..where((tbl) => tbl.preKeyId.equals(preKeyId))).get(); - return preKeyRecord.isNotEmpty; - } - - @override - Future loadPreKey(int preKeyId) async { - final preKeyRecord = await (signalDB.select( - signalDB.signalPreKeyStores, - )..where((tbl) => tbl.preKeyId.equals(preKeyId))).get(); - if (preKeyRecord.isEmpty) { - throw InvalidKeyIdException( - '[PREKEY] No such preKey record!', - ); - } - final preKey = preKeyRecord.first.preKey; - return PreKeyRecord.fromBuffer(preKey); - } - - @override - Future removePreKey(int preKeyId) async { - await (signalDB.delete( - signalDB.signalPreKeyStores, - )..where((tbl) => tbl.preKeyId.equals(preKeyId))).go(); - } - - @override - Future storePreKey(int preKeyId, PreKeyRecord record) async { - final preKeyCompanion = SignalPreKeyStoresCompanion( - preKeyId: Value(preKeyId), - preKey: Value(record.serialize()), - ); - - try { - await signalDB - .into(signalDB.signalPreKeyStores) - .insert(preKeyCompanion, mode: InsertMode.insertOrReplace); - } catch (e) { - Log.error('$e'); - } - } -} diff --git a/lib/src/database/signal/signal_protocol_store.dart b/lib/src/database/signal/signal_protocol_store.dart deleted file mode 100644 index 0c517037..00000000 --- a/lib/src/database/signal/signal_protocol_store.dart +++ /dev/null @@ -1,122 +0,0 @@ -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/src/database/signal/signal_identity_key_store.dart'; -import 'package:twonly/src/database/signal/signal_pre_key_store.dart'; -import 'package:twonly/src/database/signal/signal_session_store.dart'; -import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart'; - -class SignalSignalProtocolStore implements SignalProtocolStore { - SignalSignalProtocolStore( - IdentityKeyPair identityKeyPair, - int registrationId, - ) { - _identityKeyStore = SignalIdentityKeyStore( - identityKeyPair, - registrationId, - ); - } - - final preKeyStore = SignalPreKeyStore(); - final sessionStore = SignalSessionStore(); - final signedPreKeyStore = SignalSignedPreKeyStore(); - - late IdentityKeyStore _identityKeyStore; - - @override - Future getIdentityKeyPair() async => - _identityKeyStore.getIdentityKeyPair(); - - @override - Future getLocalRegistrationId() async => - _identityKeyStore.getLocalRegistrationId(); - - @override - Future saveIdentity( - SignalProtocolAddress address, - IdentityKey? identityKey, - ) async => _identityKeyStore.saveIdentity(address, identityKey); - - @override - Future isTrustedIdentity( - SignalProtocolAddress address, - IdentityKey? identityKey, - Direction direction, - ) async => - _identityKeyStore.isTrustedIdentity(address, identityKey, direction); - - @override - Future getIdentity(SignalProtocolAddress address) async => - _identityKeyStore.getIdentity(address); - - @override - Future loadPreKey(int preKeyId) async => - preKeyStore.loadPreKey(preKeyId); - - @override - Future storePreKey(int preKeyId, PreKeyRecord record) async { - await preKeyStore.storePreKey(preKeyId, record); - } - - @override - Future containsPreKey(int preKeyId) async => - preKeyStore.containsPreKey(preKeyId); - - @override - Future removePreKey(int preKeyId) async { - await preKeyStore.removePreKey(preKeyId); - } - - @override - Future loadSession(SignalProtocolAddress address) async => - sessionStore.loadSession(address); - - @override - Future> getSubDeviceSessions(String name) async => - sessionStore.getSubDeviceSessions(name); - - @override - Future storeSession( - SignalProtocolAddress address, - SessionRecord record, - ) async { - await sessionStore.storeSession(address, record); - } - - @override - Future containsSession(SignalProtocolAddress address) async => - sessionStore.containsSession(address); - - @override - Future deleteSession(SignalProtocolAddress address) async { - await sessionStore.deleteSession(address); - } - - @override - Future deleteAllSessions(String name) async { - await sessionStore.deleteAllSessions(name); - } - - @override - Future loadSignedPreKey(int signedPreKeyId) async => - signedPreKeyStore.loadSignedPreKey(signedPreKeyId); - - @override - Future> loadSignedPreKeys() async => - signedPreKeyStore.loadSignedPreKeys(); - - @override - Future storeSignedPreKey( - int signedPreKeyId, - SignedPreKeyRecord record, - ) async { - await signedPreKeyStore.storeSignedPreKey(signedPreKeyId, record); - } - - @override - Future containsSignedPreKey(int signedPreKeyId) async => - signedPreKeyStore.containsSignedPreKey(signedPreKeyId); - - @override - Future removeSignedPreKey(int signedPreKeyId) async { - await signedPreKeyStore.removeSignedPreKey(signedPreKeyId); - } -} diff --git a/lib/src/database/signal/signal_sender_key_store.dart b/lib/src/database/signal/signal_sender_key_store.dart deleted file mode 100644 index 7bf1dc52..00000000 --- a/lib/src/database/signal/signal_sender_key_store.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/database/signal.db.dart'; - -class SignalSenderKeyStore extends SenderKeyStore { - @override - Future loadSenderKey(SenderKeyName senderKeyName) async { - final identity = - await (signalDB.select(signalDB.signalSenderKeyStores) - ..where((t) => t.senderKeyName.equals(senderKeyName.serialize()))) - .getSingleOrNull(); - if (identity == null) { - throw InvalidKeyIdException( - 'No such sender key record! - $senderKeyName', - ); - } - return SenderKeyRecord.fromSerialized(identity.senderKey); - } - - @override - Future storeSenderKey( - SenderKeyName senderKeyName, - SenderKeyRecord record, - ) async { - await signalDB - .into(signalDB.signalSenderKeyStores) - .insert( - SignalSenderKeyStoresCompanion( - senderKey: Value(record.serialize()), - senderKeyName: Value(senderKeyName.serialize()), - ), - ); - } -} diff --git a/lib/src/database/signal/signal_session_store.dart b/lib/src/database/signal/signal_session_store.dart deleted file mode 100644 index f11e304e..00000000 --- a/lib/src/database/signal/signal_session_store.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/database/signal.db.dart'; - -class SignalSessionStore extends SessionStore { - @override - Future containsSession(SignalProtocolAddress address) async { - final sessions = - await (signalDB.select(signalDB.signalSessionStores)..where( - (tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()), - )) - .get(); - return sessions.isNotEmpty; - } - - @override - Future deleteAllSessions(String name) async { - await (signalDB.delete( - signalDB.signalSessionStores, - )..where((tbl) => tbl.name.equals(name))).go(); - } - - @override - Future deleteSession(SignalProtocolAddress address) async { - await (signalDB.delete(signalDB.signalSessionStores)..where( - (tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()), - )) - .go(); - } - - @override - Future> getSubDeviceSessions(String name) async { - final deviceIds = - await (signalDB.select(signalDB.signalSessionStores)..where( - (tbl) => tbl.deviceId.equals(1).not() & tbl.name.equals(name), - )) - .get(); - return deviceIds.map((row) => row.deviceId).toList(); - } - - @override - Future loadSession(SignalProtocolAddress address) async { - final dbSession = - await (signalDB.select(signalDB.signalSessionStores)..where( - (tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()), - )) - .get(); - - if (dbSession.isEmpty) { - return SessionRecord(); - } - final session = dbSession.first.sessionRecord; - return SessionRecord.fromSerialized(session); - } - - @override - Future storeSession( - SignalProtocolAddress address, - SessionRecord record, - ) async { - final sessionCompanion = SignalSessionStoresCompanion( - deviceId: Value(address.getDeviceId()), - name: Value(address.getName()), - sessionRecord: Value(record.serialize()), - ); - - if (!await containsSession(address)) { - await signalDB - .into(signalDB.signalSessionStores) - .insert(sessionCompanion); - } else { - await (signalDB.update(signalDB.signalSessionStores)..where( - (tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()), - )) - .write(sessionCompanion); - } - } -} diff --git a/lib/src/database/signal/signal_signed_pre_key_store.dart b/lib/src/database/signal/signal_signed_pre_key_store.dart deleted file mode 100644 index 9376c77e..00000000 --- a/lib/src/database/signal/signal_signed_pre_key_store.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'package:drift/drift.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/database/signal.db.dart'; -import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/utils/secure_storage.dart'; - -Future> getSignalSignedPreKeyStoreOld() async { - final storeSerialized = await SecureStorage.instance.read( - key: 'signed_pre_key_store', - ); - final store = HashMap(); - if (storeSerialized == null) { - return store; - } - final storeHashMap = json.decode(storeSerialized) as List; - for (final item in storeHashMap) { - // ignore: avoid_dynamic_calls - store[item[0] as int] = base64Decode(item[1] as String); - } - return store; -} - -class SignalSignedPreKeyStore extends SignedPreKeyStore { - @override - Future loadSignedPreKey(int signedPreKeyId) async { - final record = await (signalDB.select( - signalDB.signalSignedPreKeyStores, - )..where((tbl) => tbl.signedPreKeyId.equals(signedPreKeyId))).get(); - if (record.isEmpty) { - throw InvalidKeyIdException( - 'No such signed prekey record! $signedPreKeyId', - ); - } - return SignedPreKeyRecord.fromSerialized(record.first.signedPreKey); - } - - @override - Future> loadSignedPreKeys() async { - final records = await signalDB - .select(signalDB.signalSignedPreKeyStores) - .get(); - return records - .map((r) => SignedPreKeyRecord.fromSerialized(r.signedPreKey)) - .toList(); - } - - @override - Future storeSignedPreKey( - int signedPreKeyId, - SignedPreKeyRecord record, - ) async { - final companion = SignalSignedPreKeyStoresCompanion( - signedPreKeyId: Value(signedPreKeyId), - signedPreKey: Value(record.serialize()), - ); - - try { - await signalDB - .into(signalDB.signalSignedPreKeyStores) - .insert(companion, mode: InsertMode.insertOrReplace); - } catch (e) { - Log.error('$e'); - rethrow; - } - } - - @override - Future containsSignedPreKey(int signedPreKeyId) async { - final record = await (signalDB.select( - signalDB.signalSignedPreKeyStores, - )..where((tbl) => tbl.signedPreKeyId.equals(signedPreKeyId))).get(); - return record.isNotEmpty; - } - - @override - Future removeSignedPreKey(int signedPreKeyId) async { - await (signalDB.delete( - signalDB.signalSignedPreKeyStores, - )..where((tbl) => tbl.signedPreKeyId.equals(signedPreKeyId))).go(); - } -} diff --git a/lib/src/database/tables/signal_identity_key_store.table.dart b/lib/src/database/tables/signal_identity_key_store.table.dart deleted file mode 100644 index 1f7d3808..00000000 --- a/lib/src/database/tables/signal_identity_key_store.table.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:drift/drift.dart'; - -@DataClassName('SignalIdentityKeyStore') -class SignalIdentityKeyStores extends Table { - IntColumn get deviceId => integer()(); - TextColumn get name => text()(); - BlobColumn get identityKey => blob()(); - DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); - - @override - Set get primaryKey => {deviceId, name}; -} diff --git a/lib/src/database/tables/signal_pre_key_store.table.dart b/lib/src/database/tables/signal_pre_key_store.table.dart deleted file mode 100644 index eb742637..00000000 --- a/lib/src/database/tables/signal_pre_key_store.table.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:drift/drift.dart'; - -@DataClassName('SignalPreKeyStore') -class SignalPreKeyStores extends Table { - IntColumn get preKeyId => integer()(); - BlobColumn get preKey => blob()(); - DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); - - @override - Set get primaryKey => {preKeyId}; -} diff --git a/lib/src/database/tables/signal_sender_key_store.table.dart b/lib/src/database/tables/signal_sender_key_store.table.dart deleted file mode 100644 index 1c10183a..00000000 --- a/lib/src/database/tables/signal_sender_key_store.table.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:drift/drift.dart'; - -@DataClassName('SignalSenderKeyStore') -class SignalSenderKeyStores extends Table { - TextColumn get senderKeyName => text()(); - BlobColumn get senderKey => blob()(); - - @override - Set get primaryKey => {senderKeyName}; -} diff --git a/lib/src/database/tables/signal_session_store.table.dart b/lib/src/database/tables/signal_session_store.table.dart deleted file mode 100644 index e5227006..00000000 --- a/lib/src/database/tables/signal_session_store.table.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:drift/drift.dart'; - -@DataClassName('SignalSessionStore') -class SignalSessionStores extends Table { - IntColumn get deviceId => integer()(); - TextColumn get name => text()(); - BlobColumn get sessionRecord => blob()(); - DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); - - @override - Set get primaryKey => {deviceId, name}; -} diff --git a/lib/src/database/tables/signal_signed_pre_key_store.table.dart b/lib/src/database/tables/signal_signed_pre_key_store.table.dart deleted file mode 100644 index 82991717..00000000 --- a/lib/src/database/tables/signal_signed_pre_key_store.table.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:drift/drift.dart'; - -@DataClassName('SignalSignedPreKeyStore') -class SignalSignedPreKeyStores extends Table { - IntColumn get signedPreKeyId => integer()(); - BlobColumn get signedPreKey => blob()(); - DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); - - @override - Set get primaryKey => {signedPreKeyId}; -} diff --git a/lib/src/model/json/signal_identity.model.dart b/lib/src/model/json/signal_identity.model.dart deleted file mode 100644 index bc01d334..00000000 --- a/lib/src/model/json/signal_identity.model.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:json_annotation/json_annotation.dart'; - -part 'signal_identity.model.g.dart'; - -@JsonSerializable() -class SignalIdentity { - const SignalIdentity({ - required this.identityKeyPairU8List, - required this.registrationId, - }); - factory SignalIdentity.fromJson(Map json) => - _$SignalIdentityFromJson(json); - - final int registrationId; - - @Uint8ListConverter() - final Uint8List identityKeyPairU8List; - Map toJson() => _$SignalIdentityToJson(this); -} - -class Uint8ListConverter implements JsonConverter { - const Uint8ListConverter(); - @override - Uint8List fromJson(String json) { - return base64Decode(json); - } - - @override - String toJson(Uint8List object) { - return base64Encode(object); - } -} diff --git a/lib/src/model/json/signal_identity.model.g.dart b/lib/src/model/json/signal_identity.model.g.dart deleted file mode 100644 index e80049e6..00000000 --- a/lib/src/model/json/signal_identity.model.g.dart +++ /dev/null @@ -1,23 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'signal_identity.model.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -SignalIdentity _$SignalIdentityFromJson(Map json) => - SignalIdentity( - identityKeyPairU8List: const Uint8ListConverter().fromJson( - json['identityKeyPairU8List'] as String, - ), - registrationId: (json['registrationId'] as num).toInt(), - ); - -Map _$SignalIdentityToJson(SignalIdentity instance) => - { - 'registrationId': instance.registrationId, - 'identityKeyPairU8List': const Uint8ListConverter().toJson( - instance.identityKeyPairU8List, - ), - }; diff --git a/lib/src/services/api/api.service.dart b/lib/src/services/api/api.service.dart index 01b08c25..5b76f39a 100644 --- a/lib/src/services/api/api.service.dart +++ b/lib/src/services/api/api.service.dart @@ -7,7 +7,6 @@ import 'package:twonly/locator.dart'; import 'package:twonly/src/services/api/mediafiles/upload.api.dart'; import 'package:twonly/src/services/memories/memories_cloud.service.dart'; import 'package:twonly/src/services/notifications/fcm.notifications.dart'; -import 'package:twonly/src/services/signal/protocol_state.signal.dart'; import 'package:twonly/src/utils/log.dart'; /// The ApiProvider is responsible for communicating with the server. @@ -47,7 +46,6 @@ class ApiService { unawaited(reuploadMediaFiles()); twonlyDB.markUpdated(); - resetResyncedUsers(); // resetUserDiscoveryRequestUpdates(); memoriesCloudService.init(); } diff --git a/lib/src/services/api/utils.api.dart b/lib/src/services/api/utils.api.dart index 2edfbe99..cb4afdef 100644 --- a/lib/src/services/api/utils.api.dart +++ b/lib/src/services/api/utils.api.dart @@ -10,7 +10,6 @@ import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart as server; import 'package:twonly/src/model/protobuf/client/generated/messages.pbserver.dart' hide Message; -import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/secure_storage.dart'; @@ -69,33 +68,33 @@ Future handleMediaError(MediaFile media) async { targetMessageId: message.messageId, ), ).writeToBuffer(), - onlySendIfNoReceiptsAreOpen: false, - onlyReturnEncryptedData: false, - blocking: true, ); } Future importSignalContactAndCreateRequest( server.Response_UserData userdata, ) async { - if (!await processSignalUserData(userdata)) { + try { + await RustApi.establishSignalSession( + contactId: userdata.userId.toInt(), + expectedPublicKey: Uint8List.fromList(userdata.publicIdentityKey), + ); + + // 2. Then send user request + await RustApi.sendEncryptedContent( + contactId: userdata.userId.toInt(), + content: EncryptedContent( + contactRequest: EncryptedContent_ContactRequest( + type: EncryptedContent_ContactRequest_Type.REQUEST, + ), + ).writeToBuffer(), + ); + + return true; + } catch (e) { + Log.error('Failed to establish session and send contact request: $e'); return false; } - - // 2. Then send user request - await RustApi.sendEncryptedContent( - contactId: userdata.userId.toInt(), - content: EncryptedContent( - contactRequest: EncryptedContent_ContactRequest( - type: EncryptedContent_ContactRequest_Type.REQUEST, - ), - ).writeToBuffer(), - onlySendIfNoReceiptsAreOpen: false, - onlyReturnEncryptedData: false, - blocking: true, - ); - - return true; } Future?> getAuthenticationHeader() async { diff --git a/lib/src/services/group.service.dart b/lib/src/services/group.service.dart index 0dd2c648..2e06396d 100644 --- a/lib/src/services/group.service.dart +++ b/lib/src/services/group.service.dart @@ -51,5 +51,6 @@ Future removeMemberFromGroup(Group group, Uint8List key, int contactId) => groupPublicKey: key, contactId: contactId, ); -Future leaveAsNonAdminFromGroup(Group group) => +Future leaveGroup(Group group) => rust_groups.leaveGroup(groupId: group.groupId); +Future leaveAsNonAdminFromGroup(Group group) => leaveGroup(group); diff --git a/lib/src/services/intent/links.intent.dart b/lib/src/services/intent/links.intent.dart index 71b7bb93..733dcd47 100644 --- a/lib/src/services/intent/links.intent.dart +++ b/lib/src/services/intent/links.intent.dart @@ -6,13 +6,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart'; import 'package:go_router/go_router.dart'; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/routes.keys.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/tables/mediafiles.table.dart'; -import 'package:twonly/src/services/passwordless_recovery.service.dart' - show PasswordlessRecoveryService; -import 'package:twonly/src/services/signal/session.signal.dart'; +import 'package:twonly/src/services/passwordless_recovery.service.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/qr.utils.dart'; @@ -102,7 +101,9 @@ Future handleIntentUrl(BuildContext context, Uri uri) async { if (publicKey != null) { try { final contact = contacts.first; - final storedPublicKey = await getPublicKeyFromContact(contact.userId); + final storedPublicKey = await RustSignal.getContactPublicKey( + contactId: contact.userId, + ); final receivedPublicKey = base64Url.decode(publicKey); if (storedPublicKey == null || receivedPublicKey.isEmpty || diff --git a/lib/src/services/key_verification.service.dart b/lib/src/services/key_verification.service.dart index 6dbcc415..00db9335 100644 --- a/lib/src/services/key_verification.service.dart +++ b/lib/src/services/key_verification.service.dart @@ -4,14 +4,13 @@ import 'dart:typed_data'; import 'package:collection/collection.dart'; import 'package:cryptography_plus/cryptography_plus.dart'; import 'package:flutter/material.dart'; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/database/daos/contacts.dao.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart' as pb; import 'package:twonly/src/providers/routing.provider.dart'; -import 'package:twonly/src/services/signal/identity.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'; import 'package:twonly/src/visual/components/verification_success_dialog.comp.dart'; @@ -62,9 +61,6 @@ class KeyVerificationService { calculatedMac: calculatedMac, ), ).writeToBuffer(), - onlySendIfNoReceiptsAreOpen: false, - onlyReturnEncryptedData: false, - blocking: true, ); } @@ -74,7 +70,9 @@ class KeyVerificationService { ) async { Log.info('Received a verification proof. Verifying the calculated mac...'); - final contactPubKey = await getPublicKeyFromContact(fromUserId); + final contactPubKey = await RustSignal.getContactPublicKey( + contactId: fromUserId, + ); if (contactPubKey == null) { Log.error('No public key stored..'); return; @@ -121,7 +119,9 @@ class KeyVerificationService { required List sharedPublicIdentityKey, required int senderId, }) async { - final publicIdentityKey = await getPublicKeyFromContact(contactId); + final publicIdentityKey = await RustSignal.getContactPublicKey( + contactId: contactId, + ); if (publicIdentityKey == null) { Log.info('No public key stored for contact $contactId'); return; @@ -148,7 +148,7 @@ Future> _createVerificationBytes( ) async { final bytes = []; - final userPublicKey = await getUserPublicKey(); + final userPublicKey = await RustSignal.getUserPublicKey(); final ownBytes = [ ..._userIdToLeBytes(userService.currentUser.userId), diff --git a/lib/src/services/migrations.service.dart b/lib/src/services/migrations.service.dart index d2852d76..a09af65e 100644 --- a/lib/src/services/migrations.service.dart +++ b/lib/src/services/migrations.service.dart @@ -1,24 +1,15 @@ import 'dart:async'; -import 'dart:convert'; import 'package:drift/drift.dart'; import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; -import 'package:twonly/core/bridge/wrapper/key_manager.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; -import 'package:twonly/src/constants/secure_storage.keys.dart'; -import 'package:twonly/src/database/signal.db.dart'; -import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart' - show getSignalSignedPreKeyStoreOld; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/json/signal_identity.model.dart'; import 'package:twonly/src/services/api/mediafiles/download.api.dart'; import 'package:twonly/src/services/passwordless_recovery.service.dart'; import 'package:twonly/src/services/user.service.dart'; import 'package:twonly/src/services/user_discovery.service.dart'; -import 'package:twonly/src/utils/log.dart'; -import 'package:twonly/src/utils/secure_storage.dart'; import 'package:twonly/src/visual/views/onboarding/setup.view.dart'; Future runMigrations() async { @@ -56,53 +47,17 @@ Future runMigrations() async { }); } if (userService.currentUser.appVersion < 113) { - var migrationSuccess = true; - final signalIdentity = await SecureStorage.instance.read( - // ignore: deprecated_member_use_from_same_package - key: SecureStorageKeys.signalIdentity, - ); - - if (signalIdentity != null) { - try { - final decoded = jsonDecode(signalIdentity); - final identity = SignalIdentity.fromJson( - decoded as Map, - ); - - await RustKeyManager.importSignalIdentity( - identityKeyPairStructure: identity.identityKeyPairU8List, - registrationId: identity.registrationId, - signedPreKeyStore: await getSignalSignedPreKeyStoreOld(), - ); - Log.info('Importing signal identify to the rust key manager'); - - // Clean up old keys after successful migration - await SecureStorage.instance.delete( - // ignore: deprecated_member_use_from_same_package - key: SecureStorageKeys.signalIdentity, - ); - await SecureStorage.instance.delete( - // ignore: deprecated_member_use_from_same_package - key: SecureStorageKeys.signalSignedPreKey, - ); - } catch (e) { - Log.error('Failed to migrate signal identity: $e'); - migrationSuccess = false; - } - } - - if (migrationSuccess) { - await UserService.update((u) { - u - ..appVersion = 113 - ..canUseLoginTokenForAuth = false - // As usernames changes where not considered in the old version force users - // to reenter there passwords. - ..twonlySafeBackup?.encryptionKey = Uint8List(0) - ..twonlySafeBackup?.backupId = Uint8List(0); - }); - } + await UserService.update((u) { + u + ..appVersion = 113 + ..canUseLoginTokenForAuth = false + // As usernames changes where not considered in the old version force users + // to reenter there passwords. + ..twonlySafeBackup?.encryptionKey = Uint8List(0) + ..twonlySafeBackup?.backupId = Uint8List(0); + }); } + if (userService.currentUser.appVersion < 114) { final allMedia = await twonlyDB.mediaFilesDao .select(twonlyDB.mediaFiles) @@ -120,29 +75,7 @@ Future runMigrations() async { } if (userService.currentUser.appVersion < 115) { - var migrationSuccess = true; - try { - final rustStore = await RustKeyManager.loadSignedPrekeys(); - for (final entry in rustStore.entries) { - final companion = SignalSignedPreKeyStoresCompanion( - signedPreKeyId: Value(entry.key), - signedPreKey: Value(entry.value), - ); - await signalDB - .into(signalDB.signalSignedPreKeyStores) - .insert( - companion, - mode: InsertMode.insertOrReplace, - ); - await RustKeyManager.removeSignedPrekey(signedPreKeyId: entry.key); - } - } catch (e) { - Log.error('Failed to migrate signed prekeys to Drift: $e'); - migrationSuccess = false; - } - if (migrationSuccess) { - await UserService.update((u) => u.appVersion = 115); - } + await UserService.update((u) => u.appVersion = 115); } if (userService.currentUser.appVersion < 116) { diff --git a/lib/src/services/passwordless_recovery.service.dart b/lib/src/services/passwordless_recovery.service.dart index a25476b9..680f9f99 100644 --- a/lib/src/services/passwordless_recovery.service.dart +++ b/lib/src/services/passwordless_recovery.service.dart @@ -311,7 +311,11 @@ class PasswordlessRecoveryService { ); } - unawaited(RustApi.performPasswordlessRecoveryHeartbeat()); + unawaited( + RustApi.performPasswordlessRecoveryHeartbeat().catchError((e) { + Log.warn('Failed to perform passwordless recovery heartbeat: $e'); + }), + ); // The passwordless is configured successfully. return true; diff --git a/lib/src/services/signal/consts.signal.dart b/lib/src/services/signal/consts.signal.dart deleted file mode 100644 index 5b85d35d..00000000 --- a/lib/src/services/signal/consts.signal.dart +++ /dev/null @@ -1,2 +0,0 @@ -// multi device support is not planned, so just set this to one -const int defaultDeviceId = 1; diff --git a/lib/src/services/signal/encryption.signal.dart b/lib/src/services/signal/encryption.signal.dart deleted file mode 100644 index d5cdf7f2..00000000 --- a/lib/src/services/signal/encryption.signal.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'dart:typed_data'; - -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -// ignore: implementation_imports -import 'package:libsignal_protocol_dart/src/invalid_message_exception.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart' - as pb; -import 'package:twonly/src/services/signal/protocol_state.signal.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; -import 'package:twonly/src/services/signal/utils.signal.dart'; -import 'package:twonly/src/utils/log.dart'; - -class SignalEncryptResult { - SignalEncryptResult(this.ciphertext, this.type); - final Uint8List ciphertext; - final pb.Message_Type type; -} - -Future signalEncryptMessage( - int target, - Uint8List plaintextContent, -) async { - return lockingSignalProtocol.protect(() async { - try { - final signalStore = (await getSignalStore())!; - final address = getSignalAddress(target); - final session = SessionCipher.fromStore(signalStore, address); - final cipherText = await session.encrypt(plaintextContent); - - pb.Message_Type type; - switch (cipherText.getType()) { - case CiphertextMessage.prekeyType: - type = pb.Message_Type.PREKEY_BUNDLE; - case CiphertextMessage.whisperType: - type = pb.Message_Type.CIPHERTEXT; - default: - Log.error('Invalid ciphertext type: ${cipherText.getType()}.'); - return null; - } - - return SignalEncryptResult(cipherText.serialize(), type); - } catch (e) { - Log.error('Could not encrypt message for target $target: $e'); - return null; - } - }); -} - -Future<(pb.EncryptedContent?, pb.PlaintextContent_DecryptionErrorMessage_Type?)> -signalDecryptMessageV1( - int fromUserId, - Uint8List encryptedContentRaw, - int type, { - Set? brokenSessionsInCurrentBatch, -}) async { - Log.info('Acquiring lockingSignalProtocol for $fromUserId (V1)'); - final ( - decryptedContent, - errorType, - needsResync, - ) = await lockingSignalProtocol.protect(() async { - Log.info('Lock acquired for $fromUserId (V1)'); - try { - // Yield execution to the event loop to prevent UI freezing during bulk decryption - await Future.delayed(Duration.zero); - - final session = SessionCipher.fromStore( - (await getSignalStore())!, - getSignalAddress(fromUserId), - ); - - Uint8List plaintext; - - switch (type) { - case CiphertextMessage.prekeyType: - plaintext = await session.decrypt( - PreKeySignalMessage(encryptedContentRaw), - ); - case CiphertextMessage.whisperType: - plaintext = await session.decryptFromSignal( - SignalMessage.fromSerialized(encryptedContentRaw), - ); - default: - Log.error('Unknown Message Decryption Type: $type'); - return ( - null, - pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN, - false, - ); - } - - recordResyncAttempt(fromUserId, success: true); - return (pb.EncryptedContent.fromBuffer(plaintext), null, false); - } on InvalidKeyIdException catch (e) { - Log.warn(e); - return ( - null, - pb.PlaintextContent_DecryptionErrorMessage_Type.PREKEY_UNKNOWN, - false, - ); - } on DuplicateMessageException catch (e) { - // This is normal behavior: This can happen in case a message was decrypted, but before further processing - // the user killed the app. This results in a new transmission from the server, but as the message was already - // decrypted, this error happens. In this case, request the message again. - Log.info(e); - return ( - null, - pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN, - false, - ); - } on InvalidMessageException catch (e) { - Log.warn(e); - return ( - null, - pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN, - true, - ); - } catch (e) { - Log.error(e); - return ( - null, - pb.PlaintextContent_DecryptionErrorMessage_Type.UNKNOWN, - false, - ); - } - }); - - Log.info('Released lockingSignalProtocol for $fromUserId (V1)'); - - // Handle session resync OUTSIDE the lock to avoid holding it during - // network round-trips (which can block for up to 60 seconds) - if (needsResync) { - brokenSessionsInCurrentBatch?.add(fromUserId); - if (shouldAttemptResync(fromUserId)) { - if (await handleSessionResync(fromUserId)) { - // This flag prevents from resyncing the session the client received - // multiple new messages from the server he could not decrypt - recordResyncAttempt(fromUserId, success: false); - - // This message contains a new PreKeyBundle establishing a new signal - // session - await RustApi.sendEncryptedContent( - contactId: fromUserId, - content: pb.EncryptedContent( - errorMessages: pb.EncryptedContent_ErrorMessages( - type: pb.EncryptedContent_ErrorMessages_Type.SESSION_OUT_OF_SYNC, - ), - ).writeToBuffer(), - onlySendIfNoReceiptsAreOpen: false, - onlyReturnEncryptedData: false, - blocking: true, - ); - } - } - } - - return (decryptedContent, errorType); -} diff --git a/lib/src/services/signal/identity.signal.dart b/lib/src/services/signal/identity.signal.dart deleted file mode 100644 index 1fc5419b..00000000 --- a/lib/src/services/signal/identity.signal.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'dart:typed_data'; - -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/core/bridge/wrapper/key_manager.dart'; -import 'package:twonly/src/database/signal/signal_signed_pre_key_store.dart'; -import 'package:twonly/src/model/json/signal_identity.model.dart'; -import 'package:twonly/src/services/signal/consts.signal.dart'; -import 'package:twonly/src/services/signal/utils.signal.dart'; -import 'package:twonly/src/utils/log.dart'; - -Future getSignalIdentity() async { - try { - final identity = await RustKeyManager.getSignalIdentity(); - return SignalIdentity( - identityKeyPairU8List: identity.$1, - registrationId: identity.$2, - ); - } catch (e) { - Log.error('could not load signal identity: $e'); - return null; - } -} - -Future getSignalIdentityKeyPair() async { - final signalIdentity = await getSignalIdentity(); - if (signalIdentity == null) return null; - return IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List); -} - -Future getUserPublicKey() async { - final signalIdentity = (await getSignalIdentity())!; - final signalStore = await getSignalStoreFromIdentity(signalIdentity); - final keyPair = await signalStore.getIdentityKeyPair(); - return keyPair.getPublicKey().serialize(); -} - -Future createIfNotExistsSignalIdentity() async { - // check if identity already exists - final existingIdentity = await getSignalIdentity(); - if (existingIdentity != null) { - final store = await getSignalStoreFromIdentity(existingIdentity); - final keys = await store.loadSignedPreKeys(); - if (keys.isEmpty) { - Log.warn( - 'Signal identity exists but signed prekeys are missing. Generating a new one.', - ); - final keyPair = await store.getIdentityKeyPair(); - final signedPreKey = generateSignedPreKey(keyPair, defaultDeviceId); - await SignalSignedPreKeyStore().storeSignedPreKey( - signedPreKey.id, - signedPreKey, - ); - } - return; - } - - final identityKeyPair = generateIdentityKeyPair(); - final registrationId = generateRegistrationId(true); - - final signedPreKey = generateSignedPreKey(identityKeyPair, defaultDeviceId); - - await SignalSignedPreKeyStore().storeSignedPreKey( - signedPreKey.id, - signedPreKey, - ); - - await RustKeyManager.importSignalIdentity( - identityKeyPairStructure: identityKeyPair.serialize(), - registrationId: registrationId, - signedPreKeyStore: const {}, - ); -} diff --git a/lib/src/services/signal/protocol_state.signal.dart b/lib/src/services/signal/protocol_state.signal.dart deleted file mode 100644 index 55f5f1e7..00000000 --- a/lib/src/services/signal/protocol_state.signal.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'dart:math'; -import 'package:mutex/mutex.dart'; - -/// Unified lock for all Signal protocol operations (encryption, decryption, session management). -final lockingSignalProtocol = Mutex(); - -/// Tracking users who have already been resynced in the current session. -final Map _resyncAttempts = {}; - -const int maxResyncAttempts = 3; - -bool shouldAttemptResync(int userId) { - final attempt = _resyncAttempts[userId]; - if (attempt == null) return true; - if (attempt.failureCount >= maxResyncAttempts) return false; - - final cooldown = Duration( - minutes: 5 * pow(5, attempt.failureCount - 1).toInt(), - ); - return DateTime.now().difference(attempt.lastAttempt) > cooldown; -} - -void recordResyncAttempt(int userId, {required bool success}) { - if (success) { - _resyncAttempts.remove(userId); - } else { - final current = _resyncAttempts[userId]; - _resyncAttempts[userId] = ( - failureCount: (current?.failureCount ?? 0) + 1, - lastAttempt: DateTime.now(), - ); - } -} - -/// Reset the resync tracking set (currently unused, backoff handles expiry naturally). -void resetResyncedUsers() { - // No-op. We want the backoff state to persist across reconnects. -} diff --git a/lib/src/services/signal/session.signal.dart b/lib/src/services/signal/session.signal.dart deleted file mode 100644 index d6ce3d4c..00000000 --- a/lib/src/services/signal/session.signal.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'dart:typed_data'; - -import 'package:drift/drift.dart' as drift; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/core/bridge/wrapper/signal.dart'; -import 'package:twonly/core/signal/engine.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/database/tables/contacts.table.dart'; -import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'; -import 'package:twonly/src/services/signal/consts.signal.dart'; -import 'package:twonly/src/services/signal/protocol_state.signal.dart'; -import 'package:twonly/src/services/signal/utils.signal.dart'; -import 'package:twonly/src/utils/log.dart'; - -Future processSignalUserData(Response_UserData userData) async { - return lockingSignalProtocol.protect(() async { - return _processSignalUserData(userData); - }); -} - -Future _processSignalUserData(Response_UserData userData) async { - if (userData.hasPqcBundle()) { - return _processSignalUserDataV2(userData); - } - return _processSignalUserDataV1(userData); -} - -Future _processSignalUserDataV2(Response_UserData userData) async { - try { - final tempIdentityKey = IdentityKey( - Curve.decodePoint( - DjbECPublicKey( - Uint8List.fromList(userData.publicIdentityKey), - ).serialize(), - 1, - ), - ); - - final signalStore = await getSignalStore(); - if (signalStore != null) { - final existingIdentity = await signalStore.getIdentity( - SignalProtocolAddress(userData.userId.toString(), defaultDeviceId), - ); - - if (existingIdentity != null && existingIdentity != tempIdentityKey) { - Log.error( - 'Identity key mismatch for contact ${userData.userId}! Existing V1 key does not match the incoming V2 identity key.', - ); - return false; - } - } - - int? tempEccPreKeyId; - Uint8List? tempEccPreKeyPublic; - if (userData.pqcBundle.hasPrekey()) { - tempEccPreKeyId = userData.pqcBundle.prekey.eccPreKeyId.toInt(); - tempEccPreKeyPublic = Uint8List.fromList( - userData.pqcBundle.prekey.eccPreKey, - ); - } else if (userData.prekeys.isNotEmpty) { - tempEccPreKeyId = userData.prekeys.first.id.toInt(); - tempEccPreKeyPublic = Curve.decodePoint( - DjbECPublicKey( - Uint8List.fromList(userData.prekeys.first.prekey), - ).serialize(), - 1, - ).serialize(); - } - - final tempKyberPreKeyId = userData.pqcBundle.hasPrekey() - ? userData.pqcBundle.prekey.kyberPreKeyId.toInt() - : userData.pqcBundle.kyberSignedPrekeyId.toInt(); - final tempKyberPreKeyPublic = userData.pqcBundle.hasPrekey() - ? Uint8List.fromList(userData.pqcBundle.prekey.kyberPreKey) - : Uint8List.fromList(userData.pqcBundle.kyberSignedPrekey); - final tempKyberPreKeySignature = userData.pqcBundle.hasPrekey() - ? Uint8List.fromList(userData.pqcBundle.prekey.kyberPreKeySignature) - : Uint8List.fromList(userData.pqcBundle.kyberSignedPrekeySignature); - - final rustBundle = FrbPreKeyBundle( - registrationId: userData.registrationId.toInt(), - deviceId: 1, - preKeyId: tempEccPreKeyId, - preKeyPublic: tempEccPreKeyPublic, - signedPreKeyId: userData.pqcBundle.eccSignedPrekeyId.toInt(), - signedPreKeyPublic: Uint8List.fromList( - userData.pqcBundle.eccSignedPrekey, - ), - signedPreKeySignature: Uint8List.fromList( - userData.pqcBundle.eccSignedPrekeySignature, - ), - identityKey: tempIdentityKey.publicKey.serialize(), - kyberPreKeyId: tempKyberPreKeyId, - kyberPreKeyPublic: tempKyberPreKeyPublic, - kyberPreKeySignature: tempKyberPreKeySignature, - ); - - await RustSignal.processPrekeyBundle( - name: userData.userId.toString(), - deviceId: 1, - bundle: rustBundle, - ); - - final contact = await twonlyDB.contactsDao.getContactById( - userData.userId.toInt(), - ); - if (contact != null && contact.signalVersion != SignalVersion.v2) { - await twonlyDB.contactsDao.updateContact( - contact.userId, - const ContactsCompanion(signalVersion: drift.Value(SignalVersion.v2)), - ); - } - - return true; - } catch (e) { - Log.error('could not process pqc bundle: $e'); - return false; - } -} - -Future _processSignalUserDataV1(Response_UserData userData) async { - final SignalProtocolStore? signalStore = await getSignalStore(); - - if (signalStore == null) { - return false; - } - - final targetAddress = getSignalAddress(userData.userId.toInt()); - - final sessionBuilder = SessionBuilder.fromSignalStore( - signalStore, - targetAddress, - ); - - ECPublicKey? tempPrePublicKey; - int? tempPreKeyId; - - if (userData.prekeys.isNotEmpty) { - tempPrePublicKey = Curve.decodePoint( - DjbECPublicKey( - Uint8List.fromList(userData.prekeys.first.prekey), - ).serialize(), - 1, - ); - tempPreKeyId = userData.prekeys.first.id.toInt(); - } - - final tempSignedPreKeyId = userData.signedPrekeyId.toInt(); - - final tempSignedPreKeyPublic = Curve.decodePoint( - DjbECPublicKey(Uint8List.fromList(userData.signedPrekey)).serialize(), - 1, - ); - - final tempSignedPreKeySignature = Uint8List.fromList( - userData.signedPrekeySignature, - ); - - final tempIdentityKey = IdentityKey( - Curve.decodePoint( - DjbECPublicKey( - Uint8List.fromList(userData.publicIdentityKey), - ).serialize(), - 1, - ), - ); - - final preKeyBundle = PreKeyBundle( - userData.registrationId.toInt(), - defaultDeviceId, - tempPreKeyId, - tempPrePublicKey, - tempSignedPreKeyId, - tempSignedPreKeyPublic, - tempSignedPreKeySignature, - tempIdentityKey, - ); - - try { - await sessionBuilder.processPreKeyBundle(preKeyBundle); - return true; - } catch (e) { - Log.error('could not process pre key bundle: $e'); - return false; - } -} - -Future getPublicKeyFromContact(int contactId) async { - final signalStore = await getSignalStore(); - if (signalStore == null) return null; - try { - final targetIdentity = await signalStore.getIdentity( - SignalProtocolAddress( - contactId.toString(), - defaultDeviceId, - ), - ); - if (targetIdentity != null) { - return targetIdentity.publicKey.serialize(); - } - return null; - } catch (e) { - return null; - } -} - -Future handleSessionResync(int fromUserId) async { - final userData = await rustApiProtobuf( - RustApi.getUserById(userId: fromUserId), - decodeUserData, - ); - if (userData != null) { - Log.info('Got new session data from the server to re-sync the session'); - return processSignalUserData(userData); - } - Log.info('Could not download userdata from the server.'); - return false; -} diff --git a/lib/src/services/signal/utils.signal.dart b/lib/src/services/signal/utils.signal.dart deleted file mode 100644 index fb399884..00000000 --- a/lib/src/services/signal/utils.signal.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; -import 'package:twonly/src/database/signal/signal_protocol_store.dart'; -import 'package:twonly/src/model/json/signal_identity.model.dart'; -import 'package:twonly/src/services/signal/consts.signal.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; - -Future getSignalStore() async { - return getSignalStoreFromIdentity((await getSignalIdentity())!); -} - -Future getSignalStoreFromIdentity( - SignalIdentity signalIdentity, -) async { - final identityKeyPair = IdentityKeyPair.fromSerialized( - signalIdentity.identityKeyPairU8List, - ); - - return SignalSignalProtocolStore( - identityKeyPair, - signalIdentity.registrationId, - ); -} - -SignalProtocolAddress getSignalAddress(int userId) { - return SignalProtocolAddress(userId.toString(), defaultDeviceId); -} diff --git a/lib/src/services/user.service.dart b/lib/src/services/user.service.dart index f4b6cd10..39a5cf66 100644 --- a/lib/src/services/user.service.dart +++ b/lib/src/services/user.service.dart @@ -94,7 +94,11 @@ class UserService { } static Future handleRustUserConfigChanged(UserConfig config) async { - userService._applyRustUserConfig(config); + try { + userService._applyRustUserConfig(config); + } catch (e) { + Log.warn(e); + } } void _applyRustUserConfig(UserConfig config, {bool notify = true}) { diff --git a/lib/src/utils/qr.utils.dart b/lib/src/utils/qr.utils.dart index 0f847841..d64f9c4a 100644 --- a/lib/src/utils/qr.utils.dart +++ b/lib/src/utils/qr.utils.dart @@ -6,41 +6,27 @@ import 'package:collection/collection.dart' show ListExtensions; import 'package:drift/drift.dart' show Value; import 'package:fixnum/fixnum.dart'; import 'package:flutter/foundation.dart'; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart'; +import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart'; import 'package:twonly/src/model/protobuf/client/generated/qr.pb.dart'; -import 'package:twonly/src/services/api/utils.api.dart'; import 'package:twonly/src/services/key_verification.service.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; -import 'package:twonly/src/services/signal/utils.signal.dart'; import 'package:twonly/src/utils/log.dart'; class QrCodeUtils { static String linkPrefix = 'https://me.twonly.eu/qr/#'; static Future publicProfileLink() async { - final signalIdentity = (await getSignalIdentity())!; - - final signalStore = await getSignalStoreFromIdentity(signalIdentity); - - final signedPreKey = (await signalStore.loadSignedPreKeys())[0]; - + final publicIdentityKey = await RustSignal.getUserPublicKey(); final secretVerificationToken = await KeyVerificationService.getNewSecretVerificationToken(); final publicProfile = PublicProfile( userId: Int64(userService.currentUser.userId), username: userService.currentUser.username, - publicIdentityKey: (await signalStore.getIdentityKeyPair()) - .getPublicKey() - .serialize(), - registrationId: Int64(signalIdentity.registrationId), - signedPrekey: signedPreKey.getKeyPair().publicKey.serialize(), - signedPrekeySignature: signedPreKey.signature, - signedPrekeyId: Int64(signedPreKey.id), + publicIdentityKey: publicIdentityKey, secretVerificationToken: secretVerificationToken, timestamp: Int64(clock.now().millisecondsSinceEpoch), ); @@ -88,7 +74,9 @@ class QrCodeUtils { return (profile, null, false); } - final storedPublicKey = await getPublicKeyFromContact(contact.userId); + final storedPublicKey = await RustSignal.getContactPublicKey( + contactId: contact.userId, + ); if (storedPublicKey == null) return null; final verificationOk = profile.publicIdentityKey.equals( @@ -127,32 +115,37 @@ class QrCodeUtils { } Future addNewContactFromPublicProfile(PublicProfile profile) async { - final userdata = Response_UserData( - userId: profile.userId, - publicIdentityKey: profile.publicIdentityKey, - signedPrekey: profile.signedPrekey, - signedPrekeyId: profile.signedPrekeyId, - signedPrekeySignature: profile.signedPrekeySignature, - ); + try { + await RustApi.establishSignalSession( + contactId: profile.userId.toInt(), + expectedPublicKey: Uint8List.fromList(profile.publicIdentityKey), + ); + await RustApi.sendEncryptedContent( + contactId: profile.userId.toInt(), + content: EncryptedContent( + contactRequest: EncryptedContent_ContactRequest( + type: EncryptedContent_ContactRequest_Type.REQUEST, + ), + ).writeToBuffer(), + ); - final added = await twonlyDB.contactsDao.insertOnConflictUpdate( - ContactsCompanion( - username: Value(profile.username), - userId: Value(profile.userId.toInt()), - requested: const Value(false), - blocked: const Value(false), - deletedByUser: const Value(false), - ), - ); + final added = await twonlyDB.contactsDao.insertOnConflictUpdate( + ContactsCompanion( + username: Value(profile.username), + userId: Value(profile.userId.toInt()), + requested: const Value(false), + blocked: const Value(false), + deletedByUser: const Value(false), + ), + ); - // The user was added via the profile scanned from the QR code so the scanned public key was used. - await twonlyDB.keyVerificationDao.addKeyVerification( - profile.userId.toInt(), - VerificationType.qrScanned, - ); + if (added > 0) { + // The user was added via the profile scanned from the QR code so the scanned public key was used. + await twonlyDB.keyVerificationDao.addKeyVerification( + profile.userId.toInt(), + VerificationType.qrScanned, + ); - if (added > 0) { - if (await importSignalContactAndCreateRequest(userdata)) { if (profile.hasSecretVerificationToken()) { await KeyVerificationService.handleScannedVerificationToken( profile.userId.toInt(), @@ -160,10 +153,10 @@ Future addNewContactFromPublicProfile(PublicProfile profile) async { profile.secretVerificationToken, ); } - return true; } + return true; + } catch (e) { + Log.error('Failed to establish session and send contact request: $e'); return false; } - - return false; } diff --git a/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart b/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart index 797f7a56..4eba2188 100644 --- a/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart +++ b/lib/src/visual/views/camera/camera_preview_components/main_camera_controller.dart @@ -20,6 +20,7 @@ import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/utils/qr.utils.dart'; import 'package:twonly/src/visual/components/add_contact_dialog.comp.dart'; +import 'package:twonly/src/visual/components/alert.dialog.dart'; import 'package:twonly/src/visual/components/snackbar.dart'; import 'package:twonly/src/visual/components/verification_success_dialog.comp.dart'; import 'package:twonly/src/visual/helpers/screenshot.helper.dart'; @@ -555,12 +556,23 @@ class MainCameraController { profile.username, ); if (shouldRequest == true && context.mounted) { - showSnackbar( - context, - context.lang.requestedUserToastText(profile.username), - level: SnackbarLevel.success, - ); - await addNewContactFromPublicProfile(profile); + final success = await addNewContactFromPublicProfile(profile); + if (context.mounted) { + if (success) { + showSnackbar( + context, + context.lang.requestedUserToastText(profile.username), + level: SnackbarLevel.success, + ); + } else { + await showAlertDialog( + context, + context.lang.groupNetworkIssue, + context.lang.recoverErrorNoInternet, + customCancel: '', + ); + } + } } } continue; diff --git a/lib/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/twitter.parser.dart b/lib/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/twitter.parser.dart index f9050611..e7605c94 100644 --- a/lib/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/twitter.parser.dart +++ b/lib/src/visual/views/camera/share_image_editor_components/layers/link_preview/parser/twitter.parser.dart @@ -32,4 +32,8 @@ class TwitterParser with BaseMetaInfo { _url.startsWith('https://x.com/') && _url.contains('/status/') ? Vendor.twitterPosting : null; + + @override + String? get siteName => + vendor == Vendor.twitterPosting ? 'X (formerly Twitter)' : null; } diff --git a/lib/src/visual/views/chats/chat_list_components/empty_chat_list.comp.dart b/lib/src/visual/views/chats/chat_list_components/empty_chat_list.comp.dart index 9330061e..807cf1ac 100644 --- a/lib/src/visual/views/chats/chat_list_components/empty_chat_list.comp.dart +++ b/lib/src/visual/views/chats/chat_list_components/empty_chat_list.comp.dart @@ -4,9 +4,9 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart' show FaIcon, FontAwesomeIcons; import 'package:go_router/go_router.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/routes.keys.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/visual/components/profile_qr_code.comp.dart' show ProfileQrCodeComp; @@ -17,7 +17,7 @@ class EmptyChatListComp extends StatelessWidget { Future _shareProfile(BuildContext context) async { try { - final pubKey = await getUserPublicKey(); + final pubKey = await RustSignal.getUserPublicKey(); final params = ShareParams( text: 'https://me.twonly.eu/${userService.currentUser.username}#${base64Url.encode(pubKey)}', diff --git a/lib/src/visual/views/contact/add_new_contact.view.dart b/lib/src/visual/views/contact/add_new_contact.view.dart index fe6e33f1..f8ef22c6 100644 --- a/lib/src/visual/views/contact/add_new_contact.view.dart +++ b/lib/src/visual/views/contact/add_new_contact.view.dart @@ -8,13 +8,13 @@ import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/routes.keys.dart'; import 'package:twonly/src/database/daos/user_discovery.dao.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/api/utils.api.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/visual/components/alert.dialog.dart'; import 'package:twonly/src/visual/components/profile_qr_code.comp.dart'; @@ -94,7 +94,7 @@ class _SearchUsernameView extends State { } Future _shareProfile() async { - final pubKey = await getUserPublicKey(); + final pubKey = await RustSignal.getUserPublicKey(); final params = ShareParams( text: 'https://me.twonly.eu/${userService.currentUser.username}#${base64Url.encode(pubKey)}', diff --git a/lib/src/visual/views/contact/contact.view.dart b/lib/src/visual/views/contact/contact.view.dart index c4ec2d84..1dec2d8a 100644 --- a/lib/src/visual/views/contact/contact.view.dart +++ b/lib/src/visual/views/contact/contact.view.dart @@ -9,7 +9,6 @@ import 'package:twonly/src/constants/routes.keys.dart'; import 'package:twonly/src/database/daos/contacts.dao.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/visual/components/alert.dialog.dart'; import 'package:twonly/src/visual/components/avatar_icon.comp.dart'; @@ -123,7 +122,9 @@ class _ContactViewState extends State { Future handleReportUser(Contact contact) async { final reason = await showReportDialog(context, contact); if (reason == null) return; - final res = await rustApiResult(RustApi.reportUser(userId: contact.userId, reason: reason)); + final res = await rustApiResult( + RustApi.reportUser(userId: contact.userId, reason: reason), + ); if (!mounted) return; if (res.isSuccess) { showSnackbar( @@ -281,9 +282,10 @@ class _ContactViewState extends State { icon: FontAwesomeIcons.arrowsRotate, text: 'Update Connection to V2 (PQXDH)', onTap: () async { - final userData = await rustApiProtobuf(RustApi.getUserById(userId: contact.userId), decodeUserData); - if (userData != null) { - await processSignalUserData(userData); + try { + await RustApi.establishSignalSession( + contactId: contact.userId, + ); final updatedContact = await twonlyDB.contactsDao .getContactById(contact.userId); final isV2 = @@ -300,6 +302,13 @@ class _ContactViewState extends State { : SnackbarLevel.error, ); } + } catch (e) { + if (context.mounted) { + showSnackbar( + context, + 'Failed to update connection to V2: $e', + ); + } } }, ), diff --git a/lib/src/visual/views/groups/group.view.dart b/lib/src/visual/views/groups/group.view.dart index b7ef0f73..827a87c4 100644 --- a/lib/src/visual/views/groups/group.view.dart +++ b/lib/src/visual/views/groups/group.view.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/database/daos/contacts.dao.dart'; import 'package:twonly/src/database/tables/groups.table.dart'; @@ -135,21 +134,7 @@ class _GroupViewState extends State { } } - late bool success; - - if (_group!.isGroupAdmin) { - // Current user is a admin, to the state can be updated by the user him self. - final keyPair = IdentityKeyPair.fromSerialized( - _group!.myGroupPrivateKey!, - ); - success = !(await removeMemberFromGroup( - _group!, - keyPair.getPublicKey().serialize(), - userService.currentUser.userId, - )); - } else { - success = await leaveAsNonAdminFromGroup(_group!); - } + final success = await leaveGroup(_group!); if (!success) { if (mounted) { diff --git a/lib/src/visual/views/onboarding/register.view.dart b/lib/src/visual/views/onboarding/register.view.dart index 3801791d..a31d88ac 100644 --- a/lib/src/visual/views/onboarding/register.view.dart +++ b/lib/src/visual/views/onboarding/register.view.dart @@ -12,7 +12,6 @@ import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/routes.keys.dart'; import 'package:twonly/src/services/notifications/fcm.notifications.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; import 'package:twonly/src/services/user.service.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -99,8 +98,6 @@ class _RegisterViewState extends State { Log.info('The result of the POW is $proof'); - await createIfNotExistsSignalIdentity(); - var userId = 0; final res = await rustApiResult( diff --git a/lib/src/visual/views/public_profile.view.dart b/lib/src/visual/views/public_profile.view.dart index c9b588be..e518f006 100644 --- a/lib/src/visual/views/public_profile.view.dart +++ b/lib/src/visual/views/public_profile.view.dart @@ -6,9 +6,9 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/constants/routes.keys.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/visual/components/contact_request_badge.comp.dart'; import 'package:twonly/src/visual/components/profile_qr_code.comp.dart'; @@ -31,7 +31,7 @@ class _PublicProfileViewState extends State { } Future initAsync() async { - _publicKey = await getUserPublicKey(); + _publicKey = await RustSignal.getUserPublicKey(); if (mounted) setState(() {}); } diff --git a/lib/src/visual/views/settings/developer/automated_testing.view.dart b/lib/src/visual/views/settings/developer/automated_testing.view.dart index a30ac4cd..1b2d7d96 100644 --- a/lib/src/visual/views/settings/developer/automated_testing.view.dart +++ b/lib/src/visual/views/settings/developer/automated_testing.view.dart @@ -2,9 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:twonly/locator.dart'; -import 'package:twonly/src/services/signal/utils.signal.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -34,57 +32,6 @@ class _AutomatedTestingViewState extends State { ), body: ListView( children: [ - ListTile( - title: const Text('Trigger Signal Out-Of-Sync'), - onTap: () async { - final username = await showUserNameDialog(context); - if (username == null) return; - final contacts = await twonlyDB.contactsDao.getContactsByUsername( - username.toLowerCase(), - ); - if (contacts.length != 1) { - Log.error('No single user fund'); - return; - } - final userId = contacts.first.userId; - - final group = await twonlyDB.groupsDao.getDirectChat(userId); - if (group == null) { - Log.error('Target user must have a group!'); - return; - } - - final sessionStore = await getSignalStore(); - - // 1. Store a valid session - final originalSession = await sessionStore!.loadSession( - getSignalAddress(userId), - ); - final serializedSession = originalSession.serialize(); - - for (var i = 0; i < 10; i++) { - await RustApi.insertAndSendText( - groupId: group.groupId, - text: 'DesyncTest_1', - ); - } - - final corruptedSession = SessionRecord.fromSerialized( - serializedSession, - ); - await sessionStore.storeSession( - getSignalAddress(userId), - corruptedSession, - ); - - await RustApi.insertAndSendText( - groupId: group.groupId, - text: 'DesyncTest_2', - ); - - // The other client should res - }, - ), ListTile( title: const Text('Sending a lot of messages.'), subtitle: Text(lotsOfMessagesStatus), diff --git a/pubspec.lock b/pubspec.lock index 11acd7c5..4912c19c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -17,13 +17,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.68" - adaptive_number: - dependency: "direct main" - description: - path: "dependencies/adaptive_number" - relative: true - source: path - version: "1.0.0" analyzer: dependency: transitive description: @@ -411,13 +404,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" - ed25519_edwards: - dependency: "direct main" - description: - path: "dependencies/ed25519_edwards" - relative: true - source: path - version: "0.3.1" emoji_picker_flutter: dependency: "direct main" description: @@ -1190,13 +1176,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" - libsignal_protocol_dart: - dependency: "direct main" - description: - path: "dependencies/libsignal_protocol_dart" - relative: true - source: path - version: "0.8.0" lints: dependency: transitive description: @@ -1347,13 +1326,6 @@ packages: url: "https://pub.dev" source: hosted version: "9.3.0" - optional: - dependency: "direct main" - description: - path: "dependencies/optional" - relative: true - source: path - version: "6.1.0+1" package_config: dependency: transitive description: @@ -1529,13 +1501,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - pointycastle: - dependency: "direct main" - description: - path: "dependencies/pointycastle" - relative: true - source: path - version: "4.0.0" pool: dependency: transitive description: @@ -2139,13 +2104,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.1+1" - x25519: - dependency: "direct main" - description: - path: "dependencies/x25519" - relative: true - source: path - version: "0.1.1" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b094f043..b8abeaa3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -110,12 +110,6 @@ dependencies: image: ^4.9.2 introduction_screen: ^4.0.0 dots_indicator: ^4.0.1 - libsignal_protocol_dart: ^0.8.0 - adaptive_number: ^1.0.0 - ed25519_edwards: ^0.3.1 - optional: ^6.1.0+1 - pointycastle: ^4.0.0 - x25519: ^0.1.1 lottie: ^3.5.1 mutex: ^3.1.0 photo_view: ^0.15.0 @@ -176,18 +170,6 @@ dependency_overrides: path: ./dependencies/introduction_screen dots_indicator: path: ./dependencies/dots_indicator - libsignal_protocol_dart: - path: ./dependencies/libsignal_protocol_dart - adaptive_number: - path: ./dependencies/adaptive_number - ed25519_edwards: - path: ./dependencies/ed25519_edwards - optional: - path: ./dependencies/optional - pointycastle: - path: ./dependencies/pointycastle - x25519: - path: ./dependencies/x25519 lottie: path: ./dependencies/lottie mutex: diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 92b49797..ffa08812 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -6,6 +6,9 @@ edition = "2021" [lib] crate-type = ["cdylib", "staticlib", "rlib"] +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] } + [dependencies] flutter_rust_bridge = { version = "=2.12.0", features = ["chrono"] } thiserror = "2.0.18" @@ -49,14 +52,19 @@ rand08 = { version = "0.8.5", package = "rand" } rand = "0.9.4" uuid = { version = "1", features = ["v4"] } flate2 = "1" -reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = [ + "rustls-tls", +] } async-trait = "0.1.91" futures-util = "0.3.31" tokio-tungstenite = { version = "0.28.0", default-features = false, features = [ "connect", "rustls-tls-native-roots", ] } -rustls = { version = "0.23.43", default-features = false, features = ["ring", "std"] } +rustls = { version = "0.23.43", default-features = false, features = [ + "ring", + "std", +] } tokio-util = "0.7.16" bon = "3.9.3" stream-tungstenite = "0.6.1" diff --git a/rust/src/api/messages/incoming.rs b/rust/src/api/messages/incoming.rs index 86dc3e20..30eed7e2 100644 --- a/rust/src/api/messages/incoming.rs +++ b/rust/src/api/messages/incoming.rs @@ -18,18 +18,18 @@ mod verification; use crate::api::messages::content_type_kind; use crate::api::messages::incoming::messages::{ - decrypt_legacy_signal_with_error, ensure_contact_exists, handle_plaintext_content, - handle_sender_delivery_receipt, process_encrypted_or_queue_error, queue_decryption_error, - queue_sender_delivery_receipt, retransmit_queued_receipts, spawn_receipt_delivery, + ensure_contact_exists, handle_plaintext_content, handle_sender_delivery_receipt, + process_encrypted_or_queue_error, queue_decryption_error, queue_sender_delivery_receipt, + retransmit_queued_receipts, spawn_receipt_delivery, }; use crate::api::proto::client as proto; use crate::api::proto::server_to_client::NewMessage; use crate::api::proto::{client_to_server, server_to_client}; -use crate::bridge::callbacks::get_callbacks; use crate::context::Context; use crate::database::app::tables::{Contact, Group, Receipt}; use crate::error::{Result, TwonlyError}; use crate::sealed_sender::SealedSender; +use crate::services::contacts::ContactService; use client_to_server::response::{ok, Response}; use prost::Message as _; use proto::message::Type; @@ -210,39 +210,44 @@ pub(crate) async fn handle_decoded_server_message( handle_sender_delivery_receipt(&mut t, from_user_id, &message.receipt_id).await?; } Type::Ciphertext | Type::PrekeyBundle => { - let ciphertext = message.encrypted_content.ok_or_else(|| { - TwonlyError::Generic("legacy encrypted client message has no ciphertext".into()) - })?; - tracing::info!("Decrypting legacy signal message..."); - match decrypt_legacy_signal_with_error(from_user_id, ciphertext, message.r#type).await? - { - Ok(content) => { - tracing::info!("Decrypted successfully, processing..."); - sends_error_response = process_encrypted_or_queue_error( - ctx, - &mut t, + tracing::info!("Received legacy signal message; rejecting and upgrading session to v2"); + + let has_v2_session = { + let rust_database = ctx.rust_db.read().await.clone(); + sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM signal_sessions WHERE name = ? AND device_id = 1)", + from_user_id.to_string(), + ) + .fetch_one(&rust_database.pool) + .await? + != 0 + }; + + let is_v2_contact = { + let contact = Contact::get_contact_by_id(&mut t, from_user_id).await?; + contact.as_ref().is_some_and(|c| c.signal_version == "v2") + }; + + if !has_v2_session || !is_v2_contact { + if let Err(error) = ContactService::new(ctx) + .establish_signal_session(from_user_id, None) + .await + { + tracing::warn!( from_user_id, - &message.receipt_id, - content, - ) - .await? - .is_some(); - } - Err(error_type) => { - tracing::info!(error_type, "Decryption error"); - if error_type - == proto::plaintext_content::decryption_error_message::Type::PrekeyUnknown - as i32 - { - if let Ok(callbacks) = get_callbacks() { - (callbacks.api.resync_signal_session)(from_user_id).await; - } - } - queue_decryption_error(&mut t, from_user_id, &message.receipt_id, error_type) - .await?; - sends_error_response = true; + "failed to establish v2 signal session from server: {error}" + ); } + sqlx::query!( + "UPDATE contacts SET signal_version = 'v2' WHERE user_id = ?", + from_user_id, + ) + .execute(&mut *t) + .await?; } + + queue_decryption_error(&mut t, from_user_id, &message.receipt_id, 0).await?; + sends_error_response = true; } Type::CiphertextV2 => { let ciphertext = message.encrypted_content.ok_or_else(|| { diff --git a/rust/src/api/messages/incoming/messages.rs b/rust/src/api/messages/incoming/messages.rs index e5b278ba..c42b86e4 100644 --- a/rust/src/api/messages/incoming/messages.rs +++ b/rust/src/api/messages/incoming/messages.rs @@ -7,10 +7,9 @@ use super::handle_encrypted; use crate::api::proto::client::{self as proto}; use crate::api::Server; use crate::bridge::api::ServerResult; -use crate::bridge::callbacks::get_callbacks; use crate::context::Context; use crate::database::app::tables::{Contact, MediaFile, NewReceipt, Receipt}; -use crate::error::{twonly_error, Result, TwonlyError}; +use crate::error::{Result, TwonlyError}; use crate::services::contacts::ContactService; use crate::utils::new_uuid_v4; use prost::Message as ProstMessage; @@ -31,16 +30,10 @@ pub(crate) async fn queue_encrypted_content( content: proto::EncryptedContent, contact_will_send_receipt: bool, ) -> Result { - let Some(contact) = Contact::get_contact_by_id(t, target_user_id).await? else { - return Err(twonly_error!("missing contact")); - }; + Contact::ensure_exists(t, target_user_id).await?; let message = proto::Message { - r#type: if contact.signal_version == "v2" { - proto::message::Type::CiphertextV2 as i32 - } else { - proto::message::Type::Ciphertext as i32 - }, + r#type: proto::message::Type::CiphertextV2 as i32, receipt_id: String::new(), encrypted_content: Some(content.encode_to_vec()), plaintext_content: None, @@ -97,17 +90,8 @@ pub(crate) async fn process_encrypted_or_queue_error( ..Default::default() }; - let signal_version = Contact::get_contact_by_id(t, from_user_id) - .await? - .map(|c| c.signal_version) - .unwrap_or_else(|| "v2".to_string()); - let response = proto::Message { - r#type: if signal_version == "v2" { - proto::message::Type::CiphertextV2 as i32 - } else { - proto::message::Type::Ciphertext as i32 - }, + r#type: proto::message::Type::CiphertextV2 as i32, receipt_id: String::new(), encrypted_content: Some(response_content.encode_to_vec()), plaintext_content: None, @@ -298,7 +282,7 @@ async fn encrypt_v2_with_session_recovery( ); ContactService::new(ctx) - .establish_signal_session(contact_id) + .establish_signal_session(contact_id, None) .await?; encrypt(plaintext).await @@ -307,6 +291,84 @@ async fn encrypt_v2_with_session_recovery( } } +pub(crate) struct PreparedQueuedReceipt { + pub contact_id: i64, + pub message_id: Option, + pub contact_will_sends_receipt: i64, + pub account_deleted: i64, + pub payload: Vec, +} + +pub(crate) async fn prepare_queued_receipt_details( + ctx: &Arc, + receipt_id: &str, +) -> Result> { + let app_db = ctx.app_db.read().await.clone(); + let row = sqlx::query!( + r#" + SELECT r.contact_id, r.message, r.message_id, r.contact_will_sends_receipt, + r.retry_count, c.account_deleted, c.signal_version + FROM receipts r + JOIN contacts c ON c.user_id = r.contact_id + WHERE r.receipt_id = ? + "#, + receipt_id, + ) + .fetch_optional(&app_db.pool) + .await?; + + let Some(row) = row else { + return Ok(None); + }; + + let mut message = proto::Message::decode(row.message.as_slice()) + .map_err(|error| TwonlyError::Generic(format!("invalid queued message: {error}")))?; + message.receipt_id = receipt_id.to_owned(); + + let message_type = proto::message::Type::try_from(message.r#type) + .map_err(|_| TwonlyError::Generic("queued message has invalid type".into()))?; + + let is_encrypted = matches!( + message_type, + proto::message::Type::Ciphertext + | proto::message::Type::PrekeyBundle + | proto::message::Type::CiphertextV2 + ); + + if is_encrypted { + if row.signal_version != "v2" { + ContactService::new(ctx) + .establish_signal_session(row.contact_id, None) + .await?; + } + + let plaintext = message.encrypted_content.take().ok_or_else(|| { + TwonlyError::Generic("queued encrypted message has no content".into()) + })?; + + message.encrypted_content = + Some(encrypt_v2_with_session_recovery(ctx, row.contact_id, plaintext).await?); + message.r#type = proto::message::Type::CiphertextV2 as i32; + } + + Ok(Some(PreparedQueuedReceipt { + contact_id: row.contact_id, + message_id: row.message_id, + contact_will_sends_receipt: row.contact_will_sends_receipt, + account_deleted: row.account_deleted, + payload: message.encode_to_vec(), + })) +} + +pub(crate) async fn prepare_queued_receipt( + ctx: &Arc, + receipt_id: &str, +) -> Result>> { + Ok(prepare_queued_receipt_details(ctx, receipt_id) + .await? + .map(|receipt| receipt.payload)) +} + pub(crate) async fn send_queued_receipt(ctx: &Arc, receipt_id: &str) -> Result<()> { #[cfg(not(debug_assertions))] { @@ -324,56 +386,17 @@ pub(crate) async fn send_queued_receipt(ctx: &Arc, receipt_id: &str) -> } let app_db = ctx.app_db.read().await.clone(); - let row = sqlx::query!( - r#" - SELECT r.contact_id, r.message, r.message_id, r.contact_will_sends_receipt, - r.retry_count, c.account_deleted - FROM receipts r - JOIN contacts c ON c.user_id = r.contact_id - WHERE r.receipt_id = ? - "#, - receipt_id, - ) - .fetch_optional(&app_db.pool) - .await?; - - let Some(row) = row else { + let Some(receipt) = prepare_queued_receipt_details(ctx, receipt_id).await? else { return Ok(()); }; - if row.account_deleted != 0 { + if receipt.account_deleted != 0 { Receipt::delete(&app_db.pool, receipt_id).await?; app_db.notify_committed(["receipts"]); return Ok(()); } - let mut message = proto::Message::decode(row.message.as_slice())?; - message.receipt_id = receipt_id.to_owned(); - - let message_type = proto::message::Type::try_from(message.r#type)?; - - match message_type { - proto::message::Type::Ciphertext | proto::message::Type::PrekeyBundle => { - let plaintext = message.encrypted_content.take().ok_or_else(|| { - TwonlyError::Generic("queued legacy message has no plaintext".into()) - })?; - let (ciphertext, encrypted_type) = - encrypt_legacy_signal(row.contact_id, plaintext).await?; - message.encrypted_content = Some(ciphertext); - message.r#type = encrypted_type; - } - proto::message::Type::CiphertextV2 => { - let plaintext = message - .encrypted_content - .take() - .ok_or_else(|| TwonlyError::Generic("queued V2 message has no plaintext".into()))?; - message.encrypted_content = - Some(encrypt_v2_with_session_recovery(ctx, row.contact_id, plaintext).await?); - } - _ => {} - } - - match Server::send_text_message(ctx, row.contact_id, message.encode_to_vec()).await? { + match Server::send_text_message(ctx, receipt.contact_id, receipt.payload).await? { ServerResult::Ok(()) => {} ServerResult::ErrorCode(code) => { return Err(TwonlyError::Generic(format!( @@ -384,7 +407,7 @@ pub(crate) async fn send_queued_receipt(ctx: &Arc, receipt_id: &str) -> } let mut t = app_db.pool.begin().await?; - if let Some(message_id) = row.message_id { + if let Some(message_id) = receipt.message_id { sqlx::query!( r#" INSERT INTO message_actions(message_id, contact_id, type) @@ -393,12 +416,12 @@ pub(crate) async fn send_queued_receipt(ctx: &Arc, receipt_id: &str) -> DO UPDATE SET action_at = CAST(strftime('%s', 'now') AS INTEGER) "#, message_id, - row.contact_id, + receipt.contact_id, ) .execute(&mut *t) .await?; } - if row.contact_will_sends_receipt == 0 { + if receipt.contact_will_sends_receipt == 0 { Receipt::delete(&mut *t, receipt_id).await?; } else { sqlx::query!( @@ -420,52 +443,6 @@ pub(crate) async fn send_queued_receipt(ctx: &Arc, receipt_id: &str) -> Ok(()) } -pub(crate) async fn prepare_queued_receipt( - ctx: &Arc, - receipt_id: &str, -) -> Result>> { - let database = ctx.app_db.read().await.clone(); - let row = sqlx::query!( - r#"SELECT contact_id, message, message_id, retry_count - FROM receipts WHERE receipt_id = ?"#, - receipt_id, - ) - .fetch_optional(&database.pool) - .await?; - let Some(row) = row else { return Ok(None) }; - let mut message = proto::Message::decode(row.message.as_slice()) - .map_err(|error| TwonlyError::Generic(format!("invalid queued message: {error}")))?; - message.receipt_id = receipt_id.to_owned(); - - match proto::message::Type::try_from(message.r#type) - .map_err(|_| TwonlyError::Generic("queued message has invalid type".into()))? - { - proto::message::Type::Ciphertext => { - let plaintext = message - .encrypted_content - .take() - .ok_or_else(|| TwonlyError::Generic("queued message has no content".into()))?; - - let (ciphertext, message_type) = - encrypt_legacy_signal(row.contact_id, plaintext).await?; - - message.encrypted_content = Some(ciphertext); - message.r#type = message_type; - } - proto::message::Type::CiphertextV2 => { - let plaintext = message - .encrypted_content - .take() - .ok_or_else(|| TwonlyError::Generic("queued message has no content".into()))?; - - message.encrypted_content = - Some(encrypt_v2_with_session_recovery(ctx, row.contact_id, plaintext).await?); - } - _ => {} - } - Ok(Some(message.encode_to_vec())) -} - pub async fn retransmit_queued_receipts(ctx: &Arc) -> Result<()> { let database = ctx.app_db.read().await.clone(); let receipt_ids = sqlx::query_scalar!( @@ -490,27 +467,6 @@ pub async fn retransmit_queued_receipts(ctx: &Arc) -> Result<()> { Ok(()) } -pub(crate) async fn decrypt_legacy_signal_with_error( - from_user_id: i64, - ciphertext: Vec, - message_type: i32, -) -> Result> { - let callbacks = get_callbacks()?; - let decrypted = (callbacks.legacy_signal.decrypt)(from_user_id, ciphertext, message_type).await; - - let Some(plaintext) = decrypted.plaintext else { - return Ok(Err(decrypted.decryption_error_type.unwrap_or(0))); - }; - - proto::EncryptedContent::decode(plaintext.as_slice()) - .map(Ok) - .map_err(|error| { - TwonlyError::Generic(format!( - "Flutter returned invalid legacy Signal plaintext: {error}" - )) - }) -} - pub(crate) async fn queue_decryption_error( tr: &mut Transaction<'_, Sqlite>, from_user_id: i64, @@ -536,28 +492,6 @@ pub(crate) async fn queue_decryption_error( Ok(()) } -pub(crate) async fn encrypt_legacy_signal( - target_user_id: i64, - plaintext: Vec, -) -> Result<(Vec, i32)> { - let callbacks = get_callbacks()?; - let encrypted = (callbacks.legacy_signal.encrypt)(target_user_id, plaintext) - .await - .ok_or_else(|| TwonlyError::Generic("Flutter legacy Signal encryption failed".into()))?; - if !is_legacy_signal_type(encrypted.message_type) { - return Err(TwonlyError::Generic(format!( - "Flutter returned non-legacy Signal message type {}", - encrypted.message_type - ))); - } - Ok((encrypted.ciphertext, encrypted.message_type)) -} - -fn is_legacy_signal_type(message_type: i32) -> bool { - use proto::message::Type; - message_type == Type::Ciphertext as i32 || message_type == Type::PrekeyBundle as i32 -} - pub(crate) async fn handle_sender_delivery_receipt( transaction: &mut Transaction<'_, Sqlite>, from_user_id: i64, diff --git a/rust/src/api/proto/api/websocket/client_to_server.proto b/rust/src/api/proto/api/websocket/client_to_server.proto index ebdb8e69..b528e833 100644 --- a/rust/src/api/proto/api/websocket/client_to_server.proto +++ b/rust/src/api/proto/api/websocket/client_to_server.proto @@ -24,15 +24,38 @@ message Handshake { message Register { string username = 1; optional string invite_code = 2; - bytes public_identity_key = 3; - bytes signed_prekey = 4; - bytes signed_prekey_signature = 5; - int64 signed_prekey_id = 6; - int64 registration_id = 7; + // Deprecated legacy Signal fields. The server ignores these fields; they + // remain allocated only to avoid reusing their wire tags. + optional bytes public_identity_key = 3; + optional bytes signed_prekey = 4; + optional bytes signed_prekey_signature = 5; + optional int64 signed_prekey_id = 6; + optional int64 registration_id = 7; bool is_ios = 8; string lang_code = 9; int64 proof_of_work = 10; optional bytes login_token = 11; + optional InitialPqcKeys initial_pqc_keys = 12; + } + + message InitialPqcKeys { + message PqcPreKey { + int64 ecc_pre_key_id = 1; + bytes ecc_pre_key = 2; + int64 kyber_pre_key_id = 3; + bytes kyber_pre_key = 4; + bytes kyber_pre_key_signature = 5; + } + + bytes public_identity_key = 1; + int64 registration_id = 2; + int64 ecc_signed_prekey_id = 3; + bytes ecc_signed_prekey = 4; + bytes ecc_signed_prekey_signature = 5; + int64 kyber_signed_prekey_id = 6; + bytes kyber_signed_prekey = 7; + bytes kyber_signed_prekey_signature = 8; + repeated PqcPreKey prekeys = 9; } message GetAuthChallenge {} @@ -159,6 +182,10 @@ message ApplicationData { bytes kyber_signed_prekey = 5; bytes kyber_signed_prekey_signature = 6; repeated PqcPreKey prekeys = 7; + // Required when uploading keys for the first time after a keyless + // registration. Optional for later key refreshes. + optional bytes public_identity_key = 8; + optional int64 registration_id = 9; } message DownloadDone { diff --git a/rust/src/api/runtime/auth.rs b/rust/src/api/runtime/auth.rs index 64268419..6767a441 100644 --- a/rust/src/api/runtime/auth.rs +++ b/rust/src/api/runtime/auth.rs @@ -25,8 +25,6 @@ pub(crate) struct ApiAuthHandshaker { pub context: Arc, pub api_client: Weak, pub is_authenticated: Arc, - pub can_use_login_token_for_auth: bool, - pub legacy_user_app_version: i64, pub in_background: bool, pub events: broadcast::Sender, } @@ -308,21 +306,37 @@ impl Handshaker for ApiAuthHandshaker { receiver: &mut dyn HandshakeReceiver, _context: &ConnectionContext, ) -> std::result::Result<(), HandshakeError> { - let user_id = match self.context.user_id().await { - Ok(id) => id, - Err(e) => { - tracing::info!("ApiAuthHandshaker skipped: user_id missing ({})", e); + let user = match UserConfig::load_from(&self.context) + .map_err(|e| HandshakeError::Protocol(e.to_string()))? + { + Some(u) => u, + None => { + tracing::info!("ApiAuthHandshaker skipped: user config is not present"); return Ok(()); } }; + let user_id = self + .context + .key_manager + .lock() + .await + .user_id + .filter(|user_id| *user_id > 0); + let Some(user_id) = user_id else { + tracing::info!("ApiAuthHandshaker skipped: KeyManager has no registered user ID"); + return Ok(()); + }; + let can_use_login_token = user.can_use_login_token_for_auth; + let app_version = user.app_version; + let _ = self.events.send(ApiEvent { kind: ApiEventKind::ConnectionStateChanged, state: Some(ApiConnectionState::Authenticating), message: None, }); - if self.can_use_login_token_for_auth { + if can_use_login_token { match self .authenticate_with_login_token(sender, receiver, user_id) .await @@ -337,7 +351,7 @@ impl Handshaker for ApiAuthHandshaker { return Err(HandshakeError::Protocol(error.to_string())); } } - } else if self.legacy_user_app_version >= 62 + } else if app_version >= 62 && self .authenticate_with_legacy_token(sender, receiver, user_id) .await @@ -350,10 +364,10 @@ impl Handshaker for ApiAuthHandshaker { tracing::error!( "ApiAuthHandshaker: no auth method succeeded. legacy_app_version={}", - self.legacy_user_app_version + app_version ); - if self.legacy_user_app_version < 62 { + if app_version < 62 { return Err(HandshakeError::Protocol( "legacy user version is too old for API authentication".into(), )); diff --git a/rust/src/api/runtime/client.rs b/rust/src/api/runtime/client.rs index 81f4cbf8..3eb21c1f 100644 --- a/rust/src/api/runtime/client.rs +++ b/rust/src/api/runtime/client.rs @@ -92,8 +92,6 @@ impl ApiClient { context, api_client: Arc::downgrade(self), is_authenticated: self.is_authenticated.clone(), - can_use_login_token_for_auth: self.config.can_use_login_token_for_auth, - legacy_user_app_version: self.config.legacy_user_app_version, in_background: self.in_background.load(Ordering::Acquire), events: self.events.clone(), }; diff --git a/rust/src/api/runtime/request.rs b/rust/src/api/runtime/request.rs index 43d56918..7baee67c 100644 --- a/rust/src/api/runtime/request.rs +++ b/rust/src/api/runtime/request.rs @@ -16,6 +16,7 @@ use std::pin::Pin; use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; +use stream_tungstenite::error::SendError; use tokio::sync::oneshot; fn call_handle_server_message( @@ -80,15 +81,18 @@ impl ApiClient { pub(crate) async fn send(self: &Arc, bytes: Vec) -> Result<()> { let ws_client = self.ws_client.lock().await.clone(); if let Some(client) = ws_client { - client - .send_async( - stream_tungstenite::tokio_tungstenite::tungstenite::Message::Binary( - bytes.into(), - ), - ) - .await - .map_err(|e| TwonlyError::Generic(format!("send error: {:?}", e)))?; - Ok(()) + let msg = + stream_tungstenite::tokio_tungstenite::tungstenite::Message::Binary(bytes.into()); + let start = tokio::time::Instant::now(); + loop { + match client.send_async(msg.clone()).await { + Ok(_) => return Ok(()), + Err(SendError::NotConnected) if start.elapsed() < Duration::from_secs(10) => { + tokio::time::sleep(Duration::from_millis(50)).await; + } + Err(e) => return Err(TwonlyError::Generic(format!("send error: {:?}", e))), + } + } } else { Err(TwonlyError::Generic("Not connected".into())) } @@ -147,14 +151,32 @@ impl ApiClient { let ws_client = self.ws_client.lock().await.clone(); if let Some(client) = ws_client { - client - .send_async( - stream_tungstenite::tokio_tungstenite::tungstenite::Message::Binary( - request.encode_to_vec().into(), - ), - ) - .await - .map_err(|e| TwonlyError::Generic(format!("send error: {:?}", e)))?; + let msg = stream_tungstenite::tokio_tungstenite::tungstenite::Message::Binary( + request.encode_to_vec().into(), + ); + let start = tokio::time::Instant::now(); + let mut sent = false; + while start.elapsed() < Duration::from_secs(10) { + match client.send_async(msg.clone()).await { + Ok(_) => { + sent = true; + break; + } + Err(SendError::NotConnected) => { + tokio::time::sleep(Duration::from_millis(50)).await; + } + Err(e) => { + self.pending.lock().await.remove(&sequence); + return Err(TwonlyError::Generic(format!("send error: {:?}", e))); + } + } + } + if !sent { + self.pending.lock().await.remove(&sequence); + return Err(TwonlyError::Generic( + "send error: NotConnected (timeout)".into(), + )); + } } else { self.pending.lock().await.remove(&sequence); return Err(TwonlyError::Generic("Not connected".into())); diff --git a/rust/src/api/server/account.rs b/rust/src/api/server/account.rs index eaccf16b..91f09847 100644 --- a/rust/src/api/server/account.rs +++ b/rust/src/api/server/account.rs @@ -10,7 +10,6 @@ use crate::api::runtime::helpers::decode_ok_value; use crate::bridge::api::ServerResult; use crate::context::Context; use crate::error::{Result, TwonlyError}; -use libsignal_protocol::{GenericSignedPreKey, IdentityKeyPair, SignedPreKeyRecord}; use std::sync::Arc; impl Server { @@ -21,44 +20,69 @@ impl Server { lang_code: String, is_ios: bool, ) -> Result> { - let key_manager = ctx.key_manager.lock().await; + let mut key_manager = ctx.key_manager.lock().await; + if key_manager.signal_identity.is_none() { + let identity = crate::keys::SignalIdentityKey::generate()?; + key_manager.signal_identity = Some(identity); + key_manager.store_to_keychain(&ctx.secure_storage)?; + } let identity = key_manager .signal_identity .as_ref() .ok_or(TwonlyError::SignalIdentityNotFound)?; - let identity_pair = - IdentityKeyPair::try_from(identity.identity_key_pair_structure.as_slice()) - .map_err(|error| TwonlyError::Signal(error.to_string()))?; - let (&signed_prekey_id, record) = identity - .pre_key_store - .iter() - .min_by_key(|(id, _)| *id) - .ok_or_else(|| { - TwonlyError::Generic("Signal signed-prekey store is empty".into()) - })?; - let signed_prekey = SignedPreKeyRecord::deserialize(record) - .map_err(|error| TwonlyError::Signal(error.to_string()))?; + + let identity_key_pair_structure = identity.identity_key_pair_structure.clone(); + let registration_id = identity.registration_id; let login_token = key_manager.main_key.get_login_token().to_vec(); + drop(key_manager); + + let database = ctx.rust_db.read().await.clone(); + let registration_engine = crate::signal::engine::RustSignalEngine::new_with_pool( + database.pool.clone(), + identity_key_pair_structure.clone(), + registration_id as u32, + "pending-registration".to_string(), + )?; + let bundle = registration_engine.generate_bundle().await?; + let prekeys = registration_engine + .generate_pqc_prekeys() + .await? + .into_iter() + .map( + |key| client_to_server::handshake::initial_pqc_keys::PqcPreKey { + ecc_pre_key_id: i64::from(key.ecc_pre_key_id), + ecc_pre_key: key.ecc_pre_key, + kyber_pre_key_id: i64::from(key.kyber_pre_key_id), + kyber_pre_key: key.kyber_pre_key, + kyber_pre_key_signature: key.kyber_pre_key_signature, + }, + ) + .collect(); + let initial_pqc_keys = client_to_server::handshake::InitialPqcKeys { + public_identity_key: bundle.identity_key, + registration_id: i64::from(bundle.registration_id), + ecc_signed_prekey_id: i64::from(bundle.signed_pre_key_id), + ecc_signed_prekey: bundle.signed_pre_key_public, + ecc_signed_prekey_signature: bundle.signed_pre_key_signature, + kyber_signed_prekey_id: i64::from(bundle.kyber_pre_key_id), + kyber_signed_prekey: bundle.kyber_pre_key_public, + kyber_signed_prekey_signature: bundle.kyber_pre_key_signature, + prekeys, + }; let register = client_to_server::handshake::Register { username, invite_code: None, - public_identity_key: identity_pair.identity_key().serialize().to_vec(), - signed_prekey: signed_prekey - .public_key() - .map_err(|error| TwonlyError::Signal(error.to_string()))? - .serialize() - .to_vec(), - signed_prekey_signature: signed_prekey - .signature() - .map_err(|error| TwonlyError::Signal(error.to_string()))?, - signed_prekey_id, - registration_id: identity.registration_id, + public_identity_key: None, + signed_prekey: None, + signed_prekey_signature: None, + signed_prekey_id: None, + registration_id: None, is_ios, lang_code, proof_of_work, login_token: Some(login_token), + initial_pqc_keys: Some(initial_pqc_keys), }; - drop(key_manager); let bytes = Self::handshake( ctx, @@ -66,10 +90,43 @@ impl Server { ) .await?; - decode_ok_value(bytes, |value| match value { + let res = decode_ok_value(bytes, |value| match value { ResponseOk::Userid(id) => Some(id), _ => None, - }) + })?; + + if let ServerResult::Ok(user_id) = res { + let mut key_manager = ctx.key_manager.lock().await; + key_manager.user_id = Some(user_id); + key_manager.store_to_keychain(&ctx.secure_storage)?; + let signal_identity = key_manager.signal_identity.as_ref().map(|identity| { + ( + identity.identity_key_pair_structure.clone(), + identity.registration_id, + ) + }); + drop(key_manager); + + if let Some((identity_key_pair_structure, registration_id)) = signal_identity { + let database = ctx.rust_db.read().await.clone(); + *ctx.signal_engine.lock().await = + Some(crate::signal::engine::RustSignalEngine::new_with_pool( + database.pool.clone(), + identity_key_pair_structure, + registration_id as u32, + user_id.to_string(), + )?); + } + + let now = crate::utils::current_time().with_timezone(&chrono::Utc); + let _ = crate::user_config::UserConfig::update(ctx, |config| { + config.signal_last_signed_pre_key_updated = Some(now); + config.signal_last_pqc_pre_keys_uploaded = Some(now); + }); + let _ = crate::api::ApiRuntime::reload_configuration(ctx).await; + } + + Ok(res) } pub async fn get_proof_of_work(ctx: &Arc) -> Result> { diff --git a/rust/src/api/server/prekeys.rs b/rust/src/api/server/prekeys.rs index b8338646..ec7d8b14 100644 --- a/rust/src/api/server/prekeys.rs +++ b/rust/src/api/server/prekeys.rs @@ -26,17 +26,33 @@ impl Server { .ok_or(crate::error::TwonlyError::SignalIdentityNotFound)? .generate_bundle() .await?; + let prekeys = engine + .as_ref() + .ok_or(crate::error::TwonlyError::SignalIdentityNotFound)? + .generate_pqc_prekeys() + .await? + .into_iter() + .map(|key| PqcPreKeyInput { + ecc_pre_key_id: i64::from(key.ecc_pre_key_id), + ecc_pre_key: key.ecc_pre_key, + kyber_pre_key_id: i64::from(key.kyber_pre_key_id), + kyber_pre_key: key.kyber_pre_key, + kyber_pre_key_signature: key.kyber_pre_key_signature, + }) + .collect(); drop(engine); Self::upload_pqc_pre_keys( ctx, + bundle.identity_key, + i64::from(bundle.registration_id), i64::from(bundle.signed_pre_key_id), bundle.signed_pre_key_public, bundle.signed_pre_key_signature, i64::from(bundle.kyber_pre_key_id), bundle.kyber_pre_key_public, bundle.kyber_pre_key_signature, - Vec::new(), + prekeys, ) .await } @@ -63,6 +79,8 @@ impl Server { #[allow(clippy::too_many_arguments)] pub async fn upload_pqc_pre_keys( ctx: &Arc, + public_identity_key: Vec, + registration_id: i64, ecc_signed_prekey_id: i64, ecc_signed_prekey: Vec, ecc_signed_prekey_signature: Vec, @@ -92,6 +110,8 @@ impl Server { kyber_signed_prekey, kyber_signed_prekey_signature, prekeys, + public_identity_key: Some(public_identity_key), + registration_id: Some(registration_id), }, ), ) diff --git a/rust/src/api/server/transport.rs b/rust/src/api/server/transport.rs index 280a88c5..1c800267 100644 --- a/rust/src/api/server/transport.rs +++ b/rust/src/api/server/transport.rs @@ -73,6 +73,13 @@ impl Server { ctx: &Arc, value: client_to_server::handshake::Handshake, ) -> Result> { + let client = ApiRuntime::client(ctx).await?; + if client + .is_authenticated + .load(std::sync::atomic::Ordering::Acquire) + { + client.close().await; + } ApiRuntime::request_binary(ctx, Self::handshake_request(value)).await } } diff --git a/rust/src/backup/backup_identity.rs b/rust/src/backup/backup_identity.rs index d73ab0c5..43df5b06 100644 --- a/rust/src/backup/backup_identity.rs +++ b/rust/src/backup/backup_identity.rs @@ -18,7 +18,7 @@ impl BackupIdentity { return Err(TwonlyError::Generic("No backup password".into())); }; - let serialized_bytes = postcard::to_allocvec(key_manager)?; + let serialized_bytes = key_manager.to_bytes()?; let key = aes_gcm::Key::::from_slice(&keys.encryption_key); let cipher = Aes256Gcm::new(key); @@ -55,7 +55,7 @@ impl BackupIdentity { let decrypted_bytes = cipher.decrypt(nonce, ciphertext)?; - let key_manager: KeyManager = postcard::from_bytes(&decrypted_bytes)?; + let key_manager = KeyManager::from_bytes(&decrypted_bytes)?; key_manager.store_to_keychain(secure_storage)?; @@ -69,6 +69,7 @@ mod tests { #[test] fn test_backup_encryption_decryption() { + SecureStorage::init().unwrap(); let secure_storage = SecureStorage::new("testing"); let mut key_manager = KeyManager::generate().unwrap(); let password = "my_secure_password"; diff --git a/rust/src/bridge/api.rs b/rust/src/bridge/api.rs index aafc3c23..332efe34 100644 --- a/rust/src/bridge/api.rs +++ b/rust/src/bridge/api.rs @@ -3,16 +3,17 @@ * */ -use crate::api::messages::incoming::messages; -use crate::api::proto::server_to_client::response::ok::Ok as ResponseOk; -use crate::api::runtime::helpers::decode_ok_value; use crate::api::ApiRuntime; pub use crate::api::PqcPreKeyInput; use crate::api::Server; +use crate::api::messages::incoming::messages; +use crate::api::proto::server_to_client::response::ok::Ok as ResponseOk; +use crate::api::runtime::helpers::decode_ok_value; use crate::context::Context; use crate::error::{Result, TwonlyError}; use crate::frb_generated::StreamSink; use crate::services::contacts::ContactService; +use crate::services::messages::MessageService; use crate::user_config::UserConfig; use flutter_rust_bridge::frb; use prost::Message; @@ -432,6 +433,8 @@ impl RustApi { } #[allow(clippy::too_many_arguments)] pub async fn upload_pqc_pre_keys( + public_identity_key: Vec, + registration_id: i64, ecc_signed_prekey_id: i64, ecc_signed_prekey: Vec, ecc_signed_prekey_signature: Vec, @@ -443,6 +446,8 @@ impl RustApi { let ctx = Context::get_static()?; Server::upload_pqc_pre_keys( ctx, + public_identity_key, + registration_id, ecc_signed_prekey_id, ecc_signed_prekey, ecc_signed_prekey_signature, @@ -465,9 +470,9 @@ impl RustApi { contact_id: i64, content: Vec, message_id: Option, - only_send_if_no_receipts_are_open: bool, - only_return_encrypted_data: bool, - blocking: bool, + only_send_if_no_receipts_are_open: Option, + only_return_encrypted_data: Option, + blocking: Option, ) -> Result>> { let ctx = Context::get_static()?; crate::api::messages::outgoing::send_c2c_message_to_contact() @@ -475,9 +480,9 @@ impl RustApi { .contact_id(contact_id) .encrypted_content(content) .maybe_message_id(message_id) - .only_send_if_no_receipts_are_open(only_send_if_no_receipts_are_open) - .only_return_encrypted_data(only_return_encrypted_data) - .blocking(blocking) + .only_send_if_no_receipts_are_open(only_send_if_no_receipts_are_open.unwrap_or(false)) + .only_return_encrypted_data(only_return_encrypted_data.unwrap_or(false)) + .blocking(blocking.unwrap_or(false)) .call() .await .map_err(Into::into) @@ -487,7 +492,7 @@ impl RustApi { group_id: String, content: Vec, message_id: Option, - only_send_if_no_receipts_are_open: bool, + only_send_if_no_receipts_are_open: Option, ) -> Result<()> { let ctx = Context::get_static()?; crate::services::messages::MessageService::new(ctx) @@ -495,7 +500,7 @@ impl RustApi { group_id, content, message_id, - only_send_if_no_receipts_are_open, + only_send_if_no_receipts_are_open.unwrap_or(false), ) .await } @@ -571,15 +576,23 @@ impl RustApi { pub async fn notify_messages_opened(contact_id: i64, message_ids: Vec) -> Result<()> { let ctx = Context::get_static()?; - crate::services::messages::MessageService::new(ctx) + MessageService::new(ctx) .notify_opened(contact_id, message_ids) .await } pub async fn send_contact_profile(contact_id: i64) -> Result<()> { let ctx = Context::get_static()?; - crate::services::contacts::ContactService::new(ctx) - .send_profile(contact_id) + ContactService::new(ctx).send_profile(contact_id).await + } + + pub async fn establish_signal_session( + contact_id: i64, + expected_public_key: Option>, + ) -> Result<()> { + let ctx = Context::get_static()?; + ContactService::new(ctx) + .establish_signal_session(contact_id, expected_public_key) .await } } diff --git a/rust/src/bridge/callbacks.rs b/rust/src/bridge/callbacks.rs index 27dd7f06..9132b2c6 100644 --- a/rust/src/bridge/callbacks.rs +++ b/rust/src/bridge/callbacks.rs @@ -20,33 +20,13 @@ tokio::task_local! { pub(crate) static FLUTTER_CALLBACKS: std::sync::RwLock>> = std::sync::RwLock::new(None); -#[derive(Clone, Debug)] -pub struct LegacySignalDecryptResult { - /// Serialized `EncryptedContent` when legacy Signal decryption succeeded. - pub plaintext: Option>, - /// Serialized protobuf enum value for `DecryptionErrorMessage.Type`. - pub decryption_error_type: Option, -} - -#[derive(Clone, Debug)] -pub struct LegacySignalEncryptResult { - pub ciphertext: Vec, - /// `Message.Type.CIPHERTEXT` or `Message.Type.PREKEY_BUNDLE`. - pub message_type: i32, -} - // This will also generate the function init_flutter_callbacks which MUST be called from Flutter to initialize the callbacks callback_generator! { FlutterCallbacks { Logging logging { get_stream_sink: () => StreamSink }, - LegacySignal legacy_signal { - decrypt: (i64, Vec, i32) => LegacySignalDecryptResult, - encrypt: (i64, Vec) => Option - }, Api api { - resync_signal_session: (i64) => (), media_action: (String, String, i64, String) => (), verification_proof: (i64, Vec) => (), create_push_avatars: (i64) => (), diff --git a/rust/src/bridge/wrapper/key_manager.rs b/rust/src/bridge/wrapper/key_manager.rs index dea6cb6f..d250a9d0 100644 --- a/rust/src/bridge/wrapper/key_manager.rs +++ b/rust/src/bridge/wrapper/key_manager.rs @@ -3,8 +3,6 @@ * */ -use std::collections::HashMap; - use crate::bridge::get_twonly_flutter; use crate::error::{Result, TwonlyError}; use crate::keys::SignalIdentityKey; @@ -35,7 +33,10 @@ impl RustKeyManager { match RustSignalEngine::new(user_id.to_string()).await { Ok(engine) => *guard = Some(engine), Err(e) => { - tracing::warn!("Failed to initialize Signal engine on set_user_id: {}. It will be initialized later.", e); + tracing::warn!( + "Failed to initialize Signal engine on set_user_id: {}. It will be initialized later.", + e + ); *guard = None; } } @@ -46,7 +47,6 @@ impl RustKeyManager { pub async fn import_signal_identity( identity_key_pair_structure: Vec, registration_id: i64, - signed_pre_key_store: HashMap>, ) -> Result<()> { let ctx = get_twonly_flutter()?; let user_id = { @@ -54,7 +54,6 @@ impl RustKeyManager { key_manager.signal_identity = Some(SignalIdentityKey { identity_key_pair_structure, registration_id, - pre_key_store: signed_pre_key_store, }); key_manager.store_to_keychain(&ctx.secure_storage)?; key_manager.user_id @@ -90,55 +89,6 @@ impl RustKeyManager { } } - pub async fn load_signed_prekey(signed_pre_key_id: i64) -> Result>> { - let ctx = get_twonly_flutter()?; - let key_manager = ctx.key_manager.lock().await; - if let Some(signal_identity) = &key_manager.signal_identity { - Ok(signal_identity - .pre_key_store - .get(&signed_pre_key_id) - .cloned()) - } else { - Err(TwonlyError::SignalIdentityNotFound) - } - } - - pub async fn store_signed_prekey(signed_pre_key_id: i64, record: Vec) -> Result<()> { - let ctx = get_twonly_flutter()?; - let mut key_manager = ctx.key_manager.lock().await; - if let Some(signal_identity) = &mut key_manager.signal_identity { - signal_identity - .pre_key_store - .insert(signed_pre_key_id, record); - key_manager.store_to_keychain(&ctx.secure_storage)?; - Ok(()) - } else { - Err(TwonlyError::SignalIdentityNotFound) - } - } - - pub async fn remove_signed_prekey(signed_pre_key_id: i64) -> Result<()> { - let ctx = get_twonly_flutter()?; - let mut key_manager = ctx.key_manager.lock().await; - if let Some(signal_identity) = &mut key_manager.signal_identity { - signal_identity.pre_key_store.remove(&signed_pre_key_id); - key_manager.store_to_keychain(&ctx.secure_storage)?; - Ok(()) - } else { - Err(TwonlyError::SignalIdentityNotFound) - } - } - - pub async fn load_signed_prekeys() -> Result>> { - let ctx = get_twonly_flutter()?; - let key_manager = ctx.key_manager.lock().await; - if let Some(signal_identity) = &key_manager.signal_identity { - Ok(signal_identity.pre_key_store.to_owned()) - } else { - Err(TwonlyError::SignalIdentityNotFound) - } - } - pub async fn remove_key_manager() -> Result<()> { let ctx = get_twonly_flutter()?; crate::keys::KeyManager::remove_from_keychain(&ctx.secure_storage)?; @@ -149,13 +99,12 @@ impl RustKeyManager { pub async fn serialize() -> Result> { let ctx = get_twonly_flutter()?; let key_manager = ctx.key_manager.lock().await; - let serialized_bytes = postcard::to_allocvec(&*key_manager)?; - Ok(serialized_bytes) + key_manager.to_bytes() } pub async fn import_serialized(serialized_bytes: Vec) -> Result<()> { let ctx = get_twonly_flutter()?; - let key_manager: crate::keys::KeyManager = postcard::from_bytes(&serialized_bytes)?; + let key_manager = crate::keys::KeyManager::from_bytes(&serialized_bytes)?; key_manager.store_to_keychain(&ctx.secure_storage)?; *ctx.key_manager.lock().await = key_manager; Ok(()) diff --git a/rust/src/bridge/wrapper/signal.rs b/rust/src/bridge/wrapper/signal.rs index d7ebf178..9fc1f3e7 100644 --- a/rust/src/bridge/wrapper/signal.rs +++ b/rust/src/bridge/wrapper/signal.rs @@ -45,4 +45,16 @@ impl RustSignal { .decrypt_message(name.clone(), device_id, ciphertext.clone()) .await } + + pub async fn get_user_public_key() -> Result> { + let guard = get_twonly_flutter()?.signal_engine.lock().await; + let engine = guard.as_ref().ok_or(TwonlyError::Initialization)?; + engine.get_identity_key().await + } + + pub async fn get_contact_public_key(contact_id: i64) -> Result>> { + let guard = get_twonly_flutter()?.signal_engine.lock().await; + let engine = guard.as_ref().ok_or(TwonlyError::Initialization)?; + engine.get_contact_identity_key(&contact_id.to_string()).await + } } diff --git a/rust/src/context.rs b/rust/src/context.rs index 9fe529c5..0b1d36ab 100644 --- a/rust/src/context.rs +++ b/rust/src/context.rs @@ -5,7 +5,7 @@ use crate::api::runtime::{ApiClient, ApiRuntime}; use crate::bridge::InitConfig; -use crate::database::app::{AppDatabase, APP_DATABASE_FILE}; +use crate::database::app::{APP_DATABASE_FILE, AppDatabase}; use crate::database::signal::Database; use crate::error::Result; use crate::error::TwonlyError; @@ -111,13 +111,11 @@ impl Context { &self, identity_key_pair_structure: Vec, registration_id: i64, - pre_key_store: std::collections::HashMap>, ) -> Result<()> { let mut key_manager = self.key_manager.lock().await; key_manager.signal_identity = Some(crate::keys::SignalIdentityKey { identity_key_pair_structure, registration_id, - pre_key_store, }); Ok(()) } diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index bb9beefc..8e111d7b 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -38,7 +38,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueMoi, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -937778436; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1286774374; // Section: executor @@ -327,23 +327,65 @@ fn wire__crate__bridge__callbacks__init_flutter_callbacks_impl( rust_vec_len_: i32, data_len_: i32, ) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "init_flutter_callbacks", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { - let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "init_flutter_callbacks", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); let api_callback_id = ::sse_decode(&mut deserializer); -let api_logging_get_stream_sink = decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException(::sse_decode(&mut deserializer)); -let api_legacy_signal_decrypt = decode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException(::sse_decode(&mut deserializer)); -let api_legacy_signal_encrypt = decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException(::sse_decode(&mut deserializer)); -let api_api_resync_signal_session = decode_DartFn_Inputs_i_64_Output_unit_AnyhowException(::sse_decode(&mut deserializer)); -let api_api_media_action = decode_DartFn_Inputs_String_String_i_64_String_Output_unit_AnyhowException(::sse_decode(&mut deserializer)); -let api_api_verification_proof = decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException(::sse_decode(&mut deserializer)); -let api_api_create_push_avatars = decode_DartFn_Inputs_i_64_Output_unit_AnyhowException(::sse_decode(&mut deserializer)); -let api_api_media_received = decode_DartFn_Inputs_String_i_64_Output_unit_AnyhowException(::sse_decode(&mut deserializer)); -let api_api_user_config_changed = decode_DartFn_Inputs_user_config_Output_unit_AnyhowException(::sse_decode(&mut deserializer));deserializer.end(); move |context| { - transform_result_sse::<_, ()>((move || { - let output_ok = Result::<_,()>::Ok({ crate::bridge::callbacks::init_flutter_callbacks(api_callback_id, api_logging_get_stream_sink, api_legacy_signal_decrypt, api_legacy_signal_encrypt, api_api_resync_signal_session, api_api_media_action, api_api_verification_proof, api_api_create_push_avatars, api_api_media_received, api_api_user_config_changed); })?; Ok(output_ok) - })()) - } }) + let api_logging_get_stream_sink = + decode_DartFn_Inputs__Output_StreamSink_String_Sse_AnyhowException( + ::sse_decode(&mut deserializer), + ); + let api_api_media_action = + decode_DartFn_Inputs_String_String_i_64_String_Output_unit_AnyhowException( + ::sse_decode(&mut deserializer), + ); + let api_api_verification_proof = + decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( + ::sse_decode(&mut deserializer), + ); + let api_api_create_push_avatars = decode_DartFn_Inputs_i_64_Output_unit_AnyhowException( + ::sse_decode(&mut deserializer), + ); + let api_api_media_received = + decode_DartFn_Inputs_String_i_64_Output_unit_AnyhowException( + ::sse_decode(&mut deserializer), + ); + let api_api_user_config_changed = + decode_DartFn_Inputs_user_config_Output_unit_AnyhowException( + ::sse_decode(&mut deserializer), + ); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok({ + crate::bridge::callbacks::init_flutter_callbacks( + api_callback_id, + api_logging_get_stream_sink, + api_api_media_action, + api_api_verification_proof, + api_api_create_push_avatars, + api_api_media_received, + api_api_user_config_changed, + ); + })?; + Ok(output_ok) + })()) + } + }, + ) } fn wire__crate__bridge__initialize_twonly_flutter_impl( port_: flutter_rust_bridge::for_generated::MessagePort, @@ -1124,6 +1166,47 @@ fn wire__crate__bridge__api__rust_api_download_pending_media_impl( }, ) } +fn wire__crate__bridge__api__rust_api_establish_signal_session_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "rust_api_establish_signal_session", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_contact_id = ::sse_decode(&mut deserializer); + let api_expected_public_key = >>::sse_decode(&mut deserializer); + deserializer.end(); + move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || async move { + let output_ok = crate::bridge::api::RustApi::establish_signal_session( + api_contact_id, + api_expected_public_key, + ) + .await?; + Ok(output_ok) + })() + .await, + ) + } + }, + ) +} fn wire__crate__bridge__api__rust_api_events_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, @@ -2404,9 +2487,10 @@ fn wire__crate__bridge__api__rust_api_send_encrypted_content_impl( let api_contact_id = ::sse_decode(&mut deserializer); let api_content = >::sse_decode(&mut deserializer); let api_message_id = >::sse_decode(&mut deserializer); - let api_only_send_if_no_receipts_are_open = ::sse_decode(&mut deserializer); - let api_only_return_encrypted_data = ::sse_decode(&mut deserializer); - let api_blocking = ::sse_decode(&mut deserializer); + let api_only_send_if_no_receipts_are_open = + >::sse_decode(&mut deserializer); + let api_only_return_encrypted_data = >::sse_decode(&mut deserializer); + let api_blocking = >::sse_decode(&mut deserializer); deserializer.end(); move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( @@ -2453,7 +2537,8 @@ fn wire__crate__bridge__api__rust_api_send_encrypted_content_to_group_impl( let api_group_id = ::sse_decode(&mut deserializer); let api_content = >::sse_decode(&mut deserializer); let api_message_id = >::sse_decode(&mut deserializer); - let api_only_send_if_no_receipts_are_open = ::sse_decode(&mut deserializer); + let api_only_send_if_no_receipts_are_open = + >::sse_decode(&mut deserializer); deserializer.end(); move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( @@ -2845,6 +2930,8 @@ fn wire__crate__bridge__api__rust_api_upload_pqc_pre_keys_impl( }; let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_public_identity_key = >::sse_decode(&mut deserializer); + let api_registration_id = ::sse_decode(&mut deserializer); let api_ecc_signed_prekey_id = ::sse_decode(&mut deserializer); let api_ecc_signed_prekey = >::sse_decode(&mut deserializer); let api_ecc_signed_prekey_signature = >::sse_decode(&mut deserializer); @@ -2858,6 +2945,8 @@ fn wire__crate__bridge__api__rust_api_upload_pqc_pre_keys_impl( transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( (move || async move { let output_ok = crate::bridge::api::RustApi::upload_pqc_pre_keys( + api_public_identity_key, + api_registration_id, api_ecc_signed_prekey_id, api_ecc_signed_prekey, api_ecc_signed_prekey_signature, @@ -3324,40 +3413,9 @@ fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_signal_ide let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); let api_identity_key_pair_structure = >::sse_decode(&mut deserializer); -let api_registration_id = ::sse_decode(&mut deserializer); -let api_signed_pre_key_store = >>::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { +let api_registration_id = ::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { - let output_ok = crate::bridge::wrapper::key_manager::RustKeyManager::import_signal_identity(api_identity_key_pair_structure, api_registration_id, api_signed_pre_key_store).await?; Ok(output_ok) - })().await) - } }) -} -fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_load_signed_prekey_impl( - port_: flutter_rust_bridge::for_generated::MessagePort, - ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len_: i32, - data_len_: i32, -) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "rust_key_manager_load_signed_prekey", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { - let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let api_signed_pre_key_id = ::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { - transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { - let output_ok = crate::bridge::wrapper::key_manager::RustKeyManager::load_signed_prekey(api_signed_pre_key_id).await?; Ok(output_ok) - })().await) - } }) -} -fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_load_signed_prekeys_impl( - port_: flutter_rust_bridge::for_generated::MessagePort, - ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len_: i32, - data_len_: i32, -) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "rust_key_manager_load_signed_prekeys", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { - let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - deserializer.end(); move |context| async move { - transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { - let output_ok = crate::bridge::wrapper::key_manager::RustKeyManager::load_signed_prekeys().await?; Ok(output_ok) + let output_ok = crate::bridge::wrapper::key_manager::RustKeyManager::import_signal_identity(api_identity_key_pair_structure, api_registration_id).await?; Ok(output_ok) })().await) } }) } @@ -3376,21 +3434,6 @@ fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_key_manage })().await) } }) } -fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_signed_prekey_impl( - port_: flutter_rust_bridge::for_generated::MessagePort, - ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len_: i32, - data_len_: i32, -) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "rust_key_manager_remove_signed_prekey", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { - let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let api_signed_pre_key_id = ::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { - transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { - let output_ok = crate::bridge::wrapper::key_manager::RustKeyManager::remove_signed_prekey(api_signed_pre_key_id).await?; Ok(output_ok) - })().await) - } }) -} fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_serialize_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, @@ -3468,22 +3511,6 @@ fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_set_user_id_impl( }, ) } -fn wire__crate__bridge__wrapper__key_manager__rust_key_manager_store_signed_prekey_impl( - port_: flutter_rust_bridge::for_generated::MessagePort, - ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len_: i32, - data_len_: i32, -) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "rust_key_manager_store_signed_prekey", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { - let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let api_signed_pre_key_id = ::sse_decode(&mut deserializer); -let api_record = >::sse_decode(&mut deserializer);deserializer.end(); move |context| async move { - transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || async move { - let output_ok = crate::bridge::wrapper::key_manager::RustKeyManager::store_signed_prekey(api_signed_pre_key_id, api_record).await?; Ok(output_ok) - })().await) - } }) -} fn wire__crate__bridge__wrapper__signal__rust_signal_decrypt_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, @@ -3643,6 +3670,83 @@ fn wire__crate__bridge__wrapper__signal__rust_signal_generate_pqc_prekeys_impl( }, ) } +fn wire__crate__bridge__wrapper__signal__rust_signal_get_contact_public_key_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "rust_signal_get_contact_public_key", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_contact_id = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || async move { + let output_ok = + crate::bridge::wrapper::signal::RustSignal::get_contact_public_key( + api_contact_id, + ) + .await?; + Ok(output_ok) + })() + .await, + ) + } + }, + ) +} +fn wire__crate__bridge__wrapper__signal__rust_signal_get_user_public_key_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "rust_signal_get_user_public_key", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + deserializer.end(); + move |context| async move { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || async move { + let output_ok = + crate::bridge::wrapper::signal::RustSignal::get_user_public_key() + .await?; + Ok(output_ok) + })() + .await, + ) + } + }, + ) +} fn wire__crate__bridge__wrapper__signal__rust_signal_process_prekey_bundle_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, @@ -4229,53 +4333,6 @@ fn decode_DartFn_Inputs_i_64_Output_unit_AnyhowException( )) } } -fn decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_opt_box_autoadd_legacy_signal_encrypt_result_AnyhowException( - dart_opaque: flutter_rust_bridge::DartOpaque, -) -> impl Fn( - i64, - Vec, -) -> flutter_rust_bridge::DartFnFuture< - Option, -> { - use flutter_rust_bridge::IntoDart; - - async fn body( - dart_opaque: flutter_rust_bridge::DartOpaque, - arg0: i64, - arg1: Vec, - ) -> Option { - let args = vec![ - arg0.into_into_dart().into_dart(), - arg1.into_into_dart().into_dart(), - ]; - let message = FLUTTER_RUST_BRIDGE_HANDLER - .dart_fn_invoke(dart_opaque, args) - .await; - - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let action = deserializer.cursor.read_u8().unwrap(); - let ans = match action { - 0 => std::result::Result::Ok(>::sse_decode(&mut deserializer)), - 1 => std::result::Result::Err( - ::sse_decode(&mut deserializer), - ), - _ => unreachable!(), - }; - deserializer.end(); - let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); - ans - } - - move |arg0: i64, arg1: Vec| { - flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( - dart_opaque.clone(), - arg0, - arg1, - )) - } -} fn decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( dart_opaque: flutter_rust_bridge::DartOpaque, ) -> impl Fn(i64, Vec) -> flutter_rust_bridge::DartFnFuture<()> { @@ -4312,57 +4369,6 @@ fn decode_DartFn_Inputs_i_64_list_prim_u_8_strict_Output_unit_AnyhowException( )) } } -fn decode_DartFn_Inputs_i_64_list_prim_u_8_strict_i_32_Output_legacy_signal_decrypt_result_AnyhowException( - dart_opaque: flutter_rust_bridge::DartOpaque, -) -> impl Fn( - i64, - Vec, - i32, -) -> flutter_rust_bridge::DartFnFuture { - use flutter_rust_bridge::IntoDart; - - async fn body( - dart_opaque: flutter_rust_bridge::DartOpaque, - arg0: i64, - arg1: Vec, - arg2: i32, - ) -> crate::bridge::callbacks::LegacySignalDecryptResult { - let args = vec![ - arg0.into_into_dart().into_dart(), - arg1.into_into_dart().into_dart(), - arg2.into_into_dart().into_dart(), - ]; - let message = FLUTTER_RUST_BRIDGE_HANDLER - .dart_fn_invoke(dart_opaque, args) - .await; - - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let action = deserializer.cursor.read_u8().unwrap(); - let ans = match action { - 0 => std::result::Result::Ok( - ::sse_decode( - &mut deserializer, - ), - ), - 1 => std::result::Result::Err( - ::sse_decode(&mut deserializer), - ), - _ => unreachable!(), - }; - deserializer.end(); - let ans = ans.expect("Dart throws exception but Rust side assume it is not failable"); - ans - } - - move |arg0: i64, arg1: Vec, arg2: i32| { - flutter_rust_bridge::for_generated::convert_into_dart_fn_future(body( - dart_opaque.clone(), - arg0, - arg1, - arg2, - )) - } -} fn decode_DartFn_Inputs_user_config_Output_unit_AnyhowException( dart_opaque: flutter_rust_bridge::DartOpaque, ) -> impl Fn(crate::user_config::UserConfig) -> flutter_rust_bridge::DartFnFuture<()> { @@ -4438,14 +4444,6 @@ impl SseDecode for std::collections::HashMap> { } } -impl SseDecode for std::collections::HashMap> { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - let mut inner = )>>::sse_decode(deserializer); - return inner.into_iter().collect(); - } -} - impl SseDecode for StreamSink { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -4665,30 +4663,6 @@ impl SseDecode for crate::bridge::wrapper::app_database::LegacyMigrationReport { } } -impl SseDecode for crate::bridge::callbacks::LegacySignalDecryptResult { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - let mut var_plaintext = >>::sse_decode(deserializer); - let mut var_decryptionErrorType = >::sse_decode(deserializer); - return crate::bridge::callbacks::LegacySignalDecryptResult { - plaintext: var_plaintext, - decryption_error_type: var_decryptionErrorType, - }; - } -} - -impl SseDecode for crate::bridge::callbacks::LegacySignalEncryptResult { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - let mut var_ciphertext = >::sse_decode(deserializer); - let mut var_messageType = ::sse_decode(deserializer); - return crate::bridge::callbacks::LegacySignalEncryptResult { - ciphertext: var_ciphertext, - message_type: var_messageType, - }; - } -} - impl SseDecode for crate::bridge::wrapper::app_database::LegacyTableMigrationCount { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -4793,18 +4767,6 @@ impl SseDecode for Vec { } } -impl SseDecode for Vec<(i64, Vec)> { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - let mut len_ = ::sse_decode(deserializer); - let mut ans_ = Vec::with_capacity(len_ as usize); - for idx_ in 0..len_ { - ans_.push(<(i64, Vec)>::sse_decode(deserializer)); - } - return ans_; - } -} - impl SseDecode for Vec<(String, Vec)> { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -4889,6 +4851,17 @@ impl SseDecode for Option { } } +impl SseDecode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + if (::sse_decode(deserializer)) { + return Some(::sse_decode(deserializer)); + } else { + return None; + } + } +} + impl SseDecode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -4900,17 +4873,6 @@ impl SseDecode for Option { } } -impl SseDecode for Option { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - if (::sse_decode(deserializer)) { - return Some(::sse_decode(deserializer)); - } else { - return None; - } - } -} - impl SseDecode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -4922,19 +4884,6 @@ impl SseDecode for Option { } } -impl SseDecode for Option { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - if (::sse_decode(deserializer)) { - return Some( - ::sse_decode(deserializer), - ); - } else { - return None; - } - } -} - impl SseDecode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -5047,15 +4996,6 @@ impl SseDecode for crate::api::server::prekeys::PqcPreKeyInput { } } -impl SseDecode for (i64, Vec) { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { - let mut var_field0 = ::sse_decode(deserializer); - let mut var_field1 = >::sse_decode(deserializer); - return (var_field0, var_field1); - } -} - impl SseDecode for (Vec, i64) { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -5445,91 +5385,90 @@ fn pde_ffi_dispatcher_primary_impl( 29 => wire__crate__bridge__api__rust_api_download_done_impl(port, ptr, rust_vec_len, data_len), 30 => wire__crate__bridge__api__rust_api_download_media_impl(port, ptr, rust_vec_len, data_len), 31 => wire__crate__bridge__api__rust_api_download_pending_media_impl(port, ptr, rust_vec_len, data_len), -32 => wire__crate__bridge__api__rust_api_events_impl(port, ptr, rust_vec_len, data_len), -33 => wire__crate__bridge__api__rust_api_force_ipa_check_impl(port, ptr, rust_vec_len, data_len), -34 => wire__crate__bridge__api__rust_api_get_memories_url_impl(port, ptr, rust_vec_len, data_len), -35 => wire__crate__bridge__api__rust_api_get_memories_usage_impl(port, ptr, rust_vec_len, data_len), -36 => wire__crate__bridge__api__rust_api_get_plan_balance_impl(port, ptr, rust_vec_len, data_len), -37 => wire__crate__bridge__api__rust_api_get_proof_of_work_impl(port, ptr, rust_vec_len, data_len), -38 => wire__crate__bridge__api__rust_api_get_server_key_for_passwordless_recovery_impl(port, ptr, rust_vec_len, data_len), -39 => wire__crate__bridge__api__rust_api_get_user_by_id_impl(port, ptr, rust_vec_len, data_len), -40 => wire__crate__bridge__api__rust_api_get_user_data_impl(port, ptr, rust_vec_len, data_len), -41 => wire__crate__bridge__api__rust_api_get_user_id_from_username_impl(port, ptr, rust_vec_len, data_len), -42 => wire__crate__bridge__api__rust_api_insert_and_send_additional_data_impl(port, ptr, rust_vec_len, data_len), -43 => wire__crate__bridge__api__rust_api_insert_and_send_ask_about_user_impl(port, ptr, rust_vec_len, data_len), -44 => wire__crate__bridge__api__rust_api_insert_and_send_contact_share_impl(port, ptr, rust_vec_len, data_len), -45 => wire__crate__bridge__api__rust_api_insert_and_send_text_impl(port, ptr, rust_vec_len, data_len), -46 => wire__crate__bridge__api__rust_api_ipa_purchase_impl(port, ptr, rust_vec_len, data_len), -47 => wire__crate__bridge__api__rust_api_load_plan_balance_impl(port, ptr, rust_vec_len, data_len), -48 => wire__crate__bridge__api__rust_api_notify_messages_opened_impl(port, ptr, rust_vec_len, data_len), -49 => wire__crate__bridge__api__rust_api_perform_passwordless_recovery_heartbeat_impl(port, ptr, rust_vec_len, data_len), -50 => wire__crate__bridge__api__rust_api_prepare_queued_message_impl(port, ptr, rust_vec_len, data_len), -51 => wire__crate__bridge__api__rust_api_register_impl(port, ptr, rust_vec_len, data_len), -52 => wire__crate__bridge__api__rust_api_register_passwordless_notification_impl(port, ptr, rust_vec_len, data_len), -53 => wire__crate__bridge__api__rust_api_register_passwordless_recovery_impl(port, ptr, rust_vec_len, data_len), -54 => wire__crate__bridge__api__rust_api_reload_configuration_impl(port, ptr, rust_vec_len, data_len), -55 => wire__crate__bridge__api__rust_api_remove_additional_user_impl(port, ptr, rust_vec_len, data_len), -56 => wire__crate__bridge__api__rust_api_report_user_impl(port, ptr, rust_vec_len, data_len), -57 => wire__crate__bridge__api__rust_api_request_binary_impl(port, ptr, rust_vec_len, data_len), -58 => wire__crate__bridge__api__rust_api_request_contact_by_username_impl(port, ptr, rust_vec_len, data_len), -59 => wire__crate__bridge__api__rust_api_request_media_reupload_impl(port, ptr, rust_vec_len, data_len), -60 => wire__crate__bridge__api__rust_api_request_memories_upload_impl(port, ptr, rust_vec_len, data_len), -61 => wire__crate__bridge__api__rust_api_retransmit_all_messages_impl(port, ptr, rust_vec_len, data_len), -62 => wire__crate__bridge__api__rust_api_send_binary_impl(port, ptr, rust_vec_len, data_len), -63 => wire__crate__bridge__api__rust_api_send_contact_profile_impl(port, ptr, rust_vec_len, data_len), -64 => wire__crate__bridge__api__rust_api_send_encrypted_content_impl(port, ptr, rust_vec_len, data_len), -65 => wire__crate__bridge__api__rust_api_send_encrypted_content_to_group_impl(port, ptr, rust_vec_len, data_len), -66 => wire__crate__bridge__api__rust_api_send_queued_message_impl(port, ptr, rust_vec_len, data_len), -67 => wire__crate__bridge__api__rust_api_send_text_message_impl(port, ptr, rust_vec_len, data_len), -68 => wire__crate__bridge__api__rust_api_send_typing_impl(port, ptr, rust_vec_len, data_len), -69 => wire__crate__bridge__api__rust_api_set_background_impl(port, ptr, rust_vec_len, data_len), -70 => wire__crate__bridge__api__rust_api_set_login_token_impl(port, ptr, rust_vec_len, data_len), -71 => wire__crate__bridge__api__rust_api_set_network_available_impl(port, ptr, rust_vec_len, data_len), -72 => wire__crate__bridge__api__rust_api_submit_recovery_share_impl(port, ptr, rust_vec_len, data_len), -73 => wire__crate__bridge__api__rust_api_update_fcm_token_impl(port, ptr, rust_vec_len, data_len), -74 => wire__crate__bridge__api__rust_api_update_signed_pre_key_impl(port, ptr, rust_vec_len, data_len), -75 => wire__crate__bridge__api__rust_api_upload_pqc_pre_keys_impl(port, ptr, rust_vec_len, data_len), -76 => wire__crate__bridge__wrapper__app_database__rust_app_database_execute_impl(port, ptr, rust_vec_len, data_len), -77 => wire__crate__bridge__wrapper__app_database__rust_app_database_legacy_import_complete_impl(port, ptr, rust_vec_len, data_len), -78 => wire__crate__bridge__wrapper__app_database__rust_app_database_migrate_legacy_database_impl(port, ptr, rust_vec_len, data_len), -79 => wire__crate__bridge__wrapper__app_database__rust_app_database_select_impl(port, ptr, rust_vec_len, data_len), -80 => wire__crate__bridge__wrapper__backup__rust_backup_archive_create_backup_archive_impl(port, ptr, rust_vec_len, data_len), -81 => wire__crate__bridge__wrapper__backup__rust_backup_archive_get_backup_download_token_impl(port, ptr, rust_vec_len, data_len), -82 => wire__crate__bridge__wrapper__backup__rust_backup_archive_restore_backup_archive_impl(port, ptr, rust_vec_len, data_len), -83 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_id_impl(port, ptr, rust_vec_len, data_len), -84 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_password_keys_impl(port, ptr, rust_vec_len, data_len), -85 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_identity_backup_bytes_impl(port, ptr, rust_vec_len, data_len), -86 => wire__crate__bridge__wrapper__backup__rust_backup_identity_import_backup_password_keys_impl(port, ptr, rust_vec_len, data_len), -87 => wire__crate__bridge__wrapper__backup__rust_backup_identity_restore_identity_backup_impl(port, ptr, rust_vec_len, data_len), -88 => wire__crate__bridge__wrapper__backup__rust_backup_identity_set_backup_password_keys_impl(port, ptr, rust_vec_len, data_len), -89 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_decrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len), -90 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_encrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len), -91 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_login_token_impl(port, ptr, rust_vec_len, data_len), -92 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_signal_identity_impl(port, ptr, rust_vec_len, data_len), -93 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_user_id_impl(port, ptr, rust_vec_len, data_len), -94 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_serialized_impl(port, ptr, rust_vec_len, data_len), -95 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_signal_identity_impl(port, ptr, rust_vec_len, data_len), -96 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_load_signed_prekey_impl(port, ptr, rust_vec_len, data_len), -97 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_load_signed_prekeys_impl(port, ptr, rust_vec_len, data_len), -98 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_key_manager_impl(port, ptr, rust_vec_len, data_len), -99 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_signed_prekey_impl(port, ptr, rust_vec_len, data_len), -100 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_serialize_impl(port, ptr, rust_vec_len, data_len), -101 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_set_user_id_impl(port, ptr, rust_vec_len, data_len), -102 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_store_signed_prekey_impl(port, ptr, rust_vec_len, data_len), -103 => wire__crate__bridge__wrapper__signal__rust_signal_decrypt_impl(port, ptr, rust_vec_len, data_len), -104 => wire__crate__bridge__wrapper__signal__rust_signal_encrypt_impl(port, ptr, rust_vec_len, data_len), -105 => wire__crate__bridge__wrapper__signal__rust_signal_generate_bundle_impl(port, ptr, rust_vec_len, data_len), -106 => wire__crate__bridge__wrapper__signal__rust_signal_generate_pqc_prekeys_impl(port, ptr, rust_vec_len, data_len), -107 => wire__crate__bridge__wrapper__signal__rust_signal_process_prekey_bundle_impl(port, ptr, rust_vec_len, data_len), -108 => wire__crate__bridge__wrapper__rust_utils_generate_shares_impl(port, ptr, rust_vec_len, data_len), -109 => wire__crate__bridge__wrapper__rust_utils_recover_secret_impl(port, ptr, rust_vec_len, data_len), -110 => wire__crate__bridge__groups__update_chat_deletion_time_impl(port, ptr, rust_vec_len, data_len), -111 => wire__crate__bridge__groups__update_group_name_impl(port, ptr, rust_vec_len, data_len), -113 => wire__crate__bridge__user_config__user_config_api_create_impl(port, ptr, rust_vec_len, data_len), -114 => wire__crate__bridge__user_config__user_config_api_import_json_impl(port, ptr, rust_vec_len, data_len), -115 => wire__crate__bridge__user_config__user_config_api_load_impl(port, ptr, rust_vec_len, data_len), -116 => wire__crate__bridge__user_config__user_config_api_save_impl(port, ptr, rust_vec_len, data_len), -117 => wire__crate__bridge__user_config__user_config_api_update_impl(port, ptr, rust_vec_len, data_len), +32 => wire__crate__bridge__api__rust_api_establish_signal_session_impl(port, ptr, rust_vec_len, data_len), +33 => wire__crate__bridge__api__rust_api_events_impl(port, ptr, rust_vec_len, data_len), +34 => wire__crate__bridge__api__rust_api_force_ipa_check_impl(port, ptr, rust_vec_len, data_len), +35 => wire__crate__bridge__api__rust_api_get_memories_url_impl(port, ptr, rust_vec_len, data_len), +36 => wire__crate__bridge__api__rust_api_get_memories_usage_impl(port, ptr, rust_vec_len, data_len), +37 => wire__crate__bridge__api__rust_api_get_plan_balance_impl(port, ptr, rust_vec_len, data_len), +38 => wire__crate__bridge__api__rust_api_get_proof_of_work_impl(port, ptr, rust_vec_len, data_len), +39 => wire__crate__bridge__api__rust_api_get_server_key_for_passwordless_recovery_impl(port, ptr, rust_vec_len, data_len), +40 => wire__crate__bridge__api__rust_api_get_user_by_id_impl(port, ptr, rust_vec_len, data_len), +41 => wire__crate__bridge__api__rust_api_get_user_data_impl(port, ptr, rust_vec_len, data_len), +42 => wire__crate__bridge__api__rust_api_get_user_id_from_username_impl(port, ptr, rust_vec_len, data_len), +43 => wire__crate__bridge__api__rust_api_insert_and_send_additional_data_impl(port, ptr, rust_vec_len, data_len), +44 => wire__crate__bridge__api__rust_api_insert_and_send_ask_about_user_impl(port, ptr, rust_vec_len, data_len), +45 => wire__crate__bridge__api__rust_api_insert_and_send_contact_share_impl(port, ptr, rust_vec_len, data_len), +46 => wire__crate__bridge__api__rust_api_insert_and_send_text_impl(port, ptr, rust_vec_len, data_len), +47 => wire__crate__bridge__api__rust_api_ipa_purchase_impl(port, ptr, rust_vec_len, data_len), +48 => wire__crate__bridge__api__rust_api_load_plan_balance_impl(port, ptr, rust_vec_len, data_len), +49 => wire__crate__bridge__api__rust_api_notify_messages_opened_impl(port, ptr, rust_vec_len, data_len), +50 => wire__crate__bridge__api__rust_api_perform_passwordless_recovery_heartbeat_impl(port, ptr, rust_vec_len, data_len), +51 => wire__crate__bridge__api__rust_api_prepare_queued_message_impl(port, ptr, rust_vec_len, data_len), +52 => wire__crate__bridge__api__rust_api_register_impl(port, ptr, rust_vec_len, data_len), +53 => wire__crate__bridge__api__rust_api_register_passwordless_notification_impl(port, ptr, rust_vec_len, data_len), +54 => wire__crate__bridge__api__rust_api_register_passwordless_recovery_impl(port, ptr, rust_vec_len, data_len), +55 => wire__crate__bridge__api__rust_api_reload_configuration_impl(port, ptr, rust_vec_len, data_len), +56 => wire__crate__bridge__api__rust_api_remove_additional_user_impl(port, ptr, rust_vec_len, data_len), +57 => wire__crate__bridge__api__rust_api_report_user_impl(port, ptr, rust_vec_len, data_len), +58 => wire__crate__bridge__api__rust_api_request_binary_impl(port, ptr, rust_vec_len, data_len), +59 => wire__crate__bridge__api__rust_api_request_contact_by_username_impl(port, ptr, rust_vec_len, data_len), +60 => wire__crate__bridge__api__rust_api_request_media_reupload_impl(port, ptr, rust_vec_len, data_len), +61 => wire__crate__bridge__api__rust_api_request_memories_upload_impl(port, ptr, rust_vec_len, data_len), +62 => wire__crate__bridge__api__rust_api_retransmit_all_messages_impl(port, ptr, rust_vec_len, data_len), +63 => wire__crate__bridge__api__rust_api_send_binary_impl(port, ptr, rust_vec_len, data_len), +64 => wire__crate__bridge__api__rust_api_send_contact_profile_impl(port, ptr, rust_vec_len, data_len), +65 => wire__crate__bridge__api__rust_api_send_encrypted_content_impl(port, ptr, rust_vec_len, data_len), +66 => wire__crate__bridge__api__rust_api_send_encrypted_content_to_group_impl(port, ptr, rust_vec_len, data_len), +67 => wire__crate__bridge__api__rust_api_send_queued_message_impl(port, ptr, rust_vec_len, data_len), +68 => wire__crate__bridge__api__rust_api_send_text_message_impl(port, ptr, rust_vec_len, data_len), +69 => wire__crate__bridge__api__rust_api_send_typing_impl(port, ptr, rust_vec_len, data_len), +70 => wire__crate__bridge__api__rust_api_set_background_impl(port, ptr, rust_vec_len, data_len), +71 => wire__crate__bridge__api__rust_api_set_login_token_impl(port, ptr, rust_vec_len, data_len), +72 => wire__crate__bridge__api__rust_api_set_network_available_impl(port, ptr, rust_vec_len, data_len), +73 => wire__crate__bridge__api__rust_api_submit_recovery_share_impl(port, ptr, rust_vec_len, data_len), +74 => wire__crate__bridge__api__rust_api_update_fcm_token_impl(port, ptr, rust_vec_len, data_len), +75 => wire__crate__bridge__api__rust_api_update_signed_pre_key_impl(port, ptr, rust_vec_len, data_len), +76 => wire__crate__bridge__api__rust_api_upload_pqc_pre_keys_impl(port, ptr, rust_vec_len, data_len), +77 => wire__crate__bridge__wrapper__app_database__rust_app_database_execute_impl(port, ptr, rust_vec_len, data_len), +78 => wire__crate__bridge__wrapper__app_database__rust_app_database_legacy_import_complete_impl(port, ptr, rust_vec_len, data_len), +79 => wire__crate__bridge__wrapper__app_database__rust_app_database_migrate_legacy_database_impl(port, ptr, rust_vec_len, data_len), +80 => wire__crate__bridge__wrapper__app_database__rust_app_database_select_impl(port, ptr, rust_vec_len, data_len), +81 => wire__crate__bridge__wrapper__backup__rust_backup_archive_create_backup_archive_impl(port, ptr, rust_vec_len, data_len), +82 => wire__crate__bridge__wrapper__backup__rust_backup_archive_get_backup_download_token_impl(port, ptr, rust_vec_len, data_len), +83 => wire__crate__bridge__wrapper__backup__rust_backup_archive_restore_backup_archive_impl(port, ptr, rust_vec_len, data_len), +84 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_id_impl(port, ptr, rust_vec_len, data_len), +85 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_password_keys_impl(port, ptr, rust_vec_len, data_len), +86 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_identity_backup_bytes_impl(port, ptr, rust_vec_len, data_len), +87 => wire__crate__bridge__wrapper__backup__rust_backup_identity_import_backup_password_keys_impl(port, ptr, rust_vec_len, data_len), +88 => wire__crate__bridge__wrapper__backup__rust_backup_identity_restore_identity_backup_impl(port, ptr, rust_vec_len, data_len), +89 => wire__crate__bridge__wrapper__backup__rust_backup_identity_set_backup_password_keys_impl(port, ptr, rust_vec_len, data_len), +90 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_decrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len), +91 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_encrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len), +92 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_login_token_impl(port, ptr, rust_vec_len, data_len), +93 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_signal_identity_impl(port, ptr, rust_vec_len, data_len), +94 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_user_id_impl(port, ptr, rust_vec_len, data_len), +95 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_serialized_impl(port, ptr, rust_vec_len, data_len), +96 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_signal_identity_impl(port, ptr, rust_vec_len, data_len), +97 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_key_manager_impl(port, ptr, rust_vec_len, data_len), +98 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_serialize_impl(port, ptr, rust_vec_len, data_len), +99 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_set_user_id_impl(port, ptr, rust_vec_len, data_len), +100 => wire__crate__bridge__wrapper__signal__rust_signal_decrypt_impl(port, ptr, rust_vec_len, data_len), +101 => wire__crate__bridge__wrapper__signal__rust_signal_encrypt_impl(port, ptr, rust_vec_len, data_len), +102 => wire__crate__bridge__wrapper__signal__rust_signal_generate_bundle_impl(port, ptr, rust_vec_len, data_len), +103 => wire__crate__bridge__wrapper__signal__rust_signal_generate_pqc_prekeys_impl(port, ptr, rust_vec_len, data_len), +104 => wire__crate__bridge__wrapper__signal__rust_signal_get_contact_public_key_impl(port, ptr, rust_vec_len, data_len), +105 => wire__crate__bridge__wrapper__signal__rust_signal_get_user_public_key_impl(port, ptr, rust_vec_len, data_len), +106 => wire__crate__bridge__wrapper__signal__rust_signal_process_prekey_bundle_impl(port, ptr, rust_vec_len, data_len), +107 => wire__crate__bridge__wrapper__rust_utils_generate_shares_impl(port, ptr, rust_vec_len, data_len), +108 => wire__crate__bridge__wrapper__rust_utils_recover_secret_impl(port, ptr, rust_vec_len, data_len), +109 => wire__crate__bridge__groups__update_chat_deletion_time_impl(port, ptr, rust_vec_len, data_len), +110 => wire__crate__bridge__groups__update_group_name_impl(port, ptr, rust_vec_len, data_len), +112 => wire__crate__bridge__user_config__user_config_api_create_impl(port, ptr, rust_vec_len, data_len), +113 => wire__crate__bridge__user_config__user_config_api_import_json_impl(port, ptr, rust_vec_len, data_len), +114 => wire__crate__bridge__user_config__user_config_api_load_impl(port, ptr, rust_vec_len, data_len), +115 => wire__crate__bridge__user_config__user_config_api_save_impl(port, ptr, rust_vec_len, data_len), +116 => wire__crate__bridge__user_config__user_config_api_update_impl(port, ptr, rust_vec_len, data_len), _ => unreachable!(), } } @@ -5543,7 +5482,7 @@ fn pde_ffi_dispatcher_sync_impl( // Codec=Pde (Serialization + dispatch), see doc to use other codecs match func_id { 18 => wire__crate__bridge__api__rust_api_api_base_url_impl(ptr, rust_vec_len, data_len), - 112 => wire__crate__bridge__user_config__user_config_api_clone_impl( + 111 => wire__crate__bridge__user_config__user_config_api_clone_impl( ptr, rust_vec_len, data_len, @@ -5781,48 +5720,6 @@ impl flutter_rust_bridge::IntoIntoDart flutter_rust_bridge::for_generated::DartAbi { - [ - self.plaintext.into_into_dart().into_dart(), - self.decryption_error_type.into_into_dart().into_dart(), - ] - .into_dart() - } -} -impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive - for crate::bridge::callbacks::LegacySignalDecryptResult -{ -} -impl flutter_rust_bridge::IntoIntoDart - for crate::bridge::callbacks::LegacySignalDecryptResult -{ - fn into_into_dart(self) -> crate::bridge::callbacks::LegacySignalDecryptResult { - self - } -} -// Codec=Dco (DartCObject based), see doc to use other codecs -impl flutter_rust_bridge::IntoDart for crate::bridge::callbacks::LegacySignalEncryptResult { - fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { - [ - self.ciphertext.into_into_dart().into_dart(), - self.message_type.into_into_dart().into_dart(), - ] - .into_dart() - } -} -impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive - for crate::bridge::callbacks::LegacySignalEncryptResult -{ -} -impl flutter_rust_bridge::IntoIntoDart - for crate::bridge::callbacks::LegacySignalEncryptResult -{ - fn into_into_dart(self) -> crate::bridge::callbacks::LegacySignalEncryptResult { - self - } -} -// Codec=Dco (DartCObject based), see doc to use other codecs impl flutter_rust_bridge::IntoDart for crate::bridge::wrapper::app_database::LegacyTableMigrationCount { @@ -6305,13 +6202,6 @@ impl SseEncode for std::collections::HashMap> { } } -impl SseEncode for std::collections::HashMap> { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - )>>::sse_encode(self.into_iter().collect(), serializer); - } -} - impl SseEncode for StreamSink { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -6503,22 +6393,6 @@ impl SseEncode for crate::bridge::wrapper::app_database::LegacyMigrationReport { } } -impl SseEncode for crate::bridge::callbacks::LegacySignalDecryptResult { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - >>::sse_encode(self.plaintext, serializer); - >::sse_encode(self.decryption_error_type, serializer); - } -} - -impl SseEncode for crate::bridge::callbacks::LegacySignalEncryptResult { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - >::sse_encode(self.ciphertext, serializer); - ::sse_encode(self.message_type, serializer); - } -} - impl SseEncode for crate::bridge::wrapper::app_database::LegacyTableMigrationCount { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -6599,16 +6473,6 @@ impl SseEncode for Vec { } } -impl SseEncode for Vec<(i64, Vec)> { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - ::sse_encode(self.len() as _, serializer); - for item in self { - <(i64, Vec)>::sse_encode(item, serializer); - } - } -} - impl SseEncode for Vec<(String, Vec)> { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -6679,6 +6543,16 @@ impl SseEncode for Option { } } +impl SseEncode for Option { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.is_some(), serializer); + if let Some(value) = self { + ::sse_encode(value, serializer); + } + } +} + impl SseEncode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -6689,16 +6563,6 @@ impl SseEncode for Option { } } -impl SseEncode for Option { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - ::sse_encode(self.is_some(), serializer); - if let Some(value) = self { - ::sse_encode(value, serializer); - } - } -} - impl SseEncode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -6709,16 +6573,6 @@ impl SseEncode for Option { } } -impl SseEncode for Option { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - ::sse_encode(self.is_some(), serializer); - if let Some(value) = self { - ::sse_encode(value, serializer); - } - } -} - impl SseEncode for Option { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -6806,14 +6660,6 @@ impl SseEncode for crate::api::server::prekeys::PqcPreKeyInput { } } -impl SseEncode for (i64, Vec) { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { - ::sse_encode(self.0, serializer); - >::sse_encode(self.1, serializer); - } -} - impl SseEncode for (Vec, i64) { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { diff --git a/rust/src/keys/backup_password_keys.rs b/rust/src/keys/backup_password_keys.rs index 65df43af..f1188d65 100644 --- a/rust/src/keys/backup_password_keys.rs +++ b/rust/src/keys/backup_password_keys.rs @@ -4,7 +4,7 @@ */ use crate::error::Result; -use scrypt::{scrypt, Params}; +use scrypt::{Params, scrypt}; use serde::{Deserialize, Serialize}; use zeroize::{Zeroize, ZeroizeOnDrop}; diff --git a/rust/src/keys/identity_key/signal_identity_key.rs b/rust/src/keys/identity_key/signal_identity_key.rs index b8fe62c9..d4d3fa6e 100644 --- a/rust/src/keys/identity_key/signal_identity_key.rs +++ b/rust/src/keys/identity_key/signal_identity_key.rs @@ -3,8 +3,9 @@ * */ -use std::collections::HashMap; - +use crate::error::Result; +use libsignal_protocol::IdentityKeyPair; +use rand::SeedableRng; use serde::{Deserialize, Serialize}; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -12,19 +13,24 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub(crate) struct SignalIdentityKey { pub(crate) identity_key_pair_structure: Vec, pub(crate) registration_id: i64, - pub(crate) pre_key_store: HashMap>, } -impl SignalIdentityKey {} +impl SignalIdentityKey { + pub(crate) fn generate() -> Result { + let mut csprng = rand::rngs::StdRng::from_os_rng(); + let identity_key_pair = IdentityKeyPair::generate(&mut csprng); + let registration_id = rand::Rng::random::(&mut csprng) & 0x7fff_ffff; + Ok(Self { + identity_key_pair_structure: identity_key_pair.serialize().to_vec(), + registration_id: i64::from(registration_id), + }) + } +} impl Zeroize for SignalIdentityKey { fn zeroize(&mut self) { self.identity_key_pair_structure.zeroize(); self.registration_id.zeroize(); - for value in self.pre_key_store.values_mut() { - value.zeroize(); - } - self.pre_key_store.clear(); } } diff --git a/rust/src/keys/mod.rs b/rust/src/keys/mod.rs index 9de70d2e..82810678 100644 --- a/rust/src/keys/mod.rs +++ b/rust/src/keys/mod.rs @@ -14,9 +14,11 @@ pub(crate) use crate::keys::identity_key::signal_identity_key::SignalIdentityKey pub(crate) use crate::keys::main_key::{DatabaseKey, MainKey}; use crate::secure_storage::SecureStorage; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; use zeroize::{Zeroize, ZeroizeOnDrop}; const KEY_MANAGER_ID: &str = "twonly_key_manager"; +const KEY_MANAGER_V2_PREFIX: &[u8] = b"TWONLY_KEY_MANAGER_V2\0"; #[derive(Debug, PartialEq, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)] pub(crate) struct KeyManager { @@ -44,14 +46,12 @@ impl KeyManager { let bytes = hex::decode(hex_key)?; - let main_key: KeyManager = postcard::from_bytes(&bytes)?; - - Ok(main_key) + Self::from_bytes(&bytes) } /// Stores the main key into the secure keychain/local storage. pub fn store_to_keychain(&self, storage: &SecureStorage) -> Result<()> { - let serialized = postcard::to_allocvec(self)?; + let serialized = self.to_bytes()?; let hex_key = hex::encode(serialized); storage.write(KEY_MANAGER_ID, &hex_key)?; @@ -64,4 +64,130 @@ impl KeyManager { storage.delete(KEY_MANAGER_ID)?; Ok(()) } + + pub(crate) fn to_bytes(&self) -> Result> { + let payload = postcard::to_allocvec(self)?; + let mut serialized = Vec::with_capacity(KEY_MANAGER_V2_PREFIX.len() + payload.len()); + serialized.extend_from_slice(KEY_MANAGER_V2_PREFIX); + serialized.extend_from_slice(&payload); + Ok(serialized) + } + + pub(crate) fn from_bytes(bytes: &[u8]) -> Result { + if let Some(payload) = bytes.strip_prefix(KEY_MANAGER_V2_PREFIX) { + return Ok(postcard::from_bytes(payload)?); + } + + // Key managers written before V2 used postcard's positional encoding and + // embedded a signed-prekey HashMap in the Signal identity. Read that + // shape once and discard the obsolete private-key copy during migration. + let legacy: LegacyKeyManager = postcard::from_bytes(bytes)?; + Ok(legacy.into_current()) + } +} + +#[derive(Deserialize)] +struct LegacyKeyManager { + user_id: Option, + main_key: MainKey, + signal_identity: Option, + backup_password: Option, +} + +impl LegacyKeyManager { + fn into_current(self) -> KeyManager { + KeyManager { + user_id: self.user_id, + main_key: self.main_key, + signal_identity: self + .signal_identity + .map(LegacySignalIdentityKey::into_current), + backup_password: self.backup_password, + } + } +} + +#[derive(Deserialize)] +struct LegacySignalIdentityKey { + identity_key_pair_structure: Vec, + registration_id: i64, + pre_key_store: HashMap>, +} + +impl LegacySignalIdentityKey { + fn into_current(mut self) -> SignalIdentityKey { + for value in self.pre_key_store.values_mut() { + value.zeroize(); + } + self.pre_key_store.clear(); + SignalIdentityKey { + identity_key_pair_structure: std::mem::take(&mut self.identity_key_pair_structure), + registration_id: self.registration_id, + } + } +} + +impl Drop for LegacySignalIdentityKey { + fn drop(&mut self) { + self.identity_key_pair_structure.zeroize(); + self.registration_id.zeroize(); + for value in self.pre_key_store.values_mut() { + value.zeroize(); + } + self.pre_key_store.clear(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Serialize)] + struct OldKeyManager<'a> { + user_id: Option, + main_key: &'a MainKey, + signal_identity: Option, + backup_password: Option<&'a BackupPasswordKeys>, + } + + #[derive(Serialize)] + struct OldSignalIdentity { + identity_key_pair_structure: Vec, + registration_id: i64, + pre_key_store: HashMap>, + } + + #[test] + fn reads_legacy_key_manager_and_drops_pre_key_store() { + let key_manager = KeyManager::generate().unwrap(); + let legacy = OldKeyManager { + user_id: Some(42), + main_key: &key_manager.main_key, + signal_identity: Some(OldSignalIdentity { + identity_key_pair_structure: vec![1, 2, 3], + registration_id: 7, + pre_key_store: HashMap::from([(1, vec![4, 5, 6])]), + }), + backup_password: None, + }; + let bytes = postcard::to_allocvec(&legacy).unwrap(); + + let migrated = KeyManager::from_bytes(&bytes).unwrap(); + assert_eq!(migrated.user_id, Some(42)); + assert_eq!( + migrated.signal_identity, + Some(SignalIdentityKey { + identity_key_pair_structure: vec![1, 2, 3], + registration_id: 7, + }) + ); + } + + #[test] + fn v2_roundtrip_is_prefixed() { + let key_manager = KeyManager::generate().unwrap(); + let bytes = key_manager.to_bytes().unwrap(); + assert!(bytes.starts_with(KEY_MANAGER_V2_PREFIX)); + assert_eq!(KeyManager::from_bytes(&bytes).unwrap(), key_manager); + } } diff --git a/rust/src/sealed_sender.rs b/rust/src/sealed_sender.rs index d9f5015d..1e179d3d 100644 --- a/rust/src/sealed_sender.rs +++ b/rust/src/sealed_sender.rs @@ -4,8 +4,8 @@ */ use chacha20poly1305::{ - aead::{Aead, Payload}, KeyInit, XChaCha20Poly1305, XNonce, + aead::{Aead, Payload}, }; use hkdf::Hkdf; use libsignal_protocol::{IdentityKeyPair, KeyPair, PublicKey}; @@ -319,7 +319,7 @@ fn derive_encryption_key( #[cfg(test)] mod tests { use super::*; - use rand::{rngs::StdRng, SeedableRng}; + use rand::{SeedableRng, rngs::StdRng}; fn test_message() -> proto::Message { proto::Message { @@ -360,7 +360,6 @@ mod tests { key_manager.signal_identity = Some(crate::keys::SignalIdentityKey { identity_key_pair_structure: recipient.serialize().to_vec(), registration_id: 1, - pre_key_store: Default::default(), }); } let database = context.rust_db.read().await.clone(); diff --git a/rust/src/services/contacts.rs b/rust/src/services/contacts.rs index ec03565c..f34041ed 100644 --- a/rust/src/services/contacts.rs +++ b/rust/src/services/contacts.rs @@ -61,7 +61,11 @@ impl ContactService { .await } - pub(crate) async fn establish_signal_session(&self, user_id: i64) -> Result<()> { + pub(crate) async fn establish_signal_session( + &self, + user_id: i64, + expected_public_key: Option>, + ) -> Result<()> { let user = match Server::get_user_by_id(&self.ctx, user_id).await? { ServerResult::Ok(user) => user, ServerResult::ErrorCode(code) => { @@ -70,7 +74,31 @@ impl ContactService { ))); } }; - self.process_user_prekey_bundle(&user).await + + if let Some(expected_key) = expected_public_key { + let server_key = user + .public_identity_key + .as_ref() + .ok_or(TwonlyError::ApiResponseMissingField("public_identity_key"))?; + if server_key != &expected_key { + return Err(TwonlyError::Generic(format!( + "Public identity key mismatch for user {user_id}" + ))); + } + } + + self.process_user_prekey_bundle(&user).await?; + + let database = self.ctx.app_db.read().await.clone(); + sqlx::query!( + "UPDATE contacts SET signal_version = 'v2' WHERE user_id = ?", + user_id + ) + .execute(&database.pool) + .await?; + database.notify_committed(["contacts"]); + + Ok(()) } async fn process_user_prekey_bundle( diff --git a/rust/src/services/groups/mod.rs b/rust/src/services/groups/mod.rs index 258206f4..de25f838 100644 --- a/rust/src/services/groups/mod.rs +++ b/rust/src/services/groups/mod.rs @@ -469,6 +469,14 @@ impl GroupService { pub async fn leave_group(&self, group_id: String) -> Result { let (db, group) = self.load_group(&group_id).await?; + let user_id = self.ctx.user_id().await?; + let (_, group_state) = GroupApi::load_state(&group).await?; + if group_state.admin_ids.contains(&user_id) { + let identity = group.identity()?; + let public_key = identity.identity_key().serialize().to_vec(); + return self.remove_member(group_id, public_key, user_id).await; + } + let identity = group.identity()?; let public_key = identity.identity_key().serialize().to_vec(); let append = EncryptedAppendedGroupState { diff --git a/rust/src/signal/engine.rs b/rust/src/signal/engine.rs index 963cea4d..cb7e3b6f 100644 --- a/rust/src/signal/engine.rs +++ b/rust/src/signal/engine.rs @@ -8,10 +8,10 @@ use crate::error::{Result, TwonlyError}; use crate::user_config::UserConfig; use chrono::{Duration, Utc}; use libsignal_protocol::{ - message_encrypt, process_prekey_bundle, CiphertextMessageType, DeviceId, GenericSignedPreKey, - IdentityKey, IdentityKeyPair, IdentityKeyStore, KyberPreKeyId, KyberPreKeyStore, PreKeyBundle, - PreKeyId, PreKeySignalMessage, PreKeyStore, ProtocolAddress, PublicKey, SignalMessage, - SignedPreKeyId, SignedPreKeyStore, Timestamp, + CiphertextMessageType, DeviceId, GenericSignedPreKey, IdentityKey, IdentityKeyPair, + IdentityKeyStore, KyberPreKeyId, KyberPreKeyStore, PreKeyBundle, PreKeyId, PreKeySignalMessage, + PreKeyStore, ProtocolAddress, PublicKey, SignalMessage, SignedPreKeyId, SignedPreKeyStore, + Timestamp, message_encrypt, process_prekey_bundle, }; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; @@ -82,6 +82,8 @@ impl RustSignalEngine { if refresh_pqc { Server::upload_pqc_pre_keys( ctx, + bundle.identity_key, + i64::from(bundle.registration_id), i64::from(bundle.signed_pre_key_id), bundle.signed_pre_key_public, bundle.signed_pre_key_signature, @@ -141,6 +143,28 @@ impl RustSignalEngine { }) } + pub async fn get_identity_key(&self) -> Result> { + let store = self.store.lock().await; + let key_pair = store + .identity_store + .get_identity_key_pair() + .assert_send() + .await + .map_err(|e| TwonlyError::Signal(e.to_string()))?; + Ok(key_pair.identity_key().serialize().to_vec()) + } + + pub async fn get_contact_identity_key(&self, name: &str) -> Result>> { + let store = self.store.lock().await; + let identity = sqlx::query_scalar!( + r#"SELECT identity_key FROM signal_identities WHERE name = ?"#, + name, + ) + .fetch_optional(&store.pool) + .await?; + Ok(identity) + } + #[cfg(test)] fn generate_identity_key_pair() -> Result> { let mut csprng = rand::rngs::StdRng::from_os_rng(); @@ -159,33 +183,21 @@ impl RustSignalEngine { ) .fetch_one(&store.pool) .await?; - if id > 16_777_215 { - 1 - } else { - id + 1 - } + if id > 16_777_215 { 1 } else { id + 1 } }; let signed_pre_key_id: u32 = { let id = sqlx::query_scalar!( r#"SELECT COALESCE(MAX(signed_pre_key_id), 0) AS "id!: u32" FROM signal_signed_pre_keys"#, ).fetch_one(&store.pool).await?; - if id > 16_777_215 { - 1 - } else { - id + 1 - } + if id > 16_777_215 { 1 } else { id + 1 } }; let kyber_pre_key_id: u32 = { let id = sqlx::query_scalar!( r#"SELECT COALESCE(MAX(kyber_pre_key_id), 0) AS "id!: u32" FROM signal_kyber_pre_keys"#, ).fetch_one(&store.pool).await?; - if id > 16_777_215 { - 1 - } else { - id + 1 - } + if id > 16_777_215 { 1 } else { id + 1 } }; let pre_key_pair = libsignal_protocol::KeyPair::generate(&mut csprng); @@ -313,11 +325,7 @@ impl RustSignalEngine { r#"SELECT COALESCE(MAX(kyber_pre_key_id), 0) AS "id!: u32" FROM signal_kyber_pre_keys"#, ).fetch_one(&store.pool).await?; - if id > 16_777_215 { - 1 - } else { - id - } + if id > 16_777_215 { 1 } else { id } }; let mut pre_key_id: u32 = { @@ -327,11 +335,7 @@ impl RustSignalEngine { .fetch_one(&store.pool) .await?; - if id > 16_777_215 { - 1 - } else { - id - } + if id > 16_777_215 { 1 } else { id } }; for _ in 0..30 { diff --git a/rust/tests/api/group_resilience.rs b/rust/tests/api/group_resilience.rs index 14fb4bca..84f9998d 100644 --- a/rust/tests/api/group_resilience.rs +++ b/rust/tests/api/group_resilience.rs @@ -116,3 +116,130 @@ async fn test_add_hidden_contact() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn test_admin_and_non_admin_leave_group() -> anyhow::Result<()> { + let tester_a = create_authenticated_tester().await?; + let tester_b = create_authenticated_tester().await?; + let tester_c = create_authenticated_tester().await?; + + // Setup contacts + ContactService::new(&tester_a.context) + .request_by_username(tester_b.username.clone(), true) + .await?; + tester_b + .wait_for_contact_state(tester_a.user_id, false, true) + .await?; + ContactService::new(&tester_b.context) + .accept_request(tester_a.user_id, true) + .await?; + tester_a + .wait_for_contact_state(tester_b.user_id, true, false) + .await?; + + ContactService::new(&tester_a.context) + .request_by_username(tester_c.username.clone(), true) + .await?; + tester_c + .wait_for_contact_state(tester_a.user_id, false, true) + .await?; + ContactService::new(&tester_c.context) + .accept_request(tester_a.user_id, true) + .await?; + tester_a + .wait_for_contact_state(tester_c.user_id, true, false) + .await?; + + // Tester A creates group with Tester B and Tester C + let group_name = "Leave Test Group"; + GroupService::new(&tester_a.context) + .create_group(group_name.into(), vec![tester_b.user_id, tester_c.user_id]) + .await?; + + let group_id = { + let db_a = tester_a.context.app_db.read().await.clone(); + sqlx::query_scalar!( + "SELECT group_id FROM groups WHERE is_direct_chat = 0 ORDER BY rowid DESC LIMIT 1" + ) + .fetch_one(&db_a.pool) + .await? + }; + + tester_b.wait_for_group_exists(&group_id, group_name).await?; + tester_c.wait_for_group_exists(&group_id, group_name).await?; + + // Fetch missing public key for tester_b + { + let db_a = tester_a.context.app_db.read().await.clone(); + sqlx::query!( + "UPDATE group_members SET last_message = CAST(strftime('%s','now') AS INTEGER) WHERE group_id = ? AND contact_id = ?", + group_id, + tester_b.user_id + ) + .execute(&db_a.pool) + .await?; + GroupService::new(&tester_a.context).fetch_missing_group_public_keys().await?; + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + } + + // Promote tester_b to admin so tester_a can leave later with an admin remaining + GroupService::new(&tester_a.context) + .manage_admin(group_id.clone(), tester_b.user_id, false) + .await?; + GroupService::new(&tester_b.context) + .fetch_group_state(group_id.clone()) + .await?; + + { + let db_b = tester_b.context.app_db.read().await.clone(); + let is_admin = sqlx::query_scalar!( + "SELECT is_group_admin FROM groups WHERE group_id = ?", + group_id + ) + .fetch_one(&db_b.pool) + .await?; + assert_eq!(is_admin, 1, "tester_b should be admin after promotion"); + } + + // 1. Non-admin (tester_c) leaves the group + GroupService::new(&tester_c.context) + .leave_group(group_id.clone()) + .await?; + tester_c.wait_for_group_left(&group_id).await?; + + // Verify tester_a and tester_b see tester_c removed + GroupService::new(&tester_a.context) + .fetch_group_state(group_id.clone()) + .await?; + tester_a + .wait_for_group_member_removed(&group_id, tester_c.user_id) + .await?; + + // 2. Admin (tester_a) leaves the group using leave_group + GroupService::new(&tester_a.context) + .leave_group(group_id.clone()) + .await?; + tester_a.wait_for_group_left(&group_id).await?; + + // Verify tester_b (remaining admin) sees tester_a removed and tester_b remains admin + GroupService::new(&tester_b.context) + .fetch_group_state(group_id.clone()) + .await?; + tester_b + .wait_for_group_member_removed(&group_id, tester_a.user_id) + .await?; + + { + let db_b = tester_b.context.app_db.read().await.clone(); + let is_admin = sqlx::query_scalar!( + "SELECT is_group_admin FROM groups WHERE group_id = ?", + group_id + ) + .fetch_one(&db_b.pool) + .await?; + assert_eq!(is_admin, 1, "tester_b should still be admin"); + } + + Ok(()) +} + diff --git a/rust/tests/api/tester.rs b/rust/tests/api/tester.rs index 9f211122..f20fdf3b 100644 --- a/rust/tests/api/tester.rs +++ b/rust/tests/api/tester.rs @@ -1,4 +1,4 @@ -use libsignal_protocol::{GenericSignedPreKey, IdentityKeyPair, KeyPair, SignedPreKeyRecord}; +use libsignal_protocol::IdentityKeyPair; use rand::SeedableRng; use rust_lib_twonly::api::{ApiRuntime, Server}; use rust_lib_twonly::bridge::api::{ApiConnectionState, ServerResult}; @@ -6,7 +6,7 @@ use rust_lib_twonly::context::Context; use sha2::{Digest, Sha256}; use std::sync::Arc; use tempfile::TempDir; -use tokio::time::{sleep, Duration}; +use tokio::time::{Duration, sleep}; pub(crate) struct Tester { pub context: Arc, @@ -378,37 +378,10 @@ impl Tester { let mut csprng = rand::rngs::StdRng::from_os_rng(); let identity_pair = IdentityKeyPair::generate(&mut csprng); let registration_id: u32 = rand::Rng::random::(&mut csprng) & 0x7FFFFFFF; - let timestamp = libsignal_protocol::Timestamp::from_epoch_millis( - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() as u64, - ); - - let signed_pre_key_pair = KeyPair::generate(&mut csprng); - let signature = identity_pair - .private_key() - .calculate_signature_for_multipart_message( - &[&signed_pre_key_pair.public_key.serialize()], - &mut csprng, - ) - .map_err(|e| anyhow::anyhow!("Signal error: {}", e))?; - - let signed_prekey = - SignedPreKeyRecord::new(1.into(), timestamp, &signed_pre_key_pair, &signature); - let mut pre_key_store = std::collections::HashMap::new(); - pre_key_store.insert( - 1, - signed_prekey - .serialize() - .map_err(|e| anyhow::anyhow!("Signal error: {}", e))?, - ); - context .inject_test_signal_identity( identity_pair.serialize().to_vec(), registration_id as i64, - pre_key_store, ) .await?; } @@ -592,7 +565,9 @@ impl Tester { } sleep(Duration::from_millis(100)).await; } - Err(anyhow::anyhow!("message {message_id} was not marked as opened")) + Err(anyhow::anyhow!( + "message {message_id} was not marked as opened" + )) } pub async fn wait_for_group_chat_deletion_time( diff --git a/test/features/flame_counter_test.dart b/test/features/flame_counter_test.dart index e77d24f9..0b5a09a9 100644 --- a/test/features/flame_counter_test.dart +++ b/test/features/flame_counter_test.dart @@ -57,7 +57,7 @@ void main() { Future getAndCreateUserId() async { return mutex.protect(() async { final userId = usedUserIds += 1; - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion(userId: Value(userId), username: Value('$userId')), ); return userId; diff --git a/test/features/link_parser_test.dart b/test/features/link_parser_test.dart index b0d851cb..a68f34a5 100644 --- a/test/features/link_parser_test.dart +++ b/test/features/link_parser_test.dart @@ -81,9 +81,7 @@ void main() { url: 'https://x.com/netzpolitik_org/status/1162346968124968960', siteName: 'X (formerly Twitter)', desc: - 'Weil unsere Datenanalyse zum Twitter-Account von Maaßen rechte Millieus und ihre Verbindungen offengelegt hat, haben wir einen rechten Shitstorm an der Backe. Klar ist: Wir lassen uns nicht einschüchtern und freuen uns auf Unterstützung! \n' - '\n' - 'https://t.co/MQZ7ulHakF', + 'Weil unsere Datenanalyse zum Twitter-Account von Maaßen rechte Millieus und ihre Verbindungen offengelegt hat, haben wir einen rechten Shitstorm an der Backe. Klar ist: Wir lassen uns nicht einsch…', image: 'https://pbs.twimg.com/media/ECF8Z5KWwAIBZ6o.jpg:large', vendor: Vendor.twitterPosting, ), diff --git a/test/mocks/test_client.dart b/test/mocks/test_client.dart index f5718e10..54aef2c6 100644 --- a/test/mocks/test_client.dart +++ b/test/mocks/test_client.dart @@ -10,10 +10,7 @@ import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart' as pb; import 'package:twonly/src/services/api/api.service.dart'; -import 'package:twonly/src/services/api/messages.api.dart'; import 'package:twonly/src/services/api/rust_api_result.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/services/user.service.dart'; import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/utils/pow.dart'; @@ -52,19 +49,15 @@ class TestClient { api = ApiService(); await run(() async { - await createIfNotExistsSignalIdentity(); - - Log.info('Connecting to API...'); - final connected = await api.connect(); - Log.info('Connected: $connected'); - if (!connected) throw Exception('Failed to connect to API'); - Log.info('Requesting POW...'); - final pow = await rustApiProtobuf( - RustApi.getProofOfWork(), - decodeProofOfWork, - ); - if (pow == null) throw Exception('Failed to get POW'); + final dynamic pow; + try { + final raw = await RustApi.getProofOfWork(); + pow = decodeProofOfWork(raw); + } catch (e, st) { + print('POW EXCEPTION: $e\n$st'); + rethrow; + } Log.info('POW result: $pow'); final prefix = pow.prefix; @@ -87,15 +80,12 @@ class TestClient { appVersion: 100, ); await UserService.save(userData); - - await api.authenticate(); - await signalGetPreKeys(); }); } Future initContact(TestClient other) async { await run(() async { - await env.db.contactsDao.insertContact( + await env.db.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert( userId: Value(other.realUserId), username: other.username, @@ -107,12 +97,7 @@ class TestClient { GroupsCompanion(groupName: Value(other.username)), ); - final userData = await rustApiProtobuf( - RustApi.getUserById(userId: other.realUserId), - decodeUserData, - ); - final sessionStarted = await processSignalUserData(userData!); - if (!sessionStarted) throw Exception('Failed to start session'); + await RustApi.establishSignalSession(contactId: other.realUserId); }); } @@ -129,14 +114,14 @@ class TestClient { type: Value(MessageType.text.name), ), ); - await sendCipherText( - target.realUserId, - pb.EncryptedContent( + await RustApi.sendEncryptedContent( + contactId: target.realUserId, + content: pb.EncryptedContent( groupId: defaultGroup!.groupId, textMessage: pb.EncryptedContent_TextMessage() ..senderMessageId = m!.messageId ..text = text, - ), + ).writeToBuffer(), messageId: m.messageId, ); return m; @@ -148,7 +133,10 @@ class TestClient { pb.EncryptedContent content, ) async { await run(() async { - await sendCipherText(target.realUserId, content); + await RustApi.sendEncryptedContent( + contactId: target.realUserId, + content: content.writeToBuffer(), + ); }); } diff --git a/test/mocks/user_environment.dart b/test/mocks/user_environment.dart index eb411d5c..3d7ba690 100644 --- a/test/mocks/user_environment.dart +++ b/test/mocks/user_environment.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:drift/drift.dart' hide isNotNull, isNull; import 'package:drift/native.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/api/api.service.dart'; import 'package:twonly/src/services/user.service.dart'; @@ -67,15 +66,11 @@ class UserEnvironment { required this.username, required this.db, required this.userService, - required this.identityKeyPair, - required this.registrationId, }); final int userId; final String username; final TwonlyDB db; final UserService userService; - final IdentityKeyPair identityKeyPair; - final int registrationId; static Future create( int userId, @@ -101,16 +96,11 @@ class UserEnvironment { us.isUserCreated = true; - final identityKeyPair = generateIdentityKeyPair(); - final registrationId = generateRegistrationId(true); - return UserEnvironment( userId: userId, username: username, db: db, userService: us, - identityKeyPair: identityKeyPair, - registrationId: registrationId, ); } } diff --git a/test/rust/create_db_for_rust_testing.dart b/test/rust/create_db_for_rust_testing.dart index a9c308f6..64c8b09e 100644 --- a/test/rust/create_db_for_rust_testing.dart +++ b/test/rust/create_db_for_rust_testing.dart @@ -32,7 +32,7 @@ void main() { ]; for (var i = 0; i < users.length; i++) { - await database.contactsDao.insertContact( + await database.contactsDao.insertOnConflictUpdate( ContactsCompanion(userId: Value(i), username: Value(users[i])), ); } diff --git a/test/services/api_and_c2c_test.dart b/test/services/api_and_c2c_test.dart index a44fe2f5..b443151f 100644 --- a/test/services/api_and_c2c_test.dart +++ b/test/services/api_and_c2c_test.dart @@ -123,8 +123,8 @@ void main() { }); tearDown(() async { - await clientA.run(() async => clientA.api.close(null)); - await clientB.run(() async => clientB.api.close(null)); + await clientA.run(() async => clientA.api.dispose()); + await clientB.run(() async => clientB.api.dispose()); await clientA.env.db.close(); await clientB.env.db.close(); }); diff --git a/test/services/cloud_backup_test.dart b/test/services/cloud_backup_test.dart index a931cf45..34ca39e5 100644 --- a/test/services/cloud_backup_test.dart +++ b/test/services/cloud_backup_test.dart @@ -9,6 +9,7 @@ import 'package:twonly/core/bridge.dart' as bridge; import 'package:twonly/core/frb_generated.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; +import 'package:twonly/src/callbacks/callbacks.dart'; import 'package:twonly/src/database/tables/mediafiles.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/services/api/api.service.dart'; @@ -49,6 +50,7 @@ void main() { } else { await RustLib.init(); } + await initFlutterCallbacksForRust(); tempDir = Directory.systemTemp.createTempSync( 'twonly_cloud_backup_test_', ); diff --git a/test/services/key_verification_service_test.dart b/test/services/key_verification_service_test.dart index 7c62229d..99cb75fd 100644 --- a/test/services/key_verification_service_test.dart +++ b/test/services/key_verification_service_test.dart @@ -2,13 +2,14 @@ import 'dart:io'; import 'package:drift/drift.dart' hide isNotNull, isNull; import 'package:drift/native.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:twonly/core/frb_generated.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/database/daos/key_verification.dao.dart'; import 'package:twonly/src/database/tables/contacts.table.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/services/api/api.service.dart'; import 'package:twonly/src/services/user.service.dart'; import '../mocks/user_config.dart'; @@ -20,6 +21,18 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); + setUpAll(() async { + final dylibPath = + '${Directory.current.path}/rust/target/debug/librust_lib_twonly.dylib'; + if (File(dylibPath).existsSync()) { + await RustLib.init( + externalLibrary: ExternalLibrary.open(dylibPath), + ); + } else { + await RustLib.init(); + } + }); + setUp(() async { await locator.reset(); locator @@ -31,8 +44,7 @@ void main() { ), ), ) - ..registerSingleton(UserService()) - ..registerSingleton(ApiService()); + ..registerSingleton(UserService()); // isUserDiscoveryEnabled defaults to false, so no Rust bridge calls happen // in addKeyVerification / deleteKeyVerification. @@ -55,7 +67,7 @@ void main() { // ─── Helpers ──────────────────────────────────────────────────────────────── Future insertContact(int userId, {String? username}) async { - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert( userId: Value(userId), username: username ?? 'user$userId', diff --git a/test/services/passwordless_recovery_service_test.dart b/test/services/passwordless_recovery_service_test.dart index a67c7650..be13ba80 100644 --- a/test/services/passwordless_recovery_service_test.dart +++ b/test/services/passwordless_recovery_service_test.dart @@ -1,24 +1,18 @@ -import 'dart:convert' show utf8; import 'dart:io'; import 'package:drift/drift.dart' hide isNotNull, isNull; import 'package:drift/native.dart'; -import 'package:fixnum/fixnum.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:twonly/core/bridge.dart' as bridge; +import 'package:twonly/core/bridge/wrapper/signal.dart'; import 'package:twonly/core/frb_generated.dart'; import 'package:twonly/globals.dart'; import 'package:twonly/locator.dart'; import 'package:twonly/src/callbacks/callbacks.dart'; import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart' - as api_pb; import 'package:twonly/src/services/api/api.service.dart'; import 'package:twonly/src/services/passwordless_recovery.service.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; import 'package:twonly/src/services/user.service.dart'; import 'package:twonly/src/utils/log.dart'; @@ -89,8 +83,6 @@ void main() { ); userService.isUserCreated = true; await UserService.save(userService.currentUser); - - await createIfNotExistsSignalIdentity(); }); tearDown(() async { @@ -108,36 +100,20 @@ void main() { }); Future setupSignalSession(int contactId) async { - final identityKeyPair = generateIdentityKeyPair(); - final registrationId = generateRegistrationId(true); - final signedPreKey = generateSignedPreKey(identityKeyPair, 1); - final preKey = generatePreKeys(1, 1).first; - - final responseUserData = api_pb.Response_UserData() - ..userId = Int64(contactId) - ..username = utf8.encode('user_$contactId') - ..registrationId = Int64(registrationId) - ..publicIdentityKey = identityKeyPair.getPublicKey().serialize() - ..signedPrekey = signedPreKey.getKeyPair().publicKey.serialize() - ..signedPrekeyId = Int64(signedPreKey.id) - ..signedPrekeySignature = signedPreKey.signature; - - responseUserData.prekeys.add( - api_pb.Response_PreKey() - ..id = Int64(preKey.id) - ..prekey = preKey.getKeyPair().publicKey.serialize(), + final bundle = await RustSignal.generateBundle(); + await RustSignal.processPrekeyBundle( + name: contactId.toString(), + deviceId: 1, + bundle: bundle, ); - - final success = await processSignalUserData(responseUserData); - expect(success, isTrue); } group('PasswordlessRecoveryService - enablePasswordlessRecovery', () { test('works with SecondFactorType.none', () async { - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert(userId: const Value(2), username: 'friend_2'), ); - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert(userId: const Value(3), username: 'friend_3'), ); @@ -163,7 +139,7 @@ void main() { }); test('works with SecondFactorType.email', () async { - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert(userId: const Value(2), username: 'friend_2'), ); @@ -183,7 +159,7 @@ void main() { }); test('works with SecondFactorType.pin', () async { - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert(userId: const Value(2), username: 'friend_2'), ); @@ -203,20 +179,17 @@ void main() { }); test('sends delete messages to old trusted friends', () async { - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert( userId: const Value(2), username: 'friend_2', recoveryIsTrustedFriend: const Value(true), ), ); - await twonlyDB.contactsDao.insertContact( + await twonlyDB.contactsDao.insertOnConflictUpdate( ContactsCompanion.insert(userId: const Value(3), username: 'friend_3'), ); - await setupSignalSession(2); - await setupSignalSession(3); - final success = await PasswordlessRecoveryService.enablePasswordlessRecovery( trustedFriendIds: [3], diff --git a/test/signal/key_generation.dart b/test/signal/key_generation.dart deleted file mode 100644 index ae45c746..00000000 --- a/test/signal/key_generation.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; - -void main() { - group('testing api', () { - test('testing api connection', () async { - const offset = 100; - const count = 400; - - var prekeys = generatePreKeys(offset, count); - expect(count, prekeys.length); - - for (var i = 0; i < prekeys.length; i++) { - expect(prekeys[i].id, offset + i); - } - - prekeys += generatePreKeys(offset + count, count); - expect(count * 2, prekeys.length); - - for (var i = 0; i < (count * 2); i++) { - expect(prekeys[i].id, offset + i); - } - }); - }); -} diff --git a/test/signal/pqc_c2c_test.dart b/test/signal/pqc_c2c_test.dart deleted file mode 100644 index 014843a9..00000000 --- a/test/signal/pqc_c2c_test.dart +++ /dev/null @@ -1,220 +0,0 @@ -// ignore_for_file: avoid_print - -import 'dart:async'; -import 'dart:io'; - -import 'package:drift/drift.dart' hide isNotNull, isNull; -import 'package:flutter/services.dart'; -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:twonly/core/bridge.dart' as bridge; -import 'package:twonly/core/frb_generated.dart'; -import 'package:twonly/globals.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/callbacks/callbacks.dart'; -import 'package:twonly/src/database/tables/messages.table.dart'; -import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/services/api/api.service.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; -import 'package:twonly/src/services/user.service.dart'; -import 'package:workmanager/workmanager.dart'; - -import '../mocks/platform_channels.dart'; -import '../mocks/test_client.dart'; -import '../mocks/workmanager.dart'; - -void main() { - if (!Platform.isMacOS) { - return; - } - - TestWidgetsFlutterBinding.ensureInitialized(); - - late Directory tempDir; - - setUpAll(() async { - driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; - WorkmanagerPlatform.instance = MockWorkmanagerPlatform(); - tempDir = Directory.systemTemp.createTempSync('twonly_pqc_c2c_test_'); - AppEnvironment.initTesting( - customCacheDir: tempDir.path, - customSupportDir: tempDir.path, - ); - - final dylibPath = - '${Directory.current.path}/rust/target/debug/librust_lib_twonly.dylib'; - if (File(dylibPath).existsSync()) { - await RustLib.init(externalLibrary: ExternalLibrary.open(dylibPath)); - } else { - await RustLib.init(); - } - await initFlutterCallbacksForRust(); - - await bridge.initializeTwonlyFlutter( - config: bridge.InitConfig( - databaseDir: tempDir.path, - dataDir: tempDir.path, - ), - ); - - if (locator.isRegistered()) await locator.unregister(); - if (locator.isRegistered()) { - await locator.unregister(); - } - if (locator.isRegistered()) { - await locator.unregister(); - } - - locator - ..registerFactory(() { - final db = Zone.current[#twonlyDB] as TwonlyDB?; - if (db != null) return db; - throw StateError('No TwonlyDB in active Zone.'); - }) - ..registerFactory(() { - final us = Zone.current[#userService] as UserService?; - if (us != null) return us; - throw StateError('No UserService in active Zone.'); - }) - ..registerFactory(() { - final api = Zone.current[#apiService] as ApiService?; - if (api != null) return api; - throw StateError('No ApiService in active Zone.'); - }); - }); - - tearDownAll(() async { - if (tempDir.existsSync()) { - try { - tempDir.deleteSync(recursive: true); - } catch (_) {} - } - }); - - group('PQC C2C Migration Protocol Tests', () { - late TestClient clientA; - late TestClient clientB; - - setUp(() async { - setupPlatformChannelMocks(); - HttpOverrides.global = RealHttpOverrides(); - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( - const MethodChannel('dev.fluttercommunity.plus/package_info'), - (call) async { - return { - 'appName': 'twonly', - 'packageName': 'eu.twonly.app', - 'version': '1.0.0', - 'buildNumber': '100', - }; - }, - ); - await Workmanager().initialize(() {}); - - clientA = TestClient(3001); - clientB = TestClient(4002); - - // Initialize BOTH clients with PQC generation disabled. - await clientA.init(disablePqc: true); - await clientB.init(disablePqc: true); - - await clientA.initContact(clientB); - await clientB.initContact(clientA); - }); - - tearDown(() async { - await clientA.run(() async => clientA.api.close(null)); - await clientB.run(() async => clientB.api.close(null)); - await clientA.env.db.close(); - await clientB.env.db.close(); - }); - - test( - 'C2C: V1 to V2 PQC Migration and 100 Messages Exchange', - () async { - print('=== Starting V1 Message Exchange ==='); - - // Exchange 100 messages in V1 - for (var i = 0; i < 100; i++) { - final textAtoB = 'Hello Bob V1 - Message $i'; - await clientA.sendText(clientB, textAtoB); - final receivedByB = await clientB.expectMessage( - (m) => m.content == textAtoB && m.senderId == clientA.realUserId, - ); - expect(receivedByB.content, textAtoB); - expect(receivedByB.type, MessageType.text.name); - - final textBtoA = 'Hello Alice V1 - Reply $i'; - await clientB.sendText(clientA, textBtoA); - final receivedByA = await clientA.expectMessage( - (m) => m.content == textBtoA && m.senderId == clientB.realUserId, - ); - expect(receivedByA.content, textBtoA); - expect(receivedByA.type, MessageType.text.name); - } - - print('=== Migrating to V2 PQC ==='); - - // Step 2: Migrate to V2 - // For Client A - await clientA.run(() async { - await UserService.update((user) { - user.signalLastPqcPreKeysUploaded = null; - }); - await createIfNotExistsSignalIdentity(); // This will upload PQC keys - }); - - // For Client B - await clientB.run(() async { - await UserService.update((user) { - user.signalLastPqcPreKeysUploaded = null; - }); - await createIfNotExistsSignalIdentity(); // This will upload PQC keys - }); - - // Both clients now fetch the updated contacts from the dev server - // This will invoke processSignalUserData and migrate the signal version to V2 - await clientA.run(() async { - final userData = await rustApiProtobuf( - RustApi.getUserById(userId: clientB.realUserId), - decodeUserData, - ); - if (userData != null) await processSignalUserData(userData); - }); - await clientB.run(() async { - final userData = await rustApiProtobuf( - RustApi.getUserById(userId: clientA.realUserId), - decodeUserData, - ); - if (userData != null) await processSignalUserData(userData); - }); - - print('=== Starting V2 PQC Message Exchange ==='); - - // Step 3: Exchange 100 messages in V2 - for (var i = 0; i < 100; i++) { - final textAtoB = 'Hello Bob V2 PQC - Message $i'; - await clientA.sendText(clientB, textAtoB); - final receivedByB = await clientB.expectMessage( - (m) => m.content == textAtoB && m.senderId == clientA.realUserId, - ); - expect(receivedByB.content, textAtoB); - expect(receivedByB.type, MessageType.text.name); - - final textBtoA = 'Hello Alice V2 PQC - Reply $i'; - await clientB.sendText(clientA, textBtoA); - final receivedByA = await clientA.expectMessage( - (m) => m.content == textBtoA && m.senderId == clientB.realUserId, - ); - expect(receivedByA.content, textBtoA); - expect(receivedByA.type, MessageType.text.name); - } - - print('=== PQC Migration and Exchange Completed Successfully ==='); - }, - timeout: const Timeout(Duration(minutes: 5)), - ); - }); -} diff --git a/test/signal/pqc_migration_test.dart b/test/signal/pqc_migration_test.dart deleted file mode 100644 index 7246789b..00000000 --- a/test/signal/pqc_migration_test.dart +++ /dev/null @@ -1,182 +0,0 @@ -import 'dart:convert' show utf8; -import 'dart:io'; - -import 'package:drift/drift.dart' hide isNotNull, isNull; -import 'package:drift/native.dart'; -import 'package:fixnum/fixnum.dart'; -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:twonly/core/bridge.dart' as bridge; -import 'package:twonly/core/bridge/wrapper/key_manager.dart'; -import 'package:twonly/core/bridge/wrapper/signal.dart'; -import 'package:twonly/core/frb_generated.dart'; -import 'package:twonly/globals.dart'; -import 'package:twonly/locator.dart'; -import 'package:twonly/src/callbacks/callbacks.dart'; -import 'package:twonly/src/database/tables/contacts.table.dart'; -import 'package:twonly/src/database/twonly.db.dart'; -import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart' - as api_pb; -import 'package:twonly/src/model/protobuf/client/generated/messages.pb.dart' - as msg_pb; -import 'package:twonly/src/services/signal/encryption.signal.dart'; -import 'package:twonly/src/services/signal/identity.signal.dart'; -import 'package:twonly/src/services/signal/session.signal.dart'; -import 'package:twonly/src/utils/log.dart'; - -void main() { - if (!Platform.isMacOS) { - return; - } - - TestWidgetsFlutterBinding.ensureInitialized(); - late Directory tempDir; - late TwonlyDB db; - - setUpAll(() async { - Log.init(); - driftRuntimeOptions.dontWarnAboutMultipleDatabases = true; - final dylibPath = - '${Directory.current.path}/rust/target/debug/librust_lib_twonly.dylib'; - if (File(dylibPath).existsSync()) { - await RustLib.init(externalLibrary: ExternalLibrary.open(dylibPath)); - } else { - await RustLib.init(); - } - await initFlutterCallbacksForRust(); - - tempDir = Directory.systemTemp.createTempSync('twonly_pqc_migration_test_'); - AppEnvironment.initTesting( - customCacheDir: tempDir.path, - customSupportDir: tempDir.path, - ); - - await bridge.initializeTwonlyFlutter( - config: bridge.InitConfig( - databaseDir: tempDir.path, - dataDir: tempDir.path, - ), - ); - - db = TwonlyDB(NativeDatabase.memory()); - locator.registerFactory(() => db); - }); - - setUp(() async { - await createIfNotExistsSignalIdentity(); - await RustKeyManager.setUserId(userId: 1); - }); - - tearDownAll(() async { - await db.close(); - if (tempDir.existsSync()) { - try { - tempDir.deleteSync(recursive: true); - } catch (_) {} - } - }); - - test('PQC Migration Test: V1 to V2', () async { - const contactId = 999; - - // 1. Setup contact as V1 - await db.contactsDao.insertContact( - ContactsCompanion.insert( - userId: const Value(contactId), - username: 'test_pqc_user', - accepted: const Value(true), - signalVersion: const Value(SignalVersion.v1), - ), - ); - - var contact = await db.contactsDao.getContactById(contactId); - expect(contact, isNotNull); - expect(contact!.signalVersion, SignalVersion.v1); - - // 2. Generate a valid PQC bundle via RustSignal - final generatedBundle = await RustSignal.generateBundle(); - - final userData = api_pb.Response_UserData( - userId: Int64(contactId), - username: utf8.encode('test_pqc_user'), - registrationId: Int64(generatedBundle.registrationId), - publicIdentityKey: generatedBundle.identityKey, - pqcBundle: api_pb.Response_PqcBundle( - prekey: api_pb.Response_PqcPreKey( - eccPreKeyId: generatedBundle.preKeyId != null - ? Int64(generatedBundle.preKeyId!) - : null, - eccPreKey: generatedBundle.preKeyPublic, - kyberPreKeyId: Int64(generatedBundle.kyberPreKeyId), - kyberPreKey: generatedBundle.kyberPreKeyPublic, - kyberPreKeySignature: generatedBundle.kyberPreKeySignature, - ), - eccSignedPrekeyId: Int64(generatedBundle.signedPreKeyId), - eccSignedPrekey: generatedBundle.signedPreKeyPublic, - eccSignedPrekeySignature: generatedBundle.signedPreKeySignature, - ), - ); - - // 3. Process the UserData containing the PQC bundle - final success = await processSignalUserData(userData); - expect(success, isTrue, reason: 'Failed to process PQC user data'); - - // 4. Verify contact was upgraded to V2 - contact = await db.contactsDao.getContactById(contactId); - expect(contact, isNotNull); - expect(contact!.signalVersion, SignalVersion.v2); - }); - - test('PQC Encryption and Decryption V2', () async { - const contactId = 888; - - // Setup contact as V2 - await db.contactsDao.insertContact( - ContactsCompanion.insert( - userId: const Value(contactId), - username: 'test_pqc_user_2', - accepted: const Value(true), - signalVersion: const Value(SignalVersion.v2), - ), - ); - - // Generate bundle and process it for the contact to establish a session - final generatedBundle = await RustSignal.generateBundle(); - - final userData = api_pb.Response_UserData( - userId: Int64(contactId), - username: utf8.encode('test_pqc_user_2'), - registrationId: Int64(generatedBundle.registrationId), - publicIdentityKey: generatedBundle.identityKey, - pqcBundle: api_pb.Response_PqcBundle( - prekey: api_pb.Response_PqcPreKey( - eccPreKeyId: generatedBundle.preKeyId != null - ? Int64(generatedBundle.preKeyId!) - : null, - eccPreKey: generatedBundle.preKeyPublic, - kyberPreKeyId: Int64(generatedBundle.kyberPreKeyId), - kyberPreKey: generatedBundle.kyberPreKeyPublic, - kyberPreKeySignature: generatedBundle.kyberPreKeySignature, - ), - eccSignedPrekeyId: Int64(generatedBundle.signedPreKeyId), - eccSignedPrekey: generatedBundle.signedPreKeyPublic, - eccSignedPrekeySignature: generatedBundle.signedPreKeySignature, - ), - ); - - final success = await processSignalUserData(userData); - expect(success, isTrue); - - // Encrypt a message - final plaintext = msg_pb.EncryptedContent( - textMessage: msg_pb.EncryptedContent_TextMessage( - text: 'Hello PQC World!', - ), - ).writeToBuffer(); - - final encryptedResult = await signalEncryptMessageV2(contactId, plaintext); - expect(encryptedResult, isNotNull); - expect(encryptedResult!.type, msg_pb.Message_Type.CIPHERTEXT_V2); - expect(encryptedResult.ciphertext, isNotEmpty); - }); -}