20
#include "config-keepassx-tests.h"
21
#include "core/Metadata.h"
22
#include "format/KdbxXmlReader.h"
23
#include "format/KdbxXmlWriter.h"
24
#include "format/KeePass2.h"
25
#include "format/KeePass2Reader.h"
26
#include "format/KeePass2Writer.h"
27
#include "keys/PasswordKey.h"
30
QTEST_GUILESS_MAIN(TestKdbx3)
32
void TestKdbx3::initTestCaseImpl()
34
m_xmlDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX3)));
35
m_kdbxSourceDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX3)));
38
QSharedPointer<Database> TestKdbx3::readXml(const QString& path, bool strictMode, bool& hasError, QString& errorString)
40
KdbxXmlReader reader(KeePass2::FILE_VERSION_3_1);
41
reader.setStrictMode(strictMode);
42
auto db = reader.readDatabase(path);
43
hasError = reader.hasError();
44
errorString = reader.errorString();
48
QSharedPointer<Database> TestKdbx3::readXml(QBuffer* buf, bool strictMode, bool& hasError, QString& errorString)
50
KdbxXmlReader reader(KeePass2::FILE_VERSION_3_1);
51
reader.setStrictMode(strictMode);
52
auto db = reader.readDatabase(buf);
53
hasError = reader.hasError();
54
errorString = reader.errorString();
58
void TestKdbx3::writeXml(QBuffer* buf, Database* db, bool& hasError, QString& errorString)
60
KdbxXmlWriter writer(KeePass2::FILE_VERSION_3_1);
61
writer.writeDatabase(buf, db);
62
hasError = writer.hasError();
63
errorString = writer.errorString();
66
void TestKdbx3::readKdbx(QIODevice* device,
67
QSharedPointer<const CompositeKey> key,
68
QSharedPointer<Database> db,
72
KeePass2Reader reader;
73
reader.readDatabase(device, key, db.data());
74
hasError = reader.hasError();
76
errorString = reader.errorString();
78
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_3_1);
81
void TestKdbx3::writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString)
83
KeePass2Writer writer;
84
hasError = writer.writeDatabase(device, db);
85
hasError = writer.hasError();
87
errorString = writer.errorString();
89
QCOMPARE(writer.version(), KeePass2::FILE_VERSION_3_1);
92
void TestKdbx3::testFormat300()
94
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/Format300.kdbx");
95
auto key = QSharedPointer<CompositeKey>::create();
96
key->addKey(QSharedPointer<PasswordKey>::create("a"));
97
KeePass2Reader reader;
98
auto db = QSharedPointer<Database>::create();
99
QVERIFY(reader.readDatabase(filename, key, db.data()));
100
QCOMPARE(reader.version(), KeePass2::FILE_VERSION_3);
102
QVERIFY(!reader.hasError());
104
QCOMPARE(db->rootGroup()->name(), QString("Format300"));
105
QCOMPARE(db->metadata()->name(), QString("Test Database Format 0x00030000"));
108
void TestKdbx3::testNonAscii()
110
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/NonAscii.kdbx");
111
auto key = QSharedPointer<CompositeKey>::create();
112
key->addKey(QSharedPointer<PasswordKey>::create(QString::fromUtf8("\xce\x94\xc3\xb6\xd8\xb6")));
113
KeePass2Reader reader;
114
auto db = QSharedPointer<Database>::create();
115
QVERIFY(db->open(filename, key, nullptr));
117
QVERIFY(!reader.hasError());
118
QCOMPARE(db->metadata()->name(), QString("NonAsciiTest"));
119
QCOMPARE(db->compressionAlgorithm(), Database::CompressionNone);
122
void TestKdbx3::testCompressed()
124
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/Compressed.kdbx");
125
auto key = QSharedPointer<CompositeKey>::create();
126
key->addKey(QSharedPointer<PasswordKey>::create(""));
127
KeePass2Reader reader;
128
auto db = QSharedPointer<Database>::create();
129
QVERIFY(db->open(filename, key, nullptr));
131
QVERIFY(!reader.hasError());
132
QCOMPARE(db->metadata()->name(), QString("Compressed"));
133
QCOMPARE(db->compressionAlgorithm(), Database::CompressionGZip);
136
void TestKdbx3::testProtectedStrings()
138
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/ProtectedStrings.kdbx");
139
auto key = QSharedPointer<CompositeKey>::create();
140
key->addKey(QSharedPointer<PasswordKey>::create("masterpw"));
141
KeePass2Reader reader;
142
auto db = QSharedPointer<Database>::create();
143
QVERIFY(db->open(filename, key, nullptr));
145
QVERIFY(!reader.hasError());
146
QCOMPARE(db->metadata()->name(), QString("Protected Strings Test"));
148
Entry* entry = db->rootGroup()->entries().at(0);
150
QCOMPARE(entry->title(), QString("Sample Entry"));
151
QCOMPARE(entry->username(), QString("Protected User Name"));
152
QCOMPARE(entry->password(), QString("ProtectedPassword"));
153
QCOMPARE(entry->attributes()->value("TestProtected"), QString("ABC"));
154
QCOMPARE(entry->attributes()->value("TestUnprotected"), QString("DEF"));
156
QVERIFY(db->metadata()->protectPassword());
157
QVERIFY(entry->attributes()->isProtected("TestProtected"));
158
QVERIFY(!entry->attributes()->isProtected("TestUnprotected"));
161
void TestKdbx3::testBrokenHeaderHash()
166
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/BrokenHeaderHash.kdbx");
167
auto key = QSharedPointer<CompositeKey>::create();
168
key->addKey(QSharedPointer<PasswordKey>::create(""));
169
auto db = QSharedPointer<Database>::create();
170
QVERIFY(!db->open(filename, key, nullptr));
173
void TestKdbx3::testAttachmentIndexStability()
175
QScopedPointer<Database> db(new Database());
176
db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX3)));
177
auto compositeKey = QSharedPointer<CompositeKey>::create();
178
db->setKey(compositeKey);
179
QVERIFY(!db->uuid().isNull());
181
auto root = db->rootGroup();
183
auto group1 = new Group();
184
group1->setUuid(QUuid::createUuid());
185
QVERIFY(!group1->uuid().isNull());
186
group1->setParent(root);
188
auto attachment1 = QByteArray("qwerty");
189
auto attachment2 = QByteArray("asdf");
190
auto attachment3 = QByteArray("zxcv");
192
auto entry1 = new Entry();
193
entry1->setUuid(QUuid::createUuid());
194
QVERIFY(!entry1->uuid().isNull());
195
auto uuid1 = entry1->uuid();
196
entry1->attachments()->set("a", attachment1);
197
QCOMPARE(entry1->attachments()->keys().size(), 1);
198
QCOMPARE(entry1->attachments()->values().size(), 1);
199
entry1->setGroup(root);
201
auto entry2 = new Entry();
202
entry2->setUuid(QUuid::createUuid());
203
QVERIFY(!entry2->uuid().isNull());
204
auto uuid2 = entry2->uuid();
205
entry2->attachments()->set("a", attachment1);
206
entry2->attachments()->set("b", attachment2);
207
QCOMPARE(entry2->attachments()->keys().size(), 2);
208
QCOMPARE(entry2->attachments()->values().size(), 2);
209
entry2->setGroup(group1);
211
auto entry3 = new Entry();
212
entry3->setUuid(QUuid::createUuid());
213
QVERIFY(!entry3->uuid().isNull());
214
auto uuid3 = entry3->uuid();
215
entry3->attachments()->set("a", attachment1);
216
entry3->attachments()->set("b", attachment2);
217
entry3->attachments()->set("x", attachment3);
218
entry3->attachments()->set("y", attachment3);
219
QCOMPARE(entry3->attachments()->keys().size(), 4);
220
QCOMPARE(entry3->attachments()->values().size(), 3);
221
entry3->setGroup(group1);
224
buffer.open(QBuffer::ReadWrite);
225
KeePass2Writer writer;
226
QVERIFY(writer.writeDatabase(&buffer, db.data()));
227
QCOMPARE(writer.version(), KeePass2::FILE_VERSION_3_1);
230
KeePass2Reader reader;
233
auto db2 = QSharedPointer<Database>::create();
234
reader.readDatabase(&buffer, QSharedPointer<CompositeKey>::create(), db2.data());
235
QVERIFY(!reader.hasError());
236
QVERIFY(!db->uuid().isNull());
238
auto a1 = db2->rootGroup()->findEntryByUuid(uuid1)->attachments();
239
QCOMPARE(a1->keys().size(), 1);
240
QCOMPARE(a1->values().size(), 1);
241
QCOMPARE(a1->value("a"), attachment1);
243
auto a2 = db2->rootGroup()->findEntryByUuid(uuid2)->attachments();
244
QCOMPARE(a2->keys().size(), 2);
245
QCOMPARE(a2->values().size(), 2);
246
QCOMPARE(a2->value("a"), attachment1);
247
QCOMPARE(a2->value("b"), attachment2);
249
auto a3 = db2->rootGroup()->findEntryByUuid(uuid3)->attachments();
250
QCOMPARE(a3->keys().size(), 4);
251
QCOMPARE(a3->values().size(), 3);
252
QCOMPARE(a3->value("a"), attachment1);
253
QCOMPARE(a3->value("b"), attachment2);
254
QCOMPARE(a3->value("x"), attachment3);
255
QCOMPARE(a3->value("y"), attachment3);