@wireapp/core 25.3.1 → 27.0.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,57 @@
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
+ # [27.0.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@26.1.0...@wireapp/core@27.0.0) (2022-05-17)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Avoid silently creating client when initializing core ([#4264](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4264)) ([65a843a](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/65a843a2052dad2543e6cf046aca55ce85cc7c5e))
12
+
13
+
14
+ ### BREAKING CHANGES
15
+
16
+ * if you were relying on account.init() to also create a new client, this behavior now change and will throw an error instead. If you also want to create a device (if it doesn't exist already), you should use the account.login() or account.initClient() methods instead
17
+
18
+
19
+
20
+
21
+
22
+ # [26.1.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@26.0.0...@wireapp/core@26.1.0) (2022-05-16)
23
+
24
+
25
+ ### Features
26
+
27
+ * Allow consumer to set number of prekeys generated ([#4263](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4263)) ([648ecda](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/648ecdad260488e1d07965a84a28c346d6f015c3))
28
+
29
+
30
+
31
+
32
+
33
+ # [26.0.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@25.3.1...@wireapp/core@26.0.0) (2022-05-16)
34
+
35
+
36
+ ### Bug Fixes
37
+
38
+ * Allow sending targeted lastRead and Countly messages ([#4262](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4262)) ([69c7d98](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/69c7d98272dc9beea6e5d9a99d6392177f0be361))
39
+
40
+
41
+ ### BREAKING CHANGES
42
+
43
+ * To send `lastRead` and `countly` as protobuf message, you now need to provide a `MessageSendingOptions` object as last parameter.
44
+
45
+ ```js
46
+ core.service.conversation.sendLastRead(conversation, timestamp, true);
47
+
48
+ // Becomes
49
+
50
+ core.service.converstaion.sendLastRead(conversation, timestamp, {sendAsProtobuf: true});
51
+ ```
52
+
53
+
54
+
55
+
56
+
6
57
  ## [25.3.1](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@25.3.0...@wireapp/core@25.3.1) (2022-05-16)
7
58
 
8
59
  **Note:** Version bump only for package @wireapp/core
package/package.json CHANGED
@@ -69,6 +69,6 @@
69
69
  "test:project": "yarn dist && yarn test",
70
70
  "test:node": "nyc jasmine --config=jasmine.json"
71
71
  },
72
- "version": "25.3.1",
73
- "gitHead": "53e7ce7b1e5d68e425b128555e19e3203a5292c9"
72
+ "version": "27.0.0",
73
+ "gitHead": "35f51e328c1ad095a8f07a61b176054952d58e21"
74
74
  }
@@ -53,11 +53,26 @@ export interface Account {
53
53
  on(event: TOPIC.ERROR, listener: (payload: CoreError) => void): this;
54
54
  }
55
55
  export declare type CreateStoreFn = (storeName: string, context: Context) => undefined | Promise<CRUDEngine | undefined>;
56
+ interface AccountOptions {
57
+ /** Used to store info in the database (will create a inMemory engine if returns undefined) */
58
+ createStore?: CreateStoreFn;
59
+ /** Number of prekeys to generate when creating a new device (defaults to 2)
60
+ * Prekeys are Diffie-Hellmann public keys which allow offline initiation of a secure Proteus session between two devices.
61
+ * Having a high value will:
62
+ * - make creating a new device consuming more CPU resources
63
+ * - make it less likely that all prekeys get consumed while the device is offline and the last resort prekey will not be used to create new session
64
+ * Having a low value will:
65
+ * - make creating a new device fast
66
+ * - 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
67
+ */
68
+ nbPrekeys?: number;
69
+ }
56
70
  export declare class Account extends EventEmitter {
57
71
  private readonly apiClient;
58
72
  private readonly logger;
59
73
  private readonly createStore;
60
74
  private storeEngine?;
75
+ private readonly nbPrekeys;
61
76
  static readonly TOPIC: typeof TOPIC;
62
77
  service?: {
63
78
  account: AccountService;
@@ -77,22 +92,51 @@ export declare class Account extends EventEmitter {
77
92
  backendFeatures: BackendFeatures;
78
93
  /**
79
94
  * @param apiClient The apiClient instance to use in the core (will create a new new one if undefined)
80
- * @param storeEngineProvider Used to store info in the database (will create a inMemory engine if returns undefined)
95
+ * @param storeEngineProvider
81
96
  */
82
- constructor(apiClient?: APIClient, { createStore }?: {
83
- createStore?: CreateStoreFn;
84
- });
97
+ constructor(apiClient?: APIClient, { createStore, nbPrekeys }?: AccountOptions);
85
98
  private persistCookie;
86
99
  get clientId(): string;
87
100
  get userId(): string;
101
+ /**
102
+ * Will register a new user to the backend
103
+ *
104
+ * @param registration The user's data
105
+ * @param clientType Type of client to create (temporary or permanent)
106
+ */
88
107
  register(registration: RegisterData, clientType: ClientType): Promise<Context>;
108
+ /**
109
+ * Will init the core with an aleady existing client (both on backend and local)
110
+ * Will fail if local client cannot be found
111
+ *
112
+ * @param clientType The type of client the user is using (temporary or permanent)
113
+ * @param cookie The cookie to identify the user against backend (will use the browser's one if not given)
114
+ */
89
115
  init(clientType: ClientType, cookie?: Cookie, initClient?: boolean): Promise<Context>;
90
- initServices(context: Context): Promise<void>;
116
+ /**
117
+ * Will log the user in with the given credential.
118
+ * Will also create the local client and store it in DB
119
+ *
120
+ * @param loginData The credentials of the user
121
+ * @param initClient Should the call also create the local client
122
+ * @param clientInfo Info about the client to create (name, type...)
123
+ */
91
124
  login(loginData: LoginData, initClient?: boolean, clientInfo?: ClientInfo): Promise<Context>;
125
+ /**
126
+ * Will try to get the load the local client from local DB.
127
+ * If clientInfo are provided, will also create the client on backend and DB
128
+ * If clientInfo are not provideo, the method will fail if local client cannot be found
129
+ *
130
+ * @param loginData User's credentials
131
+ * @param clientInfo Will allow creating the client if the local client cannot be found (else will fail if local client is not found)
132
+ * @param entropyData Additional entropy data
133
+ * @returns The local existing client or newly created client
134
+ */
92
135
  initClient(loginData: LoginData, clientInfo?: ClientInfo, entropyData?: Uint8Array): Promise<{
93
136
  isNewClient: boolean;
94
137
  localClient: RegisteredClient;
95
138
  }>;
139
+ initServices(context: Context): Promise<void>;
96
140
  loadAndValidateLocalClient(): Promise<RegisteredClient>;
97
141
  private registerClient;
98
142
  private resetContext;
@@ -67,12 +67,17 @@ var TOPIC;
67
67
  (function (TOPIC) {
68
68
  TOPIC["ERROR"] = "Account.TOPIC.ERROR";
69
69
  })(TOPIC || (TOPIC = {}));
70
+ const coreDefaultClient = {
71
+ classification: client_1.ClientClassification.DESKTOP,
72
+ cookieLabel: 'default',
73
+ model: '@wireapp/core',
74
+ };
70
75
  class Account extends events_1.EventEmitter {
71
76
  /**
72
77
  * @param apiClient The apiClient instance to use in the core (will create a new new one if undefined)
73
- * @param storeEngineProvider Used to store info in the database (will create a inMemory engine if returns undefined)
78
+ * @param storeEngineProvider
74
79
  */
75
- constructor(apiClient = new api_client_1.APIClient(), { createStore = () => undefined } = {}) {
80
+ constructor(apiClient = new api_client_1.APIClient(), { createStore = () => undefined, nbPrekeys = 2 } = {}) {
76
81
  super();
77
82
  this.handlePayload = async (payload) => {
78
83
  switch (payload.type) {
@@ -90,6 +95,7 @@ class Account extends events_1.EventEmitter {
90
95
  };
91
96
  this.apiClient = apiClient;
92
97
  this.backendFeatures = this.apiClient.backendFeatures;
98
+ this.nbPrekeys = nbPrekeys;
93
99
  this.createStore = createStore;
94
100
  apiClient.on(api_client_1.APIClient.TOPIC.COOKIE_REFRESH, async (cookie) => {
95
101
  if (cookie && this.storeEngine) {
@@ -116,11 +122,24 @@ class Account extends events_1.EventEmitter {
116
122
  get userId() {
117
123
  return this.apiClient.validatedUserId;
118
124
  }
125
+ /**
126
+ * Will register a new user to the backend
127
+ *
128
+ * @param registration The user's data
129
+ * @param clientType Type of client to create (temporary or permanent)
130
+ */
119
131
  async register(registration, clientType) {
120
132
  const context = await this.apiClient.register(registration, clientType);
121
133
  await this.initServices(context);
122
134
  return context;
123
135
  }
136
+ /**
137
+ * Will init the core with an aleady existing client (both on backend and local)
138
+ * Will fail if local client cannot be found
139
+ *
140
+ * @param clientType The type of client the user is using (temporary or permanent)
141
+ * @param cookie The cookie to identify the user against backend (will use the browser's one if not given)
142
+ */
124
143
  async init(clientType, cookie, initClient = true) {
125
144
  const context = await this.apiClient.init(clientType, cookie);
126
145
  await this.initServices(context);
@@ -129,44 +148,15 @@ class Account extends events_1.EventEmitter {
129
148
  }
130
149
  return context;
131
150
  }
132
- async initServices(context) {
133
- this.storeEngine = await this.initEngine(context);
134
- const accountService = new account_1.AccountService(this.apiClient);
135
- const assetService = new conversation_1.AssetService(this.apiClient);
136
- const cryptographyService = new cryptography_1.CryptographyService(this.apiClient, this.storeEngine, {
137
- // We want to encrypt with fully qualified session ids, only if the backend is federated with other backends
138
- useQualifiedIds: this.backendFeatures.isFederated,
139
- });
140
- const clientService = new client_2.ClientService(this.apiClient, this.storeEngine, cryptographyService);
141
- const connectionService = new connection_1.ConnectionService(this.apiClient);
142
- const giphyService = new giphy_1.GiphyService(this.apiClient);
143
- const linkPreviewService = new linkPreview_1.LinkPreviewService(assetService);
144
- const conversationService = new conversation_1.ConversationService(this.apiClient, cryptographyService, {
145
- // We can use qualified ids to send messages as long as the backend supports federated endpoints
146
- useQualifiedIds: this.backendFeatures.federationEndpoints,
147
- });
148
- const notificationService = new notification_1.NotificationService(this.apiClient, cryptographyService, this.storeEngine);
149
- const selfService = new self_1.SelfService(this.apiClient);
150
- const teamService = new team_1.TeamService(this.apiClient);
151
- const broadcastService = new broadcast_1.BroadcastService(this.apiClient, cryptographyService);
152
- const userService = new user_1.UserService(this.apiClient, broadcastService, conversationService, connectionService);
153
- this.service = {
154
- account: accountService,
155
- asset: assetService,
156
- broadcast: broadcastService,
157
- client: clientService,
158
- connection: connectionService,
159
- conversation: conversationService,
160
- cryptography: cryptographyService,
161
- giphy: giphyService,
162
- linkPreview: linkPreviewService,
163
- notification: notificationService,
164
- self: selfService,
165
- team: teamService,
166
- user: userService,
167
- };
168
- }
169
- async login(loginData, initClient = true, clientInfo) {
151
+ /**
152
+ * Will log the user in with the given credential.
153
+ * Will also create the local client and store it in DB
154
+ *
155
+ * @param loginData The credentials of the user
156
+ * @param initClient Should the call also create the local client
157
+ * @param clientInfo Info about the client to create (name, type...)
158
+ */
159
+ async login(loginData, initClient = true, clientInfo = coreDefaultClient) {
170
160
  this.resetContext();
171
161
  auth_2.LoginSanitizer.removeNonPrintableCharacters(loginData);
172
162
  const context = await this.apiClient.login(loginData);
@@ -176,6 +166,16 @@ class Account extends events_1.EventEmitter {
176
166
  }
177
167
  return context;
178
168
  }
169
+ /**
170
+ * Will try to get the load the local client from local DB.
171
+ * If clientInfo are provided, will also create the client on backend and DB
172
+ * If clientInfo are not provideo, the method will fail if local client cannot be found
173
+ *
174
+ * @param loginData User's credentials
175
+ * @param clientInfo Will allow creating the client if the local client cannot be found (else will fail if local client is not found)
176
+ * @param entropyData Additional entropy data
177
+ * @returns The local existing client or newly created client
178
+ */
179
179
  async initClient(loginData, clientInfo, entropyData) {
180
180
  var _a, _b;
181
181
  if (!this.service) {
@@ -186,6 +186,10 @@ class Account extends events_1.EventEmitter {
186
186
  return { isNewClient: false, localClient };
187
187
  }
188
188
  catch (error) {
189
+ if (!clientInfo) {
190
+ // If no client info provided, the client should not be created
191
+ throw error;
192
+ }
189
193
  // There was no client so we need to "create" and "register" a client
190
194
  const notFoundInDatabase = error instanceof cryptobox.error.CryptoboxError ||
191
195
  error.constructor.name === 'CryptoboxError' ||
@@ -216,6 +220,44 @@ class Account extends events_1.EventEmitter {
216
220
  throw error;
217
221
  }
218
222
  }
223
+ async initServices(context) {
224
+ this.storeEngine = await this.initEngine(context);
225
+ const accountService = new account_1.AccountService(this.apiClient);
226
+ const assetService = new conversation_1.AssetService(this.apiClient);
227
+ const cryptographyService = new cryptography_1.CryptographyService(this.apiClient, this.storeEngine, {
228
+ // We want to encrypt with fully qualified session ids, only if the backend is federated with other backends
229
+ useQualifiedIds: this.backendFeatures.isFederated,
230
+ nbPrekeys: this.nbPrekeys,
231
+ });
232
+ const clientService = new client_2.ClientService(this.apiClient, this.storeEngine, cryptographyService);
233
+ const connectionService = new connection_1.ConnectionService(this.apiClient);
234
+ const giphyService = new giphy_1.GiphyService(this.apiClient);
235
+ const linkPreviewService = new linkPreview_1.LinkPreviewService(assetService);
236
+ const conversationService = new conversation_1.ConversationService(this.apiClient, cryptographyService, {
237
+ // We can use qualified ids to send messages as long as the backend supports federated endpoints
238
+ useQualifiedIds: this.backendFeatures.federationEndpoints,
239
+ });
240
+ const notificationService = new notification_1.NotificationService(this.apiClient, cryptographyService, this.storeEngine);
241
+ const selfService = new self_1.SelfService(this.apiClient);
242
+ const teamService = new team_1.TeamService(this.apiClient);
243
+ const broadcastService = new broadcast_1.BroadcastService(this.apiClient, cryptographyService);
244
+ const userService = new user_1.UserService(this.apiClient, broadcastService, conversationService, connectionService);
245
+ this.service = {
246
+ account: accountService,
247
+ asset: assetService,
248
+ broadcast: broadcastService,
249
+ client: clientService,
250
+ connection: connectionService,
251
+ conversation: conversationService,
252
+ cryptography: cryptographyService,
253
+ giphy: giphyService,
254
+ linkPreview: linkPreviewService,
255
+ notification: notificationService,
256
+ self: selfService,
257
+ team: teamService,
258
+ user: userService,
259
+ };
260
+ }
219
261
  async loadAndValidateLocalClient() {
220
262
  await this.service.cryptography.initCryptobox();
221
263
  const loadedClient = await this.service.client.getLocalClient();
@@ -223,7 +265,7 @@ class Account extends events_1.EventEmitter {
223
265
  this.apiClient.context.clientId = loadedClient.id;
224
266
  return loadedClient;
225
267
  }
226
- async registerClient(loginData, clientInfo, entropyData) {
268
+ async registerClient(loginData, clientInfo = coreDefaultClient, entropyData) {
227
269
  if (!this.service) {
228
270
  throw new Error('Services are not set.');
229
271
  }
@@ -36,5 +36,5 @@ export declare class ClientService {
36
36
  getLocalClient(): Promise<MetaClient>;
37
37
  createLocalClient(client: RegisteredClient, domain?: string): Promise<MetaClient>;
38
38
  synchronizeClients(): Promise<MetaClient[]>;
39
- register(loginData: LoginData, clientInfo?: ClientInfo, entropyData?: Uint8Array): Promise<RegisteredClient>;
39
+ register(loginData: LoginData, clientInfo: ClientInfo, entropyData?: Uint8Array): Promise<RegisteredClient>;
40
40
  }
@@ -71,11 +71,7 @@ class ClientService {
71
71
  return this.database.createClientList(this.apiClient.context.userId, filteredClients, (_a = this.apiClient.context) === null || _a === void 0 ? void 0 : _a.domain);
72
72
  }
73
73
  // TODO: Split functionality into "create" and "register" client
74
- async register(loginData, clientInfo = {
75
- classification: client_1.ClientClassification.DESKTOP,
76
- cookieLabel: 'default',
77
- model: '@wireapp/core',
78
- }, entropyData) {
74
+ async register(loginData, clientInfo, entropyData) {
79
75
  if (!this.apiClient.context) {
80
76
  throw new Error('Context is not set.');
81
77
  }
@@ -115,10 +115,10 @@ export declare class ConversationService {
115
115
  *
116
116
  * @param conversationId The conversation which has been read
117
117
  * @param lastReadTimestamp The timestamp at which the conversation was read
118
- * @param sendAsProtobuf?
118
+ * @param sendingOptions?
119
119
  * @return Resolves when the message has been sent
120
120
  */
121
- sendLastRead(conversationId: string, lastReadTimestamp: number, sendAsProtobuf?: boolean): Promise<(MessageSendingStatus & {
121
+ sendLastRead(conversationId: string, lastReadTimestamp: number, sendingOptions?: MessageSendingOptions): Promise<(MessageSendingStatus & {
122
122
  errored?: boolean | undefined;
123
123
  }) | (ClientMismatch & {
124
124
  errored?: boolean | undefined;
@@ -127,10 +127,10 @@ export declare class ConversationService {
127
127
  * Syncs all self user's devices with the countly id
128
128
  *
129
129
  * @param countlyId The countly id of the current device
130
- * @param sendAsProtobuf?
130
+ * @param sendingOptions?
131
131
  * @return Resolves when the message has been sent
132
132
  */
133
- sendCountlySync(countlyId: string, sendAsProtobuf?: boolean): Promise<(MessageSendingStatus & {
133
+ sendCountlySync(countlyId: string, sendingOptions: MessageSendingOptions): Promise<(MessageSendingStatus & {
134
134
  errored?: boolean | undefined;
135
135
  }) | (ClientMismatch & {
136
136
  errored?: boolean | undefined;
@@ -470,10 +470,10 @@ class ConversationService {
470
470
  *
471
471
  * @param conversationId The conversation which has been read
472
472
  * @param lastReadTimestamp The timestamp at which the conversation was read
473
- * @param sendAsProtobuf?
473
+ * @param sendingOptions?
474
474
  * @return Resolves when the message has been sent
475
475
  */
476
- async sendLastRead(conversationId, lastReadTimestamp, sendAsProtobuf) {
476
+ async sendLastRead(conversationId, lastReadTimestamp, sendingOptions) {
477
477
  const lastRead = new protocol_messaging_1.LastRead({
478
478
  conversationId,
479
479
  lastReadTimestamp,
@@ -483,19 +483,16 @@ class ConversationService {
483
483
  messageId: MessageBuilder_1.MessageBuilder.createId(),
484
484
  });
485
485
  const { id: selfConversationId, domain: selfConversationDomain } = await this.getSelfConversationId();
486
- return this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, {
487
- conversationDomain: selfConversationDomain,
488
- sendAsProtobuf,
489
- });
486
+ return this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, Object.assign({ conversationDomain: selfConversationDomain }, sendingOptions));
490
487
  }
491
488
  /**
492
489
  * Syncs all self user's devices with the countly id
493
490
  *
494
491
  * @param countlyId The countly id of the current device
495
- * @param sendAsProtobuf?
492
+ * @param sendingOptions?
496
493
  * @return Resolves when the message has been sent
497
494
  */
498
- async sendCountlySync(countlyId, sendAsProtobuf) {
495
+ async sendCountlySync(countlyId, sendingOptions) {
499
496
  const { id: selfConversationId, domain: selfConversationDomain } = await this.getSelfConversationId();
500
497
  const dataTransfer = new protocol_messaging_1.DataTransfer({
501
498
  trackingIdentifier: {
@@ -506,10 +503,7 @@ class ConversationService {
506
503
  [conversation_2.GenericMessageType.DATA_TRANSFER]: dataTransfer,
507
504
  messageId: MessageBuilder_1.MessageBuilder.createId(),
508
505
  });
509
- return this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, {
510
- conversationDomain: selfConversationDomain,
511
- sendAsProtobuf,
512
- });
506
+ return this.sendGenericMessage(this.apiClient.validatedClientId, selfConversationId, genericMessage, Object.assign({ conversationDomain: selfConversationDomain }, sendingOptions));
513
507
  }
514
508
  /**
515
509
  * Get a fresh list from backend of clients for all the participants of the conversation.
@@ -20,8 +20,9 @@ export declare class CryptographyService {
20
20
  private readonly logger;
21
21
  cryptobox: Cryptobox;
22
22
  private readonly database;
23
- constructor(apiClient: APIClient, storeEngine: CRUDEngine, config?: {
24
- useQualifiedIds?: boolean;
23
+ constructor(apiClient: APIClient, storeEngine: CRUDEngine, config: {
24
+ useQualifiedIds: boolean;
25
+ nbPrekeys: number;
25
26
  });
26
27
  constructSessionId(userId: string | QualifiedId, clientId: string, domain?: string): string;
27
28
  static convertArrayRecipientsToBase64(recipients: OTRRecipients<Uint8Array>): OTRRecipients<string>;
@@ -32,11 +32,11 @@ const util_1 = require("../util");
32
32
  const CryptographyDatabaseRepository_1 = require("./CryptographyDatabaseRepository");
33
33
  const GenericMessageMapper_1 = require("./GenericMessageMapper");
34
34
  class CryptographyService {
35
- constructor(apiClient, storeEngine, config = {}) {
35
+ constructor(apiClient, storeEngine, config) {
36
36
  this.apiClient = apiClient;
37
37
  this.storeEngine = storeEngine;
38
38
  this.config = config;
39
- this.cryptobox = new cryptobox_1.Cryptobox(this.storeEngine);
39
+ this.cryptobox = new cryptobox_1.Cryptobox(this.storeEngine, config.nbPrekeys);
40
40
  this.database = new CryptographyDatabaseRepository_1.CryptographyDatabaseRepository(this.storeEngine);
41
41
  this.logger = (0, logdown_1.default)('@wireapp/core/cryptography/CryptographyService', {
42
42
  logger: console,