diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index 383269f68..f3a7c8541 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -35,9 +35,15 @@ KeePass2XmlReader::KeePass2XmlReader() , m_db(Q_NULLPTR) , m_meta(Q_NULLPTR) , m_error(false) + , m_strictMode(false) { } +void KeePass2XmlReader::setStrictMode(bool strictMode) +{ + m_strictMode = strictMode; +} + void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream) { m_error = false; @@ -493,7 +499,12 @@ Group* KeePass2XmlReader::parseGroup() if (m_xml.name() == "UUID") { Uuid uuid = readUuid(); if (uuid.isNull()) { - raiseError("Null group uuid"); + if (m_strictMode) { + raiseError("Null group uuid"); + } + else { + group->setUuid(Uuid::random()); + } } else { group->setUuid(uuid); @@ -508,7 +519,9 @@ Group* KeePass2XmlReader::parseGroup() else if (m_xml.name() == "IconID") { int iconId = readNumber(); if (iconId < 0) { - raiseError("Invalid group icon number"); + if (m_strictMode) { + raiseError("Invalid group icon number"); + } } else { if (iconId >= DatabaseIcons::IconCount) { @@ -584,6 +597,10 @@ Group* KeePass2XmlReader::parseGroup() } } + if (group->uuid().isNull() && !m_strictMode) { + group->setUuid(Uuid::random()); + } + if (!group->uuid().isNull()) { Group* tmpGroup = group; group = getGroup(tmpGroup->uuid()); @@ -630,7 +647,9 @@ void KeePass2XmlReader::parseDeletedObject() if (m_xml.name() == "UUID") { Uuid uuid = readUuid(); if (uuid.isNull()) { - raiseError("Null DeleteObject uuid"); + if (m_strictMode) { + raiseError("Null DeleteObject uuid"); + } } else { delObj.uuid = uuid; @@ -647,7 +666,7 @@ void KeePass2XmlReader::parseDeletedObject() if (!delObj.uuid.isNull() && !delObj.deletionTime.isNull()) { m_db->addDeletedObject(delObj); } - else { + else if (m_strictMode) { raiseError("Missing DeletedObject uuid or time"); } } @@ -665,7 +684,12 @@ Entry* KeePass2XmlReader::parseEntry(bool history) if (m_xml.name() == "UUID") { Uuid uuid = readUuid(); if (uuid.isNull()) { - raiseError("Null entry uuid"); + if (m_strictMode) { + raiseError("Null entry uuid"); + } + else { + entry->setUuid(Uuid::random()); + } } else { entry->setUuid(uuid); @@ -674,7 +698,9 @@ Entry* KeePass2XmlReader::parseEntry(bool history) else if (m_xml.name() == "IconID") { int iconId = readNumber(); if (iconId < 0) { - raiseError("Invalud entry icon number"); + if (m_strictMode) { + raiseError("Invalud entry icon number"); + } } else { entry->setIcon(iconId); @@ -726,6 +752,10 @@ Entry* KeePass2XmlReader::parseEntry(bool history) } } + if (entry->uuid().isNull() && !m_strictMode) { + entry->setUuid(Uuid::random()); + } + if (!entry->uuid().isNull()) { if (history) { entry->setUpdateTimeinfo(false); @@ -986,7 +1016,12 @@ QDateTime KeePass2XmlReader::readDateTime() QDateTime dt = QDateTime::fromString(str, Qt::ISODate); if (!dt.isValid()) { - raiseError("Invalid date time value"); + if (m_strictMode) { + raiseError("Invalid date time value"); + } + else { + dt = Tools::currentDateTimeUtc(); + } } return dt; @@ -1001,7 +1036,9 @@ QColor KeePass2XmlReader::readColor() } if (colorStr.length() != 7 || colorStr[0] != '#') { - raiseError("Invalid color value"); + if (m_strictMode) { + raiseError("Invalid color value"); + } return QColor(); } @@ -1011,7 +1048,9 @@ QColor KeePass2XmlReader::readColor() bool ok; int rgbPart = rgbPartStr.toInt(&ok, 16); if (!ok || rgbPart > 255) { - raiseError("Invalid color rgb part"); + if (m_strictMode) { + raiseError("Invalid color rgb part"); + } return QColor(); } @@ -1043,7 +1082,9 @@ Uuid KeePass2XmlReader::readUuid() { QByteArray uuidBin = readBinary(); if (uuidBin.length() != Uuid::Length) { - raiseError("Invalid uuid value"); + if (m_strictMode) { + raiseError("Invalid uuid value"); + } return Uuid(); } else { diff --git a/src/format/KeePass2XmlReader.h b/src/format/KeePass2XmlReader.h index 4520d42bf..ca311b0e4 100644 --- a/src/format/KeePass2XmlReader.h +++ b/src/format/KeePass2XmlReader.h @@ -47,6 +47,7 @@ public: bool hasError(); QString errorString(); QByteArray headerHash(); + void setStrictMode(bool strictMode); private: bool parseKeePassFile(); @@ -95,6 +96,7 @@ private: QByteArray m_headerHash; bool m_error; QString m_errorStr; + bool m_strictMode; }; #endif // KEEPASSX_KEEPASS2XMLREADER_H diff --git a/tests/TestDeletedObjects.cpp b/tests/TestDeletedObjects.cpp index 277dbcb6b..cf9e3d104 100644 --- a/tests/TestDeletedObjects.cpp +++ b/tests/TestDeletedObjects.cpp @@ -90,6 +90,7 @@ void TestDeletedObjects::createAndDelete(Database* db, int delObjectsSize) void TestDeletedObjects::testDeletedObjectsFromFile() { KeePass2XmlReader reader; + reader.setStrictMode(true); QString xmlFile = QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml"); Database* db = reader.readDatabase(xmlFile); diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index 8e87d6744..e88e990a6 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -71,6 +71,7 @@ void TestKeePass2XmlReader::initTestCase() QVERIFY(Crypto::init()); KeePass2XmlReader reader; + reader.setStrictMode(true); QString xmlFile = QString(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.xml"); m_db = reader.readDatabase(xmlFile); QVERIFY(m_db); @@ -357,23 +358,41 @@ void TestKeePass2XmlReader::testDeletedObjects() void TestKeePass2XmlReader::testBroken() { QFETCH(QString, baseName); + QFETCH(bool, strictMode); + QFETCH(bool, expectError); KeePass2XmlReader reader; + reader.setStrictMode(strictMode); QString xmlFile = QString("%1/%2.xml").arg(KEEPASSX_TEST_DATA_DIR, baseName); QVERIFY(QFile::exists(xmlFile)); QScopedPointer db(reader.readDatabase(xmlFile)); - QVERIFY(reader.hasError()); + if (reader.hasError()) { + qWarning("Reader error: %s", qPrintable(reader.errorString())); + } + QCOMPARE(reader.hasError(), expectError); } void TestKeePass2XmlReader::testBroken_data() { QTest::addColumn("baseName"); + QTest::addColumn("strictMode"); + QTest::addColumn("expectError"); - QTest::newRow("BrokenNoGroupUuid") << "BrokenNoGroupUuid"; - QTest::newRow("BrokenNoEntryUuid") << "BrokenNoEntryUuid"; - QTest::newRow("BrokenNoRootGroup") << "BrokenNoRootGroup"; - QTest::newRow("BrokenTwoRoots") << "BrokenTwoRoots"; - QTest::newRow("BrokenTwoRootGroups") << "BrokenTwoRootGroups"; + // testfile strict? error? + QTest::newRow("BrokenNoGroupUuid (strict)") << "BrokenNoGroupUuid" << true << true; + QTest::newRow("BrokenNoGroupUuid (not strict)") << "BrokenNoGroupUuid" << false << false; + QTest::newRow("BrokenNoEntryUuid (strict)") << "BrokenNoEntryUuid" << true << true; + QTest::newRow("BrokenNoEntryUuid (not strict)") << "BrokenNoEntryUuid" << false << false; + QTest::newRow("BrokenNoRootGroup (strict)") << "BrokenNoRootGroup" << true << true; + QTest::newRow("BrokenNoRootGroup (not strict)") << "BrokenNoRootGroup" << false << true; + QTest::newRow("BrokenTwoRoots (strict)") << "BrokenTwoRoots" << true << true; + QTest::newRow("BrokenTwoRoots (not strict)") << "BrokenTwoRoots" << false << true; + QTest::newRow("BrokenTwoRootGroups (strict)") << "BrokenTwoRootGroups" << true << true; + QTest::newRow("BrokenTwoRootGroups (not strict)") << "BrokenTwoRootGroups" << false << true; + QTest::newRow("BrokenGroupReference (strict)") << "BrokenGroupReference" << true << false; + QTest::newRow("BrokenGroupReference (not strict)") << "BrokenGroupReference" << false << false; + QTest::newRow("BrokenDeletedObjects (strict)") << "BrokenDeletedObjects" << true << true; + QTest::newRow("BrokenDeletedObjects (not strict)") << "BrokenDeletedObjects" << false << false; } void TestKeePass2XmlReader::cleanupTestCase() diff --git a/tests/data/BrokenDeletedObjects.xml b/tests/data/BrokenDeletedObjects.xml new file mode 100644 index 000000000..89506aa62 --- /dev/null +++ b/tests/data/BrokenDeletedObjects.xml @@ -0,0 +1,27 @@ + + + + + lmU+9n0aeESKZvcEze+bRg== + Test + + AaUYVdXsI02h4T1RiAlgtg== + + Title + Sample Entry 1 + + + + + + + 2010-08-25T16:14:12Z + + + + 5K/bzWCSmkCv5OZxYl4N/w== + + + + + diff --git a/tests/data/BrokenGroupReference.xml b/tests/data/BrokenGroupReference.xml new file mode 100644 index 000000000..b3207e1ac --- /dev/null +++ b/tests/data/BrokenGroupReference.xml @@ -0,0 +1,20 @@ + + + + True + 6w7wZdhAp0qVlXjkemuCYw== + + + + lmU+9n0aeESKZvcEze+bRg== + Test + + AaUYVdXsI02h4T1RiAlgtg== + + Title + Sample Entry 1 + + + + + diff --git a/tests/data/BrokenNoEntryUuid.xml b/tests/data/BrokenNoEntryUuid.xml index 38ab96f2e..595f836f7 100644 --- a/tests/data/BrokenNoEntryUuid.xml +++ b/tests/data/BrokenNoEntryUuid.xml @@ -9,6 +9,7 @@ Title Sample Entry 1 +