diff --git a/src/core/Database.cpp b/src/core/Database.cpp index f125a2786..0394051fc 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -32,13 +32,14 @@ QHash Database::m_uuidMap; Database::Database() : m_metadata(new Metadata(this)) , m_timer(new QTimer(this)) - , m_cipher(KeePass2::CIPHER_AES) - , m_compressionAlgo(CompressionGZip) - , m_transformRounds(50000) - , m_hasKey(false) , m_emitModified(false) , m_uuid(Uuid::random()) { + m_data.cipher = KeePass2::CIPHER_AES; + m_data.compressionAlgo = CompressionGZip; + m_data.transformRounds = 50000; + m_data.hasKey = false; + setRootGroup(new Group()); rootGroup()->setUuid(Uuid::random()); m_timer->setSingleShot(true); @@ -150,60 +151,60 @@ void Database::addDeletedObject(const Uuid& uuid) Uuid Database::cipher() const { - return m_cipher; + return m_data.cipher; } Database::CompressionAlgorithm Database::compressionAlgo() const { - return m_compressionAlgo; + return m_data.compressionAlgo; } QByteArray Database::transformSeed() const { - return m_transformSeed; + return m_data.transformSeed; } quint64 Database::transformRounds() const { - return m_transformRounds; + return m_data.transformRounds; } QByteArray Database::transformedMasterKey() const { - return m_transformedMasterKey; + return m_data.transformedMasterKey; } void Database::setCipher(const Uuid& cipher) { Q_ASSERT(!cipher.isNull()); - m_cipher = cipher; + m_data.cipher = cipher; } void Database::setCompressionAlgo(Database::CompressionAlgorithm algo) { Q_ASSERT(static_cast(algo) <= CompressionAlgorithmMax); - m_compressionAlgo = algo; + m_data.compressionAlgo = algo; } void Database::setTransformRounds(quint64 rounds) { - if (m_transformRounds != rounds) { - m_transformRounds = rounds; + if (m_data.transformRounds != rounds) { + m_data.transformRounds = rounds; - if (m_hasKey) { - setKey(m_key); + if (m_data.hasKey) { + setKey(m_data.key); } } } void Database::setKey(const CompositeKey& key, const QByteArray& transformSeed, bool updateChangedTime) { - m_key = key; - m_transformSeed = transformSeed; - m_transformedMasterKey = key.transform(transformSeed, transformRounds()); - m_hasKey = true; + m_data.key = key; + m_data.transformSeed = transformSeed; + m_data.transformedMasterKey = key.transform(transformSeed, transformRounds()); + m_data.hasKey = true; if (updateChangedTime) { m_metadata->setMasterKeyChanged(Tools::currentDateTimeUtc()); } @@ -217,14 +218,14 @@ void Database::setKey(const CompositeKey& key) bool Database::hasKey() const { - return m_hasKey; + return m_data.hasKey; } bool Database::verifyKey(const CompositeKey& key) const { Q_ASSERT(hasKey()); - return (m_key.rawKey() == key.rawKey()); + return (m_data.key.rawKey() == key.rawKey()); } void Database::createRecycleBin() @@ -269,6 +270,12 @@ void Database::setEmitModified(bool value) m_emitModified = value; } +void Database::copyAttributesFrom(const Database* other) +{ + m_data = other->m_data; + m_metadata->copyAttributesFrom(other->m_metadata); +} + Uuid Database::uuid() { return m_uuid; diff --git a/src/core/Database.h b/src/core/Database.h index 267d6b0b4..0ee9a9659 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -49,6 +49,17 @@ public: }; static const quint32 CompressionAlgorithmMax = CompressionGZip; + struct DatabaseData + { + Uuid cipher; + CompressionAlgorithm compressionAlgo; + QByteArray transformSeed; + quint64 transformRounds; + QByteArray transformedMasterKey; + CompositeKey key; + bool hasKey; + }; + Database(); ~Database(); Group* rootGroup(); @@ -91,6 +102,7 @@ public: void recycleEntry(Entry* entry); void recycleGroup(Group* group); void setEmitModified(bool value); + void copyAttributesFrom(const Database* other); /** * Returns a unique id that is only valid as long as the Database exists. @@ -124,15 +136,7 @@ private: Group* m_rootGroup; QList m_deletedObjects; QTimer* m_timer; - - Uuid m_cipher; - CompressionAlgorithm m_compressionAlgo; - QByteArray m_transformSeed; - quint64 m_transformRounds; - QByteArray m_transformedMasterKey; - - CompositeKey m_key; - bool m_hasKey; + DatabaseData m_data; bool m_emitModified; Uuid m_uuid; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 9199389ec..ada9e9723 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -500,6 +500,22 @@ void Group::copyDataFrom(const Group* other) m_lastTopVisibleEntry = other->m_lastTopVisibleEntry; } +Database* Group::exportToDb() +{ + Q_ASSERT(database()); + + Database* db = new Database(); + Group* clonedGroup = clone(Entry::CloneNewUuid | Entry::CloneIncludeHistory); + clonedGroup->setParent(db->rootGroup()); + + QSet customIcons = customIconsRecursive(); + db->metadata()->copyCustomIcons(customIcons, database()->metadata()); + + db->copyAttributesFrom(database()); + + return db; +} + void Group::addEntry(Entry* entry) { Q_ASSERT(entry); diff --git a/src/core/Group.h b/src/core/Group.h index 9480c6f16..558bebcc9 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -109,6 +109,7 @@ public: */ Group* clone(Entry::CloneFlags entryFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo) const; void copyDataFrom(const Group* other); + Database* exportToDb(); QList search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity, bool resolveInherit = true); diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index 5947255e5..074291c73 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -26,25 +26,26 @@ const int Metadata::DefaultHistoryMaxSize = 6 * 1024 * 1024; Metadata::Metadata(QObject* parent) : QObject(parent) - , m_generator("KeePassX") - , m_maintenanceHistoryDays(365) - , m_protectTitle(false) - , m_protectUsername(false) - , m_protectPassword(true) - , m_protectUrl(false) - , m_protectNotes(false) - // , m_autoEnableVisualHiding(false) - , m_recycleBinEnabled(true) - , m_masterKeyChangeRec(-1) - , m_masterKeyChangeForce(-1) - , m_historyMaxItems(DefaultHistoryMaxItems) - , m_historyMaxSize(DefaultHistoryMaxSize) , m_updateDatetime(true) { + m_data.generator = "KeePassX"; + m_data.maintenanceHistoryDays = 365; + m_data.masterKeyChangeRec = -1; + m_data.masterKeyChangeForce = -1; + m_data.historyMaxItems = DefaultHistoryMaxItems; + m_data.historyMaxSize = DefaultHistoryMaxSize; + m_data.recycleBinEnabled = true; + m_data.protectTitle = false; + m_data.protectUsername = false; + m_data.protectPassword = true; + m_data.protectUrl = false; + m_data.protectNotes = false; + // m_data.autoEnableVisualHiding = false; + QDateTime now = Tools::currentDateTimeUtc(); - m_nameChanged = now; - m_descriptionChanged = now; - m_defaultUserNameChanged = now; + m_data.nameChanged = now; + m_data.descriptionChanged = now; + m_data.defaultUserNameChanged = now; m_recycleBinChanged = now; m_entryTemplatesGroupChanged = now; m_masterKeyChanged = now; @@ -81,74 +82,79 @@ void Metadata::setUpdateDatetime(bool value) m_updateDatetime = value; } +void Metadata::copyAttributesFrom(const Metadata* other) +{ + m_data = other->m_data; +} + QString Metadata::generator() const { - return m_generator; + return m_data.generator; } QString Metadata::name() const { - return m_name; + return m_data.name; } QDateTime Metadata::nameChanged() const { - return m_nameChanged; + return m_data.nameChanged; } QString Metadata::description() const { - return m_description; + return m_data.description; } QDateTime Metadata::descriptionChanged() const { - return m_descriptionChanged; + return m_data.descriptionChanged; } QString Metadata::defaultUserName() const { - return m_defaultUserName; + return m_data.defaultUserName; } QDateTime Metadata::defaultUserNameChanged() const { - return m_defaultUserNameChanged; + return m_data.defaultUserNameChanged; } int Metadata::maintenanceHistoryDays() const { - return m_maintenanceHistoryDays; + return m_data.maintenanceHistoryDays; } QColor Metadata::color() const { - return m_color; + return m_data.color; } bool Metadata::protectTitle() const { - return m_protectTitle; + return m_data.protectTitle; } bool Metadata::protectUsername() const { - return m_protectUsername; + return m_data.protectUsername; } bool Metadata::protectPassword() const { - return m_protectPassword; + return m_data.protectPassword; } bool Metadata::protectUrl() const { - return m_protectUrl; + return m_data.protectUrl; } bool Metadata::protectNotes() const { - return m_protectNotes; + return m_data.protectNotes; } /*bool Metadata::autoEnableVisualHiding() const @@ -178,7 +184,7 @@ QList Metadata::customIconsOrder() const bool Metadata::recycleBinEnabled() const { - return m_recycleBinEnabled; + return m_data.recycleBinEnabled; } Group* Metadata::recycleBin() @@ -223,22 +229,22 @@ QDateTime Metadata::masterKeyChanged() const int Metadata::masterKeyChangeRec() const { - return m_masterKeyChangeRec; + return m_data.masterKeyChangeRec; } int Metadata::masterKeyChangeForce() const { - return m_masterKeyChangeForce; + return m_data.masterKeyChangeForce; } int Metadata::historyMaxItems() const { - return m_historyMaxItems; + return m_data.historyMaxItems; } int Metadata::historyMaxSize() const { - return m_historyMaxSize; + return m_data.historyMaxSize; } QHash Metadata::customFields() const @@ -248,12 +254,12 @@ QHash Metadata::customFields() const void Metadata::setGenerator(const QString& value) { - set(m_generator, value); + set(m_data.generator, value); } void Metadata::setName(const QString& value) { - if (set(m_name, value, m_nameChanged)) { + if (set(m_data.name, value, m_data.nameChanged)) { Q_EMIT nameTextChanged(); } } @@ -261,64 +267,64 @@ void Metadata::setName(const QString& value) void Metadata::setNameChanged(const QDateTime& value) { Q_ASSERT(value.timeSpec() == Qt::UTC); - m_nameChanged = value; + m_data.nameChanged = value; } void Metadata::setDescription(const QString& value) { - set(m_description, value, m_descriptionChanged); + set(m_data.description, value, m_data.descriptionChanged); } void Metadata::setDescriptionChanged(const QDateTime& value) { Q_ASSERT(value.timeSpec() == Qt::UTC); - m_descriptionChanged = value; + m_data.descriptionChanged = value; } void Metadata::setDefaultUserName(const QString& value) { - set(m_defaultUserName, value, m_defaultUserNameChanged); + set(m_data.defaultUserName, value, m_data.defaultUserNameChanged); } void Metadata::setDefaultUserNameChanged(const QDateTime& value) { Q_ASSERT(value.timeSpec() == Qt::UTC); - m_defaultUserNameChanged = value; + m_data.defaultUserNameChanged = value; } void Metadata::setMaintenanceHistoryDays(int value) { - set(m_maintenanceHistoryDays, value); + set(m_data.maintenanceHistoryDays, value); } void Metadata::setColor(const QColor& value) { - set(m_color, value); + set(m_data.color, value); } void Metadata::setProtectTitle(bool value) { - set(m_protectTitle, value); + set(m_data.protectTitle, value); } void Metadata::setProtectUsername(bool value) { - set(m_protectUsername, value); + set(m_data.protectUsername, value); } void Metadata::setProtectPassword(bool value) { - set(m_protectPassword, value); + set(m_data.protectPassword, value); } void Metadata::setProtectUrl(bool value) { - set(m_protectUrl, value); + set(m_data.protectUrl, value); } void Metadata::setProtectNotes(bool value) { - set(m_protectNotes, value); + set(m_data.protectNotes, value); } /*void Metadata::setAutoEnableVisualHiding(bool value) @@ -361,7 +367,7 @@ void Metadata::copyCustomIcons(const QSet& iconList, const Metadata* other void Metadata::setRecycleBinEnabled(bool value) { - set(m_recycleBinEnabled, value); + set(m_data.recycleBinEnabled, value); } void Metadata::setRecycleBin(Group* group) @@ -404,22 +410,22 @@ void Metadata::setMasterKeyChanged(const QDateTime& value) void Metadata::setMasterKeyChangeRec(int value) { - set(m_masterKeyChangeRec, value); + set(m_data.masterKeyChangeRec, value); } void Metadata::setMasterKeyChangeForce(int value) { - set(m_masterKeyChangeForce, value); + set(m_data.masterKeyChangeForce, value); } void Metadata::setHistoryMaxItems(int value) { - set(m_historyMaxItems, value); + set(m_data.historyMaxItems, value); } void Metadata::setHistoryMaxSize(int value) { - set(m_historyMaxSize, value); + set(m_data.historyMaxSize, value); } void Metadata::addCustomField(const QString& key, const QString& value) diff --git a/src/core/Metadata.h b/src/core/Metadata.h index ec3c692e6..cde7e26ae 100644 --- a/src/core/Metadata.h +++ b/src/core/Metadata.h @@ -37,6 +37,31 @@ class Metadata : public QObject public: explicit Metadata(QObject* parent = Q_NULLPTR); + struct MetadataData + { + QString generator; + QString name; + QDateTime nameChanged; + QString description; + QDateTime descriptionChanged; + QString defaultUserName; + QDateTime defaultUserNameChanged; + int maintenanceHistoryDays; + QColor color; + bool recycleBinEnabled; + int historyMaxItems; + int historyMaxSize; + int masterKeyChangeRec; + int masterKeyChangeForce; + + bool protectTitle; + bool protectUsername; + bool protectPassword; + bool protectUrl; + bool protectNotes; + // bool autoEnableVisualHiding; + }; + QString generator() const; QString name() const; QDateTime nameChanged() const; @@ -107,6 +132,14 @@ public: void addCustomField(const QString& key, const QString& value); void removeCustomField(const QString& key); void setUpdateDatetime(bool value); + /* + * Copy all attributes from other except: + * - Group pointers/uuids + * - Master key changed date + * - Custom icons + * - Custom fields + */ + void copyAttributesFrom(const Metadata* other); Q_SIGNALS: void nameTextChanged(); @@ -116,27 +149,11 @@ private: template bool set(P& property, const V& value); template bool set(P& property, const V& value, QDateTime& dateTime); - QString m_generator; - QString m_name; - QDateTime m_nameChanged; - QString m_description; - QDateTime m_descriptionChanged; - QString m_defaultUserName; - QDateTime m_defaultUserNameChanged; - int m_maintenanceHistoryDays; - QColor m_color; - - bool m_protectTitle; - bool m_protectUsername; - bool m_protectPassword; - bool m_protectUrl; - bool m_protectNotes; - // bool m_autoEnableVisualHiding; + MetadataData m_data; QHash m_customIcons; QList m_customIconsOrder; - bool m_recycleBinEnabled; QPointer m_recycleBin; QDateTime m_recycleBinChanged; QPointer m_entryTemplatesGroup; @@ -145,10 +162,6 @@ private: QPointer m_lastTopVisibleGroup; QDateTime m_masterKeyChanged; - int m_masterKeyChangeRec; - int m_masterKeyChangeForce; - int m_historyMaxItems; - int m_historyMaxSize; QHash m_customFields; diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 65d4eeda3..86b55b706 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -537,4 +537,48 @@ void TestGroup::testCopyCustomIcons() QCOMPARE(metaTarget->customIcon(group2Icon).pixel(0, 0), qRgb(4, 5, 6)); } +void TestGroup::testExportToDb() +{ + QImage iconImage(1, 1, QImage::Format_RGB32); + iconImage.setPixel(0, 0, qRgb(1, 2, 3)); + Uuid iconUuid = Uuid::random(); + + QImage iconUnusedImage(1, 1, QImage::Format_RGB32); + iconUnusedImage.setPixel(0, 0, qRgb(1, 2, 3)); + Uuid iconUnusedUuid = Uuid::random(); + + Database* dbOrg = new Database(); + Group* groupOrg = new Group(); + groupOrg->setParent(dbOrg->rootGroup()); + groupOrg->setName("GTEST"); + Entry* entryOrg = new Entry(); + entryOrg->setGroup(groupOrg); + entryOrg->setTitle("ETEST"); + dbOrg->metadata()->addCustomIcon(iconUuid, iconImage); + dbOrg->metadata()->addCustomIcon(iconUnusedUuid, iconUnusedImage); + entryOrg->setIcon(iconUuid); + entryOrg->beginUpdate(); + entryOrg->setIcon(Entry::DefaultIconNumber); + entryOrg->endUpdate(); + + Database* dbExp = groupOrg->exportToDb(); + QCOMPARE(dbExp->rootGroup()->children().size(), 1); + Group* groupExp = dbExp->rootGroup()->children().first(); + QVERIFY(groupExp != groupOrg); + QCOMPARE(groupExp->name(), groupOrg->name()); + QCOMPARE(groupExp->entries().size(), 1); + + Entry* entryExp = groupExp->entries().first(); + QCOMPARE(entryExp->title(), entryOrg->title()); + QCOMPARE(dbExp->metadata()->customIcons().size(), 1); + QVERIFY(dbExp->metadata()->containsCustomIcon(iconUuid)); + QCOMPARE(entryExp->iconNumber(), entryOrg->iconNumber()); + + QCOMPARE(entryExp->historyItems().size(), 1); + QCOMPARE(entryExp->historyItems().first()->iconUuid(), iconUuid); + + delete dbOrg; + delete dbExp; +} + QTEST_GUILESS_MAIN(TestGroup) diff --git a/tests/TestGroup.h b/tests/TestGroup.h index 40351468b..895c2cc5a 100644 --- a/tests/TestGroup.h +++ b/tests/TestGroup.h @@ -35,6 +35,7 @@ private Q_SLOTS: void testAndConcatenationInSearch(); void testClone(); void testCopyCustomIcons(); + void testExportToDb(); }; #endif // KEEPASSX_TESTGROUP_H