/* * Copyright (C) 2017 David Edmundson * * This program is free software you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "notificationsanitizer.h" #include #include #include #include #include QString NotificationSanitizer::parse(const QString &text) { // replace all \ns with
QString t = text; t.replace(QLatin1String("\n"), QStringLiteral("
")); // Now remove all inner whitespace (\ns are already
s) t = t.simplified(); // Finally, check if we don't have multiple
s following, // can happen for example when "\n \n" is sent, this replaces // all
s in succsession with just one t.replace(QRegularExpression(QStringLiteral("
\\s*
(\\s|
)*")), QLatin1String("
")); // This fancy RegExp escapes every occurence of & since QtQuick Text will blatantly cut off // text where it finds a stray ampersand. // Only &{apos, quot, gt, lt, amp}; as well as { character references will be allowed t.replace(QRegularExpression(QStringLiteral("&(?!(?:apos|quot|[gl]t|amp);|#)")), QLatin1String("&")); QXmlStreamReader r(QStringLiteral("") + t + QStringLiteral("")); QString result; QXmlStreamWriter out(&result); const QVector allowedTags = {"b", "i", "u", "img", "a", "html", "br"}; out.writeStartDocument(); while (!r.atEnd()) { r.readNext(); if (r.tokenType() == QXmlStreamReader::StartElement) { const QString name = r.name().toString(); if (!allowedTags.contains(name)) { continue; } out.writeStartElement(name); if (name == QLatin1String("img")) { auto src = r.attributes().value("src").toString(); auto alt = r.attributes().value("alt").toString(); const QUrl url(src); if (url.isLocalFile()) { out.writeAttribute(QStringLiteral("src"), src); } else { //image denied for security reasons! Do not copy the image src here! } out.writeAttribute(QStringLiteral("alt"), alt); } if (name == QLatin1String("a")) { out.writeAttribute(QStringLiteral("href"), r.attributes().value("href").toString()); } } if (r.tokenType() == QXmlStreamReader::EndElement) { const QString name = r.name().toString(); if (!allowedTags.contains(name)) { continue; } out.writeEndElement(); } if (r.tokenType() == QXmlStreamReader::Characters) { const auto text = r.text().toString(); out.writeCharacters(text); //this auto escapes chars -> HTML entities } } out.writeEndDocument(); if (r.hasError()) { qWarning() << "Notification to send to backend contains invalid XML: " << r.errorString() << "line" << r.lineNumber() << "col" << r.columnNumber(); } // The Text.StyledText format handles only html3.2 stuff and ' is html4 stuff // so we need to replace it here otherwise it will not render at all. result = result.replace(QLatin1String("'"), QChar('\'')); return result; }