@wireapp/core 41.0.0 → 41.2.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.
@@ -9,6 +9,10 @@ import { MLSService } from '../../messagingProtocols/mls';
9
9
  import { ProteusService } from '../../messagingProtocols/proteus';
10
10
  import { AddUsersToProteusConversationParams, SendProteusMessageParams } from '../../messagingProtocols/proteus/ProteusService/ProteusService.types';
11
11
  import { RemoteData } from '../content';
12
+ export declare enum AddUsersFailureReasons {
13
+ NON_FEDERATING_BACKENDS = "NON_FEDERATING_BACKENDS",
14
+ UNREACHABLE_BACKENDS = "UNREACHABLE_BACKENDS"
15
+ }
12
16
  export declare class ConversationService {
13
17
  private readonly apiClient;
14
18
  private readonly proteusService;
@@ -27,6 +31,8 @@ export declare class ConversationService {
27
31
  /**
28
32
  * Create a group conversation.
29
33
  *
34
+ * This method might fail with a `BackendsNotConnectedError` if there are users from not connected backends that are part of the payload
35
+ *
30
36
  * @note Do not include yourself as the requestor
31
37
  * @see https://staging-nginz-https.zinfra.io/swagger-ui/#!/conversations/createGroupConversation
32
38
  *
@@ -40,7 +46,10 @@ export declare class ConversationService {
40
46
  getUnencryptedAsset(assetId: string, assetToken?: string): Promise<ArrayBuffer>;
41
47
  addUsersToProteusConversation(params: AddUsersToProteusConversationParams): Promise<{
42
48
  event?: import("@wireapp/api-client/lib/event").ConversationMemberJoinEvent | undefined;
43
- failedToAdd?: QualifiedId[] | undefined;
49
+ failedToAdd?: {
50
+ reason: AddUsersFailureReasons;
51
+ users: QualifiedId[];
52
+ } | undefined;
44
53
  }>;
45
54
  removeUserFromConversation(conversationId: QualifiedId, userId: QualifiedId): Promise<ConversationMemberLeaveEvent>;
46
55
  /**
@@ -89,5 +98,17 @@ export declare class ConversationService {
89
98
  wipeMLSConversation(groupId: string): Promise<void>;
90
99
  private matchesEpoch;
91
100
  handleEpochMismatch(): Promise<void>;
101
+ /**
102
+ * Will try registering mls 1:1 conversation adding the other user.
103
+ * If it fails and the conversation is already established, it will try joining via external commit instead.
104
+ *
105
+ * @param mlsConversation - mls 1:1 conversation
106
+ * @param selfUser - user and client ids of the self user
107
+ * @param otherUserId - id of the other user
108
+ */
109
+ readonly establishMLS1to1Conversation: (groupId: string, selfUser: {
110
+ user: QualifiedId;
111
+ client: string;
112
+ }, otherUserId: QualifiedId) => Promise<void>;
92
113
  }
93
114
  //# 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":"AAmBA,OAAO,EACL,YAAY,EACZ,2BAA2B,EAC3B,WAAW,EACX,eAAe,EACf,oBAAoB,EAEpB,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAC,4BAA4B,EAAC,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAC,GAAG,EAAC,MAAM,oCAAoC,CAAC;AAIvD,OAAO,EAAC,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAI9C,OAAO,EAAC,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,UAAU,EAAC,MAAM,6BAA6B,CAAC;AAE5G,OAAO,EAAC,YAAY,EAAuB,iBAAiB,EAAC,MAAM,qBAAqB,CAAC;AAEzF,OAAO,EAAC,UAAU,EAAuB,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAkC,cAAc,EAAC,MAAM,kCAAkC,CAAC;AACjG,OAAO,EACL,mCAAmC,EACnC,wBAAwB,EACzB,MAAM,sEAAsE,CAAC;AAG9E,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAC;AAGtC,oBAAY,sBAAsB;IAChC,uBAAuB,4BAA4B;IACnD,oBAAoB,yBAAyB;CAC9C;AAED,qBAAa,mBAAmB;IAK5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAN/B,SAAgB,YAAY,EAAE,YAAY,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgD;gBAGpD,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,cAAc,EAC9B,WAAW,CAAC,wBAAY;IAK3C,IAAI,UAAU,IAAI,UAAU,CAK3B;IAED;;;;;OAKG;IACU,2BAA2B,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAkBpG;;;;;;;;;;OAUG;IACU,yBAAyB,CAAC,gBAAgB,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IAInF,eAAe,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAInE,gBAAgB,CAAC,eAAe,CAAC,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAO/E,QAAQ,CAAC,EAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAC,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAWhF,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAK/E,6BAA6B,CAAC,MAAM,EAAE,mCAAmC;;;;;;;IAIzE,0BAA0B,CACrC,cAAc,EAAE,WAAW,EAC3B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,4BAA4B,CAAC;IAIxC;;;OAGG;IACU,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,oBAAoB,EAAE,wBAAwB,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAO5F,eAAe,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D,cAAc,CAAC,cAAc,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjE;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAIpB,0BAA0B,CAC/B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,WAAW,EACnB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,IAAI,CAAC;IAaT,yBAAyB,CAC9B,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,OAAO,EACjB,gBAAgB,GAAE,MAAM,GAAG,IAAiB,GAC3C,OAAO,CAAC,IAAI,CAAC;IAaT,yBAAyB,CAC9B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,2BAA2B,GAAG,MAAM,GACrD,OAAO,CAAC,IAAI,CAAC;IAMhB;;;;OAIG;IAEH;;;OAGG;IACU,qBAAqB,CAChC,gBAAgB,EAAE,eAAe,EACjC,UAAU,EAAE,WAAW,EACvB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC;YAqCX,cAAc;IAiC5B;;;;;;OAMG;IACU,yBAAyB,CAAC,EACrC,cAAc,EACd,OAAO,EACP,cAAc,GACf,EAAE,QAAQ,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IAkBvC,8BAA8B,CAAC,EAC1C,OAAO,EACP,cAAc,EACd,gBAAgB,GACjB,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC;IAoBhC,oBAAoB,CAAC,cAAc,EAAE,WAAW;IAI7D;;;;;OAKG;IACU,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAmBvD,4BAA4B,CAAC,OAAO,EAAE,MAAM;IAI5C,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAIlD,YAAY;IAYb,mBAAmB;IA4BhC;;;;;;;OAOG;IACH,SAAgB,4BAA4B,YACjC,MAAM,YACL;QAAC,IAAI,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,eAChC,WAAW,KACvB,QAAQ,IAAI,CAAC,CA0Bd;CACH"}
@@ -21,7 +21,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
21
  return (mod && mod.__esModule) ? mod : { "default": mod };
22
22
  };
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.ConversationService = void 0;
24
+ exports.ConversationService = exports.AddUsersFailureReasons = void 0;
25
25
  const conversation_1 = require("@wireapp/api-client/lib/conversation");
