@wireapp/core 31.1.3 → 31.1.4

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 (227) hide show
  1. package/package.json +9 -8
  2. package/src/main/Account.d.ts +214 -0
  3. package/src/main/Account.js +463 -0
  4. package/src/main/CoreError.d.ts +9 -0
  5. package/src/main/CoreError.js +26 -0
  6. package/src/main/account/AccountService.d.ts +7 -0
  7. package/src/main/account/AccountService.js +33 -0
  8. package/src/main/account/AccountService.js.map +1 -0
  9. package/src/main/account/index.d.ts +1 -0
  10. package/src/main/account/index.js +36 -0
  11. package/src/main/account/index.js.map +1 -0
  12. package/src/main/auth/LoginSanitizer.d.ts +5 -0
  13. package/src/main/auth/LoginSanitizer.js +41 -0
  14. package/src/main/auth/index.d.ts +1 -0
  15. package/src/main/auth/index.js +36 -0
  16. package/src/main/broadcast/AvailabilityType.d.ts +2 -0
  17. package/src/main/broadcast/AvailabilityType.js +21 -0
  18. package/src/main/broadcast/BroadcastService.d.ts +24 -0
  19. package/src/main/broadcast/BroadcastService.js +74 -0
  20. package/src/main/broadcast/index.d.ts +2 -0
  21. package/src/main/broadcast/index.js +37 -0
  22. package/src/main/client/ClientBackendRepository.d.ts +11 -0
  23. package/src/main/client/ClientBackendRepository.js +43 -0
  24. package/src/main/client/ClientDatabaseRepository.d.ts +27 -0
  25. package/src/main/client/ClientDatabaseRepository.js +85 -0
  26. package/src/main/client/ClientInfo.d.ts +8 -0
  27. package/src/main/client/ClientInfo.js +21 -0
  28. package/src/main/client/ClientService.d.ts +40 -0
  29. package/src/main/client/ClientService.js +103 -0
  30. package/src/main/client/index.d.ts +4 -0
  31. package/src/main/client/index.js +39 -0
  32. package/src/main/connection/ConnectionService.d.ts +11 -0
  33. package/src/main/connection/ConnectionService.js +45 -0
  34. package/src/main/connection/index.d.ts +1 -0
  35. package/src/main/connection/index.js +36 -0
  36. package/src/main/conversation/AbortReason.d.ts +2 -0
  37. package/src/main/conversation/AbortReason.js +21 -0
  38. package/src/main/conversation/AssetService/AssetService.d.ts +62 -0
  39. package/src/main/conversation/AssetService/AssetService.js +88 -0
  40. package/src/main/conversation/AssetService/index.d.ts +1 -0
  41. package/src/main/conversation/AssetService/index.js +36 -0
  42. package/src/main/conversation/AssetTransferState.d.ts +4 -0
  43. package/src/main/conversation/AssetTransferState.js +27 -0
  44. package/src/main/conversation/ClientActionType.d.ts +1 -0
  45. package/src/main/conversation/ClientActionType.js +24 -0
  46. package/src/main/conversation/ConversationMapper/ConversationMapper.d.ts +6 -0
  47. package/src/main/conversation/ConversationMapper/ConversationMapper.js +57 -0
  48. package/src/main/conversation/ConversationMapper/index.d.ts +1 -0
  49. package/src/main/conversation/ConversationMapper/index.js +36 -0
  50. package/src/main/conversation/ConversationService/ConversationService.d.ts +149 -0
  51. package/src/main/conversation/ConversationService/ConversationService.js +584 -0
  52. package/src/main/conversation/ConversationService/ConversationService.types.d.ts +110 -0
  53. package/src/main/conversation/ConversationService/ConversationService.types.js +28 -0
  54. package/src/main/conversation/ConversationService/index.d.ts +2 -0
  55. package/src/main/conversation/ConversationService/index.js +37 -0
  56. package/src/main/conversation/ConversationService/messageGenerator.d.ts +9 -0
  57. package/src/main/conversation/ConversationService/messageGenerator.js +313 -0
  58. package/src/main/conversation/GenericMessageType.d.ts +25 -0
  59. package/src/main/conversation/GenericMessageType.js +49 -0
  60. package/src/main/conversation/MessageTimer/MessageTimer.d.ts +10 -0
  61. package/src/main/conversation/MessageTimer/MessageTimer.js +54 -0
  62. package/src/main/conversation/MessageTimer/index.d.ts +1 -0
  63. package/src/main/conversation/MessageTimer/index.js +36 -0
  64. package/src/main/conversation/ReactionType.d.ts +4 -0
  65. package/src/main/conversation/ReactionType.js +27 -0
  66. package/src/main/conversation/content/AssetContent.d.ts +42 -0
  67. package/src/main/conversation/content/AssetContent.js +21 -0
  68. package/src/main/conversation/content/ButtonActionConfirmationContent.d.ts +2 -0
  69. package/src/main/conversation/content/ButtonActionConfirmationContent.js +21 -0
  70. package/src/main/conversation/content/ButtonActionContent.d.ts +2 -0
  71. package/src/main/conversation/content/ButtonActionContent.js +21 -0
  72. package/src/main/conversation/content/CallingContent.d.ts +1 -0
  73. package/src/main/conversation/content/CallingContent.js +21 -0
  74. package/src/main/conversation/content/ClearedContent.d.ts +2 -0
  75. package/src/main/conversation/content/ClearedContent.js +21 -0
  76. package/src/main/conversation/content/ClientActionContent.d.ts +2 -0
  77. package/src/main/conversation/content/ClientActionContent.js +21 -0
  78. package/src/main/conversation/content/ClientAddContent.d.ts +4 -0
  79. package/src/main/conversation/content/ClientAddContent.js +21 -0
  80. package/src/main/conversation/content/ClientRemoveContent.d.ts +6 -0
  81. package/src/main/conversation/content/ClientRemoveContent.js +21 -0
  82. package/src/main/conversation/content/CompositeContent.d.ts +2 -0
  83. package/src/main/conversation/content/CompositeContent.js +21 -0
  84. package/src/main/conversation/content/ConfirmationContent.d.ts +2 -0
  85. package/src/main/conversation/content/ConfirmationContent.js +21 -0
  86. package/src/main/conversation/content/ContentType.d.ts +21 -0
  87. package/src/main/conversation/content/ContentType.js +94 -0
  88. package/src/main/conversation/content/ConversationContent.d.ts +3 -0
  89. package/src/main/conversation/content/ConversationContent.js +21 -0
  90. package/src/main/conversation/content/DeletedContent.d.ts +2 -0
  91. package/src/main/conversation/content/DeletedContent.js +21 -0
  92. package/src/main/conversation/content/EditedTextContent.d.ts +11 -0
  93. package/src/main/conversation/content/EditedTextContent.js +21 -0
  94. package/src/main/conversation/content/FileContent.d.ts +13 -0
  95. package/src/main/conversation/content/FileContent.js +21 -0
  96. package/src/main/conversation/content/HiddenContent.d.ts +2 -0
  97. package/src/main/conversation/content/HiddenContent.js +21 -0
  98. package/src/main/conversation/content/ImageContent.d.ts +7 -0
  99. package/src/main/conversation/content/ImageContent.js +21 -0
  100. package/src/main/conversation/content/KnockContent.d.ts +2 -0
  101. package/src/main/conversation/content/KnockContent.js +21 -0
  102. package/src/main/conversation/content/LinkPreviewContent.d.ts +10 -0
  103. package/src/main/conversation/content/LinkPreviewContent.js +21 -0
  104. package/src/main/conversation/content/LocationContent.d.ts +9 -0
  105. package/src/main/conversation/content/LocationContent.js +21 -0
  106. package/src/main/conversation/content/MentionContent.d.ts +2 -0
  107. package/src/main/conversation/content/MentionContent.js +21 -0
  108. package/src/main/conversation/content/QuoteContent.d.ts +7 -0
  109. package/src/main/conversation/content/QuoteContent.js +21 -0
  110. package/src/main/conversation/content/ReactionContent.d.ts +7 -0
  111. package/src/main/conversation/content/ReactionContent.js +21 -0
  112. package/src/main/conversation/content/TextContent.d.ts +9 -0
  113. package/src/main/conversation/content/TextContent.js +21 -0
  114. package/src/main/conversation/content/TweetContent.d.ts +2 -0
  115. package/src/main/conversation/content/TweetContent.js +21 -0
  116. package/src/main/conversation/content/index.d.ts +28 -0
  117. package/src/main/conversation/content/index.js +76 -0
  118. package/src/main/conversation/index.d.ts +9 -0
  119. package/src/main/conversation/index.js +44 -0
  120. package/src/main/conversation/message/CompositeContentBuilder.d.ts +14 -0
  121. package/src/main/conversation/message/CompositeContentBuilder.js +54 -0
  122. package/src/main/conversation/message/Message.d.ts +4 -0
  123. package/src/main/conversation/message/Message.js +21 -0
  124. package/src/main/conversation/message/MessageBuilder.d.ts +96 -0
  125. package/src/main/conversation/message/MessageBuilder.js +125 -0
  126. package/src/main/conversation/message/MessageService.d.ts +67 -0
  127. package/src/main/conversation/message/MessageService.js +293 -0
  128. package/src/main/conversation/message/MessageToProtoMapper.d.ts +7 -0
  129. package/src/main/conversation/message/MessageToProtoMapper.js +99 -0
  130. package/src/main/conversation/message/OtrMessage.d.ts +80 -0
  131. package/src/main/conversation/message/OtrMessage.js +21 -0
  132. package/src/main/conversation/message/PayloadBundle.d.ts +76 -0
  133. package/src/main/conversation/message/PayloadBundle.js +81 -0
  134. package/src/main/conversation/message/TeamMessage.d.ts +31 -0
  135. package/src/main/conversation/message/TeamMessage.js +21 -0
  136. package/src/main/conversation/message/TextContentBuilder.d.ts +13 -0
  137. package/src/main/conversation/message/TextContentBuilder.js +75 -0
  138. package/src/main/conversation/message/UserClientsUtil.d.ts +22 -0
  139. package/src/main/conversation/message/UserClientsUtil.js +38 -0
  140. package/src/main/conversation/message/UserMessage.d.ts +43 -0
  141. package/src/main/conversation/message/UserMessage.js +21 -0
  142. package/src/main/conversation/message/messageSender.d.ts +4 -0
  143. package/src/main/conversation/message/messageSender.js +36 -0
  144. package/src/main/cryptography/AssetCryptography/EncryptedAsset.d.ts +11 -0
  145. package/src/main/cryptography/AssetCryptography/EncryptedAsset.js +21 -0
  146. package/src/main/cryptography/AssetCryptography/crypto.browser.d.ts +2 -0
  147. package/src/main/cryptography/AssetCryptography/crypto.browser.js +46 -0
  148. package/src/main/cryptography/AssetCryptography/crypto.node.d.ts +2 -0
  149. package/src/main/cryptography/AssetCryptography/crypto.node.js +72 -0
  150. package/src/main/cryptography/AssetCryptography/index.d.ts +8 -0
  151. package/src/main/cryptography/AssetCryptography/index.js +53 -0
  152. package/src/main/cryptography/AssetCryptography/interfaces.d.ts +9 -0
  153. package/src/main/cryptography/AssetCryptography/interfaces.js +21 -0
  154. package/src/main/cryptography/CryptographyDatabaseRepository.d.ts +16 -0
  155. package/src/main/cryptography/CryptographyDatabaseRepository.js +44 -0
  156. package/src/main/cryptography/CryptographyService.d.ts +52 -0
  157. package/src/main/cryptography/CryptographyService.js +205 -0
  158. package/src/main/cryptography/GenericMessageMapper.d.ts +6 -0
  159. package/src/main/cryptography/GenericMessageMapper.js +160 -0
  160. package/src/main/cryptography/MessageHashService.d.ts +16 -0
  161. package/src/main/cryptography/MessageHashService.js +118 -0
  162. package/src/main/cryptography/SessionPayloadBundle.d.ts +4 -0
  163. package/src/main/cryptography/SessionPayloadBundle.js +21 -0
  164. package/src/main/cryptography/index.d.ts +4 -0
  165. package/src/main/cryptography/index.js +39 -0
  166. package/src/main/giphy/GiphyService.d.ts +9 -0
  167. package/src/main/giphy/GiphyService.js +37 -0
  168. package/src/main/giphy/index.d.ts +1 -0
  169. package/src/main/giphy/index.js +36 -0
  170. package/src/main/index.d.ts +17 -0
  171. package/src/main/index.js +59 -0
  172. package/src/main/linkPreview/LinkPreviewService.d.ts +7 -0
  173. package/src/main/linkPreview/LinkPreviewService.js +52 -0
  174. package/src/main/linkPreview/index.d.ts +1 -0
  175. package/src/main/linkPreview/index.js +36 -0
  176. package/src/main/mls/MLSService/MLSService.d.ts +39 -0
  177. package/src/main/mls/MLSService/MLSService.js +181 -0
  178. package/src/main/mls/index.d.ts +1 -0
  179. package/src/main/mls/index.js +36 -0
  180. package/src/main/mls/keyMaterialUpdatesStore/index.d.ts +1 -0
  181. package/src/main/mls/keyMaterialUpdatesStore/index.js +36 -0
  182. package/src/main/mls/keyMaterialUpdatesStore/keyMaterialUpdatesStore.d.ts +9 -0
  183. package/src/main/mls/keyMaterialUpdatesStore/keyMaterialUpdatesStore.js +51 -0
  184. package/src/main/mls/keyPackagesStatusStore/keyPackagesStatusStore.d.ts +7 -0
  185. package/src/main/mls/keyPackagesStatusStore/keyPackagesStatusStore.js +42 -0
  186. package/src/main/mls/types.d.ts +33 -0
  187. package/src/main/mls/types.js +21 -0
  188. package/src/main/notification/NotificationBackendRepository.d.ts +11 -0
  189. package/src/main/notification/NotificationBackendRepository.js +34 -0
  190. package/src/main/notification/NotificationDatabaseRepository.d.ts +42 -0
  191. package/src/main/notification/NotificationDatabaseRepository.js +97 -0
  192. package/src/main/notification/NotificationService.d.ts +129 -0
  193. package/src/main/notification/NotificationService.js +501 -0
  194. package/src/main/notification/index.d.ts +1 -0
  195. package/src/main/notification/index.js +36 -0
  196. package/src/main/notification/types.d.ts +16 -0
  197. package/src/main/notification/types.js +21 -0
  198. package/src/main/self/SelfService.d.ts +13 -0
  199. package/src/main/self/SelfService.js +55 -0
  200. package/src/main/self/index.d.ts +1 -0
  201. package/src/main/self/index.js +36 -0
  202. package/src/main/team/TeamService.d.ts +15 -0
  203. package/src/main/team/TeamService.js +55 -0
  204. package/src/main/team/index.d.ts +1 -0
  205. package/src/main/team/index.js +36 -0
  206. package/src/main/test/CryptographyHelper.d.ts +4 -0
  207. package/src/main/test/CryptographyHelper.js +69 -0
  208. package/src/main/test/PayloadHelper.d.ts +3 -0
  209. package/src/main/test/PayloadHelper.js +66 -0
  210. package/src/main/user/UserMapper.d.ts +5 -0
  211. package/src/main/user/UserMapper.js +88 -0
  212. package/src/main/user/UserService.d.ts +25 -0
  213. package/src/main/user/UserService.js +81 -0
  214. package/src/main/user/index.d.ts +1 -0
  215. package/src/main/user/index.js +36 -0
  216. package/src/main/util/LowPrecisionTaskScheduler/LowPrecisionTaskScheduler.d.ts +21 -0
  217. package/src/main/util/LowPrecisionTaskScheduler/LowPrecisionTaskScheduler.js +62 -0
  218. package/src/main/util/TaskScheduler/TaskScheduler.d.ts +10 -0
  219. package/src/main/util/TaskScheduler/TaskScheduler.js +70 -0
  220. package/src/main/util/TypePredicateUtil.d.ts +7 -0
  221. package/src/main/util/TypePredicateUtil.js +55 -0
  222. package/src/main/util/encryptedStore.d.ts +45 -0
  223. package/src/main/util/encryptedStore.js +116 -0
  224. package/src/main/util/fullyQualifiedClientIdUtils.d.ts +13 -0
  225. package/src/main/util/fullyQualifiedClientIdUtils.js +42 -0
  226. package/src/main/util/index.d.ts +1 -0
  227. package/src/main/util/index.js +36 -0
