diff --git a/app/definitions/IAttachment.ts b/app/definitions/IAttachment.ts index 3f61116b80b..0780ba13841 100644 --- a/app/definitions/IAttachment.ts +++ b/app/definitions/IAttachment.ts @@ -1,5 +1,5 @@ import { IUser } from './IUser'; -import { E2EType, IAttachmentTranslations, IMessageE2EEContent } from './IMessage'; +import { E2EType, IAttachmentTranslations, TEncryptedContent } from './IMessage'; export type TAttachmentEncryption = { iv: string; @@ -72,7 +72,7 @@ export interface IServerAttachment { uploading: boolean; url: string; user: Pick; - content?: IMessageE2EEContent; + content?: TEncryptedContent; } export interface IShareAttachment { diff --git a/app/definitions/IMessage.ts b/app/definitions/IMessage.ts index 6c19bebfcf6..276702434a6 100644 --- a/app/definitions/IMessage.ts +++ b/app/definitions/IMessage.ts @@ -80,11 +80,31 @@ interface IMessageFile { type: string; } -export type IMessageE2EEContent = { +interface IEncryptedContent { + /** + * The encryption algorithm used. + * Currently supported algorithms are: + * - `rc.v1.aes-sha2`: Rocket.Chat E2E Encryption version 1, using AES encryption with SHA-256 hashing. + * - `rc.v2.aes-sha2`: Rocket.Chat E2E Encryption version 2, using AES encryption with SHA-256 hashing and improved key management. + */ + algorithm: string; + ciphertext: string; // base64-encoded encrypted subset JSON of IMessage +} + +interface IEncryptedContentV1 extends IEncryptedContent { + /** + * The encryption algorithm used. + */ algorithm: 'rc.v1.aes-sha2'; - ciphertext: string; // Encrypted subset JSON of IMessage -}; +} + +interface IEncryptedContentV2 extends IEncryptedContent { + algorithm: 'rc.v2.aes-sha2'; + iv: string; // base64-encoded initialization vector + kid: string; // ID of the key used to encrypt the message +} +export type TEncryptedContent = IEncryptedContentV1 | IEncryptedContentV2; export interface IMessageFromServer { _id: string; rid: string; @@ -112,7 +132,7 @@ export interface IMessageFromServer { username: string; }; score?: number; - content?: IMessageE2EEContent; + content?: TEncryptedContent; } export interface ILoadMoreMessage { @@ -148,6 +168,7 @@ export interface IMessage extends IMessageFromServer { tmsg?: string; blocks?: any; e2e?: E2EType; + e2eMentions?: { e2eUserMentions?: string[]; e2eChannelMentions?: string[] }; tshow?: boolean; comment?: string; subscription?: { id: string }; diff --git a/app/definitions/rest/v1/chat.ts b/app/definitions/rest/v1/chat.ts index 968490ac4d9..6bd42c29108 100644 --- a/app/definitions/rest/v1/chat.ts +++ b/app/definitions/rest/v1/chat.ts @@ -1,4 +1,4 @@ -import type { IMessage, IMessageFromServer, IReadReceipts } from '../../IMessage'; +import type { TEncryptedContent, IMessage, IMessageFromServer, IReadReceipts } from '../../IMessage'; import type { IServerRoom } from '../../IRoom'; import { PaginatedResult } from '../helpers/PaginatedResult'; @@ -75,7 +75,13 @@ export type ChatEndpoints = { }; }; 'chat.update': { - POST: (params: { roomId: IServerRoom['_id']; msgId: string; text: string }) => { + POST: (params: { + roomId: IServerRoom['_id']; + msgId: string; + text?: string; + content?: TEncryptedContent; + e2eMentions?: IMessage['e2eMentions']; + }) => { messages: IMessageFromServer; }; }; diff --git a/app/lib/encryption/room.ts b/app/lib/encryption/room.ts index 2226f77f18a..71b0ff543a7 100644 --- a/app/lib/encryption/room.ts +++ b/app/lib/encryption/room.ts @@ -645,6 +645,10 @@ export default class EncryptionRoom { e2e: 'pending' })) }; + + if (content.text) { + message.msg = content.text; + } } const decryptedMessage: IMessage = { diff --git a/app/lib/services/restApi.ts b/app/lib/services/restApi.ts index c8ec7512a12..ce37b2b2a1d 100644 --- a/app/lib/services/restApi.ts +++ b/app/lib/services/restApi.ts @@ -963,10 +963,28 @@ export function e2eResetRoomKey(rid: string, e2eKey: string, e2eKeyId: string): return sdk.post('e2e.resetRoomKey', { rid, e2eKey, e2eKeyId }); } -export const editMessage = async (message: Pick) => { - const { rid, msg } = await Encryption.encryptMessage(message as IMessage); +export const editMessage = async (message: Pick) => { + const result = await Encryption.encryptMessage(message as IMessage); + if (!result) { + throw new Error('Failed to encrypt message'); + } + + if (result.content) { + // RC 0.49.0 + return sdk.post('chat.update', { + roomId: message.rid, + msgId: message.id, + content: result.content, + e2eMentions: result.e2eMentions + }); + } + // RC 0.49.0 - return sdk.post('chat.update', { roomId: rid, msgId: message.id, text: msg }); + return sdk.post('chat.update', { + roomId: message.rid, + msgId: message.id, + text: message.msg || '' + }); }; export const registerPushToken = () =>