@wireapp/core 46.24.1 → 46.24.3

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.
Files changed (48) hide show
  1. package/lib/Account.d.ts +8 -7
  2. package/lib/Account.d.ts.map +1 -1
  3. package/lib/Account.js +23 -21
  4. package/lib/client/ClientService.js +1 -1
  5. package/lib/conversation/ConversationService/ConversationService.d.ts +8 -12
  6. package/lib/conversation/ConversationService/ConversationService.d.ts.map +1 -1
  7. package/lib/conversation/ConversationService/ConversationService.js +13 -11
  8. package/lib/conversation/ConversationService/ConversationService.test.js +11 -5
  9. package/lib/messagingProtocols/common.types.d.ts +0 -9
  10. package/lib/messagingProtocols/common.types.d.ts.map +1 -1
  11. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIService.types.d.ts +2 -2
  12. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIService.types.d.ts.map +1 -1
  13. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIService.types.js +1 -2
  14. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.d.ts.map +1 -1
  15. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.js +5 -6
  16. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.test.js +15 -20
  17. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.d.ts +3 -9
  18. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.d.ts.map +1 -1
  19. package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceInternal.js +12 -30
  20. package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.d.ts.map +1 -1
  21. package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.js +2 -7
  22. package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.test.js +34 -0
  23. package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.test.js +2 -2
  24. package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts +31 -16
  25. package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts.map +1 -1
  26. package/lib/messagingProtocols/mls/MLSService/MLSService.js +171 -74
  27. package/lib/messagingProtocols/mls/MLSService/MLSService.test.js +151 -93
  28. package/lib/messagingProtocols/mls/types.d.ts +8 -0
  29. package/lib/messagingProtocols/mls/types.d.ts.map +1 -1
  30. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts +13 -4
  31. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts.map +1 -1
  32. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.js +62 -79
  33. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts +2 -0
  34. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts.map +1 -1
  35. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts +3 -5
  36. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts.map +1 -1
  37. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.js +14 -14
  38. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts.map +1 -1
  39. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.js +1 -3
  40. package/lib/messagingProtocols/proteus/ProteusService/WithMockedGenerics.test.js +0 -3
  41. package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.test.js +0 -3
  42. package/lib/secretStore/secretKeyGenerator.d.ts +0 -1
  43. package/lib/secretStore/secretKeyGenerator.d.ts.map +1 -1
  44. package/lib/secretStore/secretKeyGenerator.js +1 -3
  45. package/package.json +6 -6
  46. package/lib/test/StoreHelper.d.ts +0 -2
  47. package/lib/test/StoreHelper.d.ts.map +0 -1
  48. package/lib/test/StoreHelper.js +0 -27
@@ -19,12 +19,16 @@
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
21
  exports.MLSService = exports.MLSServiceEvents = exports.optionalToUint8Array = void 0;
22
+ const http_1 = require("@wireapp/api-client/lib/http");
23
+ const TimeUtil_1 = require("@wireapp/commons/lib/util/TimeUtil");
22
24
  const bazinga64_1 = require("bazinga64");
23
25
  const commons_1 = require("@wireapp/commons");
24
26
  const core_crypto_1 = require("@wireapp/core-crypto");
27
+ const priority_queue_1 = require("@wireapp/priority-queue");
25
28
  const ClientMLSError_1 = require("./ClientMLSError");
26
29
  const CoreCryptoMLSError_1 = require("./CoreCryptoMLSError");
27
30
  const conversation_1 = require("../../../conversation");
31
+ const messageSender_1 = require("../../../conversation/message/messageSender");
28
32
  const fullyQualifiedClientIdUtils_1 = require("../../../util/fullyQualifiedClientIdUtils");
29
33
  const numberToHex_1 = require("../../../util/numberToHex");
30
34
  const TaskScheduler_1 = require("../../../util/TaskScheduler");
@@ -48,7 +52,6 @@ var MLSServiceEvents;
48
52
  MLSServiceEvents["NEW_EPOCH"] = "newEpoch";
49
53
  MLSServiceEvents["MLS_CLIENT_MISMATCH"] = "mlsClientMismatch";
