Strip invalid XML chars when writing databases.

These characters are unprintable or just plain invalid.
QXmlStreamReader throws and error when reading XML documents with such chars.

Closes 
This commit is contained in:
Felix Geyer 2016-01-24 17:20:16 +01:00
parent 5e6b17aba4
commit 2d741afe3e
4 changed files with 52 additions and 2 deletions

@ -374,7 +374,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
}
if (!value.isEmpty()) {
m_xml.writeCharacters(value);
m_xml.writeCharacters(stripInvalidXml10Chars(value));
}
m_xml.writeEndElement();
@ -445,7 +445,7 @@ void KeePass2XmlWriter::writeString(const QString& qualifiedName, const QString&
m_xml.writeEmptyElement(qualifiedName);
}
else {
m_xml.writeTextElement(qualifiedName, string);
m_xml.writeTextElement(qualifiedName, stripInvalidXml10Chars(string));
}
}
@ -549,6 +549,23 @@ QString KeePass2XmlWriter::colorPartToString(int value)
return str;
}
QString KeePass2XmlWriter::stripInvalidXml10Chars(QString str)
{
for (int i = str.size() - 1; i >= 0; i--) {
const ushort uc = str.at(i).unicode();
if ((uc < 0x20 && uc != 0x09 && uc != 0x0A && uc != 0x0D)
|| (uc > 0xD7FF && uc < 0xE000)
|| (uc > 0xFFFD))
{
qWarning("Stripping invalid XML 1.0 codepoint %x", uc);
str.remove(i, 1);
}
}
return str;
}
void KeePass2XmlWriter::raiseError(const QString& errorMessage)
{
m_error = true;

@ -73,6 +73,7 @@ private:
void writeColor(const QString& qualifiedName, const QColor& color);
void writeTriState(const QString& qualifiedName, Group::TriState triState);
QString colorPartToString(int value);
QString stripInvalidXml10Chars(QString str);
void raiseError(const QString& errorMessage);

@ -17,6 +17,7 @@
#include "TestKeePass2XmlReader.h"
#include <QBuffer>
#include <QFile>
#include <QTest>
@ -26,6 +27,7 @@
#include "core/Metadata.h"
#include "crypto/Crypto.h"
#include "format/KeePass2XmlReader.h"
#include "format/KeePass2XmlWriter.h"
#include "config-keepassx-tests.h"
QTEST_GUILESS_MAIN(TestKeePass2XmlReader)
@ -408,6 +410,35 @@ void TestKeePass2XmlReader::testEmptyUuids()
QVERIFY(!reader.hasError());
}
void TestKeePass2XmlReader::testInvalidXmlChars()
{
QScopedPointer<Database> dbWrite(new Database());
Entry* entry = new Entry();
entry->setUuid(Uuid::random());
entry->setNotes(QString("a %1 b %2 c %3").arg(QChar(0x02)).arg(QChar(0xD800)).arg(QChar(0xFFFE)));
entry->setGroup(dbWrite->rootGroup());
QBuffer buffer;
buffer.open(QIODevice::ReadWrite);
KeePass2XmlWriter writer;
writer.writeDatabase(&buffer, dbWrite.data());
QVERIFY(!writer.hasError());
buffer.seek(0);
KeePass2XmlReader reader;
reader.setStrictMode(true);
QScopedPointer<Database> dbRead(reader.readDatabase(&buffer));
if (reader.hasError()) {
qWarning("Database read error: %s", qPrintable(reader.errorString()));
}
QVERIFY(!reader.hasError());
QVERIFY(!dbRead.isNull());
QCOMPARE(dbRead->rootGroup()->entries().size(), 1);
// check that the invalid codepoints have been stripped
QCOMPARE(dbRead->rootGroup()->entries().first()->notes(), QString("a b c "));
}
void TestKeePass2XmlReader::cleanupTestCase()
{
delete m_db;

@ -42,6 +42,7 @@ private Q_SLOTS:
void testBroken();
void testBroken_data();
void testEmptyUuids();
void testInvalidXmlChars();
void cleanupTestCase();
private: