-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CustomData from KDBX4 to Group and Entry #1477
Conversation
Introduce missing CustomData-attributes of KDBX4 format to allow storing of plugin data for groups and entries - adopt Metadata to use the same storage mechanism Add simple view for CustomData as part of EditWidgetProperties Tracking of CustomData-Modification using SIGNAL-SLOT update-mechanism
Small improvements to existing tests Create test to check modification of CustomData in Entry, Group and Metadata
HistoryItem size calculation uses the correct CustomData object
src/core/Entry.cpp
Outdated
@@ -340,6 +342,16 @@ const EntryAttachments* Entry::attachments() const | |||
return m_attachments; | |||
} | |||
|
|||
CustomData *Entry::customData() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CustomData* Entry
src/core/Entry.cpp
Outdated
return m_customData; | ||
} | ||
|
||
const CustomData *Entry::customData() const |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CustomData* Entry
src/core/Entry.h
Outdated
@@ -107,6 +108,8 @@ class Entry : public QObject | |||
const EntryAttributes* attributes() const; | |||
EntryAttachments* attachments(); | |||
const EntryAttachments* attachments() const; | |||
CustomData *customData(); | |||
const CustomData *customData() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CustomData* customData
. There's more occurrences of this in the PR, I did not comment on all of them.
if (config()->get("IgnoreGroupExpansion").toBool()) { | ||
updateTimeinfo(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckieschnick I'm not even sure we should be updating the time info in that case. @phoerious thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say that depends on what KeePass does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite sure if it is required by KeePass - the change was necessary due to retain the behavior after changing the timestamp update to use the self-listen mechanism with modified-signal (which is explicitly not emitted when "IgnoreGroupExpansion" is on). I think, if the behavior deviates from KeePass, it should be fixed separately.
src/format/KdbxXmlReader.cpp
Outdated
@@ -743,7 +747,10 @@ Entry* KdbxXmlReader::parseEntry(bool history) | |||
} | |||
continue; | |||
} | |||
|
|||
if (m_xml.name() == "CustomData" ){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckieschnick space before {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And no space before )
src/format/KdbxXmlWriter.cpp
Outdated
@@ -277,6 +276,10 @@ void KdbxXmlWriter::writeGroup(const Group* group) | |||
|
|||
writeUuid("LastTopVisibleEntry", group->lastTopVisibleEntry()); | |||
|
|||
if (!group->customData()->isEmpty()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckieschnick the check for emptiness could be moved into writeCustomData
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space before {
@@ -41,12 +41,12 @@ | |||
</Binaries> | |||
<CustomData> | |||
<Item> | |||
<Key>A Sample Test Key</Key> | |||
<Value>valu</Value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckieschnick looks like tabs are used in the rest of the file, maybe it would be better to keep it that way for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckieschnick I added some comments, but it looks good in general. Could not test it though, since I'm blocked by #1472.
src/core/CustomData.cpp
Outdated
@@ -0,0 +1,156 @@ | |||
/* | |||
* Copyright (C) 2012 Felix Geyer <debfx@fobos.de> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this copyright. debfx is the KeePassX maintainer and not involved in KeePassXC.
src/core/CustomData.cpp
Outdated
bool addAttribute = !m_data.contains(key); | ||
bool changeValue = !addAttribute && (m_data.value(key) != value); | ||
|
||
if (addAttribute ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove space before )
src/core/CustomData.cpp
Outdated
bool emitModified = false; | ||
|
||
bool addAttribute = !m_data.contains(key); | ||
bool changeValue = !addAttribute && (m_data.value(key) != value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value() will return a default-constructed element if the key does not exist. Avoid that by checking if the key exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The case is already covered since !addAttributes
equals m_data.contains(key)
- m_data.value(key)
is only called when the key exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True.
src/core/CustomData.cpp
Outdated
|
||
if (addAttribute || changeValue) { | ||
m_data.insert(key, value); | ||
emitModified = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not emit directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I derived the code from an existing class (I think it was EntryAttributes
) to reduce style issues. This part was already part of the existing class, so I took it for a code convention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just emit the signal right away. There's no point in doing it later.
src/core/CustomData.cpp
Outdated
void CustomData::rename(const QString& oldKey, const QString& newKey) | ||
{ | ||
if (!m_data.contains(oldKey)) { | ||
Q_ASSERT(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid Q_ASSERT(false). Replace with
bool exists = m_data.contains(oldKey);
Q_ASSERT(exists);
if (!exists) {
return;
]
src/gui/EditWidgetProperties.h
Outdated
@@ -35,11 +38,21 @@ class EditWidgetProperties : public QWidget | |||
explicit EditWidgetProperties(QWidget* parent = nullptr); | |||
~EditWidgetProperties(); | |||
|
|||
void setFields(TimeInfo timeInfo, Uuid uuid); | |||
void setFields(const TimeInfo &timeInfo, const Uuid &uuid); | |||
void setCustomData(const CustomData *customData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const TimeInfo&
const Uuid&
CustomData*
tests/TestKeePass2Format.cpp
Outdated
@@ -53,6 +53,7 @@ void TestKeePass2Format::initTestCase() | |||
entry->setPassword(QString::fromUtf8("\xc3\xa4\xa3\xb6\xc3\xbc\xe9\x9b\xbb\xe7\xb4\x85")); | |||
entry->setUuid(Uuid::random()); | |||
entry->attributes()->set("test", "protectedTest", true); | |||
entry->customData()->set("CustomDataEntryKey", "CustomDataValue" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove space before )
tests/TestModified.cpp
Outdated
@@ -315,7 +313,7 @@ void TestModified::testHistoryItems() | |||
entry->setTitle("b"); | |||
entry->endUpdate(); | |||
QCOMPARE(entry->historyItems().size(), ++historyItemsSize); | |||
historyEntry = entry->historyItems().at(historyItemsSize - 1); | |||
Entry *historyEntry = entry->historyItems().at(historyItemsSize - 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto*
tests/TestModified.cpp
Outdated
void TestModified::testCustomData() | ||
{ | ||
int spyCount = 0; | ||
Database* db = new Database(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use QScopedPointer or allocate on the stack
tests/TestModified.cpp
Outdated
|
||
Group* group = new Group(); | ||
group->setParent(root); | ||
Entry* entry = new Entry(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto* for all these to avoid class name repetition.
|
||
void CustomData::copyDataFrom(const CustomData* other) | ||
{ | ||
if (*this != *other) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ckieschnick is this really a possibility? shouldn't we assert this doesn't happen instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not that familiar with the KeePassXC code. Skimming the code, I think an assert would be correct - but the check it is a pattern in different data classes (EntryAttributes
, EntryAttachments
) which suggests that there is or there was a case of self assignment (since CustomData
are used in Entry
, Group
and Metadata
the risk is even higher). So I pass the question back to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add an assert in addition to the check. The assert is for debug purposes only.
Fixed several code style issues (whitespace, position of * and &, assert style) Added several QPointer and QScopedPointer where appropriate
@@ -397,20 +397,20 @@ void KdbxXmlReader::parseBinaries() | |||
} | |||
} | |||
|
|||
void KdbxXmlReader::parseCustomData() | |||
void KdbxXmlReader::parseCustomData(CustomData *customData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You missed a few of these.
const QString key = index.data().toString(); | ||
m_customData->remove(key); | ||
} | ||
this->updateModel(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also remove the explicit this pointer (I might have missed that last time).
Since I can't push to the private source repository, please continue here: #1494 |
Added support for CustomData from KDBX 4 format in Entry and Group.
Description
Added a CustomData-class to manage custom fields from Metadata, Groups and Entries. Update of timestamps by changing CustomData is implemented through forwarding the modified signal and the self-update-timestamp mechanism which was previously only used in Entry.
Management of CustomData for Group and Entry is similar to KeePass which allows to delete the attributes within the Edit dialog
Motivation and context
Change is required since opening and storing a valid kdbx4-database from KeePass should not loose information. The format version 4 requires to load and store custom data at entries and groups.
How has this been tested?
Added tests to the Testsuite and extended the NewDatabase.xml fixture to contain CustomData at Metadata, Group, Entry and History level.
Types of changes
Checklist:
-DWITH_ASAN=ON
. [REQUIRED]