@wireapp/core 46.0.19 → 46.1.0-hotfix-1.0
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.js +56 -43
- package/lib/account/AccountService.js +0 -1
- package/lib/broadcast/BroadcastService.js +0 -3
- package/lib/client/ClientBackendRepository.js +0 -1
- package/lib/client/ClientDatabaseRepository.js +7 -16
- package/lib/client/ClientService.d.ts.map +1 -1
- package/lib/client/ClientService.js +13 -14
- package/lib/connection/ConnectionService.js +0 -1
- package/lib/conversation/AssetService/AssetService.d.ts +1 -0
- package/lib/conversation/AssetService/AssetService.d.ts.map +1 -1
- package/lib/conversation/AssetService/AssetService.js +6 -13
- package/lib/conversation/AssetService/AssetService.test.js +1 -1
- package/lib/conversation/ConversationService/ConversationService.d.ts.map +1 -1
- package/lib/conversation/ConversationService/ConversationService.js +80 -90
- package/lib/conversation/ConversationService/ConversationService.test.js +5 -12
- package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts.map +1 -1
- package/lib/conversation/MessageTimer/MessageTimer.js +0 -2
- package/lib/conversation/SubconversationService/SubconversationService.d.ts +8 -0
- package/lib/conversation/SubconversationService/SubconversationService.d.ts.map +1 -1
- package/lib/conversation/SubconversationService/SubconversationService.js +51 -23
- package/lib/conversation/content/AssetContent.d.ts +1 -0
- package/lib/conversation/content/AssetContent.d.ts.map +1 -1
- package/lib/conversation/content/ContentType.js +19 -18
- package/lib/conversation/content/FileContent.d.ts +1 -0
- package/lib/conversation/content/FileContent.d.ts.map +1 -1
- package/lib/conversation/content/ImageContent.d.ts +1 -0
- package/lib/conversation/content/ImageContent.d.ts.map +1 -1
- package/lib/conversation/message/MessageBuilder.js +23 -22
- package/lib/conversation/message/MessageService.js +4 -5
- package/lib/conversation/message/MessageService.test.js +9 -20
- package/lib/conversation/message/MessageToProtoMapper.js +2 -2
- package/lib/conversation/message/RecipientsHelper.js +2 -1
- package/lib/conversation/message/TextContentBuilder.js +2 -3
- package/lib/conversation/message/UserClientsUtil.js +3 -2
- package/lib/conversation/message/messageSender.js +6 -5
- package/lib/cryptography/AssetCryptography/AssetCryptography.d.ts.map +1 -1
- package/lib/cryptography/GenericMessageMapper.js +22 -74
- package/lib/cryptography/MessageHashService.d.ts +1 -0
- package/lib/cryptography/MessageHashService.d.ts.map +1 -1
- package/lib/cryptography/MessageHashService.js +0 -2
- package/lib/errors/DecryptionError.js +0 -2
- package/lib/errors/FederatedBackendsError.js +2 -3
- package/lib/giphy/GiphyService.js +0 -1
- package/lib/linkPreview/LinkPreviewService.js +12 -2
- package/lib/messagingProtocols/mls/E2EIdentityService/Connection/AcmeServer/AcmeService.d.ts +4 -4
- package/lib/messagingProtocols/mls/E2EIdentityService/Connection/AcmeServer/AcmeService.js +8 -9
- package/lib/messagingProtocols/mls/E2EIdentityService/Connection/AcmeServer/schema.d.ts +8 -8
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.js +3 -33
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.test.js +11 -11
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.js +5 -15
- package/lib/messagingProtocols/mls/E2EIdentityService/Helper/index.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Helper/index.js +0 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Account.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Account.js +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Authorization.d.ts +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Authorization.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Authorization.js +3 -2
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Certificate.js +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Order.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Steps/Order.js +2 -2
- package/lib/messagingProtocols/mls/E2EIdentityService/Storage/E2EIStorage.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Storage/E2EIStorage.js +2 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/Storage/E2EIStorage.schema.d.ts +4 -4
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/IncomingMessagesQueue/IncomingMesssagesQueue.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.js +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.js +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.test.js +3 -7
- package/lib/messagingProtocols/mls/MLSService/ClientMLSError.js +0 -1
- package/lib/messagingProtocols/mls/MLSService/CoreCryptoMLSError.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/MLSService/MLSService.js +115 -110
- package/lib/messagingProtocols/mls/MLSService/MLSService.test.js +9 -31
- package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.js +2 -1
- package/lib/messagingProtocols/mls/conversationRejoinQueue.js +4 -3
- package/lib/messagingProtocols/mls/utils/MLSId.js +3 -2
- package/lib/messagingProtocols/proteus/EventHandler/events/otrMessageAdd/otrMessageAdd.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.js +2 -6
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.js +0 -3
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.store.js +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoboxWrapper.js +4 -5
- package/lib/messagingProtocols/proteus/ProteusService/DecryptionErrorGenerator/DecryptionErrorGenerator.js +2 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.js +16 -20
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts +7 -4
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.test.js +15 -15
- package/lib/messagingProtocols/proteus/ProteusService/cryptoMigrationStateStore.js +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/identityClearer.js +2 -1
- package/lib/messagingProtocols/proteus/ProteusService/sessionIdMigrator.js +3 -2
- package/lib/messagingProtocols/proteus/ProteusService/userDomainFilters.js +2 -1
- package/lib/messagingProtocols/proteus/Utility/Recipients.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.js +14 -14
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.test.js +2 -5
- package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts.map +1 -1
- package/lib/notification/NotificationBackendRepository.d.ts +1 -1
- package/lib/notification/NotificationBackendRepository.js +0 -1
- package/lib/notification/NotificationDatabaseRepository.js +0 -1
- package/lib/notification/NotificationService.js +49 -38
- package/lib/secretStore/encryptedStore.js +22 -10
- package/lib/secretStore/secretKeyGenerator.js +2 -2
- package/lib/secretStore/secretKeyGenerator.test.js +1 -1
- package/lib/self/SelfService.js +1 -2
- package/lib/storage/CoreDB.js +3 -2
- package/lib/team/TeamService.js +0 -1
- package/lib/test/PayloadHelper.js +4 -3
- package/lib/testUtils/index.js +3 -2
- package/lib/user/UserService.d.ts +2 -2
- package/lib/user/UserService.js +0 -1
- package/lib/util/LocalStorageStore/index.d.ts.map +1 -1
- package/lib/util/LowPrecisionTaskScheduler/LowPrecisionTaskScheduler.js +6 -4
- package/lib/util/RecurringTaskScheduler/RecurringTaskScheduler.d.ts.map +1 -1
- package/lib/util/RecurringTaskScheduler/RecurringTaskScheduler.js +33 -34
- package/lib/util/TaskScheduler/TaskScheduler.d.ts +1 -1
- package/lib/util/TaskScheduler/TaskScheduler.d.ts.map +1 -1
- package/lib/util/TypePredicateUtil.js +10 -7
- package/lib/util/fullyQualifiedClientIdUtils.js +2 -1
- package/package.json +6 -6
|
@@ -38,14 +38,6 @@ const util_1 = require("../../util");
|
|
|
38
38
|
const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
|
|
39
39
|
const messageSender_1 = require("../message/messageSender");
|
|
40
40
|
class ConversationService extends commons_1.TypedEventEmitter {
|
|
41
|
-
apiClient;
|
|
42
|
-
proteusService;
|
|
43
|
-
coreDatabase;
|
|
44
|
-
groupIdFromConversationId;
|
|
45
|
-
subconversationService;
|
|
46
|
-
_mlsService;
|
|
47
|
-
messageTimer;
|
|
48
|
-
logger = (0, logdown_1.default)('@wireapp/core/ConversationService');
|
|
49
41
|
constructor(apiClient, proteusService, coreDatabase, groupIdFromConversationId, subconversationService, _mlsService) {
|
|
50
42
|
super();
|
|
51
43
|
this.apiClient = apiClient;
|
|
@@ -54,6 +46,67 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
54
46
|
this.groupIdFromConversationId = groupIdFromConversationId;
|
|
55
47
|
this.subconversationService = subconversationService;
|
|
56
48
|
this._mlsService = _mlsService;
|
|
49
|
+
this.logger = (0, logdown_1.default)('@wireapp/core/ConversationService');
|
|
50
|
+
/**
|
|
51
|
+
* Blacklists a conversation.
|
|
52
|
+
* When conversations is blacklisted, it means that it will be completely ignored by a client, even though it does exist on backend and we're the conversation member.
|
|
53
|
+
* @param conversationId id of the conversation to blacklist
|
|
54
|
+
*/
|
|
55
|
+
this.blacklistConversation = async (conversationId) => {
|
|
56
|
+
await this.coreDatabase.put('conversationBlacklist', conversationId, conversationId.id);
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Removes a conversation from the blacklists.
|
|
60
|
+
* @param conversationId id of the conversation to remove from the blacklist
|
|
61
|
+
*/
|
|
62
|
+
this.removeConversationFromBlacklist = async (conversationId) => {
|
|
63
|
+
await this.coreDatabase.delete('conversationBlacklist', conversationId.id);
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Will try registering mls 1:1 conversation adding the other user.
|
|
67
|
+
* If it fails and the conversation is already established, it will try joining via external commit instead.
|
|
68
|
+
*
|
|
69
|
+
* @param mlsConversation - mls 1:1 conversation
|
|
70
|
+
* @param selfUser - user and client ids of the self user
|
|
71
|
+
* @param otherUserId - id of the other user
|
|
72
|
+
*/
|
|
73
|
+
this.establishMLS1to1Conversation = async (groupId, selfUser, otherUserId, shouldRetry = true) => {
|
|
74
|
+
this.logger.info(`Trying to establish a MLS 1:1 conversation with user ${otherUserId.id}...`);
|
|
75
|
+
// Before trying to register a group, check if the group is already established o backend.
|
|
76
|
+
// If remote epoch is higher than 0, it means that the group was already established.
|
|
77
|
+
// It's possible that we've already received a welcome message.
|
|
78
|
+
const mlsConversation = await this.getMLS1to1Conversation(otherUserId);
|
|
79
|
+
if (mlsConversation.epoch > 0) {
|
|
80
|
+
this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is already established on backend, checking the local epoch...`);
|
|
81
|
+
const isMLSGroupEstablishedLocally = await this.isMLSGroupEstablishedLocally(groupId);
|
|
82
|
+
// If group is already established locally, there's nothing more to do
|
|
83
|
+
if (isMLSGroupEstablishedLocally) {
|
|
84
|
+
this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is already established locally.`);
|
|
85
|
+
return mlsConversation;
|
|
86
|
+
}
|
|
87
|
+
// If local epoch is 0 it means that we've not received a welcome message
|
|
88
|
+
// We try joining via external commit.
|
|
89
|
+
this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is not yet established locally, joining via external commit...`);
|
|
90
|
+
await this.joinByExternalCommit(mlsConversation.qualified_id);
|
|
91
|
+
return this.getMLS1to1Conversation(otherUserId);
|
|
92
|
+
}
|
|
93
|
+
// If group is not established on backend,
|
|
94
|
+
// we wipe the it locally (in case it exsits in the local store) and try to register it.
|
|
95
|
+
await this.mlsService.wipeConversation(groupId);
|
|
96
|
+
try {
|
|
97
|
+
await this.mlsService.register1to1Conversation(groupId, otherUserId, selfUser);
|
|
98
|
+
this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) established successfully.`);
|
|
99
|
+
return this.getMLS1to1Conversation(otherUserId);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this.logger.info(`Could not register MLS group with id ${groupId}: `, error);
|
|
103
|
+
if (!shouldRetry) {
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is not established, retrying to establish it`);
|
|
107
|
+
return this.establishMLS1to1Conversation(groupId, selfUser, otherUserId, false);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
57
110
|
this.messageTimer = new conversation_2.MessageTimer();
|
|
58
111
|
}
|
|
59
112
|
get mlsService() {
|
|
@@ -76,7 +129,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
76
129
|
const allClients = await this.apiClient.api.user.postListClients({ qualified_users: qualifiedMembers });
|
|
77
130
|
const qualifiedUserClients = {};
|
|
78
131
|
Object.entries(allClients.qualified_user_map).map(([domain, userClientMap]) => Object.entries(userClientMap).map(async ([userId, clients]) => {
|
|
79
|
-
qualifiedUserClients[domain]
|
|
132
|
+
qualifiedUserClients[domain] || (qualifiedUserClients[domain] = {});
|
|
80
133
|
qualifiedUserClients[domain][userId] = clients.map(client => client.id);
|
|
81
134
|
}));
|
|
82
135
|
return qualifiedUserClients;
|
|
@@ -130,21 +183,6 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
130
183
|
sendTypingStop(conversationId) {
|
|
131
184
|
return this.apiClient.api.conversation.postTyping(conversationId, { status: data_1.CONVERSATION_TYPING.STOPPED });
|
|
132
185
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Blacklists a conversation.
|
|
135
|
-
* When conversations is blacklisted, it means that it will be completely ignored by a client, even though it does exist on backend and we're the conversation member.
|
|
136
|
-
* @param conversationId id of the conversation to blacklist
|
|
137
|
-
*/
|
|
138
|
-
blacklistConversation = async (conversationId) => {
|
|
139
|
-
await this.coreDatabase.put('conversationBlacklist', conversationId, conversationId.id);
|
|
140
|
-
};
|
|
141
|
-
/**
|
|
142
|
-
* Removes a conversation from the blacklists.
|
|
143
|
-
* @param conversationId id of the conversation to remove from the blacklist
|
|
144
|
-
*/
|
|
145
|
-
removeConversationFromBlacklist = async (conversationId) => {
|
|
146
|
-
await this.coreDatabase.delete('conversationBlacklist', conversationId.id);
|
|
147
|
-
};
|
|
148
186
|
/**
|
|
149
187
|
* returns the number of messages that are in the queue expecting to be sent
|
|
150
188
|
*/
|
|
@@ -192,11 +230,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
192
230
|
* field must be empty as backend is not aware which users
|
|
193
231
|
* are in a MLS conversation because of the MLS architecture.
|
|
194
232
|
*/
|
|
195
|
-
const newConversation = await this.apiClient.api.conversation.postConversation({
|
|
196
|
-
...conversationData,
|
|
197
|
-
users: undefined,
|
|
198
|
-
qualified_users: undefined,
|
|
199
|
-
});
|
|
233
|
+
const newConversation = await this.apiClient.api.conversation.postConversation(Object.assign(Object.assign({}, conversationData), { users: undefined, qualified_users: undefined }));
|
|
200
234
|
const { group_id: groupId, qualified_id: qualifiedId } = newConversation;
|
|
201
235
|
if (!groupId) {
|
|
202
236
|
throw new Error('No group_id found in response which is required for creating MLS conversations.');
|
|
@@ -216,6 +250,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
216
250
|
};
|
|
217
251
|
}
|
|
218
252
|
async sendMLSMessage(params, shouldRetry = true) {
|
|
253
|
+
var _a, _b;
|
|
219
254
|
const { payload, groupId, conversationId } = params;
|
|
220
255
|
const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
|
|
221
256
|
// immediately execute pending commits before sending the message
|
|
@@ -225,7 +260,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
225
260
|
let sentAt = '';
|
|
226
261
|
try {
|
|
227
262
|
response = await this.apiClient.api.conversation.postMlsMessage(encrypted);
|
|
228
|
-
sentAt = response.time
|
|
263
|
+
sentAt = ((_a = response.time) === null || _a === void 0 ? void 0 : _a.length) > 0 ? response.time : new Date().toISOString();
|
|
229
264
|
}
|
|
230
265
|
catch (error) {
|
|
231
266
|
const isMLSStaleMessageError = error instanceof http_1.BackendError && error.label === http_1.BackendErrorLabel.MLS_STALE_MESSAGE;
|
|
@@ -237,10 +272,10 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
237
272
|
}
|
|
238
273
|
throw error;
|
|
239
274
|
}
|
|
240
|
-
const failedToSend = response
|
|
275
|
+
const failedToSend = (response === null || response === void 0 ? void 0 : response.failed) || ((_b = response === null || response === void 0 ? void 0 : response.failed_to_send) !== null && _b !== void 0 ? _b : []).length > 0
|
|
241
276
|
? {
|
|
242
|
-
queued: response
|
|
243
|
-
failed: response
|
|
277
|
+
queued: response === null || response === void 0 ? void 0 : response.failed_to_send,
|
|
278
|
+
failed: response === null || response === void 0 ? void 0 : response.failed,
|
|
244
279
|
}
|
|
245
280
|
: undefined;
|
|
246
281
|
return {
|
|
@@ -306,12 +341,12 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
306
341
|
}
|
|
307
342
|
async matchesEpoch(groupId, backendEpoch) {
|
|
308
343
|
const localEpoch = await this.mlsService.getEpoch(groupId);
|
|
309
|
-
this.logger.
|
|
344
|
+
this.logger.log(`Comparing conversation's (group_id: ${groupId}) local and backend epoch number: {local: ${String(localEpoch)}, backend: ${backendEpoch}}`);
|
|
310
345
|
//corecrypto stores epoch number as BigInt, we're mapping both values to be sure comparison is valid
|
|
311
346
|
return BigInt(localEpoch) === BigInt(backendEpoch);
|
|
312
347
|
}
|
|
313
348
|
async handleConversationsEpochMismatch() {
|
|
314
|
-
this.logger.
|
|
349
|
+
this.logger.info(`There were some missed messages, handling possible epoch mismatch in MLS conversations.`);
|
|
315
350
|
//fetch all the mls conversations from backend
|
|
316
351
|
const conversations = await this.apiClient.api.conversation.getConversationList();
|
|
317
352
|
const foundConversations = conversations.found || [];
|
|
@@ -328,7 +363,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
328
363
|
async handleSubconversationEpochMismatch(subconversation, parentGroupId) {
|
|
329
364
|
const { parent_qualified_id: parentConversationId, group_id: groupId, epoch, subconv_id: subconversationId, } = subconversation;
|
|
330
365
|
if (await this.hasEpochMismatch(groupId, epoch)) {
|
|
331
|
-
this.logger.
|
|
366
|
+
this.logger.log(`Subconversation "${subconversationId}" (parent id: ${parentConversationId.id}) was not established or its epoch number was out of date, joining via external commit`);
|
|
332
367
|
// We only support conference subconversations for now
|
|
333
368
|
if (subconversationId !== conversation_1.SUBCONVERSATION_ID.CONFERENCE) {
|
|
334
369
|
throw new Error('Unexpected subconversation id');
|
|
@@ -349,10 +384,10 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
349
384
|
async handleConversationEpochMismatch(remoteMlsConversation, onSuccessfulRejoin) {
|
|
350
385
|
const { qualified_id: qualifiedId, group_id: groupId, epoch } = remoteMlsConversation;
|
|
351
386
|
if (await this.hasEpochMismatch(groupId, epoch)) {
|
|
352
|
-
this.logger.
|
|
387
|
+
this.logger.log(`Conversation (id ${qualifiedId.id}) was not established or it's epoch number was out of date, joining via external commit`);
|
|
353
388
|
try {
|
|
354
389
|
await this.joinByExternalCommit(qualifiedId);
|
|
355
|
-
onSuccessfulRejoin
|
|
390
|
+
onSuccessfulRejoin === null || onSuccessfulRejoin === void 0 ? void 0 : onSuccessfulRejoin();
|
|
356
391
|
}
|
|
357
392
|
catch (error) {
|
|
358
393
|
const message = `There was an error while handling epoch mismatch in MLS conversation (id: ${qualifiedId.id}):`;
|
|
@@ -381,51 +416,6 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
381
416
|
async getMLS1to1Conversation(userId) {
|
|
382
417
|
return this.apiClient.api.conversation.getMLS1to1Conversation(userId);
|
|
383
418
|
}
|
|
384
|
-
/**
|
|
385
|
-
* Will try registering mls 1:1 conversation adding the other user.
|
|
386
|
-
* If it fails and the conversation is already established, it will try joining via external commit instead.
|
|
387
|
-
*
|
|
388
|
-
* @param mlsConversation - mls 1:1 conversation
|
|
389
|
-
* @param selfUser - user and client ids of the self user
|
|
390
|
-
* @param otherUserId - id of the other user
|
|
391
|
-
*/
|
|
392
|
-
establishMLS1to1Conversation = async (groupId, selfUser, otherUserId, shouldRetry = true) => {
|
|
393
|
-
this.logger.debug(`Trying to establish a MLS 1:1 conversation with user ${otherUserId.id}...`);
|
|
394
|
-
// Before trying to register a group, check if the group is already established o backend.
|
|
395
|
-
// If remote epoch is higher than 0, it means that the group was already established.
|
|
396
|
-
// It's possible that we've already received a welcome message.
|
|
397
|
-
const mlsConversation = await this.getMLS1to1Conversation(otherUserId);
|
|
398
|
-
if (mlsConversation.epoch > 0) {
|
|
399
|
-
this.logger.debug(`Conversation (id ${mlsConversation.qualified_id.id}) is already established on backend, checking the local epoch...`);
|
|
400
|
-
const isMLSGroupEstablishedLocally = await this.isMLSGroupEstablishedLocally(groupId);
|
|
401
|
-
// If group is already established locally, there's nothing more to do
|
|
402
|
-
if (isMLSGroupEstablishedLocally) {
|
|
403
|
-
this.logger.debug(`Conversation (id ${mlsConversation.qualified_id.id}) is already established locally.`);
|
|
404
|
-
return mlsConversation;
|
|
405
|
-
}
|
|
406
|
-
// If local epoch is 0 it means that we've not received a welcome message
|
|
407
|
-
// We try joining via external commit.
|
|
408
|
-
this.logger.debug(`Conversation (id ${mlsConversation.qualified_id.id}) is not yet established locally, joining via external commit...`);
|
|
409
|
-
await this.joinByExternalCommit(mlsConversation.qualified_id);
|
|
410
|
-
return this.getMLS1to1Conversation(otherUserId);
|
|
411
|
-
}
|
|
412
|
-
// If group is not established on backend,
|
|
413
|
-
// we wipe the it locally (in case it exsits in the local store) and try to register it.
|
|
414
|
-
await this.mlsService.wipeConversation(groupId);
|
|
415
|
-
try {
|
|
416
|
-
await this.mlsService.register1to1Conversation(groupId, otherUserId, selfUser);
|
|
417
|
-
this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) established successfully.`);
|
|
418
|
-
return this.getMLS1to1Conversation(otherUserId);
|
|
419
|
-
}
|
|
420
|
-
catch (error) {
|
|
421
|
-
if (!shouldRetry) {
|
|
422
|
-
this.logger.error(`Could not register MLS group with id ${groupId}: `, error);
|
|
423
|
-
throw error;
|
|
424
|
-
}
|
|
425
|
-
this.logger.error(`Conversation (id ${mlsConversation.qualified_id.id}) is not established, retrying to establish it`);
|
|
426
|
-
return this.establishMLS1to1Conversation(groupId, selfUser, otherUserId, false);
|
|
427
|
-
}
|
|
428
|
-
};
|
|
429
419
|
/**
|
|
430
420
|
* Will try to register mls group by sending an empty commit to establish it.
|
|
431
421
|
* After group was successfully established, it will try to add other users to the group.
|
|
@@ -438,13 +428,13 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
438
428
|
async tryEstablishingMLSGroup({ groupId, conversationId, selfUserId, qualifiedUsers, }) {
|
|
439
429
|
const wasGroupEstablishedBySelfClient = await this.mlsService.tryEstablishingMLSGroup(groupId);
|
|
440
430
|
if (!wasGroupEstablishedBySelfClient) {
|
|
441
|
-
this.logger.
|
|
431
|
+
this.logger.info('Group was not established by self client, skipping adding users to the group.');
|
|
442
432
|
return;
|
|
443
433
|
}
|
|
444
|
-
this.logger.
|
|
434
|
+
this.logger.info('Group was established by self client, adding other users to the group...');
|
|
445
435
|
const usersToAdd = [
|
|
446
436
|
...qualifiedUsers,
|
|
447
|
-
{
|
|
437
|
+
Object.assign(Object.assign({}, selfUserId), { skipOwnClientId: this.apiClient.validatedClientId }),
|
|
448
438
|
];
|
|
449
439
|
const { conversation } = await this.addUsersToMLSConversation({
|
|
450
440
|
conversationId,
|
|
@@ -453,10 +443,10 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
453
443
|
});
|
|
454
444
|
const addedUsers = conversation.members.others;
|
|
455
445
|
if (addedUsers.length > 0) {
|
|
456
|
-
this.logger.
|
|
446
|
+
this.logger.info(`Successfully added ${addedUsers} users to the group.`);
|
|
457
447
|
}
|
|
458
448
|
else {
|
|
459
|
-
this.logger.
|
|
449
|
+
this.logger.info('No other users were added to the group.');
|
|
460
450
|
}
|
|
461
451
|
}
|
|
462
452
|
async handleMLSMessageAddEvent(event) {
|
|
@@ -465,7 +455,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
465
455
|
}
|
|
466
456
|
catch (error) {
|
|
467
457
|
if ((0, CoreCryptoMLSError_1.isCoreCryptoMLSWrongEpochError)(error)) {
|
|
468
|
-
this.logger.
|
|
458
|
+
this.logger.info(`Received message for the wrong epoch in conversation ${event.conversation}, handling epoch mismatch...`);
|
|
469
459
|
const { qualified_conversation: conversationId, subconv } = event;
|
|
470
460
|
if (!conversationId) {
|
|
471
461
|
throw new Error('Qualified conversation id is missing in the event');
|
|
@@ -503,7 +493,7 @@ class ConversationService extends commons_1.TypedEventEmitter {
|
|
|
503
493
|
if (!conversationId) {
|
|
504
494
|
throw new Error('Qualified conversation id is missing in the event');
|
|
505
495
|
}
|
|
506
|
-
this.logger.
|
|
496
|
+
this.logger.info(`Received an orphan welcome message, joining the conversation (${conversationId.id}) via external commit...`);
|
|
507
497
|
void (0, conversationRejoinQueue_1.queueConversationRejoin)(conversationId.id, () => this.joinByExternalCommit(conversationId));
|
|
508
498
|
return null;
|
|
509
499
|
}
|
|
@@ -71,17 +71,9 @@ const createMLSWelcomeMessageEventMock = (conversationId) => ({
|
|
|
71
71
|
type: event_1.CONVERSATION_EVENT.MLS_WELCOME_MESSAGE,
|
|
72
72
|
time: '2023-08-21T06:47:43.387Z',
|
|
73
73
|
});
|
|
74
|
-
jest.mock('../../messagingProtocols/proteus', () => ({
|
|
75
|
-
...jest.requireActual('../../messagingProtocols/proteus'),
|
|
76
|
-
getGenericMessageParams: jest.fn(),
|
|
77
|
-
getRecipientsForConversation: jest.fn(),
|
|
78
|
-
getConversationQualifiedMembers: jest.fn(),
|
|
79
|
-
}));
|
|
74
|
+
jest.mock('../../messagingProtocols/proteus', () => (Object.assign(Object.assign({}, jest.requireActual('../../messagingProtocols/proteus')), { getGenericMessageParams: jest.fn(), getRecipientsForConversation: jest.fn(), getConversationQualifiedMembers: jest.fn() })));
|
|
80
75
|
const MockedMessagingProtocols = MessagingProtocols;
|
|
81
|
-
jest.mock('../message/messageSender', () => ({
|
|
82
|
-
...jest.requireActual('../message/messageSender'),
|
|
83
|
-
sendMessage: jest.fn().mockImplementation(fn => fn()),
|
|
84
|
-
}));
|
|
76
|
+
jest.mock('../message/messageSender', () => (Object.assign(Object.assign({}, jest.requireActual('../message/messageSender')), { sendMessage: jest.fn().mockImplementation(fn => fn()) })));
|
|
85
77
|
const mockedProteusService = {
|
|
86
78
|
encryptGenericMessage: () => Promise.resolve(),
|
|
87
79
|
sendProteusMessage: () => Promise.resolve({ sentAt: new Date() }),
|
|
@@ -446,13 +438,14 @@ describe('ConversationService', () => {
|
|
|
446
438
|
});
|
|
447
439
|
describe('getConversations', () => {
|
|
448
440
|
it('returns a list of conversations by conversation ids', async () => {
|
|
441
|
+
var _a;
|
|
449
442
|
const [conversationService, { apiClient }] = await buildConversationService();
|
|
450
443
|
const conversationIds = Array.from({ length: 10 }, () => ({ id: PayloadHelper.getUUID(), domain: 'test.zinfra.io' }));
|
|
451
444
|
jest.spyOn(apiClient.api.conversation, 'getConversationsByQualifiedIds').mockResolvedValueOnce({
|
|
452
445
|
found: conversationIds,
|
|
453
446
|
});
|
|
454
447
|
const conversations = await conversationService.getConversations(conversationIds);
|
|
455
|
-
expect(conversations.found
|
|
448
|
+
expect((_a = conversations.found) === null || _a === void 0 ? void 0 : _a.length).toBe(conversationIds.length);
|
|
456
449
|
});
|
|
457
450
|
it('returns a full list of conversations if a list of conversations is not provided', async () => {
|
|
458
451
|
const [conversationService, { apiClient }] = await buildConversationService();
|
|
@@ -585,7 +578,7 @@ describe('ConversationService', () => {
|
|
|
585
578
|
expect(conversationService.addUsersToMLSConversation).toHaveBeenCalledWith({
|
|
586
579
|
conversationId: mockConversationId,
|
|
587
580
|
groupId: mockGroupId,
|
|
588
|
-
qualifiedUsers: [...otherUsersToAdd, {
|
|
581
|
+
qualifiedUsers: [...otherUsersToAdd, Object.assign(Object.assign({}, selfUserId), { skipOwnClientId: apiClient.clientId })],
|
|
589
582
|
});
|
|
590
583
|
});
|
|
591
584
|
it('should not add any users if MLS group was not established by the self client', async () => {
|
package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getConversationQualifiedMembers.d.ts","sourceRoot":"","sources":["../../../../src/conversation/ConversationService/Utility/getConversationQualifiedMembers.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAEzD,UAAU,MAAM;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,WAAW,CAAC;CAC7B;AACD,QAAA,MAAM,+BAA+B,kCAAuC,MAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"getConversationQualifiedMembers.d.ts","sourceRoot":"","sources":["../../../../src/conversation/ConversationService/Utility/getConversationQualifiedMembers.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AAC5D,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAEzD,UAAU,MAAM;IACd,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,WAAW,CAAC;CAC7B;AACD,QAAA,MAAM,+BAA+B,kCAAuC,MAAM,KAAG,QAAQ,WAAW,EAAE,CAWzG,CAAC;AAEF,OAAO,EAAC,+BAA+B,EAAC,CAAC"}
|
|
@@ -20,8 +20,6 @@
|
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.MessageTimer = void 0;
|
|
22
22
|
class MessageTimer {
|
|
23
|
-
conversationLevelTimers;
|
|
24
|
-
messageLevelTimers;
|
|
25
23
|
constructor() {
|
|
26
24
|
this.conversationLevelTimers = new Map();
|
|
27
25
|
this.messageLevelTimers = new Map();
|
|
@@ -38,6 +38,14 @@ export declare class SubconversationService extends TypedEventEmitter<Events> {
|
|
|
38
38
|
* @param conversationId Id of the parent conversation which subconversation we want to leave
|
|
39
39
|
*/
|
|
40
40
|
leaveConferenceSubconversation(conversationId: QualifiedId): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Short term solution to an issues with 1:1 MLS call, see
|
|
43
|
+
* https://wearezeta.atlassian.net/wiki/spaces/PAD/pages/1314750477/2024-07-29+1+1+calls+over+SFT#Do-not-leave-the-subconversation
|
|
44
|
+
* Will delete a conference subconversation when hanging up on a 1:1 call instead of leaving.
|
|
45
|
+
*
|
|
46
|
+
* @param conversationId Id of the parent conversation which subconversation we want to leave
|
|
47
|
+
*/
|
|
48
|
+
leave1on1ConferenceSubconversation(conversationId: QualifiedId): Promise<void>;
|
|
41
49
|
leaveStaleConferenceSubconversations(): Promise<void>;
|
|
42
50
|
getSubconversationEpochInfo(parentConversationId: QualifiedId, parentConversationGroupId: string, shouldAdvanceEpoch?: boolean): Promise<{
|
|
43
51
|
members: SubconversationEpochInfoMember[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubconversationService.d.ts","sourceRoot":"","sources":["../../../src/conversation/SubconversationService/SubconversationService.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAkB,MAAM,sCAAsC,CAAC;AACzF,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAIzD,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAGlD,KAAK,MAAM,GAAG;IACZ,wBAAwB,EAAE;QAAC,cAAc,EAAE,WAAW,CAAA;KAAC,CAAC;CACzD,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAID,qBAAa,sBAAuB,SAAQ,iBAAiB,CAAC,MAAM,CAAC;IAIjE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAL/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmD;gBAGvD,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"SubconversationService.d.ts","sourceRoot":"","sources":["../../../src/conversation/SubconversationService/SubconversationService.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAkB,MAAM,sCAAsC,CAAC;AACzF,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAIzD,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;AACxD,OAAO,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAGlD,KAAK,MAAM,GAAG;IACZ,wBAAwB,EAAE;QAAC,cAAc,EAAE,WAAW,CAAA;KAAC,CAAC;CACzD,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAID,qBAAa,sBAAuB,SAAQ,iBAAiB,CAAC,MAAM,CAAC;IAIjE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAL/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmD;gBAGvD,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,WAAW,CAAC,wBAAY;IAK3C,IAAI,UAAU,IAAI,UAAU,CAK3B;IAED;;;;;;OAMG;IACU,6BAA6B,CACxC,cAAc,EAAE,WAAW,EAC3B,OAAO,EAAE,MAAM,EACf,WAAW,UAAO,GACjB,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC;IAiD5C;;;;OAIG;IACU,8BAA8B,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBvF;;;;;;OAMG;IACU,kCAAkC,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC9E,oCAAoC,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrD,2BAA2B,CACtC,oBAAoB,EAAE,WAAW,EACjC,yBAAyB,EAAE,MAAM,EACjC,kBAAkB,UAAQ,GACzB,OAAO,CAAC;QACT,OAAO,EAAE,8BAA8B,EAAE,CAAC;QAC1C,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;IAoCI,uBAAuB,CAClC,oBAAoB,EAAE,WAAW,EACjC,yBAAyB,EAAE,MAAM,EACjC,yBAAyB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,EACvE,aAAa,EAAE,CAAC,IAAI,EAAE;QACpB,OAAO,EAAE,8BAA8B,EAAE,CAAC;QAC1C,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,KAAK,IAAI,GACT,OAAO,CAAC,MAAM,IAAI,CAAC;IAiDT,yCAAyC,CACpD,cAAc,EAAE,WAAW,EAC3B,cAAc,EAAE;QAAC,IAAI,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,GACpD,OAAO,CAAC,IAAI,CAAC;YAgCF,mCAAmC;YAMnC,4BAA4B;YAI5B,+BAA+B;YAO/B,8BAA8B;IAwBrC,yBAAyB,yBACR,WAAW,qBACd,kBAAkB,KACpC,QAAQ,MAAM,GAAG,SAAS,CAAC,CAO5B;IAEK,iCAAiC,sBACnB,kBAAkB,KACpC,QACD;QACE,oBAAoB,EAAE,WAAW,CAAC;QAClC,iBAAiB,EAAE,kBAAkB,CAAC;QACtC,OAAO,EAAE,MAAM,CAAC;KACjB,EAAE,CACJ,CAOC;IAEK,0BAA0B,yBACT,WAAW,qBACd,kBAAkB,WAC5B,MAAM,qBAOf;IAEK,2BAA2B,yBACV,WAAW,qBACd,kBAAkB,mBAMrC;CACH"}
|
|
@@ -30,15 +30,27 @@ const subconversationUtil_1 = require("./subconversationUtil");
|
|
|
30
30
|
const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
|
|
31
31
|
const MLS_CONVERSATION_KEY_LENGTH = 32;
|
|
32
32
|
class SubconversationService extends commons_1.TypedEventEmitter {
|
|
33
|
-
apiClient;
|
|
34
|
-
coreDatabase;
|
|
35
|
-
_mlsService;
|
|
36
|
-
logger = (0, logdown_1.default)('@wireapp/core/SubconversationService');
|
|
37
33
|
constructor(apiClient, coreDatabase, _mlsService) {
|
|
38
34
|
super();
|
|
39
35
|
this.apiClient = apiClient;
|
|
40
36
|
this.coreDatabase = coreDatabase;
|
|
41
37
|
this._mlsService = _mlsService;
|
|
38
|
+
this.logger = (0, logdown_1.default)('@wireapp/core/SubconversationService');
|
|
39
|
+
this.getSubconversationGroupId = async (parentConversationId, subconversationId) => {
|
|
40
|
+
const foundSubconversation = await this.coreDatabase.get('subconversations', (0, subconversationUtil_1.generateSubconversationStoreKey)(parentConversationId, subconversationId));
|
|
41
|
+
return foundSubconversation === null || foundSubconversation === void 0 ? void 0 : foundSubconversation.groupId;
|
|
42
|
+
};
|
|
43
|
+
this.getAllGroupIdsBySubconversationId = async (subconversationId) => {
|
|
44
|
+
const allSubconversations = await this.coreDatabase.getAll('subconversations');
|
|
45
|
+
const foundSubconversations = allSubconversations.filter(subconversation => subconversation.subconversationId === subconversationId);
|
|
46
|
+
return foundSubconversations;
|
|
47
|
+
};
|
|
48
|
+
this.saveSubconversationGroupId = async (parentConversationId, subconversationId, groupId) => {
|
|
49
|
+
return this.coreDatabase.put('subconversations', { parentConversationId, subconversationId, groupId }, (0, subconversationUtil_1.generateSubconversationStoreKey)(parentConversationId, subconversationId));
|
|
50
|
+
};
|
|
51
|
+
this.clearSubconversationGroupId = async (parentConversationId, subconversationId) => {
|
|
52
|
+
return this.coreDatabase.delete('subconversations', (0, subconversationUtil_1.generateSubconversationStoreKey)(parentConversationId, subconversationId));
|
|
53
|
+
};
|
|
42
54
|
}
|
|
43
55
|
get mlsService() {
|
|
44
56
|
if (!this._mlsService) {
|
|
@@ -115,6 +127,40 @@ class SubconversationService extends commons_1.TypedEventEmitter {
|
|
|
115
127
|
// once we've left the subconversation, we can remove it from the store
|
|
116
128
|
await this.clearSubconversationGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
|
|
117
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Short term solution to an issues with 1:1 MLS call, see
|
|
132
|
+
* https://wearezeta.atlassian.net/wiki/spaces/PAD/pages/1314750477/2024-07-29+1+1+calls+over+SFT#Do-not-leave-the-subconversation
|
|
133
|
+
* Will delete a conference subconversation when hanging up on a 1:1 call instead of leaving.
|
|
134
|
+
*
|
|
135
|
+
* @param conversationId Id of the parent conversation which subconversation we want to leave
|
|
136
|
+
*/
|
|
137
|
+
async leave1on1ConferenceSubconversation(conversationId) {
|
|
138
|
+
const subconversationGroupId = await this.getSubconversationGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
|
|
139
|
+
if (!subconversationGroupId) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const doesGroupExistLocally = await this.mlsService.conversationExists(subconversationGroupId);
|
|
143
|
+
if (!doesGroupExistLocally) {
|
|
144
|
+
// If the subconversation was known by a client but is does not exist locally, we can remove it from the store.
|
|
145
|
+
return this.clearSubconversationGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const epochInfo = await this.getSubconversationEpochInfo(conversationId, subconversationGroupId);
|
|
149
|
+
if (!epochInfo) {
|
|
150
|
+
throw new Error('Failed to get epoch info for conference subconversation');
|
|
151
|
+
}
|
|
152
|
+
await this.apiClient.api.conversation.deleteSubconversation(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE, {
|
|
153
|
+
groupId: subconversationGroupId,
|
|
154
|
+
epoch: epochInfo.epoch,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
this.logger.error(`Failed to delete conference subconversation:`, error);
|
|
159
|
+
}
|
|
160
|
+
await this.mlsService.wipeConversation(subconversationGroupId);
|
|
161
|
+
// once we've deleted the subconversation, we can remove it from the store
|
|
162
|
+
await this.clearSubconversationGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
|
|
163
|
+
}
|
|
118
164
|
async leaveStaleConferenceSubconversations() {
|
|
119
165
|
const conversationIds = await this.getAllGroupIdsBySubconversationId(conversation_1.SUBCONVERSATION_ID.CONFERENCE);
|
|
120
166
|
for (const { parentConversationId } of conversationIds) {
|
|
@@ -161,10 +207,7 @@ class SubconversationService extends commons_1.TypedEventEmitter {
|
|
|
161
207
|
return;
|
|
162
208
|
}
|
|
163
209
|
const newSubconversationEpoch = Number(await this.mlsService.getEpoch(subconversationGroupId));
|
|
164
|
-
return onEpochUpdate({
|
|
165
|
-
...subconversationEpochInfo,
|
|
166
|
-
epoch: newSubconversationEpoch,
|
|
167
|
-
});
|
|
210
|
+
return onEpochUpdate(Object.assign(Object.assign({}, subconversationEpochInfo), { epoch: newSubconversationEpoch }));
|
|
168
211
|
};
|
|
169
212
|
this.mlsService.on('newEpoch', forwardNewEpoch);
|
|
170
213
|
await forwardNewEpoch({ groupId: subconversationGroupId, epoch: initialEpoch });
|
|
@@ -212,20 +255,5 @@ class SubconversationService extends commons_1.TypedEventEmitter {
|
|
|
212
255
|
};
|
|
213
256
|
});
|
|
214
257
|
}
|
|
215
|
-
getSubconversationGroupId = async (parentConversationId, subconversationId) => {
|
|
216
|
-
const foundSubconversation = await this.coreDatabase.get('subconversations', (0, subconversationUtil_1.generateSubconversationStoreKey)(parentConversationId, subconversationId));
|
|
217
|
-
return foundSubconversation?.groupId;
|
|
218
|
-
};
|
|
219
|
-
getAllGroupIdsBySubconversationId = async (subconversationId) => {
|
|
220
|
-
const allSubconversations = await this.coreDatabase.getAll('subconversations');
|
|
221
|
-
const foundSubconversations = allSubconversations.filter(subconversation => subconversation.subconversationId === subconversationId);
|
|
222
|
-
return foundSubconversations;
|
|
223
|
-
};
|
|
224
|
-
saveSubconversationGroupId = async (parentConversationId, subconversationId, groupId) => {
|
|
225
|
-
return this.coreDatabase.put('subconversations', { parentConversationId, subconversationId, groupId }, (0, subconversationUtil_1.generateSubconversationStoreKey)(parentConversationId, subconversationId));
|
|
226
|
-
};
|
|
227
|
-
clearSubconversationGroupId = async (parentConversationId, subconversationId) => {
|
|
228
|
-
return this.coreDatabase.delete('subconversations', (0, subconversationUtil_1.generateSubconversationStoreKey)(parentConversationId, subconversationId));
|
|
229
|
-
};
|
|
230
258
|
}
|
|
231
259
|
exports.SubconversationService = SubconversationService;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetContent.d.ts","sourceRoot":"","sources":["../../../src/conversation/content/AssetContent.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,KAAK,EAAC,MAAM,6BAA6B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,IAAI,CAAC;AACnD,OAAO,EAAC,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,eAAe,EAAC,MAAM,GAAG,CAAC;AAElF,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC;AACjD,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC;AACrC,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAGD,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,WAAW;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,oBAAoB,CAAC;IACrF,kBAAkB,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,KAAK,EAAE,sBAAsB,CAAC;IAC9B,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,KAAK,EAAE,sBAAsB,CAAC;IAC9B,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,SAAS;IACzD,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,MAAM,EAAE,WAAW,CAAC;CACrB"}
|
|
1
|
+
{"version":3,"file":"AssetContent.d.ts","sourceRoot":"","sources":["../../../src/conversation/content/AssetContent.ts"],"names":[],"mappings":";AAmBA,OAAO,EAAC,KAAK,EAAC,MAAM,6BAA6B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,kBAAkB,EAAC,MAAM,IAAI,CAAC;AACnD,OAAO,EAAC,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,eAAe,EAAC,MAAM,GAAG,CAAC;AAElF,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC;AACjD,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC;AACjD,MAAM,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC;AACrC,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAGD,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,UAAW,SAAQ,KAAK,CAAC,WAAW;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,MAAM,EAAE,UAAU,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,oBAAoB,CAAC;IACrF,kBAAkB,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,KAAK,EAAE,sBAAsB,CAAC;IAC9B,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,KAAK,EAAE,sBAAsB,CAAC;IAC9B,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,SAAS;IACzD,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAsB,SAAQ,SAAS;IACtD,MAAM,EAAE,WAAW,CAAC;CACrB"}
|
|
@@ -18,75 +18,76 @@
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.isAbortedAssetContent =
|
|
22
|
-
exports.isAssetContent = isAssetContent;
|
|
23
|
-
exports.isClearedContent = isClearedContent;
|
|
24
|
-
exports.isClientActionContent = isClientActionContent;
|
|
25
|
-
exports.isClientActionType = isClientActionType;
|
|
26
|
-
exports.isConfirmationContent = isConfirmationContent;
|
|
27
|
-
exports.isConnection = isConnection;
|
|
28
|
-
exports.isDeletedContent = isDeletedContent;
|
|
29
|
-
exports.isEditedTextContent = isEditedTextContent;
|
|
30
|
-
exports.isFileAssetAbortContent = isFileAssetAbortContent;
|
|
31
|
-
exports.isFileAssetContent = isFileAssetContent;
|
|
32
|
-
exports.isFileAssetMetaDataContent = isFileAssetMetaDataContent;
|
|
33
|
-
exports.isHiddenContent = isHiddenContent;
|
|
34
|
-
exports.isImageAssetContent = isImageAssetContent;
|
|
35
|
-
exports.isImageContent = isImageContent;
|
|
36
|
-
exports.isLocationContent = isLocationContent;
|
|
37
|
-
exports.isReactionContent = isReactionContent;
|
|
38
|
-
exports.isTextContent = isTextContent;
|
|
21
|
+
exports.isTextContent = exports.isReactionContent = exports.isLocationContent = exports.isImageContent = exports.isImageAssetContent = exports.isHiddenContent = exports.isFileAssetMetaDataContent = exports.isFileAssetContent = exports.isFileAssetAbortContent = exports.isEditedTextContent = exports.isDeletedContent = exports.isConnection = exports.isConfirmationContent = exports.isClientActionType = exports.isClientActionContent = exports.isClearedContent = exports.isAssetContent = exports.isAbortedAssetContent = void 0;
|
|
39
22
|
function isAbortedAssetContent(content) {
|
|
40
23
|
return !!content.abortReason;
|
|
41
24
|
}
|
|
25
|
+
exports.isAbortedAssetContent = isAbortedAssetContent;
|
|
42
26
|
function isAssetContent(content) {
|
|
43
27
|
return !!(content.uploaded || content.preview);
|
|
44
28
|
}
|
|
29
|
+
exports.isAssetContent = isAssetContent;
|
|
45
30
|
function isClearedContent(content) {
|
|
46
31
|
return !!content.clearedTimestamp;
|
|
47
32
|
}
|
|
33
|
+
exports.isClearedContent = isClearedContent;
|
|
48
34
|
function isClientActionContent(content) {
|
|
49
35
|
return !!content.clientAction;
|
|
50
36
|
}
|
|
37
|
+
exports.isClientActionContent = isClientActionContent;
|
|
51
38
|
function isClientActionType(content) {
|
|
52
39
|
return typeof content === 'number';
|
|
53
40
|
}
|
|
41
|
+
exports.isClientActionType = isClientActionType;
|
|
54
42
|
function isConfirmationContent(content) {
|
|
55
43
|
return !!content.firstMessageId;
|
|
56
44
|
}
|
|
45
|
+
exports.isConfirmationContent = isConfirmationContent;
|
|
57
46
|
function isConnection(content) {
|
|
58
47
|
return !!content.from && !!content.to;
|
|
59
48
|
}
|
|
49
|
+
exports.isConnection = isConnection;
|
|
60
50
|
function isDeletedContent(content) {
|
|
61
51
|
return !!content.messageId && !content.text;
|
|
62
52
|
}
|
|
53
|
+
exports.isDeletedContent = isDeletedContent;
|
|
63
54
|
function isEditedTextContent(content) {
|
|
64
55
|
return !!content.text && !!content.originalMessageId;
|
|
65
56
|
}
|
|
57
|
+
exports.isEditedTextContent = isEditedTextContent;
|
|
66
58
|
function isFileAssetAbortContent(content) {
|
|
67
59
|
return !!content.reason;
|
|
68
60
|
}
|
|
61
|
+
exports.isFileAssetAbortContent = isFileAssetAbortContent;
|
|
69
62
|
function isFileAssetContent(content) {
|
|
70
63
|
return !!content.asset && !!content.file;
|
|
71
64
|
}
|
|
65
|
+
exports.isFileAssetContent = isFileAssetContent;
|
|
72
66
|
function isFileAssetMetaDataContent(content) {
|
|
73
67
|
return !!content.metaData;
|
|
74
68
|
}
|
|
69
|
+
exports.isFileAssetMetaDataContent = isFileAssetMetaDataContent;
|
|
75
70
|
function isHiddenContent(content) {
|
|
76
71
|
return !!content.conversationId;
|
|
77
72
|
}
|
|
73
|
+
exports.isHiddenContent = isHiddenContent;
|
|
78
74
|
function isImageAssetContent(content) {
|
|
79
75
|
return !!content.asset && !!content.image;
|
|
80
76
|
}
|
|
77
|
+
exports.isImageAssetContent = isImageAssetContent;
|
|
81
78
|
function isImageContent(content) {
|
|
82
79
|
return !!content.data && !!content.type;
|
|
83
80
|
}
|
|
81
|
+
exports.isImageContent = isImageContent;
|
|
84
82
|
function isLocationContent(content) {
|
|
85
83
|
return !!content.latitude && !!content.longitude;
|
|
86
84
|
}
|
|
85
|
+
exports.isLocationContent = isLocationContent;
|
|
87
86
|
function isReactionContent(content) {
|
|
88
87
|
return !!content.type && !!content.originalMessageId;
|
|
89
88
|
}
|
|
89
|
+
exports.isReactionContent = isReactionContent;
|
|
90
90
|
function isTextContent(content) {
|
|
91
91
|
return !!content.text;
|
|
92
92
|
}
|
|
93
|
+
exports.isTextContent = isTextContent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileContent.d.ts","sourceRoot":"","sources":["../../../src/conversation/content/FileContent.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAE3E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB"}
|
|
1
|
+
{"version":3,"file":"FileContent.d.ts","sourceRoot":"","sources":["../../../src/conversation/content/FileContent.ts"],"names":[],"mappings":";AAmBA,OAAO,EAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAE3E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageContent.d.ts","sourceRoot":"","sources":["../../../src/conversation/content/ImageContent.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf"}
|
|
1
|
+
{"version":3,"file":"ImageContent.d.ts","sourceRoot":"","sources":["../../../src/conversation/content/ImageContent.ts"],"names":[],"mappings":";AAmBA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf"}
|