diff --git a/app/definitions/IMessage.ts b/app/definitions/IMessage.ts index c26a69d06..092183cd8 100644 --- a/app/definitions/IMessage.ts +++ b/app/definitions/IMessage.ts @@ -149,7 +149,7 @@ export interface IMessage extends IMessageFromServer { export type TMessageModel = IMessage & Model & { - asPlain?: () => IMessage; + asPlain: () => IMessage; }; export type TAnyMessageModel = TMessageModel | TThreadModel | TThreadMessageModel; diff --git a/app/definitions/IThread.ts b/app/definitions/IThread.ts index 4e298bdaa..e8231b864 100644 --- a/app/definitions/IThread.ts +++ b/app/definitions/IThread.ts @@ -38,4 +38,7 @@ export interface IThread extends IMessage { draftMessage?: string; } -export type TThreadModel = IThread & Model; +export type TThreadModel = IThread & + Model & { + asPlain: () => IMessage; + }; diff --git a/app/definitions/IThreadMessage.ts b/app/definitions/IThreadMessage.ts index 7383d69eb..cf2f846ca 100644 --- a/app/definitions/IThreadMessage.ts +++ b/app/definitions/IThreadMessage.ts @@ -6,4 +6,7 @@ export interface IThreadMessage extends IMessage { tmsg?: string; } -export type TThreadMessageModel = IThreadMessage & Model; +export type TThreadMessageModel = IThreadMessage & + Model & { + asPlain: () => IMessage; + }; diff --git a/app/lib/database/model/Thread.js b/app/lib/database/model/Thread.js index ff534c85d..947493b6b 100644 --- a/app/lib/database/model/Thread.js +++ b/app/lib/database/model/Thread.js @@ -77,4 +77,42 @@ export default class Thread extends Model { @field('e2e') e2e; @field('draft_message') draftMessage; + + asPlain() { + return { + id: this.id, + msg: this.msg, + t: this.t, + ts: this.ts, + u: this.u, + alias: this.alias, + parseUrls: this.parseUrls, + groupable: this.groupable, + avatar: this.avatar, + emoji: this.emoji, + attachments: this.attachments, + urls: this.urls, + _updatedAt: this._updatedAt, + status: this.status, + pinned: this.pinned, + starred: this.starred, + editedBy: this.editedBy, + reactions: this.reactions, + role: this.role, + drid: this.drid, + dcount: this.dcount, + dlm: this.dlm, + tmid: this.tmid, + tcount: this.tcount, + tlm: this.tlm, + replies: this.replies, + mentions: this.mentions, + channels: this.channels, + unread: this.unread, + autoTranslate: this.autoTranslate, + translations: this.translations, + e2e: this.e2e, + draftMessage: this.draftMessage + }; + } } diff --git a/app/lib/database/model/ThreadMessage.js b/app/lib/database/model/ThreadMessage.js index bc5502fd2..0d2ad16bf 100644 --- a/app/lib/database/model/ThreadMessage.js +++ b/app/lib/database/model/ThreadMessage.js @@ -77,4 +77,42 @@ export default class ThreadMessage extends Model { @field('draft_message') draftMessage; @field('e2e') e2e; + + asPlain() { + return { + id: this.id, + msg: this.msg, + t: this.t, + ts: this.ts, + u: this.u, + rid: this.rid, + alias: this.alias, + parseUrls: this.parseUrls, + groupable: this.groupable, + avatar: this.avatar, + emoji: this.emoji, + attachments: this.attachments, + urls: this.urls, + _updatedAt: this._updatedAt, + status: this.status, + pinned: this.pinned, + starred: this.starred, + editedBy: this.editedBy, + reactions: this.reactions, + role: this.role, + drid: this.drid, + dcount: this.dcount, + dlm: this.dlm, + tcount: this.tcount, + tlm: this.tlm, + replies: this.replies, + mentions: this.mentions, + channels: this.channels, + unread: this.unread, + autoTranslate: this.autoTranslate, + translations: this.translations, + draftMessage: this.draftMessage, + e2e: this.e2e + }; + } } diff --git a/app/lib/database/services/Message.ts b/app/lib/database/services/Message.ts index 172202fb7..69b666f69 100644 --- a/app/lib/database/services/Message.ts +++ b/app/lib/database/services/Message.ts @@ -1,5 +1,3 @@ -import { Clause } from '@nozbe/watermelondb/QueryDescription'; - import database from '..'; import { TAppDatabase } from '../interfaces'; import { MESSAGES_TABLE } from '../model/Message'; @@ -15,18 +13,7 @@ export const getMessageById = async (messageId: string | null) => { try { const result = await messageCollection.find(messageId); return result; - } catch (error) { - return null; - } -}; - -export const getMessageByQuery = async (...query: Clause[]) => { - const db = database.active; - const messageCollection = getCollection(db); - try { - const result = await messageCollection.query(...query).fetch(); - return result; - } catch (error) { + } catch { return null; } }; diff --git a/app/lib/encryption/helpers/getMessageUrlRegex.ts b/app/lib/encryption/helpers/getMessageUrlRegex.ts index 78e3993ef..46d4dc0e2 100644 --- a/app/lib/encryption/helpers/getMessageUrlRegex.ts +++ b/app/lib/encryption/helpers/getMessageUrlRegex.ts @@ -1,2 +1,3 @@ +// https://github.com/RocketChat/Rocket.Chat/blob/0226236b871d12c62338111c70b65d5d406447a3/apps/meteor/lib/getMessageUrlRegex.ts#L1-L2 export const getMessageUrlRegex = (): RegExp => /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\w]*)?\??([-\+=&!:;%@\/\.\,\w]+)?(?:#([^\s\)]+))?)?/g; diff --git a/app/lib/encryption/helpers/mapMessageFromApi.ts b/app/lib/encryption/helpers/mapMessageFromApi.ts index 1f662ff19..f7dc030d6 100644 --- a/app/lib/encryption/helpers/mapMessageFromApi.ts +++ b/app/lib/encryption/helpers/mapMessageFromApi.ts @@ -1,13 +1,10 @@ import { IMessage } from '../../../definitions'; -export const mapMessageFromApi = ({ attachments, tlm, ts, _updatedAt, ...message }: IMessage) => ({ +export const mapMessageFromAPI = ({ attachments, tlm, ts, _updatedAt, ...message }: IMessage) => ({ ...message, ts: new Date(ts), ...(tlm && { tlm: new Date(tlm) }), _updatedAt: new Date(_updatedAt), - // FIXME: webRtcCallEndTs doesn't exist in our interface IMessage, but exists on @rocket.chat/core-typings - // @ts-ignore - ...(message?.webRtcCallEndTs && { webRtcCallEndTs: new Date(message.webRtcCallEndTs) }), ...(attachments && { attachments: attachments.map(({ ts, ...attachment }) => ({ ...(ts && { ts: new Date(ts) }), diff --git a/app/lib/encryption/helpers/mapMessageFromDB.ts b/app/lib/encryption/helpers/mapMessageFromDB.ts index 827a2c990..dab98ad5e 100644 --- a/app/lib/encryption/helpers/mapMessageFromDB.ts +++ b/app/lib/encryption/helpers/mapMessageFromDB.ts @@ -1,15 +1,12 @@ import { TMessageModel } from '../../../definitions'; export const mapMessageFromDB = (messageModel: TMessageModel) => { - const parsedMessage = messageModel.asPlain!(); + const parsedMessage = messageModel.asPlain(); return { ...parsedMessage, ts: new Date(parsedMessage.ts), ...(parsedMessage.tlm && { tlm: new Date(parsedMessage.tlm) }), _updatedAt: new Date(parsedMessage._updatedAt), - // FIXME: webRtcCallEndTs doesn't exist in our interface IMessage, but exists on @rocket.chat/core-typings - // @ts-ignore - ...(parsedMessage?.webRtcCallEndTs && { webRtcCallEndTs: new Date(parsedMessage.webRtcCallEndTs) }), ...(parsedMessage.attachments && { attachments: parsedMessage.attachments.map(({ ts, ...attachment }) => ({ ...(ts && { ts: new Date(ts) }), diff --git a/app/lib/encryption/room.ts b/app/lib/encryption/room.ts index 343e9eff6..881452751 100644 --- a/app/lib/encryption/room.ts +++ b/app/lib/encryption/room.ts @@ -3,7 +3,6 @@ import { Base64 } from 'js-base64'; import SimpleCrypto from 'react-native-simple-crypto'; import ByteBuffer from 'bytebuffer'; import parse from 'url-parse'; -import { Q } from '@nozbe/watermelondb'; import getSingleMessage from '../methods/getSingleMessage'; import { IMessage, IUser } from '../../definitions'; @@ -25,10 +24,10 @@ import { Encryption } from './index'; import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../constants'; import { Services } from '../services'; import { getMessageUrlRegex } from './helpers/getMessageUrlRegex'; -import { mapMessageFromApi } from './helpers/mapMessageFromApi'; +import { mapMessageFromAPI } from './helpers/mapMessageFromAPI'; import { mapMessageFromDB } from './helpers/mapMessageFromDB'; import { createQuoteAttachment } from './helpers/createQuoteAttachment'; -import { getMessageByQuery } from '../database/services/Message'; +import { getMessageById } from '../database/services/Message'; export default class EncryptionRoom { ready: boolean; @@ -283,7 +282,7 @@ export default class EncryptionRoom { e2e: 'done' }; - const decryptedMessageWithQuote = await this.parseQuoteAttachment(decryptedMessage); + const decryptedMessageWithQuote = await this.decryptQuoteAttachment(decryptedMessage); return decryptedMessageWithQuote; } } catch { @@ -293,29 +292,31 @@ export default class EncryptionRoom { return message; }; - async parseQuoteAttachment(message: IMessage) { - const urls = message.msg?.match(getMessageUrlRegex()) || []; + async decryptQuoteAttachment(message: IMessage) { + const urls = message?.msg?.match(getMessageUrlRegex()) || []; await Promise.all( urls.map(async (url: string) => { const parsedUrl = parse(url, true); const messageId = parsedUrl.query?.msg; - if (!messageId || Array.isArray(messageId)) { + if (!messageId) { return; } - const messageFromDB = await getMessageByQuery(Q.and(Q.where('id', messageId), Q.where('e2e', E2E_STATUS.DONE))); - if (messageFromDB?.length) { - const decryptedQuoteMessage = mapMessageFromDB(messageFromDB[0]); + // From local db + const messageFromDB = await getMessageById(messageId); + if (messageFromDB && messageFromDB.e2e === 'done') { + const decryptedQuoteMessage = mapMessageFromDB(messageFromDB); message.attachments = message.attachments || []; const quoteAttachment = createQuoteAttachment(decryptedQuoteMessage, url); return message.attachments.push(quoteAttachment); } + // From API const quotedMessageObject = await getSingleMessage(messageId); if (!quotedMessageObject) { return; } - const decryptedQuoteMessage = await this.decrypt(mapMessageFromApi(quotedMessageObject)); + const decryptedQuoteMessage = await this.decrypt(mapMessageFromAPI(quotedMessageObject)); message.attachments = message.attachments || []; const quoteAttachment = createQuoteAttachment(decryptedQuoteMessage, url); return message.attachments.push(quoteAttachment);