@wireapp/core 20.0.0 → 20.1.1

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,47 @@
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
+ ## [20.1.1](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@20.1.0...@wireapp/core@20.1.1) (2021-12-14)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **core:** Call message send success callback after mismatch handling ([ada3fd1](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/ada3fd1378a7c5fecddd03db9547a89f90a7a174))
12
+
13
+
14
+
15
+
16
+
17
+ # [20.1.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@20.0.2...@wireapp/core@20.1.0) (2021-12-14)
18
+
19
+
20
+ ### Features
21
+
22
+ * **core:** Add tweet metadata on linkPreview when needed ([dc84806](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/dc848068e155aed22415827f3dcbeb3992e9c790))
23
+
24
+
25
+
26
+
27
+
28
+ ## [20.0.2](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@20.0.1...@wireapp/core@20.0.2) (2021-12-09)
29
+
30
+ **Note:** Version bump only for package @wireapp/core
31
+
32
+
33
+
34
+
35
+
36
+ ## [20.0.1](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@20.0.0...@wireapp/core@20.0.1) (2021-12-09)
37
+
38
+
39
+ ### Bug Fixes
40
+
41
+ * **core:** Generate new session and reencrypt payload when sessionIds are missing ([#4200](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4200)) ([07eab82](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/07eab82ee7512bb4eba71adf20c13c5609dbc024))
42
+
43
+
44
+
45
+
46
+
6
47
  # [20.0.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@19.0.0...@wireapp/core@20.0.0) (2021-12-08)
7
48
 
8
49
 
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "dependencies": {
6
6
  "@types/long": "4.0.1",
7
7
  "@types/node": "~14",
8
- "@wireapp/api-client": "16.0.0",
8
+ "@wireapp/api-client": "16.1.0",
9
9
  "@wireapp/cryptobox": "12.7.1",
10
10
  "bazinga64": "5.10.0",
11
11
  "hash.js": "1.1.7",
@@ -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": "20.0.0",
73
- "gitHead": "43fa0f4292ed1379349812589900944b22a1afb8"
72
+ "version": "20.1.1",
73
+ "gitHead": "746f0e8bfe633138756d1497a068bc5214084b9a"
74
74
  }
@@ -686,11 +686,11 @@ class ConversationService {
686
686
  onClientMismatch: callbacks === null || callbacks === void 0 ? void 0 : callbacks.onClientMismatch,
687
687
  });
688
688
  if (!response.errored) {
689
- (_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuccess) === null || _b === void 0 ? void 0 : _b.call(callbacks, genericMessage, response.time);
690
689
  if (!this.isClearFromMismatch(response)) {
691
690
  // We warn the consumer that there is a mismatch that did not prevent message sending
692
- (_c = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onClientMismatch) === null || _c === void 0 ? void 0 : _c.call(callbacks, response, true);
691
+ (_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onClientMismatch) === null || _b === void 0 ? void 0 : _b.call(callbacks, response, true);
693
692
  }
693
+ (_c = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuccess) === null || _c === void 0 ? void 0 : _c.call(callbacks, genericMessage, response.time);
694
694
  }
695
695
  return Object.assign(Object.assign({}, payloadBundle), { content: processedContent || payloadBundle.content, messageTimer: ((_d = genericMessage.ephemeral) === null || _d === void 0 ? void 0 : _d.expireAfterMillis) || 0, state: response.errored ? conversation_2.PayloadBundleState.CANCELLED : conversation_2.PayloadBundleState.OUTGOING_SENT });
696
696
  }
@@ -59,7 +59,10 @@ class MessageService {
59
59
  plainTextPayload = externalPayload.text;
60
60
  cipherText = externalPayload.cipherText;
61
61
  }
