From e947f81cd2bacf565059597dd04d3860d244c11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Tinkl?= Date: Wed, 4 Jan 2023 00:38:16 +0100 Subject: [PATCH] fix: Chat input: can't send html text from the clipboard We always take the plain text from the clipboard but even the plaintext can contain HTML tags, so escape those and wrap the result in a `
foo
` container. That way we preserve not only the linebreaks but also any whitespace or tags. Fixes #8919 --- src/app/global/utils.nim | 3 +++ .../popups/ContactVerificationRequestPopup.qml | 2 +- ui/imports/shared/status/StatusChatInput.qml | 15 +++++++-------- ui/imports/utils/Utils.qml | 11 +++++------ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/app/global/utils.nim b/src/app/global/utils.nim index 5c4bd53417..a571148cb7 100644 --- a/src/app/global/utils.nim +++ b/src/app/global/utils.nim @@ -140,6 +140,9 @@ QtObject: proc plainText*(self: Utils, text: string): string {.slot.} = result = plain_text(text) + proc escapeHtml*(self: Utils, text: string): string {.slot.} = + result = escape_html(text) + proc getEmojiHashAsJson*(self: Utils, publicKey: string): string {.slot.} = procs_from_visual_identity_service.getEmojiHashAsJson(publicKey) diff --git a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml index 0befbae267..c4006c4c56 100644 --- a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml +++ b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml @@ -28,7 +28,7 @@ StatusModal { root.close() } - d.senderPublicKey = request.from, + d.senderPublicKey = request.from d.senderDisplayName = request.displayName d.senderIcon = request.icon d.challengeText = request.challenge diff --git a/ui/imports/shared/status/StatusChatInput.qml b/ui/imports/shared/status/StatusChatInput.qml index 2c460af887..d5dca3c388 100644 --- a/ui/imports/shared/status/StatusChatInput.qml +++ b/ui/imports/shared/status/StatusChatInput.qml @@ -365,10 +365,10 @@ Rectangle { } else if (event.key === Qt.Key_Escape && control.isReply) { control.isReply = false event.accepted = true - } else if (event.key === Qt.Key_Up && getPlainText() == "") { + } else if (event.key === Qt.Key_Up && messageInputField.length === 0) { event.accepted = true control.keyUpPress() - return + return } const symbolPressed = event.text.length > 0 && @@ -458,8 +458,8 @@ Rectangle { d.copyTextStart = messageInputField.cursorPosition messageInputField.readOnly = true - const clipboardText = globalUtils.plainText(QClipboardProxy.text) - const copiedText = globalUtils.plainText(d.copiedTextPlain) + const clipboardText = Utils.plainText(QClipboardProxy.text) + const copiedText = Utils.plainText(d.copiedTextPlain) if (copiedText === clipboardText) { d.internalPaste = true } else { @@ -574,7 +574,7 @@ Rectangle { const deparsedEmoji = StatusQUtils.Emoji.deparse(textWithoutMention); - return globalUtils.plainText(deparsedEmoji) + return Utils.plainText(deparsedEmoji) } function removeMentions(currentText) { @@ -717,9 +717,8 @@ Rectangle { insertInTextInput(d.copyTextStart, d.copiedTextFormatted) messageInputField.cursorPosition = d.copyTextStart + messageInputField.length - prevLength d.internalPaste = false - } else if (event.matches(StandardKey.Paste)) { - insertInTextInput(d.copyTextStart, QClipboardProxy.text) - messageInputField.cursorPosition = d.copyTextStart + QClipboardProxy.text.length + } else if (event.matches(StandardKey.Paste) && QClipboardProxy.hasText) { + messageInputField.insert(d.copyTextStart, "
" + Utils.escapeHtml(QClipboardProxy.text) + "
") // preserve formatting } if (event.key !== Qt.Key_Escape) { diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index e27c347259..11185483cb 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -731,12 +731,11 @@ QtObject { } function escapeHtml(unsafeStr) { - return unsafeStr - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); + return globalUtilsInst.escapeHtml(unsafeStr) + } + + function plainText(text) { + return globalUtilsInst.plainText(text) } function isInvalidPasswordMessage(msg) {