keepassxc

Форк
0
/
TestEntry.cpp 
770 строк · 35.0 Кб
1
/*
2
 *  Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
3
 *  Copyright (C) 2013 Felix Geyer <debfx@fobos.de>
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 <QTest>
20

21
#include "TestEntry.h"
22
#include "core/Clock.h"
23
#include "core/Group.h"
24
#include "core/Metadata.h"
25
#include "core/TimeInfo.h"
26
#include "crypto/Crypto.h"
27

28
QTEST_GUILESS_MAIN(TestEntry)
29

30
void TestEntry::initTestCase()
31
{
32
    QVERIFY(Crypto::init());
33
}
34

35
void TestEntry::testHistoryItemDeletion()
36
{
37
    QScopedPointer<Entry> entry(new Entry());
38
    QPointer<Entry> historyEntry = new Entry();
39

40
    entry->addHistoryItem(historyEntry);
41
    QCOMPARE(entry->historyItems().size(), 1);
42

43
    QList<Entry*> historyEntriesToRemove;
44
    historyEntriesToRemove.append(historyEntry);
45
    entry->removeHistoryItems(historyEntriesToRemove);
46
    QCOMPARE(entry->historyItems().size(), 0);
47
    QVERIFY(historyEntry.isNull());
48
}
49

50
void TestEntry::testCopyDataFrom()
51
{
52
    QScopedPointer<Entry> entry(new Entry());
53

54
    entry->setTitle("testtitle");
55
    entry->attributes()->set("attr1", "abc");
56
    entry->attributes()->set("attr2", "def");
57

58
    entry->attachments()->set("test", "123");
59
    entry->attachments()->set("test2", "456");
60

61
    AutoTypeAssociations::Association assoc;
62
    assoc.window = "1";
63
    assoc.sequence = "2";
64
    entry->autoTypeAssociations()->add(assoc);
65
    assoc.window = "3";
66
    assoc.sequence = "4";
67
    entry->autoTypeAssociations()->add(assoc);
68

69
    QScopedPointer<Entry> entry2(new Entry());
70
    entry2->copyDataFrom(entry.data());
71

72
    QCOMPARE(entry2->title(), QString("testtitle"));
73
    QCOMPARE(entry2->attributes()->value("attr1"), QString("abc"));
74
    QCOMPARE(entry2->attributes()->value("attr2"), QString("def"));
75

76
    QCOMPARE(entry2->attachments()->keys().size(), 2);
77
    QCOMPARE(entry2->attachments()->value("test"), QByteArray("123"));
78
    QCOMPARE(entry2->attachments()->value("test2"), QByteArray("456"));
79

80
    QCOMPARE(entry2->autoTypeAssociations()->size(), 2);
81
    QCOMPARE(entry2->autoTypeAssociations()->get(0).window, QString("1"));
82
    QCOMPARE(entry2->autoTypeAssociations()->get(1).window, QString("3"));
83
}
84

85
void TestEntry::testClone()
86
{
87
    QScopedPointer<Entry> entryOrg(new Entry());
88
    entryOrg->setUuid(QUuid::createUuid());
89
    entryOrg->setTitle("Original Title");
90
    entryOrg->beginUpdate();
91
    entryOrg->setTitle("New Title");
92
    entryOrg->endUpdate();
93
    TimeInfo entryOrgTime = entryOrg->timeInfo();
94
    QDateTime dateTime = Clock::datetimeUtc(60);
95
    entryOrgTime.setCreationTime(dateTime);
96
    entryOrg->setTimeInfo(entryOrgTime);
97

98
    QScopedPointer<Entry> entryCloneNone(entryOrg->clone(Entry::CloneNoFlags));
99
    QCOMPARE(entryCloneNone->uuid(), entryOrg->uuid());
100
    QCOMPARE(entryCloneNone->title(), QString("New Title"));
101
    QCOMPARE(entryCloneNone->historyItems().size(), 0);
102
    QCOMPARE(entryCloneNone->timeInfo().creationTime(), entryOrg->timeInfo().creationTime());
103

104
    QScopedPointer<Entry> entryCloneNewUuid(entryOrg->clone(Entry::CloneNewUuid));
105
    QVERIFY(entryCloneNewUuid->uuid() != entryOrg->uuid());
106
    QVERIFY(!entryCloneNewUuid->uuid().isNull());
107
    QCOMPARE(entryCloneNewUuid->title(), QString("New Title"));
108
    QCOMPARE(entryCloneNewUuid->historyItems().size(), 0);
109
    QCOMPARE(entryCloneNewUuid->timeInfo().creationTime(), entryOrg->timeInfo().creationTime());
110

111
    // Reset modification time
112
    entryOrgTime.setLastModificationTime(Clock::datetimeUtc(60));
113
    entryOrg->setTimeInfo(entryOrgTime);
114

115
    QScopedPointer<Entry> entryCloneRename(entryOrg->clone(Entry::CloneRenameTitle));
116
    QCOMPARE(entryCloneRename->uuid(), entryOrg->uuid());
117
    QCOMPARE(entryCloneRename->title(), QString("New Title - Clone"));
118
    // Cloning should not modify time info unless explicitly requested
119
    QCOMPARE(entryCloneRename->timeInfo(), entryOrg->timeInfo());
120

121
    QScopedPointer<Entry> entryCloneResetTime(entryOrg->clone(Entry::CloneResetTimeInfo));
122
    QCOMPARE(entryCloneResetTime->uuid(), entryOrg->uuid());
123
    QCOMPARE(entryCloneResetTime->title(), QString("New Title"));
124
    QCOMPARE(entryCloneResetTime->historyItems().size(), 0);
125
    QVERIFY(entryCloneResetTime->timeInfo().creationTime() != entryOrg->timeInfo().creationTime());
126

127
    // Date back history of original entry
128
    Entry* firstHistoryItem = entryOrg->historyItems()[0];
129
    TimeInfo entryOrgHistoryTimeInfo = firstHistoryItem->timeInfo();
130
    QDateTime datedBackEntryOrgModificationTime = entryOrgHistoryTimeInfo.lastModificationTime().addMSecs(-10);
131
    entryOrgHistoryTimeInfo.setLastModificationTime(datedBackEntryOrgModificationTime);
132
    entryOrgHistoryTimeInfo.setCreationTime(datedBackEntryOrgModificationTime);
133
    firstHistoryItem->setTimeInfo(entryOrgHistoryTimeInfo);
134

135
    QScopedPointer<Entry> entryCloneHistory(entryOrg->clone(Entry::CloneIncludeHistory | Entry::CloneResetTimeInfo));
136
    QCOMPARE(entryCloneHistory->uuid(), entryOrg->uuid());
137
    QCOMPARE(entryCloneHistory->title(), QString("New Title"));
138
    QCOMPARE(entryCloneHistory->historyItems().size(), entryOrg->historyItems().size());
139
    QCOMPARE(entryCloneHistory->historyItems().at(0)->title(), QString("Original Title"));
140
    QVERIFY(entryCloneHistory->timeInfo().creationTime() != entryOrg->timeInfo().creationTime());
141
    // Timeinfo of history items should not be modified
142
    QList<Entry*> entryOrgHistory = entryOrg->historyItems(), clonedHistory = entryCloneHistory->historyItems();
143
    auto entryOrgHistoryItem = entryOrgHistory.constBegin();
144
    for (auto entryCloneHistoryItem = clonedHistory.constBegin(); entryCloneHistoryItem != clonedHistory.constEnd();
145
         ++entryCloneHistoryItem, ++entryOrgHistoryItem) {
146
        QCOMPARE((*entryOrgHistoryItem)->timeInfo(), (*entryCloneHistoryItem)->timeInfo());
147
    }
148

149
    Database db;
150
    auto* entryOrgClone = entryOrg->clone(Entry::CloneNoFlags);
151
    entryOrgClone->setGroup(db.rootGroup());
152

153
    Entry* entryCloneUserRef = entryOrgClone->clone(Entry::CloneUserAsRef);
154
    entryCloneUserRef->setGroup(db.rootGroup());
155
    QCOMPARE(entryCloneUserRef->uuid(), entryOrgClone->uuid());
156
    QCOMPARE(entryCloneUserRef->title(), QString("New Title"));
157
    QCOMPARE(entryCloneUserRef->historyItems().size(), 0);
158
    QCOMPARE(entryCloneUserRef->timeInfo().creationTime(), entryOrgClone->timeInfo().creationTime());
159
    QVERIFY(entryCloneUserRef->attributes()->isReference(EntryAttributes::UserNameKey));
160
    QCOMPARE(entryCloneUserRef->resolvePlaceholder(entryCloneUserRef->username()), entryOrgClone->username());
161

162
    Entry* entryClonePassRef = entryOrgClone->clone(Entry::ClonePassAsRef);
163
    entryClonePassRef->setGroup(db.rootGroup());
164
    QCOMPARE(entryClonePassRef->uuid(), entryOrgClone->uuid());
165
    QCOMPARE(entryClonePassRef->title(), QString("New Title"));
166
    QCOMPARE(entryClonePassRef->historyItems().size(), 0);
167
    QCOMPARE(entryClonePassRef->timeInfo().creationTime(), entryOrgClone->timeInfo().creationTime());
168
    QVERIFY(entryClonePassRef->attributes()->isReference(EntryAttributes::PasswordKey));
169
    QCOMPARE(entryClonePassRef->resolvePlaceholder(entryCloneUserRef->password()), entryOrg->password());
170
    QCOMPARE(entryClonePassRef->attributes()->referenceUuid(EntryAttributes::PasswordKey), entryOrgClone->uuid());
171
}
172

173
void TestEntry::testResolveUrl()
174
{
175
    QScopedPointer<Entry> entry(new Entry());
176
    QString testUrl("www.google.com");
177
    QString testCmd("cmd://firefox " + testUrl);
178
    QString testFileUnix("/home/example/test.txt");
179
    QString testFileWindows("c:/WINDOWS/test.txt");
180
    QString testComplexCmd("cmd://firefox --start-now --url 'http://" + testUrl + "' --quit");
181
    QString nonHttpUrl("ftp://google.com");
182
    QString noUrl("random text inserted here");
183

184
    // Test standard URL's
185
    QCOMPARE(entry->resolveUrl(""), QString(""));
186
    QCOMPARE(entry->resolveUrl(testUrl), "https://" + testUrl);
187
    QCOMPARE(entry->resolveUrl("http://" + testUrl), "http://" + testUrl);
188
    // Test file:// URL's
189
    QCOMPARE(entry->resolveUrl("file://" + testFileUnix), "file://" + testFileUnix);
190
    QCOMPARE(entry->resolveUrl(testFileUnix), "file://" + testFileUnix);
191
    QCOMPARE(entry->resolveUrl("file:///" + testFileWindows), "file:///" + testFileWindows);
192
    QCOMPARE(entry->resolveUrl(testFileWindows), "file:///" + testFileWindows);
193
    // Test cmd:// with no URL
194
    QCOMPARE(entry->resolveUrl("cmd://firefox"), QString(""));
195
    QCOMPARE(entry->resolveUrl("cmd://firefox --no-url"), QString(""));
196
    // Test cmd:// with URL's
197
    QCOMPARE(entry->resolveUrl(testCmd), "https://" + testUrl);
198
    QCOMPARE(entry->resolveUrl(testComplexCmd), "http://" + testUrl);
199
    // Test non-http URL
200
    QCOMPARE(entry->resolveUrl(nonHttpUrl), QString(""));
201
    // Test no URL
202
    QCOMPARE(entry->resolveUrl(noUrl), QString(""));
203
}
204

205
void TestEntry::testResolveUrlPlaceholders()
206
{
207
    Entry entry;
208
    entry.setUrl("https://user:pw@keepassxc.org:80/path/example.php?q=e&s=t+2#fragment");
209

210
    QString rmvscm("//user:pw@keepassxc.org:80/path/example.php?q=e&s=t+2#fragment"); // Entry URL without scheme name.
211
    QString scm("https"); // Scheme name of the entry URL.
212
    QString host("keepassxc.org"); // Host component of the entry URL.
213
    QString port("80"); // Port number of the entry URL.
214
    QString path("/path/example.php"); // Path component of the entry URL.
215
    QString query("q=e&s=t+2"); // Query information of the entry URL.
216
    QString userinfo("user:pw"); // User information of the entry URL.
217
    QString username("user"); // User name of the entry URL.
218
    QString password("pw"); // Password of the entry URL.
219
    QString fragment("fragment"); // Fragment of the entry URL.
220

221
    QCOMPARE(entry.resolvePlaceholder("{URL:RMVSCM}"), rmvscm);
222
    QCOMPARE(entry.resolvePlaceholder("{URL:WITHOUTSCHEME}"), rmvscm);
223
    QCOMPARE(entry.resolvePlaceholder("{URL:SCM}"), scm);
224
    QCOMPARE(entry.resolvePlaceholder("{URL:SCHEME}"), scm);
225
    QCOMPARE(entry.resolvePlaceholder("{URL:HOST}"), host);
226
    QCOMPARE(entry.resolvePlaceholder("{URL:PORT}"), port);
227
    QCOMPARE(entry.resolvePlaceholder("{URL:PATH}"), path);
228
    QCOMPARE(entry.resolvePlaceholder("{URL:QUERY}"), query);
229
    QCOMPARE(entry.resolvePlaceholder("{URL:USERINFO}"), userinfo);
230
    QCOMPARE(entry.resolvePlaceholder("{URL:USERNAME}"), username);
231
    QCOMPARE(entry.resolvePlaceholder("{URL:PASSWORD}"), password);
232
    QCOMPARE(entry.resolvePlaceholder("{URL:FRAGMENT}"), fragment);
233
}
234

235
void TestEntry::testResolveRecursivePlaceholders()
236
{
237
    Database db;
238
    auto* root = db.rootGroup();
239

240
    auto* entry1 = new Entry();
241
    entry1->setGroup(root);
242
    entry1->setUuid(QUuid::createUuid());
243
    entry1->setTitle("{USERNAME}");
244
    entry1->setUsername("{PASSWORD}");
245
    entry1->setPassword("{URL}");
246
    entry1->setUrl("{S:CustomTitle}");
247
    entry1->attributes()->set("CustomTitle", "RecursiveValue");
248
    QCOMPARE(entry1->resolveMultiplePlaceholders(entry1->title()), QString("RecursiveValue"));
249

250
    auto* entry2 = new Entry();
251
    entry2->setGroup(root);
252
    entry2->setUuid(QUuid::createUuid());
253
    entry2->setTitle("Entry2Title");
254
    entry2->setUsername("{S:CustomUserNameAttribute}");
255
    entry2->setPassword(QString("{REF:P@I:%1}").arg(entry1->uuidToHex()));
256
    entry2->setUrl("http://{S:IpAddress}:{S:Port}/{S:Uri}");
257
    entry2->attributes()->set("CustomUserNameAttribute", "CustomUserNameValue");
258
    entry2->attributes()->set("IpAddress", "127.0.0.1");
259
    entry2->attributes()->set("Port", "1234");
260
    entry2->attributes()->set("Uri", "uri/path");
261

262
    auto* entry3 = new Entry();
263
    entry3->setGroup(root);
264
    entry3->setUuid(QUuid::createUuid());
265
    entry3->setTitle(QString("{REF:T@I:%1}").arg(entry2->uuidToHex()));
266
    entry3->setUsername(QString("{REF:U@I:%1}").arg(entry2->uuidToHex()));
267
    entry3->setPassword(QString("{REF:P@I:%1}").arg(entry2->uuidToHex()));
268
    entry3->setUrl(QString("{REF:A@I:%1}").arg(entry2->uuidToHex()));
269

270
    QCOMPARE(entry3->resolveMultiplePlaceholders(entry3->title()), QString("Entry2Title"));
271
    QCOMPARE(entry3->resolveMultiplePlaceholders(entry3->username()), QString("CustomUserNameValue"));
272
    QCOMPARE(entry3->resolveMultiplePlaceholders(entry3->password()), QString("RecursiveValue"));
273
    QCOMPARE(entry3->resolveMultiplePlaceholders(entry3->url()), QString("http://127.0.0.1:1234/uri/path"));
274

275
    auto* entry4 = new Entry();
276
    entry4->setGroup(root);
277
    entry4->setUuid(QUuid::createUuid());
278
    entry4->setTitle(QString("{REF:T@I:%1}").arg(entry3->uuidToHex()));
279
    entry4->setUsername(QString("{REF:U@I:%1}").arg(entry3->uuidToHex()));
280
    entry4->setPassword(QString("{REF:P@I:%1}").arg(entry3->uuidToHex()));
281
    entry4->setUrl(QString("{REF:A@I:%1}").arg(entry3->uuidToHex()));
282

283
    QCOMPARE(entry4->resolveMultiplePlaceholders(entry4->title()), QString("Entry2Title"));
284
    QCOMPARE(entry4->resolveMultiplePlaceholders(entry4->username()), QString("CustomUserNameValue"));
285
    QCOMPARE(entry4->resolveMultiplePlaceholders(entry4->password()), QString("RecursiveValue"));
286
    QCOMPARE(entry4->resolveMultiplePlaceholders(entry4->url()), QString("http://127.0.0.1:1234/uri/path"));
287

288
    auto* entry5 = new Entry();
289
    entry5->setGroup(root);
290
    entry5->setUuid(QUuid::createUuid());
291
    entry5->attributes()->set("Scheme", "http");
292
    entry5->attributes()->set("Host", "host.org");
293
    entry5->attributes()->set("Port", "2017");
294
    entry5->attributes()->set("Path", "/some/path");
295
    entry5->attributes()->set("UserName", "username");
296
    entry5->attributes()->set("Password", "password");
297
    entry5->attributes()->set("Query", "q=e&t=s");
298
    entry5->attributes()->set("Fragment", "fragment");
299
    entry5->setUrl("{S:Scheme}://{S:UserName}:{S:Password}@{S:Host}:{S:Port}{S:Path}?{S:Query}#{S:Fragment}");
300
    entry5->setTitle("title+{URL:Path}+{URL:Fragment}+title");
301

302
    const QString url("http://username:password@host.org:2017/some/path?q=e&t=s#fragment");
303
    QCOMPARE(entry5->resolveMultiplePlaceholders(entry5->url()), url);
304
    QCOMPARE(entry5->resolveMultiplePlaceholders(entry5->title()), QString("title+/some/path+fragment+title"));
305

306
    auto* entry6 = new Entry();
307
    entry6->setGroup(root);
308
    entry6->setUuid(QUuid::createUuid());
309
    entry6->setTitle(QString("{REF:T@I:%1}").arg(entry3->uuidToHex()));
310
    entry6->setUsername(QString("{TITLE}"));
311
    entry6->setPassword(QString("{PASSWORD}"));
312

313
    QCOMPARE(entry6->resolvePlaceholder(entry6->title()), QString("Entry2Title"));
314
    QCOMPARE(entry6->resolvePlaceholder(entry6->username()), QString("Entry2Title"));
315
    QCOMPARE(entry6->resolvePlaceholder(entry6->password()), QString("{PASSWORD}"));
316

317
    auto* entry7 = new Entry();
318
    entry7->setGroup(root);
319
    entry7->setUuid(QUuid::createUuid());
320
    entry7->setTitle(QString("{REF:T@I:%1} and something else").arg(entry3->uuidToHex()));
321
    entry7->setUsername(QString("{TITLE}"));
322
    entry7->setPassword(QString("PASSWORD"));
323

324
    QCOMPARE(entry7->resolvePlaceholder(entry7->title()), QString("Entry2Title and something else"));
325
    QCOMPARE(entry7->resolvePlaceholder(entry7->username()), QString("Entry2Title and something else"));
326
    QCOMPARE(entry7->resolvePlaceholder(entry7->password()), QString("PASSWORD"));
327
}
328

329
void TestEntry::testResolveReferencePlaceholders()
330
{
331
    Database db;
332
    auto* root = db.rootGroup();
333

334
    auto* entry1 = new Entry();
335
    entry1->setGroup(root);
336
    entry1->setUuid(QUuid::createUuid());
337
    entry1->setTitle("Title1");
338
    entry1->setUsername("Username1");
339
    entry1->setPassword("Password1");
340
    entry1->setUrl("Url1");
341
    entry1->setNotes("Notes1");
342
    entry1->attributes()->set("CustomAttribute1", "CustomAttributeValue1");
343

344
    auto* group = new Group();
345
    group->setParent(root);
346
    auto* entry2 = new Entry();
347
    entry2->setGroup(group);
348
    entry2->setUuid(QUuid::createUuid());
349
    entry2->setTitle("Title2");
350
    entry2->setUsername("Username2");
351
    entry2->setPassword("Password2");
352
    entry2->setUrl("Url2");
353
    entry2->setNotes("Notes2");
354
    entry2->attributes()->set("CustomAttribute2", "CustomAttributeValue2");
355

356
    auto* entry3 = new Entry();
357
    entry3->setGroup(group);
358
    entry3->setUuid(QUuid::createUuid());
359
    entry3->setTitle("{S:AttributeTitle}");
360
    entry3->setUsername("{S:AttributeUsername}");
361
    entry3->setPassword("{S:AttributePassword}");
362
    entry3->setUrl("{S:AttributeUrl}");
363
    entry3->setNotes("{S:AttributeNotes}");
364
    entry3->attributes()->set("AttributeTitle", "TitleValue");
365
    entry3->attributes()->set("AttributeUsername", "UsernameValue");
366
    entry3->attributes()->set("AttributePassword", "PasswordValue");
367
    entry3->attributes()->set("AttributeUrl", "UrlValue");
368
    entry3->attributes()->set("AttributeNotes", "NotesValue");
369

370
    auto* tstEntry = new Entry();
371
    tstEntry->setGroup(root);
372
    tstEntry->setUuid(QUuid::createUuid());
373

374
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())), entry1->title());
375
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title());
376
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), entry1->title());
377
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry1->password())), entry1->title());
378
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry1->url())), entry1->title());
379
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry1->notes())), entry1->title());
380
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(
381
                 QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))),
382
             entry1->title());
383

384
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())), entry1->title());
385
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title());
386
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())),
387
             entry1->username());
388
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry1->password())),
389
             entry1->password());
390
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), entry1->url());
391
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), entry1->notes());
392

393
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuidToHex())), entry2->title());
394
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), entry2->title());
395
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry2->username())), entry2->title());
396
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@P:%1}").arg(entry2->password())), entry2->title());
397
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@A:%1}").arg(entry2->url())), entry2->title());
398
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@N:%1}").arg(entry2->notes())), entry2->title());
399
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(
400
                 QString("{REF:T@O:%1}").arg(entry2->attributes()->value("CustomAttribute2"))),
401
             entry2->title());
402

403
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), entry2->title());
404
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry2->username())),
405
             entry2->username());
406
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@P:%1}").arg(entry2->password())),
407
             entry2->password());
408
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry2->url())), entry2->url());
409
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry2->notes())), entry2->notes());
410

411
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex())),
412
             entry3->attributes()->value("AttributeTitle"));
413
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex())),
414
             entry3->attributes()->value("AttributeUsername"));
415
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex())),
416
             entry3->attributes()->value("AttributePassword"));
417
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex())),
418
             entry3->attributes()->value("AttributeUrl"));
419
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex())),
420
             entry3->attributes()->value("AttributeNotes"));
421

422
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex().toUpper())),
423
             entry3->attributes()->value("AttributeTitle"));
424
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex().toUpper())),
425
             entry3->attributes()->value("AttributeUsername"));
426
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex().toUpper())),
427
             entry3->attributes()->value("AttributePassword"));
428
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex().toUpper())),
429
             entry3->attributes()->value("AttributeUrl"));
430
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex().toUpper())),
431
             entry3->attributes()->value("AttributeNotes"));
432

433
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:t@i:%1}").arg(entry3->uuidToHex().toLower())),
434
             entry3->attributes()->value("AttributeTitle"));
435
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:u@i:%1}").arg(entry3->uuidToHex().toLower())),
436
             entry3->attributes()->value("AttributeUsername"));
437
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:p@i:%1}").arg(entry3->uuidToHex().toLower())),
438
             entry3->attributes()->value("AttributePassword"));
439
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:a@i:%1}").arg(entry3->uuidToHex().toLower())),
440
             entry3->attributes()->value("AttributeUrl"));
441
    QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:n@i:%1}").arg(entry3->uuidToHex().toLower())),
442
             entry3->attributes()->value("AttributeNotes"));
443
}
444

445
void TestEntry::testResolveNonIdPlaceholdersToUuid()
446
{
447
    Database db;
448
    auto* root = db.rootGroup();
449

450
    auto* referencedEntryTitle = new Entry();
451
    referencedEntryTitle->setGroup(root);
452
    referencedEntryTitle->setTitle("myTitle");
453
    referencedEntryTitle->setUuid(QUuid::createUuid());
454

455
    auto* referencedEntryUsername = new Entry();
456
    referencedEntryUsername->setGroup(root);
457
    referencedEntryUsername->setUsername("myUser");
458
    referencedEntryUsername->setUuid(QUuid::createUuid());
459

460
    auto* referencedEntryPassword = new Entry();
461
    referencedEntryPassword->setGroup(root);
462
    referencedEntryPassword->setPassword("myPassword");
463
    referencedEntryPassword->setUuid(QUuid::createUuid());
464

465
    auto* referencedEntryUrl = new Entry();
466
    referencedEntryUrl->setGroup(root);
467
    referencedEntryUrl->setUrl("myUrl");
468
    referencedEntryUrl->setUuid(QUuid::createUuid());
469

470
    auto* referencedEntryNotes = new Entry();
471
    referencedEntryNotes->setGroup(root);
472
    referencedEntryNotes->setNotes("myNotes");
473
    referencedEntryNotes->setUuid(QUuid::createUuid());
474

475
    const QList<QChar> placeholders{'T', 'U', 'P', 'A', 'N'};
476
    for (const QChar& searchIn : placeholders) {
477
        const Entry* referencedEntry = nullptr;
478
        QString newEntryNotesRaw("{REF:I@%1:%2}");
479

480
        switch (searchIn.toLatin1()) {
481
        case 'T':
482
            referencedEntry = referencedEntryTitle;
483
            newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->title());
484
            break;
485
        case 'U':
486
            referencedEntry = referencedEntryUsername;
487
            newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->username());
488
            break;
489
        case 'P':
490
            referencedEntry = referencedEntryPassword;
491
            newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->password());
492
            break;
493
        case 'A':
494
            referencedEntry = referencedEntryUrl;
495
            newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->url());
496
            break;
497
        case 'N':
498
            referencedEntry = referencedEntryNotes;
499
            newEntryNotesRaw = newEntryNotesRaw.arg(searchIn, referencedEntry->notes());
500
            break;
501
        default:
502
            break;
503
        }
504

505
        auto* newEntry = new Entry();
506
        newEntry->setGroup(root);
507
        newEntry->setNotes(newEntryNotesRaw);
508

509
        const QString newEntryNotesResolved = newEntry->resolveMultiplePlaceholders(newEntry->notes());
510
        QCOMPARE(newEntryNotesResolved, referencedEntry->uuidToHex());
511
    }
512
}
513

514
void TestEntry::testResolveClonedEntry()
515
{
516
    Database db;
517
    auto* root = db.rootGroup();
518

519
    auto* original = new Entry();
520
    original->setGroup(root);
521
    original->setUuid(QUuid::createUuid());
522
    original->setTitle("Title");
523
    original->setUsername("SomeUsername");
524
    original->setPassword("SomePassword");
525

526
    QCOMPARE(original->resolveMultiplePlaceholders(original->username()), original->username());
527
    QCOMPARE(original->resolveMultiplePlaceholders(original->password()), original->password());
528

529
    // Top-level clones.
530
    Entry* clone1 = original->clone(Entry::CloneNewUuid);
531
    clone1->setGroup(root);
532
    Entry* clone2 = original->clone(Entry::CloneUserAsRef | Entry::CloneNewUuid);
533
    clone2->setGroup(root);
534
    Entry* clone3 = original->clone(Entry::ClonePassAsRef | Entry::CloneNewUuid);
535
    clone3->setGroup(root);
536
    Entry* clone4 = original->clone(Entry::CloneUserAsRef | Entry::ClonePassAsRef | Entry::CloneNewUuid);
537
    clone4->setGroup(root);
538

539
    QCOMPARE(clone1->resolveMultiplePlaceholders(clone1->username()), original->username());
540
    QCOMPARE(clone1->resolveMultiplePlaceholders(clone1->password()), original->password());
541
    QCOMPARE(clone2->resolveMultiplePlaceholders(clone2->username()), original->username());
542
    QCOMPARE(clone2->resolveMultiplePlaceholders(clone2->password()), original->password());
543
    QCOMPARE(clone3->resolveMultiplePlaceholders(clone3->username()), original->username());
544
    QCOMPARE(clone3->resolveMultiplePlaceholders(clone3->password()), original->password());
545
    QCOMPARE(clone4->resolveMultiplePlaceholders(clone4->username()), original->username());
546
    QCOMPARE(clone4->resolveMultiplePlaceholders(clone4->password()), original->password());
547

548
    // Second-level clones.
549
    Entry* cclone1 = clone4->clone(Entry::CloneNewUuid);
550
    cclone1->setGroup(root);
551
    Entry* cclone2 = clone4->clone(Entry::CloneUserAsRef | Entry::CloneNewUuid);
552
    cclone2->setGroup(root);
553
    Entry* cclone3 = clone4->clone(Entry::ClonePassAsRef | Entry::CloneNewUuid);
554
    cclone3->setGroup(root);
555
    Entry* cclone4 = clone4->clone(Entry::CloneUserAsRef | Entry::ClonePassAsRef | Entry::CloneNewUuid);
556
    cclone4->setGroup(root);
557

558
    QCOMPARE(cclone1->resolveMultiplePlaceholders(cclone1->username()), original->username());
559
    QCOMPARE(cclone1->resolveMultiplePlaceholders(cclone1->password()), original->password());
560
    QCOMPARE(cclone2->resolveMultiplePlaceholders(cclone2->username()), original->username());
561
    QCOMPARE(cclone2->resolveMultiplePlaceholders(cclone2->password()), original->password());
562
    QCOMPARE(cclone3->resolveMultiplePlaceholders(cclone3->username()), original->username());
563
    QCOMPARE(cclone3->resolveMultiplePlaceholders(cclone3->password()), original->password());
564
    QCOMPARE(cclone4->resolveMultiplePlaceholders(cclone4->username()), original->username());
565
    QCOMPARE(cclone4->resolveMultiplePlaceholders(cclone4->password()), original->password());
566

567
    // Change the original's attributes and make sure that the changes are tracked.
568
    QString oldUsername = original->username();
569
    QString oldPassword = original->password();
570
    original->setUsername("DifferentUsername");
571
    original->setPassword("DifferentPassword");
572

573
    QCOMPARE(clone1->resolveMultiplePlaceholders(clone1->username()), oldUsername);
574
    QCOMPARE(clone1->resolveMultiplePlaceholders(clone1->password()), oldPassword);
575
    QCOMPARE(clone2->resolveMultiplePlaceholders(clone2->username()), original->username());
576
    QCOMPARE(clone2->resolveMultiplePlaceholders(clone2->password()), oldPassword);
577
    QCOMPARE(clone3->resolveMultiplePlaceholders(clone3->username()), oldUsername);
578
    QCOMPARE(clone3->resolveMultiplePlaceholders(clone3->password()), original->password());
579
    QCOMPARE(clone4->resolveMultiplePlaceholders(clone4->username()), original->username());
580
    QCOMPARE(clone4->resolveMultiplePlaceholders(clone4->password()), original->password());
581

582
    QCOMPARE(cclone1->resolveMultiplePlaceholders(cclone1->username()), original->username());
583
    QCOMPARE(cclone1->resolveMultiplePlaceholders(cclone1->password()), original->password());
584
    QCOMPARE(cclone2->resolveMultiplePlaceholders(cclone2->username()), original->username());
585
    QCOMPARE(cclone2->resolveMultiplePlaceholders(cclone2->password()), original->password());
586
    QCOMPARE(cclone3->resolveMultiplePlaceholders(cclone3->username()), original->username());
587
    QCOMPARE(cclone3->resolveMultiplePlaceholders(cclone3->password()), original->password());
588
    QCOMPARE(cclone4->resolveMultiplePlaceholders(cclone4->username()), original->username());
589
    QCOMPARE(cclone4->resolveMultiplePlaceholders(cclone4->password()), original->password());
590
}
591

592
void TestEntry::testIsRecycled()
593
{
594
    auto entry = new Entry();
595
    QVERIFY(!entry->isRecycled());
596

597
    Database db;
598
    Group* root = db.rootGroup();
599
    QVERIFY(root);
600
    entry->setGroup(root);
601
    QVERIFY(!entry->isRecycled());
602

603
    QVERIFY(db.metadata()->recycleBinEnabled());
604
    db.recycleEntry(entry);
605
    QVERIFY(entry->isRecycled());
606

607
    auto group1 = new Group();
608
    group1->setParent(root);
609

610
    auto entry1 = new Entry();
611
    entry1->setGroup(group1);
612
    QVERIFY(!entry1->isRecycled());
613
    db.recycleGroup(group1);
614
    QVERIFY(entry1->isRecycled());
615
}
616

617
void TestEntry::testMoveUpDown()
618
{
619
    Database db;
620
    Group* root = db.rootGroup();
621
    QVERIFY(root);
622

623
    auto entry0 = new Entry();
624
    QVERIFY(entry0);
625
    entry0->setGroup(root);
626
    auto entry1 = new Entry();
627
    QVERIFY(entry1);
628
    entry1->setGroup(root);
629
    auto entry2 = new Entry();
630
    QVERIFY(entry2);
631
    entry2->setGroup(root);
632
    auto entry3 = new Entry();
633
    QVERIFY(entry3);
634
    entry3->setGroup(root);
635
    // default order, straight
636
    QCOMPARE(root->entries().at(0), entry0);
637
    QCOMPARE(root->entries().at(1), entry1);
638
    QCOMPARE(root->entries().at(2), entry2);
639
    QCOMPARE(root->entries().at(3), entry3);
640

641
    entry0->moveDown();
642
    QCOMPARE(root->entries().at(0), entry1);
643
    QCOMPARE(root->entries().at(1), entry0);
644
    QCOMPARE(root->entries().at(2), entry2);
645
    QCOMPARE(root->entries().at(3), entry3);
646

647
    entry0->moveDown();
648
    QCOMPARE(root->entries().at(0), entry1);
649
    QCOMPARE(root->entries().at(1), entry2);
650
    QCOMPARE(root->entries().at(2), entry0);
651
    QCOMPARE(root->entries().at(3), entry3);
652

653
    entry0->moveDown();
654
    QCOMPARE(root->entries().at(0), entry1);
655
    QCOMPARE(root->entries().at(1), entry2);
656
    QCOMPARE(root->entries().at(2), entry3);
657
    QCOMPARE(root->entries().at(3), entry0);
658

659
    // no effect
660
    entry0->moveDown();
661
    QCOMPARE(root->entries().at(0), entry1);
662
    QCOMPARE(root->entries().at(1), entry2);
663
    QCOMPARE(root->entries().at(2), entry3);
664
    QCOMPARE(root->entries().at(3), entry0);
665

666
    entry0->moveUp();
667
    QCOMPARE(root->entries().at(0), entry1);
668
    QCOMPARE(root->entries().at(1), entry2);
669
    QCOMPARE(root->entries().at(2), entry0);
670
    QCOMPARE(root->entries().at(3), entry3);
671

672
    entry0->moveUp();
673
    QCOMPARE(root->entries().at(0), entry1);
674
    QCOMPARE(root->entries().at(1), entry0);
675
    QCOMPARE(root->entries().at(2), entry2);
676
    QCOMPARE(root->entries().at(3), entry3);
677

678
    entry0->moveUp();
679
    QCOMPARE(root->entries().at(0), entry0);
680
    QCOMPARE(root->entries().at(1), entry1);
681
    QCOMPARE(root->entries().at(2), entry2);
682
    QCOMPARE(root->entries().at(3), entry3);
683

684
    // no effect
685
    entry0->moveUp();
686
    QCOMPARE(root->entries().at(0), entry0);
687
    QCOMPARE(root->entries().at(1), entry1);
688
    QCOMPARE(root->entries().at(2), entry2);
689
    QCOMPARE(root->entries().at(3), entry3);
690

691
    entry2->moveUp();
692
    QCOMPARE(root->entries().at(0), entry0);
693
    QCOMPARE(root->entries().at(1), entry2);
694
    QCOMPARE(root->entries().at(2), entry1);
695
    QCOMPARE(root->entries().at(3), entry3);
696

697
    entry0->moveDown();
698
    QCOMPARE(root->entries().at(0), entry2);
699
    QCOMPARE(root->entries().at(1), entry0);
700
    QCOMPARE(root->entries().at(2), entry1);
701
    QCOMPARE(root->entries().at(3), entry3);
702

703
    entry3->moveUp();
704
    QCOMPARE(root->entries().at(0), entry2);
705
    QCOMPARE(root->entries().at(1), entry0);
706
    QCOMPARE(root->entries().at(2), entry3);
707
    QCOMPARE(root->entries().at(3), entry1);
708

709
    entry3->moveUp();
710
    QCOMPARE(root->entries().at(0), entry2);
711
    QCOMPARE(root->entries().at(1), entry3);
712
    QCOMPARE(root->entries().at(2), entry0);
713
    QCOMPARE(root->entries().at(3), entry1);
714

715
    entry2->moveDown();
716
    QCOMPARE(root->entries().at(0), entry3);
717
    QCOMPARE(root->entries().at(1), entry2);
718
    QCOMPARE(root->entries().at(2), entry0);
719
    QCOMPARE(root->entries().at(3), entry1);
720

721
    entry1->moveUp();
722
    QCOMPARE(root->entries().at(0), entry3);
723
    QCOMPARE(root->entries().at(1), entry2);
724
    QCOMPARE(root->entries().at(2), entry1);
725
    QCOMPARE(root->entries().at(3), entry0);
726
}
727

728
void TestEntry::testPreviousParentGroup()
729
{
730
    Database db;
731
    auto* root = db.rootGroup();
732
    root->setUuid(QUuid::createUuid());
733
    QVERIFY(!root->uuid().isNull());
734

735
    auto* group1 = new Group();
736
    group1->setUuid(QUuid::createUuid());
737
    group1->setParent(root);
738
    QVERIFY(!group1->uuid().isNull());
739

740
    auto* group2 = new Group();
741
    group2->setParent(root);
742
    group2->setUuid(QUuid::createUuid());
743
    QVERIFY(!group2->uuid().isNull());
744

745
    auto* entry = new Entry();
746
    QVERIFY(entry);
747
    QVERIFY(entry->previousParentGroupUuid().isNull());
748
    QVERIFY(!entry->previousParentGroup());
749

750
    entry->setGroup(root);
751
    QVERIFY(entry->previousParentGroupUuid().isNull());
752
    QVERIFY(!entry->previousParentGroup());
753

754
    // Previous parent shouldn't be recorded if new and old parent are the same
755
    entry->setGroup(root);
756
    QVERIFY(entry->previousParentGroupUuid().isNull());
757
    QVERIFY(!entry->previousParentGroup());
758

759
    entry->setGroup(group1);
760
    QVERIFY(entry->previousParentGroupUuid() == root->uuid());
761
    QVERIFY(entry->previousParentGroup() == root);
762

763
    entry->setGroup(group2);
764
    QVERIFY(entry->previousParentGroupUuid() == group1->uuid());
765
    QVERIFY(entry->previousParentGroup() == group1);
766

767
    entry->setGroup(group2);
768
    QVERIFY(entry->previousParentGroupUuid() == group1->uuid());
769
    QVERIFY(entry->previousParentGroup() == group1);
770
}
771

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

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

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

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