50
54
  MLSServiceEvents["NEW_CRL_DISTRIBUTION_POINTS"] = "newCrlDistributionPoints";
51
- MLSServiceEvents["MLS_EVENT_DISTRIBUTED"] = "mlsEventDistributed";
52
55
  })(MLSServiceEvents || (exports.MLSServiceEvents = MLSServiceEvents = {}));
53
56
  class MLSService extends commons_1.TypedEventEmitter {
54
57
  apiClient;
@@ -59,27 +62,18 @@ class MLSService extends commons_1.TypedEventEmitter {
59
62
  _config;
60
63
  textEncoder = new TextEncoder();
61
64
  textDecoder = new TextDecoder();
65
+ conflictBackoffQueue = new priority_queue_1.PriorityQueue({
66
+ maxRetries: 10,
67
+ retryDelay: 500,
68
+ maxRetryDelay: TimeUtil_1.TimeInMillis.SECOND * 32,
69
+ shouldRetry: error => error instanceof http_1.BackendError && error.code === http_1.StatusCode.CONFLICT,
70
+ });
62
71
  constructor(apiClient, coreCryptoClient, coreDatabase, recurringTaskScheduler) {
63
72
  super();
64
73
  this.apiClient = apiClient;
65
74
  this.coreCryptoClient = coreCryptoClient;
66
75
  this.coreDatabase = coreDatabase;
67
76
  this.recurringTaskScheduler = recurringTaskScheduler;
68
- const mlsTransport = {
69
- sendCommitBundle: this._uploadCommitBundle,
70
- // Info: This is not used for now, but we need to implement it to be able to use the mls transport
71
- sendMessage: async () => {
72
- return 'success';
73
- },
74
- };
75
- const epochObserver = {
76
- epochChanged: async (groupId, epoch) => {
77
- const groupIdStr = bazinga64_1.Encoder.toBase64(groupId).asString;
78
- this.emit(MLSServiceEvents.NEW_EPOCH, { epoch, groupId: groupIdStr });
79
- },
80
- };
81
- void this.coreCryptoClient.registerEpochObserver(epochObserver);
82
- void this.coreCryptoClient.provideTransport(mlsTransport);
83
77
  }
84
78
  /**
85
79
  * return true if the MLS service if configured and ready to be used
@@ -109,7 +103,13 @@ class MLSService extends commons_1.TypedEventEmitter {
109
103
  ...defaultConfig,
110
104
  ...filteredMLSConfig,
111
105
  };
112
- await this.coreCryptoClient.transaction(cx => cx.mlsInit((0, MLSId_1.generateMLSDeviceId)(userId, client.id), this.config.ciphersuites, this.config.nbKeyPackages));
106
+ await this.coreCryptoClient.mlsInit((0, MLSId_1.generateMLSDeviceId)(userId, client.id), this.config.ciphersuites, this.config.nbKeyPackages);
107
+ await this.coreCryptoClient.registerCallbacks({
108
+ // All authorization/membership rules are enforced on backend
109
+ clientIsExistingGroupUser: async () => true,
110
+ authorize: async () => true,
111
+ userAuthorize: async () => true,
112
+ });
113
113
  try {
114
114
  const ccClientSignature = await this.getCCClientSignatureString();
115
115
  const mlsDeviceStatus = (0, Helper_1.getMLSDeviceStatus)(client, this.config.defaultCiphersuite, ccClientSignature);
@@ -151,26 +151,47 @@ class MLSService extends commons_1.TypedEventEmitter {
151
151
  ? core_crypto_1.CredentialType.X509
152
152
  : core_crypto_1.CredentialType.Basic;
153
153
  }
154
- _uploadCommitBundle = async ({ commit, groupInfo, welcome, }) => {
155
- // We need to lock the incoming mls messages queue while we are uploading the commit bundle
156
- // it's possible that we will be sent some mls messages before we receive the response from backend and accept a commit locally.
157
- const bundlePayload = new Uint8Array([...commit, ...groupInfo.payload, ...(welcome || [])]);
154
+ uploadCommitBundle = async (groupId, commitBundle, { isExternalCommit = false, regenerateCommitBundle } = {}) => {
158
155
  try {
159
- const response = await this.apiClient.api.conversation.postMlsCommitBundle(bundlePayload);
160
- if (response.failed_to_send) {
161
- this.logger.warn(`Failed to send commit bundle to backend`);
162
- return 'retry';
163
- }
164
- const { events, time } = response;
165
- this.emit(MLSServiceEvents.MLS_EVENT_DISTRIBUTED, { events, time });
166
- return 'success';
156
+ return await this._uploadCommitBundle(groupId, async () => commitBundle, isExternalCommit);
167
157
  }
168
158
  catch (error) {
169
- return {
170
- abort: { reason: error instanceof Error ? error.message : 'unknown error' },
171
- };
159
+ if (error instanceof http_1.BackendError && error.code === http_1.StatusCode.CONFLICT && regenerateCommitBundle) {
160
+ return this.conflictBackoffQueue.add(async () => this._uploadCommitBundle(groupId, regenerateCommitBundle, isExternalCommit));
161
+ }
162
+ throw error;
172
163
  }
173
164
  };
165
+ _uploadCommitBundle = async (groupId, generateCommitBundle, isExternalCommit) => {
166
+ const groupIdStr = bazinga64_1.Encoder.toBase64(groupId).asString;
167
+ // We need to lock the incoming mls messages queue while we are uploading the commit bundle
168
+ // it's possible that we will be sent some mls messages before we receive the response from backend and accept a commit locally.
169
+ return (0, messageAdd_1.withLockedMLSMessagesQueue)(groupIdStr, async () => {
170
+ const { commit, groupInfo, welcome } = await generateCommitBundle();
171
+ const bundlePayload = new Uint8Array([...commit, ...groupInfo.payload, ...(welcome || [])]);
172
+ try {
173
+ const response = await this.apiClient.api.conversation.postMlsCommitBundle(bundlePayload);
174
+ if (isExternalCommit) {
175
+ await this.coreCryptoClient.mergePendingGroupFromExternalCommit(groupId);
176
+ }
177
+ else {
178
+ await this.coreCryptoClient.commitAccepted(groupId);
179
+ }
180
+ const newEpoch = await this.getEpoch(groupId);
181
+ this.emit(MLSServiceEvents.NEW_EPOCH, { epoch: newEpoch, groupId: groupIdStr });
182
+ return response;
183
+ }
184
+ catch (error) {
185
+ if (isExternalCommit) {
186
+ await this.coreCryptoClient.clearPendingGroupFromExternalCommit(groupId);
187
+ }
188
+ else {
189
+ await this.coreCryptoClient.clearPendingCommit(groupId);
190
+ }
191
+ throw error;
192
+ }
193
+ });
194
+ };
174
195
  /**
175
196
  * Will add users to an existing MLS group and send a commit bundle to backend.
176
197
  * Cannot be called with an empty array of keys.
@@ -183,8 +204,23 @@ class MLSService extends commons_1.TypedEventEmitter {
183
204
  if (keyPackages.length < 1) {
184
205
  throw new Error('Empty list of keys provided to addUsersToExistingConversation');
185
206
  }
186
- const crlNewDistributionPoints = await this.coreCryptoClient.transaction(cx => cx.addClientsToConversation(groupIdBytes, keyPackages));
187
- this.dispatchNewCrlDistributionPoints(crlNewDistributionPoints);
207
+ // TODO: handle federation error when sending a commit bundle to backend like we do in ProteusService
208
+ const response = await this.processCommitAction(groupIdBytes, async () => {
209
+ const commitBundle = await this.coreCryptoClient.addClientsToConversation(groupIdBytes, keyPackages);
210
+ this.dispatchNewCrlDistributionPoints(commitBundle);
211
+ return commitBundle;
212
+ });
213
+ const failedUsers = response.failed;
214
+ const failures = failedUsers
215
+ ? [
216
+ {
217
+ users: failedUsers,
218
+ backends: failedUsers.map(({ domain }) => domain),
219
+ reason: conversation_1.AddUsersFailureReasons.UNREACHABLE_BACKENDS,
220
+ },
221
+ ]
222
+ : [];
223
+ return { ...response, failures };
188
224
  }
189
225
  /**
190
226
  * Will return a list of client ids which are already in the group at core crypto level
@@ -266,55 +302,90 @@ class MLSService extends commons_1.TypedEventEmitter {
266
302
  const groupIdBytes = typeof groupId === 'string' ? bazinga64_1.Decoder.fromBase64(groupId).asBytes : groupId;
267
303
  return this.coreCryptoClient.conversationEpoch(groupIdBytes);
268
304
  }
305
+ async newProposal(proposalType, args) {
306
+ return this.coreCryptoClient.newProposal(proposalType, args);
307
+ }
269
308
  async joinByExternalCommit(getGroupInfo) {
270
309
  const credentialType = await this.getCredentialType();
271
- const groupInfo = await getGroupInfo();
272
- const welcomeBundle = await this.coreCryptoClient.transaction(cx => cx.joinByExternalCommit(groupInfo, credentialType));
273
- await this.dispatchNewCrlDistributionPoints(welcomeBundle.crlNewDistributionPoints);
274
- if (welcomeBundle.id) {
310
+ const generateCommit = async () => {
311
+ const groupInfo = await getGroupInfo();
312
+ const joinRequest = await this.coreCryptoClient.joinByExternalCommit(groupInfo, credentialType);
313
+ this.dispatchNewCrlDistributionPoints(joinRequest);
314
+ const { conversationId, ...commitBundle } = joinRequest;
315
+ return { groupId: conversationId, commitBundle };
316
+ };
317
+ const { commitBundle, groupId } = await generateCommit();
318
+ const mlsResponse = await this.uploadCommitBundle(groupId, commitBundle, {
319
+ isExternalCommit: true,
320
+ regenerateCommitBundle: async () => (await generateCommit()).commitBundle,
321
+ });
322
+ if (mlsResponse) {
275
323
  //after we've successfully joined via external commit, we schedule periodic key material renewal
276
- const groupIdStr = bazinga64_1.Encoder.toBase64(welcomeBundle.id).asString;
324
+ const groupIdStr = bazinga64_1.Encoder.toBase64(groupId).asString;
277
325
  await this.scheduleKeyMaterialRenewal(groupIdStr);
278
326
  }
327
+ return mlsResponse;
279
328
  }
280
329
  async exportSecretKey(groupId, keyLength) {
281
330
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
282
331
  const key = await this.coreCryptoClient.exportSecretKey(groupIdBytes, keyLength);
283
332
  return bazinga64_1.Encoder.toBase64(key).asString;
284
333
  }
285
- dispatchNewCrlDistributionPoints(crlNewDistributionPoints) {
334
+ dispatchNewCrlDistributionPoints(payload) {
335
+ const { crlNewDistributionPoints } = payload;
286
336
  if (crlNewDistributionPoints && crlNewDistributionPoints.length > 0) {
287
337
  this.emit(MLSServiceEvents.NEW_CRL_DISTRIBUTION_POINTS, crlNewDistributionPoints);
288
338
  }
289
339
  }
290
340
  async processWelcomeMessage(welcomeMessage) {
291
- const welcomeBundle = await this.coreCryptoClient.transaction(cx => cx.processWelcomeMessage(welcomeMessage));
292
- this.dispatchNewCrlDistributionPoints(welcomeBundle.crlNewDistributionPoints);
341
+ const welcomeBundle = await this.coreCryptoClient.processWelcomeMessage(welcomeMessage);
342
+ this.dispatchNewCrlDistributionPoints(welcomeBundle);
293
343
  return welcomeBundle.id;
294
344
  }
295
345
  async decryptMessage(conversationId, payload) {
296
- try {
297
- const decryptedMessage = await this.coreCryptoClient.transaction(cx => cx.decryptMessage(conversationId, payload));
298
- this.dispatchNewCrlDistributionPoints(decryptedMessage.crlNewDistributionPoints);
299
- return decryptedMessage;
300
- }
301
- catch (error) {
302
- // According to CoreCrypto JS doc on .decryptMessage method, we should ignore some errors (corecrypto handle them internally)
303
- if ((0, CoreCryptoMLSError_1.shouldMLSDecryptionErrorBeIgnored)(error)) {
304
- return {
305
- hasEpochChanged: false,
306
- isActive: false,
307
- };
346
+ return await this.coreCryptoClient.transaction(async (cx) => {
347
+ try {
348
+ const decryptedMessage = await cx.decryptMessage(conversationId, payload);
349
+ this.dispatchNewCrlDistributionPoints(decryptedMessage);
350
+ return decryptedMessage;
308
351
  }
309
- return undefined;
310
- }
352
+ catch (error) {
353
+ // According to CoreCrypto JS doc on .decryptMessage method, we should ignore some errors (corecrypto handle them internally)
354
+ if ((0, CoreCryptoMLSError_1.shouldMLSDecryptionErrorBeIgnored)(error)) {
355
+ return {
356
+ hasEpochChanged: false,
357
+ isActive: false,
358
+ proposals: [],
359
+ };
360
+ }
361
+ throw error;
362
+ }
363
+ });
311
364
  }
312
365
  async encryptMessage(conversationId, message) {
313
- return this.coreCryptoClient.transaction(cx => cx.encryptMessage(conversationId, message));
366
+ return this.coreCryptoClient.encryptMessage(conversationId, message);
367
+ }
368
+ /**
369
+ * Will wrap a coreCrypto call that generates a CommitBundle and do all the necessary work so that commitbundle is handled the right way.
370
+ * It does:
371
+ * - commit the pending proposal
372
+ * - then generates the commitBundle with the given function
373
+ * - uploads the commitBundle to backend
374
+ * - warns coreCrypto that the commit was successfully processed
375
+ * @param groupId
376
+ * @param generateCommit The function that will generate a coreCrypto CommitBundle
377
+ */
378
+ async processCommitAction(groupId, generateCommit) {
379
+ const groupIdStr = bazinga64_1.Encoder.toBase64(groupId).asString;
380
+ return (0, messageSender_1.sendMessage)(async () => {
381
+ await this.commitPendingProposals(groupIdStr);
382
+ const commitBundle = await generateCommit();
383
+ return this.uploadCommitBundle(groupId, commitBundle, { regenerateCommitBundle: generateCommit });
384
+ });
314
385
  }
315
- async updateKeyingMaterial(groupId) {
386
+ updateKeyingMaterial(groupId) {
316
387
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
317
- await this.coreCryptoClient.transaction(cx => cx.updateKeyingMaterial(groupIdBytes));
388
+ return this.processCommitAction(groupIdBytes, () => this.coreCryptoClient.updateKeyingMaterial(groupIdBytes));
318
389
  }
319
390
  /**
320
391
  * Will create an empty conversation inside of coreCrypto.
@@ -342,7 +413,7 @@ class MLSService extends commons_1.TypedEventEmitter {
342
413
  ciphersuite: this.config.defaultCiphersuite,
343
414
  };
344
415
  const credentialType = await this.getCredentialType();
345
- return this.coreCryptoClient.transaction(cx => cx.createConversation(groupIdBytes, credentialType, configuration));
416
+ return this.coreCryptoClient.createConversation(groupIdBytes, credentialType, configuration);
346
417
  }
347
418
  /**
348
419
  * Will create a conversation inside of coreCrypto, add users to it or update the keying material if empty key packages list is provided.
@@ -366,17 +437,19 @@ class MLSService extends commons_1.TypedEventEmitter {
366
437
  }));
367
438
  if (keyPackages.length <= 0) {
368
439
  // If there are no clients to add, just update the keying material
369
- await this.updateKeyingMaterial(groupId);
440
+ const response = await this.updateKeyingMaterial(groupId);
370
441
  await this.scheduleKeyMaterialRenewal(groupId);
371
- return keysClaimingFailures;
442
+ return { ...response, failures: keysClaimingFailures };
372
443
  }
444
+ const response = await this.addUsersToExistingConversation(groupId, keyPackages);
373
445
  // We schedule a periodic key material renewal
374
446
  await this.scheduleKeyMaterialRenewal(groupId);
375
447
  /**
376
448
  * @note If we can't fetch a user's key packages then we can not add them to mls conversation
377
449
  * so we're adding them to the list of failed users.
378
450
  */
379
- return keysClaimingFailures;
451
+ response.failures = [...keysClaimingFailures, ...response.failures];
452
+ return response;
380
453
  }
381
454
  /**
382
455
  * Will create a 1:1 conversation inside of coreCrypto, try claiming key packages for user and (if succesfull) add them to the MLS group.
@@ -399,10 +472,14 @@ class MLSService extends commons_1.TypedEventEmitter {
399
472
  const { keyPackages: selfKeyPackages, failures: selfKeysClaimingFailures } = await this.getKeyPackagesPayload([
400
473
  { ...selfUser.user, skipOwnClientId: selfUser.client },
401
474
  ]);
402
- await this.addUsersToExistingConversation(groupId, [...otherUserKeyPackages, ...selfKeyPackages]);
475
+ const response = await this.addUsersToExistingConversation(groupId, [
476
+ ...otherUserKeyPackages,
477
+ ...selfKeyPackages,
478
+ ]);
403
479
  // We schedule a periodic key material renewal
404
480
  await this.scheduleKeyMaterialRenewal(groupId);
405
- return [...otherUserKeysClaimingFailures, ...selfKeysClaimingFailures];
481
+ response.failures = [...otherUserKeysClaimingFailures, ...selfKeysClaimingFailures, ...response.failures];
482
+ return response;
406
483
  }
407
484
  catch (error) {
408
485
  await this.wipeConversation(groupId);
@@ -448,7 +525,7 @@ class MLSService extends commons_1.TypedEventEmitter {
448
525
  */
449
526
  removeClientsFromConversation(groupId, clientIds) {
450
527
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
451
- return this.coreCryptoClient.transaction(cx => cx.removeClientsFromConversation(groupIdBytes, clientIds.map(id => this.textEncoder.encode(id))));
528
+ return this.processCommitAction(groupIdBytes, () => this.coreCryptoClient.removeClientsFromConversation(groupIdBytes, clientIds.map(id => this.textEncoder.encode(id))));
452
529
  }
453
530
  /**
454
531
  * Will check if mls group exists in corecrypto.
@@ -469,11 +546,11 @@ class MLSService extends commons_1.TypedEventEmitter {
469
546
  }
470
547
  async clientValidKeypackagesCount() {
471
548
  const credentialType = await this.getCredentialType();
472
- return this.coreCryptoClient.transaction(cx => cx.clientValidKeypackagesCount(this.config.defaultCiphersuite, credentialType));
549
+ return this.coreCryptoClient.clientValidKeypackagesCount(this.config.defaultCiphersuite, credentialType);
473
550
  }
474
551
  async clientKeypackages(amountRequested) {
475
552
  const credentialType = await this.getCredentialType();
476
- return this.coreCryptoClient.transaction(cx => cx.clientKeypackages(this.config.defaultCiphersuite, credentialType, amountRequested));
553
+ return this.coreCryptoClient.clientKeypackages(this.config.defaultCiphersuite, credentialType, amountRequested);
477
554
  }
478
555
  /**
479
556
  * Will send an empty commit into a group (renew key material)
@@ -620,7 +697,7 @@ class MLSService extends commons_1.TypedEventEmitter {
620
697
  return;
621
698
  }
622
699
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
623
- return this.coreCryptoClient.transaction(cx => cx.wipeConversation(groupIdBytes));
700
+ return this.coreCryptoClient.wipeConversation(groupIdBytes);
624
701
  }
625
702
  /**
626
703
  * If there are pending proposals, we need to either process them,
@@ -663,7 +740,10 @@ class MLSService extends commons_1.TypedEventEmitter {
663
740
  async commitPendingProposals(groupId, shouldRetry = true) {
664
741
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
665
742
  try {
666
- await this.coreCryptoClient.transaction(cx => cx.commitPendingProposals(groupIdBytes));
743
+ const commitBundle = await this.coreCryptoClient.commitPendingProposals(groupIdBytes);
744
+ if (commitBundle) {
745
+ await this.uploadCommitBundle(groupIdBytes, commitBundle);
746
+ }
667
747
  await this.cancelPendingProposalsTask(groupId);
668
748
  }
669
749
  catch (error) {
@@ -671,6 +751,11 @@ class MLSService extends commons_1.TypedEventEmitter {
671
751
  throw error;
672
752
  }
673
753
  this.logger.warn('Failed to commit proposals, clearing the pending commit and retrying', error);
754
+ // If we failed to commit the proposals, we need to clear the pending commit and retry
755
+ // this is to avoid a situation where we are stuck with pending proposals that we can't commit.
756
+ // If there's nothing to clear the methods might throw an error, which we can ignore.
757
+ await this.coreCryptoClient.clearPendingCommit(groupIdBytes).catch(() => undefined);
758
+ await this.coreCryptoClient.clearPendingGroupFromExternalCommit(groupIdBytes).catch(() => undefined);
674
759
  return this.commitPendingProposals(groupId, false);
675
760
  }
676
761
  }
@@ -739,20 +824,32 @@ class MLSService extends commons_1.TypedEventEmitter {
739
824
  * @param oAuthIdToken The OAuth id token if the user is already authenticated
740
825
  * @returns AcmeChallenge if the user is not authenticated, true if the user is authenticated
741
826
  */
742
- async enrollE2EI(discoveryUrl, user, client, nbPrekeys, certificateTtl, getOAuthToken, getAllConversations) {
827
+ async enrollE2EI(discoveryUrl, user, client, nbPrekeys, certificateTtl, getOAuthToken) {
743
828
  const isCertificateRenewal = await this.coreCryptoClient.e2eiIsEnabled(this.config.defaultCiphersuite);
744
829
  const e2eiServiceInternal = new E2EIServiceInternal_1.E2EIServiceInternal(this.coreDatabase, this.coreCryptoClient, this.apiClient, certificateTtl, nbPrekeys, { user, clientId: client.id, discoveryUrl });
745
- const { keyPackages, newCrlDistributionPoints } = await e2eiServiceInternal.generateCertificate(getOAuthToken, isCertificateRenewal, getAllConversations, this.config.defaultCiphersuite);
746
- this.dispatchNewCrlDistributionPoints(newCrlDistributionPoints);
830
+ const rotateBundle = await e2eiServiceInternal.generateCertificate(getOAuthToken, isCertificateRenewal, this.config.defaultCiphersuite);
831
+ this.dispatchNewCrlDistributionPoints(rotateBundle);
747
832
  // upload the clients public keys
748
833
  if (!this.isInitializedMLSClient(client)) {
749
834
  // we only upload public keys for the initial certification process if the device is not already a registered MLS device.
750
835
  await this.uploadMLSPublicKeys(client);
751
836
  }
752
837
  // replace old key packages with new key packages with x509 certificate
753
- await this.replaceKeyPackages(client.id, keyPackages);
838
+ await this.replaceKeyPackages(client.id, rotateBundle.newKeyPackages);
754
839
  // Verify that we have enough key packages
755
840
  await this.verifyRemoteMLSKeyPackagesAmount(client.id);
841
+ // Update keying material
842
+ for (const [groupId, commitBundle] of rotateBundle.commits) {
843
+ const groupIdAsBytes = bazinga64_1.Converter.hexStringToArrayBufferView(groupId);
844
+ // manual copy of the commit bundle data because of a problem while cloning it
845
+ const newCommitBundle = {
846
+ commit: commitBundle.commit,
847
+ // @ts-ignore
848
+ groupInfo: commitBundle?.group_info || commitBundle.groupInfo,
849
+ welcome: commitBundle?.welcome,
850
+ };
851
+ await this.uploadCommitBundle(groupIdAsBytes, newCommitBundle);
852
+ }
756
853
  }
757
854
  }
758
855
  exports.MLSService = MLSService;