@wireapp/core 40.5.3-draft-20-cc.3 → 40.5.3-draft-20-cc.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.
Files changed (143) hide show
  1. package/lib/Account.d.ts +9 -7
  2. package/lib/Account.d.ts.map +1 -1
  3. package/lib/Account.js +32 -35
  4. package/lib/CoreError.js +1 -1
  5. package/lib/broadcast/BroadcastService.d.ts +2 -11
  6. package/lib/broadcast/BroadcastService.d.ts.map +1 -1
  7. package/lib/broadcast/BroadcastService.js +5 -39
  8. package/lib/client/ClientDatabaseRepository.d.ts +5 -5
  9. package/lib/client/ClientDatabaseRepository.d.ts.map +1 -1
  10. package/lib/client/ClientDatabaseRepository.js +10 -17
  11. package/lib/client/ClientService.d.ts +5 -1
  12. package/lib/client/ClientService.d.ts.map +1 -1
  13. package/lib/client/ClientService.js +11 -9
  14. package/lib/connection/ConnectionService.d.ts +2 -2
  15. package/lib/connection/ConnectionService.d.ts.map +1 -1
  16. package/lib/connection/ConnectionService.js +2 -2
  17. package/lib/conversation/AssetTransferState.js +1 -1
  18. package/lib/conversation/ConversationService/ConversationService.d.ts +12 -5
  19. package/lib/conversation/ConversationService/ConversationService.d.ts.map +1 -1
  20. package/lib/conversation/ConversationService/ConversationService.js +26 -11
  21. package/lib/conversation/ConversationService/ConversationService.test.js +1 -1
  22. package/lib/conversation/ConversationService/ConversationService.types.d.ts +12 -11
  23. package/lib/conversation/ConversationService/ConversationService.types.d.ts.map +1 -1
  24. package/lib/conversation/ConversationService/ConversationService.types.js +1 -1
  25. package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts +1 -1
  26. package/lib/conversation/ConversationService/Utility/getConversationQualifiedMembers.d.ts.map +1 -1
  27. package/lib/conversation/GenericMessageType.js +1 -1
  28. package/lib/conversation/ReactionType.d.ts +1 -4
  29. package/lib/conversation/ReactionType.d.ts.map +1 -1
  30. package/lib/conversation/ReactionType.js +0 -6
  31. package/lib/conversation/message/Message.types.js +1 -1
  32. package/lib/conversation/message/MessageBuilder.d.ts +1 -1
  33. package/lib/conversation/message/MessageBuilder.d.ts.map +1 -1
  34. package/lib/conversation/message/MessageBuilder.js +2 -2
  35. package/lib/conversation/message/MessageService.d.ts +6 -31
  36. package/lib/conversation/message/MessageService.d.ts.map +1 -1
  37. package/lib/conversation/message/MessageService.js +19 -162
  38. package/lib/conversation/message/MessageService.test.js +151 -141
  39. package/lib/conversation/message/PayloadBundle.js +1 -1
  40. package/lib/conversation/message/UserClientsUtil.d.ts +14 -10
  41. package/lib/conversation/message/UserClientsUtil.d.ts.map +1 -1
  42. package/lib/conversation/message/UserClientsUtil.js +21 -11
  43. package/lib/conversation/message/UserClientsUtils.test.js +5 -9
  44. package/lib/messagingProtocols/mls/EventHandler/EventHandler.d.ts +1 -1
  45. package/lib/messagingProtocols/mls/EventHandler/EventHandler.d.ts.map +1 -1
  46. package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.d.ts +1 -1
  47. package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.d.ts.map +1 -1
  48. package/lib/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.js +7 -2
  49. package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.d.ts.map +1 -1
  50. package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.js +2 -0
  51. package/lib/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.test.js +3 -1
  52. package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts +20 -8
  53. package/lib/messagingProtocols/mls/MLSService/MLSService.d.ts.map +1 -1
  54. package/lib/messagingProtocols/mls/MLSService/MLSService.js +81 -40
  55. package/lib/messagingProtocols/mls/MLSService/MLSService.test.js +9 -0
  56. package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.d.ts +1 -1
  57. package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.d.ts.map +1 -1
  58. package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.js +5 -5
  59. package/lib/messagingProtocols/mls/MLSService/commitBundleUtil.test.js +3 -3
  60. package/lib/messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore.d.ts +13 -0
  61. package/lib/messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore.d.ts.map +1 -0
  62. package/lib/messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore.js +67 -0
  63. package/lib/messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore.test.d.ts +2 -0
  64. package/lib/messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore.test.d.ts.map +1 -0
  65. package/lib/messagingProtocols/mls/MLSService/stores/subconversationGroupIdStore/subconversationGroupIdStore.test.js +72 -0
  66. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts +10 -5
  67. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.d.ts.map +1 -1
  68. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/CoreCryptoWrapper.js +33 -11
  69. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.d.ts +2 -3
  70. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.d.ts.map +1 -1
  71. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.js +8 -9
  72. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.store.d.ts +4 -9
  73. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.store.d.ts.map +1 -1
  74. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.store.js +10 -24
  75. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CoreCryptoWrapper/PrekeysTracker/PrekeysTracker.test.js +2 -10
  76. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.d.ts +1 -2
  77. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.d.ts.map +1 -1
  78. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.js +3 -3
  79. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts +2 -2
  80. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoClient.types.d.ts.map +1 -1
  81. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoboxWrapper.d.ts +1 -1
  82. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoboxWrapper.d.ts.map +1 -1
  83. package/lib/messagingProtocols/proteus/ProteusService/CryptoClient/CryptoboxWrapper.js +2 -2
  84. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts +14 -7
  85. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.d.ts.map +1 -1
  86. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.js +31 -35
  87. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts +1 -1
  88. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.d.ts.map +1 -1
  89. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.mocks.js +2 -3
  90. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.test.js +109 -89
  91. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.types.d.ts +6 -9
  92. package/lib/messagingProtocols/proteus/ProteusService/ProteusService.types.d.ts.map +1 -1
  93. package/lib/messagingProtocols/proteus/Utility/Recipients.d.ts +4 -10
  94. package/lib/messagingProtocols/proteus/Utility/Recipients.d.ts.map +1 -1
  95. package/lib/messagingProtocols/proteus/Utility/Recipients.js +16 -16
  96. package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.d.ts +15 -10
  97. package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.d.ts.map +1 -1
  98. package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.js +80 -92
  99. package/lib/messagingProtocols/proteus/Utility/SessionHandler/SessionHandler.test.js +70 -54
  100. package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts +5 -14
  101. package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.d.ts.map +1 -1
  102. package/lib/messagingProtocols/proteus/Utility/getGenericMessageParams.js +3 -35
  103. package/lib/messagingProtocols/proteus/Utility/isClearFromMismatch.d.ts +2 -2
  104. package/lib/messagingProtocols/proteus/Utility/isClearFromMismatch.d.ts.map +1 -1
  105. package/lib/notification/NotificationDatabaseRepository.js +1 -1
  106. package/lib/notification/Notifications.types.js +1 -1
  107. package/lib/user/UserService.d.ts +6 -17
  108. package/lib/user/UserService.d.ts.map +1 -1
  109. package/lib/user/UserService.js +2 -47
  110. package/lib/util/TaskScheduler/TaskScheduler.d.ts +4 -1
  111. package/lib/util/TaskScheduler/TaskScheduler.d.ts.map +1 -1
  112. package/lib/util/TaskScheduler/TaskScheduler.js +24 -3
  113. package/lib/util/TaskScheduler/TaskScheduler.store.d.ts +7 -0
  114. package/lib/util/TaskScheduler/TaskScheduler.store.d.ts.map +1 -0
  115. package/lib/util/TaskScheduler/TaskScheduler.store.js +34 -0
  116. package/lib/util/TypePredicateUtil.d.ts +0 -1
  117. package/lib/util/TypePredicateUtil.d.ts.map +1 -1
  118. package/lib/util/TypePredicateUtil.js +1 -2
  119. package/package.json +3 -3
  120. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/index.d.ts +0 -2
  121. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/index.d.ts.map +0 -1
  122. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/index.js +0 -35
  123. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/keyMaterialUpdatesStore.d.ts +0 -11
  124. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/keyMaterialUpdatesStore.d.ts.map +0 -1
  125. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/keyMaterialUpdatesStore.js +0 -50
  126. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/keyMaterialUpdatesStore.test.d.ts +0 -2
  127. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/keyMaterialUpdatesStore.test.d.ts.map +0 -1
  128. package/lib/messagingProtocols/mls/MLSService/stores/keyMaterialUpdatesStore/keyMaterialUpdatesStore.test.js +0 -39
  129. package/lib/messagingProtocols/mls/MLSService/subconversationGroupIdMapper.d.ts +0 -4
  130. package/lib/messagingProtocols/mls/MLSService/subconversationGroupIdMapper.d.ts.map +0 -1
  131. package/lib/messagingProtocols/mls/MLSService/subconversationGroupIdMapper.js +0 -35
  132. package/lib/messagingProtocols/mls/MLSService/subconversationGroupIdMapper.test.d.ts +0 -2
  133. package/lib/messagingProtocols/mls/MLSService/subconversationGroupIdMapper.test.d.ts.map +0 -1
  134. package/lib/messagingProtocols/mls/MLSService/subconversationGroupIdMapper.test.js +0 -35
  135. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/PreKeyBundle.d.ts +0 -25
  136. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/PreKeyBundle.d.ts.map +0 -1
  137. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/PreKeyBundle.js +0 -93
  138. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/PreKeyBundle.test.d.ts +0 -2
  139. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/PreKeyBundle.test.d.ts.map +0 -1
  140. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/PreKeyBundle.test.js +0 -66
  141. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/index.d.ts +0 -2
  142. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/index.d.ts.map +0 -1
  143. package/lib/messagingProtocols/proteus/Utility/PreKeyBundle/index.js +0 -35