26
26
  const data_1 = require("@wireapp/api-client/lib/conversation/data");
27
27
  const bazinga64_1 = require("bazinga64");
@@ -35,12 +35,44 @@ const proteus_1 = require("../../messagingProtocols/proteus");
35
35
  const util_1 = require("../../util");
36
36
  const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
37
37
  const messageSender_1 = require("../message/messageSender");
38
+ var AddUsersFailureReasons;
39
+ (function (AddUsersFailureReasons) {
40
+ AddUsersFailureReasons["NON_FEDERATING_BACKENDS"] = "NON_FEDERATING_BACKENDS";
41
+ AddUsersFailureReasons["UNREACHABLE_BACKENDS"] = "UNREACHABLE_BACKENDS";
42
+ })(AddUsersFailureReasons || (exports.AddUsersFailureReasons = AddUsersFailureReasons = {}));
38
43
  class ConversationService {
39
44
  constructor(apiClient, proteusService, _mlsService) {
40
45
  this.apiClient = apiClient;
41
46
  this.proteusService = proteusService;
42
47
  this._mlsService = _mlsService;
43
48
  this.logger = (0, logdown_1.default)('@wireapp/core/ConversationService');
49
+ /**
50
+ * Will try registering mls 1:1 conversation adding the other user.
51
+ * If it fails and the conversation is already established, it will try joining via external commit instead.
52
+ *
53
+ * @param mlsConversation - mls 1:1 conversation
54
+ * @param selfUser - user and client ids of the self user
55
+ * @param otherUserId - id of the other user
56
+ */
57
+ this.establishMLS1to1Conversation = async (groupId, selfUser, otherUserId) => {
58
+ try {
59
+ await this.mlsService.registerConversation(groupId, [otherUserId, selfUser.user], selfUser);
60
+ }
61
+ catch (error) {
62
+ this.logger.info(`Could not register MLS group with id ${groupId}.`);
63
+ const mlsConversation = await this.apiClient.api.conversation.getMLS1to1Conversation(otherUserId);
64
+ if (mlsConversation.epoch > 0) {
65
+ this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is already established, joining via external commit`);
66
+ // If its already established, we join with external commit
67
+ await this.joinByExternalCommit(mlsConversation.qualified_id);
68
+ return;
69
+ }
70
+ this.logger.info(`Conversation (id ${mlsConversation.qualified_id.id}) is not established, retrying to establish it`);
71
+ // If conversation is not established, we can wipe it and try to establish it again
72
+ await this.wipeMLSConversation(groupId);
73
+ return this.establishMLS1to1Conversation(groupId, selfUser, otherUserId);
74
+ }
75
+ };
44
76
  this.messageTimer = new conversation_2.MessageTimer();
45
77
  }
46
78
  get mlsService() {
@@ -68,8 +100,19 @@ class ConversationService {
68
100
  }));
69
101
  return qualifiedUserClients;
70
102
  }
71
- async createProteusConversation(conversationData, otherUserIds) {
72
- return this.proteusService.createConversation({ conversationData, otherUserIds });
103
+ /**
104
+ * Create a group conversation.
105
+ *
106
+ * This method might fail with a `BackendsNotConnectedError` if there are users from not connected backends that are part of the payload
107
+ *
108
+ * @note Do not include yourself as the requestor
109
+ * @see https://staging-nginz-https.zinfra.io/swagger-ui/#!/conversations/createGroupConversation
110
+ *
111
+ * @param conversationData Payload object for group creation
112
+ * @returns Resolves when the conversation was created
113
+ */
114
+ async createProteusConversation(conversationData) {
115
+ return this.proteusService.createConversation(conversationData);
73
116
  }
74
117
  async getConversation(conversationId) {
75
118
  return this.apiClient.api.conversation.getConversation(conversationId);
@@ -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();
@@ -0,0 +1,9 @@
1
+ /**
2
+ * This error means we are trying to add users that are parts of 2 backends that are not federating with each other to a new conversation.
3
+ */
4
+ export declare class NonFederatingBackendsError extends Error {
5
+ readonly backends: string[];
6
+ constructor(backends: string[]);
7
+ }
8
+ export declare function isNonFederatingBackendsError(error: unknown): error is NonFederatingBackendsError;
9
+ //# sourceMappingURL=FederatedBackendsError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FederatedBackendsError.d.ts","sourceRoot":"","sources":["../../src/errors/FederatedBackendsError.ts"],"names":[],"mappings":"AAmBA;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;aACvB,QAAQ,EAAE,MAAM,EAAE;gBAAlB,QAAQ,EAAE,MAAM,EAAE;CAI/C;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAEhG"}
@@ -0,0 +1,36 @@
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.isNonFederatingBackendsError = exports.NonFederatingBackendsError = void 0;
22
+ /**
23
+ * This error means we are trying to add users that are parts of 2 backends that are not federating with each other to a new conversation.
24
+ */
25
+ class NonFederatingBackendsError extends Error {
26
+ constructor(backends) {
27
+ super('2 backends are not connected');
28
+ this.backends = backends;
29
+ this.name = 'NonFederatingBackendError';
30
+ }
31
+ }
32
+ exports.NonFederatingBackendsError = NonFederatingBackendsError;
33
+ function isNonFederatingBackendsError(error) {
34
+ return !!error && typeof error === 'object' && 'name' in error && error.name === 'NonFederatingBackendError';
35
+ }
36
+ exports.isNonFederatingBackendsError = isNonFederatingBackendsError;
@@ -0,0 +1,3 @@
1
+ export * from './DecryptionError';
2
+ export * from './FederatedBackendsError';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/errors/index.ts"],"names":[],"mappings":"AAmBA,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,36 @@
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
32
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ __exportStar(require("./DecryptionError"), exports);
36
+ __exportStar(require("./FederatedBackendsError"), exports);
package/lib/index.d.ts CHANGED
@@ -5,4 +5,5 @@ export { CoreError } from './CoreError';
5
5
  export * as cryptography from './cryptography/';
6
6
  export * as util from './util';
7
7
  export * as MessageBuilder from './conversation/message/MessageBuilder';
8
+ export * as errors from './errors';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAC,MAAM,WAAW,CAAC;AAC1E,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAAO,KAAK,cAAc,MAAM,uCAAuC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAC,MAAM,WAAW,CAAC;AAC1E,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC/B,OAAO,KAAK,cAAc,MAAM,uCAAuC,CAAC;AACxE,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC"}
package/lib/index.js CHANGED
@@ -41,7 +41,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
41
41
  return result;
42
42
  };
43
43
  Object.defineProperty(exports, "__esModule", { value: true });
44
- exports.MessageBuilder = exports.util = exports.cryptography = exports.CoreError = exports.conversation = exports.auth = exports.ConnectionState = exports.Account = void 0;
44
+ exports.errors = exports.MessageBuilder = exports.util = exports.cryptography = exports.CoreError = exports.conversation = exports.auth = exports.ConnectionState = exports.Account = void 0;
45
45
  var Account_1 = require("./Account");
46
46
  Object.defineProperty(exports, "Account", { enumerable: true, get: function () { return Account_1.Account; } });
47
47
  Object.defineProperty(exports, "ConnectionState", { enumerable: true, get: function () { return Account_1.ConnectionState; } });
@@ -52,3 +52,4 @@ Object.defineProperty(exports, "CoreError", { enumerable: true, get: function ()
52
52
  exports.cryptography = __importStar(require("./cryptography/"));
53
53
  exports.util = __importStar(require("./util"));
54
54
  exports.MessageBuilder = __importStar(require("./conversation/message/MessageBuilder"));
55
+ exports.errors = __importStar(require("./errors"));
@@ -1,12 +1,12 @@
1
1
  import type { APIClient } from '@wireapp/api-client/lib/APIClient';
2
2
  import type { PreKey, Context } from '@wireapp/api-client/lib/auth';
3
- import { Conversation, QualifiedOTRRecipients, QualifiedUserClients } from '@wireapp/api-client/lib/conversation';
3
+ import { Conversation, NewConversation, QualifiedOTRRecipients, QualifiedUserClients } from '@wireapp/api-client/lib/conversation';
4
4
  import type { ConversationMemberJoinEvent } from '@wireapp/api-client/lib/event';
5
5
  import type { QualifiedId, QualifiedUserPreKeyBundleMap } from '@wireapp/api-client/lib/user';
6
6
  import { CRUDEngine } from '@wireapp/store-engine';
7
7
  import { CryptoClient } from './CryptoClient';
8
- import type { AddUsersToProteusConversationParams, CreateProteusConversationParams, ProteusServiceConfig, SendProteusMessageParams } from './ProteusService.types';
9
- import { SendResult } from '../../../conversation';
8
+ import type { AddUsersToProteusConversationParams, ProteusServiceConfig, SendProteusMessageParams } from './ProteusService.types';
9
+ import { AddUsersFailureReasons, SendResult } from '../../../conversation';
10
10
  import type { EventHandlerResult } from '../../common.types';
11
11
  import { EventHandlerParams } from '../EventHandler';
12
12
  export type EncryptionResult = {
@@ -40,14 +40,17 @@ export declare class ProteusService {
40
40
  * If not provided and the session doesn't exists it will fetch a new prekey from the backend
41
41
  */
42
42
  getRemoteFingerprint(userId: QualifiedId, clientId: string, prekey?: PreKey): Promise<string>;
43
- createConversation({ conversationData, otherUserIds, }: CreateProteusConversationParams): Promise<Conversation>;
43
+ createConversation(conversationData: NewConversation): Promise<Conversation>;
44
44
  /**
45
45
  * Tries to add all the given users to the given conversation.
46
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
47
  */
48
48
  addUsersToConversation({ conversationId, qualifiedUsers }: AddUsersToProteusConversationParams): Promise<{
49
49
  event?: ConversationMemberJoinEvent;
50
- failedToAdd?: QualifiedId[];
50
+ failedToAdd?: {
51
+ reason: AddUsersFailureReasons;
52
+ users: QualifiedId[];
53
+ };
51
54
  }>;
52
55
  sendMessage({ userIds, conversationId, nativePush, targetMode, payload, onClientMismatch, }: SendProteusMessageParams): Promise<SendResult>;
53
56
  private decrypt;
@@ -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,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"}
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,EAGZ,eAAe,EACf,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,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EAAC,sBAAsB,EAA2C,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAGlH,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,gBAAgB,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;IAiCzF;;;OAGG;IACU,sBAAsB,CAAC,EAAC,cAAc,EAAE,cAAc,EAAC,EAAE,mCAAmC,GAAG,OAAO,CAAC;QAClH,KAAK,CAAC,EAAE,2BAA2B,CAAC;QACpC,WAAW,CAAC,EAAE;YAAC,MAAM,EAAE,sBAAsB,CAAC;YAAC,KAAK,EAAE,WAAW,EAAE,CAAA;SAAC,CAAC;KACtE,CAAC;IAqCW,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"}
@@ -32,6 +32,7 @@ const sessionIdMigrator_1 = require("./sessionIdMigrator");
32
32
  const userDomainFilters_1 = require("./userDomainFilters");
33
33
  const conversation_2 = require("../../../conversation");
34
34
  const MessageService_1 = require("../../../conversation/message/MessageService");
35
+ const errors_1 = require("../../../errors");
35
36
  const EventHandler_1 = require("../EventHandler");
36
37
  const getGenericMessageParams_1 = require("../Utility/getGenericMessageParams");
37
38
  const isClearFromMismatch_1 = require("../Utility/isClearFromMismatch");
@@ -106,32 +107,25 @@ class ProteusService {
106
107
  const sessionId = await (0, SessionHandler_1.initSession)({ userId, clientId, initialPrekey: prekey }, { cryptoClient: this.cryptoClient, apiClient: this.apiClient });
107
108
  return this.cryptoClient.getRemoteFingerprint(sessionId);
108
109
  }
109
- async createConversation({ conversationData, otherUserIds, }) {
110
- let payload;
111
- if (typeof conversationData === 'string') {
112
- const ids = typeof otherUserIds === 'string' ? [otherUserIds] : otherUserIds;
113
- payload = {
114
- name: conversationData,
115
- receipt_mode: null,
116
- users: ids !== null && ids !== void 0 ? ids : [],
117
- };
118
- }
119
- else {
120
- payload = conversationData;
110
+ async createConversation(conversationData) {
111
+ var _a;
112
+ try {
113
+ return await this.apiClient.api.conversation.postConversation(conversationData);
121
114
  }
122
- return this.apiClient.api.conversation.postConversation(payload).catch(async (error) => {
123
- var _a;
115
+ catch (error) {
124
116
  if ((0, conversation_1.isFederatedBackendsError)(error)) {
125
117
  switch (error.label) {
118
+ case conversation_1.FederatedBackendsErrorLabel.NON_FEDERATING_BACKENDS: {
119
+ // In case we are trying to create a conversation with users from 2 backends that are not connected, we should stop the procedure and throw an error
120
+ throw new errors_1.NonFederatingBackendsError(error.backends);
121
+ }
126
122
  case conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS: {
127
123
  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 });
124
+ const { excludedUsers: unreachableUsers, includedUsers: availableUsers } = (0, userDomainFilters_1.filterUsersFromDomains)((_a = conversationData.qualified_users) !== null && _a !== void 0 ? _a : [], backends);
125
+ conversationData = Object.assign(Object.assign({}, conversationData), { qualified_users: availableUsers });
130
126
  // If conversation creation returns an error because a backend is offline,
131
127
  // 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
- });
128
+ const response = await this.apiClient.api.conversation.postConversation(conversationData);
135
129
  // on a succesfull conversation creation with the available users,
136
130
  // we append the users from an unreachable backend to the response
137
131
  response.failed_to_add = unreachableUsers;
@@ -140,7 +134,7 @@ class ProteusService {
140
134
  }
141
135
  }
142
136
  throw error;
143
- });
137
+ }
144
138
  }
145
139
  /**
146
140
  * Tries to add all the given users to the given conversation.
@@ -151,19 +145,26 @@ class ProteusService {
151
145
  return { event: await this.apiClient.api.conversation.postMembers(conversationId, qualifiedUsers) };
152
146
  }
153
147
  catch (error) {
148
+ const failureReasonsMap = {
149
+ [conversation_1.FederatedBackendsErrorLabel.NON_FEDERATING_BACKENDS]: conversation_2.AddUsersFailureReasons.NON_FEDERATING_BACKENDS,
150
+ [conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS]: conversation_2.AddUsersFailureReasons.UNREACHABLE_BACKENDS,
151
+ };
154
152
  if ((0, conversation_1.isFederatedBackendsError)(error)) {
155
153
  switch (error.label) {
154
+ case conversation_1.FederatedBackendsErrorLabel.NON_FEDERATING_BACKENDS:
156
155
  case conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS: {
157
156
  const { backends } = error;
158
157
  const { excludedUsers: unreachableUsers, includedUsers: availableUsers } = (0, userDomainFilters_1.filterUsersFromDomains)(qualifiedUsers, backends);
159
158
  if (availableUsers.length === 0) {
160
- return { failedToAdd: unreachableUsers };
159
+ return { failedToAdd: { reason: failureReasonsMap[error.label], users: unreachableUsers } };
161
160
  }
162
- // In case the request to add users failed with a `UNREACHABLE_BACKENDS` error, we try again with the users from available backends
161
+ // In case the request to add users failed with a `UNREACHABLE_BACKENDS` or `NOT_CONNECTED_BACKENDS` errors, we try again with the users from available backends
163
162
  const response = await this.apiClient.api.conversation.postMembers(conversationId, availableUsers);
164
163
  return {
165
164
  event: response,
166
- failedToAdd: unreachableUsers,
165
+ failedToAdd: unreachableUsers.length > 0
166
+ ? { reason: failureReasonsMap[error.label], users: unreachableUsers }
167
+ : undefined,
167
168
  };
168
169
  }
169
170
  }
@@ -51,6 +51,7 @@ const SessionHandler_1 = require("../Utility/SessionHandler");
51
51
  const notification_1 = require("../../../notification");
52
52
  const event_1 = require("@wireapp/api-client/lib/event");
53
53
  const protocol_messaging_1 = require("@wireapp/protocol-messaging");
54
+ const errors_1 = require("../../../errors");
54
55
  jest.mock('./CryptoClient/CoreCryptoWrapper/PrekeysTracker', () => {
55
56
  return {
56
57
  PrekeyTracker: jest.fn().mockImplementation(() => {
@@ -487,7 +488,8 @@ describe('ProteusService', () => {
487
488
  const conversationId = { id: 'conv1', domain: 'domain1' };
488
489
  const userDomain1 = { id: 'user-1-1', domain: 'domain1' };
489
490
  const user2Domain1 = { id: 'user-2-1', domain: 'domain1' };
490
- const userDomain2 = { id: 'user-2-2', domain: 'domain2' };
491
+ const userDomain2 = { id: 'user-1-2', domain: 'domain2' };
492
+ const userDomain3 = { id: 'user-1-3', domain: 'domain3' };
491
493
  it('adds all requested users to an existing conversation', async () => {
492
494
  const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
493
495
  jest.spyOn(apiClient.api.conversation, 'postMembers').mockResolvedValueOnce(baseResponse.event);
@@ -498,6 +500,7 @@ describe('ProteusService', () => {
498
500
  expect(event).toEqual(baseResponse);
499
501
  });
500
502
  it('partially add users if some backends are unreachable', async () => {
503
+ var _a, _b;
501
504
  const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
502
505
  const postMembersSpy = jest
503
506
  .spyOn(apiClient.api.conversation, 'postMembers')
@@ -510,7 +513,28 @@ describe('ProteusService', () => {
510
513
  expect(postMembersSpy).toHaveBeenCalledTimes(2);
511
514
  expect(postMembersSpy).toHaveBeenCalledWith(conversationId, expect.arrayContaining([userDomain1, user2Domain1, userDomain2]));
512
515
  expect(postMembersSpy).toHaveBeenCalledWith(conversationId, expect.arrayContaining([userDomain2]));
513
- expect(result.failedToAdd).toEqual([userDomain1, user2Domain1]);
516
+ expect((_a = result.failedToAdd) === null || _a === void 0 ? void 0 : _a.reason).toBe(conversation_2.AddUsersFailureReasons.UNREACHABLE_BACKENDS);
517
+ expect((_b = result.failedToAdd) === null || _b === void 0 ? void 0 : _b.users).toEqual([userDomain1, user2Domain1]);
518
+ });
519
+ it('partially add users if some users are part of not-connected backends', async () => {
520
+ var _a, _b;
521
+ const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
522
+ const postMembersSpy = jest
523
+ .spyOn(apiClient.api.conversation, 'postMembers')
524
+ .mockRejectedValueOnce(new conversation_1.FederatedBackendsError(conversation_1.FederatedBackendsErrorLabel.NON_FEDERATING_BACKENDS, [
525
+ userDomain2.domain,
526
+ userDomain3.domain,
527
+ ]))
528
+ .mockResolvedValueOnce(baseResponse.event);
529
+ const result = await proteusService.addUsersToConversation({
530
+ conversationId,
531
+ qualifiedUsers: [userDomain1, user2Domain1, userDomain2, userDomain3],
532
+ });
533
+ expect(postMembersSpy).toHaveBeenCalledTimes(2);
534
+ expect(postMembersSpy).toHaveBeenCalledWith(conversationId, expect.arrayContaining([userDomain1, user2Domain1, userDomain2]));
535
+ expect(postMembersSpy).toHaveBeenCalledWith(conversationId, expect.arrayContaining([userDomain1, user2Domain1]));
536
+ expect((_a = result.failedToAdd) === null || _a === void 0 ? void 0 : _a.reason).toBe(conversation_2.AddUsersFailureReasons.NON_FEDERATING_BACKENDS);
537
+ expect((_b = result.failedToAdd) === null || _b === void 0 ? void 0 : _b.users).toEqual([userDomain2, userDomain3]);
514
538
  });
515
539
  });
516
540
  describe('createConversation', () => {
@@ -545,10 +569,8 @@ describe('ProteusService', () => {
545
569
  const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
546
570
  jest.spyOn(apiClient.api.conversation, 'postConversation').mockResolvedValueOnce(Object.assign({}, newConversation));
547
571
  const result = await proteusService.createConversation({
548
- conversationData: {
549
- receipt_mode: null,
550
- qualified_users: [userDomain1, user2Domain1, userDomain2],
551
- },
572
+ receipt_mode: null,
573
+ qualified_users: [userDomain1, user2Domain1, userDomain2],
552
574
  });
553
575
  expect(result).toEqual(newConversation);
554
576
  });
@@ -559,10 +581,8 @@ describe('ProteusService', () => {
559
581
  .mockRejectedValueOnce(new conversation_1.FederatedBackendsError(conversation_1.FederatedBackendsErrorLabel.UNREACHABLE_BACKENDS, [userDomain1.domain]))
560
582
  .mockResolvedValueOnce(newConversation);
561
583
  const result = await proteusService.createConversation({
562
- conversationData: {
563
- receipt_mode: null,
564
- qualified_users: [userDomain1, user2Domain1, userDomain2],
565
- },
584
+ receipt_mode: null,
585
+ qualified_users: [userDomain1, user2Domain1, userDomain2],
566
586
  });
567
587
  expect(postConversationSpy).toHaveBeenCalledTimes(2);
568
588
  expect(postConversationSpy).toHaveBeenCalledWith(expect.objectContaining({ qualified_users: [userDomain1, user2Domain1, userDomain2] }));
@@ -579,15 +599,26 @@ describe('ProteusService', () => {
579
599
  ]))
580
600
  .mockResolvedValueOnce({});
581
601
  const result = await proteusService.createConversation({
582
- conversationData: {
583
- receipt_mode: null,
584
- qualified_users: [userDomain1, user2Domain1, userDomain2],
585
- },
602
+ receipt_mode: null,
603
+ qualified_users: [userDomain1, user2Domain1, userDomain2],
586
604
  });
587
605
  expect(postConversationSpy).toHaveBeenCalledTimes(2);
588
606
  expect(postConversationSpy).toHaveBeenCalledWith(expect.objectContaining({ qualified_users: [userDomain1, user2Domain1, userDomain2] }));
589
607
  expect(postConversationSpy).toHaveBeenCalledWith(expect.objectContaining({ qualified_users: [] }));
590
608
  expect(result.failed_to_add).toEqual([userDomain1, user2Domain1, userDomain2]);
591
609
  });
610
+ it('fails to create a conversation if there are users from non-connected backends', async () => {
611
+ const [proteusService, { apiClient }] = await (0, ProteusService_mocks_1.buildProteusService)();
612
+ jest
613
+ .spyOn(apiClient.api.conversation, 'postConversation')
614
+ .mockRejectedValueOnce(new conversation_1.FederatedBackendsError(conversation_1.FederatedBackendsErrorLabel.NON_FEDERATING_BACKENDS, [
615
+ userDomain1.domain,
616
+ userDomain2.domain,
617
+ ]));
618
+ await expect(() => proteusService.createConversation({
619
+ receipt_mode: null,
620
+ qualified_users: [userDomain1, user2Domain1, userDomain2],
621
+ })).rejects.toThrow(errors_1.NonFederatingBackendsError);
622
+ });
592
623
  });
593
624
  });
@@ -102,22 +102,14 @@ describe('createConversation', () => {
102
102
  it('when a new conversation object is given', async () => {
103
103
  const proteusService = await prepareProteusService();
104
104
  const conversationData = createConversationResult;
105
- const returnData = await proteusService.createConversation({ conversationData });
105
+ const returnData = await proteusService.createConversation(conversationData);
106
106
  expect(returnData).toStrictEqual(createConversationResult);
107
107
  });
108
108
  it('create a new conversation with no name', async () => {
109
109
  const proteusService = await prepareProteusService();
110
- const otherUserIds = ['user1', 'user2'];
111
110
  const conversationData = { users: ['user1', 'user2'], receipt_mode: null };
112
- const returnData = await proteusService.createConversation({ conversationData, otherUserIds });
111
+ const returnData = await proteusService.createConversation(conversationData);
113
112
  expect(returnData).toStrictEqual(conversationData);
114
113
  });
115
- it('when a conversation string and userIds are given', async () => {
116
- const proteusService = await prepareProteusService();
117
- const otherUserIds = ['user1', 'user2'];
118
- const conversationData = 'test';
119
- const returnData = await proteusService.createConversation({ conversationData, otherUserIds });
120
- expect(returnData).toStrictEqual(createConversationResult);
121
- });
122
114
  });
123
115
  });
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": "^25.0.0",
14
+ "@wireapp/api-client": "^25.2.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": "41.0.0",
64
- "gitHead": "7d3f425539e2e8a549fa813c1b6d5d19598475d8"
63
+ "version": "41.2.0",
64
+ "gitHead": "139c43189700e34d69f734596cfd6e3f12732ff3"
65
65
  }