@wireapp/core 17.29.0 → 17.31.2

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 (243) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/package.json +8 -8
  3. package/src/main/conversation/ConversationMapper.js +2 -0
  4. package/src/main/conversation/ConversationService.d.ts +5 -2
  5. package/src/main/conversation/ConversationService.js +0 -2
  6. package/src/main/conversation/message/PayloadBundle.d.ts +3 -0
  7. package/src/main/cryptography/GenericMessageMapper.d.ts +0 -1
  8. package/src/main/cryptography/GenericMessageMapper.js +23 -158
  9. package/src/main/Account.js.map +0 -1
  10. package/src/main/Account.test.browser.js +0 -114
  11. package/src/main/Account.test.node.d.ts +0 -1
  12. package/src/main/Account.test.node.js +0 -214
  13. package/src/main/Account.test.node.js.map +0 -1
  14. package/src/main/Account.test.node.ts +0 -236
  15. package/src/main/Account.ts +0 -401
  16. package/src/main/CoreError.js.map +0 -1
  17. package/src/main/CoreError.ts +0 -30
  18. package/src/main/auth/LoginSanitizer.js.map +0 -1
  19. package/src/main/auth/LoginSanitizer.test.node.d.ts +0 -1
  20. package/src/main/auth/LoginSanitizer.test.node.js +0 -56
  21. package/src/main/auth/LoginSanitizer.test.node.js.map +0 -1
  22. package/src/main/auth/LoginSanitizer.test.node.ts +0 -68
  23. package/src/main/auth/LoginSanitizer.ts +0 -44
  24. package/src/main/auth/index.js.map +0 -1
  25. package/src/main/auth/index.ts +0 -20
  26. package/src/main/broadcast/AvailabilityType.js.map +0 -1
  27. package/src/main/broadcast/AvailabilityType.ts +0 -22
  28. package/src/main/broadcast/BroadcastService.js.map +0 -1
  29. package/src/main/broadcast/BroadcastService.ts +0 -66
  30. package/src/main/broadcast/index.js.map +0 -1
  31. package/src/main/broadcast/index.ts +0 -21
  32. package/src/main/client/ClientBackendRepository.js.map +0 -1
  33. package/src/main/client/ClientBackendRepository.ts +0 -33
  34. package/src/main/client/ClientDatabaseRepository.js.map +0 -1
  35. package/src/main/client/ClientDatabaseRepository.ts +0 -130
  36. package/src/main/client/ClientInfo.js.map +0 -1
  37. package/src/main/client/ClientInfo.ts +0 -28
  38. package/src/main/client/ClientService.js.map +0 -1
  39. package/src/main/client/ClientService.ts +0 -116
  40. package/src/main/client/index.js.map +0 -1
  41. package/src/main/client/index.ts +0 -23
  42. package/src/main/connection/ConnectionService.js.map +0 -1
  43. package/src/main/connection/ConnectionService.ts +0 -49
  44. package/src/main/connection/index.js.map +0 -1
  45. package/src/main/connection/index.ts +0 -20
  46. package/src/main/conversation/AbortReason.js.map +0 -1
  47. package/src/main/conversation/AbortReason.ts +0 -22
  48. package/src/main/conversation/AssetService.js.map +0 -1
  49. package/src/main/conversation/AssetService.test.node.d.ts +0 -1
  50. package/src/main/conversation/AssetService.test.node.js +0 -61
  51. package/src/main/conversation/AssetService.test.node.js.map +0 -1
  52. package/src/main/conversation/AssetService.test.node.ts +0 -65
  53. package/src/main/conversation/AssetService.ts +0 -60
  54. package/src/main/conversation/AssetTransferState.js.map +0 -1
  55. package/src/main/conversation/AssetTransferState.ts +0 -23
  56. package/src/main/conversation/ClientActionType.js.map +0 -1
  57. package/src/main/conversation/ClientActionType.ts +0 -20
  58. package/src/main/conversation/ConversationMapper.js.map +0 -1
  59. package/src/main/conversation/ConversationMapper.test.node.d.ts +0 -1
  60. package/src/main/conversation/ConversationMapper.test.node.js +0 -111
  61. package/src/main/conversation/ConversationMapper.test.node.js.map +0 -1
  62. package/src/main/conversation/ConversationMapper.test.node.ts +0 -154
  63. package/src/main/conversation/ConversationMapper.ts +0 -54
  64. package/src/main/conversation/ConversationService.js.map +0 -1
  65. package/src/main/conversation/ConversationService.test.node.d.ts +0 -1
  66. package/src/main/conversation/ConversationService.test.node.js +0 -344
  67. package/src/main/conversation/ConversationService.test.node.js.map +0 -1
  68. package/src/main/conversation/ConversationService.test.node.ts +0 -416
  69. package/src/main/conversation/ConversationService.ts +0 -1020
  70. package/src/main/conversation/GenericMessageType.js.map +0 -1
  71. package/src/main/conversation/GenericMessageType.ts +0 -44
  72. package/src/main/conversation/MessageTimer.js.map +0 -1
  73. package/src/main/conversation/MessageTimer.test.node.d.ts +0 -1
  74. package/src/main/conversation/MessageTimer.test.node.js +0 -88
  75. package/src/main/conversation/MessageTimer.test.node.js.map +0 -1
  76. package/src/main/conversation/MessageTimer.test.node.ts +0 -103
  77. package/src/main/conversation/MessageTimer.ts +0 -56
  78. package/src/main/conversation/ReactionType.js.map +0 -1
  79. package/src/main/conversation/ReactionType.ts +0 -23
  80. package/src/main/conversation/content/AssetContent.js.map +0 -1
  81. package/src/main/conversation/content/AssetContent.ts +0 -71
  82. package/src/main/conversation/content/ButtonActionConfirmationContent.js.map +0 -1
  83. package/src/main/conversation/content/ButtonActionConfirmationContent.ts +0 -21
  84. package/src/main/conversation/content/ButtonActionContent.js.map +0 -1
  85. package/src/main/conversation/content/ButtonActionContent.ts +0 -21
  86. package/src/main/conversation/content/CallingContent.js.map +0 -1
  87. package/src/main/conversation/content/CallingContent.ts +0 -20
  88. package/src/main/conversation/content/ClearedContent.js.map +0 -1
  89. package/src/main/conversation/content/ClearedContent.ts +0 -21
  90. package/src/main/conversation/content/ClientActionContent.js.map +0 -1
  91. package/src/main/conversation/content/ClientActionContent.ts +0 -22
  92. package/src/main/conversation/content/ClientAddContent.js.map +0 -1
  93. package/src/main/conversation/content/ClientAddContent.ts +0 -24
  94. package/src/main/conversation/content/ClientRemoveContent.js.map +0 -1
  95. package/src/main/conversation/content/ClientRemoveContent.ts +0 -25
  96. package/src/main/conversation/content/CompositeContent.js.map +0 -1
  97. package/src/main/conversation/content/CompositeContent.ts +0 -21
  98. package/src/main/conversation/content/ConfirmationContent.js.map +0 -1
  99. package/src/main/conversation/content/ConfirmationContent.ts +0 -21
  100. package/src/main/conversation/content/ContentType.js.map +0 -1
  101. package/src/main/conversation/content/ContentType.ts +0 -112
  102. package/src/main/conversation/content/ConversationContent.js.map +0 -1
  103. package/src/main/conversation/content/ConversationContent.ts +0 -71
  104. package/src/main/conversation/content/DeletedContent.js.map +0 -1
  105. package/src/main/conversation/content/DeletedContent.ts +0 -21
  106. package/src/main/conversation/content/EditedTextContent.js.map +0 -1
  107. package/src/main/conversation/content/EditedTextContent.ts +0 -31
  108. package/src/main/conversation/content/FileContent.js.map +0 -1
  109. package/src/main/conversation/content/FileContent.ts +0 -32
  110. package/src/main/conversation/content/HiddenContent.js.map +0 -1
  111. package/src/main/conversation/content/HiddenContent.ts +0 -21
  112. package/src/main/conversation/content/ImageContent.js.map +0 -1
  113. package/src/main/conversation/content/ImageContent.ts +0 -25
  114. package/src/main/conversation/content/KnockContent.js.map +0 -1
  115. package/src/main/conversation/content/KnockContent.ts +0 -21
  116. package/src/main/conversation/content/LinkPreviewContent.js.map +0 -1
  117. package/src/main/conversation/content/LinkPreviewContent.ts +0 -32
  118. package/src/main/conversation/content/LocationContent.js.map +0 -1
  119. package/src/main/conversation/content/LocationContent.ts +0 -29
  120. package/src/main/conversation/content/MentionContent.js.map +0 -1
  121. package/src/main/conversation/content/MentionContent.ts +0 -21
  122. package/src/main/conversation/content/QuoteContent.js.map +0 -1
  123. package/src/main/conversation/content/QuoteContent.ts +0 -29
  124. package/src/main/conversation/content/ReactionContent.js.map +0 -1
  125. package/src/main/conversation/content/ReactionContent.ts +0 -27
  126. package/src/main/conversation/content/TextContent.js.map +0 -1
  127. package/src/main/conversation/content/TextContent.ts +0 -29
  128. package/src/main/conversation/content/TweetContent.js.map +0 -1
  129. package/src/main/conversation/content/TweetContent.ts +0 -21
  130. package/src/main/conversation/content/index.js.map +0 -1
  131. package/src/main/conversation/content/index.ts +0 -49
  132. package/src/main/conversation/index.js.map +0 -1
  133. package/src/main/conversation/index.ts +0 -28
  134. package/src/main/conversation/message/CompositeContentBuilder.js.map +0 -1
  135. package/src/main/conversation/message/CompositeContentBuilder.ts +0 -60
  136. package/src/main/conversation/message/Message.js.map +0 -1
  137. package/src/main/conversation/message/Message.ts +0 -24
  138. package/src/main/conversation/message/MessageBuilder.js.map +0 -1
  139. package/src/main/conversation/message/MessageBuilder.test.browser.js +0 -27
  140. package/src/main/conversation/message/MessageBuilder.ts +0 -488
  141. package/src/main/conversation/message/MessageService.js.map +0 -1
  142. package/src/main/conversation/message/MessageService.test.node.d.ts +0 -1
  143. package/src/main/conversation/message/MessageService.test.node.js +0 -308
  144. package/src/main/conversation/message/MessageService.test.node.js.map +0 -1
  145. package/src/main/conversation/message/MessageService.test.node.ts +0 -398
  146. package/src/main/conversation/message/MessageService.ts +0 -383
  147. package/src/main/conversation/message/MessageToProtoMapper.js.map +0 -1
  148. package/src/main/conversation/message/MessageToProtoMapper.ts +0 -114
  149. package/src/main/conversation/message/OtrMessage.js.map +0 -1
  150. package/src/main/conversation/message/OtrMessage.ts +0 -160
  151. package/src/main/conversation/message/PayloadBundle.js.map +0 -1
  152. package/src/main/conversation/message/PayloadBundle.ts +0 -98
  153. package/src/main/conversation/message/TeamMessage.js.map +0 -1
  154. package/src/main/conversation/message/TeamMessage.ts +0 -72
  155. package/src/main/conversation/message/TextContentBuilder.js.map +0 -1
  156. package/src/main/conversation/message/TextContentBuilder.ts +0 -88
  157. package/src/main/conversation/message/UserClientsUtil.js.map +0 -1
  158. package/src/main/conversation/message/UserClientsUtil.ts +0 -44
  159. package/src/main/conversation/message/UserClientsUtils.test.node.d.ts +0 -1
  160. package/src/main/conversation/message/UserClientsUtils.test.node.js +0 -42
  161. package/src/main/conversation/message/UserClientsUtils.test.node.js.map +0 -1
  162. package/src/main/conversation/message/UserClientsUtils.test.node.ts +0 -44
  163. package/src/main/conversation/message/UserMessage.js.map +0 -1
  164. package/src/main/conversation/message/UserMessage.ts +0 -95
  165. package/src/main/cryptography/AssetCryptography.browser.js.map +0 -1
  166. package/src/main/cryptography/AssetCryptography.browser.ts +0 -76
  167. package/src/main/cryptography/AssetCryptography.node.js.map +0 -1
  168. package/src/main/cryptography/AssetCryptography.node.ts +0 -85
  169. package/src/main/cryptography/CryptographyDatabaseRepository.js.map +0 -1
  170. package/src/main/cryptography/CryptographyDatabaseRepository.ts +0 -44
  171. package/src/main/cryptography/CryptographyService.js.map +0 -1
  172. package/src/main/cryptography/CryptographyService.test.browser.js +0 -195
  173. package/src/main/cryptography/CryptographyService.test.node.d.ts +0 -1
  174. package/src/main/cryptography/CryptographyService.test.node.js +0 -228
  175. package/src/main/cryptography/CryptographyService.test.node.js.map +0 -1
  176. package/src/main/cryptography/CryptographyService.test.node.ts +0 -246
  177. package/src/main/cryptography/CryptographyService.ts +0 -246
  178. package/src/main/cryptography/EncryptedAsset.js.map +0 -1
  179. package/src/main/cryptography/EncryptedAsset.ts +0 -30
  180. package/src/main/cryptography/GenericMessageMapper.js.map +0 -1
  181. package/src/main/cryptography/GenericMessageMapper.ts +0 -364
  182. package/src/main/cryptography/MessageHashService.js.map +0 -1
  183. package/src/main/cryptography/MessageHashService.test.browser.js +0 -176
  184. package/src/main/cryptography/MessageHashService.test.node.d.ts +0 -1
  185. package/src/main/cryptography/MessageHashService.test.node.js +0 -138
  186. package/src/main/cryptography/MessageHashService.test.node.js.map +0 -1
  187. package/src/main/cryptography/MessageHashService.test.node.ts +0 -176
  188. package/src/main/cryptography/MessageHashService.ts +0 -109
  189. package/src/main/cryptography/SessionPayloadBundle.js.map +0 -1
  190. package/src/main/cryptography/SessionPayloadBundle.ts +0 -23
  191. package/src/main/cryptography/index.js.map +0 -1
  192. package/src/main/cryptography/index.ts +0 -23
  193. package/src/main/giphy/GiphyService.js.map +0 -1
  194. package/src/main/giphy/GiphyService.ts +0 -37
  195. package/src/main/giphy/index.js.map +0 -1
  196. package/src/main/giphy/index.ts +0 -20
  197. package/src/main/index.js.map +0 -1
  198. package/src/main/index.test.browser.js +0 -22
  199. package/src/main/index.ts +0 -34
  200. package/src/main/notification/NotificationBackendRepository.js.map +0 -1
  201. package/src/main/notification/NotificationBackendRepository.ts +0 -33
  202. package/src/main/notification/NotificationDatabaseRepository.js.map +0 -1
  203. package/src/main/notification/NotificationDatabaseRepository.ts +0 -74
  204. package/src/main/notification/NotificationService.js.map +0 -1
  205. package/src/main/notification/NotificationService.test.browser.js +0 -179
  206. package/src/main/notification/NotificationService.test.node.d.ts +0 -1
  207. package/src/main/notification/NotificationService.test.node.js +0 -99
  208. package/src/main/notification/NotificationService.test.node.js.map +0 -1
  209. package/src/main/notification/NotificationService.test.node.ts +0 -124
  210. package/src/main/notification/NotificationService.ts +0 -260
  211. package/src/main/notification/index.js.map +0 -1
  212. package/src/main/notification/index.ts +0 -20
  213. package/src/main/self/SelfService.js.map +0 -1
  214. package/src/main/self/SelfService.ts +0 -59
  215. package/src/main/self/index.js.map +0 -1
  216. package/src/main/self/index.ts +0 -20
  217. package/src/main/team/TeamService.js.map +0 -1
  218. package/src/main/team/TeamService.ts +0 -68
  219. package/src/main/team/index.js.map +0 -1
  220. package/src/main/team/index.ts +0 -20
  221. package/src/main/test/CryptographyHelper.js.map +0 -1
  222. package/src/main/test/CryptographyHelper.ts +0 -57
  223. package/src/main/test/PayloadHelper.js.map +0 -1
  224. package/src/main/test/PayloadHelper.ts +0 -60
  225. package/src/main/user/UserMapper.js.map +0 -1
  226. package/src/main/user/UserMapper.test.node.d.ts +0 -1
  227. package/src/main/user/UserMapper.test.node.js +0 -55
  228. package/src/main/user/UserMapper.test.node.js.map +0 -1
  229. package/src/main/user/UserMapper.test.node.ts +0 -63
  230. package/src/main/user/UserMapper.ts +0 -92
  231. package/src/main/user/UserService.js.map +0 -1
  232. package/src/main/user/UserService.test.node.js +0 -141
  233. package/src/main/user/UserService.ts +0 -98
  234. package/src/main/user/index.js.map +0 -1
  235. package/src/main/user/index.ts +0 -20
  236. package/src/main/util/TypePredicateUtil.js.map +0 -1
  237. package/src/main/util/TypePredicateUtil.test.node.d.ts +0 -1
  238. package/src/main/util/TypePredicateUtil.test.node.js +0 -42
  239. package/src/main/util/TypePredicateUtil.test.node.js.map +0 -1
  240. package/src/main/util/TypePredicateUtil.test.node.ts +0 -44
  241. package/src/main/util/TypePredicateUtil.ts +0 -52
  242. package/src/main/util/index.js.map +0 -1
  243. package/src/main/util/index.ts +0 -20
