@wireapp/core 28.4.7 → 28.5.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.
- package/CHANGELOG.md +27 -0
- package/package.json +4 -6
- package/src/main/Account.js +2 -2
- package/src/main/conversation/ConversationService.d.ts +19 -18
- package/src/main/conversation/ConversationService.js +4 -19
- package/src/main/conversation/message/PayloadBundle.d.ts +1 -0
- package/src/main/conversation/message/PayloadBundle.js +1 -0
- package/src/main/cryptography/CryptographyDatabaseRepository.d.ts +2 -1
- package/src/main/cryptography/CryptographyDatabaseRepository.js +2 -0
- package/src/main/notification/NotificationDatabaseRepository.d.ts +9 -0
- package/src/main/notification/NotificationDatabaseRepository.js +10 -0
- package/src/main/notification/NotificationService.d.ts +20 -1
- package/src/main/notification/NotificationService.js +72 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [28.5.2](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@28.5.1...@wireapp/core@28.5.2) (2022-07-18)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @wireapp/core
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [28.5.1](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@28.5.0...@wireapp/core@28.5.1) (2022-07-15)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @wireapp/core
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# [28.5.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@28.4.7...@wireapp/core@28.5.0) (2022-07-15)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* Decrypt incoming MLS messages ([#4315](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4315)) ([c93b0ae](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/c93b0aea0a43f5eef204d5a20ca047215d6998d6))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
6
33
|
## [28.4.7](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@28.4.6...@wireapp/core@28.4.7) (2022-07-15)
|
|
7
34
|
|
|
8
35
|
**Note:** Version bump only for package @wireapp/core
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"@otak/core-crypto": "0.3.0-beta-1",
|
|
8
8
|
"@types/long": "4.0.1",
|
|
9
9
|
"@types/node": "~14",
|
|
10
|
-
"@wireapp/api-client": "19.
|
|
10
|
+
"@wireapp/api-client": "19.15.2",
|
|
11
11
|
"@wireapp/commons": "4.3.0",
|
|
12
12
|
"@wireapp/cryptobox": "12.8.0",
|
|
13
13
|
"@wireapp/store-engine-dexie": "1.6.10",
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
"karma-spec-reporter": "0.0.32",
|
|
43
43
|
"mock-socket": "9.0.3",
|
|
44
44
|
"nock": "13.1.1",
|
|
45
|
-
"nodemon": "2.0.19",
|
|
46
45
|
"nyc": "15.1.0",
|
|
47
46
|
"rimraf": "3.0.2",
|
|
48
47
|
"typescript": "4.4.2",
|
|
@@ -76,9 +75,8 @@
|
|
|
76
75
|
"test:browser": "webpack --mode=development && karma start",
|
|
77
76
|
"test:project": "yarn dist && yarn test",
|
|
78
77
|
"test:node": "nyc jasmine --config=jasmine.json",
|
|
79
|
-
"watch": "tsc ---watch"
|
|
80
|
-
"test:watch": "nodemon --ext ts --exec 'yarn test:node'"
|
|
78
|
+
"watch": "tsc ---watch"
|
|
81
79
|
},
|
|
82
|
-
"version": "28.
|
|
83
|
-
"gitHead": "
|
|
80
|
+
"version": "28.5.2",
|
|
81
|
+
"gitHead": "3672473cb01c76c33ea73d14a0f8a19e1b97bccb"
|
|
84
82
|
}
|
package/src/main/Account.js
CHANGED
|
@@ -229,11 +229,11 @@ class Account extends events_1.EventEmitter {
|
|
|
229
229
|
const connectionService = new connection_1.ConnectionService(this.apiClient);
|
|
230
230
|
const giphyService = new giphy_1.GiphyService(this.apiClient);
|
|
231
231
|
const linkPreviewService = new linkPreview_1.LinkPreviewService(assetService);
|
|
232
|
+
const notificationService = new notification_1.NotificationService(this.apiClient, cryptographyService, this.storeEngine, () => this.coreCryptoClient);
|
|
232
233
|
const conversationService = new conversation_1.ConversationService(this.apiClient, cryptographyService, {
|
|
233
234
|
// We can use qualified ids to send messages as long as the backend supports federated endpoints
|
|
234
235
|
useQualifiedIds: this.backendFeatures.federationEndpoints,
|
|
235
|
-
}, () => this.coreCryptoClient);
|
|
236
|
-
const notificationService = new notification_1.NotificationService(this.apiClient, cryptographyService, this.storeEngine);
|
|
236
|
+
}, () => this.coreCryptoClient, notificationService);
|
|
237
237
|
const selfService = new self_1.SelfService(this.apiClient);
|
|
238
238
|
const teamService = new team_1.TeamService(this.apiClient);
|
|
239
239
|
const broadcastService = new broadcast_1.BroadcastService(this.apiClient, cryptographyService);
|
|
@@ -9,22 +9,39 @@ import type { RemoteData } from '../conversation/content/';
|
|
|
9
9
|
import type { CryptographyService } from '../cryptography/';
|
|
10
10
|
import type { ClearConversationMessage, DeleteMessage, HideMessage, OtrMessage } from './message/OtrMessage';
|
|
11
11
|
import { XOR } from '@wireapp/commons/src/main/util/TypeUtil';
|
|
12
|
+
import type { NotificationService } from '../notification';
|
|
12
13
|
export declare enum MessageTargetMode {
|
|
13
14
|
NONE = 0,
|
|
14
15
|
USERS = 1,
|
|
15
16
|
USERS_CLIENTS = 2
|
|
16
17
|
}
|
|
17
18
|
interface SendCommonParams<T> {
|
|
19
|
+
/**
|
|
20
|
+
* The protocol to use to send the message (MLS or Proteus)
|
|
21
|
+
*/
|
|
18
22
|
protocol: ConversationProtocol;
|
|
23
|
+
/**
|
|
24
|
+
* The message to send to the conversation
|
|
25
|
+
*/
|
|
19
26
|
payload: T;
|
|
20
27
|
onStart?: (message: GenericMessage) => void | boolean | Promise<boolean>;
|
|
21
28
|
onSuccess?: (message: GenericMessage, sentTime?: string) => void;
|
|
22
29
|
}
|
|
23
30
|
declare type SendProteusMessageParams<T> = SendCommonParams<T> & MessageSendingOptions & {
|
|
31
|
+
/**
|
|
32
|
+
* Can be either a QualifiedId[], string[], UserClients or QualfiedUserClients. The type has some effect on the behavior of the method. (Needed only for Proteus)
|
|
33
|
+
* 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
|
|
34
|
+
* 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)
|
|
35
|
+
* When given a QualifiedId[] or QualifiedUserClients the method will send the message through the federated API endpoint
|
|
36
|
+
* When given a string[] or UserClients the method will send the message through the old API endpoint
|
|
37
|
+
*/
|
|
24
38
|
userIds?: string[] | QualifiedId[] | UserClients | QualifiedUserClients;
|
|
25
39
|
onClientMismatch?: (status: ClientMismatch | MessageSendingStatus, wasSent: boolean) => void | boolean | Promise<boolean>;
|
|
26
40
|
};
|
|
27
41
|
declare type SendMlsMessageParams<T> = SendCommonParams<T> & {
|
|
42
|
+
/**
|
|
43
|
+
* The groupId of the conversation to send the message to (Needed only for MLS)
|
|
44
|
+
*/
|
|
28
45
|
groupId: string;
|
|
29
46
|
};
|
|
30
47
|
interface MessageSendingOptions {
|
|
@@ -77,12 +94,13 @@ export declare class ConversationService {
|
|
|
77
94
|
private readonly apiClient;
|
|
78
95
|
private readonly config;
|
|
79
96
|
private readonly coreCryptoClientProvider;
|
|
97
|
+
private readonly notificationService;
|
|
80
98
|
readonly messageTimer: MessageTimer;
|
|
81
99
|
private readonly messageService;
|
|
82
100
|
private selfConversationId?;
|
|
83
101
|
constructor(apiClient: APIClient, cryptographyService: CryptographyService, config: {
|
|
84
102
|
useQualifiedIds?: boolean;
|
|
85
|
-
}, coreCryptoClientProvider: () => CoreCrypto);
|
|
103
|
+
}, coreCryptoClientProvider: () => CoreCrypto, notificationService: NotificationService);
|
|
86
104
|
private createEphemeral;
|
|
87
105
|
private getConversationQualifiedMembers;
|
|
88
106
|
/**
|
|
@@ -191,24 +209,7 @@ export declare class ConversationService {
|
|
|
191
209
|
getUnencryptedAsset(assetId: string, assetToken?: string): Promise<ArrayBuffer>;
|
|
192
210
|
addUser(conversationId: QualifiedId, userIds: string | string[] | QualifiedId | QualifiedId[]): Promise<QualifiedId[]>;
|
|
193
211
|
removeUser(conversationId: string, userId: string): Promise<string>;
|
|
194
|
-
/**
|
|
195
|
-
* Sends a mls message to a conversation
|
|
196
|
-
*
|
|
197
|
-
* @param params.payload The message to send to the conversation
|
|
198
|
-
* @param params.protocol The protocol to use to send the message (MLS or Proteus)
|
|
199
|
-
* @param params.groupId? The groupId of the conversation to send the message to (Needed only for MLS)
|
|
200
|
-
* @return resolves with the sent message
|
|
201
|
-
*/
|
|
202
212
|
private sendMlsMessage;
|
|
203
|
-
/**
|
|
204
|
-
* Sends a proteus message to a conversation
|
|
205
|
-
* @param params.userIds? Can be either a QualifiedId[], string[], UserClients or QualfiedUserClients. The type has some effect on the behavior of the method. (Needed only for Proteus)
|
|
206
|
-
* 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
|
|
207
|
-
* 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)
|
|
208
|
-
* When given a QualifiedId[] or QualifiedUserClients the method will send the message through the federated API endpoint
|
|
209
|
-
* When given a string[] or UserClients the method will send the message through the old API endpoint
|
|
210
|
-
* @return resolves with the sent message
|
|
211
|
-
*/
|
|
212
213
|
private sendProteusMessage;
|
|
213
214
|
/**
|
|
214
215
|
* Sends a message to a conversation
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
3
|
* Wire
|
|
4
|
-
* Copyright (C)
|
|
4
|
+
* Copyright (C) 2022 Wire Swiss GmbH
|
|
5
5
|
*
|
|
6
6
|
* This program is free software: you can redistribute it and/or modify
|
|
7
7
|
* it under the terms of the GNU General Public License as published by
|
|
@@ -39,10 +39,11 @@ function isMLS(params) {
|
|
|
39
39
|
return params.protocol === conversation_1.ConversationProtocol.MLS;
|
|
40
40
|
}
|
|
41
41
|
class ConversationService {
|
|
42
|
-
constructor(apiClient, cryptographyService, config, coreCryptoClientProvider) {
|
|
42
|
+
constructor(apiClient, cryptographyService, config, coreCryptoClientProvider, notificationService) {
|
|
43
43
|
this.apiClient = apiClient;
|
|
44
44
|
this.config = config;
|
|
45
45
|
this.coreCryptoClientProvider = coreCryptoClientProvider;
|
|
46
|
+
this.notificationService = notificationService;
|
|
46
47
|
this.messageTimer = new conversation_2.MessageTimer();
|
|
47
48
|
this.messageService = new MessageService_1.MessageService(this.apiClient, cryptographyService);
|
|
48
49
|
}
|
|
@@ -685,6 +686,7 @@ class ConversationService {
|
|
|
685
686
|
sendingPromises.push(this.apiClient.api.conversation.postMlsMessage(Uint8Array.from(memberAddedMessages.message)));
|
|
686
687
|
}
|
|
687
688
|
await Promise.all(sendingPromises);
|
|
689
|
+
await this.notificationService.saveConversationGroupId(newConversation);
|
|
688
690
|
// We fetch the fresh version of the conversation created on backend with the newly added users
|
|
689
691
|
return this.getConversations(newConversation.id);
|
|
690
692
|
}
|
|
@@ -720,14 +722,6 @@ class ConversationService {
|
|
|
720
722
|
await this.apiClient.api.conversation.deleteMember(conversationId, userId);
|
|
721
723
|
return userId;
|
|
722
724
|
}
|
|
723
|
-
/**
|
|
724
|
-
* Sends a mls message to a conversation
|
|
725
|
-
*
|
|
726
|
-
* @param params.payload The message to send to the conversation
|
|
727
|
-
* @param params.protocol The protocol to use to send the message (MLS or Proteus)
|
|
728
|
-
* @param params.groupId? The groupId of the conversation to send the message to (Needed only for MLS)
|
|
729
|
-
* @return resolves with the sent message
|
|
730
|
-
*/
|
|
731
725
|
async sendMlsMessage(params, genericMessage, content) {
|
|
732
726
|
var _a, _b;
|
|
733
727
|
const { groupId, onSuccess, payload } = params;
|
|
@@ -743,15 +737,6 @@ class ConversationService {
|
|
|
743
737
|
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 });
|
|
744
738
|
}
|
|
745
739
|
}
|
|
746
|
-
/**
|
|
747
|
-
* Sends a proteus message to a conversation
|
|
748
|
-
* @param params.userIds? Can be either a QualifiedId[], string[], UserClients or QualfiedUserClients. The type has some effect on the behavior of the method. (Needed only for Proteus)
|
|
749
|
-
* 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
|
|
750
|
-
* 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)
|
|
751
|
-
* When given a QualifiedId[] or QualifiedUserClients the method will send the message through the federated API endpoint
|
|
752
|
-
* When given a string[] or UserClients the method will send the message through the old API endpoint
|
|
753
|
-
* @return resolves with the sent message
|
|
754
|
-
*/
|
|
755
740
|
async sendProteusMessage(params, genericMessage, content) {
|
|
756
741
|
var _a;
|
|
757
742
|
const { userIds, sendAsProtobuf, conversationDomain, nativePush, targetMode, payload, onClientMismatch, onSuccess } = params;
|
|
@@ -50,6 +50,7 @@ export declare enum PayloadBundleType {
|
|
|
50
50
|
MESSAGE_DELETE = "PayloadBundleType.MESSAGE_DELETE",
|
|
51
51
|
MESSAGE_EDIT = "PayloadBundleType.MESSAGE_EDIT",
|
|
52
52
|
MESSAGE_HIDE = "PayloadBundleType.MESSAGE_HIDE",
|
|
53
|
+
MLS_WELCOME_MESSAGE = "PayloadBundleType.MLS_WELCOME",
|
|
53
54
|
PING = "PayloadBundleType.PING",
|
|
54
55
|
REACTION = "PayloadBundleType.REACTION",
|
|
55
56
|
TEAM_CONVERSATION_CREATE = "PayloadBundleType.TEAM_CONVERSATION_CREATE",
|
|
@@ -54,6 +54,7 @@ var PayloadBundleType;
|
|
|
54
54
|
PayloadBundleType["MESSAGE_DELETE"] = "PayloadBundleType.MESSAGE_DELETE";
|
|
55
55
|
PayloadBundleType["MESSAGE_EDIT"] = "PayloadBundleType.MESSAGE_EDIT";
|
|
56
56
|
PayloadBundleType["MESSAGE_HIDE"] = "PayloadBundleType.MESSAGE_HIDE";
|
|
57
|
+
PayloadBundleType["MLS_WELCOME_MESSAGE"] = "PayloadBundleType.MLS_WELCOME";
|
|
57
58
|
PayloadBundleType["PING"] = "PayloadBundleType.PING";
|
|
58
59
|
PayloadBundleType["REACTION"] = "PayloadBundleType.REACTION";
|
|
59
60
|
PayloadBundleType["TEAM_CONVERSATION_CREATE"] = "PayloadBundleType.TEAM_CONVERSATION_CREATE";
|
|
@@ -4,7 +4,8 @@ export declare enum DatabaseStores {
|
|
|
4
4
|
CLIENTS = "clients",
|
|
5
5
|
KEYS = "keys",
|
|
6
6
|
PRE_KEYS = "prekeys",
|
|
7
|
-
SESSIONS = "sessions"
|
|
7
|
+
SESSIONS = "sessions",
|
|
8
|
+
GROUP_IDS = "group_ids"
|
|
8
9
|
}
|
|
9
10
|
export declare class CryptographyDatabaseRepository {
|
|
10
11
|
private readonly storeEngine;
|
|
@@ -26,6 +26,7 @@ var DatabaseStores;
|
|
|
26
26
|
DatabaseStores["KEYS"] = "keys";
|
|
27
27
|
DatabaseStores["PRE_KEYS"] = "prekeys";
|
|
28
28
|
DatabaseStores["SESSIONS"] = "sessions";
|
|
29
|
+
DatabaseStores["GROUP_IDS"] = "group_ids";
|
|
29
30
|
})(DatabaseStores = exports.DatabaseStores || (exports.DatabaseStores = {}));
|
|
30
31
|
class CryptographyDatabaseRepository {
|
|
31
32
|
constructor(storeEngine) {
|
|
@@ -38,6 +39,7 @@ class CryptographyDatabaseRepository {
|
|
|
38
39
|
this.storeEngine.deleteAll(CryptographyDatabaseRepository.STORES.KEYS),
|
|
39
40
|
this.storeEngine.deleteAll(CryptographyDatabaseRepository.STORES.SESSIONS),
|
|
40
41
|
this.storeEngine.deleteAll(CryptographyDatabaseRepository.STORES.PRE_KEYS),
|
|
42
|
+
this.storeEngine.deleteAll(CryptographyDatabaseRepository.STORES.GROUP_IDS),
|
|
41
43
|
]);
|
|
42
44
|
}
|
|
43
45
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { BackendEvent } from '@wireapp/api-client/src/event';
|
|
2
2
|
import type { Notification } from '@wireapp/api-client/src/notification/';
|
|
3
3
|
import type { CRUDEngine } from '@wireapp/store-engine';
|
|
4
|
+
declare type CompoundGroupIdParams = {
|
|
5
|
+
groupId: string;
|
|
6
|
+
conversationId: string;
|
|
7
|
+
conversationDomain: string;
|
|
8
|
+
};
|
|
4
9
|
export declare enum DatabaseStores {
|
|
5
10
|
EVENTS = "events"
|
|
6
11
|
}
|
|
@@ -17,4 +22,8 @@ export declare class NotificationDatabaseRepository {
|
|
|
17
22
|
createLastEventDate(eventDate: Date): Promise<Date>;
|
|
18
23
|
getLastNotificationId(): Promise<string>;
|
|
19
24
|
updateLastNotificationId(lastNotification: Notification): Promise<string>;
|
|
25
|
+
private generateCompoundGroupIdPrimaryKey;
|
|
26
|
+
addCompoundGroupId(params: CompoundGroupIdParams): Promise<void>;
|
|
27
|
+
getCompoundGroupId(params: Omit<CompoundGroupIdParams, 'groupId'>): Promise<string>;
|
|
20
28
|
}
|
|
29
|
+
export {};
|
|
@@ -30,6 +30,7 @@ var DatabaseKeys;
|
|
|
30
30
|
DatabaseKeys["PRIMARY_KEY_LAST_NOTIFICATION"] = "z.storage.StorageKey.NOTIFICATION.LAST_ID";
|
|
31
31
|
})(DatabaseKeys = exports.DatabaseKeys || (exports.DatabaseKeys = {}));
|
|
32
32
|
const STORE_AMPLIFY = CryptographyDatabaseRepository_1.CryptographyDatabaseRepository.STORES.AMPLIFY;
|
|
33
|
+
const STORE_GROUPIDS = CryptographyDatabaseRepository_1.CryptographyDatabaseRepository.STORES.GROUP_IDS;
|
|
33
34
|
class NotificationDatabaseRepository {
|
|
34
35
|
constructor(storeEngine) {
|
|
35
36
|
this.storeEngine = storeEngine;
|
|
@@ -59,6 +60,15 @@ class NotificationDatabaseRepository {
|
|
|
59
60
|
});
|
|
60
61
|
return lastNotification.id;
|
|
61
62
|
}
|
|
63
|
+
generateCompoundGroupIdPrimaryKey({ conversationId, conversationDomain, }) {
|
|
64
|
+
return `${conversationId}@${conversationDomain}`;
|
|
65
|
+
}
|
|
66
|
+
async addCompoundGroupId(params) {
|
|
67
|
+
await this.storeEngine.updateOrCreate(STORE_GROUPIDS, this.generateCompoundGroupIdPrimaryKey(params), params.groupId);
|
|
68
|
+
}
|
|
69
|
+
async getCompoundGroupId(params) {
|
|
70
|
+
return this.storeEngine.read(STORE_GROUPIDS, this.generateCompoundGroupIdPrimaryKey(params));
|
|
71
|
+
}
|
|
62
72
|
}
|
|
63
73
|
exports.NotificationDatabaseRepository = NotificationDatabaseRepository;
|
|
64
74
|
//# sourceMappingURL=NotificationDatabaseRepository.js.map
|
|
@@ -9,6 +9,9 @@ import { NotificationError } from '../CoreError';
|
|
|
9
9
|
import type { CryptographyService } from '../cryptography';
|
|
10
10
|
import { GenericMessage } from '@wireapp/protocol-messaging';
|
|
11
11
|
import { AbortHandler } from '@wireapp/api-client/src/tcp';
|
|
12
|
+
import type { CoreCrypto } from '@otak/core-crypto/platforms/web/corecrypto';
|
|
13
|
+
import { QualifiedId } from '@wireapp/api-client/src/user';
|
|
14
|
+
import { Conversation } from '@wireapp/api-client/src/conversation';
|
|
12
15
|
export declare type HandledEventPayload = {
|
|
13
16
|
event: Events.BackendEvent;
|
|
14
17
|
mappedEvent?: PayloadBundle;
|
|
@@ -29,13 +32,14 @@ export interface NotificationService {
|
|
|
29
32
|
on(event: TOPIC.NOTIFICATION_ERROR, listener: (payload: NotificationError) => void): this;
|
|
30
33
|
}
|
|
31
34
|
export declare class NotificationService extends EventEmitter {
|
|
35
|
+
private readonly coreCryptoClientProvider;
|
|
32
36
|
private readonly apiClient;
|
|
33
37
|
private readonly backend;
|
|
34
38
|
private readonly cryptographyService;
|
|
35
39
|
private readonly database;
|
|
36
40
|
private readonly logger;
|
|
37
41
|
static readonly TOPIC: typeof TOPIC;
|
|
38
|
-
constructor(apiClient: APIClient, cryptographyService: CryptographyService, storeEngine: CRUDEngine);
|
|
42
|
+
constructor(apiClient: APIClient, cryptographyService: CryptographyService, storeEngine: CRUDEngine, coreCryptoClientProvider: () => CoreCrypto | undefined);
|
|
39
43
|
private getAllNotifications;
|
|
40
44
|
/** Should only be called with a completely new client. */
|
|
41
45
|
initializeNotificationStream(): Promise<string>;
|
|
@@ -56,5 +60,20 @@ export declare class NotificationService extends EventEmitter {
|
|
|
56
60
|
handleNotification(notification: Notification, source: PayloadBundleSource, dryRun?: boolean): AsyncGenerator<HandledEventPayload>;
|
|
57
61
|
private cleanupPayloadBundle;
|
|
58
62
|
private handleEvent;
|
|
63
|
+
/**
|
|
64
|
+
* If there is a groupId in the conversation, we need to store the conversationId => groupId pair
|
|
65
|
+
* in order to find the groupId when decrypting messages
|
|
66
|
+
* This is a bit hacky but since mls messages do not embed the groupId we need to keep a mapping of those
|
|
67
|
+
*
|
|
68
|
+
* @param conversation conversation with group_id
|
|
69
|
+
*/
|
|
70
|
+
saveConversationGroupId(conversation: Conversation): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* If there is a matching conversationId => groupId pair in the database,
|
|
73
|
+
* we can find the groupId and return it as a Uint8Array
|
|
74
|
+
*
|
|
75
|
+
* @param conversationQualifiedId
|
|
76
|
+
*/
|
|
77
|
+
getUint8ArrayFromConversationGroupId(conversationQualifiedId: QualifiedId): Promise<Uint8Array>;
|
|
59
78
|
}
|
|
60
79
|
export {};
|
|
@@ -63,13 +63,16 @@ const CoreError_1 = require("../CoreError");
|
|
|
63
63
|
const UserMapper_1 = require("../user/UserMapper");
|
|
64
64
|
const NotificationBackendRepository_1 = require("./NotificationBackendRepository");
|
|
65
65
|
const NotificationDatabaseRepository_1 = require("./NotificationDatabaseRepository");
|
|
66
|
+
const protocol_messaging_1 = require("@wireapp/protocol-messaging");
|
|
67
|
+
const bazinga64_1 = require("bazinga64");
|
|
66
68
|
var TOPIC;
|
|
67
69
|
(function (TOPIC) {
|
|
68
70
|
TOPIC["NOTIFICATION_ERROR"] = "NotificationService.TOPIC.NOTIFICATION_ERROR";
|
|
69
71
|
})(TOPIC || (TOPIC = {}));
|
|
70
72
|
class NotificationService extends events_1.EventEmitter {
|
|
71
|
-
constructor(apiClient, cryptographyService, storeEngine) {
|
|
73
|
+
constructor(apiClient, cryptographyService, storeEngine, coreCryptoClientProvider) {
|
|
72
74
|
super();
|
|
75
|
+
this.coreCryptoClientProvider = coreCryptoClientProvider;
|
|
73
76
|
this.logger = (0, logdown_1.default)('@wireapp/core/notification/NotificationService', {
|
|
74
77
|
logger: console,
|
|
75
78
|
markdown: false,
|
|
@@ -206,8 +209,38 @@ class NotificationService extends events_1.EventEmitter {
|
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
211
|
async handleEvent(event, source, dryRun = false) {
|
|
212
|
+
var _a;
|
|
213
|
+
const coreCryptoClient = this.coreCryptoClientProvider();
|
|
209
214
|
switch (event.type) {
|
|
210
|
-
|
|
215
|
+
case Events.CONVERSATION_EVENT.MLS_WELCOME_MESSAGE:
|
|
216
|
+
if (!coreCryptoClient) {
|
|
217
|
+
// TODO throw proper error
|
|
218
|
+
throw new Error('TODO');
|
|
219
|
+
}
|
|
220
|
+
const data = bazinga64_1.Decoder.fromBase64(event.data).asBytes;
|
|
221
|
+
// We extract the groupId from the welcome message and let coreCrypto store this group
|
|
222
|
+
const newGroupId = await coreCryptoClient.processWelcomeMessage(data);
|
|
223
|
+
const groupIdStr = bazinga64_1.Encoder.toBase64(newGroupId).asString;
|
|
224
|
+
// The groupId can then be sent back to the consumer
|
|
225
|
+
return {
|
|
226
|
+
event,
|
|
227
|
+
mappedEvent: ConversationMapper_1.ConversationMapper.mapConversationEvent(Object.assign(Object.assign({}, event), { data: groupIdStr }), source),
|
|
228
|
+
};
|
|
229
|
+
case Events.CONVERSATION_EVENT.MLS_MESSAGE_ADD:
|
|
230
|
+
if (!coreCryptoClient) {
|
|
231
|
+
// TODO throw proper error
|
|
232
|
+
throw new Error('TODO');
|
|
233
|
+
}
|
|
234
|
+
const encryptedData = bazinga64_1.Decoder.fromBase64(event.data).asBytes;
|
|
235
|
+
const groupId = await this.getUint8ArrayFromConversationGroupId(event.qualified_conversation || { id: event.conversation, domain: '' });
|
|
236
|
+
const rawData = await coreCryptoClient.decryptMessage(groupId, encryptedData);
|
|
237
|
+
if (!rawData) {
|
|
238
|
+
// TODO
|
|
239
|
+
throw new Error('empty message');
|
|
240
|
+
}
|
|
241
|
+
const decryptedData = protocol_messaging_1.GenericMessage.decode(rawData);
|
|
242
|
+
return { event, decryptedData };
|
|
243
|
+
// Encrypted Proteus events
|
|
211
244
|
case Events.CONVERSATION_EVENT.OTR_MESSAGE_ADD: {
|
|
212
245
|
if (dryRun) {
|
|
213
246
|
// In case of a dry run, we do not want to decrypt messages
|
|
@@ -228,6 +261,13 @@ class NotificationService extends events_1.EventEmitter {
|
|
|
228
261
|
}
|
|
229
262
|
// Meta events
|
|
230
263
|
case Events.CONVERSATION_EVENT.MEMBER_JOIN:
|
|
264
|
+
// As of today (07/07/2022) the backend sends `WELCOME` message to the user's own conversation (not the actual conversation that the welcome should be part of)
|
|
265
|
+
// So in order to map conversation Ids and groupId together, we need to first fetch the conversation and get the groupId linked to it.
|
|
266
|
+
const conversation = await this.apiClient.api.conversation.getConversation((_a = event.qualified_conversation) !== null && _a !== void 0 ? _a : { id: event.conversation, domain: '' });
|
|
267
|
+
if (!conversation) {
|
|
268
|
+
throw new Error('no conv');
|
|
269
|
+
}
|
|
270
|
+
await this.saveConversationGroupId(conversation);
|
|
231
271
|
case Events.CONVERSATION_EVENT.MESSAGE_TIMER_UPDATE:
|
|
232
272
|
case Events.CONVERSATION_EVENT.RENAME:
|
|
233
273
|
case Events.CONVERSATION_EVENT.TYPING: {
|
|
@@ -245,6 +285,36 @@ class NotificationService extends events_1.EventEmitter {
|
|
|
245
285
|
}
|
|
246
286
|
return { event };
|
|
247
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* If there is a groupId in the conversation, we need to store the conversationId => groupId pair
|
|
290
|
+
* in order to find the groupId when decrypting messages
|
|
291
|
+
* This is a bit hacky but since mls messages do not embed the groupId we need to keep a mapping of those
|
|
292
|
+
*
|
|
293
|
+
* @param conversation conversation with group_id
|
|
294
|
+
*/
|
|
295
|
+
async saveConversationGroupId(conversation) {
|
|
296
|
+
if (conversation.group_id) {
|
|
297
|
+
const { group_id: groupId, qualified_id: { id: conversationId, domain: conversationDomain }, } = conversation;
|
|
298
|
+
await this.database.addCompoundGroupId({ conversationDomain, conversationId, groupId });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* If there is a matching conversationId => groupId pair in the database,
|
|
303
|
+
* we can find the groupId and return it as a Uint8Array
|
|
304
|
+
*
|
|
305
|
+
* @param conversationQualifiedId
|
|
306
|
+
*/
|
|
307
|
+
async getUint8ArrayFromConversationGroupId(conversationQualifiedId) {
|
|
308
|
+
const { id: conversationId, domain: conversationDomain } = conversationQualifiedId;
|
|
309
|
+
const groupId = await this.database.getCompoundGroupId({
|
|
310
|
+
conversationId,
|
|
311
|
+
conversationDomain,
|
|
312
|
+
});
|
|
313
|
+
if (!groupId) {
|
|
314
|
+
throw new Error(`Could not find a group_id for conversation ${conversationId}@${conversationDomain}`);
|
|
315
|
+
}
|
|
316
|
+
return bazinga64_1.Decoder.fromBase64(groupId).asBytes;
|
|
317
|
+
}
|
|
248
318
|
}
|
|
249
319
|
exports.NotificationService = NotificationService;
|
|
250
320
|
NotificationService.TOPIC = TOPIC;
|