mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-04-03 20:47:37 +03:00
Introduce synchronize merge method
* Create history-based merging that keeps older data in history instead of discarding or deleting it * Extract merge logic into the Merger class * Allows special merge behavior * Improve handling of deletion and changes on groups * Enable basic change tracking while merging * Prevent unintended timestamp changes while merging * Handle differences in timestamp precision * Introduce comparison operators to allow for more sophisticated comparisons (ignore special properties, ...) * Introduce Clock class to handle datetime across the app Merge Strategies: * Default (use inherited/fallback method) * Duplicate (duplicate conflicting nodes, apply all deletions) * KeepLocal (use local values, but apply all deletions) * KeepRemote (use remote values, but apply all deletions) * KeepNewer (merge history only) * Synchronize (merge history, newest value stays on top, apply all deletions)
This commit is contained in:
parent
b40e5686dc
commit
c1e9f45df9
43 changed files with 2777 additions and 585 deletions
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "TestEntry.h"
|
||||
#include "TestGlobal.h"
|
||||
#include "core/Clock.h"
|
||||
#include "crypto/Crypto.h"
|
||||
|
||||
QTEST_GUILESS_MAIN(TestEntry)
|
||||
|
@ -88,9 +89,7 @@ void TestEntry::testClone()
|
|||
entryOrg->setTitle("New Title");
|
||||
entryOrg->endUpdate();
|
||||
TimeInfo entryOrgTime = entryOrg->timeInfo();
|
||||
QDateTime dateTime;
|
||||
dateTime.setTimeSpec(Qt::UTC);
|
||||
dateTime.setTime_t(60);
|
||||
QDateTime dateTime = Clock::datetimeUtc(60);
|
||||
entryOrgTime.setCreationTime(dateTime);
|
||||
entryOrg->setTimeInfo(entryOrgTime);
|
||||
|
||||
|
@ -225,7 +224,7 @@ void TestEntry::testResolveRecursivePlaceholders()
|
|||
entry2->setUuid(QUuid::createUuid());
|
||||
entry2->setTitle("Entry2Title");
|
||||
entry2->setUsername("{S:CustomUserNameAttribute}");
|
||||
entry2->setPassword(QString("{REF:P@I:%1}").arg(QString(entry1->uuid().toRfc4122().toHex())));
|
||||
entry2->setPassword(QString("{REF:P@I:%1}").arg(entry1->uuidToHex()));
|
||||
entry2->setUrl("http://{S:IpAddress}:{S:Port}/{S:Uri}");
|
||||
entry2->attributes()->set("CustomUserNameAttribute", "CustomUserNameValue");
|
||||
entry2->attributes()->set("IpAddress", "127.0.0.1");
|
||||
|
@ -235,10 +234,10 @@ void TestEntry::testResolveRecursivePlaceholders()
|
|||
auto* entry3 = new Entry();
|
||||
entry3->setGroup(root);
|
||||
entry3->setUuid(QUuid::createUuid());
|
||||
entry3->setTitle(QString("{REF:T@I:%1}").arg(QString(entry2->uuid().toRfc4122().toHex())));
|
||||
entry3->setUsername(QString("{REF:U@I:%1}").arg(QString(entry2->uuid().toRfc4122().toHex())));
|
||||
entry3->setPassword(QString("{REF:P@I:%1}").arg(QString(entry2->uuid().toRfc4122().toHex())));
|
||||
entry3->setUrl(QString("{REF:A@I:%1}").arg(QString(entry2->uuid().toRfc4122().toHex())));
|
||||
entry3->setTitle(QString("{REF:T@I:%1}").arg(entry2->uuidToHex()));
|
||||
entry3->setUsername(QString("{REF:U@I:%1}").arg(entry2->uuidToHex()));
|
||||
entry3->setPassword(QString("{REF:P@I:%1}").arg(entry2->uuidToHex()));
|
||||
entry3->setUrl(QString("{REF:A@I:%1}").arg(entry2->uuidToHex()));
|
||||
|
||||
QCOMPARE(entry3->resolveMultiplePlaceholders(entry3->title()), QString("Entry2Title"));
|
||||
QCOMPARE(entry3->resolveMultiplePlaceholders(entry3->username()), QString("CustomUserNameValue"));
|
||||
|
@ -248,10 +247,10 @@ void TestEntry::testResolveRecursivePlaceholders()
|
|||
auto* entry4 = new Entry();
|
||||
entry4->setGroup(root);
|
||||
entry4->setUuid(QUuid::createUuid());
|
||||
entry4->setTitle(QString("{REF:T@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex())));
|
||||
entry4->setUsername(QString("{REF:U@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex())));
|
||||
entry4->setPassword(QString("{REF:P@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex())));
|
||||
entry4->setUrl(QString("{REF:A@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex())));
|
||||
entry4->setTitle(QString("{REF:T@I:%1}").arg(entry3->uuidToHex()));
|
||||
entry4->setUsername(QString("{REF:U@I:%1}").arg(entry3->uuidToHex()));
|
||||
entry4->setPassword(QString("{REF:P@I:%1}").arg(entry3->uuidToHex()));
|
||||
entry4->setUrl(QString("{REF:A@I:%1}").arg(entry3->uuidToHex()));
|
||||
|
||||
QCOMPARE(entry4->resolveMultiplePlaceholders(entry4->title()), QString("Entry2Title"));
|
||||
QCOMPARE(entry4->resolveMultiplePlaceholders(entry4->username()), QString("CustomUserNameValue"));
|
||||
|
@ -279,7 +278,7 @@ void TestEntry::testResolveRecursivePlaceholders()
|
|||
auto* entry6 = new Entry();
|
||||
entry6->setGroup(root);
|
||||
entry6->setUuid(QUuid::createUuid());
|
||||
entry6->setTitle(QString("{REF:T@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex())));
|
||||
entry6->setTitle(QString("{REF:T@I:%1}").arg(entry3->uuidToHex()));
|
||||
entry6->setUsername(QString("{TITLE}"));
|
||||
entry6->setPassword(QString("{PASSWORD}"));
|
||||
|
||||
|
@ -290,7 +289,7 @@ void TestEntry::testResolveRecursivePlaceholders()
|
|||
auto* entry7 = new Entry();
|
||||
entry7->setGroup(root);
|
||||
entry7->setUuid(QUuid::createUuid());
|
||||
entry7->setTitle(QString("{REF:T@I:%1} and something else").arg(QString(entry3->uuid().toRfc4122().toHex())));
|
||||
entry7->setTitle(QString("{REF:T@I:%1} and something else").arg(entry3->uuidToHex()));
|
||||
entry7->setUsername(QString("{TITLE}"));
|
||||
entry7->setPassword(QString("PASSWORD"));
|
||||
|
||||
|
@ -344,7 +343,7 @@ void TestEntry::testResolveReferencePlaceholders()
|
|||
tstEntry->setGroup(root);
|
||||
tstEntry->setUuid(QUuid::createUuid());
|
||||
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(QString(entry1->uuid().toRfc4122().toHex()))),
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())),
|
||||
entry1->title());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry1->username())), entry1->title());
|
||||
|
@ -355,7 +354,7 @@ void TestEntry::testResolveReferencePlaceholders()
|
|||
QString("{REF:T@O:%1}").arg(entry1->attributes()->value("CustomAttribute1"))),
|
||||
entry1->title());
|
||||
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(QString(entry1->uuid().toRfc4122().toHex()))),
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry1->uuidToHex())),
|
||||
entry1->title());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry1->title())), entry1->title());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@U:%1}").arg(entry1->username())),
|
||||
|
@ -365,7 +364,7 @@ void TestEntry::testResolveReferencePlaceholders()
|
|||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry1->url())), entry1->url());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry1->notes())), entry1->notes());
|
||||
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(QString(entry2->uuid().toRfc4122().toHex()))),
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry2->uuidToHex())),
|
||||
entry2->title());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@T:%1}").arg(entry2->title())), entry2->title());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@U:%1}").arg(entry2->username())), entry2->title());
|
||||
|
@ -384,23 +383,23 @@ void TestEntry::testResolveReferencePlaceholders()
|
|||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@A:%1}").arg(entry2->url())), entry2->url());
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@N:%1}").arg(entry2->notes())), entry2->notes());
|
||||
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex()))), entry3->attributes()->value("AttributeTitle"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex()))), entry3->attributes()->value("AttributeUsername"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex()))), entry3->attributes()->value("AttributePassword"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex()))), entry3->attributes()->value("AttributeUrl"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex()))), entry3->attributes()->value("AttributeNotes"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeTitle"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeUsername"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributePassword"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeUrl"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex())), entry3->attributes()->value("AttributeNotes"));
|
||||
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toUpper()))), entry3->attributes()->value("AttributeTitle"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toUpper()))), entry3->attributes()->value("AttributeUsername"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toUpper()))), entry3->attributes()->value("AttributePassword"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toUpper()))), entry3->attributes()->value("AttributeUrl"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toUpper()))), entry3->attributes()->value("AttributeNotes"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:T@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeTitle"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:U@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeUsername"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:P@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributePassword"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:A@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeUrl"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:N@I:%1}").arg(entry3->uuidToHex().toUpper())), entry3->attributes()->value("AttributeNotes"));
|
||||
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:t@i:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toLower()))), entry3->attributes()->value("AttributeTitle"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:u@i:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toLower()))), entry3->attributes()->value("AttributeUsername"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:p@i:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toLower()))), entry3->attributes()->value("AttributePassword"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:a@i:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toLower()))), entry3->attributes()->value("AttributeUrl"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:n@i:%1}").arg(QString(entry3->uuid().toRfc4122().toHex().toLower()))), entry3->attributes()->value("AttributeNotes"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:t@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeTitle"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:u@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeUsername"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:p@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributePassword"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:a@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeUrl"));
|
||||
QCOMPARE(tstEntry->resolveMultiplePlaceholders(QString("{REF:n@i:%1}").arg(entry3->uuidToHex().toLower())), entry3->attributes()->value("AttributeNotes"));
|
||||
}
|
||||
|
||||
void TestEntry::testResolveNonIdPlaceholdersToUuid()
|
||||
|
@ -469,7 +468,7 @@ void TestEntry::testResolveNonIdPlaceholdersToUuid()
|
|||
|
||||
const QString newEntryNotesResolved =
|
||||
newEntry->resolveMultiplePlaceholders(newEntry->notes());
|
||||
QCOMPARE(newEntryNotesResolved, QString(referencedEntry->uuid().toRfc4122().toHex()));
|
||||
QCOMPARE(newEntryNotesResolved, referencedEntry->uuidToHex());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue