@wireapp/core 40.9.3 → 41.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,7 +38,10 @@ export declare class ConversationService {
38
38
  getConversations(conversationIds?: QualifiedId[]): Promise<RemoteConversations>;
39
39
  getAsset({ assetId, assetToken, otrKey, sha256 }: RemoteData): Promise<Uint8Array>;
40
40
  getUnencryptedAsset(assetId: string, assetToken?: string): Promise<ArrayBuffer>;
41
- addUsersToProteusConversation(params: AddUsersToProteusConversationParams): Promise<import("@wireapp/api-client/lib/event").ConversationMemberJoinEvent>;
41
+ addUsersToProteusConversation(params: AddUsersToProteusConversationParams): Promise<{
42
+ event?: import("@wireapp/api-client/lib/event").ConversationMemberJoinEvent | undefined;
43
+ failedToAdd?: QualifiedId[] | undefined;
44
+ }>;
42
45
  removeUserFromConversation(conversationId: QualifiedId, userId: QualifiedId): Promise<ConversationMemberLeaveEvent>;
43
46
  /**
44
47
  * Sends a message to a conversation
@@ -86,5 +89,17 @@ export declare class ConversationService {
86
89
  wipeMLSConversation(groupId: string): Promise<void>;
87
90
  private matchesEpoch;
88
91
  handleEpochMismatch(): Promise<void>;
92
+ /**
93
+ * Will try registering mls 1:1 conversation adding the other user.
94
+ * If it fails and the conversation is already established, it will try joining via external commit instead.
95
+ *
96
+ * @param mlsConversation - mls 1:1 conversation
97
+ * @param selfUser - user and client ids of the self user
98
+ * @param otherUserId - id of the other user
99
+ */
100
+ readonly establishMLS1to1Conversation: (groupId: string, selfUser: {
101
+ user: QualifiedId;
102
+ client: string;
103
+ }, otherUserId: QualifiedId) => Promise<void>;
89
104
  }
90
105
  //# sourceMappingURL=ConversationService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationService.d.ts","sourceRoot":"","sources":["../../../src/conversation/ConversationService/ConversationService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ConversationService.d.ts","sourceRoot":"","sources":["../../../src/conversation/ConversationService/ConversationService.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,33 @@ class ConversationService {
41
41
  this.proteusService = proteusService;
42
42
  this._mlsService = _mlsService;
43
43
  this.logger = (0, logdown_1.default)('@wireapp/core/ConversationService');
44
+ /**
45
+ * Will try registering mls 1:1 conversation adding the other user.
46
+ * If it fails and the conversation is already established, it will try joining via external commit instead.
47
+ *
48
+ * @param mlsConversation - mls 1:1 conversation
49
+ * @param selfUser - user and client ids of the self user
50
+ * @param otherUserId - id of the other user
51
+ */
52
+ this.establishMLS1to1Conversation = async (groupId, selfUser, otherUserId) => {
53
+ try {
54
+ await this.mlsService.registerConversation(groupId, [otherUserId, selfUser.user], selfUser);
55
+ }
56
+ catch (error) {
57
+ this.logger.info(`Could not register MLS group with id ${groupId}.`);
58
+ const mlsConversation = await this.apiClient.api.conversation.getMLS1to1Conversation(otherUserId);
59
+ if (mlsConversation.epoch > 0) {
60
+ this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is already established, joining via external commit`);
61
+ // If its already established, we join with external commit
62
+ await this.joinByExternalCommit(mlsConversation.qualified_id);
63
+ return;
64
+ }
65
+ this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is not established, retrying to establish it`);
66
+ // If conversation is not established, we can wipe it and try to establish it again
67
+ await this.wipeMLSConversation(groupId);
68
+ return this.establishMLS1to1Conversation(groupId, selfUser, otherUserId);
69
+ }
70
+ };
44
71
  this.messageTimer = new conversation_2.MessageTimer();
45
72
  }