@@ -1,1020 +0,0 @@
1
- /*
2
- * Wire
3
- * Copyright (C) 2018 Wire Swiss GmbH
4
- *
5
- * This program is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation, either version 3 of the License, or
8
- * (at your option) any later version.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program. If not, see http://www.gnu.org/licenses/.
17
- *
18
- */
19
-
20
- import type {APIClient} from '@wireapp/api-client';
21
- import {
22
- MessageSendingStatus,
23
- Conversation,
24
- CONVERSATION_TYPE,
25
- DefaultConversationRoleName,
26
- MutedStatus,
27
- NewConversation,
28
- QualifiedUserClients,
29
- UserClients,
30
- ClientMismatch,
31
- } from '@wireapp/api-client/src/conversation/';
32
- import {CONVERSATION_TYPING, ConversationMemberUpdateData} from '@wireapp/api-client/src/conversation/data/';
33
- import type {ConversationMemberLeaveEvent} from '@wireapp/api-client/src/event/';
34
- import type {QualifiedId, QualifiedUserPreKeyBundleMap, UserPreKeyBundleMap} from '@wireapp/api-client/src/user/';
35
- import {
36
- Asset,
37
- ButtonAction,
38
- ButtonActionConfirmation,
39
- Calling,
40
- Cleared,
41
- ClientAction,
42
- Composite,
43
- Confirmation,
44
- Ephemeral,
45
- GenericMessage,
46
- Knock,
47
- Location,
48
- MessageDelete,
49
- MessageEdit,
50
- MessageHide,
51
- Reaction,
52
- } from '@wireapp/protocol-messaging';
53
-
54
- import {
55
- AssetService,
56
- AssetTransferState,
57
- GenericMessageType,
58
- MessageTimer,
59
- PayloadBundleSource,
60
- PayloadBundleState,
61
- PayloadBundleType,
62
- } from '../conversation/';
63
- import type {AssetContent, ClearedContent, DeletedContent, HiddenContent, RemoteData} from '../conversation/content/';
64
- import type {CryptographyService} from '../cryptography/';
65
- import * as AssetCryptography from '../cryptography/AssetCryptography.node';
66
- import {isStringArray, isQualifiedIdArray, isQualifiedUserClients, isUserClients} from '../util/TypePredicateUtil';
67
- import {MessageBuilder} from './message/MessageBuilder';
68
- import {MessageService} from './message/MessageService';
69
- import {MessageToProtoMapper} from './message/MessageToProtoMapper';
70
- import type {
71
- ButtonActionConfirmationMessage,
72
- ButtonActionMessage,
73
- CallMessage,
74
- ClearConversationMessage,
75
- CompositeMessage,
76
- ConfirmationMessage,
77
- DeleteMessage,
78
- EditedTextMessage,
79
- FileAssetAbortMessage,
80
- FileAssetMessage,
81
- FileAssetMetaDataMessage,
82
- HideMessage,
83
- ImageAssetMessageOutgoing,
84
- LocationMessage,
85
- OtrMessage,
86
- PingMessage,
87
- ReactionMessage,
88
- ResetSessionMessage,
89
- TextMessage,
90
- } from './message/OtrMessage';
91
-
92
- export enum MessageTargetMode {
93
- NONE,
94
- USERS,
95
- USERS_CLIENTS,
96
- }
97
-
98
- interface MessageSendingOptions {
99
- /**
100
- * The federated domain the server runs on. Should only be set for federation enabled envs
101
- */
102
- conversationDomain?: string;
103
-
104
- /**
105
- * can be either a QualifiedId[] or QualfiedUserClients or undefined. The type has some effect on the behavior of the method.
106
- * When given undefined the method will fetch both the members of the conversations and their devices. No ClientMismatch can happen in that case
107
- * When given a QualifiedId[] the method will fetch the freshest list of devices for those users (since they are not given by the consumer). As a consequence no ClientMismatch error will trigger and we will ignore missing clients when sending
108
- * When given a QualifiedUserClients the method will only send to the clients listed in the userIds. This could lead to ClientMismatch (since the given list of devices might not be the freshest one and new clients could have been created)
109
- */
110
- userIds?: string[] | QualifiedId[] | UserClients | QualifiedUserClients;
111
-
112
- /**
113
- * Will send the message as a protobuf payload
114
- */
115
- sendAsProtobuf?: boolean;
116
- nativePush?: boolean;
117
-
118
- /**
119
- * Will be called whenever there is a clientmismatch returned from the server. Needs to be combined with a userIds of type QualifiedUserClients
120
- */
121
- onClientMismatch?: MessageSendingCallbacks['onClientMismatch'];
122
-
123
- /**
124
- * Defines the behavior to use when a mismatch happens on backend side:
125
- * - NONE -> Not a targetted message, we want to send to all the users/clients in the conversation. Will report all missing users and clients (default mode)
126
- * - USERS -> A message targetted to all the clients of the given users (according to params.userIds). Will ignore missing users and only report missing clients for the given params.userIds
127
- * - USERS_CLIENTS -> A message targetted at some specific clients of specific users (according to params.userIds). Will force sending the message even if users or clients are missing
128
- */
129
- targetMode?: MessageTargetMode;
130
- }
131
-
132
- export interface MessageSendingCallbacks {
133
- onStart?: (message: GenericMessage) => void | boolean | Promise<boolean>;
134
- onSuccess?: (message: GenericMessage, sentTime?: string) => void;
135
- /**
136
- * Called whenever there is a clientmismatch returned from the server. Will also indicate the sending status of the message (if it was already sent or not)
137
- *
138
- * @param status The mismatch info
139
- * @param wasSent Indicate whether the message was already sent or if it can still be canceled
140
- * @return
141
- */
142
- onClientMismatch?: (
143
- status: ClientMismatch | MessageSendingStatus,
144
- wasSent: boolean,
145
- ) => void | boolean | Promise<boolean>;
146
- }
147
-
148
- export class ConversationService {
149
- public readonly messageTimer: MessageTimer;
150
- public readonly messageBuilder: MessageBuilder;
151
- private readonly messageService: MessageService;
152
-
153
- constructor(
154
- private readonly apiClient: APIClient,
155
- cryptographyService: CryptographyService,
156
- private readonly assetService: AssetService,
157
- ) {
158
- this.messageTimer = new MessageTimer();
159
- this.messageBuilder = new MessageBuilder(this.apiClient, this.assetService);
160
- this.messageService = new MessageService(this.apiClient, cryptographyService);
161
- }
162
-
163
- private createEphemeral(originalGenericMessage: GenericMessage, expireAfterMillis: number): GenericMessage {
164
- const ephemeralMessage = Ephemeral.create({
165
- expireAfterMillis,
166
- [originalGenericMessage.content!]: originalGenericMessage[originalGenericMessage.content!],
167
- });
168
-
169
- const genericMessage = GenericMessage.create({
170
- [GenericMessageType.EPHEMERAL]: ephemeralMessage,
171
- messageId: originalGenericMessage.messageId,
172
- });
173
-
174
- return genericMessage;
175
- }
176
-
177
- private async getConversationQualifiedMembers(conversationId: QualifiedId): Promise<QualifiedId[]> {
178
- const conversation = await this.apiClient.conversation.api.getConversation(conversationId, true);
179
- /*
180
- * If you are sending a message to a conversation, you have to include
181
- * yourself in the list of users if you want to sync a message also to your
182
- * other clients.
183
- */
184
- return (
185
- conversation.members.others
186
- .filter(member => !!member.qualified_id)
187
- .map(member => member.qualified_id!)
188
- // TODO(Federation): Use 'domain' from 'conversation.members.self' when backend has it implemented
189
- .concat({domain: this.apiClient.context!.domain!, id: conversation.members.self.id})
190
- );
191
- }
192
-
193
- /**
194
- * Will generate a prekey bundle for specific users.
195
- * If a QualifiedId array is given the bundle will contain all the clients from those users fetched from the server.
196
- * If a QualifiedUserClients is provided then only the clients in the payload will be targeted (which could generate a ClientMismatch when sending messages)
197
- *
198
- * @param {QualifiedId[]|QualifiedUserClients} userIds - Targeted users.
199
- * @returns {Promise<QualifiedUserPreKeyBundleMap}
200
- */
201
- private async getQualifiedPreKeyBundle(
202
- userIds: QualifiedId[] | QualifiedUserClients,
203
- ): Promise<QualifiedUserPreKeyBundleMap> {
204
- type Target = {id: QualifiedId; clients?: string[]};
205
- let targets: Target[] = [];
206
-
207
- if (userIds) {
208
- if (isQualifiedIdArray(userIds)) {
209
- targets = userIds.map(id => ({id}));
210
- } else {
211
- targets = Object.entries(userIds).reduce<Target[]>((accumulator, [domain, userClients]) => {
212
- for (const userId in userClients) {
213
- accumulator.push({id: {id: userId, domain}, clients: userClients[userId]});
214
- }
215
- return accumulator;
216
- }, []);
217
- }
218
- }
219
-
220
- const preKeys = await Promise.all(
221
- targets.map(async ({id: userId, clients}) => {
222
- const prekeyBundle = await this.apiClient.user.api.getUserPreKeys(userId);
223
- // We filter the clients that should not receive the message (if a QualifiedUserClients was given as parameter)
224
- const userClients = clients
225
- ? prekeyBundle.clients.filter(client => clients.includes(client.client))
226
- : prekeyBundle.clients;
227
- return {user: userId, clients: userClients};
228
- }),
229
- );
230
-
231
- return preKeys.reduce<QualifiedUserPreKeyBundleMap>((bundleMap, qualifiedPrekey) => {
232
- bundleMap[qualifiedPrekey.user.domain] ||= {};
233
- for (const client of qualifiedPrekey.clients) {
234
- bundleMap[qualifiedPrekey.user.domain][qualifiedPrekey.user.id] ||= {};
235
- bundleMap[qualifiedPrekey.user.domain][qualifiedPrekey.user.id][client.client] = client.prekey;
236
- }
237
- return bundleMap;
238
- }, {});
239
- }
240
-
241
- async getPreKeyBundleMap(conversationId: string, userIds?: string[] | UserClients): Promise<UserPreKeyBundleMap> {
242
- let members: string[] = [];
243
-
244
- if (userIds) {
245
- if (isStringArray(userIds)) {
246
- members = userIds;
247
- } else if (isUserClients(userIds)) {
248
- members = Object.keys(userIds);
249
- }
250
- }
251
-
252
- if (!members.length) {
253
- const conversation = await this.apiClient.conversation.api.getConversation(conversationId);
254
- /*
255
- * If you are sending a message to a conversation, you have to include
256
- * yourself in the list of users if you want to sync a message also to your
257
- * other clients.
258
- */
259
- members = conversation.members.others.map(member => member.id).concat(conversation.members.self.id);
260
- }
261
-
262
- const preKeys = await Promise.all(members.map(member => this.apiClient.user.api.getUserPreKeys(member)));
263
-
264
- return preKeys.reduce((bundleMap: UserPreKeyBundleMap, bundle) => {
265
- const userId = bundle.user;
266
- bundleMap[userId] ||= {};
267
- for (const client of bundle.clients) {
268
- bundleMap[userId][client.client] = client.prekey;
269
- }
270
- return bundleMap;
271
- }, {});
272
- }
273
-
274
- private getSelfConversation(): Promise<Conversation> {
275
- const {userId} = this.apiClient.context!;
276
- return this.apiClient.conversation.api.getConversation(userId);
277
- }
278
-
279
- private async getQualifiedRecipientsForConversation(
280
- conversationId: QualifiedId,
281
- userIds?: QualifiedId[] | QualifiedUserClients,
282
- ): Promise<QualifiedUserClients | QualifiedUserPreKeyBundleMap> {
283
- if (isQualifiedUserClients(userIds)) {
284
- return userIds;
285
- }
286
- const recipientIds = userIds || (await this.getConversationQualifiedMembers(conversationId));
287
- return this.getQualifiedPreKeyBundle(recipientIds);
288
- }
289
-
290
- private async getRecipientsForConversation(
291
- conversationId: string,
292
- userIds?: string[] | UserClients,
293
- ): Promise<UserClients | UserPreKeyBundleMap> {
294
- if (isUserClients(userIds)) {
295
- return userIds;
296
- }
297
- return this.getPreKeyBundleMap(conversationId, userIds);
298
- }
299
-
300
- /**
301
- * Sends a message to a conversation
302
- *
303
- * @param sendingClientId The clientId from which the message is sent
304
- * @param conversationId The conversation in which to send the message
305
- * @param genericMessage The payload of the message to send
306
- * @return Resolves with the message sending status from backend
307
- */
308
- private async sendGenericMessage(
309
- sendingClientId: string,
310
- conversationId: string,
311
- genericMessage: GenericMessage,
312
- {
313
- conversationDomain,
314
- userIds,
315
- nativePush,
316
- sendAsProtobuf,
317
- onClientMismatch,
318
- targetMode = MessageTargetMode.NONE,
319
- }: MessageSendingOptions = {},
320
- ) {
321
- const plainText = GenericMessage.encode(genericMessage).finish();
322
- if (targetMode !== MessageTargetMode.NONE && !userIds) {
323
- throw new Error('Cannot send targetted message when no userIds are given');
324
- }
325
- if (conversationDomain) {
326
- if (isStringArray(userIds) || isUserClients(userIds)) {
327
- throw new Error('Invalid userIds option for sending to federated backend');
328
- }
329
- const recipients = await this.getQualifiedRecipientsForConversation(
330
- {id: conversationId, domain: conversationDomain},
331
- userIds,
332
- );
333
- let reportMissing;
334
- if (targetMode === MessageTargetMode.NONE) {
335
- reportMissing = isQualifiedUserClients(userIds); // we want to check mismatch in case the consumer gave an exact list of users/devices
336
- } else if (targetMode === MessageTargetMode.USERS) {
337
- reportMissing = this.extractQualifiedUserIds(userIds);
338
- } else {
339
- // in case the message is fully targetted at user/client pairs, we do not want to report the missing clients or users at all
340
- reportMissing = false;
341
- }
342
- return this.messageService.sendFederatedMessage(sendingClientId, recipients, plainText, {
343
- conversationId: {id: conversationId, domain: conversationDomain},
344
- nativePush,
345
- reportMissing,
346
- onClientMismatch: mismatch => onClientMismatch?.(mismatch, false),
347
- });
348
- }
349
-
350
- if (isQualifiedIdArray(userIds) || isQualifiedUserClients(userIds)) {
351
- throw new Error('Invalid userIds option for sending');
352
- }
353
- const recipients = await this.getRecipientsForConversation(conversationId, userIds);
354
- let reportMissing;
355
- if (targetMode === MessageTargetMode.NONE) {
356
- reportMissing = isUserClients(userIds); // we want to check mismatch in case the consumer gave an exact list of users/devices
357
- } else if (targetMode === MessageTargetMode.USERS) {
358
- reportMissing = this.extractUserIds(userIds);
359
- } else {
360
- // in case the message is fully targetted at user/client pairs, we do not want to report the missing clients or users at all
361
- reportMissing = false;
362
- }
363
- return this.messageService.sendMessage(sendingClientId, recipients, plainText, {
364
- conversationId,
365
- sendAsProtobuf,
366
- nativePush,
367
- reportMissing,
368
- onClientMismatch: mistmatch => onClientMismatch?.(mistmatch, false),
369
- });
370
- }
371
-
372
- private extractUserIds(userIds?: string[] | UserClients): string[] | undefined {
373
- if (isUserClients(userIds)) {
374
- return Object.keys(userIds);
375
- }
376
- return userIds;
377
- }
378
-
379
- private extractQualifiedUserIds(userIds?: QualifiedId[] | QualifiedUserClients): QualifiedId[] | undefined {
380
- if (isQualifiedUserClients(userIds)) {
381
- return Object.entries(userIds).reduce<QualifiedId[]>((ids, [domain, userClients]) => {
382
- return ids.concat(Object.keys(userClients).map(userId => ({domain, id: userId})));
383
- }, []);
384
- }
385
- return userIds;
386
- }
387
-
388
- private generateButtonActionGenericMessage(payloadBundle: ButtonActionMessage): GenericMessage {
389
- return GenericMessage.create({
390
- [GenericMessageType.BUTTON_ACTION]: ButtonAction.create(payloadBundle.content),
391
- messageId: payloadBundle.id,
392
- });
393
- }
394
-
395
- private generateButtonActionConfirmationGenericMessage(
396
- payloadBundle: ButtonActionConfirmationMessage,
397
- ): GenericMessage {
398
- return GenericMessage.create({
399
- [GenericMessageType.BUTTON_ACTION_CONFIRMATION]: ButtonActionConfirmation.create(payloadBundle.content),
400
- messageId: payloadBundle.id,
401
- });
402
- }
403
-
404
- private generateCompositeGenericMessage(payloadBundle: CompositeMessage): GenericMessage {
405
- return GenericMessage.create({
406
- [GenericMessageType.COMPOSITE]: Composite.create(payloadBundle.content),
407
- messageId: payloadBundle.id,
408
- });
409
- }
410
-
411
- private generateConfirmationGenericMessage(payloadBundle: ConfirmationMessage): GenericMessage {
412
- const content = Confirmation.create(payloadBundle.content);
413
-
414
- return GenericMessage.create({
415
- [GenericMessageType.CONFIRMATION]: content,
416
- messageId: payloadBundle.id,
417
- });
418
- }
419
-
420
- private generateEditedTextGenericMessage(payloadBundle: EditedTextMessage): GenericMessage {
421
- const editedMessage = MessageEdit.create({
422
- replacingMessageId: payloadBundle.content.originalMessageId,
423
- text: MessageToProtoMapper.mapText(payloadBundle),
424
- });
425
-
426
- return GenericMessage.create({
427
- [GenericMessageType.EDITED]: editedMessage,
428
- messageId: payloadBundle.id,
429
- });
430
- }
431
-
432
- private generateFileDataGenericMessage(payloadBundle: FileAssetMessage): GenericMessage {
433
- if (!payloadBundle.content) {
434
- throw new Error('No content for sendFileData provided.');
435
- }
436
-
437
- const {asset, expectsReadConfirmation, legalHoldStatus} = payloadBundle.content;
438
-
439
- const remoteData = Asset.RemoteData.create({
440
- assetId: asset.key,
441
- assetToken: asset.token,
442
- otrKey: asset.keyBytes,
443
- sha256: asset.sha256,
444
- });
445
-
446
- const assetMessage = Asset.create({
447
- expectsReadConfirmation,
448
- legalHoldStatus,
449
- uploaded: remoteData,
450
- });
451
-
452
- assetMessage.status = AssetTransferState.UPLOADED;
453
-
454
- const genericMessage = GenericMessage.create({
455
- [GenericMessageType.ASSET]: assetMessage,
456
- messageId: payloadBundle.id,
457
- });
458
-
459
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
460
- return expireAfterMillis > 0 ? this.createEphemeral(genericMessage, expireAfterMillis) : genericMessage;
461
- }
462
-
463
- private generateFileMetaDataGenericMessage(payloadBundle: FileAssetMetaDataMessage): GenericMessage {
464
- if (!payloadBundle.content) {
465
- throw new Error('No content for sendFileMetaData provided.');
466
- }
467
-
468
- const {expectsReadConfirmation, legalHoldStatus, metaData} = payloadBundle.content;
469
-
470
- const original = Asset.Original.create({
471
- audio: metaData.audio,
472
- mimeType: metaData.type,
473
- name: metaData.name,
474
- size: metaData.length,
475
- video: metaData.video,
476
- });
477
-
478
- const assetMessage = Asset.create({
479
- expectsReadConfirmation,
480
- legalHoldStatus,
481
- original,
482
- });
483
-
484
- const genericMessage = GenericMessage.create({
485
- [GenericMessageType.ASSET]: assetMessage,
486
- messageId: payloadBundle.id,
487
- });
488
-
489
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
490
- return expireAfterMillis > 0 ? this.createEphemeral(genericMessage, expireAfterMillis) : genericMessage;
491
- }
492
-
493
- private generateFileAbortGenericMessage(payloadBundle: FileAssetAbortMessage): GenericMessage {
494
- if (!payloadBundle.content) {
495
- throw new Error('No content for sendFileAbort provided.');
496
- }
497
-
498
- const {expectsReadConfirmation, legalHoldStatus, reason} = payloadBundle.content;
499
-
500
- const assetMessage = Asset.create({
501
- expectsReadConfirmation,
502
- legalHoldStatus,
503
- notUploaded: reason,
504
- });
505
-
506
- assetMessage.status = AssetTransferState.NOT_UPLOADED;
507
-
508
- const genericMessage = GenericMessage.create({
509
- [GenericMessageType.ASSET]: assetMessage,
510
- messageId: payloadBundle.id,
511
- });
512
-
513
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
514
- return expireAfterMillis > 0 ? this.createEphemeral(genericMessage, expireAfterMillis) : genericMessage;
515
- }
516
-
517
- private generateImageGenericMessage(payloadBundle: ImageAssetMessageOutgoing): {
518
- content: AssetContent;
519
- genericMessage: GenericMessage;
520
- } {
521
- if (!payloadBundle.content) {
522
- throw new Error('No content for sendImage provided.');
523
- }
524
-
525
- const {asset, expectsReadConfirmation, image, legalHoldStatus} = payloadBundle.content;
526
-
527
- const imageMetadata = Asset.ImageMetaData.create({
528
- height: image.height,
529
- width: image.width,
530
- });
531
-
532
- const original = Asset.Original.create({
533
- [GenericMessageType.IMAGE]: imageMetadata,
534
- mimeType: image.type,
535
- name: null,
536
- size: image.data.length,
537
- });
538
-
539
- const remoteData = Asset.RemoteData.create({
540
- assetId: asset.key,
541
- assetToken: asset.token,
542
- otrKey: asset.keyBytes,
543
- sha256: asset.sha256,
544
- });
545
-
546
- const assetMessage = Asset.create({
547
- expectsReadConfirmation,
548
- legalHoldStatus,
549
- original,
550
- uploaded: remoteData,
551
- });
552
-
553
- assetMessage.status = AssetTransferState.UPLOADED;
554
-
555
- let genericMessage = GenericMessage.create({
556
- [GenericMessageType.ASSET]: assetMessage,
557
- messageId: payloadBundle.id,
558
- });
559
-
560
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
561
- if (expireAfterMillis) {
562
- genericMessage = this.createEphemeral(genericMessage, expireAfterMillis);
563
- }
564
- return {content: assetMessage as AssetContent, genericMessage};
565
- }
566
-
567
- private generateLocationGenericMessage(payloadBundle: LocationMessage): GenericMessage {
568
- const {expectsReadConfirmation, latitude, legalHoldStatus, longitude, name, zoom} = payloadBundle.content;
569
-
570
- const locationMessage = Location.create({
571
- expectsReadConfirmation,
572
- latitude,
573
- legalHoldStatus,
574
- longitude,
575
- name,
576
- zoom,
577
- });
578
-
579
- const genericMessage = GenericMessage.create({
580
- [GenericMessageType.LOCATION]: locationMessage,
581
- messageId: payloadBundle.id,
582
- });
583
-
584
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
585
- return expireAfterMillis > 0 ? this.createEphemeral(genericMessage, expireAfterMillis) : genericMessage;
586
- }
587
-
588
- private generatePingGenericMessage(payloadBundle: PingMessage): GenericMessage {
589
- const content = Knock.create(payloadBundle.content);
590
-
591
- const genericMessage = GenericMessage.create({
592
- [GenericMessageType.KNOCK]: content,
593
- messageId: payloadBundle.id,
594
- });
595
-
596
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
597
- return expireAfterMillis > 0 ? this.createEphemeral(genericMessage, expireAfterMillis) : genericMessage;
598
- }
599
-
600
- private generateReactionGenericMessage(payloadBundle: ReactionMessage): GenericMessage {
601
- const {legalHoldStatus, originalMessageId, type} = payloadBundle.content;
602
-
603
- const reaction = Reaction.create({
604
- emoji: type,
605
- legalHoldStatus,
606
- messageId: originalMessageId,
607
- });
608
-
609
- const genericMessage = GenericMessage.create({
610
- [GenericMessageType.REACTION]: reaction,
611
- messageId: payloadBundle.id,
612
- });
613
- return genericMessage;
614
- }
615
-
616
- private generateSessionResetGenericMessage(payloadBundle: ResetSessionMessage): GenericMessage {
617
- return GenericMessage.create({
618
- [GenericMessageType.CLIENT_ACTION]: ClientAction.RESET_SESSION,
619
- messageId: payloadBundle.id,
620
- });
621
- }
622
-
623
- private generateCallGenericMessage(payloadBundle: CallMessage): GenericMessage {
624
- const callMessage = Calling.create({
625
- content: payloadBundle.content,
626
- });
627
-
628
- return GenericMessage.create({
629
- [GenericMessageType.CALLING]: callMessage,
630
- messageId: payloadBundle.id,
631
- });
632
- }
633
-
634
- private generateTextGenericMessage(payloadBundle: TextMessage): GenericMessage {
635
- const genericMessage = GenericMessage.create({
636
- messageId: payloadBundle.id,
637
- [GenericMessageType.TEXT]: MessageToProtoMapper.mapText(payloadBundle),
638
- });
639
-
640
- const expireAfterMillis = this.messageTimer.getMessageTimer(payloadBundle.conversation);
641
- return expireAfterMillis > 0 ? this.createEphemeral(genericMessage, expireAfterMillis) : genericMessage;
642
- }
643
-
644
- public async clearConversation(
645
- conversationId: string,
646
- timestamp: number | Date = new Date(),
647
- messageId: string = MessageBuilder.createId(),
648
- sendAsProtobuf?: boolean,
649
- conversationDomain?: string,
650
- ): Promise<ClearConversationMessage> {
651
- if (timestamp instanceof Date) {
652
- timestamp = timestamp.getTime();
653
- }
654
-
655
- const content: ClearedContent = {
656
- clearedTimestamp: timestamp,
657
- conversationId,
658
- };
659
-
660
- const clearedMessage = Cleared.create(content);
661
-
662
- const genericMessage = GenericMessage.create({
663
- [GenericMessageType.CLEARED]: clearedMessage,
664
- messageId,
665
- });
666
-
667
- const {id: selfConversationId} = await this.getSelfConversation();
668
-
669
- await this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, {
670
- conversationDomain,
671
- sendAsProtobuf,
672
- });
673
-
674
- return {
675
- content,
676
- conversation: conversationId,
677
- from: this.apiClient.context!.userId,
678
- id: messageId,
679
- messageTimer: 0,
680
- source: PayloadBundleSource.LOCAL,
681
- state: PayloadBundleState.OUTGOING_SENT,
682
- timestamp: Date.now(),
683
- type: PayloadBundleType.CONVERSATION_CLEAR,
684
- };
685
- }
686
-
687
- public async deleteMessageLocal(
688
- conversationId: string,
689
- messageIdToHide: string,
690
- sendAsProtobuf?: boolean,
691
- conversationDomain?: string,
692
- ): Promise<HideMessage> {
693
- const messageId = MessageBuilder.createId();
694
-
695
- const content: HiddenContent = MessageHide.create({
696
- conversationId,
697
- messageId: messageIdToHide,
698
- });
699
-
700
- const genericMessage = GenericMessage.create({
701
- [GenericMessageType.HIDDEN]: content,
702
- messageId,
703
- });
704
-
705
- const {id: selfConversationId} = await this.getSelfConversation();
706
-
707
- await this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, {
708
- sendAsProtobuf,
709
- conversationDomain,
710
- });
711
-
712
- return {
713
- content,
714
- conversation: conversationId,
715
- from: this.apiClient.context!.userId,
716
- id: messageId,
717
- messageTimer: this.messageTimer.getMessageTimer(conversationId),
718
- source: PayloadBundleSource.LOCAL,
719
- state: PayloadBundleState.OUTGOING_SENT,
720
- timestamp: Date.now(),
721
- type: PayloadBundleType.MESSAGE_HIDE,
722
- };
723
- }
724
-
725
- public async deleteMessageEveryone(
726
- conversationId: string,
727
- messageIdToDelete: string,
728
- userIds?: string[] | QualifiedId[] | UserClients | QualifiedUserClients,
729
- sendAsProtobuf?: boolean,
730
- conversationDomain?: string,
731
- callbacks?: MessageSendingCallbacks,
732
- ): Promise<DeleteMessage> {
733
- const messageId = MessageBuilder.createId();
734
-
735
- const content: DeletedContent = MessageDelete.create({
736
- messageId: messageIdToDelete,
737
- });
738
-
739
- const genericMessage = GenericMessage.create({
740
- [GenericMessageType.DELETED]: content,
741
- messageId,
742
- });
743
- callbacks?.onStart?.(genericMessage);
744
-
745
- const response = await this.sendGenericMessage(this.apiClient.validatedClientId, conversationId, genericMessage, {
746
- userIds,
747
- sendAsProtobuf,
748
- conversationDomain,
749
- });
750
- callbacks?.onSuccess?.(genericMessage, response?.time);
751
-
752
- return {
753
- content,
754
- conversation: conversationId,
755
- from: this.apiClient.context!.userId,
756
- id: messageId,
757
- messageTimer: this.messageTimer.getMessageTimer(conversationId),
758
- source: PayloadBundleSource.LOCAL,
759
- state: PayloadBundleState.OUTGOING_SENT,
760
- timestamp: Date.now(),
761
- type: PayloadBundleType.MESSAGE_DELETE,
762
- };
763
- }
764
-
765
- public leaveConversation(conversationId: string): Promise<ConversationMemberLeaveEvent> {
766
- return this.apiClient.conversation.api.deleteMember(conversationId, this.apiClient.context!.userId);
767
- }
768
-
769
- public async leaveConversations(conversationIds?: string[]): Promise<ConversationMemberLeaveEvent[]> {
770
- if (!conversationIds) {
771
- const conversation = await this.getConversations();
772
- conversationIds = conversation
773
- .filter(conversation => conversation.type === CONVERSATION_TYPE.REGULAR)
774
- .map(conversation => conversation.id);
775
- }
776
-
777
- return Promise.all(conversationIds.map(conversationId => this.leaveConversation(conversationId)));
778
- }
779
-
780
- public createConversation(name: string, otherUserIds: string | string[] = []): Promise<Conversation> {
781
- const ids = typeof otherUserIds === 'string' ? [otherUserIds] : otherUserIds;
782
-
783
- const newConversation: NewConversation = {
784
- name,
785
- receipt_mode: null,
786
- users: ids,
787
- };
788
-
789
- return this.apiClient.conversation.api.postConversation(newConversation);
790
- }
791
-
792
- public async getConversations(conversationId: string): Promise<Conversation>;
793
- public async getConversations(conversationIds?: string[]): Promise<Conversation[]>;
794
- public async getConversations(conversationIds?: string | string[]): Promise<Conversation[] | Conversation> {
795
- if (!conversationIds || !conversationIds.length) {
796
- return this.apiClient.conversation.api.getAllConversations();
797
- }
798
- if (typeof conversationIds === 'string') {
799
- return this.apiClient.conversation.api.getConversation(conversationIds);
800
- }
801
- return this.apiClient.conversation.api.getConversationsByIds(conversationIds);
802
- }
803
-
804
- public async getAsset({assetId, assetToken, otrKey, sha256}: RemoteData): Promise<Buffer> {
805
- const request = await this.apiClient.asset.api.getAssetV3(assetId, assetToken);
806
- const encryptedBuffer = (await request.response).buffer;
807
-
808
- return AssetCryptography.decryptAsset({
809
- cipherText: Buffer.from(encryptedBuffer),
810
- keyBytes: Buffer.from(otrKey),
811
- sha256: Buffer.from(sha256),
812
- });
813
- }
814
-
815
- public async getUnencryptedAsset(assetId: string, assetToken?: string): Promise<ArrayBuffer> {
816
- const request = await this.apiClient.asset.api.getAssetV3(assetId, assetToken);
817
- return (await request.response).buffer;
818
- }
819
-
820
- public async addUser<T extends string | string[] | QualifiedId | QualifiedId[]>(
821
- conversationId: string,
822
- userIds: T,
823
- ): Promise<T> {
824
- const ids = Array.isArray(userIds) ? userIds : [userIds];
825
- if (isStringArray(ids)) {
826
- await this.apiClient.conversation.api.postMembers(conversationId, ids);
827
- } else if (isQualifiedIdArray(ids)) {
828
- await this.apiClient.conversation.api.postMembersV2(conversationId, ids);
829
- }
830
-
831
- return userIds;
832
- }
833
-
834
- public async removeUser(conversationId: string, userId: string): Promise<string> {
835
- await this.apiClient.conversation.api.deleteMember(conversationId, userId);
836
- return userId;
837
- }
838
-
839
- /**
840
- * Sends a message to a conversation
841
- *
842
- * @param params.payloadBundle The message to send to the conversation
843
- * @param params.userIds? Can be either a QualifiedId[], string[], UserClients or QualfiedUserClients. The type has some effect on the behavior of the method.
844
- * When given a QualifiedId[] or string[] the method will fetch the freshest list of devices for those users (since they are not given by the consumer). As a consequence no ClientMismatch error will trigger and we will ignore missing clients when sending
845
- * When given a QualifiedUserClients or UserClients the method will only send to the clients listed in the userIds. This could lead to ClientMismatch (since the given list of devices might not be the freshest one and new clients could have been created)
846
- * When given a QualifiedId[] or QualifiedUserClients the method will send the message through the federated API endpoint
847
- * When given a string[] or UserClients the method will send the message through the old API endpoint
848
- * @param callbacks.onStart Will be called before a message is actually sent. Returning 'false' will prevent the message from being sent
849
- * @param callbacks.onClientMismatch? Will be called when a mismatch happens. Returning `false` from the callback will stop the sending attempt
850
- * @return resolves with the sent message
851
- */
852
- public async send<T extends OtrMessage = OtrMessage>({
853
- payloadBundle,
854
- userIds,
855
- sendAsProtobuf,
856
- conversationDomain,
857
- nativePush,
858
- targetMode,
859
- callbacks,
860
- }: {
861
- payloadBundle: T;
862
- userIds?: string[] | QualifiedId[] | UserClients | QualifiedUserClients;
863
- callbacks?: MessageSendingCallbacks;
864
- } & MessageSendingOptions): Promise<T> {
865
- let genericMessage: GenericMessage;
866
- let processedContent: AssetContent | undefined = undefined;
867
-
868
- switch (payloadBundle.type) {
869
- case PayloadBundleType.ASSET:
870
- genericMessage = this.generateFileDataGenericMessage(payloadBundle);
871
- break;
872
- case PayloadBundleType.ASSET_ABORT:
873
- genericMessage = this.generateFileAbortGenericMessage(payloadBundle);
874
- break;
875
- case PayloadBundleType.ASSET_META:
876
- genericMessage = this.generateFileMetaDataGenericMessage(payloadBundle);
877
- break;
878
- case PayloadBundleType.ASSET_IMAGE:
879
- const res = this.generateImageGenericMessage(payloadBundle as ImageAssetMessageOutgoing);
880
- genericMessage = res.genericMessage;
881
- processedContent = res.content;
882
- break;
883
- case PayloadBundleType.BUTTON_ACTION:
884
- genericMessage = this.generateButtonActionGenericMessage(payloadBundle);
885
- break;
886
- case PayloadBundleType.BUTTON_ACTION_CONFIRMATION:
887
- genericMessage = this.generateButtonActionConfirmationGenericMessage(payloadBundle);
888
- break;
889
- case PayloadBundleType.CALL:
890
- genericMessage = this.generateCallGenericMessage(payloadBundle);
891
- break;
892
- case PayloadBundleType.CLIENT_ACTION: {
893
- if (payloadBundle.content.clientAction !== ClientAction.RESET_SESSION) {
894
- throw new Error(
895
- `No send method implemented for "${payloadBundle.type}" and ClientAction "${payloadBundle.content}".`,
896
- );
897
- }
898
- genericMessage = this.generateSessionResetGenericMessage(payloadBundle);
899
- break;
900
- }
901
- case PayloadBundleType.COMPOSITE:
902
- genericMessage = this.generateCompositeGenericMessage(payloadBundle);
903
- break;
904
- case PayloadBundleType.CONFIRMATION:
905
- genericMessage = this.generateConfirmationGenericMessage(payloadBundle);
906
- break;
907
- case PayloadBundleType.LOCATION:
908
- genericMessage = this.generateLocationGenericMessage(payloadBundle);
909
- break;
910
- case PayloadBundleType.MESSAGE_EDIT:
911
- genericMessage = this.generateEditedTextGenericMessage(payloadBundle);
912
- break;
913
- case PayloadBundleType.PING:
914
- genericMessage = this.generatePingGenericMessage(payloadBundle);
915
- break;
916
- case PayloadBundleType.REACTION:
917
- genericMessage = this.generateReactionGenericMessage(payloadBundle);
918
- break;
919
- case PayloadBundleType.TEXT:
920
- genericMessage = this.generateTextGenericMessage(payloadBundle);
921
- break;
922
- default:
923
- throw new Error(`No send method implemented for "${payloadBundle['type']}".`);
924
- }
925
-
926
- if ((await callbacks?.onStart?.(genericMessage)) === false) {
927
- // If the onStart call returns false, it means the consumer wants to cancel the message sending
928
- return {...payloadBundle, state: PayloadBundleState.CANCELLED};
929
- }
930
-
931
- const response = await this.sendGenericMessage(
932
- this.apiClient.validatedClientId,
933
- payloadBundle.conversation,
934
- genericMessage,
935
- {
936
- userIds,
937
- sendAsProtobuf,
938
- conversationDomain,
939
- nativePush,
940
- targetMode,
941
- onClientMismatch: callbacks?.onClientMismatch,
942
- },
943
- );
944
-
945
- if (!response.errored) {
946
- callbacks?.onSuccess?.(genericMessage, response.time);
947
- if (!this.isClearFromMismatch(response)) {
948
- // We warn the consumer that there is a mismatch that did not prevent message sending
949
- callbacks?.onClientMismatch?.(response, true);
950
- }
951
- }
952
-
953
- return {
954
- ...payloadBundle,
955
- content: processedContent || payloadBundle.content,
956
- messageTimer: genericMessage.ephemeral?.expireAfterMillis || 0,
957
- state: response.errored ? PayloadBundleState.CANCELLED : PayloadBundleState.OUTGOING_SENT,
958
- };
959
- }
960
-
961
- public sendTypingStart(conversationId: string): Promise<void> {
962
- return this.apiClient.conversation.api.postTyping(conversationId, {status: CONVERSATION_TYPING.STARTED});
963
- }
964
-
965
- public sendTypingStop(conversationId: string): Promise<void> {
966
- return this.apiClient.conversation.api.postTyping(conversationId, {status: CONVERSATION_TYPING.STOPPED});
967
- }
968
-
969
- public setConversationMutedStatus(
970
- conversationId: string,
971
- status: MutedStatus,
972
- muteTimestamp: number | Date,
973
- ): Promise<void> {
974
- if (typeof muteTimestamp === 'number') {
975
- muteTimestamp = new Date(muteTimestamp);
976
- }
977
-
978
- const payload: ConversationMemberUpdateData = {
979
- otr_muted_ref: muteTimestamp.toISOString(),
980
- otr_muted_status: status,
981
- };
982
-
983
- return this.apiClient.conversation.api.putMembershipProperties(conversationId, payload);
984
- }
985
-
986
- public toggleArchiveConversation(
987
- conversationId: string,
988
- archived: boolean,
989
- archiveTimestamp: number | Date = new Date(),
990
- ): Promise<void> {
991
- if (typeof archiveTimestamp === 'number') {
992
- archiveTimestamp = new Date(archiveTimestamp);
993
- }
994
-
995
- const payload: ConversationMemberUpdateData = {
996
- otr_archived: archived,
997
- otr_archived_ref: archiveTimestamp.toISOString(),
998
- };
999
-
1000
- return this.apiClient.conversation.api.putMembershipProperties(conversationId, payload);
1001
- }
1002
-
1003
- public setMemberConversationRole(
1004
- conversationId: string,
1005
- userId: string,
1006
- conversationRole: DefaultConversationRoleName | string,
1007
- ): Promise<void> {
1008
- return this.apiClient.conversation.api.putOtherMember(userId, conversationId, {
1009
- conversation_role: conversationRole,
1010
- });
1011
- }
1012
-
1013
- private isClearFromMismatch(mismatch: ClientMismatch | MessageSendingStatus): boolean {
1014
- const hasMissing = Object.keys(mismatch.missing || {}).length > 0;
1015
- const hasDeleted = Object.keys(mismatch.deleted || {}).length > 0;
1016
- const hasRedundant = Object.keys(mismatch.redundant || {}).length > 0;
1017
- const hasFailed = Object.keys((mismatch as MessageSendingStatus).failed_to_send || {}).length > 0;
1018
- return !hasMissing && !hasDeleted && !hasRedundant && !hasFailed;
1019
- }
1020
- }