From 77afa9e35f0102854600f88535ad575c33675041 Mon Sep 17 00:00:00 2001 From: HoonBaek Date: Fri, 6 Jan 2023 08:55:39 +0900 Subject: [PATCH 1/3] Create util function to encode string to html --- src/ui/MessageInput/utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui/MessageInput/utils.js b/src/ui/MessageInput/utils.js index 8554b5cc7..7542df104 100644 --- a/src/ui/MessageInput/utils.js +++ b/src/ui/MessageInput/utils.js @@ -20,4 +20,8 @@ export function debounce(func, wait, immediate) { }; } +export const encodeStrToHTML = (str) => ( + str?.replace(/[\u00A0-\u9999<>]/gim, (i) => ''.concat('&#', i.charCodeAt(0), ';')) +); + export default debounce; From 9622c80e17d4ae9281b7e56976030ee76aa7c473 Mon Sep 17 00:00:00 2001 From: HoonBaek Date: Fri, 6 Jan 2023 08:56:11 +0900 Subject: [PATCH 2/3] Apply the encoding function when fill the message input value with text --- src/ui/MessageInput/index.jsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ui/MessageInput/index.jsx b/src/ui/MessageInput/index.jsx index 4bf08b6a6..97cd6a70e 100644 --- a/src/ui/MessageInput/index.jsx +++ b/src/ui/MessageInput/index.jsx @@ -19,6 +19,7 @@ import MentionUserLabel from '../MentionUserLabel'; import Icon, { IconTypes, IconColors } from '../Icon'; import Label, { LabelTypography, LabelColors } from '../Label'; import { LocalizationContext } from '../../lib/LocalizationContext'; +import { encodeStrToHTML } from './utils'; import { arrayEqual, getClassName, @@ -114,6 +115,7 @@ const MessageInput = React.forwardRef((props, ref) => { } ), []); + // #Edit mode // for easilly initialize input value from outside, but // useEffect(_, [channelUrl]) erase it const initialValue = props?.value; @@ -136,7 +138,7 @@ const MessageInput = React.forwardRef((props, ref) => { } }, [channelUrl]); - // #Mention | Fill message input values + // #Mention & #Edit | Fill message input values useEffect(() => { if (isEdit && message?.messageId) { // const textField = document.getElementById(textFieldId); @@ -150,9 +152,7 @@ const MessageInput = React.forwardRef((props, ref) => { textField.innerHTML = message?.mentionedMessageTemplate?.split(' ').map((word) => ( convertWordToStringObj(word, mentionedUsers).map((stringObj) => { const { type, value, userId } = stringObj; - if (type === StringObjType.mention - && mentionedUsers.some((user) => user?.userId === userId) - ) { + if (type === StringObjType.mention && mentionedUsers.some((user) => user?.userId === userId)) { return renderToString( { @@ -164,13 +164,13 @@ const MessageInput = React.forwardRef((props, ref) => { , ); } - return value; + return encodeStrToHTML(value); }).join('') )).join(' '); } else { /* mention disabled */ try { - textField.innerHTML = message?.message; + textField.innerHTML = encodeStrToHTML(message?.message); } catch { } setMentionedUserIds([]); } @@ -428,7 +428,7 @@ const MessageInput = React.forwardRef((props, ref) => { }} onPaste={(e) => { e.preventDefault(); - document.execCommand("insertHTML", false, e?.clipboardData.getData('text')); + document.execCommand("insertHTML", false, encodeStrToHTML(e?.clipboardData.getData('text'))); }} /> {/* placeholder */} From 45fec88c183d0d0750c19ac8ab01421587bc7cf8 Mon Sep 17 00:00:00 2001 From: HoonBaek Date: Fri, 6 Jan 2023 14:12:44 +0900 Subject: [PATCH 3/3] Rename the function to sanitizeString --- src/ui/MessageInput/index.jsx | 8 ++++---- src/ui/MessageInput/utils.js | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ui/MessageInput/index.jsx b/src/ui/MessageInput/index.jsx index 97cd6a70e..9a6341586 100644 --- a/src/ui/MessageInput/index.jsx +++ b/src/ui/MessageInput/index.jsx @@ -19,7 +19,7 @@ import MentionUserLabel from '../MentionUserLabel'; import Icon, { IconTypes, IconColors } from '../Icon'; import Label, { LabelTypography, LabelColors } from '../Label'; import { LocalizationContext } from '../../lib/LocalizationContext'; -import { encodeStrToHTML } from './utils'; +import { sanitizeString } from './utils'; import { arrayEqual, getClassName, @@ -164,13 +164,13 @@ const MessageInput = React.forwardRef((props, ref) => { , ); } - return encodeStrToHTML(value); + return sanitizeString(value); }).join('') )).join(' '); } else { /* mention disabled */ try { - textField.innerHTML = encodeStrToHTML(message?.message); + textField.innerHTML = sanitizeString(message?.message); } catch { } setMentionedUserIds([]); } @@ -428,7 +428,7 @@ const MessageInput = React.forwardRef((props, ref) => { }} onPaste={(e) => { e.preventDefault(); - document.execCommand("insertHTML", false, encodeStrToHTML(e?.clipboardData.getData('text'))); + document.execCommand("insertHTML", false, sanitizeString(e?.clipboardData.getData('text'))); }} /> {/* placeholder */} diff --git a/src/ui/MessageInput/utils.js b/src/ui/MessageInput/utils.js index 7542df104..3e77e1dad 100644 --- a/src/ui/MessageInput/utils.js +++ b/src/ui/MessageInput/utils.js @@ -20,7 +20,8 @@ export function debounce(func, wait, immediate) { }; } -export const encodeStrToHTML = (str) => ( +// Sanitize that special characters of HTML tags cause XSS issue +export const sanitizeString = (str) => ( str?.replace(/[\u00A0-\u9999<>]/gim, (i) => ''.concat('&#', i.charCodeAt(0), ';')) );