Skip to content

Commit

Permalink
Warn user if deleting entries that are referenced. Resolves #852.
Browse files Browse the repository at this point in the history
On warning, references can be replaced with original values or ignored.
Removal process can be also skipped for each conflicting entry.
  • Loading branch information
wgml committed Nov 14, 2018
1 parent f06742c commit 4389128
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 158 deletions.
47 changes: 36 additions & 11 deletions src/core/Database.cpp
Expand Up @@ -18,26 +18,24 @@

#include "Database.h"

#include <QDebug>
#include <QFile>
#include <QSaveFile>
#include <QTemporaryFile>
#include <QTextStream>
#include <QTimer>
#include <QXmlStreamReader>
#include <utility>

#include "cli/Utils.h"
#include "core/Clock.h"
#include "core/Group.h"
#include "core/Merger.h"
#include "core/Metadata.h"
#include "crypto/kdf/AesKdf.h"
#include "format/KeePass2.h"
#include "format/KeePass2Reader.h"
#include "format/KeePass2Writer.h"
#include "keys/FileKey.h"
#include "keys/PasswordKey.h"
#include <QDebug>
#include <QFile>
#include <QSaveFile>
#include <QTemporaryFile>
#include <QTextStream>
#include <QTimer>
#include <QXmlStreamReader>
#include <QtConcurrent>
#include <utility>

QHash<QUuid, Database*> Database::m_uuidMap;

Expand Down Expand Up @@ -215,6 +213,33 @@ Group* Database::findGroupRecursive(const QUuid& uuid, Group* group)
return nullptr;
}

QList<Entry*> Database::resolveReferences(const QUuid& uuid) const
{
return resolveReferences(uuid, m_rootGroup);
}

QList<Entry*> Database::resolveReferences(const QUuid& uuid, const Group* group) const
{
auto isReference = [&uuid](const Entry* e) { return e->hasReferencesTo(uuid); };

QList<Entry*> result = QtConcurrent::blockingFiltered(group->entries(), isReference);

for (Group* child : group->children()) {
result += resolveReferences(uuid, child);
}
return result;
}

void Database::replaceReferencesWithValues(Entry* entry, QList<Entry*> references)
{
for (Entry* reference : references) {
for (const QString& key : EntryAttributes::DefaultAttributes) {
if (reference->isAttributeReferenceOf(key, entry->uuid()))
reference->setDefaultAttribute(key, entry->attribute(key));
}
}
}

QList<DeletedObject> Database::deletedObjects()
{
return m_deletedObjects;
Expand Down
13 changes: 10 additions & 3 deletions src/core/Database.h
Expand Up @@ -91,6 +91,9 @@ class Database : public QObject
Entry* resolveEntry(const QUuid& uuid);
Entry* resolveEntry(const QString& text, EntryReferenceType referenceType);
Group* resolveGroup(const QUuid& uuid);
QList<Entry*> resolveReferences(const QUuid& uuid) const;
QList<Entry*> resolveReferences(const QUuid& uuid, const Group* group) const;
void replaceReferencesWithValues(Entry* entry, QList<Entry*> references);
QList<DeletedObject> deletedObjects();
const QList<DeletedObject>& deletedObjects() const;
void addDeletedObject(const DeletedObject& delObj);
Expand All @@ -110,7 +113,9 @@ class Database : public QObject
void setCipher(const QUuid& cipher);
void setCompressionAlgo(Database::CompressionAlgorithm algo);
void setKdf(QSharedPointer<Kdf> kdf);
bool setKey(const QSharedPointer<const CompositeKey>& key, bool updateChangedTime = true, bool updateTransformSalt = false);
bool setKey(const QSharedPointer<const CompositeKey>& key,
bool updateChangedTime = true,
bool updateTransformSalt = false);
bool hasKey() const;
bool verifyKey(const QSharedPointer<CompositeKey>& key) const;
QVariantMap& publicCustomData();
Expand All @@ -131,8 +136,10 @@ class Database : public QObject

static Database* databaseByUuid(const QUuid& uuid);
static Database* openDatabaseFile(const QString& fileName, QSharedPointer<const CompositeKey> key);
static Database* unlockFromStdin(const QString& databaseFilename, const QString& keyFilename = {},
FILE* outputDescriptor = stdout, FILE* errorDescriptor = stderr);
static Database* unlockFromStdin(const QString& databaseFilename,
const QString& keyFilename = {},
FILE* outputDescriptor = stdout,
FILE* errorDescriptor = stderr);

signals:
void groupDataChanged(Group* group);
Expand Down
47 changes: 44 additions & 3 deletions src/core/Entry.cpp
Expand Up @@ -24,6 +24,7 @@
#include "core/DatabaseIcons.h"
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/Tools.h"
#include "totp/totp.h"

#include <QDebug>
Expand Down Expand Up @@ -306,11 +307,26 @@ QString Entry::notes() const
return m_attributes->value(EntryAttributes::NotesKey);
}

