@wireapp/core 27.6.0 → 28.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
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.2.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@28.1.0...@wireapp/core@28.2.0) (2022-07-04)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **core, api-client:** Add MLS group creation ([#4295](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4295)) ([9755e03](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/9755e03bee6a01860b932c4da5f713809551241f))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [28.1.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@28.0.0...@wireapp/core@28.1.0) (2022-07-04)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **core:** More suited types for Account ([051b4f3](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/051b4f35be7164624f3ed7913366010bdf8b17c4))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* **api-client:** Adapt to api version 2 ([#4308](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4308)) ([2ac928d](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/2ac928d0b812080faa81e2cd9de12c959eb59276))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# [28.0.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@27.6.0...@wireapp/core@28.0.0) (2022-07-01)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Features
|
|
37
|
+
|
|
38
|
+
* Use mls config object ([#4307](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4307)) ([3d510d0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/3d510d0e041a3d049282e6a312ffa880d9bafd89))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### BREAKING CHANGES
|
|
42
|
+
|
|
43
|
+
* the enableMLS flag has been removed in favor of a config object. If the config object is set, then MLS will be activated
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
6
49
|
# [27.6.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@27.5.0...@wireapp/core@27.6.0) (2022-06-30)
|
|
7
50
|
|
|
8
51
|
|
package/package.json
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@open-wc/webpack-import-meta-loader": "0.4.7",
|
|
7
|
-
"@otak/core-crypto": "0.
|
|
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.9.0",
|
|
11
11
|
"@wireapp/cryptobox": "12.8.0",
|
|
12
12
|
"bazinga64": "5.10.0",
|
|
13
13
|
"hash.js": "1.1.7",
|
|
@@ -73,6 +73,6 @@
|
|
|
73
73
|
"test:project": "yarn dist && yarn test",
|
|
74
74
|
"test:node": "nyc jasmine --config=jasmine.json"
|
|
75
75
|
},
|
|
76
|
-
"version": "
|
|
77
|
-
"gitHead": "
|
|
76
|
+
"version": "28.2.0",
|
|
77
|
+
"gitHead": "5fb6aacf6f616c92d73593ec24cefb50a5a0f7f0"
|
|
78
78
|
}
|
package/src/main/Account.d.ts
CHANGED
|
@@ -59,13 +59,22 @@ declare type SecretCrypto<T> = {
|
|
|
59
59
|
encrypt: (value: Uint8Array) => Promise<T>;
|
|
60
60
|
decrypt: (payload: T) => Promise<Uint8Array>;
|
|
61
61
|
};
|
|
62
|
-
interface
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
/** encrypt/decrypt function pair that will be called before storing/fetching secrets in the secrets database.
|
|
62
|
+
interface MLSConfig<T = any> {
|
|
63
|
+
/**
|
|
64
|
+
* encrypt/decrypt function pair that will be called before storing/fetching secrets in the secrets database.
|
|
66
65
|
* If not provided will use the built in encryption mechanism
|
|
67
66
|
*/
|
|
68
67
|
secretsCrypto?: SecretCrypto<T>;
|
|
68
|
+
/**
|
|
69
|
+
* path on the public server to the core crypto wasm file.
|
|
70
|
+
* This file will be downloaded lazily when corecrypto is needed.
|
|
71
|
+
* It, thus, needs to know where, on the server, the file can be found
|
|
72
|
+
*/
|
|
73
|
+
coreCrypoWasmFilePath: string;
|
|
74
|
+
}
|
|
75
|
+
interface AccountOptions<T> {
|
|
76
|
+
/** Used to store info in the database (will create a inMemory engine if returns undefined) */
|
|
77
|
+
createStore?: CreateStoreFn;
|
|
69
78
|
/** Number of prekeys to generate when creating a new device (defaults to 2)
|
|
70
79
|
* Prekeys are Diffie-Hellmann public keys which allow offline initiation of a secure Proteus session between two devices.
|
|
71
80
|
* Having a high value will:
|
|
@@ -76,16 +85,18 @@ interface AccountOptions<T> {
|
|
|
76
85
|
* - make it likely that all prekeys get consumed while the device is offline and the last resort prekey will be used to create new session
|
|
77
86
|
*/
|
|
78
87
|
nbPrekeys?: number;
|
|
79
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Config for MLS devices. Will not load corecrypt or create MLS devices if undefined
|
|
90
|
+
*/
|
|
91
|
+
mlsConfig?: MLSConfig<T>;
|
|
80
92
|
}
|
|
81
|
-
export declare class Account<T =
|
|
93
|
+
export declare class Account<T = any> extends EventEmitter {
|
|
82
94
|
private readonly apiClient;
|
|
83
95
|
private readonly logger;
|
|
84
96
|
private readonly createStore;
|
|
85
97
|
private storeEngine?;
|
|
86
|
-
private readonly secretsCrypto?;
|
|
87
98
|
private readonly nbPrekeys;
|
|
88
|
-
private readonly
|
|
99
|
+
private readonly mlsConfig?;
|
|
89
100
|
private coreCryptoClient?;
|
|
90
101
|
static readonly TOPIC: typeof TOPIC;
|
|
91
102
|
service?: {
|
|
@@ -108,7 +119,7 @@ export declare class Account<T = unknown> extends EventEmitter {
|
|
|
108
119
|
* @param apiClient The apiClient instance to use in the core (will create a new new one if undefined)
|
|
109
120
|
* @param accountOptions
|
|
110
121
|
*/
|
|
111
|
-
constructor(apiClient?: APIClient, { createStore, nbPrekeys,
|
|
122
|
+
constructor(apiClient?: APIClient, { createStore, nbPrekeys, mlsConfig }?: AccountOptions<T>);
|
|
112
123
|
private persistCookie;
|
|
113
124
|
get clientId(): string;
|
|
114
125
|
get userId(): string;
|
package/src/main/Account.js
CHANGED
|
@@ -86,14 +86,13 @@ class Account extends events_1.EventEmitter {
|
|
|
86
86
|
* @param apiClient The apiClient instance to use in the core (will create a new new one if undefined)
|
|
87
87
|
* @param accountOptions
|
|
88
88
|
*/
|
|
89
|
-
constructor(apiClient = new api_client_1.APIClient(), { createStore = () => undefined, nbPrekeys = 2,
|
|
89
|
+
constructor(apiClient = new api_client_1.APIClient(), { createStore = () => undefined, nbPrekeys = 2, mlsConfig } = {}) {
|
|
90
90
|
super();
|
|
91
91
|
this.apiClient = apiClient;
|
|
92
92
|
this.backendFeatures = this.apiClient.backendFeatures;
|
|
93
|
-
this.
|
|
93
|
+
this.mlsConfig = mlsConfig;
|
|
94
94
|
this.nbPrekeys = nbPrekeys;
|
|
95
95
|
this.createStore = createStore;
|
|
96
|
-
this.enableMLS = enableMLS;
|
|
97
96
|
apiClient.on(api_client_1.APIClient.TOPIC.COOKIE_REFRESH, async (cookie) => {
|
|
98
97
|
if (cookie && this.storeEngine) {
|
|
99
98
|
try {
|
|
@@ -233,7 +232,7 @@ class Account extends events_1.EventEmitter {
|
|
|
233
232
|
const conversationService = new conversation_1.ConversationService(this.apiClient, cryptographyService, {
|
|
234
233
|
// We can use qualified ids to send messages as long as the backend supports federated endpoints
|
|
235
234
|
useQualifiedIds: this.backendFeatures.federationEndpoints,
|
|
236
|
-
});
|
|
235
|
+
}, () => this.coreCryptoClient);
|
|
237
236
|
const notificationService = new notification_1.NotificationService(this.apiClient, cryptographyService, this.storeEngine);
|
|
238
237
|
const selfService = new self_1.SelfService(this.apiClient);
|
|
239
238
|
const teamService = new team_1.TeamService(this.apiClient);
|
|
@@ -260,17 +259,17 @@ class Account extends events_1.EventEmitter {
|
|
|
260
259
|
const loadedClient = await this.service.client.getLocalClient();
|
|
261
260
|
await this.apiClient.api.client.getClient(loadedClient.id);
|
|
262
261
|
this.apiClient.context.clientId = loadedClient.id;
|
|
263
|
-
if (this.
|
|
264
|
-
this.coreCryptoClient = await this.createMLSClient(loadedClient, this.apiClient.context);
|
|
262
|
+
if (this.mlsConfig) {
|
|
263
|
+
this.coreCryptoClient = await this.createMLSClient(loadedClient, this.apiClient.context, this.mlsConfig);
|
|
265
264
|
}
|
|
266
265
|
return loadedClient;
|
|
267
266
|
}
|
|
268
|
-
async createMLSClient(client, context) {
|
|
267
|
+
async createMLSClient(client, context, mlsConfig) {
|
|
269
268
|
const coreCryptoKeyId = 'corecrypto-key';
|
|
270
269
|
const { CoreCrypto } = await Promise.resolve().then(() => __importStar(require('@otak/core-crypto')));
|
|
271
270
|
const dbName = `secrets-${this.generateDbName(context)}`;
|
|
272
|
-
const secretStore =
|
|
273
|
-
? await (0, encryptedStore_1.createCustomEncryptedStore)(dbName,
|
|
271
|
+
const secretStore = mlsConfig.secretsCrypto
|
|
272
|
+
? await (0, encryptedStore_1.createCustomEncryptedStore)(dbName, mlsConfig.secretsCrypto)
|
|
274
273
|
: await (0, encryptedStore_1.createEncryptedStore)(dbName);
|
|
275
274
|
let key = await secretStore.getsecretValue(coreCryptoKeyId);
|
|
276
275
|
if (!key) {
|
|
@@ -279,21 +278,22 @@ class Account extends events_1.EventEmitter {
|
|
|
279
278
|
}
|
|
280
279
|
const { userId, domain } = this.apiClient.context;
|
|
281
280
|
return CoreCrypto.init({
|
|
282
|
-
|
|
281
|
+
databaseName: `corecrypto-${this.generateDbName(context)}`,
|
|
283
282
|
key: bazinga64_1.Encoder.toBase64(key).asString,
|
|
284
283
|
clientId: `${userId}:${client.id}@${domain}`,
|
|
284
|
+
wasmFilePath: mlsConfig.coreCrypoWasmFilePath,
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
async registerClient(loginData, clientInfo = coreDefaultClient, entropyData) {
|
|
288
288
|
if (!this.service) {
|
|
289
289
|
throw new Error('Services are not set.');
|
|
290
290
|
}
|
|
291
|
-
this.logger.info(`Creating new client {mls: ${!!this.
|
|
291
|
+
this.logger.info(`Creating new client {mls: ${!!this.mlsConfig}}`);
|
|
292
292
|
const registeredClient = await this.service.client.register(loginData, clientInfo, entropyData);
|
|
293
|
-
if (this.
|
|
294
|
-
this.coreCryptoClient = await this.createMLSClient(registeredClient, this.apiClient.context);
|
|
293
|
+
if (this.mlsConfig) {
|
|
294
|
+
this.coreCryptoClient = await this.createMLSClient(registeredClient, this.apiClient.context, this.mlsConfig);
|
|
295
295
|
await this.service.client.uploadMLSPublicKeys(this.coreCryptoClient.clientPublicKey(), registeredClient.id);
|
|
296
|
-
await this.service.client.uploadMLSKeyPackages(this.coreCryptoClient.clientKeypackages(this.nbPrekeys), registeredClient.id);
|
|
296
|
+
await this.service.client.uploadMLSKeyPackages(await this.coreCryptoClient.clientKeypackages(this.nbPrekeys), registeredClient.id);
|
|
297
297
|
}
|
|
298
298
|
this.apiClient.context.clientId = registeredClient.id;
|
|
299
299
|
this.logger.info('Client is created');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CoreCrypto } from '@otak/core-crypto';
|
|
1
2
|
import type { APIClient } from '@wireapp/api-client';
|
|
2
3
|
import { MessageSendingStatus, Conversation, DefaultConversationRoleName, MutedStatus, NewConversation, QualifiedUserClients, UserClients, ClientMismatch } from '@wireapp/api-client/src/conversation';
|
|
3
4
|
import type { ConversationMemberLeaveEvent } from '@wireapp/api-client/src/event';
|
|
@@ -61,12 +62,13 @@ export interface MessageSendingCallbacks {
|
|
|
61
62
|
export declare class ConversationService {
|
|
62
63
|
private readonly apiClient;
|
|
63
64
|
private readonly config;
|
|
65
|
+
private readonly coreCryptoClientProvider;
|
|
64
66
|
readonly messageTimer: MessageTimer;
|
|
65
67
|
private readonly messageService;
|
|
66
68
|
private selfConversationId?;
|
|
67
69
|
constructor(apiClient: APIClient, cryptographyService: CryptographyService, config: {
|
|
68
70
|
useQualifiedIds?: boolean;
|
|
69
|
-
});
|
|
71
|
+
}, coreCryptoClientProvider: () => CoreCrypto);
|
|
70
72
|
private createEphemeral;
|
|
71
73
|
private getConversationQualifiedMembers;
|
|
72
74
|
/**
|
|
@@ -167,6 +169,7 @@ export declare class ConversationService {
|
|
|
167
169
|
* @returns Resolves when the conversation was created
|
|
168
170
|
*/
|
|
169
171
|
createConversation(conversationData: NewConversation): Promise<Conversation>;
|
|
172
|
+
private createMLSConversation;
|
|
170
173
|
getConversations(conversationId: string): Promise<Conversation>;
|
|
171
174
|
getConversations(conversationIds?: string[]): Promise<Conversation[]>;
|
|
172
175
|
getAsset({ assetId, assetToken, otrKey, sha256 }: RemoteData): Promise<Uint8Array>;
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
21
|
exports.ConversationService = exports.MessageTargetMode = void 0;
|
|
22
|
+
const bazinga64_1 = require("bazinga64");
|
|
22
23
|
const conversation_1 = require("@wireapp/api-client/src/conversation");
|
|
23
24
|
const data_1 = require("@wireapp/api-client/src/conversation/data");
|
|
24
25
|
const protocol_messaging_1 = require("@wireapp/protocol-messaging");
|
|
@@ -35,9 +36,10 @@ var MessageTargetMode;
|
|
|
35
36
|
MessageTargetMode[MessageTargetMode["USERS_CLIENTS"] = 2] = "USERS_CLIENTS";
|
|
36
37
|
})(MessageTargetMode = exports.MessageTargetMode || (exports.MessageTargetMode = {}));
|
|
37
38
|
class ConversationService {
|
|
38
|
-
constructor(apiClient, cryptographyService, config) {
|
|
39
|
+
constructor(apiClient, cryptographyService, config, coreCryptoClientProvider) {
|
|
39
40
|
this.apiClient = apiClient;
|
|
40
41
|
this.config = config;
|
|
42
|
+
this.coreCryptoClientProvider = coreCryptoClientProvider;
|
|
41
43
|
this.messageTimer = new conversation_2.MessageTimer();
|
|
42
44
|
this.messageService = new MessageService_1.MessageService(this.apiClient, cryptographyService);
|
|
43
45
|
}
|
|
@@ -620,8 +622,64 @@ class ConversationService {
|
|
|
620
622
|
else {
|
|
621
623
|
payload = conversationData;
|
|
622
624
|
}
|
|
625
|
+
if (typeof conversationData !== 'string' && conversationData.protocol === conversation_1.ConversationProtocol.MLS) {
|
|
626
|
+
return this.createMLSConversation(conversationData);
|
|
627
|
+
}
|
|
623
628
|
return this.apiClient.api.conversation.postConversation(payload);
|
|
624
629
|
}
|
|
630
|
+
async createMLSConversation(conversationData) {
|
|
631
|
+
/**
|
|
632
|
+
* @note For creating MLS conversations the users & qualified_users
|
|
633
|
+
* field must be empty as backend is not aware which users
|
|
634
|
+
* are in a MLS conversation because of the MLS architecture.
|
|
635
|
+
*/
|
|
636
|
+
const newConversation = await this.apiClient.api.conversation.postConversation(Object.assign(Object.assign({}, conversationData), { users: undefined, qualified_users: undefined }));
|
|
637
|
+
const { group_id: groupId } = newConversation;
|
|
638
|
+
const groupIdDecodedFromBase64 = bazinga64_1.Decoder.fromBase64(groupId).asBytes;
|
|
639
|
+
const { qualified_users: qualifiedUsers = [], selfUserId } = conversationData;
|
|
640
|
+
if (!selfUserId) {
|
|
641
|
+
throw new Error('You need to pass self user qualified id in order to create an MLS conversation');
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* @note We need to fetch key packages for all the users
|
|
645
|
+
* we want to add to the new MLS conversations,
|
|
646
|
+
* includes self user too.
|
|
647
|
+
*/
|
|
648
|
+
const keyPackages = await Promise.all([
|
|
649
|
+
this.apiClient.api.client.claimMLSKeyPackages(selfUserId.id, selfUserId.domain,
|
|
650
|
+
/**
|
|
651
|
+
* we should skip fetching key packages for current self client,
|
|
652
|
+
* it's already added by the backend on the group creation time
|
|
653
|
+
*/
|
|
654
|
+
conversationData.creator_client),
|
|
655
|
+
...qualifiedUsers.map(qualifiedId => this.apiClient.api.client.claimMLSKeyPackages(qualifiedId.id, qualifiedId.domain)),
|
|
656
|
+
]);
|
|
657
|
+
const coreCryptoClient = this.coreCryptoClientProvider();
|
|
658
|
+
const coreCryptoKeyPackagesPayload = keyPackages.reduce((previousValue, currentValue) => {
|
|
659
|
+
// skip users that have not uploaded their MLS key packages
|
|
660
|
+
if (currentValue.key_packages.length > 0) {
|
|
661
|
+
return [
|
|
662
|
+
...previousValue,
|
|
663
|
+
...currentValue.key_packages.map(keyPackage => ({
|
|
664
|
+
id: new TextEncoder().encode(keyPackage.client),
|
|
665
|
+
kp: bazinga64_1.Decoder.fromBase64(keyPackage.key_package).asBytes,
|
|
666
|
+
})),
|
|
667
|
+
];
|
|
668
|
+
}
|
|
669
|
+
return previousValue;
|
|
670
|
+
}, []);
|
|
671
|
+
await coreCryptoClient.createConversation(groupIdDecodedFromBase64);
|
|
672
|
+
const memberAddedMessages = await coreCryptoClient.addClientsToConversation(groupIdDecodedFromBase64, coreCryptoKeyPackagesPayload);
|
|
673
|
+
const sendingPromises = [];
|
|
674
|
+
if (memberAddedMessages === null || memberAddedMessages === void 0 ? void 0 : memberAddedMessages.welcome) {
|
|
675
|
+
sendingPromises.push(this.apiClient.api.conversation.postMlsWelcomeMessage(Uint8Array.from(memberAddedMessages.welcome)));
|
|
676
|
+
}
|
|
677
|
+
if (memberAddedMessages === null || memberAddedMessages === void 0 ? void 0 : memberAddedMessages.message) {
|
|
678
|
+
sendingPromises.push(this.apiClient.api.conversation.postMlsMessage(Uint8Array.from(memberAddedMessages.message)));
|
|
679
|
+
}
|
|
680
|
+
await Promise.all(sendingPromises);
|
|
681
|
+
return newConversation;
|
|
682
|
+
}
|
|
625
683
|
async getConversations(conversationIds) {
|
|
626
684
|
if (!conversationIds || !conversationIds.length) {
|
|
627
685
|
return this.apiClient.api.conversation.getAllConversations();
|