@@ -51,12 +51,14 @@ function generateQualifiedRecipients(users) {
51
51
  return payload;
52
52
  }
53
53
  function generateRecipients(users) {
54
- return users.reduce((acc, { id, clients }) => {
55
- acc[id] = clients;
54
+ return users.reduce((acc, { id, domain, clients }) => {
55
+ const domainUsers = acc[domain] || {};
56
+ domainUsers[id] = clients;
57
+ acc[domain] = domainUsers;
56
58
  return acc;
57
59
  }, {});
58
60
  }
59
- function fakeEncryptQualified(_, recipients) {
61
+ function fakeEncrypt(_, recipients) {
60
62
  const encryptedPayload = Object.entries(recipients).reduce((acc, [domain, users]) => {
61
63
  acc[domain] = Object.entries(users).reduce((userClients, [userId, clients]) => {
62
64
  userClients[userId] = clients.reduce((payloads, client) => {
@@ -67,44 +69,102 @@ function fakeEncryptQualified(_, recipients) {
67
69
  }, {});
68
70
  return acc;
69
71
  }, {});
70
- return Promise.resolve(encryptedPayload);
71
- }
72
- function fakeEncrypt(_, recipients) {
73
- const encryptedPayload = Object.entries(recipients).reduce((userClients, [userId, clients]) => {
74
- userClients[userId] || (userClients[userId] = clients.reduce((acc, clientId) => {
75
- acc[clientId] = new Uint8Array();
76
- return acc;
77
- }, {}));
78
- return userClients;
79
- }, {});
80
- return Promise.resolve(encryptedPayload);
72
+ return Promise.resolve({ payloads: encryptedPayload });
81
73
  }
82
74
  const buildMessageService = async () => {
83
75
  const apiClient = new api_client_1.APIClient();
84
- const [proteusService] = await (0, ProteusService_mocks_1.buildProteusService)(true);
76
+ const [proteusService] = await (0, ProteusService_mocks_1.buildProteusService)();
85
77
  const messageService = new MessageService_1.MessageService(apiClient, proteusService);
86
- jest.spyOn(proteusService, 'encryptQualified').mockImplementation(fakeEncryptQualified);
87
78
  jest.spyOn(proteusService, 'encrypt').mockImplementation(fakeEncrypt);
88
- return [messageService, { apiClient }];
79
+ return [messageService, { apiClient, proteusService }];
89
80
  };
90
81
  describe('MessageService', () => {
91
- describe('sendFederatedMessage', () => {
82
+ describe('sendMessage', () => {
83
+ const generateUsers = (userCount, clientsPerUser) => {
84
+ return Array.from(Array(userCount)).map((_, i) => ({
85
+ id: `user${i}`,
86
+ domain: `${i}.domain`,
87
+ clients: Array.from(Array(clientsPerUser)).map((_, j) => `client${i}${j}`),
88
+ }));
89
+ };
90
+ const clientId = 'sendingClient';
91
+ const conversationId = { id: 'conv1', domain: '' };
92
+ const createMessage = (content) => {
93
+ const customTextMessage = protocol_messaging_1.GenericMessage.create({
94
+ messageId: (0, PayloadHelper_1.getUUID)(),
95
+ text: protocol_messaging_1.Text.create({ content }),
96
+ });
97
+ return protocol_messaging_1.GenericMessage.encode(customTextMessage).finish();
98
+ };
92
99
  it('sends a message and forwards backend response', async () => {
93
100
  const [messageService, { apiClient }] = await buildMessageService();
94
- jest.spyOn(apiClient.api.conversation, 'postOTRMessageV2').mockResolvedValue(baseMessageSendingStatus);
101
+ jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockResolvedValue(baseMessageSendingStatus);
95
102
  const recipients = generateQualifiedRecipients([user1, user2]);
96
- const result = await messageService.sendFederatedMessage('senderclientid', recipients, new Uint8Array(), {
97
- conversationId: { id: 'convid', domain: '' },
103
+ const result = await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
104
+ conversationId: { id: 'convid', domain: 'domain' },
105
+ });
106
+ expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalled();
107
+ expect(result).toEqual(Object.assign(Object.assign({}, baseMessageSendingStatus), { failed: undefined }));
108
+ });
109
+ it('should send regular to conversation', async () => {
110
+ const [messageService, { apiClient }] = await buildMessageService();
111
+ const message = 'Lorem ipsum dolor sit amet';
112
+ jest
113
+ .spyOn(apiClient.api.conversation, 'postOTRMessage')
114
+ .mockReturnValue(Promise.resolve({}));
115
+ await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message), {
116
+ conversationId,
98
117
  });
99
- expect(apiClient.api.conversation.postOTRMessageV2).toHaveBeenCalled();
100
- expect(result).toEqual(baseMessageSendingStatus);
118
+ expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledWith(conversationId.id, conversationId.domain, expect.any(Object));
119
+ });
120
+ it('should broadcast regular message if no conversationId is given', async () => {
121
+ const [messageService, { apiClient }] = await buildMessageService();
122
+ const message = 'Lorem ipsum dolor sit amet';
123
+ jest
124
+ .spyOn(apiClient.api.broadcast, 'postBroadcastMessage')
125
+ .mockReturnValue(Promise.resolve({}));
126
+ await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message));
127
+ expect(apiClient.api.broadcast.postBroadcastMessage).toHaveBeenCalledWith(clientId, expect.any(Object));
101
128
  });
102
129
  describe('client mismatch', () => {
130
+ const baseClientMismatch = {
131
+ deleted: {},
132
+ missing: {},
133
+ redundant: {},
134
+ failed_to_send: {},
135
+ time: new Date().toISOString(),
136
+ };
137
+ it('handles client mismatch when no other clients from that domain are known', async () => {
138
+ const [messageService, { apiClient }] = await buildMessageService();
139
+ let spyCounter = 0;
140
+ const clientMismatch = Object.assign(Object.assign({}, baseClientMismatch), { missing: { [user1.domain]: { [user1.id]: ['client'] } } });
141
+ jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
142
+ spyCounter++;
143
+ if (spyCounter === 1) {
144
+ const error = new Error();
145
+ error.response = {
146
+ status: http_status_codes_1.StatusCodes.PRECONDITION_FAILED,
147
+ data: clientMismatch,
148
+ };
149
+ return Promise.reject(error);
150
+ }
151
+ return Promise.resolve(baseClientMismatch);
152
+ });
153
+ jest
154
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
155
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
156
+ const recipients = generateRecipients([]);
157
+ await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
158
+ reportMissing: true,
159
+ conversationId: { id: 'convid', domain: '' },
160
+ });
161
+ expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledTimes(2);
162
+ });
103
163
  it('handles client mismatch internally if no onClientMismatch is given', async () => {
104
164
  const [messageService, { apiClient }] = await buildMessageService();
105
165
  let spyCounter = 0;
106
- const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { deleted: { [user1.domain]: { [user1.id]: [user1.clients[0]] } }, missing: { '2.wire.test': { [user2.id]: ['client22'] } } });
107
- jest.spyOn(apiClient.api.conversation, 'postOTRMessageV2').mockImplementation(() => {
166
+ const clientMismatch = Object.assign(Object.assign({}, baseClientMismatch), { deleted: { [user1.domain]: { [user1.id]: [user1.clients[0]] } }, missing: { [user2.domain]: { [user2.id]: ['client22'] } } });
167
+ jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
108
168
  spyCounter++;
109
169
  if (spyCounter === 1) {
110
170
  const error = new Error();
@@ -114,22 +174,24 @@ describe('MessageService', () => {
114
174
  };
115
175
  return Promise.reject(error);
116
176
  }
117
- return Promise.resolve(baseMessageSendingStatus);
177
+ return Promise.resolve(baseClientMismatch);
118
178
  });
119
- jest.spyOn(apiClient.api.user, 'postQualifiedMultiPreKeyBundles').mockReturnValue(Promise.resolve({}));
120
- const recipients = generateQualifiedRecipients([user1, user2]);
121
- await messageService.sendFederatedMessage('senderclientid', recipients, new Uint8Array(), {
179
+ jest
180
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
181
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
182
+ const recipients = generateRecipients([user1, user2]);
183
+ await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
122
184
  reportMissing: true,
123
185
  conversationId: { id: 'convid', domain: '' },
124
186
  });
125
- expect(apiClient.api.conversation.postOTRMessageV2).toHaveBeenCalledTimes(2);
187
+ expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledTimes(2);
126
188
  });
127
189
  it('continues message sending if onClientMismatch returns true', async () => {
128
190
  const [messageService, { apiClient }] = await buildMessageService();
129
- const onClientMismatch = jest.fn().mockReturnValue(true);
130
- const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { missing: { '2.wire.test': { [user2.id]: ['client22'] } } });
191
+ const onClientMismatch = jest.fn().mockReturnValue(Promise.resolve(true));
192
+ const clientMismatch = Object.assign(Object.assign({}, baseClientMismatch), { missing: { [user2.domain]: { [user2.id]: ['client22'] } } });
131
193
  let spyCounter = 0;
132
- jest.spyOn(apiClient.api.conversation, 'postOTRMessageV2').mockImplementation(() => {
194
+ jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
133
195
  spyCounter++;
134
196
  if (spyCounter === 1) {
135
197
  const error = new Error();
@@ -139,23 +201,25 @@ describe('MessageService', () => {
139
201
  };
140
202
  return Promise.reject(error);
141
203
  }
142
- return Promise.resolve(baseMessageSendingStatus);
204
+ return Promise.resolve(baseClientMismatch);
143
205
  });
144
- jest.spyOn(apiClient.api.user, 'postQualifiedMultiPreKeyBundles').mockReturnValue(Promise.resolve({}));
145
- const recipients = generateQualifiedRecipients([user1, user2]);
146
- await messageService.sendFederatedMessage('senderclientid', recipients, new Uint8Array(), {
206
+ jest
207
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
208
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
209
+ const recipients = generateRecipients([user1, user2]);
210
+ await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
147
211
  reportMissing: true,
148
212
  onClientMismatch,
149
213
  conversationId: { id: 'convid', domain: '' },
150
214
  });
151
- expect(apiClient.api.conversation.postOTRMessageV2).toHaveBeenCalledTimes(2);
215
+ expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledTimes(2);
152
216
  expect(onClientMismatch).toHaveBeenCalledWith(clientMismatch);
153
217
  });
154
218
  it('stops message sending if onClientMismatch returns false', async () => {
155
219
  const [messageService, { apiClient }] = await buildMessageService();
156
- const onClientMismatch = jest.fn().mockReturnValue(false);
157
- const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { missing: { '2.wire.test': { [user2.id]: ['client22'] } } });
158
- jest.spyOn(apiClient.api.conversation, 'postOTRMessageV2').mockImplementation(() => {
220
+ const onClientMismatch = jest.fn().mockReturnValue(Promise.resolve(false));
221
+ const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { missing: { [user2.id]: ['client22'] } });
222
+ jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
159
223
  const error = new Error();
160
224
  error.response = {
161
225
  status: http_status_codes_1.StatusCodes.PRECONDITION_FAILED,
@@ -163,105 +227,24 @@ describe('MessageService', () => {
163
227
  };
164
228
  return Promise.reject(error);
165
229
  });
166
- jest.spyOn(apiClient.api.user, 'postQualifiedMultiPreKeyBundles').mockReturnValue(Promise.resolve({}));
167
- const recipients = generateQualifiedRecipients([user1, user2]);
168
- await messageService.sendFederatedMessage('senderclientid', recipients, new Uint8Array(), {
230
+ jest
231
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
232
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
233
+ const recipients = generateRecipients([user1, user2]);
234
+ await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
169
235
  reportMissing: true,
170
236
  onClientMismatch,
171
237
  conversationId: { id: 'convid', domain: '' },
172
238
  });
173
- expect(apiClient.api.conversation.postOTRMessageV2).toHaveBeenCalledTimes(1);
239
+ expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledTimes(1);
174
240
  expect(onClientMismatch).toHaveBeenCalledWith(clientMismatch);
175
241
  });
176
242
  });
177
- });
178
- describe('sendMessage', () => {
179
- const generateUsers = (userCount, clientsPerUser) => {
180
- return Array.from(Array(userCount)).map((_, i) => ({
181
- id: `user${i}`,
182
- domain: `${i}.domain`,
183
- clients: Array.from(Array(clientsPerUser)).map((_, j) => `client${i}${j}`),
184
- }));
185
- };
186
- const clientId = 'sendingClient';
187
- const conversationId = { id: 'conv1', domain: '' };
188
- const createMessage = (content) => {
189
- const customTextMessage = protocol_messaging_1.GenericMessage.create({
190
- messageId: (0, PayloadHelper_1.getUUID)(),
191
- text: protocol_messaging_1.Text.create({ content }),
192
- });
193
- return protocol_messaging_1.GenericMessage.encode(customTextMessage).finish();
194
- };
195
- it('should send regular to conversation', async () => {
196
- const [messageService, { apiClient }] = await buildMessageService();
197
- const message = 'Lorem ipsum dolor sit amet';
198
- jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockReturnValue(Promise.resolve({}));
199
- await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message), {
200
- conversationId,
201
- });
202
- expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledWith(clientId, conversationId.id, expect.any(Object), false);
203
- });
204
- it('should send protobuf message to conversation', async () => {
205
- const [messageService, { apiClient }] = await buildMessageService();
206
- const message = 'Lorem ipsum dolor sit amet';
207
- jest
208
- .spyOn(apiClient.api.conversation, 'postOTRProtobufMessage')
209
- .mockReturnValue(Promise.resolve({}));
210
- await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message), {
211
- conversationId,
212
- sendAsProtobuf: true,
213
- });
214
- expect(apiClient.api.conversation.postOTRProtobufMessage).toHaveBeenCalledWith(clientId, conversationId.id, expect.any(Object), false);
215
- });
216
- it('should broadcast regular message if no conversationId is given', async () => {
217
- const [messageService, { apiClient }] = await buildMessageService();
218
- const message = 'Lorem ipsum dolor sit amet';
219
- jest
220
- .spyOn(apiClient.api.broadcast, 'postBroadcastMessage')
221
- .mockReturnValue(Promise.resolve({}));
222
- await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message));
223
- expect(apiClient.api.broadcast.postBroadcastMessage).toHaveBeenCalledWith(clientId, expect.any(Object), false);
224
- });
225
- it('should broadcast protobuf message if no conversationId is given', async () => {
226
- const [messageService, { apiClient }] = await buildMessageService();
227
- const message = 'Lorem ipsum dolor sit amet';
228
- jest
229
- .spyOn(apiClient.api.broadcast, 'postBroadcastProtobufMessage')
230
- .mockReturnValue(Promise.resolve({}));
231
- await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message), {
232
- sendAsProtobuf: true,
233
- });
234
- expect(apiClient.api.broadcast.postBroadcastProtobufMessage).toHaveBeenCalledWith(clientId, expect.any(Object), false);
235
- });
236
- it('should not send as external if payload small', async () => {
237
- const [messageService, { apiClient }] = await buildMessageService();
238
- const message = 'Lorem ipsum dolor sit amet';
239
- jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockReturnValue(Promise.resolve({}));
240
- await messageService.sendMessage(clientId, generateRecipients(generateUsers(3, 3)), createMessage(message), {
241
- conversationId,
242
- });
243
- expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledWith(clientId, conversationId.id, expect.objectContaining({ data: undefined }), false);
244
- });
245
- it('should send as external if payload is big', async () => {
246
- const [messageService, { apiClient }] = await buildMessageService();
247
- const longMessage = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Duis autem';
248
- jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockReturnValue(Promise.resolve({}));
249
- await messageService.sendMessage(clientId, generateRecipients(generateUsers(30, 10)), createMessage(longMessage), {
250
- conversationId,
251
- });
252
- expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledWith(clientId, conversationId.id, expect.objectContaining({ data: expect.any(String) }), false);
253
- });
254
243
  describe('client mismatch', () => {
255
- const baseClientMismatch = {
256
- deleted: {},
257
- missing: {},
258
- redundant: {},
259
- time: new Date().toISOString(),
260
- };
261
244
  it('handles client mismatch internally if no onClientMismatch is given', async () => {
262
245
  const [messageService, { apiClient }] = await buildMessageService();
263
246
  let spyCounter = 0;
264
- const clientMismatch = Object.assign(Object.assign({}, baseClientMismatch), { deleted: { [user1.id]: [user1.clients[0]] }, missing: { [user2.id]: ['client22'] } });
247
+ const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { deleted: { [user1.domain]: { [user1.id]: [user1.clients[0]] } }, missing: { '2.wire.test': { [user2.id]: ['client22'] } } });
265
248
  jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
266
249
  spyCounter++;
267
250
  if (spyCounter === 1) {
@@ -272,10 +255,12 @@ describe('MessageService', () => {
272
255
  };
273
256
  return Promise.reject(error);
274
257
  }
275
- return Promise.resolve(baseClientMismatch);
258
+ return Promise.resolve(baseMessageSendingStatus);
276
259
  });
277
- jest.spyOn(apiClient.api.user, 'postMultiPreKeyBundles').mockReturnValue(Promise.resolve({}));
278
- const recipients = generateRecipients([user1, user2]);
260
+ jest
261
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
262
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
263
+ const recipients = generateQualifiedRecipients([user1, user2]);
279
264
  await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
280
265
  reportMissing: true,
281
266
  conversationId: { id: 'convid', domain: '' },
@@ -284,8 +269,8 @@ describe('MessageService', () => {
284
269
  });
285
270
  it('continues message sending if onClientMismatch returns true', async () => {
286
271
  const [messageService, { apiClient }] = await buildMessageService();
287
- const onClientMismatch = jest.fn().mockReturnValue(Promise.resolve(true));
288
- const clientMismatch = Object.assign(Object.assign({}, baseClientMismatch), { missing: { [user2.id]: ['client22'] } });
272
+ const onClientMismatch = jest.fn().mockReturnValue(true);
273
+ const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { missing: { '2.wire.test': { [user2.id]: ['client22'] } } });
289
274
  let spyCounter = 0;
290
275
  jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
291
276
  spyCounter++;
@@ -297,10 +282,12 @@ describe('MessageService', () => {
297
282
  };
298
283
  return Promise.reject(error);
299
284
  }
300
- return Promise.resolve(baseClientMismatch);
285
+ return Promise.resolve(baseMessageSendingStatus);
301
286
  });
302
- jest.spyOn(apiClient.api.user, 'postMultiPreKeyBundles').mockReturnValue(Promise.resolve({}));
303
- const recipients = generateRecipients([user1, user2]);
287
+ jest
288
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
289
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
290
+ const recipients = generateQualifiedRecipients([user1, user2]);
304
291
  await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
305
292
  reportMissing: true,
306
293
  onClientMismatch,
@@ -309,10 +296,31 @@ describe('MessageService', () => {
309
296
  expect(apiClient.api.conversation.postOTRMessage).toHaveBeenCalledTimes(2);
310
297
  expect(onClientMismatch).toHaveBeenCalledWith(clientMismatch);
311
298
  });
299
+ it('warns the consumer if they try to send a message to a deleted client', async () => {
300
+ const [messageService, { apiClient, proteusService }] = await buildMessageService();
301
+ const onClientMismatch = jest.fn().mockReturnValue(true);
302
+ const recipients = generateQualifiedRecipients([user1, user2]);
303
+ const unknowns = {
304
+ [user1.domain]: {
305
+ [user1.id]: [user1.clients[0]],
306
+ },
307
+ };
308
+ jest.spyOn(proteusService, 'encrypt').mockResolvedValue({
309
+ payloads: {},
310
+ unknowns,
311
+ });
312
+ jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockResolvedValue(baseMessageSendingStatus);
313
+ const result = await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
314
+ reportMissing: true,
315
+ onClientMismatch,
316
+ conversationId: { id: 'convid', domain: '' },
317
+ });
318
+ expect(result.deleted).toEqual(unknowns);
319
+ });
312
320
  it('stops message sending if onClientMismatch returns false', async () => {
313
321
  const [messageService, { apiClient }] = await buildMessageService();
314
- const onClientMismatch = jest.fn().mockReturnValue(Promise.resolve(false));
315
- const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { missing: { [user2.id]: ['client22'] } });
322
+ const onClientMismatch = jest.fn().mockReturnValue(false);
323
+ const clientMismatch = Object.assign(Object.assign({}, baseMessageSendingStatus), { missing: { '2.wire.test': { [user2.id]: ['client22'] } } });
316
324
  jest.spyOn(apiClient.api.conversation, 'postOTRMessage').mockImplementation(() => {
317
325
  const error = new Error();
318
326
  error.response = {
@@ -321,8 +329,10 @@ describe('MessageService', () => {
321
329
  };
322
330
  return Promise.reject(error);
323
331
  });
324
- jest.spyOn(apiClient.api.user, 'postMultiPreKeyBundles').mockReturnValue(Promise.resolve({}));
325
- const recipients = generateRecipients([user1, user2]);
332
+ jest
333
+ .spyOn(apiClient.api.user, 'postMultiPreKeyBundles')
334
+ .mockReturnValue(Promise.resolve({ qualified_user_client_prekeys: {} }));
335
+ const recipients = generateQualifiedRecipients([user1, user2]);
326
336
  await messageService.sendMessage('senderclientid', recipients, new Uint8Array(), {
327
337
  reportMissing: true,
328
338
  onClientMismatch,
@@ -64,4 +64,4 @@ var PayloadBundleType;
64
64
  PayloadBundleType["USER_LEGAL_HOLD_REQUEST"] = "PayloadBundleType.USER_LEGAL_HOLD_REQUEST";
65
65
  PayloadBundleType["USER_PROPERTIES_SET"] = "PayloadBundleType.USER_PROPERTIES_SET";
66
66
  PayloadBundleType["USER_UPDATE"] = "PayloadBundleType.USER_UPDATE";
67
- })(PayloadBundleType = exports.PayloadBundleType || (exports.PayloadBundleType = {}));
67
+ })(PayloadBundleType || (exports.PayloadBundleType = PayloadBundleType = {}));
@@ -1,23 +1,27 @@
1
1
  import { QualifiedId } from '@wireapp/api-client/lib/user';
2
- type UserClientsContainer<T> = {
2
+ type UserMap<T> = {
3
3
  [userId: string]: T;
4
4
  };
5
- type QualifiedUserClientsContainer<T> = {
6
- [domain: string]: UserClientsContainer<T>;
5
+ type QualifiedUserMap<T> = {
6
+ [domain: string]: UserMap<T>;
7
7
  };
8
- export declare function flattenUserClients<T>(userClients: UserClientsContainer<T>, domain?: string): {
9
- data: T;
10
- userId: QualifiedId;
11
- }[];
12
8
  /**
13
- * Will flatten a container of users=>clients infos to an array
9
+ * Will flatten a container of domain=>users=>anything infos to an array
14
10
  *
15
- * @param userClients The UserClients (qualified or not) to flatten
11
+ * @param userMap The qualified UserMap to flatten
16
12
  * @return An array containing the qualified user Ids and the clients info
17
13
  */
18
- export declare function flattenQualifiedUserClients<T = unknown>(userClients: QualifiedUserClientsContainer<T>): {
14
+ export declare function flattenUserMap<T = unknown>(userMap: QualifiedUserMap<T>): {
19
15
  data: T;
20
16
  userId: QualifiedId;
21
17
  }[];
18
+ /**
19
+ * Will convert a list of qualified users to a UserMap
20
+ * @param users the list of users to convert
21
+ */
22
+ export declare function nestUsersList<T = unknown>(users: {
23
+ data: T;
24
+ userId: QualifiedId;
25
+ }[]): QualifiedUserMap<T>;
22
26
  export {};
23
27
  //# sourceMappingURL=UserClientsUtil.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UserClientsUtil.d.ts","sourceRoot":"","sources":["../../../src/conversation/message/UserClientsUtil.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAEzD,KAAK,oBAAoB,CAAC,CAAC,IAAI;IAAC,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAA;CAAC,CAAC;AACrD,KAAK,6BAA6B,CAAC,CAAC,IAAI;IAAC,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAAA;CAAC,CAAC;AAEpF,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC,EACpC,MAAM,GAAE,MAAW,GAClB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAC,EAAE,CAElC;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,GAAG,OAAO,EACrD,WAAW,EAAE,6BAA6B,CAAC,CAAC,CAAC,GAC5C;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAC,EAAE,CAIlC"}
1
+ {"version":3,"file":"UserClientsUtil.d.ts","sourceRoot":"","sources":["../../../src/conversation/message/UserClientsUtil.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,WAAW,EAAC,MAAM,8BAA8B,CAAC;AAEzD,KAAK,OAAO,CAAC,CAAC,IAAI;IAAC,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAA;CAAC,CAAC;AACxC,KAAK,gBAAgB,CAAC,CAAC,IAAI;IAAC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;CAAC,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAC,EAAE,CAI1G;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAC,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAQvG"}
@@ -18,20 +18,30 @@
18
18
  *
19
19
  */
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.flattenQualifiedUserClients = exports.flattenUserClients = void 0;
22
- function flattenUserClients(userClients, domain = '') {
23
- return Object.entries(userClients).map(([id, data]) => ({ data, userId: { domain, id } }));
24
- }
25
- exports.flattenUserClients = flattenUserClients;
21
+ exports.nestUsersList = exports.flattenUserMap = void 0;
26
22
  /**
27
- * Will flatten a container of users=>clients infos to an array
23
+ * Will flatten a container of domain=>users=>anything infos to an array
28
24
  *
29
- * @param userClients The UserClients (qualified or not) to flatten
25
+ * @param userMap The qualified UserMap to flatten
30
26
  * @return An array containing the qualified user Ids and the clients info
31
27
  */
32
- function flattenQualifiedUserClients(userClients) {
33
- return Object.entries(userClients).reduce((ids, [domain, userClients]) => {
34
- return [...ids, ...flattenUserClients(userClients, domain)];
28
+ function flattenUserMap(userMap) {
29
+ return Object.entries(userMap).reduce((ids, [domain, userClients]) => {
30
+ return [...ids, ...Object.entries(userClients).map(([id, data]) => ({ data, userId: { domain, id } }))];
35
31
  }, []);
36
32
  }
37
- exports.flattenQualifiedUserClients = flattenQualifiedUserClients;
33
+ exports.flattenUserMap = flattenUserMap;
34
+ /**
35
+ * Will convert a list of qualified users to a UserMap
36
+ * @param users the list of users to convert
37
+ */
38
+ function nestUsersList(users) {
39
+ return users.reduce((users, { data, userId: { domain, id } }) => {
40
+ if (!users[domain]) {
41
+ users[domain] = {};
42
+ }
43
+ users[domain][id] = data;
44
+ return users;
45
+ }, {});
46
+ }
47
+ exports.nestUsersList = nestUsersList;
@@ -27,15 +27,11 @@ describe('userClientsUtils', () => {
27
27
  { data: ['client11'], userId: { domain: 'domain1', id: 'user2' } },
28
28
  { data: ['client1', 'client2'], userId: { domain: 'domain2', id: 'user3' } },
29
29
  ];
30
- expect((0, UserClientsUtil_1.flattenQualifiedUserClients)(payload)).toEqual(expected);
30
+ expect((0, UserClientsUtil_1.flattenUserMap)(payload)).toEqual(expected);
31
31
  });
32
- it('extracts user and data info from non-qualified payload', () => {
33
- const payload = { user1: ['client1'], user2: ['client11'], user3: ['client1', 'client2'] };
34
- const expected = [
35
- { data: ['client1'], userId: { domain: '', id: 'user1' } },
36
- { data: ['client11'], userId: { domain: '', id: 'user2' } },
37
- { data: ['client1', 'client2'], userId: { domain: '', id: 'user3' } },
38
- ];
39
- expect((0, UserClientsUtil_1.flattenUserClients)(payload)).toEqual(expected);
32
+ it('nest and flatten are inverse operations', () => {
33
+ const payload = { domain1: { user1: ['client1'], user2: ['client11'] }, domain2: { user3: ['client1', 'client2'] } };
34
+ const result = (0, UserClientsUtil_1.nestUsersList)((0, UserClientsUtil_1.flattenUserMap)(payload));
35
+ expect(result).toEqual(payload);
40
36
  });
41
37
  });
@@ -1,5 +1,5 @@
1
1
  import { EventHandlerParams } from './EventHandler.types';
2
2
  import { EventHandlerResult } from '../../common.types';
3
- declare const handleBackendEvent: (params: EventHandlerParams, onEpochChanged: (groupId: string) => void) => EventHandlerResult;
3
+ declare const handleBackendEvent: (params: EventHandlerParams, onEpochChanged: (groupId: string) => Promise<void>) => EventHandlerResult;
4
4
  export { handleBackendEvent };
5
5
  //# sourceMappingURL=EventHandler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EventHandler.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/mls/EventHandler/EventHandler.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAEtD,QAAA,MAAM,kBAAkB,WACd,kBAAkB,4BACA,MAAM,KAAK,IAAI,uBAS1C,CAAC;AAEF,OAAO,EAAC,kBAAkB,EAAC,CAAC"}
1
+ {"version":3,"file":"EventHandler.d.ts","sourceRoot":"","sources":["../../../../src/messagingProtocols/mls/EventHandler/EventHandler.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EAAC,kBAAkB,EAAC,MAAM,oBAAoB,CAAC;AAEtD,QAAA,MAAM,kBAAkB,WACd,kBAAkB,4BACA,MAAM,KAAK,QAAQ,IAAI,CAAC,uBASnD,CAAC;AAEF,OAAO,EAAC,kBAAkB,EAAC,CAAC"}
@@ -5,6 +5,6 @@ declare const isMLSMessageAddEvent: (event: BackendEvent) => event is Conversati
5
5
  interface HandleMLSMessageAddParams extends EventHandlerParams {
6
6
  event: ConversationMLSMessageAddEvent;
7
7
  }
8
- declare const handleMLSMessageAdd: ({ mlsService, event }: HandleMLSMessageAddParams, onEpochChanged: (groupId: string) => void) => EventHandlerResult;
8
+ declare const handleMLSMessageAdd: ({ mlsService, event }: HandleMLSMessageAddParams, onEpochChanged: (groupId: string) => Promise<void>) => EventHandlerResult;
9
9
  export { isMLSMessageAddEvent, handleMLSMessageAdd };
10
10
  //# sourceMappingURL=messageAdd.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messageAdd.d.ts","sourceRoot":"","sources":["../../../../../../src/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,YAAY,EAAE,8BAA8B,EAAqB,MAAM,+BAA+B,CAAC;AAK/G,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAE5D,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAE5D,QAAA,MAAM,oBAAoB,UAAW,YAAY,4CACE,CAAC;AAEpD,UAAU,yBAA0B,SAAQ,kBAAkB;IAC5D,KAAK,EAAE,8BAA8B,CAAC;CACvC;AACD,QAAA,MAAM,mBAAmB,0BACF,yBAAyB,4BACpB,MAAM,KAAK,IAAI,uBAuC1C,CAAC;AAEF,OAAO,EAAC,oBAAoB,EAAE,mBAAmB,EAAC,CAAC"}
1
+ {"version":3,"file":"messageAdd.d.ts","sourceRoot":"","sources":["../../../../../../src/messagingProtocols/mls/EventHandler/events/messageAdd/messageAdd.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,YAAY,EAAE,8BAA8B,EAAqB,MAAM,+BAA+B,CAAC;AAK/G,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAE5D,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAE5D,QAAA,MAAM,oBAAoB,UAAW,YAAY,4CACE,CAAC;AAEpD,UAAU,yBAA0B,SAAQ,kBAAkB;IAC5D,KAAK,EAAE,8BAA8B,CAAC;CACvC;AACD,QAAA,MAAM,mBAAmB,0BACF,yBAAyB,4BACpB,MAAM,KAAK,QAAQ,IAAI,CAAC,uBA+CnD,CAAC;AAEF,OAAO,EAAC,oBAAoB,EAAE,mBAAmB,EAAC,CAAC"}
@@ -28,7 +28,12 @@ exports.isMLSMessageAddEvent = isMLSMessageAddEvent;
28
28
  const handleMLSMessageAdd = async ({ mlsService, event }, onEpochChanged) => {
29
29
  var _a;
30
30
  const encryptedData = bazinga64_1.Decoder.fromBase64(event.data).asBytes;
31
- const groupId = await mlsService.getGroupIdFromConversationId((_a = event.qualified_conversation) !== null && _a !== void 0 ? _a : { id: event.conversation, domain: '' }, event.subconv);
31
+ const qualifiedConversationId = (_a = event.qualified_conversation) !== null && _a !== void 0 ? _a : { id: event.conversation, domain: '' };
32
+ const groupId = await mlsService.getGroupIdFromConversationId(qualifiedConversationId, event.subconv);
33
+ // We should not receive a message for a group the client is not aware of
34
+ if (!groupId) {
35
+ throw new Error(`Could not find a group_id for conversation ${qualifiedConversationId.id}@${qualifiedConversationId.domain}`);
36
+ }
32
37
  const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
33
38
  const { proposals, commitDelay, message, senderClientId: encodedSenderClientId, hasEpochChanged, } = await mlsService.decryptMessage(groupIdBytes, encryptedData);
34
39
  if (encodedSenderClientId) {
@@ -47,7 +52,7 @@ const handleMLSMessageAdd = async ({ mlsService, event }, onEpochChanged) => {
47
52
  });
48
53
  }
49
54
  if (hasEpochChanged) {
50
- onEpochChanged(groupId);
55
+ await onEpochChanged(groupId);
51
56
  }
52
57
  return message ? { event, decryptedData: protocol_messaging_1.GenericMessage.decode(message) } : undefined;
53
58
  };
@@ -1 +1 @@
1
- {"version":3,"file":"welcomeMessage.d.ts","sourceRoot":"","sources":["../../../../../../src/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,YAAY,EAAE,2BAA2B,EAAqB,MAAM,+BAA+B,CAAC;AAG5G,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAE5D,QAAA,MAAM,qBAAqB,UAAW,YAAY,yCACK,CAAC;AAExD,UAAU,0BAA2B,SAAQ,kBAAkB;IAC7D,KAAK,EAAE,2BAA2B,CAAC;CACpC;AACD,QAAA,MAAM,oBAAoB,0BAA+B,0BAA0B,uBASlF,CAAC;AAEF,OAAO,EAAC,qBAAqB,EAAE,oBAAoB,EAAC,CAAC"}
1
+ {"version":3,"file":"welcomeMessage.d.ts","sourceRoot":"","sources":["../../../../../../src/messagingProtocols/mls/EventHandler/events/welcomeMessage/welcomeMessage.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAC,YAAY,EAAE,2BAA2B,EAAqB,MAAM,+BAA+B,CAAC;AAG5G,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAE5D,QAAA,MAAM,qBAAqB,UAAW,YAAY,yCACK,CAAC;AAExD,UAAU,0BAA2B,SAAQ,kBAAkB;IAC7D,KAAK,EAAE,2BAA2B,CAAC;CACpC;AACD,QAAA,MAAM,oBAAoB,0BAA+B,0BAA0B,uBAYlF,CAAC;AAEF,OAAO,EAAC,qBAAqB,EAAE,oBAAoB,EAAC,CAAC"}
@@ -29,6 +29,8 @@ const handleWelcomeMessage = async ({ mlsService, event }) => {
29
29
  const newGroupId = await mlsService.processWelcomeMessage(data);
30
30
  const groupIdStr = bazinga64_1.Encoder.toBase64(newGroupId).asString;
31
31
  // The groupId can then be sent back to the consumer
32
+ // After we were added to the group we need to schedule a periodic key material renewal
33
+ mlsService.scheduleKeyMaterialRenewal(groupIdStr);
32
34
  return {
33
35
  event: Object.assign(Object.assign({}, event), { data: groupIdStr }),
34
36
  };
@@ -36,6 +36,7 @@ const mockParams = {
36
36
  source: {},
37
37
  mlsService: {
38
38
  processWelcomeMessage: jest.fn().mockResolvedValue('conversationId'),
39
+ scheduleKeyMaterialRenewal: jest.fn(),
39
40
  },
40
41
  dryRun: false,
41
42
  };
@@ -55,9 +56,10 @@ describe('MLS welcomeMessage eventHandler', () => {
55
56
  });
56
57
  });
57
58
  describe('handleWelcomeMessage', () => {
58
- it('calls processWelcomeMessage', async () => {
59
+ it('calls processWelcomeMessage and schedules periodic key material updates', async () => {
59
60
  await (0, welcomeMessage_1.handleWelcomeMessage)(mockParams);
60
61
  expect(mockParams.mlsService.processWelcomeMessage).toHaveBeenCalled();
62
+ expect(mockParams.mlsService.scheduleKeyMaterialRenewal).toHaveBeenCalled();
61
63
  });
62
64
  it('returns a eventHandlerResult', async () => {
63
65
  const eventHandlerResult = await (0, welcomeMessage_1.handleWelcomeMessage)(mockParams);