Skip to content

Commit

Permalink
Prevent data loss when drag/drop between databases
Browse files Browse the repository at this point in the history
* Fixes keepassxreboot#5262
* Always reset the UUID on groups and entries moved or copied between databases. This prevents data loss when the group/entry is moved back to the original database.
  • Loading branch information
droidmonkey committed Oct 15, 2020
1 parent 389899e commit b10a55a
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 28 deletions.
2 changes: 2 additions & 0 deletions src/core/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const int Entry::ResolveMaximumDepth = 10;
const QString Entry::AutoTypeSequenceUsername = "{USERNAME}{ENTER}";
const QString Entry::AutoTypeSequencePassword = "{PASSWORD}{ENTER}";

Entry::CloneFlags Entry::DefaultCloneFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo;

Entry::Entry()
: m_attributes(new EntryAttributes(this))
, m_attachments(new EntryAttachments(this))
Expand Down
13 changes: 7 additions & 6 deletions src/core/Entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,6 @@ class Entry : public QObject
CustomData* customData();
const CustomData* customData() const;

static const int DefaultIconNumber;
static const int ResolveMaximumDepth;
static const QString AutoTypeSequenceUsername;
static const QString AutoTypeSequencePassword;

void setUuid(const QUuid& uuid);
void setIcon(int iconNumber);
void setIcon(const QUuid& uuid);
Expand Down Expand Up @@ -209,13 +204,19 @@ class Entry : public QObject
DbDir
};

static const int DefaultIconNumber;
static const int ResolveMaximumDepth;
static const QString AutoTypeSequenceUsername;
static const QString AutoTypeSequencePassword;
static CloneFlags DefaultCloneFlags;

/**
* Creates a duplicate of this entry except that the returned entry isn't
* part of any group.
* Note that you need to copy the custom icons manually when inserting the
* new entry into another database.
*/
Entry* clone(CloneFlags flags) const;
Entry* clone(CloneFlags flags = DefaultCloneFlags) const;
void copyDataFrom(const Entry* other);
QString maskPasswordPlaceholders(const QString& str) const;
Entry* resolveReference(const QString& str) const;
Expand Down
4 changes: 1 addition & 3 deletions src/core/Group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ const int Group::RecycleBinIconNumber = 43;
const QString Group::RootAutoTypeSequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}";

Group::CloneFlags Group::DefaultCloneFlags =
static_cast<Group::CloneFlags>(Group::CloneNewUuid | Group::CloneResetTimeInfo | Group::CloneIncludeEntries);
Entry::CloneFlags Group::DefaultEntryCloneFlags =
static_cast<Entry::CloneFlags>(Entry::CloneNewUuid | Entry::CloneResetTimeInfo);
Group::CloneNewUuid | Group::CloneResetTimeInfo | Group::CloneIncludeEntries;

Group::Group()
: m_customData(new CustomData(this))
Expand Down
3 changes: 1 addition & 2 deletions src/core/Group.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ class Group : public QObject
static const int DefaultIconNumber;
static const int RecycleBinIconNumber;
static CloneFlags DefaultCloneFlags;
static Entry::CloneFlags DefaultEntryCloneFlags;
static const QString RootAutoTypeSequence;

Group* findChildByName(const QString& name);
Expand Down Expand Up @@ -158,7 +157,7 @@ class Group : public QObject
QSet<QUuid> customIconsRecursive() const;
QList<QString> usernamesRecursive(int topN = -1) const;

Group* clone(Entry::CloneFlags entryFlags = DefaultEntryCloneFlags,
Group* clone(Entry::CloneFlags entryFlags = Entry::DefaultCloneFlags,
CloneFlags groupFlags = DefaultCloneFlags) const;

void copyDataFrom(const Group* other);
Expand Down
43 changes: 26 additions & 17 deletions src/gui/group/GroupModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,19 +252,23 @@ bool GroupModel::dropMimeData(const QMimeData* data,
row--;
}

Group* group;
if (action == Qt::MoveAction) {
group = dragGroup;
} else {
group = dragGroup->clone();
}

Database* sourceDb = dragGroup->database();
Database* targetDb = parentGroup->database();

Group* group = dragGroup;

if (sourceDb != targetDb) {
QSet<QUuid> customIcons = group->customIconsRecursive();
targetDb->metadata()->copyCustomIcons(customIcons, sourceDb->metadata());

// Always clone the group across db's to reset UUIDs
group = dragGroup->clone();
if (action == Qt::MoveAction) {
// Remove the original group from the sourceDb
delete dragGroup;
}
} else if (action == Qt::CopyAction) {
group = dragGroup->clone();
}

group->setParent(parentGroup, row);
Expand All @@ -288,19 +292,24 @@ bool GroupModel::dropMimeData(const QMimeData* data,
continue;
}

Entry* entry;
if (action == Qt::MoveAction) {
entry = dragEntry;
} else {
entry = dragEntry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo);
}

Database* sourceDb = dragEntry->group()->database();
Database* targetDb = parentGroup->database();
QUuid customIcon = entry->iconUuid();

if (sourceDb != targetDb && !customIcon.isNull() && !targetDb->metadata()->hasCustomIcon(customIcon)) {
targetDb->metadata()->addCustomIcon(customIcon, sourceDb->metadata()->customIcon(customIcon));
Entry* entry = dragEntry;

if (sourceDb != targetDb) {
QUuid customIcon = entry->iconUuid();
if (!customIcon.isNull() && !targetDb->metadata()->hasCustomIcon(customIcon)) {
targetDb->metadata()->addCustomIcon(customIcon, sourceDb->metadata()->customIcon(customIcon));
}

// Always clone the entry across db's to reset the UUID
entry = dragEntry->clone();
if (action == Qt::MoveAction) {
delete dragEntry;
}
} else if (action == Qt::CopyAction) {
entry = dragEntry->clone();
}

entry->setGroup(parentGroup);
Expand Down

0 comments on commit b10a55a

Please sign in to comment.