snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import QueryString from 'node:querystring';
|
||||
import URL from 'node:url';
|
||||
|
||||
import type { MessageAttachment, IMessage, IUser, IOmnichannelRoom, IRoom } from '@rocket.chat/core-typings';
|
||||
import { isOmnichannelRoom, isQuoteAttachment } from '@rocket.chat/core-typings';
|
||||
|
||||
import { createQuoteAttachment } from '../../../../lib/createQuoteAttachment';
|
||||
|
||||
const recursiveRemoveAttachments = (attachments: MessageAttachment, deep = 1, quoteChainLimit: number): MessageAttachment => {
|
||||
if (attachments && isQuoteAttachment(attachments)) {
|
||||
if (deep < quoteChainLimit - 1) {
|
||||
attachments.attachments?.map((msg) => recursiveRemoveAttachments(msg, deep + 1, quoteChainLimit));
|
||||
} else if (attachments.attachments) {
|
||||
attachments.attachments = attachments.attachments.filter((attachment) => !isQuoteAttachment(attachment));
|
||||
if (attachments.attachments.length === 0) {
|
||||
delete attachments.attachments;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attachments;
|
||||
};
|
||||
|
||||
const validateAttachmentDeepness = (message: IMessage, quoteChainLimit: number): IMessage => {
|
||||
if (!message?.attachments) {
|
||||
return message;
|
||||
}
|
||||
|
||||
if ((message.attachments && quoteChainLimit < 2) || isNaN(quoteChainLimit)) {
|
||||
message.attachments = message.attachments.filter((attachment) => !isQuoteAttachment(attachment));
|
||||
if (message.attachments.length === 0) {
|
||||
delete message.attachments;
|
||||
}
|
||||
}
|
||||
|
||||
message.attachments = message.attachments?.map((attachment) => recursiveRemoveAttachments(attachment, 1, quoteChainLimit));
|
||||
|
||||
return message;
|
||||
};
|
||||
|
||||
const removeQuoteAttachments = (message: IMessage) => {
|
||||
if (!message.attachments) {
|
||||
return;
|
||||
}
|
||||
message.attachments = message.attachments.filter((attachment) => !isQuoteAttachment(attachment));
|
||||
};
|
||||
|
||||
type JumpToMessageInit = {
|
||||
getMessages(messageIds: IMessage['_id'][]): Promise<IMessage[]>;
|
||||
getRooms(roomIds: IRoom['_id'][]): Promise<IRoom[] | IOmnichannelRoom[] | null>;
|
||||
canAccessRoom(room: IRoom, user: Pick<IUser, '_id' | 'username' | 'name' | 'language'>): Promise<boolean>;
|
||||
getUserAvatarURL(user?: string): string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform URLs in messages into quote attachments
|
||||
*/
|
||||
export class BeforeSaveJumpToMessage {
|
||||
private getMessages: JumpToMessageInit['getMessages'];
|
||||
|
||||
private getRooms: JumpToMessageInit['getRooms'];
|
||||
|
||||
private canAccessRoom: JumpToMessageInit['canAccessRoom'];
|
||||
|
||||
private getUserAvatarURL: JumpToMessageInit['getUserAvatarURL'];
|
||||
|
||||
constructor(options: JumpToMessageInit) {
|
||||
this.getMessages = options.getMessages;
|
||||
this.getRooms = options.getRooms;
|
||||
this.canAccessRoom = options.canAccessRoom;
|
||||
this.getUserAvatarURL = options.getUserAvatarURL;
|
||||
}
|
||||
|
||||
async createAttachmentForMessageURLs({
|
||||
message,
|
||||
user: currentUser,
|
||||
config,
|
||||
}: {
|
||||
message: IMessage;
|
||||
user: Pick<IUser, '_id' | 'username' | 'name' | 'language'>;
|
||||
config: {
|
||||
chainLimit: number;
|
||||
siteUrl: string;
|
||||
useRealName: boolean;
|
||||
};
|
||||
}): Promise<IMessage> {
|
||||
// Quote attachments are always rebuilt. Do not keep old ones since they may not still be linked to the message
|
||||
removeQuoteAttachments(message);
|
||||
|
||||
// if no message is present, or the message doesn't have any URL, skip
|
||||
if (!message?.urls?.length) {
|
||||
return message;
|
||||
}
|
||||
|
||||
const linkedMessages = message.urls
|
||||
.filter((item) => item.url.includes(config.siteUrl))
|
||||
.map((item) => {
|
||||
const urlObj = URL.parse(item.url);
|
||||
|
||||
// if the URL doesn't have query params (doesn't reference message) skip
|
||||
if (!urlObj.query) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { msg: msgId } = QueryString.parse(urlObj.query);
|
||||
|
||||
if (typeof msgId !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
return { msgId, url: item.url };
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
const msgs = await this.getMessages(linkedMessages.map((linkedMsg) => linkedMsg?.msgId) as string[]);
|
||||
|
||||
const validMessages = msgs.filter((msg) => validateAttachmentDeepness(msg, config.chainLimit));
|
||||
|
||||
const rooms = await this.getRooms(validMessages.map((msg) => msg.rid));
|
||||
|
||||
const roomsWithPermission =
|
||||
rooms &&
|
||||
(await Promise.all(
|
||||
rooms.map(async (room) => {
|
||||
if (!!message.token && isOmnichannelRoom(room) && !!room.v?.token && message.token === room.v.token) {
|
||||
return room;
|
||||
}
|
||||
|
||||
if (currentUser && (await this.canAccessRoom(room, currentUser))) {
|
||||
return room;
|
||||
}
|
||||
}),
|
||||
));
|
||||
|
||||
const validRooms = roomsWithPermission?.filter((room) => !!room);
|
||||
|
||||
const { useRealName } = config;
|
||||
|
||||
const quotes = [];
|
||||
|
||||
for (const item of message.urls) {
|
||||
if (!item.url.includes(config.siteUrl)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const linkedMessage = linkedMessages.find((msg) => msg?.url === item.url);
|
||||
if (!linkedMessage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const messageFromUrl = validMessages.find((msg) => msg._id === linkedMessage.msgId);
|
||||
if (!messageFromUrl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!validRooms?.find((room) => room?._id === messageFromUrl.rid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item.ignoreParse = true;
|
||||
|
||||
quotes.push(createQuoteAttachment(messageFromUrl, item.url, useRealName, this.getUserAvatarURL(messageFromUrl.u.username)));
|
||||
}
|
||||
|
||||
if (quotes.length > 0) {
|
||||
const currentAttachments = message.attachments || [];
|
||||
message.attachments = [...currentAttachments, ...quotes];
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user