@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.
- package/package.json +9 -8
- package/src/main/Account.d.ts +214 -0
- package/src/main/Account.js +463 -0
- package/src/main/CoreError.d.ts +9 -0
- package/src/main/CoreError.js +26 -0
- package/src/main/account/AccountService.d.ts +7 -0
- package/src/main/account/AccountService.js +33 -0
- package/src/main/account/AccountService.js.map +1 -0
- package/src/main/account/index.d.ts +1 -0
- package/src/main/account/index.js +36 -0
- package/src/main/account/index.js.map +1 -0
- package/src/main/auth/LoginSanitizer.d.ts +5 -0
- package/src/main/auth/LoginSanitizer.js +41 -0
- package/src/main/auth/index.d.ts +1 -0
- package/src/main/auth/index.js +36 -0
- package/src/main/broadcast/AvailabilityType.d.ts +2 -0
- package/src/main/broadcast/AvailabilityType.js +21 -0
- package/src/main/broadcast/BroadcastService.d.ts +24 -0
- package/src/main/broadcast/BroadcastService.js +74 -0
- package/src/main/broadcast/index.d.ts +2 -0
- package/src/main/broadcast/index.js +37 -0
- package/src/main/client/ClientBackendRepository.d.ts +11 -0
- package/src/main/client/ClientBackendRepository.js +43 -0
- package/src/main/client/ClientDatabaseRepository.d.ts +27 -0
- package/src/main/client/ClientDatabaseRepository.js +85 -0
- package/src/main/client/ClientInfo.d.ts +8 -0
- package/src/main/client/ClientInfo.js +21 -0
- package/src/main/client/ClientService.d.ts +40 -0
- package/src/main/client/ClientService.js +103 -0
- package/src/main/client/index.d.ts +4 -0
- package/src/main/client/index.js +39 -0
- package/src/main/connection/ConnectionService.d.ts +11 -0
- package/src/main/connection/ConnectionService.js +45 -0
- package/src/main/connection/index.d.ts +1 -0
- package/src/main/connection/index.js +36 -0
- package/src/main/conversation/AbortReason.d.ts +2 -0
- package/src/main/conversation/AbortReason.js +21 -0
- package/src/main/conversation/AssetService/AssetService.d.ts +62 -0
- package/src/main/conversation/AssetService/AssetService.js +88 -0
- package/src/main/conversation/AssetService/index.d.ts +1 -0
- package/src/main/conversation/AssetService/index.js +36 -0
- package/src/main/conversation/AssetTransferState.d.ts +4 -0
- package/src/main/conversation/AssetTransferState.js +27 -0
- package/src/main/conversation/ClientActionType.d.ts +1 -0
- package/src/main/conversation/ClientActionType.js +24 -0
- package/src/main/conversation/ConversationMapper/ConversationMapper.d.ts +6 -0
- package/src/main/conversation/ConversationMapper/ConversationMapper.js +57 -0
- package/src/main/conversation/ConversationMapper/index.d.ts +1 -0
- package/src/main/conversation/ConversationMapper/index.js +36 -0
- package/src/main/conversation/ConversationService/ConversationService.d.ts +149 -0
- package/src/main/conversation/ConversationService/ConversationService.js +584 -0
- package/src/main/conversation/ConversationService/ConversationService.types.d.ts +110 -0
- package/src/main/conversation/ConversationService/ConversationService.types.js +28 -0
- package/src/main/conversation/ConversationService/index.d.ts +2 -0
- package/src/main/conversation/ConversationService/index.js +37 -0
- package/src/main/conversation/ConversationService/messageGenerator.d.ts +9 -0
- package/src/main/conversation/ConversationService/messageGenerator.js +313 -0
- package/src/main/conversation/GenericMessageType.d.ts +25 -0
- package/src/main/conversation/GenericMessageType.js +49 -0
- package/src/main/conversation/MessageTimer/MessageTimer.d.ts +10 -0
- package/src/main/conversation/MessageTimer/MessageTimer.js +54 -0
- package/src/main/conversation/MessageTimer/index.d.ts +1 -0
- package/src/main/conversation/MessageTimer/index.js +36 -0
- package/src/main/conversation/ReactionType.d.ts +4 -0
- package/src/main/conversation/ReactionType.js +27 -0
- package/src/main/conversation/content/AssetContent.d.ts +42 -0
- package/src/main/conversation/content/AssetContent.js +21 -0
- package/src/main/conversation/content/ButtonActionConfirmationContent.d.ts +2 -0
- package/src/main/conversation/content/ButtonActionConfirmationContent.js +21 -0
- package/src/main/conversation/content/ButtonActionContent.d.ts +2 -0
- package/src/main/conversation/content/ButtonActionContent.js +21 -0
- package/src/main/conversation/content/CallingContent.d.ts +1 -0
- package/src/main/conversation/content/CallingContent.js +21 -0
- package/src/main/conversation/content/ClearedContent.d.ts +2 -0
- package/src/main/conversation/content/ClearedContent.js +21 -0
- package/src/main/conversation/content/ClientActionContent.d.ts +2 -0
- package/src/main/conversation/content/ClientActionContent.js +21 -0
- package/src/main/conversation/content/ClientAddContent.d.ts +4 -0
- package/src/main/conversation/content/ClientAddContent.js +21 -0
- package/src/main/conversation/content/ClientRemoveContent.d.ts +6 -0
- package/src/main/conversation/content/ClientRemoveContent.js +21 -0
- package/src/main/conversation/content/CompositeContent.d.ts +2 -0
- package/src/main/conversation/content/CompositeContent.js +21 -0
- package/src/main/conversation/content/ConfirmationContent.d.ts +2 -0
- package/src/main/conversation/content/ConfirmationContent.js +21 -0
- package/src/main/conversation/content/ContentType.d.ts +21 -0
- package/src/main/conversation/content/ContentType.js +94 -0
- package/src/main/conversation/content/ConversationContent.d.ts +3 -0
- package/src/main/conversation/content/ConversationContent.js +21 -0
- package/src/main/conversation/content/DeletedContent.d.ts +2 -0
- package/src/main/conversation/content/DeletedContent.js +21 -0
- package/src/main/conversation/content/EditedTextContent.d.ts +11 -0
- package/src/main/conversation/content/EditedTextContent.js +21 -0
- package/src/main/conversation/content/FileContent.d.ts +13 -0
- package/src/main/conversation/content/FileContent.js +21 -0
- package/src/main/conversation/content/HiddenContent.d.ts +2 -0
- package/src/main/conversation/content/HiddenContent.js +21 -0
- package/src/main/conversation/content/ImageContent.d.ts +7 -0
- package/src/main/conversation/content/ImageContent.js +21 -0
- package/src/main/conversation/content/KnockContent.d.ts +2 -0
- package/src/main/conversation/content/KnockContent.js +21 -0
- package/src/main/conversation/content/LinkPreviewContent.d.ts +10 -0
- package/src/main/conversation/content/LinkPreviewContent.js +21 -0
- package/src/main/conversation/content/LocationContent.d.ts +9 -0
- package/src/main/conversation/content/LocationContent.js +21 -0
- package/src/main/conversation/content/MentionContent.d.ts +2 -0
- package/src/main/conversation/content/MentionContent.js +21 -0
- package/src/main/conversation/content/QuoteContent.d.ts +7 -0
- package/src/main/conversation/content/QuoteContent.js +21 -0
- package/src/main/conversation/content/ReactionContent.d.ts +7 -0
- package/src/main/conversation/content/ReactionContent.js +21 -0
- package/src/main/conversation/content/TextContent.d.ts +9 -0
- package/src/main/conversation/content/TextContent.js +21 -0
- package/src/main/conversation/content/TweetContent.d.ts +2 -0
- package/src/main/conversation/content/TweetContent.js +21 -0
- package/src/main/conversation/content/index.d.ts +28 -0
- package/src/main/conversation/content/index.js +76 -0
- package/src/main/conversation/index.d.ts +9 -0
- package/src/main/conversation/index.js +44 -0
- package/src/main/conversation/message/CompositeContentBuilder.d.ts +14 -0
- package/src/main/conversation/message/CompositeContentBuilder.js +54 -0
- package/src/main/conversation/message/Message.d.ts +4 -0
- package/src/main/conversation/message/Message.js +21 -0
- package/src/main/conversation/message/MessageBuilder.d.ts +96 -0
- package/src/main/conversation/message/MessageBuilder.js +125 -0
- package/src/main/conversation/message/MessageService.d.ts +67 -0
- package/src/main/conversation/message/MessageService.js +293 -0
- package/src/main/conversation/message/MessageToProtoMapper.d.ts +7 -0
- package/src/main/conversation/message/MessageToProtoMapper.js +99 -0
- package/src/main/conversation/message/OtrMessage.d.ts +80 -0
- package/src/main/conversation/message/OtrMessage.js +21 -0
- package/src/main/conversation/message/PayloadBundle.d.ts +76 -0
- package/src/main/conversation/message/PayloadBundle.js +81 -0
- package/src/main/conversation/message/TeamMessage.d.ts +31 -0
- package/src/main/conversation/message/TeamMessage.js +21 -0
- package/src/main/conversation/message/TextContentBuilder.d.ts +13 -0
- package/src/main/conversation/message/TextContentBuilder.js +75 -0
- package/src/main/conversation/message/UserClientsUtil.d.ts +22 -0
- package/src/main/conversation/message/UserClientsUtil.js +38 -0
- package/src/main/conversation/message/UserMessage.d.ts +43 -0
- package/src/main/conversation/message/UserMessage.js +21 -0
- package/src/main/conversation/message/messageSender.d.ts +4 -0
- package/src/main/conversation/message/messageSender.js +36 -0
- package/src/main/cryptography/AssetCryptography/EncryptedAsset.d.ts +11 -0
- package/src/main/cryptography/AssetCryptography/EncryptedAsset.js +21 -0
- package/src/main/cryptography/AssetCryptography/crypto.browser.d.ts +2 -0
- package/src/main/cryptography/AssetCryptography/crypto.browser.js +46 -0
- package/src/main/cryptography/AssetCryptography/crypto.node.d.ts +2 -0
- package/src/main/cryptography/AssetCryptography/crypto.node.js +72 -0
- package/src/main/cryptography/AssetCryptography/index.d.ts +8 -0
- package/src/main/cryptography/AssetCryptography/index.js +53 -0
- package/src/main/cryptography/AssetCryptography/interfaces.d.ts +9 -0
- package/src/main/cryptography/AssetCryptography/interfaces.js +21 -0
- package/src/main/cryptography/CryptographyDatabaseRepository.d.ts +16 -0
- package/src/main/cryptography/CryptographyDatabaseRepository.js +44 -0
- package/src/main/cryptography/CryptographyService.d.ts +52 -0
- package/src/main/cryptography/CryptographyService.js +205 -0
- package/src/main/cryptography/GenericMessageMapper.d.ts +6 -0
- package/src/main/cryptography/GenericMessageMapper.js +160 -0
- package/src/main/cryptography/MessageHashService.d.ts +16 -0
- package/src/main/cryptography/MessageHashService.js +118 -0
- package/src/main/cryptography/SessionPayloadBundle.d.ts +4 -0
- package/src/main/cryptography/SessionPayloadBundle.js +21 -0
- package/src/main/cryptography/index.d.ts +4 -0
- package/src/main/cryptography/index.js +39 -0
- package/src/main/giphy/GiphyService.d.ts +9 -0
- package/src/main/giphy/GiphyService.js +37 -0
- package/src/main/giphy/index.d.ts +1 -0
- package/src/main/giphy/index.js +36 -0
- package/src/main/index.d.ts +17 -0
- package/src/main/index.js +59 -0
- package/src/main/linkPreview/LinkPreviewService.d.ts +7 -0
- package/src/main/linkPreview/LinkPreviewService.js +52 -0
- package/src/main/linkPreview/index.d.ts +1 -0
- package/src/main/linkPreview/index.js +36 -0
- package/src/main/mls/MLSService/MLSService.d.ts +39 -0
- package/src/main/mls/MLSService/MLSService.js +181 -0
- package/src/main/mls/index.d.ts +1 -0
- package/src/main/mls/index.js +36 -0
- package/src/main/mls/keyMaterialUpdatesStore/index.d.ts +1 -0
- package/src/main/mls/keyMaterialUpdatesStore/index.js +36 -0
- package/src/main/mls/keyMaterialUpdatesStore/keyMaterialUpdatesStore.d.ts +9 -0
- package/src/main/mls/keyMaterialUpdatesStore/keyMaterialUpdatesStore.js +51 -0
- package/src/main/mls/keyPackagesStatusStore/keyPackagesStatusStore.d.ts +7 -0
- package/src/main/mls/keyPackagesStatusStore/keyPackagesStatusStore.js +42 -0
- package/src/main/mls/types.d.ts +33 -0
- package/src/main/mls/types.js +21 -0
- package/src/main/notification/NotificationBackendRepository.d.ts +11 -0
- package/src/main/notification/NotificationBackendRepository.js +34 -0
- package/src/main/notification/NotificationDatabaseRepository.d.ts +42 -0
- package/src/main/notification/NotificationDatabaseRepository.js +97 -0
- package/src/main/notification/NotificationService.d.ts +129 -0
- package/src/main/notification/NotificationService.js +501 -0
- package/src/main/notification/index.d.ts +1 -0
- package/src/main/notification/index.js +36 -0
- package/src/main/notification/types.d.ts +16 -0
- package/src/main/notification/types.js +21 -0
- package/src/main/self/SelfService.d.ts +13 -0
- package/src/main/self/SelfService.js +55 -0
- package/src/main/self/index.d.ts +1 -0
- package/src/main/self/index.js +36 -0
- package/src/main/team/TeamService.d.ts +15 -0
- package/src/main/team/TeamService.js +55 -0
- package/src/main/team/index.d.ts +1 -0
- package/src/main/team/index.js +36 -0
- package/src/main/test/CryptographyHelper.d.ts +4 -0
- package/src/main/test/CryptographyHelper.js +69 -0
- package/src/main/test/PayloadHelper.d.ts +3 -0
- package/src/main/test/PayloadHelper.js +66 -0
- package/src/main/user/UserMapper.d.ts +5 -0
- package/src/main/user/UserMapper.js +88 -0
- package/src/main/user/UserService.d.ts +25 -0
- package/src/main/user/UserService.js +81 -0
- package/src/main/user/index.d.ts +1 -0
- package/src/main/user/index.js +36 -0
- package/src/main/util/LowPrecisionTaskScheduler/LowPrecisionTaskScheduler.d.ts +21 -0
- package/src/main/util/LowPrecisionTaskScheduler/LowPrecisionTaskScheduler.js +62 -0
- package/src/main/util/TaskScheduler/TaskScheduler.d.ts +10 -0
- package/src/main/util/TaskScheduler/TaskScheduler.js +70 -0
- package/src/main/util/TypePredicateUtil.d.ts +7 -0
- package/src/main/util/TypePredicateUtil.js +55 -0
- package/src/main/util/encryptedStore.d.ts +45 -0
- package/src/main/util/encryptedStore.js +116 -0
- package/src/main/util/fullyQualifiedClientIdUtils.d.ts +13 -0
- package/src/main/util/fullyQualifiedClientIdUtils.js +42 -0
- package/src/main/util/index.d.ts +1 -0
- 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
|