fix mentions with markdown and in edits

This commit is contained in:
Nicolas Werner 2024-05-31 18:17:35 +02:00
parent 1c5f747856
commit ec9af40fc5
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
7 changed files with 50 additions and 18 deletions

View file

@ -606,7 +606,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare( FetchContent_Declare(
MatrixClient MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG 8b3c9a34770df147fbd78134dc71a9b27471d153 GIT_TAG 604a2ec95b03fbf8c856bc481e7582f5c6a64748
) )
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "") set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "") set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")

View file

@ -223,7 +223,7 @@ modules:
buildsystem: cmake-ninja buildsystem: cmake-ninja
name: mtxclient name: mtxclient
sources: sources:
- commit: 8b3c9a34770df147fbd78134dc71a9b27471d153 - commit: 604a2ec95b03fbf8c856bc481e7582f5c6a64748
#tag: v0.9.2 #tag: v0.9.2
type: git type: git
url: https://github.com/Nheko-Reborn/mtxclient.git url: https://github.com/Nheko-Reborn/mtxclient.git

View file

@ -11,6 +11,7 @@
#include "CompletionModelRoles.h" #include "CompletionModelRoles.h"
#include "Logging.h" #include "Logging.h"
#include "UserSettingsPage.h" #include "UserSettingsPage.h"
#include "Utils.h"
UsersModel::UsersModel(const std::string &roomId, QObject *parent) UsersModel::UsersModel(const std::string &roomId, QObject *parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
@ -66,10 +67,7 @@ UsersModel::data(const QModelIndex &index, int role) const
case CompletionModel::CompletionRole: case CompletionModel::CompletionRole:
if (UserSettings::instance()->markdown()) if (UserSettings::instance()->markdown())
return QStringLiteral("[%1](https://matrix.to/#/%2)") return QStringLiteral("[%1](https://matrix.to/#/%2)")
.arg(QString(displayNames[index.row()]) .arg(utils::escapeMentionMarkdown(QString(displayNames[index.row()])),
.replace("[", "\\[")
.replace("]", "\\]")
.toHtmlEscaped(),
QString(QUrl::toPercentEncoding(userids[index.row()]))); QString(QUrl::toPercentEncoding(userids[index.row()])));
else else
return displayNames[index.row()]; return displayNames[index.row()];

View file

@ -581,6 +581,34 @@ utils::linkifyMessage(const QString &body)
return doc; return doc;
} }
QString
utils::escapeMentionMarkdown(QString input)
{
input = input.toHtmlEscaped();
constexpr std::array<char, 10> markdownChars = {
'\\',
'`',
'*',
'_',
/*'{', '}',*/ '[',
']',
'<',
'>',
/* '(', ')', '#', '-', '+', '.', '!', */ '~',
'|',
};
QByteArray replacement = "\\\\";
for (char c : markdownChars) {
replacement[1] = c;
input.replace(QChar::fromLatin1(c), QLatin1StringView(replacement));
}
return input;
}
QString QString
utils::escapeBlacklistedHtml(const QString &rawStr) utils::escapeBlacklistedHtml(const QString &rawStr)
{ {
@ -1139,18 +1167,19 @@ utils::getFormattedQuoteBody(const RelatedInfo &related, const QString &html)
return QStringLiteral("sent a video"); return QStringLiteral("sent a video");
} }
default: { default: {
return related.quoted_formatted_body; return escapeBlacklistedHtml(related.quoted_formatted_body);
} }
} }
}; };
return QStringLiteral("<mx-reply><blockquote><a " return QStringLiteral("<mx-reply><blockquote><a "
"href=\"https://matrix.to/#/%1/%2\">In reply " "href=\"https://matrix.to/#/%1/%2\">In reply "
"to</a> <a href=\"https://matrix.to/#/%3\">%4</a><br" "to</a> <a href=\"https://matrix.to/#/%3\">%4</a><br"
"/>%5</blockquote></mx-reply>") "/>%5</blockquote></mx-reply>")
.arg(related.room, .arg(related.room,
QString::fromStdString(related.related_event), QString::fromStdString(related.related_event),
related.quoted_user, QUrl::toPercentEncoding(related.quoted_user),
related.quoted_user, related.quoted_user.toHtmlEscaped(),
getFormattedBody()) + getFormattedBody()) +
html; html;
} }

