@wireapp/core 17.34.0 → 20.0.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,102 @@
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.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)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **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))
12
+
13
+
14
+
15
+
16
+
17
+ # [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)
18
+
19
+
20
+ ### Code Refactoring
21
+
22
+ * **core:** Harmonize asset param name ([#4199](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4199)) ([f29c825](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/f29c825df427e9fccae164a728f0071fdf1bc3af))
23
+
24
+
25
+ ### BREAKING CHANGES
26
+
27
+ * **core:** The `imageAsset` property given to the `MessageBuilder.createImage` function has been renamed `asset` to be coherent with sending files.
28
+ Replace `MessageBuilder.createImage({..., imageAsset: asset})` with `MessageBuilder.createImage({..., asset})`
29
+
30
+
31
+
32
+
33
+
34
+ # [19.0.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@18.0.0...@wireapp/core@19.0.0) (2021-12-08)
35
+
36
+
37
+ ### Features
38
+
39
+ * **core:** Ability to cancel asset uploading ([#4198](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4198)) ([e111f46](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/e111f46d06bf2ec22f2002c9a2954cdf0c9e8d09))
40
+
41
+
42
+ ### BREAKING CHANGES
43
+
44
+ * **core:** Uploading an asset now return a structure that allow cancelling the upload. Thus instances of `await account.service.asset.uploadAsset(...)` must be replaced by
45
+ ```
46
+ const {cancel, response} = await account.service.asset.uploadAsset(...);
47
+ cancel() // This is how you cancel the upload
48
+ await response// This will contain the uploaded asset once the upload is done
49
+ ```
50
+
51
+
52
+
53
+
54
+
55
+ # [18.0.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@17.34.0...@wireapp/core@18.0.0) (2021-12-08)
56
+
57
+
58
+ ### Features
59
+
60
+ * **core:** Make message builder stateless ([#4197](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/issues/4197)) ([95a51a6](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/commit/95a51a614b20730767916885182eb185b46c4c38))
61
+
62
+
63
+ ### BREAKING CHANGES
64
+
65
+ * **core:** - `MessageBuilder` has been moved from `account.services.conversation.messageBuilder` to an own stateless class.
66
+ - All method of the `MessageBuilder` now take a required `from` parameter
67
+ - `MessageBuilder` is not uploading files under the hood. Upload must be done in a separate function call
68
+
69
+ Replace
70
+
71
+ ```
72
+ const textPayload = account.service.conversation.messageBuilder.createText(...);
73
+ ```
74
+
75
+ With
76
+
77
+ ```
78
+ import {MessageBuilder} from '@wireapp/core/src/main/conversation/message/MessageBuilder';
79
+ //...
80
+ const textPayload = MessageBuilder.createText(...);
81
+ ```
82
+
83
+ Replace
84
+
85
+ ```
86
+ const linkPreview = await account.service.conversation.messageBuilder.createLinkPreview(...);
87
+ cons textPayload = account.service.conversation.messageBuilder.createText(...).withLinkPreview([linkPreview]);
88
+ ```
89
+
90
+ With
91
+
92
+ ```
93
+ cons textPayload = account.service.conversation.messageBuilder
94
+ .createText(...)
95
+ .withLinkPreview([await this.account.service.linkPreview.uploadLinkPreviewImage(newLinkPreview)]);
96
+ ```
97
+
98
+
99
+
100
+
101
+
6
102
  # [17.34.0](https://github.com/wireapp/wire-web-packages/tree/main/packages/core/compare/@wireapp/core@17.33.1...@wireapp/core@17.34.0) (2021-12-06)
7
103
 
8
104
 
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": "15.11.1",
8
+ "@wireapp/api-client": "16.0.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": "17.34.0",
73
- "gitHead": "c070dc05ea9e0abbf6bc6837035ea756dcfa5af0"
72
+ "version": "20.0.1",
73
+ "gitHead": "3c5496c4f2d17974cd871b65c7882464caec343e"
74
74
  }
@@ -20,6 +20,7 @@ import { SelfService } from './self/';
20
20
  import { TeamService } from './team/';
21
21
  import { UserService } from './user/';
22
22
  import { AccountService } from './account/';
23
+ import { LinkPreviewService } from './linkPreview';
23
24
  declare enum TOPIC {
24
25
  ERROR = "Account.TOPIC.ERROR"
25
26
  }
@@ -71,6 +72,7 @@ export declare class Account extends EventEmitter {
71
72
  conversation: ConversationService;
72
73
  cryptography: CryptographyService;
73
74
  giphy: GiphyService;
75
+ linkPreview: LinkPreviewService;
74
76
  notification: NotificationService;
75
77
  self: SelfService;
76
78
  team: TeamService;
@@ -62,6 +62,7 @@ const self_1 = require("./self/");
62
62
  const team_1 = require("./team/");
63
63
  const user_1 = require("./user/");
64
64
  const account_1 = require("./account/");
65
+ const linkPreview_1 = require("./linkPreview");
65
66
  var TOPIC;
66
67
  (function (TOPIC) {
67
68
  TOPIC["ERROR"] = "Account.TOPIC.ERROR";
@@ -155,7 +156,8 @@ class Account extends events_1.EventEmitter {
155
156
  const clientService = new client_2.ClientService(this.apiClient, storeEngine, cryptographyService);
156
157
  const connectionService = new connection_1.ConnectionService(this.apiClient);
157
158
  const giphyService = new giphy_1.GiphyService(this.apiClient);
158
- const conversationService = new conversation_1.ConversationService(this.apiClient, cryptographyService, assetService);
159
+ const linkPreviewService = new linkPreview_1.LinkPreviewService(assetService);
160
+ const conversationService = new conversation_1.ConversationService(this.apiClient, cryptographyService);
159
161
  const notificationService = new notification_1.NotificationService(this.apiClient, cryptographyService, storeEngine);
160
162
  const selfService = new self_1.SelfService(this.apiClient);
161
163
  const teamService = new team_1.TeamService(this.apiClient);
@@ -170,6 +172,7 @@ class Account extends events_1.EventEmitter {
170
172
  conversation: conversationService,
171
173
  cryptography: cryptographyService,
172
174
  giphy: giphyService,
175
+ linkPreview: linkPreviewService,
173
176
  notification: notificationService,
174
177
  self: selfService,
175
178
  team: teamService,
@@ -1,11 +1,10 @@
1
+ /// <reference types="node" />
1
2
  import type { APIClient } from '@wireapp/api-client';
2
3
  import type { AssetOptions } from '@wireapp/api-client/src/asset';
3
- import type { FileContent, ImageContent } from '../conversation/content/';
4
+ import type { ProgressCallback, RequestCancelable } from '@wireapp/api-client/src/http';
4
5
  import type { EncryptedAssetUploaded } from '../cryptography/';
5
6
  export declare class AssetService {
6
7
  private readonly apiClient;
7
8
  constructor(apiClient: APIClient);
8
- private postAsset;
9
- uploadImageAsset(image: ImageContent, options?: AssetOptions): Promise<EncryptedAssetUploaded>;
10
- uploadFileAsset(file: FileContent, options?: AssetOptions): Promise<EncryptedAssetUploaded>;
9
+ uploadAsset(plainText: Buffer | Uint8Array, options?: AssetOptions, progressCallback?: ProgressCallback): Promise<RequestCancelable<EncryptedAssetUploaded>>;
11
10
  }
@@ -24,27 +24,23 @@ class AssetService {
24
24
  constructor(apiClient) {
25
25
  this.apiClient = apiClient;
26
26
  }
27
- async postAsset(plainText, options, progressCallback) {
27
+ async uploadAsset(plainText, options, progressCallback) {
28
28
  const { cipherText, keyBytes, sha256 } = await (0, AssetCryptography_1.encryptAsset)({
29
29
  plainText,
30
30
  algorithm: options === null || options === void 0 ? void 0 : options.algorithm,
31
31
  hash: options === null || options === void 0 ? void 0 : options.hash,
32
32
  });
33
- const request = await this.apiClient.asset.api.postAsset(new Uint8Array(cipherText), options, progressCallback);
34
- const { key, token } = await request.response;
35
- return {
36
- cipherText,
37
- key,
38
- keyBytes,
39
- sha256,
40
- token,
41
- };
42
- }
43
- uploadImageAsset(image, options) {
44
- return this.postAsset(image.data, options);
45
- }
46
- uploadFileAsset(file, options) {
47
- return this.postAsset(file.data, options);
33
+ const request = this.apiClient.asset.api.postAsset(new Uint8Array(cipherText), options, progressCallback);
34
+ return Object.assign(Object.assign({}, request), { response: request.response.then(response => {
35
+ const { key, token } = response;
36
+ return {
37
+ cipherText,
38
+ key,
39
+ keyBytes,
40
+ sha256,
41
+ token,
42
+ };
43
+ }) });
48
44
  }
49
45
  }
50
46
  exports.AssetService = AssetService;
@@ -4,10 +4,9 @@ import { MessageSendingStatus, Conversation, DefaultConversationRoleName, MutedS
4
4
  import type { ConversationMemberLeaveEvent } from '@wireapp/api-client/src/event/';
5
5
  import type { QualifiedId, UserPreKeyBundleMap } from '@wireapp/api-client/src/user/';
6
6
  import { GenericMessage } from '@wireapp/protocol-messaging';
7
- import { AssetService, MessageTimer } from '../conversation/';
7
+ import { MessageTimer } from '../conversation/';
8
8
  import type { RemoteData } from '../conversation/content/';
9
9
  import type { CryptographyService } from '../cryptography/';
10
- import { MessageBuilder } from './message/MessageBuilder';
11
10
  import type { ClearConversationMessage, DeleteMessage, HideMessage, OtrMessage } from './message/OtrMessage';
12
11
  export declare enum MessageTargetMode {
13
12
  NONE = 0,
@@ -62,11 +61,9 @@ export interface MessageSendingCallbacks {
62
61
  }
63
62
  export declare class ConversationService {
64
63
  private readonly apiClient;
65
- private readonly assetService;
66
64
  readonly messageTimer: MessageTimer;
67
- readonly messageBuilder: MessageBuilder;
68
65
  private readonly messageService;
69
- constructor(apiClient: APIClient, cryptographyService: CryptographyService, assetService: AssetService);
66
+ constructor(apiClient: APIClient, cryptographyService: CryptographyService);
70
67
  private createEphemeral;
71
68
  private getConversationQualifiedMembers;
72
69
  /**
@@ -35,11 +35,9 @@ var MessageTargetMode;
35
35
  MessageTargetMode[MessageTargetMode["USERS_CLIENTS"] = 2] = "USERS_CLIENTS";
36
36
  })(MessageTargetMode = exports.MessageTargetMode || (exports.MessageTargetMode = {}));
37
37
  class ConversationService {
38
- constructor(apiClient, cryptographyService, assetService) {
38
+ constructor(apiClient, cryptographyService) {
39
39
  this.apiClient = apiClient;
40
- this.assetService = assetService;
41
40
  this.messageTimer = new conversation_2.MessageTimer();
42
- this.messageBuilder = new MessageBuilder_1.MessageBuilder(this.apiClient, this.assetService);
43
41
  this.messageService = new MessageService_1.MessageService(this.apiClient, cryptographyService);
44
42
  }
45
43
  createEphemeral(originalGenericMessage, expireAfterMillis) {
@@ -2,9 +2,9 @@ import type { ILinkPreview } from '@wireapp/protocol-messaging';
2
2
  import type { ImageAssetContent, ImageContent, LegalHoldStatus } from '../content/';
3
3
  export interface LinkPreviewContent extends Omit<ILinkPreview, 'image'> {
4
4
  expectsReadConfirmation?: boolean;
5
- image?: ImageContent;
6
5
  legalHoldStatus?: LegalHoldStatus;
6
+ image: ImageContent;
7
7
  }
8
- export interface LinkPreviewUploadedContent extends LinkPreviewContent {
8
+ export interface LinkPreviewUploadedContent extends Omit<LinkPreviewContent, 'image'> {
9
9
  imageUploaded?: ImageAssetContent;
10
10
  }
@@ -1,26 +1,24 @@
1
- import type { APIClient } from '@wireapp/api-client';
2
- import type { CipherOptions } from '@wireapp/api-client/src/asset';
3
1
  import { Confirmation } from '@wireapp/protocol-messaging';
4
2
  import { AbortReason } from '..';
5
- import type { AssetService } from '../AssetService';
6
- import type { ButtonActionConfirmationContent, ButtonActionContent, CallingContent, FileContent, FileMetaDataContent, ImageContent, KnockContent, LegalHoldStatus, LinkPreviewContent, LinkPreviewUploadedContent, LocationContent, ReactionContent } from '../content';
3
+ import { EncryptedAssetUploaded } from '../../cryptography';
4
+ import type { ButtonActionConfirmationContent, ButtonActionContent, CallingContent, FileContent, FileMetaDataContent, ImageContent, KnockContent, LegalHoldStatus, LocationContent, ReactionContent } from '../content';
7
5
  import { CompositeContentBuilder } from './CompositeContentBuilder';
8
6
  import type { ButtonActionConfirmationMessage, ButtonActionMessage, CallMessage, ConfirmationMessage, FileAssetAbortMessage, FileAssetMessage, FileAssetMetaDataMessage, ImageAssetMessageOutgoing, LocationMessage, PingMessage, ReactionMessage, ResetSessionMessage } from './OtrMessage';
9
7
  import { TextContentBuilder } from './TextContentBuilder';
10
8
  interface BaseOptions {
11
9
  conversationId: string;
10
+ from: string;
12
11
  messageId?: string;
13
12
  }
14
13
  interface CreateImageOptions extends BaseOptions {
15
- cipherOptions?: CipherOptions;
16
14
  expectsReadConfirmation?: boolean;
15
+ asset: EncryptedAssetUploaded;
17
16
  image: ImageContent;
18
17
  legalHoldStatus?: LegalHoldStatus;
19
18
  }
20
- interface CreateFileOptions {
21
- cipherOptions?: CipherOptions;
22
- conversationId: string;
19
+ interface CreateFileOptions extends BaseOptions {
23
20
  expectsReadConfirmation?: boolean;
21
+ asset: EncryptedAssetUploaded;
24
22
  file: FileContent;
25
23
  legalHoldStatus?: LegalHoldStatus;
26
24
  originalMessageId: string;
@@ -37,6 +35,7 @@ interface CreateFileMetadataOptions extends BaseOptions {
37
35
  interface CreateFileAbortOptions {
38
36
  conversationId: string;
39
37
  expectsReadConfirmation?: boolean;
38
+ from: string;
40
39
  legalHoldStatus?: LegalHoldStatus;
41
40
  originalMessageId: string;
42
41
  reason: AbortReason;
@@ -68,26 +67,21 @@ interface CreateActionMessageOptions extends BaseOptions {
68
67
  content: ButtonActionContent;
69
68
  }
70
69
  export declare class MessageBuilder {
71
- private readonly apiClient;
72
- private readonly assetService;
73
- constructor(apiClient: APIClient, assetService: AssetService);
74
- createEditedText({ conversationId, messageId, newMessageText, originalMessageId, }: CreateEditedTextOptions): TextContentBuilder;
75
- createFileData({ conversationId, cipherOptions, expectsReadConfirmation, file, legalHoldStatus, originalMessageId, }: CreateFileOptions): Promise<FileAssetMessage>;
76
- createFileMetadata({ conversationId, expectsReadConfirmation, legalHoldStatus, messageId, metaData, }: CreateFileMetadataOptions): FileAssetMetaDataMessage;
77
- createFileAbort({ conversationId, expectsReadConfirmation, legalHoldStatus, originalMessageId, reason, }: CreateFileAbortOptions): Promise<FileAssetAbortMessage>;
78
- createImage({ conversationId, cipherOptions, expectsReadConfirmation, image, legalHoldStatus, messageId, }: CreateImageOptions): Promise<ImageAssetMessageOutgoing>;
79
- createLocation({ conversationId, location, messageId, }: CreateLocationOptions): LocationMessage;
80
- createCall({ content, conversationId, messageId }: CreateCallOptions): CallMessage;
81
- createReaction({ conversationId, messageId, reaction, }: CreateReactionOptions): ReactionMessage;
82
- createText({ conversationId, messageId, text, }: CreateTextOptions): TextContentBuilder;
83
- createConfirmation({ conversationId, firstMessageId, messageId, moreMessageIds, type, }: CreateConfirmationOptions): ConfirmationMessage;
84
- createButtonActionMessage({ content, conversationId, messageId, }: CreateActionMessageOptions): ButtonActionMessage;
85
- createButtonActionConfirmationMessage({ content, conversationId, messageId, }: CreateButtonActionConfirmationOptions): ButtonActionConfirmationMessage;
86
- createComposite({ conversationId, messageId }: BaseOptions): CompositeContentBuilder;
87
- createPing({ conversationId, messageId, ping, }: CreatePingOptions): PingMessage;
88
- createSessionReset({ conversationId, messageId }: BaseOptions): ResetSessionMessage;
89
- createLinkPreview(linkPreview: LinkPreviewContent): Promise<LinkPreviewUploadedContent>;
70
+ static createEditedText(payload: CreateEditedTextOptions): TextContentBuilder;
71
+ static createFileData(payload: CreateFileOptions): FileAssetMessage;
72
+ static createFileMetadata(payload: CreateFileMetadataOptions): FileAssetMetaDataMessage;
73
+ static createFileAbort(payload: CreateFileAbortOptions): FileAssetAbortMessage;
74
+ static createImage(payload: CreateImageOptions): ImageAssetMessageOutgoing;
75
+ static createLocation(payload: CreateLocationOptions): LocationMessage;
76
+ static createCall(payload: CreateCallOptions): CallMessage;
77
+ static createReaction(payload: CreateReactionOptions): ReactionMessage;
78
+ static createText(payload: CreateTextOptions): TextContentBuilder;
79
+ static createConfirmation(payload: CreateConfirmationOptions): ConfirmationMessage;
80
+ static createButtonActionMessage(payload: CreateActionMessageOptions): ButtonActionMessage;
81
+ static createButtonActionConfirmationMessage(payload: CreateButtonActionConfirmationOptions): ButtonActionConfirmationMessage;
82
+ static createComposite(payload: BaseOptions): CompositeContentBuilder;
83
+ static createPing(payload: CreatePingOptions): PingMessage;
84
+ static createSessionReset(payload: BaseOptions): ResetSessionMessage;
90
85
  static createId(): string;
91
- private getSelfUserId;
92
86
  }
93
87
  export {};
@@ -27,249 +27,93 @@ const uuidjs_1 = __importDefault(require("uuidjs"));
27
27
  const __1 = require("..");
28
28
  const CompositeContentBuilder_1 = require("./CompositeContentBuilder");
29
29
  const TextContentBuilder_1 = require("./TextContentBuilder");
30
+ function createCommonProperties(options) {
31
+ return {
32
+ id: options.messageId || MessageBuilder.createId(),
33
+ conversation: options.conversationId,
34
+ from: options.from,
35
+ source: __1.PayloadBundleSource.LOCAL,
36
+ state: __1.PayloadBundleState.OUTGOING_UNSENT,
37
+ timestamp: Date.now(),
38
+ };
39
+ }
30
40
  class MessageBuilder {
31
- constructor(apiClient, assetService) {
32
- this.apiClient = apiClient;
33
- this.assetService = assetService;
34
- }
35
- createEditedText({ conversationId, messageId = MessageBuilder.createId(), newMessageText, originalMessageId, }) {
36
- const content = {
37
- originalMessageId,
38
- text: newMessageText,
39
- };
40
- const payloadBundle = {
41
- content,
42
- conversation: conversationId,
43
- from: this.getSelfUserId(),
44
- id: messageId,
45
- source: __1.PayloadBundleSource.LOCAL,
46
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
47
- timestamp: Date.now(),
48
- type: __1.PayloadBundleType.MESSAGE_EDIT,
49
- };
50
- return new TextContentBuilder_1.TextContentBuilder(payloadBundle);
51
- }
52
- async createFileData({ conversationId, cipherOptions, expectsReadConfirmation, file, legalHoldStatus, originalMessageId, }) {
53
- const imageAsset = await this.assetService.uploadFileAsset(file, Object.assign({}, cipherOptions));
54
- const content = {
55
- asset: imageAsset,
56
- expectsReadConfirmation,
57
- file,
58
- legalHoldStatus,
59
- };
60
- return {
61
- content,
62
- conversation: conversationId,
63
- from: this.getSelfUserId(),
64
- id: originalMessageId,
65
- source: __1.PayloadBundleSource.LOCAL,
66
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
67
- timestamp: Date.now(),
68
- type: __1.PayloadBundleType.ASSET,
69
- };
70
- }
71
- createFileMetadata({ conversationId, expectsReadConfirmation, legalHoldStatus, messageId = MessageBuilder.createId(), metaData, }) {
72
- const content = {
73
- expectsReadConfirmation,
74
- legalHoldStatus,
75
- metaData,
76
- };
77
- return {
78
- content,
79
- conversation: conversationId,
80
- from: this.getSelfUserId(),
81
- id: messageId,
82
- source: __1.PayloadBundleSource.LOCAL,
83
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
84
- timestamp: Date.now(),
85
- type: __1.PayloadBundleType.ASSET_META,
86
- };
87
- }
88
- async createFileAbort({ conversationId, expectsReadConfirmation, legalHoldStatus, originalMessageId, reason, }) {
89
- const content = {
90
- expectsReadConfirmation,
91
- legalHoldStatus,
92
- reason,
93
- };
94
- return {
95
- content,
96
- conversation: conversationId,
97
- from: this.getSelfUserId(),
98
- id: originalMessageId,
99
- source: __1.PayloadBundleSource.LOCAL,
100
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
101
- timestamp: Date.now(),
102
- type: __1.PayloadBundleType.ASSET_ABORT,
103
- };
104
- }
105
- async createImage({ conversationId, cipherOptions, expectsReadConfirmation, image, legalHoldStatus, messageId = MessageBuilder.createId(), }) {
106
- const imageAsset = await this.assetService.uploadImageAsset(image, Object.assign({}, cipherOptions));
107
- const content = {
108
- asset: imageAsset,
109
- expectsReadConfirmation,
110
- image,
111
- legalHoldStatus,
112
- };
113
- return {
114
- content,
115
- conversation: conversationId,
116
- from: this.getSelfUserId(),
117
- id: messageId,
118
- source: __1.PayloadBundleSource.LOCAL,
119
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
120
- timestamp: Date.now(),
121
- type: __1.PayloadBundleType.ASSET_IMAGE,
122
- };
123
- }
124
- createLocation({ conversationId, location, messageId = MessageBuilder.createId(), }) {
125
- return {
126
- content: location,
127
- conversation: conversationId,
128
- from: this.getSelfUserId(),
129
- id: messageId,
130
- source: __1.PayloadBundleSource.LOCAL,
131
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
132
- timestamp: Date.now(),
133
- type: __1.PayloadBundleType.LOCATION,
134
- };
135
- }
136
- createCall({ content, conversationId, messageId = MessageBuilder.createId() }) {
137
- return {
138
- content,
139
- conversation: conversationId,
140
- from: this.getSelfUserId(),
141
- id: messageId,
142
- source: __1.PayloadBundleSource.LOCAL,
143
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
144
- timestamp: Date.now(),
145
- type: __1.PayloadBundleType.CALL,
146
- };
147
- }
148
- createReaction({ conversationId, messageId = MessageBuilder.createId(), reaction, }) {
149
- return {
150
- content: reaction,
151
- conversation: conversationId,
152
- from: this.getSelfUserId(),
153
- id: messageId,
154
- source: __1.PayloadBundleSource.LOCAL,
155
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
156
- timestamp: Date.now(),
157
- type: __1.PayloadBundleType.REACTION,
158
- };
159
- }
160
- createText({ conversationId, messageId = MessageBuilder.createId(), text, }) {
161
- const content = { text };
162
- const payloadBundle = {
163
- content,
164
- conversation: conversationId,
165
- from: this.getSelfUserId(),
166
- id: messageId,
167
- source: __1.PayloadBundleSource.LOCAL,
168
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
169
- timestamp: Date.now(),
170
- type: __1.PayloadBundleType.TEXT,
171
- };
172
- return new TextContentBuilder_1.TextContentBuilder(payloadBundle);
173
- }
174
- createConfirmation({ conversationId, firstMessageId, messageId = MessageBuilder.createId(), moreMessageIds, type, }) {
175
- const content = { firstMessageId, moreMessageIds, type };
176
- return {
177
- content,
178
- conversation: conversationId,
179
- from: this.getSelfUserId(),
180
- id: messageId,
181
- source: __1.PayloadBundleSource.LOCAL,
182
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
183
- timestamp: Date.now(),
184
- type: __1.PayloadBundleType.CONFIRMATION,
185
- };
186
- }
187
- createButtonActionMessage({ content, conversationId, messageId = MessageBuilder.createId(), }) {
188
- return {
189
- content,
190
- conversation: conversationId,
191
- from: this.getSelfUserId(),
192
- id: messageId,
193
- source: __1.PayloadBundleSource.LOCAL,
194
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
195
- timestamp: Date.now(),
196
- type: __1.PayloadBundleType.BUTTON_ACTION,
197
- };
198
- }
199
- createButtonActionConfirmationMessage({ content, conversationId, messageId = MessageBuilder.createId(), }) {
200
- return {
201
- content,
202
- conversation: conversationId,
203
- from: this.getSelfUserId(),
204
- id: messageId,
205
- source: __1.PayloadBundleSource.LOCAL,
206
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
207
- timestamp: Date.now(),
208
- type: __1.PayloadBundleType.BUTTON_ACTION_CONFIRMATION,
209
- };
210
- }
211
- createComposite({ conversationId, messageId = MessageBuilder.createId() }) {
212
- const content = {};
213
- const payloadBundle = {
214
- content,
215
- conversation: conversationId,
216
- from: this.getSelfUserId(),
217
- id: messageId,
218
- source: __1.PayloadBundleSource.LOCAL,
219
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
220
- timestamp: Date.now(),
221
- type: __1.PayloadBundleType.COMPOSITE,
222
- };
223
- return new CompositeContentBuilder_1.CompositeContentBuilder(payloadBundle);
224
- }
225
- createPing({ conversationId, messageId = MessageBuilder.createId(), ping = {
226
- hotKnock: false,
227
- }, }) {
228
- return {
229
- content: ping,
230
- conversation: conversationId,
231
- from: this.getSelfUserId(),
232
- id: messageId,
233
- source: __1.PayloadBundleSource.LOCAL,
234
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
235
- timestamp: Date.now(),
236
- type: __1.PayloadBundleType.PING,
237
- };
238
- }
239
- createSessionReset({ conversationId, messageId = MessageBuilder.createId() }) {
240
- const content = {
241
- clientAction: protocol_messaging_1.ClientAction.RESET_SESSION,
242
- };
243
- return {
244
- content,
245
- conversation: conversationId,
246
- from: this.getSelfUserId(),
247
- id: messageId,
248
- source: __1.PayloadBundleSource.LOCAL,
249
- state: __1.PayloadBundleState.OUTGOING_UNSENT,
250
- timestamp: Date.now(),
251
- type: __1.PayloadBundleType.CLIENT_ACTION,
252
- };
253
- }
254
- async createLinkPreview(linkPreview) {
255
- const linkPreviewUploaded = Object.assign({}, linkPreview);
256
- const linkPreviewImage = linkPreview.image;
257
- if (linkPreviewImage) {
258
- const imageAsset = await this.assetService.uploadImageAsset(linkPreviewImage);
259
- delete linkPreviewUploaded.image;
260
- linkPreviewUploaded.imageUploaded = {
261
- asset: imageAsset,
262
- image: linkPreviewImage,
263
- };
264
- }
265
- return linkPreviewUploaded;
41
+ static createEditedText(payload) {
42
+ return new TextContentBuilder_1.TextContentBuilder(Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {
43
+ originalMessageId: payload.originalMessageId,
44
+ text: payload.newMessageText,
45
+ }, type: __1.PayloadBundleType.MESSAGE_EDIT }));
46
+ }
47
+ static createFileData(payload) {
48
+ const { asset, expectsReadConfirmation, file, legalHoldStatus, originalMessageId } = payload;
49
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {
50
+ asset,
51
+ expectsReadConfirmation,
52
+ file,
53
+ legalHoldStatus,
54
+ }, id: originalMessageId, type: __1.PayloadBundleType.ASSET });
55
+ }
56
+ static createFileMetadata(payload) {
57
+ const { expectsReadConfirmation, legalHoldStatus, metaData } = payload;
58
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {
59
+ expectsReadConfirmation,
60
+ legalHoldStatus,
61
+ metaData,
62
+ }, type: __1.PayloadBundleType.ASSET_META });
63
+ }
64
+ static createFileAbort(payload) {
65
+ const { expectsReadConfirmation, legalHoldStatus, reason } = payload;
66
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {
67
+ expectsReadConfirmation,
68
+ legalHoldStatus,
69
+ reason,
70
+ }, id: payload.originalMessageId, type: __1.PayloadBundleType.ASSET_ABORT });
71
+ }
72
+ static createImage(payload) {
73
+ const { expectsReadConfirmation, image, asset, legalHoldStatus } = payload;
74
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {
75
+ expectsReadConfirmation,
76
+ image,
77
+ asset,
78
+ legalHoldStatus,
79
+ }, type: __1.PayloadBundleType.ASSET_IMAGE });
80
+ }
81
+ static createLocation(payload) {
82
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: payload.location, type: __1.PayloadBundleType.LOCATION });
83
+ }
84
+ static createCall(payload) {
85
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: payload.content, type: __1.PayloadBundleType.CALL });
86
+ }
87
+ static createReaction(payload) {
88
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: payload.reaction, type: __1.PayloadBundleType.REACTION });
89
+ }
90
+ static createText(payload) {
91
+ return new TextContentBuilder_1.TextContentBuilder(Object.assign(Object.assign({}, createCommonProperties(payload)), { content: { text: payload.text }, type: __1.PayloadBundleType.TEXT }));
92
+ }
93
+ static createConfirmation(payload) {
94
+ const { firstMessageId, moreMessageIds, type } = payload;
95
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: { firstMessageId, moreMessageIds, type }, type: __1.PayloadBundleType.CONFIRMATION });
96
+ }
97
+ static createButtonActionMessage(payload) {
98
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: payload.content, type: __1.PayloadBundleType.BUTTON_ACTION });
99
+ }
100
+ static createButtonActionConfirmationMessage(payload) {
101
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: payload.content, type: __1.PayloadBundleType.BUTTON_ACTION_CONFIRMATION });
102
+ }
103
+ static createComposite(payload) {
104
+ return new CompositeContentBuilder_1.CompositeContentBuilder(Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {}, type: __1.PayloadBundleType.COMPOSITE }));
105
+ }
106
+ static createPing(payload) {
107
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: payload.ping || { hotKnock: false }, type: __1.PayloadBundleType.PING });
108
+ }
109
+ static createSessionReset(payload) {
110
+ return Object.assign(Object.assign({}, createCommonProperties(payload)), { content: {
111
+ clientAction: protocol_messaging_1.ClientAction.RESET_SESSION,
112
+ }, type: __1.PayloadBundleType.CLIENT_ACTION });
266
113
  }
267
114
  static createId() {
268
115
  return uuidjs_1.default.genV4().toString();
269
116
  }
270
- getSelfUserId() {
271
- return this.apiClient.context.userId;
272
- }
273
117
  }
274
118
  exports.MessageBuilder = MessageBuilder;
275
119
  //# sourceMappingURL=MessageBuilder.js.map
@@ -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;
@@ -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}"`);
@@ -4,8 +4,10 @@ import * as conversation from './conversation/';
4
4
  import { CoreError } from './CoreError';
5
5
  import * as cryptography from './cryptography/';
6
6
  import * as util from './util';
7
+ import { MessageBuilder } from './conversation/message/MessageBuilder';
7
8
  declare const _default: {
8
9
  Account: typeof Account;
10
+ MessageBuilder: typeof MessageBuilder;
9
11
  CoreError: typeof CoreError;
10
12
  auth: typeof auth;
11
13
  conversation: typeof conversation;
package/src/main/index.js CHANGED
@@ -42,8 +42,10 @@ const conversation = __importStar(require("./conversation/"));
42
42
  const CoreError_1 = require("./CoreError");
43
43
  const cryptography = __importStar(require("./cryptography/"));
44
44
  const util = __importStar(require("./util"));
45
+ const MessageBuilder_1 = require("./conversation/message/MessageBuilder");
45
46
  module.exports = {
46
47
  Account: Account_1.Account,
48
+ MessageBuilder: MessageBuilder_1.MessageBuilder,
47
49
  CoreError: CoreError_1.CoreError,
48
50
  auth,
49
51
  conversation,
@@ -0,0 +1,7 @@
1
+ import { AssetService } from '../conversation';
2
+ import { LinkPreviewContent, LinkPreviewUploadedContent } from '../conversation/content';
3
+ export declare class LinkPreviewService {
4
+ private readonly assetService;
5
+ constructor(assetService: AssetService);
6
+ uploadLinkPreviewImage(linkPreview: LinkPreviewContent): Promise<LinkPreviewUploadedContent>;
7
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /*
3
+ * Wire
4
+ * Copyright (C) 2018 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
+ var __rest = (this && this.__rest) || function (s, e) {
21
+ var t = {};
22
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
23
+ t[p] = s[p];
24
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
25
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
26
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
27
+ t[p[i]] = s[p[i]];
28
+ }
29
+ return t;
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.LinkPreviewService = void 0;
33
+ class LinkPreviewService {
34
+ constructor(assetService) {
35
+ this.assetService = assetService;
36
+ }
37
+ async uploadLinkPreviewImage(linkPreview) {
38
+ const { image } = linkPreview, preview = __rest(linkPreview, ["image"]);
39
+ if (!image) {
40
+ return preview;
41
+ }
42
+ const uploadedLinkPreview = preview;
43
+ const asset = await (await this.assetService.uploadAsset(linkPreview.image.data)).response;
44
+ uploadedLinkPreview.imageUploaded = {
45
+ asset,
46
+ image,
47
+ };
48
+ return uploadedLinkPreview;
49
+ }
50
+ }
51
+ exports.LinkPreviewService = LinkPreviewService;
52
+ //# sourceMappingURL=LinkPreviewService.js.map
@@ -0,0 +1 @@
1
+ export * from './LinkPreviewService';
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ /*
3
+ * Wire
4
+ * Copyright (C) 2018 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
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
28
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
29
+ };
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ __exportStar(require("./LinkPreviewService"), exports);
32
+ //# sourceMappingURL=index.js.map