@@ -0,0 +1,584 @@
1
+ "use strict";
2
+ /*
3
+ * Wire
4
+ * Copyright (C) 2022 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.ConversationService = void 0;
22
+ const core_crypto_1 = require("@wireapp/core-crypto");
23
+ const conversation_1 = require("@wireapp/api-client/src/conversation");
24
+ const data_1 = require("@wireapp/api-client/src/conversation/data");
25
+ const protocol_messaging_1 = require("@wireapp/protocol-messaging");
26
+ const conversation_2 = require("../../conversation/");
27
+ const AssetCryptography_1 = require("../../cryptography/AssetCryptography");
28
+ const TypePredicateUtil_1 = require("../../util/TypePredicateUtil");
29
+ const MessageBuilder_1 = require("../message/MessageBuilder");
30
+ const MessageService_1 = require("../message/MessageService");
31
+ const ConversationService_types_1 = require("./ConversationService.types");
32
+ const bazinga64_1 = require("bazinga64");
33
+ const fullyQualifiedClientIdUtils_1 = require("../../util/fullyQualifiedClientIdUtils");
34
+ const mls_1 = require("../../mls");
35
+ const messageSender_1 = require("../message/messageSender");
36
+ const messageGenerator_1 = require("./messageGenerator");
37
+ class ConversationService {
38
+ constructor(apiClient, cryptographyService, config, notificationService, mlsService) {
39
+ this.apiClient = apiClient;
40
+ this.config = config;
41
+ this.notificationService = notificationService;
42
+ this.mlsService = mlsService;
43
+ this.messageTimer = new conversation_2.MessageTimer();
44
+ this.messageService = new MessageService_1.MessageService(this.apiClient, cryptographyService);
45
+ }
46
+ async getConversationQualifiedMembers(conversationId) {
47
+ const conversation = await this.apiClient.api.conversation.getConversation(conversationId);
48
+ /*
49
+ * If you are sending a message to a conversation, you have to include
50
+ * yourself in the list of users if you want to sync a message also to your
51
+ * other clients.
52
+ */
53
+ return conversation.members.others
54
+ .filter(member => !!member.qualified_id)
55
+ .map(member => member.qualified_id)
56
+ .concat(conversation.members.self.qualified_id);
57
+ }
58
+ /**
59
+ * Will generate a prekey bundle for specific users.
60
+ * If a QualifiedId array is given the bundle will contain all the clients from those users fetched from the server.
61
+ * If a QualifiedUserClients is provided then only the clients in the payload will be targeted (which could generate a ClientMismatch when sending messages)
62
+ *
63
+ * @param {QualifiedId[]|QualifiedUserClients} userIds - Targeted users.
64
+ * @returns {Promise<QualifiedUserPreKeyBundleMap}
65
+ */
66
+ async getQualifiedPreKeyBundle(userIds) {
67
+ let targets = [];
68
+ if (userIds) {
69
+ if ((0, TypePredicateUtil_1.isQualifiedIdArray)(userIds)) {
70
+ targets = userIds.map(id => ({ id }));
71
+ }
72
+ else {
73
+ targets = Object.entries(userIds).reduce((accumulator, [domain, userClients]) => {
74
+ for (const userId in userClients) {
75
+ accumulator.push({ id: { id: userId, domain }, clients: userClients[userId] });
76
+ }
77
+ return accumulator;
78
+ }, []);
79
+ }
80
+ }
81
+ const preKeys = await Promise.all(targets.map(async ({ id: userId, clients }) => {
82
+ const prekeyBundle = await this.apiClient.api.user.getUserPreKeys(userId);
83
+ // We filter the clients that should not receive the message (if a QualifiedUserClients was given as parameter)
84
+ const userClients = clients
85
+ ? prekeyBundle.clients.filter(client => clients.includes(client.client))
86
+ : prekeyBundle.clients;
87
+ return { user: userId, clients: userClients };
88
+ }));
89
+ return preKeys.reduce((bundleMap, qualifiedPrekey) => {
90
+ var _a, _b, _c;
91
+ bundleMap[_a = qualifiedPrekey.user.domain] || (bundleMap[_a] = {});
92
+ for (const client of qualifiedPrekey.clients) {
93
+ (_b = bundleMap[qualifiedPrekey.user.domain])[_c = qualifiedPrekey.user.id] || (_b[_c] = {});
94
+ bundleMap[qualifiedPrekey.user.domain][qualifiedPrekey.user.id][client.client] = client.prekey;
95
+ }
96
+ return bundleMap;
97
+ }, {});
98
+ }
99
+ async getPreKeyBundleMap(conversationId, userIds) {
100
+ let members = [];
101
+ if (userIds) {
102
+ if ((0, TypePredicateUtil_1.isStringArray)(userIds)) {
103
+ members = userIds;
104
+ }
105
+ else if ((0, TypePredicateUtil_1.isUserClients)(userIds)) {
106
+ members = Object.keys(userIds);
107
+ }
108
+ }
109
+ if (!members.length) {
110
+ const conversation = await this.apiClient.api.conversation.getConversation(conversationId);
111
+ /*
112
+ * If you are sending a message to a conversation, you have to include
113
+ * yourself in the list of users if you want to sync a message also to your
114
+ * other clients.
115
+ */
116
+ members = conversation.members.others.map(member => member.id).concat(conversation.members.self.id);
117
+ }
118
+ const preKeys = await Promise.all(members.map(member => this.apiClient.api.user.getUserPreKeys(member)));
119
+ return preKeys.reduce((bundleMap, bundle) => {
120
+ const userId = bundle.user;
121
+ bundleMap[userId] || (bundleMap[userId] = {});
122
+ for (const client of bundle.clients) {
123
+ bundleMap[userId][client.client] = client.prekey;
124
+ }
125
+ return bundleMap;
126
+ }, {});
127
+ }
128
+ async getSelfConversationId() {
129
+ if (!this.selfConversationId) {
130
+ const { userId } = this.apiClient.context;
131
+ const { qualified_id, id } = await this.apiClient.api.conversation.getConversation(userId);
132
+ const domain = this.config.useQualifiedIds ? qualified_id.domain : '';
133
+ this.selfConversationId = { id, domain };
134
+ }
135
+ return this.selfConversationId;
136
+ }
137
+ async getQualifiedRecipientsForConversation(conversationId, userIds) {
138
+ if ((0, TypePredicateUtil_1.isQualifiedUserClients)(userIds)) {
139
+ return userIds;
140
+ }
141
+ const recipientIds = userIds || (await this.getConversationQualifiedMembers(conversationId));
142
+ return this.getQualifiedPreKeyBundle(recipientIds);
143
+ }
144
+ async getRecipientsForConversation(conversationId, userIds) {
145
+ if ((0, TypePredicateUtil_1.isUserClients)(userIds)) {
146
+ return userIds;
147
+ }
148
+ return this.getPreKeyBundleMap(conversationId, userIds);
149
+ }
150
+ /**
151
+ * Sends a message to a conversation
152
+ *
153
+ * @param sendingClientId The clientId from which the message is sent
154
+ * @param conversationId The conversation in which to send the message
155
+ * @param genericMessage The payload of the message to send
156
+ * @return Resolves with the message sending status from backend
157
+ */
158
+ async sendGenericMessage(sendingClientId, conversationId, genericMessage, { conversationDomain, userIds, nativePush, sendAsProtobuf, onClientMismatch, targetMode = ConversationService_types_1.MessageTargetMode.NONE, } = {}) {
159
+ const plainText = protocol_messaging_1.GenericMessage.encode(genericMessage).finish();
160
+ if (targetMode !== ConversationService_types_1.MessageTargetMode.NONE && !userIds) {
161
+ throw new Error('Cannot send targetted message when no userIds are given');
162
+ }
163
+ if (conversationDomain && this.config.useQualifiedIds) {
164
+ if ((0, TypePredicateUtil_1.isStringArray)(userIds) || (0, TypePredicateUtil_1.isUserClients)(userIds)) {
165
+ throw new Error('Invalid userIds option for sending to federated backend');
166
+ }
167
+ const recipients = await this.getQualifiedRecipientsForConversation({ id: conversationId, domain: conversationDomain }, userIds);
168
+ let reportMissing;
169
+ if (targetMode === ConversationService_types_1.MessageTargetMode.NONE) {
170
+ reportMissing = (0, TypePredicateUtil_1.isQualifiedUserClients)(userIds); // we want to check mismatch in case the consumer gave an exact list of users/devices
171
+ }
172
+ else if (targetMode === ConversationService_types_1.MessageTargetMode.USERS) {
173
+ reportMissing = this.extractQualifiedUserIds(userIds);
174
+ }
175
+ else {
176
+ // in case the message is fully targetted at user/client pairs, we do not want to report the missing clients or users at all
177
+ reportMissing = false;
178
+ }
179
+ return this.messageService.sendFederatedMessage(sendingClientId, recipients, plainText, {
180
+ conversationId: { id: conversationId, domain: conversationDomain },
181
+ nativePush,
182
+ reportMissing,
183
+ onClientMismatch: mismatch => onClientMismatch === null || onClientMismatch === void 0 ? void 0 : onClientMismatch(mismatch, false),
184
+ });
185
+ }
186
+ if ((0, TypePredicateUtil_1.isQualifiedIdArray)(userIds) || (0, TypePredicateUtil_1.isQualifiedUserClients)(userIds)) {
187
+ throw new Error('Invalid userIds option for sending');
188
+ }
189
+ const recipients = await this.getRecipientsForConversation(conversationId, userIds);
190
+ let reportMissing;
191
+ if (targetMode === ConversationService_types_1.MessageTargetMode.NONE) {
192
+ reportMissing = (0, TypePredicateUtil_1.isUserClients)(userIds); // we want to check mismatch in case the consumer gave an exact list of users/devices
193
+ }
194
+ else if (targetMode === ConversationService_types_1.MessageTargetMode.USERS) {
195
+ reportMissing = this.extractUserIds(userIds);
196
+ }
197
+ else {
198
+ // in case the message is fully targetted at user/client pairs, we do not want to report the missing clients or users at all
199
+ reportMissing = false;
200
+ }
201
+ return this.messageService.sendMessage(sendingClientId, recipients, plainText, {
202
+ conversationId,
203
+ sendAsProtobuf,
204
+ nativePush,
205
+ reportMissing,
206
+ onClientMismatch: mistmatch => onClientMismatch === null || onClientMismatch === void 0 ? void 0 : onClientMismatch(mistmatch, false),
207
+ });
208
+ }
209
+ extractUserIds(userIds) {
210
+ if ((0, TypePredicateUtil_1.isUserClients)(userIds)) {
211
+ return Object.keys(userIds);
212
+ }
213
+ return userIds;
214
+ }
215
+ extractQualifiedUserIds(userIds) {
216
+ if ((0, TypePredicateUtil_1.isQualifiedUserClients)(userIds)) {
217
+ return Object.entries(userIds).reduce((ids, [domain, userClients]) => {
218
+ return ids.concat(Object.keys(userClients).map(userId => ({ domain, id: userId })));
219
+ }, []);
220
+ }
221
+ return userIds;
222
+ }
223
+ async clearConversation(conversationId, timestamp = new Date(), messageId = MessageBuilder_1.MessageBuilder.createId(), sendAsProtobuf) {
224
+ if (timestamp instanceof Date) {
225
+ timestamp = timestamp.getTime();
226
+ }
227
+ const content = {
228
+ clearedTimestamp: timestamp,
229
+ conversationId,
230
+ };
231
+ const clearedMessage = protocol_messaging_1.Cleared.create(content);
232
+ const genericMessage = protocol_messaging_1.GenericMessage.create({
233
+ [conversation_2.GenericMessageType.CLEARED]: clearedMessage,
234
+ messageId,
235
+ });
236
+ const { id: selfConversationId, domain } = await this.getSelfConversationId();
237
+ await this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, {
238
+ conversationDomain: domain,
239
+ sendAsProtobuf,
240
+ });
241
+ return {
242
+ content,
243
+ conversation: conversationId,
244
+ from: this.apiClient.context.userId,
245
+ id: messageId,
246
+ messageTimer: 0,
247
+ source: conversation_2.PayloadBundleSource.LOCAL,
248
+ state: conversation_2.PayloadBundleState.OUTGOING_SENT,
249
+ timestamp: Date.now(),
250
+ type: conversation_2.PayloadBundleType.CONVERSATION_CLEAR,
251
+ };
252
+ }
253
+ /**
254
+ * Sends a LastRead message to the current user's self conversation.
255
+ * This will allow all the user's devices to compute which messages are unread
256
+ *
257
+ * @param conversationId The conversation which has been read
258
+ * @param lastReadTimestamp The timestamp at which the conversation was read
259
+ * @param sendingOptions?
260
+ * @return Resolves when the message has been sent
261
+ */
262
+ async sendLastRead(conversationId, lastReadTimestamp, sendingOptions) {
263
+ const lastRead = new protocol_messaging_1.LastRead({
264
+ conversationId,
265
+ lastReadTimestamp,
266
+ });
267
+ const genericMessage = protocol_messaging_1.GenericMessage.create({
268
+ [conversation_2.GenericMessageType.LAST_READ]: lastRead,
269
+ messageId: MessageBuilder_1.MessageBuilder.createId(),
270
+ });
271
+ const { id: selfConversationId, domain: selfConversationDomain } = await this.getSelfConversationId();
272
+ return this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, Object.assign({ conversationDomain: selfConversationDomain }, sendingOptions));
273
+ }
274
+ /**
275
+ * Syncs all self user's devices with the countly id
276
+ *
277
+ * @param countlyId The countly id of the current device
278
+ * @param sendingOptions?
279
+ * @return Resolves when the message has been sent
280
+ */
281
+ async sendCountlySync(countlyId, sendingOptions) {
282
+ const { id: selfConversationId, domain: selfConversationDomain } = await this.getSelfConversationId();
283
+ const dataTransfer = new protocol_messaging_1.DataTransfer({
284
+ trackingIdentifier: {
285
+ identifier: countlyId,
286
+ },
287
+ });
288
+ const genericMessage = new protocol_messaging_1.GenericMessage({
289
+ [conversation_2.GenericMessageType.DATA_TRANSFER]: dataTransfer,
290
+ messageId: MessageBuilder_1.MessageBuilder.createId(),
291
+ });
292
+ return this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, Object.assign({ conversationDomain: selfConversationDomain }, sendingOptions));
293
+ }
294
+ /**
295
+ * Get a fresh list from backend of clients for all the participants of the conversation.
296
+ * This is a hacky way of getting all the clients for a conversation.
297
+ * The idea is to send an empty message to the backend to absolutely no users and let backend reply with a mismatch error.
298
+ * We then get the missing members in the mismatch, that is our fresh list of participants' clients.
299
+ *
300
+ * @deprecated
301
+ * @param {string} conversationId
302
+ * @param {string} conversationDomain? - If given will send the message to the new qualified endpoint
303
+ */
304
+ getAllParticipantsClients(conversationId, conversationDomain) {
305
+ const sendingClientId = this.apiClient.validatedClientId;
306
+ const recipients = {};
307
+ const text = new Uint8Array();
308
+ return new Promise(async (resolve) => {
309
+ const onClientMismatch = (mismatch) => {
310
+ resolve(mismatch.missing);
311
+ // When the mismatch happens, we ask the messageService to cancel the sending
312
+ return false;
313
+ };
314
+ if (conversationDomain && this.config.useQualifiedIds) {
315
+ await this.messageService.sendFederatedMessage(sendingClientId, recipients, text, {
316
+ conversationId: { id: conversationId, domain: conversationDomain },
317
+ onClientMismatch,
318
+ reportMissing: true,
319
+ });
320
+ }
321
+ else {
322
+ await this.messageService.sendMessage(sendingClientId, recipients, text, {
323
+ conversationId,
324
+ onClientMismatch,
325
+ });
326
+ }
327
+ });
328
+ }
329
+ /**
330
+ * Get a fresh list from backend of clients for all the participants of the conversation.
331
+ * @fixme there are some case where this method is not enough to detect removed devices
332
+ * @param {string} conversationId
333
+ * @param {string} conversationDomain? - If given will send the message to the new qualified endpoint
334
+ */
335
+ async fetchAllParticipantsClients(conversationId, conversationDomain) {
336
+ const qualifiedMembers = await this.getConversationQualifiedMembers(conversationDomain ? { id: conversationId, domain: conversationDomain } : conversationId);
337
+ const allClients = await this.apiClient.api.user.postListClients({ qualified_users: qualifiedMembers });
338
+ const qualifiedUserClients = {};
339
+ Object.entries(allClients.qualified_user_map).map(([domain, userClientMap]) => Object.entries(userClientMap).map(async ([userId, clients]) => {
340
+ qualifiedUserClients[domain] || (qualifiedUserClients[domain] = {});
341
+ qualifiedUserClients[domain][userId] = clients.map(client => client.id);
342
+ }));
343
+ return qualifiedUserClients;
344
+ }
345
+ createProteusConversation(conversationData, otherUserIds) {
346
+ let payload;
347
+ if (typeof conversationData === 'string') {
348
+ const ids = typeof otherUserIds === 'string' ? [otherUserIds] : otherUserIds;
349
+ payload = {
350
+ name: conversationData,
351
+ receipt_mode: null,
352
+ users: ids !== null && ids !== void 0 ? ids : [],
353
+ };
354
+ }
355
+ else {
356
+ payload = conversationData;
357
+ }
358
+ return this.apiClient.api.conversation.postConversation(payload);
359
+ }
360
+ async getConversations(conversationIds) {
361
+ if (!conversationIds || !conversationIds.length) {
362
+ return this.apiClient.api.conversation.getAllConversations();
363
+ }
364
+ if (typeof conversationIds === 'string') {
365
+ return this.apiClient.api.conversation.getConversation(conversationIds);
366
+ }
367
+ return this.apiClient.api.conversation.getConversationsByIds(conversationIds);
368
+ }
369
+ async getAsset({ assetId, assetToken, otrKey, sha256 }) {
370
+ const request = this.apiClient.api.asset.getAssetV3(assetId, assetToken);
371
+ const encryptedBuffer = (await request.response).buffer;
372
+ return (0, AssetCryptography_1.decryptAsset)({
373
+ cipherText: new Uint8Array(encryptedBuffer),
374
+ keyBytes: otrKey,
375
+ sha256: sha256,
376
+ });
377
+ }
378
+ async getUnencryptedAsset(assetId, assetToken) {
379
+ const request = await this.apiClient.api.asset.getAssetV3(assetId, assetToken);
380
+ return (await request.response).buffer;
381
+ }
382
+ async addUsersToProteusConversation({ conversationId, qualifiedUserIds }) {
383
+ return this.apiClient.api.conversation.postMembers(conversationId, qualifiedUserIds);
384
+ }
385
+ async removeUserFromConversation(conversationId, userId) {
386
+ return this.apiClient.api.conversation.deleteMember(conversationId, userId);
387
+ }
388
+ async sendProteusMessage(params, genericMessage, content) {
389
+ var _a;
390
+ const { userIds, sendAsProtobuf, conversationDomain, nativePush, targetMode, payload, onClientMismatch, onSuccess } = params;
391
+ const response = await this.sendGenericMessage(this.apiClient.validatedClientId, payload.conversation, genericMessage, {
392
+ userIds,
393
+ sendAsProtobuf,
394
+ conversationDomain,
395
+ nativePush,
396
+ targetMode,
397
+ onClientMismatch,
398
+ });
399
+ if (!response.errored) {
400
+ if (!this.isClearFromMismatch(response)) {
401
+ // We warn the consumer that there is a mismatch that did not prevent message sending
402
+ await (onClientMismatch === null || onClientMismatch === void 0 ? void 0 : onClientMismatch(response, true));
403
+ }
404
+ onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(genericMessage, response.time);
405
+ }
406
+ return Object.assign(Object.assign({}, payload), { content, messageTimer: ((_a = genericMessage.ephemeral) === null || _a === void 0 ? void 0 : _a.expireAfterMillis) || 0, state: response.errored ? conversation_2.PayloadBundleState.CANCELLED : conversation_2.PayloadBundleState.OUTGOING_SENT });
407
+ }
408
+ /**
409
+ * Sends a message to a conversation
410
+ * @return resolves with the sent message
411
+ */
412
+ async send(params) {
413
+ function isMLS(params) {
414
+ return params.protocol === conversation_1.ConversationProtocol.MLS;
415
+ }
416
+ const { payload, onStart } = params;
417
+ const { genericMessage, content } = (0, messageGenerator_1.generateGenericMessage)(payload, this.messageTimer);
418
+ if ((await (onStart === null || onStart === void 0 ? void 0 : onStart(genericMessage))) === false) {
419
+ // If the onStart call returns false, it means the consumer wants to cancel the message sending
420
+ return Object.assign(Object.assign({}, payload), { state: conversation_2.PayloadBundleState.CANCELLED });
421
+ }
422
+ return (0, messageSender_1.sendMessage)(() => isMLS(params)
423
+ ? this.sendMLSMessage(params, genericMessage, content)
424
+ : this.sendProteusMessage(params, genericMessage, content));
425
+ }
426
+ sendTypingStart(conversationId) {
427
+ return this.apiClient.api.conversation.postTyping(conversationId, { status: data_1.CONVERSATION_TYPING.STARTED });
428
+ }
429
+ sendTypingStop(conversationId) {
430
+ return this.apiClient.api.conversation.postTyping(conversationId, { status: data_1.CONVERSATION_TYPING.STOPPED });
431
+ }
432
+ setConversationMutedStatus(conversationId, status, muteTimestamp) {
433
+ if (typeof muteTimestamp === 'number') {
434
+ muteTimestamp = new Date(muteTimestamp);
435
+ }
436
+ const payload = {
437
+ otr_muted_ref: muteTimestamp.toISOString(),
438
+ otr_muted_status: status,
439
+ };
440
+ return this.apiClient.api.conversation.putMembershipProperties(conversationId, payload);
441
+ }
442
+ toggleArchiveConversation(conversationId, archived, archiveTimestamp = new Date()) {
443
+ if (typeof archiveTimestamp === 'number') {
444
+ archiveTimestamp = new Date(archiveTimestamp);
445
+ }
446
+ const payload = {
447
+ otr_archived: archived,
448
+ otr_archived_ref: archiveTimestamp.toISOString(),
449
+ };
450
+ return this.apiClient.api.conversation.putMembershipProperties(conversationId, payload);
451
+ }
452
+ setMemberConversationRole(conversationId, userId, conversationRole) {
453
+ return this.apiClient.api.conversation.putOtherMember(userId, conversationId, {
454
+ conversation_role: conversationRole,
455
+ });
456
+ }
457
+ isClearFromMismatch(mismatch) {
458
+ const hasMissing = Object.keys(mismatch.missing || {}).length > 0;
459
+ const hasDeleted = Object.keys(mismatch.deleted || {}).length > 0;
460
+ const hasRedundant = Object.keys(mismatch.redundant || {}).length > 0;
461
+ const hasFailed = Object.keys(mismatch.failed_to_send || {}).length > 0;
462
+ return !hasMissing && !hasDeleted && !hasRedundant && !hasFailed;
463
+ }
464
+ /**
465
+ * ###############################################
466
+ * ################ MLS Functions ################
467
+ * ###############################################
468
+ */
469
+ async createMLSConversation(conversationData) {
470
+ /**
471
+ * @note For creating MLS conversations the users & qualified_users
472
+ * field must be empty as backend is not aware which users
473
+ * are in a MLS conversation because of the MLS architecture.
474
+ */
475
+ const newConversation = await this.apiClient.api.conversation.postConversation(Object.assign(Object.assign({}, conversationData), { users: undefined, qualified_users: undefined }));
476
+ const { group_id: groupId, qualified_id: qualifiedId } = newConversation;
477
+ if (!groupId) {
478
+ throw new Error('No group_id found in response which is required for creating MLS conversations.');
479
+ }
480
+ const groupIdDecodedFromBase64 = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
481
+ const { qualified_users: qualifiedUsers = [], selfUserId } = conversationData;
482
+ if (!selfUserId) {
483
+ throw new Error('You need to pass self user qualified id in order to create an MLS conversation');
484
+ }
485
+ await this.mlsService.createConversation(groupIdDecodedFromBase64);
486
+ const coreCryptoKeyPackagesPayload = await this.mlsService.getKeyPackagesPayload([
487
+ {
488
+ id: selfUserId.id,
489
+ domain: selfUserId.domain,
490
+ /**
491
+ * we should skip fetching key packages for current self client,
492
+ * it's already added by the backend on the group creation time
493
+ */
494
+ skipOwn: conversationData.creator_client,
495
+ },
496
+ ...qualifiedUsers,
497
+ ]);
498
+ const response = await this.mlsService.addUsersToExistingConversation(groupIdDecodedFromBase64, coreCryptoKeyPackagesPayload);
499
+ //We store the info when conversation (along with key material) was created, so we will know when to renew it
500
+ const groupCreationTimeStamp = new Date().getTime();
501
+ await this.notificationService.storeLastKeyMaterialUpdateDate({
502
+ previousUpdateDate: groupCreationTimeStamp,
503
+ groupId,
504
+ });
505
+ // We fetch the fresh version of the conversation created on backend with the newly added users
506
+ const conversation = await this.getConversations(qualifiedId.id);
507
+ return {
508
+ events: (response === null || response === void 0 ? void 0 : response.events) || [],
509
+ conversation,
510
+ };
511
+ }
512
+ async sendMLSMessage(params, genericMessage, content) {
513
+ var _a, _b;
514
+ const { groupId, onSuccess, payload } = params;
515
+ const groupIdBytes = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
516
+ // immediately execute pending commits before sending the message
517
+ await this.notificationService.commitPendingProposals({ groupId });
518
+ const encrypted = await this.mlsService.encryptMessage(groupIdBytes, protocol_messaging_1.GenericMessage.encode(genericMessage).finish());
519
+ try {
520
+ const { time = '' } = await this.apiClient.api.conversation.postMlsMessage(encrypted);
521
+ onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(genericMessage, (time === null || time === void 0 ? void 0 : time.length) > 0 ? time : new Date().toISOString());
522
+ return Object.assign(Object.assign({}, payload), { content, messageTimer: ((_a = genericMessage.ephemeral) === null || _a === void 0 ? void 0 : _a.expireAfterMillis) || 0, state: conversation_2.PayloadBundleState.OUTGOING_SENT });
523
+ }
524
+ catch (_c) {
525
+ return Object.assign(Object.assign({}, payload), { content, messageTimer: ((_b = genericMessage.ephemeral) === null || _b === void 0 ? void 0 : _b.expireAfterMillis) || 0, state: conversation_2.PayloadBundleState.CANCELLED });
526
+ }
527
+ }
528
+ async addUsersToMLSConversation({ qualifiedUserIds, groupId, conversationId, }) {
529
+ const groupIdDecodedFromBase64 = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
530
+ const coreCryptoKeyPackagesPayload = await this.mlsService.getKeyPackagesPayload([...qualifiedUserIds]);
531
+ const response = await this.mlsService.addUsersToExistingConversation(groupIdDecodedFromBase64, coreCryptoKeyPackagesPayload);
532
+ const conversation = await this.getConversations(conversationId.id);
533
+ return {
534
+ events: (response === null || response === void 0 ? void 0 : response.events) || [],
535
+ conversation,
536
+ };
537
+ }
538
+ async storeLastKeyMaterialUpdateDateWithCurrentTime(groupId) {
539
+ const currentTime = new Date().getTime();
540
+ await this.notificationService.storeLastKeyMaterialUpdateDate({ groupId, previousUpdateDate: currentTime });
541
+ }
542
+ async removeUsersFromMLSConversation({ groupId, conversationId, qualifiedUserIds, }) {
543
+ const groupIdDecodedFromBase64 = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
544
+ const clientsToRemove = await this.apiClient.api.user.postListClients({ qualified_users: qualifiedUserIds });
545
+ const fullyQualifiedClientIds = (0, fullyQualifiedClientIdUtils_1.mapQualifiedUserClientIdsToFullyQualifiedClientIds)(clientsToRemove.qualified_user_map);
546
+ const messageResponse = await this.mlsService.removeClientsFromConversation(groupIdDecodedFromBase64, fullyQualifiedClientIds);
547
+ //key material gets updated after removing a user from the group, so we can reset last key update time value in the store
548
+ await this.storeLastKeyMaterialUpdateDateWithCurrentTime(groupId);
549
+ const conversation = await this.getConversations(conversationId.id);
550
+ return {
551
+ events: (messageResponse === null || messageResponse === void 0 ? void 0 : messageResponse.events) || [],
552
+ conversation,
553
+ };
554
+ }
555
+ /**
556
+ * Will send an external proposal for the current device to join a specific conversation.
557
+ * In order for the external proposal to be sent correctly, the underlying mls conversation needs to be in a non-established state
558
+ * @param conversationGroupId The conversation to join
559
+ * @param epoch The current epoch of the local conversation
560
+ */
561
+ async sendExternalJoinProposal(conversationGroupId, epoch) {
562
+ return (0, messageSender_1.sendMessage)(async () => {
563
+ const groupIdDecodedFromBase64 = bazinga64_1.Decoder.fromBase64(conversationGroupId).asBytes;
564
+ const externalProposal = await this.mlsService.newExternalProposal(core_crypto_1.ExternalProposalType.Add, {
565
+ epoch,
566
+ conversationId: groupIdDecodedFromBase64,
567
+ });
568
+ await this.apiClient.api.conversation.postMlsMessage(
569
+ //@todo: it's temporary - we wait for core-crypto fix to return the actual Uint8Array instead of regular array
570
+ (0, mls_1.optionalToUint8Array)(externalProposal));
571
+ //We store the info when user was added (and key material was created), so we will know when to renew it
572
+ await this.storeLastKeyMaterialUpdateDateWithCurrentTime(conversationGroupId);
573
+ });
574
+ }
575
+ async isMLSConversationEstablished(conversationGroupId) {
576
+ const groupIdDecodedFromBase64 = bazinga64_1.Decoder.fromBase64(conversationGroupId).asBytes;
577
+ return this.mlsService.conversationExists(groupIdDecodedFromBase64);
578
+ }
579
+ async wipeMLSConversation(conversationId) {
580
+ return this.mlsService.wipeConversation(conversationId);
581
+ }
582
+ }
583
+ exports.ConversationService = ConversationService;
584
+ //# sourceMappingURL=ConversationService.js.map