62
- const encryptedPayload = await this.cryptographyService.encrypt(plainTextPayload, recipients);
62
+ const { encrypted, missing } = await this.cryptographyService.encrypt(plainTextPayload, recipients);
63
+ const encryptedPayload = Object.keys(missing).length
64
+ ? await this.reencryptAfterMismatch({ missing, deleted: {} }, encrypted, plainText)
65
+ : encrypted;
63
66
  const send = (payload) => {
64
67
  return options.sendAsProtobuf
65
68
  ? this.sendOTRProtobufMessage(sendingClientId, payload, Object.assign(Object.assign({}, options), { assetData: cipherText }))
@@ -97,7 +100,10 @@ class MessageService {
97
100
  const send = (payload) => {
98
101
  return this.sendFederatedOtrMessage(sendingClientId, payload, options);
99
102
  };
100
- const encryptedPayload = await this.cryptographyService.encryptQualified(plainText, recipients);
103
+ const { encrypted, missing } = await this.cryptographyService.encryptQualified(plainText, recipients);
104
+ const encryptedPayload = Object.keys(missing).length
105
+ ? await this.reencryptAfterFederatedMismatch({ missing, deleted: {} }, encrypted, plainText)
106
+ : encrypted;
101
107
  try {
102
108
  return await send(encryptedPayload);
103
109
  }
@@ -216,8 +222,8 @@ class MessageService {
216
222
  deleted.forEach(({ userId, data }) => data.forEach(clientId => delete recipients[userId.id][clientId]));
217
223
  if (missing.length) {
218
224
  const missingPreKeyBundles = await this.apiClient.user.api.postMultiPreKeyBundles(mismatch.missing);
219
- const reEncrypted = await this.cryptographyService.encrypt(plainText, missingPreKeyBundles);
220
- const reEncryptedPayloads = (0, UserClientsUtil_1.flattenUserClients)(reEncrypted);
225
+ const { encrypted } = await this.cryptographyService.encrypt(plainText, missingPreKeyBundles);
226
+ const reEncryptedPayloads = (0, UserClientsUtil_1.flattenUserClients)(encrypted);
221
227
  // add missing clients to the recipients
222
228
  reEncryptedPayloads.forEach(({ data, userId }) => (recipients[userId.id] = Object.assign(Object.assign({}, recipients[userId.id]), data)));
223
229
  }
@@ -238,8 +244,8 @@ class MessageService {
238
244
  deleted.forEach(({ userId, data }) => data.forEach(clientId => delete recipients[userId.domain][userId.id][clientId]));
239
245
  if (Object.keys(missing).length) {
240
246
  const missingPreKeyBundles = await this.apiClient.user.api.postQualifiedMultiPreKeyBundles(mismatch.missing);
241
- const reEncrypted = await this.cryptographyService.encryptQualified(plainText, missingPreKeyBundles);
242
- const reEncryptedPayloads = (0, UserClientsUtil_1.flattenQualifiedUserClients)(reEncrypted);
247
+ const { encrypted } = await this.cryptographyService.encryptQualified(plainText, missingPreKeyBundles);
248
+ const reEncryptedPayloads = (0, UserClientsUtil_1.flattenQualifiedUserClients)(encrypted);
243
249
  reEncryptedPayloads.forEach(({ data, userId }) => (recipients[userId.domain][userId.id] = Object.assign(Object.assign({}, recipients[userId.domain][userId.id]), data)));
244
250
  }
245
251
  return recipients;
@@ -37,6 +37,7 @@ class MessageToProtoMapper {
37
37
  author: linkPreview.tweet.author,
38
38
  username: linkPreview.tweet.username,
39
39
  });
40
+ linkPreviewMessage.metaData = 'tweet';
40
41
  }
41
42
  if (linkPreview.imageUploaded) {
42
43
  const { asset, image } = linkPreview.imageUploaded;
@@ -29,9 +29,14 @@ export declare class CryptographyService {
29
29
  static convertBase64RecipientsToArray(recipients: OTRRecipients<string>): OTRRecipients<Uint8Array>;
30
30
  createCryptobox(): Promise<SerializedPreKey[]>;
31
31
  decrypt(sessionId: string, encodedCiphertext: string): Promise<Uint8Array>;
32
- private static dismantleSessionId;
33
- encryptQualified(plainText: Uint8Array, preKeyBundles: QualifiedUserPreKeyBundleMap | QualifiedUserClients): Promise<QualifiedOTRRecipients>;
34
- encrypt(plainText: Uint8Array, users: UserPreKeyBundleMap | UserClients, domain?: string): Promise<OTRRecipients<Uint8Array>>;
32
+ encryptQualified(plainText: Uint8Array, preKeyBundles: QualifiedUserPreKeyBundleMap | QualifiedUserClients): Promise<{
33
+ missing: QualifiedUserClients;
34
+ encrypted: QualifiedOTRRecipients;
35
+ }>;
36
+ encrypt(plainText: Uint8Array, users: UserPreKeyBundleMap | UserClients, domain?: string): Promise<{
37
+ missing: UserClients;
38
+ encrypted: OTRRecipients<Uint8Array>;
39
+ }>;
35
40
  private encryptPayloadForSession;
36
41
  initCryptobox(): Promise<void>;
37
42
  deleteCryptographyStores(): Promise<boolean[]>;
@@ -81,41 +81,39 @@ class CryptographyService {
81
81
  const messageBytes = bazinga64_1.Decoder.fromBase64(encodedCiphertext).asBytes;
82
82
  return this.cryptobox.decrypt(sessionId, messageBytes.buffer);
83
83
  }
84
- static dismantleSessionId(sessionId) {
85
- // see https://regex101.com/r/c8FtCw/1
86
- const regex = /((?<domain>.+)@)?(?<userId>.+)@(?<clientId>.+)$/g;
87
- const match = regex.exec(sessionId);
88
- const { domain, userId, clientId } = (match === null || match === void 0 ? void 0 : match.groups) || {};
89
- return { clientId, domain, userId };
90
- }
91
84
  async encryptQualified(plainText, preKeyBundles) {
92
85
  const qualifiedOTRRecipients = {};
86
+ const missing = {};
93
87
  for (const [domain, preKeyBundleMap] of Object.entries(preKeyBundles)) {
94
- qualifiedOTRRecipients[domain] = await this.encrypt(plainText, preKeyBundleMap, domain);
88
+ const result = await this.encrypt(plainText, preKeyBundleMap, domain);
89
+ qualifiedOTRRecipients[domain] = result.encrypted;
90
+ missing[domain] = result.missing;
95
91
  }
96
- return qualifiedOTRRecipients;
92
+ return {
93
+ encrypted: qualifiedOTRRecipients,
94
+ missing,
95
+ };
97
96
  }
98
97
  async encrypt(plainText, users, domain) {
99
- const bundles = [];
98
+ const encrypted = {};
99
+ const missing = {};
100
100
  for (const userId in users) {
101
101
  const clientIds = (0, util_1.isUserClients)(users) ? users[userId] : Object.keys(users[userId]);
102
102
  for (const clientId of clientIds) {
103
103
  const base64PreKey = (0, util_1.isUserClients)(users) ? undefined : users[userId][clientId].key;
104
104
  const sessionId = CryptographyService.constructSessionId(userId, clientId, domain || null);
105
- bundles.push(this.encryptPayloadForSession(sessionId, plainText, base64PreKey));
105
+ const result = await this.encryptPayloadForSession(sessionId, plainText, base64PreKey);
106
+ if (result) {
107
+ encrypted[userId] || (encrypted[userId] = {});
108
+ encrypted[userId][clientId] = result.encryptedPayload;
109
+ }
110
+ else {
111
+ missing[userId] || (missing[userId] = []);
112
+ missing[userId].push(clientId);
113
+ }
106
114
  }
107
115
  }
108
- const payloads = await Promise.all(bundles);
109
- return payloads.reduce((recipients, payload) => {
110
- if (!payload) {
111
- return recipients;
112
- }
113
- const { encryptedPayload, sessionId } = payload;
114
- const { userId, clientId } = CryptographyService.dismantleSessionId(sessionId);
115
- recipients[userId] || (recipients[userId] = {});
116
- recipients[userId][clientId] = encryptedPayload;
117
- return recipients;
118
- }, {});
116
+ return { encrypted, missing };
119
117
  }
120
118
  async encryptPayloadForSession(sessionId, plainText, base64EncodedPreKey) {
121
119
  this.logger.log(`Encrypting payload for session ID "${sessionId}"`);