@wireapp/core 46.46.6-beta.10.d7a6c4c53 → 46.46.6-beta.14.f6fd03fe6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Account.d.ts +51 -168
- package/lib/Account.d.ts.map +1 -1
- package/lib/Account.js +127 -517
- package/lib/Account.test.js +147 -158
- package/lib/broadcast/AvailabilityType.d.ts +1 -1
- package/lib/broadcast/AvailabilityType.d.ts.map +1 -1
- package/lib/broadcast/BroadcastService.d.ts +1 -1
- package/lib/broadcast/BroadcastService.d.ts.map +1 -1
- package/lib/broadcast/BroadcastService.js +1 -1
- package/lib/client/ClientService.d.ts +3 -4
- package/lib/client/ClientService.d.ts.map +1 -1
- package/lib/client/ClientService.js +5 -19
- package/lib/conversation/AbortReason.d.ts +1 -1
- package/lib/conversation/AbortReason.d.ts.map +1 -1
- package/lib/conversation/AssetService/AssetService.d.ts +30 -12
- package/lib/conversation/AssetService/AssetService.d.ts.map +1 -1
- package/lib/conversation/AssetService/AssetService.js +10 -1
- package/lib/conversation/AssetService/AssetService.test.js +3 -8
- package/lib/conversation/ClientActionType.d.ts +1 -1
- package/lib/conversation/ClientActionType.d.ts.map +1 -1
- package/lib/conversation/ClientActionType.js +1 -1
- package/lib/conversation/ConversationService/ConversationService.d.ts +14 -98
- package/lib/conversation/ConversationService/ConversationService.d.ts.map +1 -1
- package/lib/conversation/ConversationService/ConversationService.js +101 -314
- package/lib/conversation/ConversationService/ConversationService.test.js +47 -441
- package/lib/conversation/ConversationService/ConversationService.types.d.ts +4 -5
- package/lib/conversation/ConversationService/ConversationService.types.d.ts.map +1 -1
- package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts.map +1 -1
- package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.js +3 -6
- package/lib/conversation/SubconversationService/SubconversationService.d.ts.map +1 -1
- package/lib/conversation/SubconversationService/SubconversationService.js +11 -158
- package/lib/conversation/SubconversationService/SubconversationService.test.js +2 -8
- package/lib/conversation/content/AssetContent.d.ts +1 -1
- package/lib/conversation/content/AssetContent.d.ts.map +1 -1
- package/lib/conversation/content/ButtonActionConfirmationContent.d.ts +1 -1
- package/lib/conversation/content/ButtonActionConfirmationContent.d.ts.map +1 -1
- package/lib/conversation/content/ButtonActionContent.d.ts +1 -1
- package/lib/conversation/content/ButtonActionContent.d.ts.map +1 -1
- package/lib/conversation/content/ClearedContent.d.ts +1 -1
- package/lib/conversation/content/ClearedContent.d.ts.map +1 -1
- package/lib/conversation/content/ClientActionContent.d.ts +1 -1
- package/lib/conversation/content/ClientActionContent.d.ts.map +1 -1
- package/lib/conversation/content/CompositeContent.d.ts +1 -1
- package/lib/conversation/content/CompositeContent.d.ts.map +1 -1
- package/lib/conversation/content/ConfirmationContent.d.ts +1 -1
- package/lib/conversation/content/ConfirmationContent.d.ts.map +1 -1
- package/lib/conversation/content/DeletedContent.d.ts +1 -1
- package/lib/conversation/content/DeletedContent.d.ts.map +1 -1
- package/lib/conversation/content/HiddenContent.d.ts +1 -1
- package/lib/conversation/content/HiddenContent.d.ts.map +1 -1
- package/lib/conversation/content/KnockContent.d.ts +1 -1
- package/lib/conversation/content/KnockContent.d.ts.map +1 -1
- package/lib/conversation/content/LinkPreviewContent.d.ts +1 -1
- package/lib/conversation/content/LinkPreviewContent.d.ts.map +1 -1
- package/lib/conversation/content/MentionContent.d.ts +1 -1
- package/lib/conversation/content/MentionContent.d.ts.map +1 -1
- package/lib/conversation/content/MultipartContent.d.ts +1 -1
- package/lib/conversation/content/MultipartContent.d.ts.map +1 -1
- package/lib/conversation/content/QuoteContent.d.ts +1 -1
- package/lib/conversation/content/QuoteContent.d.ts.map +1 -1
- package/lib/conversation/content/TweetContent.d.ts +1 -1
- package/lib/conversation/content/TweetContent.d.ts.map +1 -1
- package/lib/conversation/content/index.d.ts +1 -1
- package/lib/conversation/content/index.d.ts.map +1 -1
- package/lib/conversation/content/index.js +1 -1
- package/lib/conversation/message/MessageBuilder.d.ts +1 -1
- package/lib/conversation/message/MessageBuilder.d.ts.map +1 -1
- package/lib/conversation/message/MessageBuilder.js +1 -1
- package/lib/conversation/message/MessageService.d.ts.map +1 -1
- package/lib/conversation/message/MessageService.js +1 -1
- package/lib/conversation/message/MessageService.test.js +1 -7
- package/lib/conversation/message/MessageToProtoMapper.d.ts +1 -1
- package/lib/conversation/message/MessageToProtoMapper.d.ts.map +1 -1
- package/lib/conversation/message/MessageToProtoMapper.js +1 -1
- package/lib/conversation/message/messageSender.js +2 -2
- package/lib/cryptography/AssetCryptography/EncryptedAsset.d.ts +2 -2
- package/lib/cryptography/AssetCryptography/EncryptedAsset.d.ts.map +1 -1
- package/lib/messagingProtocols/common.types.d.ts +0 -9
- package/lib/messagingProtocols/common.types.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIService.types.d.ts +2 -2
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIService.types.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIService.types.js +1 -2
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.d.ts +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.js +11 -13
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.test.js +16 -21
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.d.ts +3 -9
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.js +12 -31
- package/lib/messagingProtocols/mls/E2EIdentityService/Helper/index.d.ts +0 -6
- package/lib/messagingProtocols/mls/E2EIdentityService/Helper/index.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Helper/index.js +1 -19
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingMessagesQueue/IncomingMesssagesQueue.d.ts +4 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingMessagesQueue/IncomingMesssagesQueue.d.ts.map +1 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingMessagesQueue/IncomingMesssagesQueue.js +69 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingMessagesQueue/index.d.ts +2 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/{IncomingProposalsQueue → IncomingMessagesQueue}/index.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/{IncomingProposalsQueue → IncomingMessagesQueue}/index.js +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/index.d.ts +1 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/index.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/index.js +1 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.js +14 -23
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.test.d.ts +2 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.test.d.ts.map +1 -0
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.test.js +98 -0
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.js +2 -5
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.test.js +3 -13
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.d.ts +2 -38
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.js +6 -41
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts +34 -38
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/MLSService/MLSService.js +208 -267
- package/lib/messagingProtocols/mls/MLSService/MLSService.test.js +160 -157
- package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.js +3 -3
- package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.test.js +5 -5
- package/lib/messagingProtocols/mls/conversationRejoinQueue.js +2 -2
- package/lib/messagingProtocols/mls/types.d.ts +8 -0
- package/lib/messagingProtocols/mls/types.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/EventHandler/events/otrMessageAdd/otrMessageAdd.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/EventHandler/events/otrMessageAdd/otrMessageAdd.js +1 -7
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts +15 -8
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.js +62 -97
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts +6 -0
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/DecryptionErrorGenerator/DecryptionErrorGenerator.d.ts +6 -1
- package/lib/messagingProtocols/proteus/ProteusService/DecryptionErrorGenerator/DecryptionErrorGenerator.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/DecryptionErrorGenerator/DecryptionErrorGenerator.js +22 -19
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts +3 -5
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.js +24 -11
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts +0 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.js +2 -11
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.test.js +9 -13
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.types.d.ts +2 -3
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.types.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/WithMockedGenerics.test.js +4 -11
- package/lib/messagingProtocols/proteus/ProteusService/cryptoMigrationStateStore.d.ts +4 -0
- package/lib/messagingProtocols/proteus/ProteusService/cryptoMigrationStateStore.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/cryptoMigrationStateStore.js +5 -0
- package/lib/messagingProtocols/proteus/ProteusService/identityClearer.d.ts +1 -2
- package/lib/messagingProtocols/proteus/ProteusService/identityClearer.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/identityClearer.js +2 -8
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.test.js +0 -4
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts +1 -1
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.js +1 -1
- package/lib/notification/NotificationService.d.ts +6 -20
- package/lib/notification/NotificationService.d.ts.map +1 -1
- package/lib/notification/NotificationService.js +14 -23
- package/lib/notification/NotificationService.test.js +0 -8
- package/lib/secretStore/secretKeyGenerator.d.ts +0 -1
- package/lib/secretStore/secretKeyGenerator.d.ts.map +1 -1
- package/lib/secretStore/secretKeyGenerator.js +1 -3
- package/lib/self/SelfService.d.ts +2 -2
- package/lib/self/SelfService.d.ts.map +1 -1
- package/lib/self/SelfService.test.js +2 -5
- package/lib/team/TeamService.d.ts +2 -5
- package/lib/team/TeamService.d.ts.map +1 -1
- package/lib/team/TeamService.js +2 -12
- package/lib/user/UserService.d.ts +2 -2
- package/lib/user/UserService.d.ts.map +1 -1
- package/lib/user/UserService.js +3 -3
- package/lib/util/TypePredicateUtil.d.ts.map +1 -1
- package/lib/util/TypePredicateUtil.js +2 -2
- package/package.json +3 -3
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingProposalsQueue/IncomingProposalsQueue.d.ts +0 -7
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingProposalsQueue/IncomingProposalsQueue.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingProposalsQueue/IncomingProposalsQueue.js +0 -48
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingProposalsQueue/index.d.ts +0 -2
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.test.d.ts +0 -2
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.test.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.test.js +0 -124
- package/lib/messagingProtocols/mls/recovery/MlsErrorMapper.d.ts +0 -78
- package/lib/messagingProtocols/mls/recovery/MlsErrorMapper.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/recovery/MlsErrorMapper.js +0 -173
- package/lib/messagingProtocols/mls/recovery/MlsErrorMapper.test.d.ts +0 -2
- package/lib/messagingProtocols/mls/recovery/MlsErrorMapper.test.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/recovery/MlsErrorMapper.test.js +0 -117
- package/lib/messagingProtocols/mls/recovery/MlsRecoveryOrchestrator.d.ts +0 -167
- package/lib/messagingProtocols/mls/recovery/MlsRecoveryOrchestrator.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/recovery/MlsRecoveryOrchestrator.js +0 -317
- package/lib/messagingProtocols/mls/recovery/MlsRecoveryOrchestrator.test.d.ts +0 -2
- package/lib/messagingProtocols/mls/recovery/MlsRecoveryOrchestrator.test.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/recovery/MlsRecoveryOrchestrator.test.js +0 -248
- package/lib/messagingProtocols/mls/recovery/index.d.ts +0 -5
- package/lib/messagingProtocols/mls/recovery/index.d.ts.map +0 -1
- package/lib/messagingProtocols/mls/recovery/index.js +0 -28
- package/lib/test/StoreHelper.d.ts +0 -2
- package/lib/test/StoreHelper.d.ts.map +0 -1
- package/lib/test/StoreHelper.js +0 -27
|
@@ -19,17 +19,16 @@
|
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.ConversationService = void 0;
|
|
22
|
+
const protocol_messaging_1 = require("@pydio/protocol-messaging");
|
|
22
23
|
const conversation_1 = require("@wireapp/api-client/lib/conversation");
|
|
23
24
|
const data_1 = require("@wireapp/api-client/lib/conversation/data");
|
|
24
25
|
const event_1 = require("@wireapp/api-client/lib/event");
|
|
25
|
-
const
|
|
26
|
+
const http_1 = require("@wireapp/api-client/lib/http");
|
|
26
27
|
const bazinga64_1 = require("bazinga64");
|
|
27
28
|
const commons_1 = require("@wireapp/commons");
|
|
28
|
-
const core_crypto_1 = require("@wireapp/core-crypto");
|
|
29
|
-
const protocol_messaging_1 = require("@wireapp/protocol-messaging");
|
|
30
29
|
const conversation_2 = require("../../conversation/");
|
|
31
|
-
const
|
|
32
|
-
const
|
|
30
|
+
const conversationRejoinQueue_1 = require("../../messagingProtocols/mls/conversationRejoinQueue");
|
|
31
|
+
const CoreCryptoMLSError_1 = require("../../messagingProtocols/mls/MLSService/CoreCryptoMLSError");
|
|
33
32
|
const proteus_1 = require("../../messagingProtocols/proteus");
|
|
34
33
|
const util_1 = require("../../util");
|
|
35
34
|
const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
|
|
@@ -40,44 +39,18 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
40
39
|
coreDatabase;
|
|
41
40
|
groupIdFromConversationId;
|
|
42
41
|
subconversationService;
|
|
43
|
-
isMLSConversationRecoveryEnabled;
|
|
44
42
|
_mlsService;
|
|
45
43
|
messageTimer;
|
|
46
44
|
logger = commons_1.LogFactory.getLogger('@wireapp/core/ConversationService');
|
|
47
|
-
|
|
48
|
-
groupIdConversationMap = new Map();
|
|
49
|
-
MLSRecoveryOrchestrator;
|
|
50
|
-
constructor(apiClient, proteusService, coreDatabase, groupIdFromConversationId, subconversationService, isMLSConversationRecoveryEnabled, _mlsService) {
|
|
45
|
+
constructor(apiClient, proteusService, coreDatabase, groupIdFromConversationId, subconversationService, _mlsService) {
|
|
51
46
|
super();
|
|
52
47
|
this.apiClient = apiClient;
|
|
53
48
|
this.proteusService = proteusService;
|
|
54
49
|
this.coreDatabase = coreDatabase;
|
|
55
50
|
this.groupIdFromConversationId = groupIdFromConversationId;
|
|
56
51
|
this.subconversationService = subconversationService;
|
|
57
|
-
this.isMLSConversationRecoveryEnabled = isMLSConversationRecoveryEnabled;
|
|
58
52
|
this._mlsService = _mlsService;
|
|
59
53
|
this.messageTimer = new conversation_2.MessageTimer();
|
|
60
|
-
// Make MLS recovery orchestrator mandatory in this service
|
|
61
|
-
if (!this._mlsService) {
|
|
62
|
-
throw new Error('MLSService is required to construct ConversationService with MLS capabilities');
|
|
63
|
-
}
|
|
64
|
-
this.mlsService.on(mls_1.MLSServiceEvents.MLS_EVENT_DISTRIBUTED, data => {
|
|
65
|
-
this.emit(mls_1.MLSServiceEvents.MLS_EVENT_DISTRIBUTED, data);
|
|
66
|
-
});
|
|
67
|
-
this.mlsService.on(mls_1.MLSServiceEvents.KEY_MATERIAL_UPDATE_FAILURE, ({ error, groupId }) => {
|
|
68
|
-
this.logger.warn(`Key material update failure for group ${groupId}`, { error });
|
|
69
|
-
return this.reactToKeyMaterialUpdateFailure({ error, groupId });
|
|
70
|
-
});
|
|
71
|
-
// Initialize MLS recovery orchestrator with default policies and single-flight de-duplication
|
|
72
|
-
const mapper = (0, recovery_1.createDefaultMlsErrorMapper)();
|
|
73
|
-
this.MLSRecoveryOrchestrator = new recovery_1.MlsRecoveryOrchestratorImpl(mapper, recovery_1.minimalDefaultPolicies, {
|
|
74
|
-
// Call the low-level API to avoid nested recovery when orchestrator triggers an external commit join
|
|
75
|
-
joinViaExternalCommit: (conversationId) => this.performJoinByExternalCommitAPI(conversationId),
|
|
76
|
-
resetAndReestablish: (conversationId) => this.handleBrokenMLSConversation(conversationId),
|
|
77
|
-
recoverFromEpochMismatch: (conversationId, subconvId) => this.recoverMLSGroupFromEpochMismatch(conversationId, subconvId),
|
|
78
|
-
addMissingUsers: (conversationId, groupId, users) => this.performAddUsersToMLSConversationAPI({ conversationId, groupId, qualifiedUsers: users }),
|
|
79
|
-
wipeMLSConversation: this.wipeMLSConversation,
|
|
80
|
-
});
|
|
81
54
|
}
|
|
82
55
|
get mlsService() {
|
|
83
56
|
if (!this._mlsService) {
|
|
@@ -143,7 +116,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
143
116
|
*/
|
|
144
117
|
async send(params) {
|
|
145
118
|
function isMLS(params) {
|
|
146
|
-
return params.protocol ===
|
|
119
|
+
return params.protocol === conversation_1.ConversationProtocol.MLS;
|
|
147
120
|
}
|
|
148
121
|
return (0, messageSender_1.sendMessage)(() => (isMLS(params) ? this.sendMLSMessage(params) : this.proteusService.sendMessage(params)));
|
|
149
122
|
}
|
|
@@ -224,71 +197,42 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
224
197
|
if (!groupId) {
|
|
225
198
|
throw new Error('No group_id found in response which is required for creating MLS conversations.');
|
|
226
199
|
}
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Centralized handler for scenarios where an MLS conversation is detected as broken.
|
|
231
|
-
* It resets the conversation and then invokes the provided callback so callers can retry
|
|
232
|
-
* their original operation (e.g., re-adding/removing users, re-joining, etc.) with the new group id.
|
|
233
|
-
*
|
|
234
|
-
* Contract:
|
|
235
|
-
* - input: conversationId to reset; callback invoked after reset with the new group id
|
|
236
|
-
* - output: the value returned by the callback
|
|
237
|
-
* - error: throws if reset fails or new group id is missing
|
|
238
|
-
*/
|
|
239
|
-
async handleBrokenMLSConversation(conversationId) {
|
|
240
|
-
if (!(await this.isMLSConversationRecoveryEnabled())) {
|
|
241
|
-
throw new Error('MLS conversation recovery is disabled');
|
|
242
|
-
}
|
|
243
|
-
const { conversation: { group_id: newGroupId }, } = await this.resetMLSConversation(conversationId);
|
|
244
|
-
if (!newGroupId) {
|
|
245
|
-
const errorMessage = 'Tried to reset MLS conversation but no group_id found in response';
|
|
246
|
-
this.logger.error(errorMessage, { conversationId });
|
|
247
|
-
throw new Error(errorMessage);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Will create a conversation on backend and register it to CoreCrypto once created
|
|
252
|
-
* @param conversationData
|
|
253
|
-
*/
|
|
254
|
-
async establishMLSGroupConversation(groupId, userIdsToAdd, selfUserId, selfClientId, conversationQualifiedId) {
|
|
255
|
-
const failures = await this.mlsService.registerConversation(groupId, userIdsToAdd.concat(selfUserId), {
|
|
200
|
+
const { events, failures } = await this.mlsService.registerConversation(groupId, qualifiedUsers.concat(selfUserId), {
|
|
256
201
|
creator: {
|
|
257
202
|
user: selfUserId,
|
|
258
203
|
client: selfClientId,
|
|
259
204
|
},
|
|
260
205
|
});
|
|
261
206
|
// We fetch the fresh version of the conversation created on backend with the newly added users
|
|
262
|
-
const conversation = await this.apiClient.api.conversation.getConversation(
|
|
207
|
+
const conversation = await this.apiClient.api.conversation.getConversation(qualifiedId);
|
|
263
208
|
return {
|
|
209
|
+
events,
|
|
264
210
|
conversation,
|
|
265
211
|
failedToAdd: failures,
|
|
266
212
|
};
|
|
267
213
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
*
|
|
271
|
-
* Uses the MLS recovery orchestrator to handle transient MLS errors (for example, wrong epoch)
|
|
272
|
-
* according to per-operation policies. When configured, the original send is retried once
|
|
273
|
-
* after a successful recovery. Unrecoverable errors are re-thrown by the orchestrator.
|
|
274
|
-
* The low-level send logic lives in {@link performSendMLSMessageAPI}.
|
|
275
|
-
*/
|
|
276
|
-
async sendMLSMessage(params) {
|
|
277
|
-
const { groupId, conversationId } = params;
|
|
278
|
-
return this.MLSRecoveryOrchestrator.execute({
|
|
279
|
-
context: { operationName: recovery_1.OperationName.send, qualifiedConversationId: conversationId, groupId },
|
|
280
|
-
callBack: () => this.performSendMLSMessageAPI(params),
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
// Low-level API for sending an MLS message without any recovery logic
|
|
284
|
-
async performSendMLSMessageAPI(params) {
|
|
285
|
-
const { payload, groupId } = params;
|
|
214
|
+
async sendMLSMessage(params, shouldRetry = true) {
|
|
215
|
+
const { payload, groupId, conversationId } = params;
|
|
286
216
|
const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
|
|
287
217
|
// immediately execute pending commits before sending the message
|
|
288
|
-
await this.mlsService.commitPendingProposals(groupId
|
|
289
|
-
const encrypted = await this.mlsService.encryptMessage(
|
|
290
|
-
|
|
291
|
-
|
|
218
|
+
await this.mlsService.commitPendingProposals(groupId);
|
|
219
|
+
const encrypted = await this.mlsService.encryptMessage(groupIdBytes, protocol_messaging_1.GenericMessage.encode(payload).finish());
|
|
220
|
+
let response = null;
|
|
221
|
+
let sentAt = '';
|
|
222
|
+
try {
|
|
223
|
+
response = await this.apiClient.api.conversation.postMlsMessage(encrypted);
|
|
224
|
+
sentAt = response.time?.length > 0 ? response.time : new Date().toISOString();
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
const isMLSStaleMessageError = error instanceof http_1.BackendError && error.label === http_1.BackendErrorLabel.MLS_STALE_MESSAGE;
|
|
228
|
+
if (isMLSStaleMessageError) {
|
|
229
|
+
await this.recoverMLSGroupFromEpochMismatch(conversationId);
|
|
230
|
+
if (shouldRetry) {
|
|
231
|
+
return this.sendMLSMessage(params, false);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
292
236
|
const failedToSend = response?.failed || (response?.failed_to_send ?? []).length > 0
|
|
293
237
|
? {
|
|
294
238
|
queued: response?.failed_to_send,
|
|
@@ -303,166 +247,40 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
303
247
|
};
|
|
304
248
|
}
|
|
305
249
|
/**
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
* Claims key packages and passes them to CoreCrypto.addClientsToConversation. The MLS recovery
|
|
309
|
-
* orchestrator handles recoverable failures (e.g., wrong epoch) and may retry the operation once
|
|
310
|
-
* depending on policy. The optional shouldRetry flag is ignored; retries are governed by policies.
|
|
250
|
+
* Will add users to existing MLS group by claiming their key packages and passing them to CoreCrypto.addClientsToConversation
|
|
311
251
|
*
|
|
312
|
-
* @param qualifiedUsers List of qualified user ids (
|
|
313
|
-
* @param groupId Id of the
|
|
314
|
-
* @param conversationId
|
|
252
|
+
* @param qualifiedUsers List of qualified user ids (with optional skipOwnClientId field - if provided we will not claim key package for this self client)
|
|
253
|
+
* @param groupId Id of the group to which we want to add users
|
|
254
|
+
* @param conversationId Id of the conversation to which we want to add users
|
|
315
255
|
*/
|
|
316
256
|
async addUsersToMLSConversation({ qualifiedUsers, groupId, conversationId, }) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
// Low-level API to add users without any recovery logic; used by orchestrator and direct callers
|
|
323
|
-
async performAddUsersToMLSConversationAPI({ qualifiedUsers, groupId, conversationId, }) {
|
|
324
|
-
this.logger.info(`Adding users to MLS conversation`, { groupId, conversationId, qualifiedUsers });
|
|
325
|
-
const exisitingClientIdsInGroup = await this.mlsService.getClientIdsInGroup(groupId);
|
|
257
|
+
const { keyPackages, failures: keysClaimingFailures } = await this.mlsService.getKeyPackagesPayload(qualifiedUsers);
|
|
258
|
+
const { events, failures } = keyPackages.length > 0
|
|
259
|
+
? await this.mlsService.addUsersToExistingConversation(groupId, keyPackages)
|
|
260
|
+
: { events: [], failures: [] };
|
|
326
261
|
const conversation = await this.getConversation(conversationId);
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (keyPackages && keyPackages?.length > 0) {
|
|
330
|
-
await this.mlsService.addUsersToExistingConversation(groupId, keyPackages);
|
|
331
|
-
// We store the info when user was added (and key material was created), so we will know when to renew it
|
|
332
|
-
await this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
333
|
-
}
|
|
262
|
+
//We store the info when user was added (and key material was created), so we will know when to renew it
|
|
263
|
+
await this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
334
264
|
return {
|
|
265
|
+
events,
|
|
335
266
|
conversation,
|
|
336
|
-
failedToAdd: keysClaimingFailures,
|
|
267
|
+
failedToAdd: [...keysClaimingFailures, ...failures],
|
|
337
268
|
};
|
|
338
269
|
}
|
|
339
|
-
/**
|
|
340
|
-
* Remove users from an existing MLS group with recovery.
|
|
341
|
-
*
|
|
342
|
-
* The MLS recovery orchestrator handles recoverable failures and may retry the operation once
|
|
343
|
-
* depending on policy. The optional shouldRetry flag is ignored; retries are policy-driven.
|
|
344
|
-
*/
|
|
345
270
|
async removeUsersFromMLSConversation({ groupId, conversationId, qualifiedUserIds, }) {
|
|
346
|
-
return this.MLSRecoveryOrchestrator.execute({
|
|
347
|
-
context: { operationName: recovery_1.OperationName.removeUsers, qualifiedConversationId: conversationId, groupId },
|
|
348
|
-
callBack: () => this.performRemoveUsersFromMLSConversationAPI({ groupId, conversationId, qualifiedUserIds }),
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
// Low-level API to remove users without recovery logic; used by orchestrator and direct callers
|
|
352
|
-
async performRemoveUsersFromMLSConversationAPI({ groupId, conversationId, qualifiedUserIds, }) {
|
|
353
271
|
const clientsToRemove = await this.apiClient.api.user.postListClients({ qualified_users: qualifiedUserIds });
|
|
354
272
|
const fullyQualifiedClientIds = (0, fullyQualifiedClientIdUtils_1.mapQualifiedUserClientIdsToFullyQualifiedClientIds)(clientsToRemove.qualified_user_map);
|
|
355
|
-
await this.mlsService.removeClientsFromConversation(groupId, fullyQualifiedClientIds);
|
|
356
|
-
//
|
|
273
|
+
const messageResponse = await this.mlsService.removeClientsFromConversation(groupId, fullyQualifiedClientIds);
|
|
274
|
+
//key material gets updated after removing a user from the group, so we can reset last key update time value in the store
|
|
357
275
|
await this.mlsService.resetKeyMaterialRenewal(groupId);
|
|
358
|
-
|
|
276
|
+
const conversation = await this.getConversation(conversationId);
|
|
277
|
+
return {
|
|
278
|
+
events: messageResponse.events,
|
|
279
|
+
conversation,
|
|
280
|
+
};
|
|
359
281
|
}
|
|
360
|
-
/**
|
|
361
|
-
* Join an MLS conversation via external commit with recovery.
|
|
362
|
-
*
|
|
363
|
-
* If the group is not established or is out of date, the orchestrator recovers accordingly.
|
|
364
|
-
* The join operation itself is not automatically re-run by policy.
|
|
365
|
-
*/
|
|
366
282
|
async joinByExternalCommit(conversationId) {
|
|
367
|
-
|
|
368
|
-
context: { operationName: recovery_1.OperationName.joinExternalCommit, qualifiedConversationId: conversationId },
|
|
369
|
-
callBack: () => this.performJoinByExternalCommitAPI(conversationId),
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
// Low-level API call for joining via external commit (no recovery logic)
|
|
373
|
-
async performJoinByExternalCommitAPI(conversationId) {
|
|
374
|
-
await this.mlsService.joinByExternalCommit(() => this.apiClient.api.conversation.getGroupInfo(conversationId));
|
|
375
|
-
}
|
|
376
|
-
async refreshGroupIdConversationMap() {
|
|
377
|
-
const conversations = await this.apiClient.api.conversation.getConversationList();
|
|
378
|
-
this.groupIdConversationMap.clear();
|
|
379
|
-
for (const conversation of conversations.found || []) {
|
|
380
|
-
if (conversation.group_id) {
|
|
381
|
-
this.groupIdConversationMap.set(conversation.group_id, conversation);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
async getConversationByGroupId(groupId) {
|
|
386
|
-
if (!this.groupIdConversationMap.has(groupId)) {
|
|
387
|
-
await this.refreshGroupIdConversationMap();
|
|
388
|
-
}
|
|
389
|
-
return this.groupIdConversationMap.get(groupId);
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* React to a key material update failure using the recovery orchestrator.
|
|
393
|
-
*
|
|
394
|
-
* The original error is forwarded to the orchestrator under the 'keyMaterialUpdate' operation
|
|
395
|
-
* so it can map and apply the configured recovery policy. Unrecoverable errors are logged.
|
|
396
|
-
*/
|
|
397
|
-
reactToKeyMaterialUpdateFailure = async ({ error, groupId }) => {
|
|
398
|
-
this.logger.info(`Reacting to key material update failure for group ${groupId}`);
|
|
399
|
-
const conversation = await this.getConversationByGroupId(groupId);
|
|
400
|
-
if (!conversation) {
|
|
401
|
-
this.logger.warn(`No conversation found for group ${groupId}`, { error });
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
try {
|
|
405
|
-
await this.MLSRecoveryOrchestrator.execute({
|
|
406
|
-
context: {
|
|
407
|
-
operationName: recovery_1.OperationName.keyMaterialUpdate,
|
|
408
|
-
qualifiedConversationId: conversation.qualified_id,
|
|
409
|
-
groupId,
|
|
410
|
-
},
|
|
411
|
-
callBack: async () => {
|
|
412
|
-
// Surface the ORIGINAL error to the orchestrator for mapping & policy resolution
|
|
413
|
-
// Deliberately throwing the raw value so mapper can recognize core-crypto/API error shapes
|
|
414
|
-
throw error;
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
catch (e) {
|
|
419
|
-
this.logger.error('Failed to react to key material update failure', { error: e, groupId });
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
async resetMLSConversation(conversationId) {
|
|
423
|
-
this.logger.info(`Resetting MLS conversation with id ${conversationId.id}`);
|
|
424
|
-
// STEP 1: Fetch the conversation to retrieve the group ID & epoch
|
|
425
|
-
const conversation = await this.apiClient.api.conversation.getConversation(conversationId);
|
|
426
|
-
const { group_id: groupId, epoch } = conversation;
|
|
427
|
-
if (!groupId || !epoch) {
|
|
428
|
-
const errorMessage = 'Could not find group id or epoch for the conversation';
|
|
429
|
-
this.logger.error(errorMessage, { conversationId });
|
|
430
|
-
throw new Error(errorMessage);
|
|
431
|
-
}
|
|
432
|
-
// STEP 2: Request backend to reset the conversation
|
|
433
|
-
this.logger.info(`Requesting backend to reset the conversation (group_id: ${groupId}, epoch: ${String(epoch)})`);
|
|
434
|
-
await this.apiClient.api.conversation.resetMLSConversation({
|
|
435
|
-
epoch,
|
|
436
|
-
groupId,
|
|
437
|
-
});
|
|
438
|
-
// STEP 3: fetch self user info
|
|
439
|
-
this.logger.info(`Re-establishing the conversation by re-adding all members (conversation_id: ${conversationId.id})`);
|
|
440
|
-
const { validatedClientId: clientId, userId, domain } = this.apiClient;
|
|
441
|
-
if (!userId || !domain) {
|
|
442
|
-
const errorMessage = 'Could not find userId or domain of the self user';
|
|
443
|
-
this.logger.error(errorMessage, { conversationId });
|
|
444
|
-
throw new Error(errorMessage);
|
|
445
|
-
}
|
|
446
|
-
const selfUserQualifiedId = { id: userId, domain };
|
|
447
|
-
// STEP 4: Fetch the updated conversation data from backend to retrieve the new group ID
|
|
448
|
-
const updatedConversation = await this.apiClient.api.conversation.getConversation(conversationId);
|
|
449
|
-
const { group_id: newGroupId, members } = updatedConversation;
|
|
450
|
-
this.logger.info(`MLS conversation new group ID fetched from backend ${conversationId.id}`, {
|
|
451
|
-
newGroupId,
|
|
452
|
-
});
|
|
453
|
-
if (!newGroupId || !clientId) {
|
|
454
|
-
throw new Error(`Failed to recover MLS conversation: missing groupId (${newGroupId}), or clientId (${clientId})`);
|
|
455
|
-
}
|
|
456
|
-
const usersToReAdd = members.others.map(member => member.qualified_id).filter(userId => !!userId);
|
|
457
|
-
// STEP 5: Re-establish the conversation by re-adding all members
|
|
458
|
-
return await this.establishMLSGroupConversation(newGroupId, usersToReAdd, selfUserQualifiedId, clientId, conversationId).then(result => {
|
|
459
|
-
this.logger.info(`Successfully reset MLS conversation`, {
|
|
460
|
-
conversationId: conversationId.id,
|
|
461
|
-
oldGroupId: groupId,
|
|
462
|
-
newGroupId,
|
|
463
|
-
});
|
|
464
|
-
return result;
|
|
465
|
-
});
|
|
283
|
+
return this.mlsService.joinByExternalCommit(() => this.apiClient.api.conversation.getGroupInfo(conversationId));
|
|
466
284
|
}
|
|
467
285
|
/**
|
|
468
286
|
* Will check if mls group exists locally.
|
|
@@ -479,9 +297,9 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
479
297
|
async isMLSGroupEstablishedLocally(groupId) {
|
|
480
298
|
return this.mlsService.isConversationEstablished(groupId);
|
|
481
299
|
}
|
|
482
|
-
|
|
300
|
+
async wipeMLSConversation(groupId) {
|
|
483
301
|
return this.mlsService.wipeConversation(groupId);
|
|
484
|
-
}
|
|
302
|
+
}
|
|
485
303
|
async matchesEpoch(groupId, backendEpoch) {
|
|
486
304
|
const localEpoch = await this.mlsService.getEpoch(groupId);
|
|
487
305
|
this.logger.debug(`Comparing conversation's (group_id: ${groupId}) local and backend epoch number: {local: ${String(localEpoch)}, backend: ${backendEpoch}}`);
|
|
@@ -549,14 +367,8 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
549
367
|
async hasEpochMismatch(groupId, epoch) {
|
|
550
368
|
const isEstablished = await this.mlsGroupExistsLocally(groupId);
|
|
551
369
|
const doesEpochMatch = isEstablished && (await this.matchesEpoch(groupId, epoch));
|
|
552
|
-
//
|
|
553
|
-
|
|
554
|
-
this.logger.info(`Conversation (group_id: ${groupId}) epoch mismatch check result: ${hasEpochMismatch}`, {
|
|
555
|
-
isEstablished,
|
|
556
|
-
doesEpochMatch,
|
|
557
|
-
epoch,
|
|
558
|
-
});
|
|
559
|
-
return hasEpochMismatch;
|
|
370
|
+
//if conversation is not established or epoch does not match -> try to rejoin
|
|
371
|
+
return !isEstablished || !doesEpochMatch;
|
|
560
372
|
}
|
|
561
373
|
/**
|
|
562
374
|
* Get a MLS 1:1-conversation with a given user.
|
|
@@ -626,71 +438,47 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
626
438
|
* @param qualifiedUsers - list of qualified users to add to the group (should not include the self user)
|
|
627
439
|
*/
|
|
628
440
|
async tryEstablishingMLSGroup({ groupId, conversationId, selfUserId, qualifiedUsers, }) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
this.logger.debug('Group was established by self client, adding other users to the group...');
|
|
636
|
-
const usersToAdd = [
|
|
637
|
-
...qualifiedUsers,
|
|
638
|
-
{ ...selfUserId, skipOwnClientId: this.apiClient.validatedClientId },
|
|
639
|
-
];
|
|
640
|
-
const { conversation } = await this.addUsersToMLSConversation({
|
|
641
|
-
conversationId,
|
|
642
|
-
groupId,
|
|
643
|
-
qualifiedUsers: usersToAdd,
|
|
644
|
-
});
|
|
645
|
-
const addedUsers = conversation.members.others;
|
|
646
|
-
if (addedUsers.length > 0) {
|
|
647
|
-
this.logger.debug(`Successfully added ${addedUsers} users to the group.`);
|
|
648
|
-
}
|
|
649
|
-
else {
|
|
650
|
-
this.logger.debug('No other users were added to the group.');
|
|
651
|
-
}
|
|
441
|
+
const wasGroupEstablishedBySelfClient = await this.mlsService.tryEstablishingMLSGroup(groupId);
|
|
442
|
+
if (!wasGroupEstablishedBySelfClient) {
|
|
443
|
+
this.logger.debug('Group was not established by self client, skipping adding users to the group.');
|
|
444
|
+
return;
|
|
652
445
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
446
|
+
this.logger.debug('Group was established by self client, adding other users to the group...');
|
|
447
|
+
const usersToAdd = [
|
|
448
|
+
...qualifiedUsers,
|
|
449
|
+
{ ...selfUserId, skipOwnClientId: this.apiClient.validatedClientId },
|
|
450
|
+
];
|
|
451
|
+
const { conversation } = await this.addUsersToMLSConversation({
|
|
452
|
+
conversationId,
|
|
453
|
+
groupId,
|
|
454
|
+
qualifiedUsers: usersToAdd,
|
|
455
|
+
});
|
|
456
|
+
const addedUsers = conversation.members.others;
|
|
457
|
+
if (addedUsers.length > 0) {
|
|
458
|
+
this.logger.debug(`Successfully added ${addedUsers} users to the group.`);
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
this.logger.debug('No other users were added to the group.');
|
|
656
462
|
}
|
|
657
463
|
}
|
|
658
|
-
/**
|
|
659
|
-
* Handle an inbound MLS message-add event with recovery.
|
|
660
|
-
*
|
|
661
|
-
* Policies (see MlsRecoveryOrchestrator):
|
|
662
|
-
* - WrongEpoch.handleMessageAdd → recover from epoch mismatch and re-run once.
|
|
663
|
-
* - GroupOutOfSync.handleMessageAdd → not handled here; the error bubbles.
|
|
664
|
-
*
|
|
665
|
-
* Returns the decrypted payload when available. Unknown or unrecoverable errors are logged
|
|
666
|
-
* and result in null so event processing can continue safely.
|
|
667
|
-
*/
|
|
668
464
|
async handleMLSMessageAddEvent(event) {
|
|
669
465
|
try {
|
|
670
|
-
|
|
671
|
-
if (!qualifiedConversationId) {
|
|
672
|
-
throw new Error('Qualified conversation id is missing in the MLS message-add event');
|
|
673
|
-
}
|
|
674
|
-
return await this.MLSRecoveryOrchestrator.execute({
|
|
675
|
-
context: {
|
|
676
|
-
operationName: recovery_1.OperationName.handleMessageAdd,
|
|
677
|
-
qualifiedConversationId,
|
|
678
|
-
subconvId: subconv,
|
|
679
|
-
},
|
|
680
|
-
callBack: async () => {
|
|
681
|
-
return this.mlsService.handleMLSMessageAddEvent(event, this.groupIdFromConversationId);
|
|
682
|
-
},
|
|
683
|
-
});
|
|
466
|
+
return await this.mlsService.handleMLSMessageAddEvent(event, this.groupIdFromConversationId);
|
|
684
467
|
}
|
|
685
468
|
catch (error) {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
469
|
+
if ((0, CoreCryptoMLSError_1.isCoreCryptoMLSWrongEpochError)(error)) {
|
|
470
|
+
this.logger.warn(`Received message for the wrong epoch in conversation ${event.conversation}, handling epoch mismatch...`);
|
|
471
|
+
const { qualified_conversation: conversationId, subconv } = event;
|
|
472
|
+
if (!conversationId) {
|
|
473
|
+
throw new Error('Qualified conversation id is missing in the event');
|
|
474
|
+
}
|
|
475
|
+
(0, conversationRejoinQueue_1.queueConversationRejoin)(conversationId.id, () => this.recoverMLSGroupFromEpochMismatch(conversationId, subconv));
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
throw error;
|
|
690
479
|
}
|
|
691
480
|
}
|
|
692
481
|
async recoverMLSGroupFromEpochMismatch(conversationId, subconversationId) {
|
|
693
|
-
this.logger.info(`Recovering MLS group from epoch mismatch`, { conversationId, subconversationId });
|
|
694
482
|
if (subconversationId) {
|
|
695
483
|
const parentGroupId = await this.groupIdFromConversationId(conversationId);
|
|
696
484
|
const subconversation = await this.apiClient.api.conversation.getSubconversation(conversationId, subconversationId);
|
|
@@ -705,25 +493,24 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
705
493
|
}
|
|
706
494
|
return this.handleConversationEpochMismatch(mlsConversation, () => this.emit('MLSConversationRecovered', { conversationId: mlsConversation.qualified_id }));
|
|
707
495
|
}
|
|
708
|
-
/**
|
|
709
|
-
* Handle an MLS welcome event with recovery.
|
|
710
|
-
*
|
|
711
|
-
* Policies (see MlsRecoveryOrchestrator):
|
|
712
|
-
* - OrphanWelcome → join via external commit (no auto re-run).
|
|
713
|
-
* - ConversationAlreadyExists → wipe local state and re-run welcome once.
|
|
714
|
-
*
|
|
715
|
-
* Always resolves to null; the effects are applied to local state.
|
|
716
|
-
*/
|
|
717
496
|
async handleMLSWelcomeMessageEvent(event) {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
497
|
+
try {
|
|
498
|
+
return await this.mlsService.handleMLSWelcomeMessageEvent(event, this.apiClient.validatedClientId);
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
if ((0, CoreCryptoMLSError_1.isCoreCryptoMLSOrphanWelcomeMessageError)(error)) {
|
|
502
|
+
const { qualified_conversation: conversationId } = event;
|
|
503
|
+
// Note that we don't care about a subconversation here, as the welcome message is always for the parent conversation.
|
|
504
|
+
// Subconversations are always joined via external commit.
|
|
505
|
+
if (!conversationId) {
|
|
506
|
+
throw new Error('Qualified conversation id is missing in the event');
|
|
507
|
+
}
|
|
508
|
+
this.logger.warn(`Received an orphan welcome message, joining the conversation (${conversationId.id}) via external commit...`);
|
|
509
|
+
void (0, conversationRejoinQueue_1.queueConversationRejoin)(conversationId.id, () => this.joinByExternalCommit(conversationId));
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
throw error;
|
|
513
|
+
}
|
|
727
514
|
}
|
|
728
515
|
async handleOtrMessageAddEvent(event) {
|
|
729
516
|
return this.proteusService.handleOtrMessageAddEvent(event);
|