The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Rocket.Chat/packages/rocketchat-lib/server/functions/sendMessage.js

168 lines
4.9 KiB

const validateAttachmentsFields = attachmentFields => {
check(attachmentFields, Match.ObjectIncluding({
short: Match.Maybe(Boolean),
title: String,
value: String
}));
};
const validateAttachment = attachment => {
check(attachment, Match.ObjectIncluding({
color: Match.Maybe(String),
text: Match.Maybe(String),
ts: Match.Maybe(String),
thumb_url: Match.Maybe(String),
message_link: Match.Maybe(String),
collapsed: Match.Maybe(Boolean),
author_name: Match.Maybe(String),
author_link: Match.Maybe(String),
author_icon: Match.Maybe(String),
title: Match.Maybe(String),
title_link: Match.Maybe(String),
title_link_download: Match.Maybe(Boolean),
image_url: Match.Maybe(String),
audio_url: Match.Maybe(String),
video_url: Match.Maybe(String),
fields: Match.Maybe(Array)
}));
if (attachment.fields && attachment.fields.length) {
attachment.fields.map(validateAttachmentsFields);
}
};
const validateBodyAttachments = attachments => attachments.map(validateAttachment);
RocketChat.sendMessage = function(user, message, room, upsert = false) {
if (!user || !message || !room._id) {
return false;
}
check(message, Match.ObjectIncluding({
_id: Match.Maybe(String),
msg: Match.Maybe(String),
text: Match.Maybe(String),
alias: Match.Maybe(String),
emoji: Match.Maybe(String),
avatar: Match.Maybe(String),
attachments: Match.Maybe(Array)
}));
if (Array.isArray(message.attachments) && message.attachments.length) {
validateBodyAttachments(message.attachments);
}
if (!message.ts) {
message.ts = new Date();
}
const { _id, username, name } = user;
message.u = {
_id,
username,
name
};
message.rid = room._id;
if (!Match.test(message.msg, String)) {
message.msg = '';
}
if (message.ts == null) {
message.ts = new Date();
}
if (!room.usernames || room.usernames.length === 0) {
const updated_room = RocketChat.models.Rooms.findOneById(room._id);
if (updated_room) {
room = updated_room;
} else {
room.usernames = [];
}
}
if (RocketChat.settings.get('Message_Read_Receipt_Enabled')) {
message.unread = true;
}
// For the Rocket.Chat Apps :)
if (message && Apps && Apps.isLoaded()) {
const prevent = Promise.await(Apps.getBridges().getListenerBridge().messageEvent('IPreMessageSentPrevent', message));
if (prevent) {
throw new Meteor.Error('error-app-prevented-sending', 'A Rocket.Chat App prevented the messaging sending.');
}
let result;
result = Promise.await(Apps.getBridges().getListenerBridge().messageEvent('IPreMessageSentExtend', message));
result = Promise.await(Apps.getBridges().getListenerBridge().messageEvent('IPreMessageSentModify', result));
if (typeof result === 'object') {
message = Object.assign(message, result);
}
}
if (message.parseUrls !== false) {
const urlRegex = /([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\(\)\w]*)?\??([-\+=&!:;%@\/\.\,\w]+)?(?:#([^\s\)]+))?)?/g;
const urls = message.msg.match(urlRegex);
if (urls) {
// ignoredUrls contain blocks of quotes with urls inside
const ignoredUrls = message.msg.match(/(?:(?:\`{1,3})(?:[\n\r]*?.*?)*?)(([A-Za-z]{3,9}):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+=!:~%\/\.@\,\(\)\w]*)?\??([-\+=&!:;%@\/\.\,\w]+)?(?:#([^\s\)]+))?)?)(?:(?:[\n\r]*.*?)*?(?:\`{1,3}))/gm);
if (ignoredUrls) {
ignoredUrls.forEach((url) => {
const shouldBeIgnored = url.match(urlRegex);
if (shouldBeIgnored) {
shouldBeIgnored.forEach((match) => {
const matchIndex = urls.indexOf(match);
urls.splice(matchIndex, 1);
});
}
});
}
if (urls) {
// use the Set to remove duplicity, so it doesn't embed the same link twice
message.urls = [...new Set(urls)].map(function(url) {
return {
url
};
});
}
}
}
message = RocketChat.callbacks.run('beforeSaveMessage', message);
if (message) {
// Avoid saving sandstormSessionId to the database
let sandstormSessionId = null;
if (message.sandstormSessionId) {
sandstormSessionId = message.sandstormSessionId;
delete message.sandstormSessionId;
}
if (message._id && upsert) {
const _id = message._id;
delete message._id;
RocketChat.models.Messages.upsert({
_id,
'u._id': message.u._id
}, message);
message._id = _id;
} else {
message._id = RocketChat.models.Messages.insert(message);
}
if (Apps && Apps.isLoaded()) {
// This returns a promise, but it won't mutate anything about the message
// so, we don't really care if it is successful or fails
Apps.getBridges().getListenerBridge().messageEvent('IPostMessageSent', message);
}
/*
Defer other updates as their return is not interesting to the user
*/
Meteor.defer(() => {
// Execute all callbacks
message.sandstormSessionId = sandstormSessionId;
return RocketChat.callbacks.run('afterSaveMessage', message, room, user._id);
});
return message;
}
};