46
73
  get mlsService() {
@@ -56,6 +56,8 @@ const mockedMLSService = {
56
56
  commitPendingProposals: () => Promise.resolve(),
57
57
  getEpoch: () => Promise.resolve(),
58
58
  joinByExternalCommit: jest.fn(),
59
+ registerConversation: jest.fn(),
60
+ wipeConversation: jest.fn(),
59
61
  };
60
62
  const mockedProteusService = {
61
63
  encryptGenericMessage: () => Promise.resolve(),
@@ -186,6 +188,55 @@ describe('ConversationService', () => {
186
188
  expect(conversationService.joinByExternalCommit).not.toHaveBeenCalled();
187
189
  });
188
190
  });
191
+ describe('establishMLS1to1Conversation', () => {
192
+ it('successfully register an MLS group if it did not exist before', async () => {
193
+ const [conversationService, { mlsService }] = buildConversationService();
194
+ const mockGroupId = 'mock-group-id';
195
+ const selfUser = { user: { id: 'self-user-id', domain: 'staging.zinfra.io' }, client: 'self-user-client-id' };
196
+ const otherUserId = { id: 'other-user-id', domain: 'staging.zinfra.io' };
197
+ await conversationService.establishMLS1to1Conversation(mockGroupId, selfUser, otherUserId);
198
+ expect(mlsService.registerConversation).toHaveBeenCalledTimes(1);
199
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(mockGroupId, [otherUserId, selfUser.user], selfUser);
200
+ expect(mlsService.joinByExternalCommit).not.toHaveBeenCalled();
201
+ expect(mlsService.wipeConversation).not.toHaveBeenCalled();
202
+ });
203
+ it('joins with external commit if epoch number is higher than 0', async () => {
204
+ const [conversationService, { apiClient, mlsService }] = buildConversationService();
205
+ const mockConversationId = { id: 'mock-conversation-id', domain: 'staging.zinfra.io' };
206
+ const mockGroupId = 'mock-group-id';
207
+ const selfUser = { user: { id: 'self-user-id', domain: 'staging.zinfra.io' }, client: 'self-user-client-id' };
208
+ const otherUserId = { id: 'other-user-id', domain: 'staging.zinfra.io' };
209
+ jest.spyOn(mlsService, 'registerConversation').mockRejectedValueOnce(undefined);
210
+ jest.spyOn(apiClient.api.conversation, 'getMLS1to1Conversation').mockResolvedValueOnce({
211
+ qualified_id: mockConversationId,
212
+ protocol: conversation_1.ConversationProtocol.MLS,
213
+ epoch: 1,
214
+ group_id: mockGroupId,
215
+ });
216
+ await conversationService.establishMLS1to1Conversation(mockGroupId, selfUser, otherUserId);
217
+ expect(mlsService.registerConversation).toHaveBeenCalledTimes(1);
218
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(mockGroupId, [otherUserId, selfUser.user], selfUser);
219
+ expect(conversationService.joinByExternalCommit).toHaveBeenCalledWith(mockConversationId);
220
+ });
221
+ it('retries to register mls group if epoch number is equal 0', async () => {
222
+ const [conversationService, { apiClient, mlsService }] = buildConversationService();
223
+ const mockConversationId = { id: 'mock-conversation-id', domain: 'staging.zinfra.io' };
224
+ const mockGroupId = 'mock-group-id';
225
+ const selfUser = { user: { id: 'self-user-id', domain: 'staging.zinfra.io' }, client: 'self-user-client-id' };
226
+ const otherUserId = { id: 'other-user-id', domain: 'staging.zinfra.io' };
227
+ jest.spyOn(mlsService, 'registerConversation').mockRejectedValueOnce(undefined);
228
+ jest.spyOn(apiClient.api.conversation, 'getMLS1to1Conversation').mockResolvedValueOnce({
229
+ qualified_id: mockConversationId,
230
+ protocol: conversation_1.ConversationProtocol.MLS,
231
+ epoch: 0,
232
+ group_id: mockGroupId,
233
+ });
234
+ await conversationService.establishMLS1to1Conversation(mockGroupId, selfUser, otherUserId);
235
+ expect(mlsService.registerConversation).toHaveBeenCalledWith(mockGroupId, [otherUserId, selfUser.user], selfUser);
236
+ expect(mlsService.wipeConversation).toHaveBeenCalledWith(mockGroupId);
237
+ expect(mlsService.registerConversation).toHaveBeenCalledTimes(2);
238
+ });
239
+ });
189
240
  describe('fetchAllParticipantsClients', () => {
190
241
  it('gives the members and clients of a federated conversation', async () => {
191
242
  const [conversationService, { apiClient }] = buildConversationService();
@@ -1,6 +1,7 @@
1
1
  import type { APIClient } from '@wireapp/api-client/lib/APIClient';
2
2
  import type { PreKey, Context } from '@wireapp/api-client/lib/auth';
3
3
  import { Conversation, QualifiedOTRRecipients, QualifiedUserClients } from '@wireapp/api-client/lib/conversation';
4
+ import type { ConversationMemberJoinEvent } from '@wireapp/api-client/lib/event';
4
5
  import type { QualifiedId, QualifiedUserPreKeyBundleMap } from '@wireapp/api-client/lib/user';
5
6
  import { CRUDEngine } from '@wireapp/store-engine';
6
7
  import { CryptoClient } from './CryptoClient';
@@ -40,7 +41,14 @@ export declare class ProteusService {
40
41
  */
41
42
  getRemoteFingerprint(userId: QualifiedId, clientId: string, prekey?: PreKey): Promise<string>;
42
43
  createConversation({ conversationData, otherUserIds, }: CreateProteusConversationParams): Promise<Conversation>;
43
- addUsersToConversation({ conversationId, qualifiedUsers }: AddUsersToProteusConversationParams): Promise<import("@wireapp/api-client/lib/event").ConversationMemberJoinEvent>;
44
+ /**
45
+ * Tries to add all the given users to the given conversation.
46
+ * If some users are not reachable, it will try to add the remaining users and list them in the `failedToAdd` property of the response.
47
+ */
48
+ addUsersToConversation({ conversationId, qualifiedUsers }: AddUsersToProteusConversationParams): Promise<{
49
+ event?: ConversationMemberJoinEvent;
50
+ failedToAdd?: QualifiedId[];
51
+ }>;
44
52
  sendMessage({ userIds, conversationId, nativePush, targetMode, payload, onClientMismatch, }: SendProteusMessageParams): Promise<SendResult>;
45
53
  private decrypt;
46
54
  deleteSession(userId: QualifiedId, clientId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"ProteusService.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/proteus/ProteusService/ProteusService.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AACjE,OAAO,KAAK,EAAC,MAAM,EAAE,OAAO,EAAC,MAAM,8BAA8B,CAAC;AAClE,OAAO,EACL,YAAY,EAIZ,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,WAAW,EAAE,4BAA4B,EAAC,MAAM,8BAA8B,CAAC;AAI5F,OAAO,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAI5C,OAAO,KAAK,EACV,mCAAmC,EACnC,+BAA+B,EAC/B,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAA0C,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAE1F,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAC,kBAAkB,EAAqB,MAAM,iBAAiB,CAAC;AAWvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wEAAwE;IACxE,QAAQ,EAAE,sBAAsB,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,sGAAsG;IACtG,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG/C,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,oBAAoB;IAKlC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG,kBAAkB;IAiBhG,UAAU,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO;IA2B1D,YAAY,CAAC,OAAO,CAAC,EAAE,UAAU;IAIxC;;OAEG;IACI,mBAAmB;IAInB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIxE;;;;;;OAMG;IACU,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAQ3E,kBAAkB,CAAC,EAC9B,gBAAgB,EAChB,YAAY,GACb,EAAE,+BAA+B,GAAG,OAAO,CAAC,YAAY,CAAC;IA2C7C,sBAAsB,CAAC,EAAC,cAAc,EAAE,cAAc,EAAC,EAAE,mCAAmC;IAI5F,WAAW,CAAC,EACvB,OAAO,EACP,cAAc,EACd,UAAU,EACV,UAAU,EACV,OAAO,EACP,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC;YA6CnC,OAAO;IAuBd,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM;IAQ7C,OAAO,CAClB,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,4BAA4B,GAAG,oBAAoB,GAC9D,OAAO,CAAC,gBAAgB,CAAC;IAiBtB,IAAI,CAAC,WAAW,CAAC,EAAE,UAAU;CAMpC"}
1
+ {"version":3,"file":"ProteusService.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/proteus/ProteusService/ProteusService.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,mCAAmC,CAAC;AACjE,OAAO,KAAK,EAAC,MAAM,EAAE,OAAO,EAAC,MAAM,8BAA8B,CAAC;AAClE,OAAO,EACL,YAAY,EAIZ,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,+BAA+B,CAAC;AAC/E,OAAO,KAAK,EAAC,WAAW,EAAE,4BAA4B,EAAC,MAAM,8BAA8B,CAAC;AAI5F,OAAO,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAI5C,OAAO,KAAK,EACV,mCAAmC,EACnC,+BAA+B,EAC/B,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAA0C,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAE1F,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAC,kBAAkB,EAAqB,MAAM,iBAAiB,CAAC;AAWvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,wEAAwE;IACxE,QAAQ,EAAE,sBAAsB,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,sGAAsG;IACtG,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG/C,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,oBAAoB;IAKlC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAAG,kBAAkB;IAiBhG,UAAU,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO;IA2B1D,YAAY,CAAC,OAAO,CAAC,EAAE,UAAU;IAIxC;;OAEG;IACI,mBAAmB;IAInB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIxE;;;;;;OAMG;IACU,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAQ3E,kBAAkB,CAAC,EAC9B,gBAAgB,EAChB,YAAY,GACb,EAAE,+BAA+B,GAAG,OAAO,CAAC,YAAY,CAAC;IA0C1D;;;OAGG;IACU,sBAAsB,CAAC,EAAC,cAAc,EAAE,cAAc,EAAC,EAAE,mCAAmC,GAAG,OAAO,CAAC;QAClH,KAAK,CAAC,EAAE,2BAA2B,CAAC;QACpC,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;KAC7B,CAAC;IA4BW,WAAW,CAAC,EACvB,OAAO,EACP,cAAc,EACd,UAAU,EACV,UAAU,EACV,OAAO,EACP,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC;YA6CnC,OAAO;IAuBd,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM;IAQ7C,OAAO,CAClB,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,4BAA4B,GAAG,oBAAoB,GAC9D,OAAO,CAAC,gBAAgB,CAAC;IAiBtB,IAAI,CAAC,WAAW,CAAC,EAAE,UAAU;CAMpC"}
@@ -29,6 +29,7 @@ const cryptoMigrationStateStore_1 = require("./cryptoMigrationStateStore");
29
29
  const DecryptionErrorGenerator_1 = require("./DecryptionErrorGenerator");
30
30
  const identityClearer_1 = require("./identityClearer");
31
31
  const sessionIdMigrator_1 = require("./sessionIdMigrator");
32
+ const userDomainFilters_1 = require("./userDomainFilters");
32
33
  const conversation_2 = require("../../../conversation");
33
34
  const MessageService_1 = require("../../../conversation/message/MessageService");
34
35
  const EventHandler_1 = require("../EventHandler");
@@ -120,31 +121,55 @@ class ProteusService {
120
121
  }
121
122
  return this.apiClient.api.conversation.postConversation(payload).catch(async (error) => {
122
123
  var _a;
123
- const backendError = error;
124
- switch (backendError.label) {
125
- case conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS: {
126
- const { backends } = backendError;
127
- const users = (_a = payload.qualified_users) !== null && _a !== void 0 ? _a : [];
128
- const availableUsers = [];
129
- const unreachableUsers = [];
130
- users.forEach(user => backends.includes(user.domain) ? unreachableUsers.push(user) : availableUsers.push(user));
131
- payload = Object.assign(Object.assign({}, payload), { qualified_users: availableUsers });
132
- // If conversation creation returns an error because a backend is offline,
133
- // we try creating the conversation again with users from available backends
134
- const response = await this.apiClient.api.conversation.postConversation(payload).catch((error) => {
135
- throw error;
136
- });
137
- // on a succesfull conversation creation with the available users,
138
- // we append the users from an unreachable backend to the response
139
- response.failed_to_add = unreachableUsers;
140
- return response;
124
+ if ((0, conversation_1.isFederatedBackendsError)(error)) {
125
+ switch (error.label) {
126
+ case conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS: {
127
+ const { backends } = error;
128
+ const { excludedUsers: unreachableUsers, includedUsers: availableUsers } = (0, userDomainFilters_1.filterUsersFromDomains)((_a = payload.qualified_users) !== null && _a !== void 0 ? _a : [], backends);
129
+ payload = Object.assign(Object.assign({}, payload), { qualified_users: availableUsers });
130
+ // If conversation creation returns an error because a backend is offline,
131
+ // we try creating the conversation again with users from available backends
132
+ const response = await this.apiClient.api.conversation.postConversation(payload).catch((error) => {
133
+ throw error;
134
+ });
135
+ // on a succesfull conversation creation with the available users,
136
+ // we append the users from an unreachable backend to the response
137
+ response.failed_to_add = unreachableUsers;
138
+ return response;
139
+ }
141
140
  }
142
141
  }
143
142
  throw error;
144
143
  });
145
144
  }
145
+ /**
146
+ * Tries to add all the given users to the given conversation.
147
+ * If some users are not reachable, it will try to add the remaining users and list them in the `failedToAdd` property of the response.
148
+ */
146
149
  async addUsersToConversation({ conversationId, qualifiedUsers }) {
147
- return this.apiClient.api.conversation.postMembers(conversationId, qualifiedUsers);
150
+ try {
151
+ return { event: await this.apiClient.api.conversation.postMembers(conversationId, qualifiedUsers) };
152
+ }
153
+ catch (error) {
154
+ if ((0, conversation_1.isFederatedBackendsError)(error)) {
155
+ switch (error.label) {
156
+ case conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS: {
157
+ const { backends } = error;
158
+ const { excludedUsers: unreachableUsers, includedUsers: availableUsers } = (0, userDomainFilters_1.filterUsersFromDomains)(qualifiedUsers, backends);
159
+ if (availableUsers.length === 0) {
160
+ return { failedToAdd: unreachableUsers };
161
+ }
162
+ // In case the request to add users failed with a `UNREACHABLE_BACKENDS` error, we try again with the users from available backends
163
+ const response = await this.apiClient.api.conversation.postMembers(conversationId, availableUsers);
164
+ return {
165
+ event: response,
166
+ failedToAdd: unreachableUsers,
167
+ };
168
+ }
169
+ }
170
+ }
171
+ throw error;
172
+ }
148
173
  }
149
174
  async sendMessage({ userIds, conversationId, nativePush, targetMode, payload, onClientMismatch, }) {
150
175
  var _a;
@@ -474,6 +474,45 @@ describe('ProteusService', () => {
474
474
  });
475
475
  });
476
476
  });
477
+ describe('addUsersToConversation', () => {
478
+ const baseResponse = {
479
+ event: {
480
+ conversation: '',
481
+ from: '',
482
+ time: Date.now().toString(),
483
+ data: { users: [], user_ids: [] },
484
+ type: event_1.CONVERSATION_EVENT.MEMBER_JOIN,
485
+ },
486
+ };
487
+ const conversationId = { id: 'conv1', domain: 'domain1' };
488
+ const userDomain1 = { id: 'user-1-1', domain: 'domain1' };
489
+ const user2Domain1 = { id: 'user-2-1', domain: 'domain1' };
490
+ const userDomain2 = { id: 'user-2-2', domain: 'domain2' };
491
+ it('adds all requested users to an existing conversation', async () => {
492
+ const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
493
+ jest.spyOn(apiClient.api.conversation, 'postMembers').mockResolvedValueOnce(baseResponse.event);
494
+ const event = await proteusService.addUsersToConversation({
495
+ conversationId,
496
+ qualifiedUsers: [userDomain1, user2Domain1, userDomain2],
497
+ });
498
+ expect(event).toEqual(baseResponse);
499
+ });
500
+ it('partially add users if some backends are unreachable', async () => {
501
+ const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
502
+ const postMembersSpy = jest
503
+ .spyOn(apiClient.api.conversation, 'postMembers')
504
+ .mockRejectedValueOnce(new conversation_1.FederatedBackendsError(conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS, [userDomain1.domain]))
505
+ .mockResolvedValueOnce(baseResponse.event);
506
+ const result = await proteusService.addUsersToConversation({
507
+ conversationId,
508
+ qualifiedUsers: [userDomain1, user2Domain1, userDomain2],
509
+ });
510
+ expect(postMembersSpy).toHaveBeenCalledTimes(2);
511
+ expect(postMembersSpy).toHaveBeenCalledWith(conversationId, expect.arrayContaining([userDomain1, user2Domain1, userDomain2]));
512
+ expect(postMembersSpy).toHaveBeenCalledWith(conversationId, expect.arrayContaining([userDomain2]));
513
+ expect(result.failedToAdd).toEqual([userDomain1, user2Domain1]);
514
+ });
515
+ });
477
516
  describe('createConversation', () => {
478
517
  const newConversation = {
479
518
  qualified_id: { id: '', domain: '' },
@@ -0,0 +1,6 @@
1
+ import { QualifiedId } from '@wireapp/api-client/lib/user';
2
+ export declare function filterUsersFromDomains(userIds: QualifiedId[], domainsToExclude: string[]): {
3
+ excludedUsers: QualifiedId[];
4
+ includedUsers: QualifiedId[];
5
+ };
6
+ //# sourceMappingURL=userDomainFilters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userDomainFilters.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/proteus/ProteusService/userDomainFilters.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAEzD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,WAAW,EAAE,EACtB,gBAAgB,EAAE,MAAM,EAAE,GACzB;IAAC,aAAa,EAAE,WAAW,EAAE,CAAC;IAAC,aAAa,EAAE,WAAW,EAAE,CAAA;CAAC,CAW9D"}
@@ -0,0 +1,31 @@
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
+ exports.filterUsersFromDomains = void 0;
22
+ function filterUsersFromDomains(userIds, domainsToExclude) {
23
+ const excludedUsers = [];
24
+ const includedUsers = [];
25
+ userIds.forEach(user => domainsToExclude.includes(user.domain) ? excludedUsers.push(user) : includedUsers.push(user));
26
+ return {
27
+ excludedUsers,
28
+ includedUsers,
29
+ };
30
+ }
31
+ exports.filterUsersFromDomains = filterUsersFromDomains;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "./lib/cryptography/AssetCryptography/crypto.node": "./lib/cryptography/AssetCryptography/crypto.browser.js"
12
12
  },
13
13
  "dependencies": {
14
- "@wireapp/api-client": "^24.21.2",
14
+ "@wireapp/api-client": "^25.1.0",
15
15
  "@wireapp/commons": "^5.1.0",
16
16
  "@wireapp/core-crypto": "1.0.0-rc.6",
17
17
  "@wireapp/cryptobox": "12.8.0",
@@ -60,6 +60,6 @@
60
60
  "test:coverage": "jest --coverage",
61
61
  "watch": "tsc --watch"
62
62
  },
63
- "version": "40.9.3",
64
- "gitHead": "737803befa8e5090a776c8ceaff97d031c9f98da"
63
+ "version": "41.1.0",
64
+ "gitHead": "b88ae7c76cc5ed141344814dd0012cdaf47a8af2"
65
65
  }