mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-14 13:17:24 +01:00
Fix username links resulting in truncated chat messages (#11945)
* introduce MAX_MESSAGE_LENGTH constant * add test * fix path * fix and tests * fix typo in tests
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
|
||||
TAVERN_ID,
|
||||
} from '../../../../../website/server/models/group';
|
||||
import { CHAT_FLAG_FROM_SHADOW_MUTE } from '../../../../../website/common/script/constants';
|
||||
import { CHAT_FLAG_FROM_SHADOW_MUTE, MAX_MESSAGE_LENGTH } from '../../../../../website/common/script/constants';
|
||||
import { getMatchesByWordArray } from '../../../../../website/server/libs/stringUtils';
|
||||
import bannedWords from '../../../../../website/server/libs/bannedWords';
|
||||
import guildsAllowingBannedWords from '../../../../../website/server/libs/guildsAllowingBannedWords';
|
||||
@@ -494,6 +494,7 @@ describe('POST /chat', () => {
|
||||
123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789.
|
||||
THIS PART WON'T BE IN THE MESSAGE (over 3000)
|
||||
`;
|
||||
expect(veryLongMessage.length > MAX_MESSAGE_LENGTH).to.equal(true);
|
||||
|
||||
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: veryLongMessage });
|
||||
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
|
||||
@@ -501,9 +502,27 @@ describe('POST /chat', () => {
|
||||
expect(newMessage.message.id).to.exist;
|
||||
expect(groupMessages[0].id).to.exist;
|
||||
|
||||
expect(newMessage.message.text.length).to.eql(3000);
|
||||
expect(newMessage.message.text.length).to.eql(MAX_MESSAGE_LENGTH);
|
||||
expect(newMessage.message.text).to.not.contain('MESSAGE');
|
||||
expect(groupMessages[0].text.length).to.eql(3000);
|
||||
expect(groupMessages[0].text.length).to.eql(MAX_MESSAGE_LENGTH);
|
||||
});
|
||||
|
||||
it('chat message with mentions - mention link should not count towards 3000 chars limit', async () => {
|
||||
const memberUsername = 'memberUsername';
|
||||
await member.update({ 'auth.local.username': memberUsername });
|
||||
|
||||
const messageWithMentions = `hi @${memberUsername} 123456789
|
||||
123456789 123456789 123456789 123456789 123456789 123456789 89 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12345678 END.`;
|
||||
expect(messageWithMentions.length).to.equal(MAX_MESSAGE_LENGTH);
|
||||
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: messageWithMentions });
|
||||
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
|
||||
|
||||
const mentionLink = `[@${memberUsername}](/profile/${member._id})`;
|
||||
expect(newMessage.message.text).to.include(mentionLink);
|
||||
expect(newMessage.message.text).to.include(' END.');
|
||||
expect(newMessage.message.text.length)
|
||||
.to.eql(messageWithMentions.length - (`@${memberUsername}`).length + mentionLink.length);
|
||||
expect(groupMessages[0].text.length).to.eql(newMessage.message.text.length);
|
||||
});
|
||||
|
||||
it('creates a chat with user styles', async () => {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
v-model="newMessage"
|
||||
:placeholder="placeholder"
|
||||
:class="{'user-entry': newMessage}"
|
||||
maxlength="3000"
|
||||
:maxlength="MAX_MESSAGE_LENGTH"
|
||||
@keydown="updateCarretPosition"
|
||||
@keyup.ctrl.enter="sendMessageShortcut()"
|
||||
@keydown.tab="handleTab($event)"
|
||||
@@ -30,7 +30,7 @@
|
||||
@keydown.esc="handleEscape($event)"
|
||||
@paste="disableMessageSendShortcut()"
|
||||
></textarea>
|
||||
<span>{{ currentLength }} / 3000</span>
|
||||
<span>{{ currentLength }} / {{ MAX_MESSAGE_LENGTH }}</span>
|
||||
<autocomplete
|
||||
ref="autocomplete"
|
||||
:text="newMessage"
|
||||
@@ -91,6 +91,7 @@ import communityGuidelines from './communityGuidelines';
|
||||
import chatMessage from '../chat/chatMessages';
|
||||
import { mapState } from '@/libs/store';
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
import { MAX_MESSAGE_LENGTH } from '@/../../common/script/constants';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
@@ -116,6 +117,7 @@ export default {
|
||||
LEFT: 0,
|
||||
},
|
||||
textbox: this.$refs,
|
||||
MAX_MESSAGE_LENGTH: MAX_MESSAGE_LENGTH.toString(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
v-model="newMessage"
|
||||
class="flex-fill"
|
||||
:placeholder="$t('needsTextPlaceholder')"
|
||||
maxlength="3000"
|
||||
:maxlength="MAX_MESSAGE_LENGTH"
|
||||
:class="{'has-content': newMessage !== ''}"
|
||||
@keyup.ctrl.enter="sendPrivateMessage()"
|
||||
></textarea>
|
||||
@@ -518,6 +518,7 @@ import groupBy from 'lodash/groupBy';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import habiticaMarkdown from 'habitica-markdown';
|
||||
import axios from 'axios';
|
||||
import { MAX_MESSAGE_LENGTH } from '@/../../common/script/constants';
|
||||
import { mapState } from '@/libs/store';
|
||||
import styleHelper from '@/mixins/styleHelper';
|
||||
import toggleSwitch from '@/components/ui/toggleSwitch';
|
||||
@@ -563,6 +564,7 @@ export default {
|
||||
messagesLoading: false,
|
||||
initiatedConversation: null,
|
||||
updateConversationsCounter: 0,
|
||||
MAX_MESSAGE_LENGTH: MAX_MESSAGE_LENGTH.toString(),
|
||||
};
|
||||
},
|
||||
async mounted () {
|
||||
|
||||
@@ -9,6 +9,7 @@ export const LARGE_GROUP_COUNT_MESSAGE_CUTOFF = 5000;
|
||||
export const MAX_SUMMARY_SIZE_FOR_GUILDS = 250;
|
||||
export const MAX_SUMMARY_SIZE_FOR_CHALLENGES = 250;
|
||||
export const MIN_SHORTNAME_SIZE_FOR_CHALLENGES = 3;
|
||||
export const MAX_MESSAGE_LENGTH = 3000;
|
||||
|
||||
export const CHAT_FLAG_LIMIT_FOR_HIDING = 2; // hide posts that have this many flags
|
||||
export const CHAT_FLAG_FROM_MOD = 5; // a flag from a moderator counts as this many flags
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
MINIMUM_PASSWORD_LENGTH,
|
||||
SUPPORTED_SOCIAL_NETWORKS,
|
||||
TAVERN_ID,
|
||||
MAX_MESSAGE_LENGTH,
|
||||
} from './constants';
|
||||
import content from './content/index';
|
||||
import * as count from './count';
|
||||
@@ -108,6 +109,7 @@ api.constants = {
|
||||
CHAT_FLAG_FROM_MOD,
|
||||
CHAT_FLAG_FROM_SHADOW_MUTE,
|
||||
MINIMUM_PASSWORD_LENGTH,
|
||||
MAX_MESSAGE_LENGTH,
|
||||
};
|
||||
// TODO Move these under api.constants
|
||||
api.maxLevel = MAX_LEVEL;
|
||||
|
||||
@@ -2,7 +2,10 @@ import nconf from 'nconf';
|
||||
import { authWithHeaders } from '../../middlewares/auth';
|
||||
import { model as Group } from '../../models/group';
|
||||
import { model as User } from '../../models/user';
|
||||
import { chatModel as Chat } from '../../models/message';
|
||||
import {
|
||||
chatModel as Chat,
|
||||
sanitizeText as sanitizeMessageText,
|
||||
} from '../../models/message';
|
||||
import common from '../../../common';
|
||||
import {
|
||||
BadRequest,
|
||||
@@ -187,7 +190,8 @@ api.postChat = {
|
||||
throw new NotAuthorized(res.t('messageGroupChatSpam'));
|
||||
}
|
||||
|
||||
const [message, mentions, mentionedMembers] = await highlightMentions(req.body.message);
|
||||
const sanitizedMessageText = sanitizeMessageText(req.body.message);
|
||||
const [message, mentions, mentionedMembers] = await highlightMentions(sanitizedMessageText);
|
||||
let client = req.headers['x-client'] || '3rd Party';
|
||||
if (client) {
|
||||
client = client.replace('habitica-', '');
|
||||
|
||||
@@ -21,6 +21,9 @@ import {
|
||||
import { sendNotification as sendPushNotification } from '../../libs/pushNotifications';
|
||||
import common from '../../../common';
|
||||
import { sentMessage } from '../../libs/inbox';
|
||||
import {
|
||||
sanitizeText as sanitizeMessageText,
|
||||
} from '../../models/message';
|
||||
import { highlightMentions } from '../../libs/highlightMentions';
|
||||
|
||||
const { achievements } = common;
|
||||
@@ -677,7 +680,8 @@ api.sendPrivateMessage = {
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
const sender = res.locals.user;
|
||||
const message = (await highlightMentions(req.body.message))[0];
|
||||
const sanitizedMessageText = sanitizeMessageText(req.body.message);
|
||||
const message = (await highlightMentions(sanitizedMessageText))[0];
|
||||
|
||||
const receiver = await User.findById(req.body.toUserId).exec();
|
||||
if (!receiver) throw new NotFound(res.t('userNotFound'));
|
||||
|
||||
@@ -3,6 +3,7 @@ import { v4 as uuid } from 'uuid';
|
||||
import { defaults } from 'lodash';
|
||||
import removeMd from 'remove-markdown';
|
||||
import baseModel from '../libs/baseModel';
|
||||
import shared from '../../common';
|
||||
|
||||
const defaultSchema = () => ({
|
||||
id: String,
|
||||
@@ -113,14 +114,20 @@ export function setUserStyles (newMessage, user) {
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize an input message, separate from messageDefaults because
|
||||
// it must run before mentions are highlighted
|
||||
export function sanitizeText (msg) {
|
||||
// Trim messages longer than the MAX_MESSAGE_LENGTH
|
||||
return msg.substring(0, shared.constants.MAX_MESSAGE_LENGTH);
|
||||
}
|
||||
|
||||
export function messageDefaults (msg, user, client, flagCount = 0, info = {}) {
|
||||
const id = uuid();
|
||||
const trimmedMessage = msg.substring(0, 3000);
|
||||
const message = {
|
||||
id,
|
||||
_id: id,
|
||||
text: trimmedMessage,
|
||||
unformattedText: removeMd(trimmedMessage),
|
||||
text: msg,
|
||||
unformattedText: removeMd(msg),
|
||||
info,
|
||||
timestamp: Number(new Date()),
|
||||
likes: {},
|
||||
|
||||
@@ -110,7 +110,7 @@ schema.methods.getObjectionsToInteraction = function getObjectionsToInteraction
|
||||
|
||||
|
||||
/**
|
||||
* Sends a message to a this. Archives a copy in sender's inbox.
|
||||
* Sends a message to a user. Archives a copy in sender's inbox.
|
||||
*
|
||||
* @param userToReceiveMessage The receiver
|
||||
* @param options
|
||||
|
||||
Reference in New Issue
Block a user