@wireapp/core 46.24.0 → 46.24.2
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 +8 -7
- package/lib/Account.d.ts.map +1 -1
- package/lib/Account.js +23 -21
- package/lib/client/ClientService.js +1 -1
- package/lib/conversation/ConversationService/ConversationService.d.ts +8 -12
- package/lib/conversation/ConversationService/ConversationService.d.ts.map +1 -1
- package/lib/conversation/ConversationService/ConversationService.js +13 -11
- package/lib/conversation/ConversationService/ConversationService.test.js +11 -5
- 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.map +1 -1
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.js +5 -6
- package/lib/messagingProtocols/mls/E2EIdentityService/E2EIServiceExternal.test.js +15 -20
- 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 -30
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.js +2 -7
- package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.test.js +34 -0
- package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.test.js +2 -2
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts +31 -16
- package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts.map +1 -1
- package/lib/messagingProtocols/mls/MLSService/MLSService.js +171 -74
- package/lib/messagingProtocols/mls/MLSService/MLSService.test.js +151 -93
- package/lib/messagingProtocols/mls/types.d.ts +8 -0
- package/lib/messagingProtocols/mls/types.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts +13 -4
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.js +62 -79
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts +2 -0
- package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts.map +1 -1
- 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 +14 -14
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts.map +1 -1
- package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.js +1 -3
- package/lib/messagingProtocols/proteus/ProteusService/WithMockedGenerics.test.js +0 -3
- package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.test.js +0 -3
- 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/package.json +6 -6
- 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,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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
170
|
-
|
|
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
|
-
|
|
187
|
-
this.
|
|
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
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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(
|
|
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(
|
|
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.
|
|
292
|
-
this.dispatchNewCrlDistributionPoints(welcomeBundle
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
386
|
+
updateKeyingMaterial(groupId) {
|
|
316
387
|
const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
|
|
317
|
-
|
|
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.
|
|
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
|
-
|
|
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, [
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
746
|
-
this.dispatchNewCrlDistributionPoints(
|
|
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,
|
|
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;
|