QString Entry::attribute(const QString& key) const
{
return m_attributes->value(key);
}

bool Entry::isExpired() const
{
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < Clock::currentDateTimeUtc();
}

bool Entry::isAttributeReferenceOf(const QString& key, const QUuid& uuid) const
{
if (!m_attributes->isReference(key)) {
return false;
}

const QString ref = Tools::reference(uuid, key).toUpper();
return m_attributes->value(key) == ref;
}

bool Entry::hasReferences() const
{
const QList<QString> keyList = EntryAttributes::DefaultAttributes;
Expand All @@ -322,6 +338,17 @@ bool Entry::hasReferences() const
return false;
}

bool Entry::hasReferencesTo(const QUuid& uuid) const
{
const QList<QString> keyList = EntryAttributes::DefaultAttributes;
for (const QString& key : keyList) {
if (isAttributeReferenceOf(key, uuid)) {
return true;
}
}
return false;
}

EntryAttributes* Entry::attributes()
{
return m_attributes;
Expand Down Expand Up @@ -498,6 +525,17 @@ void Entry::setNotes(const QString& notes)
m_attributes->set(EntryAttributes::NotesKey, notes, m_attributes->isProtected(EntryAttributes::NotesKey));
}

void Entry::setDefaultAttribute(const QString& attribute, const QString& value)
{
Q_ASSERT(EntryAttributes::isDefaultAttribute(attribute));

if (!EntryAttributes::isDefaultAttribute(attribute)) {
return;
}

m_attributes->set(attribute, value, m_attributes->isProtected(attribute));
}

void Entry::setExpires(const bool& value)
{
if (m_data.timeInfo.expires() != value) {
Expand Down Expand Up @@ -658,12 +696,14 @@ Entry* Entry::clone(CloneFlags flags) const
if (flags & CloneUserAsRef) {
// Build the username reference
QString username = "{REF:U@I:" + uuidToHex() + "}";
entry->m_attributes->set(EntryAttributes::UserNameKey, username.toUpper(), m_attributes->isProtected(EntryAttributes::UserNameKey));
entry->m_attributes->set(
EntryAttributes::UserNameKey, username.toUpper(), m_attributes->isProtected(EntryAttributes::UserNameKey));
}

if (flags & ClonePassAsRef) {
QString password = "{REF:P@I:" + uuidToHex() + "}";
entry->m_attributes->set(EntryAttributes::PasswordKey, password.toUpper(), m_attributes->isProtected(EntryAttributes::PasswordKey));
entry->m_attributes->set(
EntryAttributes::PasswordKey, password.toUpper(), m_attributes->isProtected(EntryAttributes::PasswordKey));
}

entry->m_autoTypeAssociations->copyDataFrom(m_autoTypeAssociations);
Expand Down Expand Up @@ -1066,7 +1106,8 @@ QString Entry::resolveUrl(const QString& url) const

// Validate the URL
QUrl tempUrl = QUrl(newUrl);
if (tempUrl.isValid() && (tempUrl.scheme() == "http" || tempUrl.scheme() == "https" || tempUrl.scheme() == "file")) {
if (tempUrl.isValid()
&& (tempUrl.scheme() == "http" || tempUrl.scheme() == "https" || tempUrl.scheme() == "file")) {
return tempUrl.url();
}

Expand Down
4 changes: 4 additions & 0 deletions src/core/Entry.h
Expand Up @@ -104,12 +104,15 @@ class Entry : public QObject
QString username() const;
QString password() const;
QString notes() const;
QString attribute(const QString& key) const;
QString totp() const;
QSharedPointer<Totp::Settings> totpSettings() const;

bool hasTotp() const;
bool isExpired() const;
bool isAttributeReferenceOf(const QString& key, const QUuid& uuid) const;
bool hasReferences() const;
bool hasReferencesTo(const QUuid& uuid) const;
EntryAttributes* attributes();
const EntryAttributes* attributes() const;
EntryAttachments* attachments();
Expand Down Expand Up @@ -138,6 +141,7 @@ class Entry : public QObject
void setUsername(const QString& username);
void setPassword(const QString& password);
void setNotes(const QString& notes);
void setDefaultAttribute(const QString& attribute, const QString& value);
void setExpires(const bool& value);
void setExpiryTime(const QDateTime& dateTime);
void setTotp(QSharedPointer<Totp::Settings> settings);
Expand Down

0 comments on commit 4389128

Please sign in to comment.