View file

@ -140,6 +140,9 @@ linkifyMessage(const QString &body);
QString QString
markdownToHtml(const QString &text, bool rainbowify = false, bool noExtensions = false); markdownToHtml(const QString &text, bool rainbowify = false, bool noExtensions = false);
QString
escapeMentionMarkdown(QString input);
//! Escape every html tag, that was not whitelisted //! Escape every html tag, that was not whitelisted
QString QString
escapeBlacklistedHtml(const QString &data); escapeBlacklistedHtml(const QString &data);

View file

@ -462,8 +462,7 @@ replaceMatrixToMarkdownLink(QString input)
int newline = input.indexOf('\n', endOfName); int newline = input.indexOf('\n', endOfName);
if (endOfLink > endOfName && (newline == -1 || endOfLink < newline)) { if (endOfLink > endOfName && (newline == -1 || endOfLink < newline)) {
auto name = input.mid(startOfName + 1, endOfName - startOfName - 1); auto name = input.mid(startOfName + 1, endOfName - startOfName - 1);
name.replace("\\[", "["); name.remove(QChar(u'\\'), Qt::CaseSensitive);
name.replace("\\]", "]");
input.replace(startOfName, endOfLink - startOfName + 1, name); input.replace(startOfName, endOfLink - startOfName + 1, name);
replaced = true; replaced = true;
} }
@ -522,6 +521,7 @@ InputBar::generateMentions()
// this->containsAtRoom_ = false; // this->containsAtRoom_ = false;
// this->mentions_.clear(); // this->mentions_.clear();
// this->mentionTexts_.clear(); // this->mentionTexts_.clear();
return mention; return mention;
} }

View file

@ -3080,8 +3080,6 @@ TimelineModel::setEdit(const QString &newEdit)
input()->storeForEdit(); input()->storeForEdit();
} }
auto quoted = [](QString in) { return in.replace("[", "\\[").replace("]", "\\]"); };
if (edit_ != newEdit) { if (edit_ != newEdit) {
auto ev = events.get(newEdit.toStdString(), ""); auto ev = events.get(newEdit.toStdString(), "");
if (ev && mtx::accessors::sender(*ev) == http::client()->user_id().to_string()) { if (ev && mtx::accessors::sender(*ev) == http::client()->user_id().to_string()) {
@ -3100,9 +3098,11 @@ TimelineModel::setEdit(const QString &newEdit)
for (const auto &user : mentionsList->user_ids) { for (const auto &user : mentionsList->user_ids) {
auto userid = QString::fromStdString(user); auto userid = QString::fromStdString(user);
mentions.append(userid); mentions.append(userid);
mentionTexts.append( mentionTexts.append(QStringLiteral("[%1](https://matrix.to/#/%2)")
QStringLiteral("[%1](https://matrix.to/#/%2)") .arg(utils::escapeMentionMarkdown(
.arg(displayName(userid).replace("[", "\\[").replace("]", "\\]"), // not using TimelineModel::displayName here,
// because it would double html escape
cache::displayName(room_id_, userid)),
QString(QUrl::toPercentEncoding(userid)))); QString(QUrl::toPercentEncoding(userid))));
} }
} }
@ -3127,7 +3127,9 @@ TimelineModel::setEdit(const QString &newEdit)
for (const auto &[user, link] : reverseNameMapping) { for (const auto &[user, link] : reverseNameMapping) {
// TODO(Nico): html unescape the user name // TODO(Nico): html unescape the user name
editText.replace(user, QStringLiteral("[%1](%2)").arg(quoted(user), link)); editText.replace(
user,
QStringLiteral("[%1](%2)").arg(utils::escapeMentionMarkdown(user), link));
} }
} }