keepassxc

Форк
0
/
TestDatabase.cpp 
270 строк · 9.1 Кб
1
/*
2
 *  Copyright (C) 2017 Vladimir Svyatski <v.unreal@gmail.com>
3
 *  Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation, either version 2 or (at your option)
8
 *  version 3 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
#include "TestDatabase.h"
20

21
#include <QRegularExpression>
22
#include <QSignalSpy>
23
#include <QTest>
24

25
#include "config-keepassx-tests.h"
26
#include "core/Group.h"
27
#include "core/Metadata.h"
28
#include "core/Tools.h"
29
#include "crypto/Crypto.h"
30
#include "format/KeePass2Writer.h"
31
#include "util/TemporaryFile.h"
32

33
#ifdef Q_OS_WIN
34
#include <QFileInfo>
35
#include <Windows.h>
36
#endif
37

38
QTEST_GUILESS_MAIN(TestDatabase)
39

40
static QString dbFileName = QStringLiteral(KEEPASSX_TEST_DATA_DIR).append("/NewDatabase.kdbx");
41

42
void TestDatabase::initTestCase()
43
{
44
    QVERIFY(Crypto::init());
45
}
46

47
void TestDatabase::testOpen()
48
{
49
    auto db = QSharedPointer<Database>::create();
50
    QVERIFY(!db->isInitialized());
51
    QVERIFY(!db->isModified());
52

53
    auto key = QSharedPointer<CompositeKey>::create();
54
    key->addKey(QSharedPointer<PasswordKey>::create("a"));
55

56
    bool ok = db->open(dbFileName, key);
57
    QVERIFY(ok);
58

59
    QVERIFY(db->isInitialized());
60
    QVERIFY(!db->isModified());
61

62
    db->metadata()->setName("test");
63
    QVERIFY(db->isModified());
64
}
65

66
void TestDatabase::testSave()
67
{
68
    TemporaryFile tempFile;
69
    QVERIFY(tempFile.copyFromFile(dbFileName));
70

71
    auto db = QSharedPointer<Database>::create();
72
    auto key = QSharedPointer<CompositeKey>::create();
73
    key->addKey(QSharedPointer<PasswordKey>::create("a"));
74

75
    QString error;
76
    bool ok = db->open(tempFile.fileName(), key, &error);
77
    QVERIFY(ok);
78

79
    // Test safe saves
80
    db->metadata()->setName("test");
81
    QVERIFY(db->isModified());
82
    QVERIFY2(db->save(Database::Atomic, {}, &error), error.toLatin1());
83
    QVERIFY(!db->isModified());
84

85
    // Test temp-file saves
86
    db->metadata()->setName("test2");
87
    QVERIFY2(db->save(Database::TempFile, QString(), &error), error.toLatin1());
88
    QVERIFY(!db->isModified());
89

90
    // Test direct-write saves
91
    db->metadata()->setName("test3");
92
    QVERIFY2(db->save(Database::DirectWrite, QString(), &error), error.toLatin1());
93
    QVERIFY(!db->isModified());
94

95
    // Test save backups
96
    TemporaryFile backupFile;
97
    auto backupFilePath = backupFile.fileName();
98
    db->metadata()->setName("test4");
99
    QVERIFY2(db->save(Database::Atomic, backupFilePath, &error), error.toLatin1());
100
    QVERIFY(!db->isModified());
101

102
    QVERIFY(QFile::exists(backupFilePath));
103
    QFile::remove(backupFilePath);
104
    QVERIFY(!QFile::exists(backupFilePath));
105
}
106

107
void TestDatabase::testSaveAs()
108
{
109
    TemporaryFile tempFile;
110
    QVERIFY(tempFile.copyFromFile(dbFileName));
111

112
    auto db = QSharedPointer<Database>::create();
113
    auto key = QSharedPointer<CompositeKey>::create();
114
    key->addKey(QSharedPointer<PasswordKey>::create("a"));
115

116
    QString error;
117
    QVERIFY(db->open(tempFile.fileName(), key, &error));
118

119
    // Happy path case when try to save as new DB.
120
    QSignalSpy spyFilePathChanged(db.data(), SIGNAL(filePathChanged(const QString&, const QString&)));
121
    QString newDbFileName = QStringLiteral(KEEPASSX_TEST_DATA_DIR).append("/SaveAsNewDatabase.kdbx");
122
    QVERIFY2(db->saveAs(newDbFileName, Database::Atomic, QString(), &error), error.toLatin1());
123
    QVERIFY(!db->isModified());
124
    QCOMPARE(spyFilePathChanged.count(), 1);
125
    QVERIFY(QFile::exists(newDbFileName));
126
#ifdef Q_OS_WIN
127
    QVERIFY(!QFileInfo::QFileInfo(newDbFileName).isHidden());
128
    SetFileAttributes(newDbFileName.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN);
129
    QVERIFY2(db->saveAs(newDbFileName, Database::Atomic, QString(), &error), error.toLatin1());
130
    QVERIFY(QFileInfo::QFileInfo(newDbFileName).isHidden());
131
#endif
132
    QFile::remove(newDbFileName);
133
    QVERIFY(!QFile::exists(newDbFileName));
134

135
    // Negative case when try to save not initialized DB.
136
    db->releaseData();
137
    QVERIFY2(!db->saveAs(newDbFileName, Database::Atomic, QString(), &error), error.toLatin1());
138
    QCOMPARE(error, QString("Could not save, database has not been initialized!"));
139
}
140

141
void TestDatabase::testSignals()
142
{
143
    TemporaryFile tempFile;
144
    QVERIFY(tempFile.copyFromFile(dbFileName));
145

146
    auto db = QSharedPointer<Database>::create();
147
    auto key = QSharedPointer<CompositeKey>::create();
148
    key->addKey(QSharedPointer<PasswordKey>::create("a"));
149

150
    QSignalSpy spyFilePathChanged(db.data(), SIGNAL(filePathChanged(const QString&, const QString&)));
151
    QString error;
152
    bool ok = db->open(tempFile.fileName(), key, &error);
153
    QVERIFY(ok);
154
    QCOMPARE(spyFilePathChanged.count(), 1);
155

156
    QSignalSpy spyModified(db.data(), SIGNAL(modified()));
157
    db->metadata()->setName("test1");
158
    QTRY_COMPARE(spyModified.count(), 1);
159

160
    QSignalSpy spySaved(db.data(), SIGNAL(databaseSaved()));
161
    QVERIFY(db->save(Database::Atomic, {}, &error));
162
    QCOMPARE(spySaved.count(), 1);
163

164
    // Short delay to allow file system settling to reduce test failures
165
    Tools::wait(100);
166

167
    QSignalSpy spyFileChanged(db.data(), SIGNAL(databaseFileChanged()));
168
    QVERIFY(tempFile.copyFromFile(dbFileName));
169
    QTRY_COMPARE(spyFileChanged.count(), 1);
170
    QTRY_VERIFY(!db->isModified());
171

172
    db->metadata()->setName("test2");
173
    QTRY_VERIFY(db->isModified());
174

175
    QSignalSpy spyDiscarded(db.data(), SIGNAL(databaseDiscarded()));
176
    QVERIFY(db->open(tempFile.fileName(), key, &error));
177
    QCOMPARE(spyDiscarded.count(), 1);
178
}
179

180
void TestDatabase::testEmptyRecycleBinOnDisabled()
181
{
182
    QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinDisabled.kdbx");
183
    auto key = QSharedPointer<CompositeKey>::create();
184
    key->addKey(QSharedPointer<PasswordKey>::create("123"));
185
    auto db = QSharedPointer<Database>::create();
186
    QVERIFY(db->open(filename, key, nullptr));
187

188
    QSignalSpy spyModified(db.data(), SIGNAL(modified()));
189

190
    db->emptyRecycleBin();
191
    // The database must be unmodified in this test after emptying the recycle bin.
192
    QTRY_COMPARE(spyModified.count(), 0);
193
}
194

195
void TestDatabase::testEmptyRecycleBinOnNotCreated()
196
{
197
    QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinNotYetCreated.kdbx");
198
    auto key = QSharedPointer<CompositeKey>::create();
199
    key->addKey(QSharedPointer<PasswordKey>::create("123"));
200
    auto db = QSharedPointer<Database>::create();
201
    QVERIFY(db->open(filename, key, nullptr));
202

203
    QSignalSpy spyModified(db.data(), SIGNAL(modified()));
204

205
    db->emptyRecycleBin();
206
    // The database must be unmodified in this test after emptying the recycle bin.
207
    QTRY_COMPARE(spyModified.count(), 0);
208
}
209

210
void TestDatabase::testEmptyRecycleBinOnEmpty()
211
{
212
    QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinEmpty.kdbx");
213
    auto key = QSharedPointer<CompositeKey>::create();
214
    key->addKey(QSharedPointer<PasswordKey>::create("123"));
215
    auto db = QSharedPointer<Database>::create();
216
    QVERIFY(db->open(filename, key, nullptr));
217

218
    QSignalSpy spyModified(db.data(), SIGNAL(modified()));
219

220
    db->emptyRecycleBin();
221
    // The database must be unmodified in this test after emptying the recycle bin.
222
    QTRY_COMPARE(spyModified.count(), 0);
223
}
224

225
void TestDatabase::testEmptyRecycleBinWithHierarchicalData()
226
{
227
    QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/RecycleBinWithData.kdbx");
228
    auto key = QSharedPointer<CompositeKey>::create();
229
    key->addKey(QSharedPointer<PasswordKey>::create("123"));
230
    auto db = QSharedPointer<Database>::create();
231
    QVERIFY(db->open(filename, key, nullptr));
232

233
    QFile originalFile(filename);
234
    qint64 initialSize = originalFile.size();
235

236
    db->emptyRecycleBin();
237
    QVERIFY(db->metadata()->recycleBin());
238
    QVERIFY(db->metadata()->recycleBin()->entries().empty());
239
    QVERIFY(db->metadata()->recycleBin()->children().empty());
240

241
    QTemporaryFile afterCleanup;
242
    afterCleanup.open();
243

244
    KeePass2Writer writer;
245
    writer.writeDatabase(&afterCleanup, db.data());
246
    QVERIFY(afterCleanup.size() < initialSize);
247
}
248

249
void TestDatabase::testCustomIcons()
250
{
251
    Database db;
252

253
    QUuid uuid1 = QUuid::createUuid();
254
    QByteArray icon1("icon 1");
255
    Q_ASSERT(!icon1.isNull());
256
    db.metadata()->addCustomIcon(uuid1, icon1);
257
    Metadata::CustomIconData iconData = db.metadata()->customIcon(uuid1);
258
    QCOMPARE(iconData.data, icon1);
259
    QVERIFY(iconData.name.isNull());
260
    QVERIFY(iconData.lastModified.isNull());
261

262
    QUuid uuid2 = QUuid::createUuid();
263
    QByteArray icon2("icon 2");
264
    QDateTime date = QDateTime::currentDateTimeUtc();
265
    db.metadata()->addCustomIcon(uuid2, icon2, "Test", date);
266
    iconData = db.metadata()->customIcon(uuid2);
267
    QCOMPARE(iconData.data, icon2);
268
    QCOMPARE(iconData.name, QString("Test"));
269
    QCOMPARE(iconData.lastModified, date);
270
}
271

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.