@wireapp/core 42.19.0 → 42.19.1

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 CHANGED
@@ -9,6 +9,7 @@ import { BroadcastService } from './broadcast/';
9
9
  import { ClientInfo, ClientService } from './client/';
10
10
  import { ConnectionService } from './connection/';
11
11
  import { AssetService, ConversationService } from './conversation/';
12
+ import { SubconversationService } from './conversation/SubconversationService/SubconversationService';
12
13
  import { GiphyService } from './giphy/';
13
14
  import { LinkPreviewService } from './linkPreview';
14
15
  import { MLSService } from './messagingProtocols/mls';
@@ -83,6 +84,7 @@ export declare class Account extends TypedEventEmitter<Events> {
83
84
  client: ClientService;
84
85
  connection: ConnectionService;
85
86
  conversation: ConversationService;
87
+ subconversation: SubconversationService;
86
88
  giphy: GiphyService;
87
89
  linkPreview: LinkPreviewService;
88
90
  notification: NotificationService;
@@ -1 +1 @@
1
- {"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"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"}
package/lib/Account.js CHANGED
@@ -45,6 +45,7 @@ const client_2 = require("./client/");
45
45
  const connection_1 = require("./connection/");
46
46
  const conversation_1 = require("./conversation/");
47
47
  const messageSender_1 = require("./conversation/message/messageSender");
48
+ const SubconversationService_1 = require("./conversation/SubconversationService/SubconversationService");
48
49
  const giphy_1 = require("./giphy/");
49
50
  const linkPreview_1 = require("./linkPreview");
50
51
  const mls_1 = require("./messagingProtocols/mls");
@@ -245,7 +246,7 @@ class Account extends commons_1.TypedEventEmitter {
245
246
  // initialize scheduler for syncing key packages with backend
246
247
  await this.service.mls.schedulePeriodicKeyPackagesBackendSync(validClient.id);
247
248
  // leave stale conference subconversations (e.g after a crash)
248
- await this.service.mls.leaveStaleConferenceSubconversations();
249
+ await this.service.subconversation.leaveStaleConferenceSubconversations();
249
250
  }
250
251
  return validClient;
251
252
  }
@@ -306,6 +307,7 @@ class Account extends commons_1.TypedEventEmitter {
306
307
  const giphyService = new giphy_1.GiphyService(this.apiClient);
307
308
  const linkPreviewService = new linkPreview_1.LinkPreviewService(assetService);
308
309
  const conversationService = new conversation_1.ConversationService(this.apiClient, proteusService, this.db, mlsService);
310
+ const subconversationService = new SubconversationService_1.SubconversationService(this.apiClient, mlsService);
309
311
  const notificationService = new notification_1.NotificationService(this.apiClient, this.storeEngine, conversationService);
310
312
  const selfService = new self_1.SelfService(this.apiClient);
311
313
  const teamService = new team_1.TeamService(this.apiClient);
@@ -321,6 +323,7 @@ class Account extends commons_1.TypedEventEmitter {
321
323
  client: clientService,
322
324
  connection: connectionService,
323
325
  conversation: conversationService,
326
+ subconversation: subconversationService,
324
327
  giphy: giphyService,
325
328
  linkPreview: linkPreviewService,
326
329
  notification: notificationService,
@@ -0,0 +1,60 @@
1
+ import { QualifiedId } from '@wireapp/api-client/lib/user';
2
+ import { APIClient } from '@wireapp/api-client';
3
+ import { TypedEventEmitter } from '@wireapp/commons';
4
+ import { MLSService } from '../../messagingProtocols/mls';
5
+ type Events = {
6
+ MLSConversationRecovered: {
7
+ conversationId: QualifiedId;
8
+ };
9
+ };
10
+ export interface SubconversationEpochInfoMember {
11
+ userid: `${string}@${string}`;
12
+ clientid: string;
13
+ in_subconv: boolean;
14
+ }
15
+ export declare class SubconversationService extends TypedEventEmitter<Events> {
16
+ private readonly apiClient;
17
+ private readonly _mlsService?;
18
+ private readonly logger;
19
+ constructor(apiClient: APIClient, _mlsService?: MLSService | undefined);
20
+ get mlsService(): MLSService;
21
+ /**
22
+ * Will join or register an mls subconversation for conference calls.
23
+ * Will return the secret key derived from the subconversation
24
+ *
25
+ * @param conversationId Id of the parent conversation in which the call should happen
26
+ */
27
+ joinConferenceSubconversation(conversationId: QualifiedId, shouldRetry?: boolean): Promise<{
28
+ groupId: string;
29
+ epoch: number;
30
+ }>;
31
+ /**
32
+ * Will leave conference subconversation if it's known by client and established.
33
+ *
34
+ * @param conversationId Id of the parent conversation which subconversation we want to leave
35
+ */
36
+ leaveConferenceSubconversation(conversationId: QualifiedId): Promise<void>;
37
+ leaveStaleConferenceSubconversations(): Promise<void>;
38
+ getSubconversationEpochInfo(conversationId: QualifiedId, shouldAdvanceEpoch?: boolean): Promise<{
39
+ members: SubconversationEpochInfoMember[];
40
+ epoch: number;
41
+ secretKey: string;
42
+ keyLength: number;
43
+ } | null>;
44
+ subscribeToEpochUpdates(conversationId: QualifiedId, findConversationByGroupId: (groupId: string) => QualifiedId | undefined, onEpochUpdate: (info: {
45
+ members: SubconversationEpochInfoMember[];
46
+ epoch: number;
47
+ secretKey: string;
48
+ keyLength: number;
49
+ }) => void): Promise<() => void>;
50
+ removeClientFromConferenceSubconversation(conversationId: QualifiedId, clientToRemove: {
51
+ user: QualifiedId;
52
+ clientId: string;
53
+ }): Promise<void>;
54
+ private joinSubconversationByExternalCommit;
55
+ private getConferenceSubconversation;
56
+ private deleteConferenceSubconversation;
57
+ private generateSubconversationMembers;
58
+ }
59
+ export {};
60
+ //# sourceMappingURL=SubconversationService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubconversationService.d.ts","sourceRoot":"","sources":["../../../src/conversation/SubconversationService/SubconversationService.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAIzD,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAC,iBAAiB,EAAC,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAC,UAAU,EAAC,MAAM,8BAA8B,CAAC;AAIxD,KAAK,MAAM,GAAG;IACZ,wBAAwB,EAAE;QAAC,cAAc,EAAE,WAAW,CAAA;KAAC,CAAC;CACzD,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;IAC9B,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,WAAW,CAAC;IAJ/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmD;gBAGvD,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,wBAAY;IAK3C,IAAI,UAAU,IAAI,UAAU,CAK3B;IAED;;;;;OAKG;IACU,6BAA6B,CACxC,cAAc,EAAE,WAAW,EAC3B,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;IA4B1E,oCAAoC,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrD,2BAA2B,CACtC,cAAc,EAAE,WAAW,EAC3B,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;IAsCI,uBAAuB,CAClC,cAAc,EAAE,WAAW,EAC3B,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;IAuCT,yCAAyC,CACpD,cAAc,EAAE,WAAW,EAC3B,cAAc,EAAE;QAAC,IAAI,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAC,GACpD,OAAO,CAAC,IAAI,CAAC;YAmCF,mCAAmC;YAMnC,4BAA4B;YAI5B,+BAA+B;YAO/B,8BAA8B;CAqB7C"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ /*
3
+ * Wire
4
+ * Copyright (C) 2023 Wire Swiss GmbH
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see http://www.gnu.org/licenses/.
18
+ *
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.SubconversationService = void 0;
25
+ const conversation_1 = require("@wireapp/api-client/lib/conversation");
26
+ const TimeUtil_1 = require("@wireapp/commons/lib/util/TimeUtil");
27
+ const logdown_1 = __importDefault(require("logdown"));
28
+ const commons_1 = require("@wireapp/commons");
29
+ const subconversationGroupIdStore_1 = require("../../messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore");
30
+ const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
31
+ const MLS_CONVERSATION_KEY_LENGTH = 32;
32
+ class SubconversationService extends commons_1.TypedEventEmitter {
33
+ constructor(apiClient, _mlsService) {
34
+ super();
35
+ this.apiClient = apiClient;
36
+ this._mlsService = _mlsService;
37
+ this.logger = (0, logdown_1.default)('@wireapp/core/SubconversationService');
38
+ }
39
+ get mlsService() {
40
+ if (!this._mlsService) {
41
+ throw new Error('MLSService was not initialised!');
42
+ }
43
+ return this._mlsService;
44
+ }
45
+ /**
46
+ * Will join or register an mls subconversation for conference calls.
47
+ * Will return the secret key derived from the subconversation
48
+ *
49
+ * @param conversationId Id of the parent conversation in which the call should happen
50
+ */
51
+ async joinConferenceSubconversation(conversationId, shouldRetry = true) {
52
+ try {
53
+ const { group_id: subconversationGroupId, epoch: subconversationEpoch, epoch_timestamp: subconversationEpochTimestamp, subconv_id: subconversationId, } = await this.getConferenceSubconversation(conversationId);
54
+ if (subconversationEpoch === 0) {
55
+ const doesConversationExistsLocally = await this.mlsService.conversationExists(subconversationGroupId);
56
+ if (doesConversationExistsLocally) {
57
+ await this.mlsService.wipeConversation(subconversationGroupId);
58
+ }
59
+ // If subconversation is not yet established, create it and upload the commit bundle.
60
+ await this.mlsService.registerConversation(subconversationGroupId, []);
61
+ }
62
+ else {
63
+ const epochUpdateTime = new Date(subconversationEpochTimestamp).getTime();
64
+ const epochAge = new Date().getTime() - epochUpdateTime;
65
+ if (epochAge > TimeUtil_1.TimeInMillis.DAY) {
66
+ // If subconversation does exist, but it's older than 24h, delete and re-join
67
+ await this.deleteConferenceSubconversation(conversationId, {
68
+ groupId: subconversationGroupId,
69
+ epoch: subconversationEpoch,
70
+ });
71
+ await this.mlsService.wipeConversation(subconversationGroupId);
72
+ return this.joinConferenceSubconversation(conversationId);
73
+ }
74
+ await this.joinSubconversationByExternalCommit(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
75
+ }
76
+ const epoch = Number(await this.mlsService.getEpoch(subconversationGroupId));
77
+ // We store the mapping between the subconversation and the parent conversation
78
+ subconversationGroupIdStore_1.subconversationGroupIdStore.storeGroupId(conversationId, subconversationId, subconversationGroupId);
79
+ return { groupId: subconversationGroupId, epoch };
80
+ }
81
+ catch (error) {
82
+ if (shouldRetry) {
83
+ return this.joinConferenceSubconversation(conversationId, false);
84
+ }
85
+ throw error;
86
+ }
87
+ }
88
+ /**
89
+ * Will leave conference subconversation if it's known by client and established.
90
+ *
91
+ * @param conversationId Id of the parent conversation which subconversation we want to leave
92
+ */
93
+ async leaveConferenceSubconversation(conversationId) {
94
+ const subconversationGroupId = subconversationGroupIdStore_1.subconversationGroupIdStore.getGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
95
+ if (!subconversationGroupId) {
96
+ return;
97
+ }
98
+ const doesGroupExistLocally = await this.mlsService.conversationExists(subconversationGroupId);
99
+ if (!doesGroupExistLocally) {
100
+ // If the subconversation was known by a client but is does not exist locally, we can remove it from the store.
101
+ return subconversationGroupIdStore_1.subconversationGroupIdStore.removeGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
102
+ }
103
+ try {
104
+ await this.apiClient.api.conversation.deleteSubconversationSelf(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
105
+ }
106
+ catch (error) {
107
+ this.logger.error(`Failed to leave conference subconversation:`, error);
108
+ }
109
+ await this.mlsService.wipeConversation(subconversationGroupId);
110
+ // once we've left the subconversation, we can remove it from the store
111
+ subconversationGroupIdStore_1.subconversationGroupIdStore.removeGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
112
+ }
113
+ async leaveStaleConferenceSubconversations() {
114
+ const conversationIds = subconversationGroupIdStore_1.subconversationGroupIdStore.getAllGroupIdsBySubconversationId(conversation_1.SUBCONVERSATION_ID.CONFERENCE);
115
+ for (const { parentConversationId } of conversationIds) {
116
+ await this.leaveConferenceSubconversation(parentConversationId);
117
+ }
118
+ }
119
+ async getSubconversationEpochInfo(conversationId, shouldAdvanceEpoch = false) {
120
+ const subconversationGroupId = await this.mlsService.getGroupIdFromConversationId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
121
+ const parentGroupId = await this.mlsService.getGroupIdFromConversationId(conversationId);
122
+ // this method should not be called if the subconversation (and its parent conversation) is not established
123
+ if (!subconversationGroupId || !parentGroupId) {
124
+ this.logger.error(`Could not obtain epoch info for conference subconversation of conversation ${JSON.stringify(conversationId)}: parent or subconversation group ID is missing`);
125
+ return null;
126
+ }
127
+ //we don't want to react to avs callbacks when conversation was not yet established
128
+ const doesMLSGroupExist = await this.mlsService.conversationExists(subconversationGroupId);
129
+ if (!doesMLSGroupExist) {
130
+ return null;
131
+ }
132
+ const members = await this.generateSubconversationMembers(subconversationGroupId, parentGroupId);
133
+ if (shouldAdvanceEpoch) {
134
+ await this.mlsService.renewKeyMaterial(subconversationGroupId);
135
+ }
136
+ const epoch = Number(await this.mlsService.getEpoch(subconversationGroupId));
137
+ const secretKey = await this.mlsService.exportSecretKey(subconversationGroupId, MLS_CONVERSATION_KEY_LENGTH);
138
+ return { members, epoch, keyLength: MLS_CONVERSATION_KEY_LENGTH, secretKey };
139
+ }
140
+ async subscribeToEpochUpdates(conversationId, findConversationByGroupId, onEpochUpdate) {
141
+ const { epoch: initialEpoch, groupId: subconversationGroupId } = await this.joinConferenceSubconversation(conversationId);
142
+ const forwardNewEpoch = async ({ groupId, epoch }) => {
143
+ var _a, _b;
144
+ if (groupId !== subconversationGroupId) {
145
+ // if the epoch update did not happen in the subconversation directly, check if it happened in the parent conversation
146
+ const parentConversationId = findConversationByGroupId(groupId);
147
+ if (!parentConversationId) {
148
+ return;
149
+ }
150
+ const foundSubconversationGroupId = await ((_b = (_a = this.mlsService).getGroupIdFromConversationId) === null || _b === void 0 ? void 0 : _b.call(_a, parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE));
151
+ // if the conference subconversation of parent conversation is not known, ignore the epoch update
152
+ if (foundSubconversationGroupId !== subconversationGroupId) {
153
+ return;
154
+ }
155
+ }
156
+ const subconversationEpochInfo = await this.getSubconversationEpochInfo(conversationId);
157
+ if (!subconversationEpochInfo) {
158
+ return;
159
+ }
160
+ return onEpochUpdate(Object.assign(Object.assign({}, subconversationEpochInfo), { epoch: Number(epoch) }));
161
+ };
162
+ this.mlsService.on('newEpoch', forwardNewEpoch);
163
+ await forwardNewEpoch({ groupId: subconversationGroupId, epoch: initialEpoch });
164
+ return () => this.mlsService.off('newEpoch', forwardNewEpoch);
165
+ }
166
+ async removeClientFromConferenceSubconversation(conversationId, clientToRemove) {
167
+ const subconversationGroupId = await this.mlsService.getGroupIdFromConversationId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
168
+ if (!subconversationGroupId) {
169
+ return;
170
+ }
171
+ const doesMLSGroupExist = await this.mlsService.conversationExists(subconversationGroupId);
172
+ if (!doesMLSGroupExist) {
173
+ return;
174
+ }
175
+ const { user: { id: userId, domain }, clientId, } = clientToRemove;
176
+ const clientToRemoveQualifiedId = (0, fullyQualifiedClientIdUtils_1.constructFullyQualifiedClientId)(userId, clientId, domain);
177
+ const subconversationMembers = await this.mlsService.getClientIds(subconversationGroupId);
178
+ const isSubconversationMember = subconversationMembers.some(({ userId, clientId, domain }) => (0, fullyQualifiedClientIdUtils_1.constructFullyQualifiedClientId)(userId, clientId, domain) === clientToRemoveQualifiedId);
179
+ if (!isSubconversationMember) {
180
+ return;
181
+ }
182
+ return void this.mlsService.removeClientsFromConversation(subconversationGroupId, [clientToRemoveQualifiedId]);
183
+ }
184
+ async joinSubconversationByExternalCommit(conversationId, subconversation) {
185
+ await this.mlsService.joinByExternalCommit(() => this.apiClient.api.conversation.getSubconversationGroupInfo(conversationId, subconversation));
186
+ }
187
+ async getConferenceSubconversation(conversationId) {
188
+ return this.apiClient.api.conversation.getSubconversation(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
189
+ }
190
+ async deleteConferenceSubconversation(conversationId, data) {
191
+ return this.apiClient.api.conversation.deleteSubconversation(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE, data);
192
+ }
193
+ async generateSubconversationMembers(subconversationGroupId, parentGroupId) {
194
+ const subconversationMemberIds = await this.mlsService.getClientIds(subconversationGroupId);
195
+ const parentMemberIds = await this.mlsService.getClientIds(parentGroupId);
196
+ return parentMemberIds.map(parentMember => {
197
+ const isSubconversationMember = subconversationMemberIds.some(({ userId, clientId, domain }) => (0, fullyQualifiedClientIdUtils_1.constructFullyQualifiedClientId)(userId, clientId, domain) ===
198
+ (0, fullyQualifiedClientIdUtils_1.constructFullyQualifiedClientId)(parentMember.userId, parentMember.clientId, parentMember.domain));
199
+ return {
200
+ userid: `${parentMember.userId}@${parentMember.domain}`,
201
+ clientid: parentMember.clientId,
202
+ in_subconv: isSubconversationMember,
203
+ };
204
+ });
205
+ }
206
+ }
207
+ exports.SubconversationService = SubconversationService;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=SubconversationService.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubconversationService.test.d.ts","sourceRoot":"","sources":["../../../src/conversation/SubconversationService/SubconversationService.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,390 @@
1
+ "use strict";
2
+ /*
3
+ * Wire
4
+ * Copyright (C) 2023 Wire Swiss GmbH
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see http://www.gnu.org/licenses/.
18
+ *
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ const conversation_1 = require("@wireapp/api-client/lib/conversation");
22
+ const http_1 = require("@wireapp/api-client/lib/http");
23
+ const api_client_1 = require("@wireapp/api-client");
24
+ const SubconversationService_1 = require("./SubconversationService");
25
+ const subconversationGroupIdStore_1 = require("../../messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore");
26
+ const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
27
+ const getSubconversationResponse = ({ epoch, epochTimestamp, parentConversationId, groupId, members = [], subconversationId = conversation_1.SUBCONVERSATION_ID.CONFERENCE, }) => {
28
+ return {
29
+ cipher_suite: 1,
30
+ epoch,
31
+ parent_qualified_id: parentConversationId,
32
+ group_id: groupId,
33
+ members,
34
+ subconv_id: subconversationId,
35
+ epoch_timestamp: epochTimestamp,
36
+ };
37
+ };
38
+ const buildSubconversationService = () => {
39
+ const apiClient = new api_client_1.APIClient({ urls: api_client_1.APIClient.BACKEND.STAGING });
40
+ const mlsService = {
41
+ conversationExists: jest.fn(),
42
+ wipeConversation: jest.fn(),
43
+ registerConversation: jest.fn(),
44
+ getEpoch: jest.fn(),
45
+ joinByExternalCommit: jest.fn(),
46
+ getGroupIdFromConversationId: jest.fn(),
47
+ exportSecretKey: jest.fn(),
48
+ getClientIds: jest.fn(),
49
+ renewKeyMaterial: jest.fn(),
50
+ on: jest.fn(),
51
+ off: jest.fn(),
52
+ removeClientsFromConversation: jest.fn(),
53
+ };
54
+ const subconversationService = new SubconversationService_1.SubconversationService(apiClient, mlsService);
55
+ return [subconversationService, { apiClient, mlsService }];
56
+ };
57
+ describe('SubconversationService', () => {
58
+ describe('joinConferenceSubconversation', () => {
59
+ afterEach(() => {
60
+ jest.useRealTimers();
61
+ jest.clearAllMocks();
62
+ });
63
+ it('wipes group locally (if it exists) before registering a group if remote epoch is equal 0', async () => {
64
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
65
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
66
+ const subconversationGroupId = 'subconversationGroupId';
67
+ const subconversationResponse = getSubconversationResponse({
68
+ epoch: 0,
69
+ epochTimestamp: '',
70
+ parentConversationId,
71
+ groupId: subconversationGroupId,
72
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
73
+ });
74
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValueOnce(subconversationResponse);
75
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(true);
76
+ await subconversationService.joinConferenceSubconversation(parentConversationId);
77
+ expect(mlsService.wipeConversation).toHaveBeenCalledWith(subconversationGroupId);
78
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(subconversationGroupId, []);
79
+ });
80
+ it('registers a group if remote epoch is 0 and group does not exist locally', async () => {
81
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
82
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
83
+ const subconversationGroupId = 'subconversationGroupId';
84
+ const subconversationResponse = getSubconversationResponse({
85
+ epoch: 0,
86
+ epochTimestamp: '',
87
+ parentConversationId,
88
+ groupId: subconversationGroupId,
89
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
90
+ });
91
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValueOnce(subconversationResponse);
92
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(false);
93
+ await subconversationService.joinConferenceSubconversation(parentConversationId);
94
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
95
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(subconversationGroupId, []);
96
+ });
97
+ it('deletes conference subconversation from backend if group is already established and epoch is older than one day, then rejoins', async () => {
98
+ jest.useFakeTimers();
99
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
100
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
101
+ const subconversationGroupId = 'subconversationGroupId';
102
+ const initialSubconversationEpoch = 1;
103
+ const currentTimeISO = '2023-10-24T12:00:00.000Z';
104
+ jest.setSystemTime(new Date(currentTimeISO));
105
+ jest.spyOn(apiClient.api.conversation, 'deleteSubconversation').mockResolvedValueOnce();
106
+ // epoch time is older than 24h
107
+ const epochTimestamp = '2023-10-23T11:00:00.000Z';
108
+ const subconversationResponse = getSubconversationResponse({
109
+ epoch: initialSubconversationEpoch,
110
+ epochTimestamp: epochTimestamp,
111
+ parentConversationId,
112
+ groupId: subconversationGroupId,
113
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
114
+ });
115
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValueOnce(subconversationResponse);
116
+ // After deletion, epoch is 0
117
+ const subconversationEpochAfterDeletion = 0;
118
+ const subconversationResponse2 = getSubconversationResponse({
119
+ epoch: subconversationEpochAfterDeletion,
120
+ epochTimestamp: epochTimestamp,
121
+ parentConversationId,
122
+ groupId: subconversationGroupId,
123
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
124
+ });
125
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValueOnce(subconversationResponse2);
126
+ await subconversationService.joinConferenceSubconversation(parentConversationId);
127
+ expect(apiClient.api.conversation.deleteSubconversation).toHaveBeenCalledWith(parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE, {
128
+ groupId: subconversationGroupId,
129
+ epoch: initialSubconversationEpoch,
130
+ });
131
+ expect(mlsService.registerConversation).toHaveBeenCalledTimes(1);
132
+ expect(mlsService.wipeConversation).toHaveBeenCalledWith(subconversationGroupId);
133
+ });
134
+ it('joins conference subconversation with external commit if group is already established and epoch is younger than one day', async () => {
135
+ jest.useFakeTimers();
136
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
137
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
138
+ const subconversationGroupId = 'subconversationGroupId';
139
+ const subconversationEpoch = 1;
140
+ const currentTimeISO = '2023-10-24T12:00:00.000Z';
141
+ jest.setSystemTime(new Date(currentTimeISO));
142
+ jest.spyOn(apiClient.api.conversation, 'deleteSubconversation').mockResolvedValueOnce();
143
+ // epoch time is younger than 24h
144
+ const epochTimestamp = '2023-10-23T13:00:00.000Z';
145
+ const subconversationResponse = getSubconversationResponse({
146
+ epoch: subconversationEpoch,
147
+ epochTimestamp: epochTimestamp,
148
+ parentConversationId,
149
+ groupId: subconversationGroupId,
150
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
151
+ });
152
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValueOnce(subconversationResponse);
153
+ await subconversationService.joinConferenceSubconversation(parentConversationId);
154
+ expect(apiClient.api.conversation.deleteSubconversation).not.toHaveBeenCalled();
155
+ expect(mlsService.registerConversation).not.toHaveBeenCalled();
156
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
157
+ expect(mlsService.joinByExternalCommit).toHaveBeenCalled();
158
+ });
159
+ it('retries to join if registering a conversations throws an error', async () => {
160
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
161
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
162
+ const subconversationGroupId = 'subconversationGroupId';
163
+ const subconversationResponse = getSubconversationResponse({
164
+ epoch: 0,
165
+ epochTimestamp: '',
166
+ parentConversationId,
167
+ groupId: subconversationGroupId,
168
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
169
+ });
170
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValue(subconversationResponse);
171
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(false);
172
+ jest
173
+ .spyOn(mlsService, 'registerConversation')
174
+ .mockRejectedValueOnce(new http_1.BackendError('', http_1.BackendErrorLabel.MLS_STALE_MESSAGE, http_1.StatusCode.CONFLICT));
175
+ await subconversationService.joinConferenceSubconversation(parentConversationId);
176
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
177
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(subconversationGroupId, []);
178
+ expect(mlsService.registerConversation).toHaveBeenCalledTimes(2);
179
+ });
180
+ it('returns fresh epoch number after joining the group', async () => {
181
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
182
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
183
+ const subconversationGroupId = 'subconversationGroupId';
184
+ const subconversationResponse = getSubconversationResponse({
185
+ epoch: 0,
186
+ epochTimestamp: '',
187
+ parentConversationId,
188
+ groupId: subconversationGroupId,
189
+ subconversationId: conversation_1.SUBCONVERSATION_ID.CONFERENCE,
190
+ });
191
+ jest.spyOn(apiClient.api.conversation, 'getSubconversation').mockResolvedValueOnce(subconversationResponse);
192
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(false);
193
+ const updatedEpoch = 1;
194
+ jest.spyOn(mlsService, 'getEpoch').mockResolvedValueOnce(updatedEpoch);
195
+ const response = await subconversationService.joinConferenceSubconversation(parentConversationId);
196
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
197
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(subconversationGroupId, []);
198
+ expect(response).toEqual({ epoch: updatedEpoch, groupId: subconversationGroupId });
199
+ });
200
+ });
201
+ describe('leaveConferenceSubconversation', () => {
202
+ it('does nothing if subconversation id is not found in the store', async () => {
203
+ const [subconversationService, { mlsService }] = buildSubconversationService();
204
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
205
+ await subconversationService.leaveConferenceSubconversation(parentConversationId);
206
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
207
+ });
208
+ it('removes subconversation id from the store if conversations was known but not established locally', async () => {
209
+ const [subconversationService, { mlsService }] = buildSubconversationService();
210
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
211
+ const subconversationGroupId = 'subconversationGroupId';
212
+ subconversationGroupIdStore_1.subconversationGroupIdStore.storeGroupId(parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE, subconversationGroupId);
213
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(false);
214
+ await subconversationService.leaveConferenceSubconversation(parentConversationId);
215
+ const groupId = subconversationGroupIdStore_1.subconversationGroupIdStore.getGroupId(parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
216
+ expect(groupId).toEqual(undefined);
217
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
218
+ });
219
+ it('deletes self client from conference subconversation', async () => {
220
+ const [subconversationService, { apiClient, mlsService }] = buildSubconversationService();
221
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
222
+ const subconversationGroupId = 'subconversationGroupId';
223
+ subconversationGroupIdStore_1.subconversationGroupIdStore.storeGroupId(parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE, subconversationGroupId);
224
+ jest.spyOn(apiClient.api.conversation, 'deleteSubconversationSelf');
225
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(true);
226
+ await subconversationService.leaveConferenceSubconversation(parentConversationId);
227
+ const groupId = subconversationGroupIdStore_1.subconversationGroupIdStore.getGroupId(parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
228
+ expect(groupId).toEqual(undefined);
229
+ expect(apiClient.api.conversation.deleteSubconversationSelf).toHaveBeenCalledWith(parentConversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
230
+ expect(mlsService.wipeConversation).toHaveBeenCalledWith(subconversationGroupId);
231
+ });
232
+ });
233
+ describe('getSubconversationEpochInfo', () => {
234
+ it('returns null if subconversation id is not known by a client', async () => {
235
+ const [subconversationService, { mlsService }] = buildSubconversationService();
236
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
237
+ jest.spyOn(mlsService, 'getGroupIdFromConversationId').mockResolvedValue(undefined);
238
+ const response = await subconversationService.getSubconversationEpochInfo(parentConversationId);
239
+ expect(response).toEqual(null);
240
+ });
241
+ it('returns null if MLS group for subconversation does not exist locally', async () => {
242
+ const [subconversationService, { mlsService }] = buildSubconversationService();
243
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
244
+ const parentConversationGroupId = 'parentConversationGroupId';
245
+ const subconversationGroupId = 'subconversationGroupId';
246
+ jest
247
+ .spyOn(mlsService, 'getGroupIdFromConversationId')
248
+ .mockImplementation(async (_conversationId, subconverstionId) => {
249
+ if (subconverstionId) {
250
+ return subconversationGroupId;
251
+ }
252
+ return parentConversationGroupId;
253
+ });
254
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(false);
255
+ const response = await subconversationService.getSubconversationEpochInfo(parentConversationId);
256
+ expect(response).toEqual(null);
257
+ });
258
+ it('returns epoch info and advances epoch number', async () => {
259
+ const [subconversationService, { mlsService }] = buildSubconversationService();
260
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
261
+ const parentConversationGroupId = 'parentConversationGroupId';
262
+ const subconversationGroupId = 'subconversationGroupId';
263
+ jest
264
+ .spyOn(mlsService, 'getGroupIdFromConversationId')
265
+ .mockImplementation(async (_conversationId, subconverstionId) => {
266
+ if (subconverstionId) {
267
+ return subconversationGroupId;
268
+ }
269
+ return parentConversationGroupId;
270
+ });
271
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValueOnce(true);
272
+ const mockedEpoch = 2;
273
+ jest.spyOn(mlsService, 'getEpoch').mockResolvedValueOnce(mockedEpoch);
274
+ const mockedSecretKey = 'mockedSecretKey';
275
+ jest.spyOn(mlsService, 'exportSecretKey').mockResolvedValueOnce(mockedSecretKey);
276
+ const subconversationMemberIds = [{ userId: 'userId1', clientId: 'clientId1', domain: 'domain' }];
277
+ const parentConversationMemberIds = [
278
+ { userId: 'userId1', clientId: 'clientId1', domain: 'domain' },
279
+ { userId: 'userId2', clientId: 'clientId2', domain: 'domain' },
280
+ ];
281
+ jest.spyOn(mlsService, 'getClientIds').mockImplementation(async (groupId) => {
282
+ if (groupId === parentConversationGroupId) {
283
+ return parentConversationMemberIds;
284
+ }
285
+ return subconversationMemberIds;
286
+ });
287
+ const response = await subconversationService.getSubconversationEpochInfo(parentConversationId, true);
288
+ const expected = {
289
+ epoch: mockedEpoch,
290
+ keyLength: 32,
291
+ members: [
292
+ { clientid: 'clientId1', in_subconv: true, userid: 'userId1@domain' },
293
+ { clientid: 'clientId2', in_subconv: false, userid: 'userId2@domain' },
294
+ ],
295
+ secretKey: mockedSecretKey,
296
+ };
297
+ expect(response).toEqual(expected);
298
+ expect(mlsService.renewKeyMaterial).toHaveBeenCalledWith(subconversationGroupId);
299
+ });
300
+ });
301
+ describe('subscribeToEpochUpdates', () => {
302
+ it('should subscribe to newEpoch event', async () => {
303
+ const [subconversationService, { mlsService }] = buildSubconversationService();
304
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
305
+ const parentConversationGroupId = 'parentConversationGroupId';
306
+ const subconversationGroupId = 'subconversationGroupId';
307
+ const mockedInitialEpoch = 1;
308
+ jest.spyOn(mlsService, 'getGroupIdFromConversationId').mockResolvedValue(subconversationGroupId);
309
+ const mockedEpochInfo = { epoch: mockedInitialEpoch, keyLength: 32, members: [], secretKey: '' };
310
+ jest.spyOn(subconversationService, 'getSubconversationEpochInfo').mockResolvedValueOnce(mockedEpochInfo);
311
+ jest
312
+ .spyOn(subconversationService, 'joinConferenceSubconversation')
313
+ .mockResolvedValue({ epoch: mockedInitialEpoch, groupId: subconversationGroupId });
314
+ const findConversationByGroupId = (groupId) => {
315
+ if (groupId === parentConversationGroupId) {
316
+ return parentConversationId;
317
+ }
318
+ return undefined;
319
+ };
320
+ const onEpochUpdateCallback = jest.fn();
321
+ const unsubscribe = await subconversationService.subscribeToEpochUpdates(parentConversationId, findConversationByGroupId, onEpochUpdateCallback);
322
+ expect(mlsService.on).toHaveBeenCalledWith('newEpoch', expect.any(Function));
323
+ expect(subconversationService.getSubconversationEpochInfo).toHaveBeenCalledWith(parentConversationId);
324
+ expect(onEpochUpdateCallback).toHaveBeenCalledWith(mockedEpochInfo);
325
+ unsubscribe();
326
+ expect(mlsService.off).toHaveBeenCalledWith('newEpoch', expect.any(Function));
327
+ });
328
+ });
329
+ describe('removeClientFromConferenceSubconversation', () => {
330
+ it('does nothing if subconversation group is not known', async () => {
331
+ const [subconversationService, { mlsService }] = buildSubconversationService();
332
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
333
+ jest.spyOn(mlsService, 'getGroupIdFromConversationId').mockResolvedValue(undefined);
334
+ const user = { id: 'userId', domain: 'domain' };
335
+ const clientId = 'clientId';
336
+ const clientToRemove = { user, clientId };
337
+ await subconversationService.removeClientFromConferenceSubconversation(parentConversationId, clientToRemove);
338
+ expect(mlsService.removeClientsFromConversation).not.toHaveBeenCalled();
339
+ });
340
+ it('does nothing if subconversation group is not established', async () => {
341
+ const [subconversationService, { mlsService }] = buildSubconversationService();
342
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
343
+ const subconversationGroupId = 'subconversationGroupId';
344
+ jest.spyOn(mlsService, 'getGroupIdFromConversationId').mockResolvedValue(subconversationGroupId);
345
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValue(false);
346
+ const user = { id: 'userId', domain: 'domain' };
347
+ const clientId = 'clientId';
348
+ const clientToRemove = { user, clientId };
349
+ await subconversationService.removeClientFromConferenceSubconversation(parentConversationId, clientToRemove);
350
+ expect(mlsService.removeClientsFromConversation).not.toHaveBeenCalled();
351
+ });
352
+ it('does nothing if client is not a subconversation group member', async () => {
353
+ const [subconversationService, { mlsService }] = buildSubconversationService();
354
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
355
+ const subconversationGroupId = 'subconversationGroupId';
356
+ jest.spyOn(mlsService, 'getGroupIdFromConversationId').mockResolvedValue(subconversationGroupId);
357
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValue(true);
358
+ const subconversationMemberIds = [
359
+ { userId: 'userId1', clientId: 'clientId1', domain: 'domain' },
360
+ { userId: 'userId2', clientId: 'clientId2', domain: 'domain2' },
361
+ ];
362
+ jest.spyOn(mlsService, 'getClientIds').mockResolvedValueOnce(subconversationMemberIds);
363
+ const user = { id: 'userId3', domain: 'domain3' };
364
+ const clientId = 'clientId3';
365
+ const clientToRemove = { user, clientId };
366
+ await subconversationService.removeClientFromConferenceSubconversation(parentConversationId, clientToRemove);
367
+ expect(mlsService.removeClientsFromConversation).not.toHaveBeenCalled();
368
+ });
369
+ it('removes client from subconversation group', async () => {
370
+ const [subconversationService, { mlsService }] = buildSubconversationService();
371
+ const parentConversationId = { id: 'parentConversationId', domain: 'domain' };
372
+ const subconversationGroupId = 'subconversationGroupId';
373
+ jest.spyOn(mlsService, 'getGroupIdFromConversationId').mockResolvedValue(subconversationGroupId);
374
+ jest.spyOn(mlsService, 'conversationExists').mockResolvedValue(true);
375
+ const user = { id: 'userId3', domain: 'domain3' };
376
+ const clientId = 'clientId3';
377
+ const clientToRemove = { user, clientId };
378
+ const subconversationMemberIds = [
379
+ { userId: 'userId1', clientId: 'clientId1', domain: 'domain' },
380
+ { userId: 'userId2', clientId: 'clientId2', domain: 'domain2' },
381
+ { userId: clientToRemove.user.id, clientId: clientToRemove.clientId, domain: clientToRemove.user.domain },
382
+ ];
383
+ jest.spyOn(mlsService, 'getClientIds').mockResolvedValueOnce(subconversationMemberIds);
384
+ await subconversationService.removeClientFromConferenceSubconversation(parentConversationId, clientToRemove);
385
+ expect(mlsService.removeClientsFromConversation).toHaveBeenCalledWith(subconversationGroupId, [
386
+ (0, fullyQualifiedClientIdUtils_1.constructFullyQualifiedClientId)(clientToRemove.user.id, clientToRemove.clientId, clientToRemove.user.domain),
387
+ ]);
388
+ });
389
+ });
390
+ });
@@ -1,6 +1,5 @@
1
1
  import type { RegisteredClient } from '@wireapp/api-client/lib/client';
2
2
  import { PostMlsMessageResponse, SUBCONVERSATION_ID } from '@wireapp/api-client/lib/conversation';
3
- import { Subconversation } from '@wireapp/api-client/lib/conversation/Subconversation';
4
3
  import { ConversationMLSMessageAddEvent, ConversationMLSWelcomeEvent } from '@wireapp/api-client/lib/event';
5
4
  import { QualifiedId } from '@wireapp/api-client/lib/user';
6
5
  import logdown from 'logdown';
@@ -20,11 +19,6 @@ interface LocalMLSServiceConfig extends MLSServiceConfig {
20
19
  */
21
20
  minRequiredNumberOfAvailableKeyPackages: number;
22
21
  }
23
- export interface SubconversationEpochInfoMember {
24
- userid: string;
25
- clientid: ClientId;
26
- in_subconv: boolean;
27
- }
28
22
  type Events = {
29
23
  newEpoch: {
30
24
  epoch: number;
@@ -60,25 +54,6 @@ export declare class MLSService extends TypedEventEmitter<Events> {
60
54
  getEpoch(groupId: string | Uint8Array): Promise<number>;
61
55
  newProposal(proposalType: ProposalType, args: ProposalArgs | AddProposalArgs | RemoveProposalArgs): Promise<import("@wireapp/core-crypto").ProposalBundle>;
62
56
  joinByExternalCommit(getGroupInfo: () => Promise<Uint8Array>): Promise<PostMlsMessageResponse>;
63
- getConferenceSubconversation(conversationId: QualifiedId): Promise<Subconversation>;
64
- private deleteConferenceSubconversation;
65
- /**
66
- * Will leave conference subconversation if it's known by client and established.
67
- *
68
- * @param conversationId Id of the parent conversation which subconversation we want to leave
69
- */
70
- leaveConferenceSubconversation(conversationId: QualifiedId): Promise<void>;
71
- leaveStaleConferenceSubconversations(): Promise<void>;
72
- /**
73
- * Will join or register an mls subconversation for conference calls.
74
- * Will return the secret key derived from the subconversation
75
- *
76
- * @param conversationId Id of the parent conversation in which the call should happen
77
- */
78
- joinConferenceSubconversation(conversationId: QualifiedId): Promise<{
79
- groupId: string;
80
- epoch: number;
81
- }>;
82
57
  exportSecretKey(groupId: string, keyLength: number): Promise<string>;
83
58
  newExternalProposal(externalProposalType: ExternalProposalType, args: ExternalAddProposalArgs): Promise<Uint8Array>;
84
59
  processWelcomeMessage(welcomeMessage: Uint8Array): Promise<ConversationId>;
@@ -1 +1 @@
1
- {"version":3,"file":"MLSService.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/mls/MLSService/MLSService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MLSService.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/mls/MLSService/MLSService.ts"],"names":[],"mappings":"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"}
@@ -33,9 +33,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
35
  exports.MLSService = exports.optionalToUint8Array = void 0;
36
- const conversation_1 = require("@wireapp/api-client/lib/conversation");
37
36
  const http_1 = require("@wireapp/api-client/lib/http");
38
- const TimeUtil_1 = require("@wireapp/commons/lib/util/TimeUtil");
39
37
  const bazinga64_1 = require("bazinga64");
40
38
  const logdown_1 = __importDefault(require("logdown"));
41
39
  const commons_1 = require("@wireapp/commons");
@@ -239,74 +237,6 @@ class MLSService extends commons_1.TypedEventEmitter {
239
237
  }
240
238
  return mlsResponse;
241
239
  }
242
- async getConferenceSubconversation(conversationId) {
243
- return this.apiClient.api.conversation.getSubconversation(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
244
- }
245
- async deleteConferenceSubconversation(conversationId, data) {
246
- return this.apiClient.api.conversation.deleteSubconversation(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE, data);
247
- }
248
- /**
249
- * Will leave conference subconversation if it's known by client and established.
250
- *
251
- * @param conversationId Id of the parent conversation which subconversation we want to leave
252
- */
253
- async leaveConferenceSubconversation(conversationId) {
254
- const subconversationGroupId = subconversationGroupIdStore_1.subconversationGroupIdStore.getGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
255
- if (!subconversationGroupId) {
256
- return;
257
- }
258
- const isSubconversationEstablished = await this.conversationExists(subconversationGroupId);
259
- if (!isSubconversationEstablished) {
260
- // if the subconversation was known by a client but is not established anymore, we can remove it from the store
261
- return subconversationGroupIdStore_1.subconversationGroupIdStore.removeGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
262
- }
263
- try {
264
- await this.apiClient.api.conversation.deleteSubconversationSelf(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
265
- }
266
- catch (error) {
267
- this.logger.error(`Failed to leave conference subconversation:`, error);
268
- }
269
- await this.wipeConversation(subconversationGroupId);
270
- // once we've left the subconversation, we can remove it from the store
271
- subconversationGroupIdStore_1.subconversationGroupIdStore.removeGroupId(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE);
272
- }
273
- async leaveStaleConferenceSubconversations() {
274
- const conversationIds = subconversationGroupIdStore_1.subconversationGroupIdStore.getAllGroupIdsBySubconversationId(conversation_1.SUBCONVERSATION_ID.CONFERENCE);
275
- for (const { parentConversationId } of conversationIds) {
276
- await this.leaveConferenceSubconversation(parentConversationId);
277
- }
278
- }
279
- /**
280
- * Will join or register an mls subconversation for conference calls.
281
- * Will return the secret key derived from the subconversation
282
- *
283
- * @param conversationId Id of the parent conversation in which the call should happen
284
- */
285
- async joinConferenceSubconversation(conversationId) {
286
- const subconversation = await this.getConferenceSubconversation(conversationId);
287
- if (subconversation.epoch === 0) {
288
- // if subconversation is not yet established, create it
289
- await this.registerConversation(subconversation.group_id, []);
290
- }
291
- else {
292
- const epochUpdateTime = new Date(subconversation.epoch_timestamp).getTime();
293
- const epochAge = new Date().getTime() - epochUpdateTime;
294
- if (epochAge > TimeUtil_1.TimeInMillis.DAY) {
295
- // if subconversation does exist, but it's older than 24h, delete and re-join
296
- await this.deleteConferenceSubconversation(conversationId, {
297
- groupId: subconversation.group_id,
298
- epoch: subconversation.epoch,
299
- });
300
- await this.wipeConversation(subconversation.group_id);
301
- return this.joinConferenceSubconversation(conversationId);
302
- }
303
- await this.joinByExternalCommit(() => this.apiClient.api.conversation.getSubconversationGroupInfo(conversationId, conversation_1.SUBCONVERSATION_ID.CONFERENCE));
304
- }
305
- const epoch = Number(await this.getEpoch(subconversation.group_id));
306
- // We store the mapping between the subconversation and the parent conversation
307
- subconversationGroupIdStore_1.subconversationGroupIdStore.storeGroupId(conversationId, subconversation.subconv_id, subconversation.group_id);
308
- return { groupId: subconversation.group_id, epoch };
309
- }
310
240
  async exportSecretKey(groupId, keyLength) {
311
241
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
312
242
  const key = await this.coreCryptoClient.exportSecretKey(groupIdBytes, keyLength);
package/package.json CHANGED
@@ -61,6 +61,6 @@
61
61
  "test:coverage": "jest --coverage",
62
62
  "watch": "tsc --watch"
63
63
  },
64
- "version": "42.19.0",
65
- "gitHead": "5ecc27e935400844c53aa6164210cb4f9846a1dd"
64
+ "version": "42.19.1",
65
+ "gitHead": "278e386599ad8b55a532765615287adf51b1c189"
66
66
  }