From 31796d33fb8a9b48632f53079a2388fc9c1b4558 Mon Sep 17 00:00:00 2001 From: Sebastian Nohn Date: Sun, 17 Nov 2013 13:38:42 +0100 Subject: [PATCH 01/10] ignore build dir --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 77211ffa6..2e9cb860c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ CMakeLists.txt.* +build/ From 1f47033835c177b9172aa970e61817185c61d7a1 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Thu, 4 Jul 2013 13:31:38 +0200 Subject: [PATCH 02/10] Make sure icon() and iconPixmap() never crash. --- src/core/Entry.cpp | 15 +++++++++++---- src/core/Group.cpp | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 7848300a8..39c9ad285 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -94,8 +94,14 @@ QImage Entry::icon() const return databaseIcons()->icon(m_data.iconNumber); } else { - // TODO: check if database() is 0 - return database()->metadata()->customIcon(m_data.customIcon); + Q_ASSERT(database()); + + if (database()) { + return database()->metadata()->customIcon(m_data.customIcon); + } + else { + return QImage(); + } } } @@ -105,9 +111,10 @@ QPixmap Entry::iconPixmap() const return databaseIcons()->iconPixmap(m_data.iconNumber); } else { + Q_ASSERT(database()); + QPixmap pixmap; - if (!QPixmapCache::find(m_pixmapCacheKey, &pixmap)) { - // TODO: check if database() is 0 + if (database() && !QPixmapCache::find(m_pixmapCacheKey, &pixmap)) { pixmap = QPixmap::fromImage(database()->metadata()->customIcon(m_data.customIcon)); m_pixmapCacheKey = QPixmapCache::insert(pixmap); } diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 0868a82ad..1142adf15 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -115,8 +115,14 @@ QImage Group::icon() const return databaseIcons()->icon(m_data.iconNumber); } else { - // TODO: check if m_db is 0 - return m_db->metadata()->customIcon(m_data.customIcon); + Q_ASSERT(m_db); + + if (m_db) { + return m_db->metadata()->customIcon(m_data.customIcon); + } + else { + return QImage(); + } } } @@ -126,9 +132,10 @@ QPixmap Group::iconPixmap() const return databaseIcons()->iconPixmap(m_data.iconNumber); } else { + Q_ASSERT(m_db); + QPixmap pixmap; - if (!QPixmapCache::find(m_pixmapCacheKey, &pixmap)) { - // TODO: check if m_db is 0 + if (m_db && !QPixmapCache::find(m_pixmapCacheKey, &pixmap)) { pixmap = QPixmap::fromImage(m_db->metadata()->customIcon(m_data.customIcon)); m_pixmapCacheKey = QPixmapCache::insert(pixmap); } From 74e912ccd3fbbb3aecb4eacfa7ca6efa07ef87ca Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Thu, 4 Jul 2013 13:41:51 +0200 Subject: [PATCH 03/10] Remember the dir when opening/saving attachments. --- src/gui/entry/EditEntryWidget.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 7bf4c62ed..a80267790 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -26,6 +26,7 @@ #include #include +#include "core/Config.h" #include "core/Database.h" #include "core/Entry.h" #include "core/Metadata.h" @@ -605,9 +606,11 @@ void EditEntryWidget::insertAttachment() { Q_ASSERT(!m_history); - // TODO: save last used dir - QString filename = fileDialog()->getOpenFileName(this, tr("Select file"), - QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); + QString defaultDir = config()->get("LastAttachmentDir").toString(); + if (defaultDir.isEmpty() || !QDir(defaultDir).exists()) { + defaultDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + } + QString filename = fileDialog()->getOpenFileName(this, tr("Select file"), defaultDir); if (filename.isEmpty() || !QFile::exists(filename)) { return; } @@ -637,8 +640,11 @@ void EditEntryWidget::saveCurrentAttachment() } QString filename = m_attachmentsModel->keyByIndex(index); - // TODO: save last used dir - QDir dir(QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation)); + QString defaultDirName = config()->get("LastAttachmentDir").toString(); + if (defaultDirName.isEmpty() || !QDir(defaultDirName).exists()) { + defaultDirName = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); + } + QDir dir(defaultDirName); QString savePath = fileDialog()->getSaveFileName(this, tr("Save attachment"), dir.filePath(filename)); if (!savePath.isEmpty()) { From cb804eb143922d0ac7b7272345b75f125de5ba22 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Thu, 4 Jul 2013 13:59:32 +0200 Subject: [PATCH 04/10] Document clone() methods. --- src/core/Entry.h | 6 ++++++ src/core/Group.cpp | 3 --- src/core/Group.h | 7 +++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/core/Entry.h b/src/core/Entry.h index d4a52933f..4343c1406 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -110,6 +110,12 @@ public: void addHistoryItem(Entry* entry); void removeHistoryItems(const QList& historyEntries); void truncateHistory(); + /** + * Creates a duplicate of this entry except that returned entry isn't part + * of any group and all TimeInfo attributes are set to the current time. + * Note that you need to copy the custom icons manually when inserting the + * new entry into another database. + */ Entry* clone() const; void copyDataFrom(const Entry* other); QString resolvePlaceholders(const QString& str) const; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 1142adf15..4fffe7182 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -466,9 +466,6 @@ QSet Group::customIconsRecursive() const Group* Group::clone() const { - // TODO: what to do about custom icons? - // they won't be available when changing the database later - Group* clonedGroup = new Group(); clonedGroup->setUpdateTimeinfo(false); diff --git a/src/core/Group.h b/src/core/Group.h index b1a51d181..09449620f 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -100,6 +100,13 @@ public: QList entriesRecursive(bool includeHistoryItems = false) const; QList groupsRecursive(bool includeSelf) const; QSet customIconsRecursive() const; + /** + * Creates a duplicate of this group including all child entries and groups. + * The exceptions are that the returned group doesn't have a parent group + * and all TimeInfo attributes are set to the current time. + * Note that you need to copy the custom icons manually when inserting the + * new group into another database. + */ Group* clone() const; void copyDataFrom(const Group* other); From f2dfef8c41b263901d5b5c44bc68f42117ede933 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 22 Nov 2013 13:27:49 +0100 Subject: [PATCH 05/10] Add flags to Entry::clone() for customized cloning. --- src/core/Entry.cpp | 32 ++++++++++++++++++------ src/core/Entry.h | 17 ++++++++++--- src/core/Group.cpp | 2 +- src/gui/DatabaseWidget.cpp | 2 +- src/gui/group/GroupModel.cpp | 2 +- tests/TestEntry.cpp | 48 ++++++++++++++++++++++++++++++++++++ tests/TestEntry.h | 2 ++ tests/TestGroup.cpp | 6 ++++- 8 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 39c9ad285..41616cb82 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -439,22 +439,40 @@ void Entry::truncateHistory() } } -Entry* Entry::clone() const +Entry* Entry::clone(CloneFlags flags) const { Entry* entry = new Entry(); entry->setUpdateTimeinfo(false); - entry->m_uuid = Uuid::random(); + if (flags & CloneNewUuid) { + entry->m_uuid = Uuid::random(); + } + else { + entry->m_uuid = m_uuid; + } entry->m_data = m_data; entry->m_attributes->copyDataFrom(m_attributes); entry->m_attachments->copyDataFrom(m_attachments); entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations); + if (flags & CloneIncludeHistory) { + Q_FOREACH (Entry* historyItem, m_history) { + Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid); + historyItemClone->setUpdateTimeinfo(false); + historyItemClone->setUuid(entry->uuid()); + historyItemClone->setUpdateTimeinfo(true); + entry->addHistoryItem(historyItemClone); + } + } entry->setUpdateTimeinfo(true); - QDateTime now = Tools::currentDateTimeUtc(); - entry->m_data.timeInfo.setCreationTime(now); - entry->m_data.timeInfo.setLastModificationTime(now); - entry->m_data.timeInfo.setLastAccessTime(now); - entry->m_data.timeInfo.setLocationChanged(now); + if (flags & CloneResetTimeInfo) { + QDateTime now = Tools::currentDateTimeUtc(); + entry->m_data.timeInfo.setCreationTime(now); + entry->m_data.timeInfo.setLastModificationTime(now); + entry->m_data.timeInfo.setLastAccessTime(now); + entry->m_data.timeInfo.setLocationChanged(now); + } + + return entry; } diff --git a/src/core/Entry.h b/src/core/Entry.h index 4343c1406..c2c2938c1 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -110,13 +110,22 @@ public: void addHistoryItem(Entry* entry); void removeHistoryItems(const QList& historyEntries); void truncateHistory(); + + enum CloneFlag { + CloneNoFlags = 0, + CloneNewUuid = 1, // generate a random uuid for the clone + CloneResetTimeInfo = 2, // set all TimeInfo attributes to the current time + CloneIncludeHistory = 4 // clone the history items + }; + Q_DECLARE_FLAGS(CloneFlags, CloneFlag) + /** - * Creates a duplicate of this entry except that returned entry isn't part - * of any group and all TimeInfo attributes are set to the current time. + * 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() const; + Entry* clone(CloneFlags flags) const; void copyDataFrom(const Entry* other); QString resolvePlaceholders(const QString& str) const; @@ -166,4 +175,6 @@ private: bool m_updateTimeinfo; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(Entry::CloneFlags) + #endif // KEEPASSX_ENTRY_H diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 4fffe7182..9c192a831 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -474,7 +474,7 @@ Group* Group::clone() const clonedGroup->m_data = m_data; Q_FOREACH (Entry* entry, entries()) { - Entry* clonedEntry = entry->clone(); + Entry* clonedEntry = entry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo); clonedEntry->setGroup(clonedGroup); } diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index d6484478d..8c635a70f 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -224,7 +224,7 @@ void DatabaseWidget::cloneEntry() return; } - Entry* entry = currentEntry->clone(); + Entry* entry = currentEntry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo); entry->setGroup(currentEntry->group()); m_entryView->setFocus(); m_entryView->setCurrentEntry(entry); diff --git a/src/gui/group/GroupModel.cpp b/src/gui/group/GroupModel.cpp index 73b9a59d9..b33a5ff54 100644 --- a/src/gui/group/GroupModel.cpp +++ b/src/gui/group/GroupModel.cpp @@ -298,7 +298,7 @@ bool GroupModel::dropMimeData(const QMimeData* data, Qt::DropAction action, entry = dragEntry; } else { - entry = dragEntry->clone(); + entry = dragEntry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo); } Database* sourceDb = dragEntry->group()->database(); diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index e3c46b100..9c027b6a2 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -21,6 +21,12 @@ #include "tests.h" #include "core/Entry.h" +#include "crypto/Crypto.h" + +void TestEntry::initTestCase() +{ + Crypto::init(); +} void TestEntry::testHistoryItemDeletion() { @@ -74,4 +80,46 @@ void TestEntry::testCopyDataFrom() QCOMPARE(entry2->autoTypeAssociations()->get(1).window, QString("3")); } +void TestEntry::testClone() +{ + Entry* entryOrg = new Entry(); + entryOrg->setUuid(Uuid::random()); + entryOrg->setTitle("Original Title"); + entryOrg->beginUpdate(); + entryOrg->setTitle("New Title"); + entryOrg->endUpdate(); + TimeInfo entryOrgTime = entryOrg->timeInfo(); + QDateTime dateTime; + dateTime.setTimeSpec(Qt::UTC); + dateTime.setMSecsSinceEpoch(60); + entryOrgTime.setCreationTime(dateTime); + entryOrg->setTimeInfo(entryOrgTime); + + Entry* entryCloneNone = entryOrg->clone(Entry::CloneNoFlags); + QCOMPARE(entryCloneNone->uuid(), entryOrg->uuid()); + QCOMPARE(entryCloneNone->title(), QString("New Title")); + QCOMPARE(entryCloneNone->historyItems().size(), 0); + QCOMPARE(entryCloneNone->timeInfo().creationTime(), entryOrg->timeInfo().creationTime()); + + Entry* entryCloneNewUuid = entryOrg->clone(Entry::CloneNewUuid); + QVERIFY(entryCloneNewUuid->uuid() != entryOrg->uuid()); + QVERIFY(!entryCloneNewUuid->uuid().isNull()); + QCOMPARE(entryCloneNewUuid->title(), QString("New Title")); + QCOMPARE(entryCloneNewUuid->historyItems().size(), 0); + QCOMPARE(entryCloneNewUuid->timeInfo().creationTime(), entryOrg->timeInfo().creationTime()); + + Entry* entryCloneResetTime = entryOrg->clone(Entry::CloneResetTimeInfo); + QCOMPARE(entryCloneNone->uuid(), entryOrg->uuid()); + QCOMPARE(entryCloneResetTime->title(), QString("New Title")); + QCOMPARE(entryCloneResetTime->historyItems().size(), 0); + QVERIFY(entryCloneResetTime->timeInfo().creationTime() != entryOrg->timeInfo().creationTime()); + + Entry* entryCloneHistory = entryOrg->clone(Entry::CloneIncludeHistory); + QCOMPARE(entryCloneNone->uuid(), entryOrg->uuid()); + QCOMPARE(entryCloneHistory->title(), QString("New Title")); + QCOMPARE(entryCloneHistory->historyItems().size(), 1); + QCOMPARE(entryCloneHistory->historyItems().first()->title(), QString("Original Title")); + QCOMPARE(entryCloneHistory->timeInfo().creationTime(), entryOrg->timeInfo().creationTime()); +} + QTEST_GUILESS_MAIN(TestEntry) diff --git a/tests/TestEntry.h b/tests/TestEntry.h index fe303a609..ed772d505 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -27,8 +27,10 @@ class TestEntry : public QObject Q_OBJECT private Q_SLOTS: + void initTestCase(); void testHistoryItemDeletion(); void testCopyDataFrom(); + void testClone(); }; #endif // KEEPASSX_TESTENTRY_H diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 22845af11..65d4eeda3 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -441,8 +441,11 @@ void TestGroup::testClone() Entry* originalGroupEntry = new Entry(); originalGroupEntry->setGroup(originalGroup); - originalGroupEntry->setTitle("GroupEntry"); + originalGroupEntry->setTitle("GroupEntryOld"); originalGroupEntry->setIcon(43); + originalGroupEntry->beginUpdate(); + originalGroupEntry->setTitle("GroupEntry"); + originalGroupEntry->endUpdate(); Group* subGroup = new Group(); subGroup->setParent(originalGroup); @@ -465,6 +468,7 @@ void TestGroup::testClone() QVERIFY(clonedGroupEntry->uuid() != originalGroupEntry->uuid()); QCOMPARE(clonedGroupEntry->title(), QString("GroupEntry")); QCOMPARE(clonedGroupEntry->iconNumber(), 43); + QCOMPARE(clonedGroupEntry->historyItems().size(), 0); Group* clonedSubGroup = clonedGroup->children().at(0); QVERIFY(clonedSubGroup->uuid() != subGroup->uuid()); From a992c76d6afcfb3277add8d9ef263f34c21ddaff Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 22 Nov 2013 13:34:34 +0100 Subject: [PATCH 06/10] Allow passing entry cloning flags to Group::clone(). --- src/core/Group.cpp | 4 ++-- src/core/Group.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 9c192a831..9199389ec 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -464,7 +464,7 @@ QSet Group::customIconsRecursive() const return result; } -Group* Group::clone() const +Group* Group::clone(Entry::CloneFlags entryFlags) const { Group* clonedGroup = new Group(); @@ -474,7 +474,7 @@ Group* Group::clone() const clonedGroup->m_data = m_data; Q_FOREACH (Entry* entry, entries()) { - Entry* clonedEntry = entry->clone(Entry::CloneNewUuid | Entry::CloneResetTimeInfo); + Entry* clonedEntry = entry->clone(entryFlags); clonedEntry->setGroup(clonedGroup); } diff --git a/src/core/Group.h b/src/core/Group.h index 09449620f..9480c6f16 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -107,7 +107,7 @@ public: * Note that you need to copy the custom icons manually when inserting the * new group into another database. */ - Group* clone() const; + Group* clone(Entry::CloneFlags entryFlags = Entry::CloneNewUuid | Entry::CloneResetTimeInfo) const; void copyDataFrom(const Group* other); QList search(const QString& searchTerm, Qt::CaseSensitivity caseSensitivity, From 98c821df05f7032f26c96c582ff36674fab526e6 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Fri, 22 Nov 2013 10:28:11 +0100 Subject: [PATCH 07/10] Add Group::exportToDb(). --- src/core/Database.cpp | 49 ++++++++++-------- src/core/Database.h | 22 ++++---- src/core/Group.cpp | 16 ++++++ src/core/Group.h | 1 + src/core/Metadata.cpp | 114 ++++++++++++++++++++++-------------------- src/core/Metadata.h | 55 ++++++++++++-------- tests/TestGroup.cpp | 44 ++++++++++++++++ tests/TestGroup.h | 1 + 8 files changed, 197 insertions(+), 105 deletions(-) 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 From 66b3d2204197f5946c09ced670e48ab981115122 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 24 Nov 2013 21:19:20 +0100 Subject: [PATCH 08/10] Use QString::toLatin1() rather than ::toAscii() The toAscii (and fromAscii) are removed from Qt5 in favor of Latin1. --- src/core/Tools.cpp | 2 +- src/core/Uuid.cpp | 6 +++--- src/format/KeePass2XmlReader.cpp | 4 ++-- src/format/KeePass2XmlWriter.cpp | 6 +++--- src/keys/FileKey.cpp | 4 ++-- tests/TestCryptoHash.cpp | 6 +++--- tests/TestKeePass2XmlReader.cpp | 4 ++-- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp index 37ef50c42..01ec316e2 100644 --- a/src/core/Tools.cpp +++ b/src/core/Tools.cpp @@ -141,7 +141,7 @@ QString imageReaderFilter() } } - formatsStringList.append("*." + QString::fromAscii(format).toLower()); + formatsStringList.append("*." + QString::fromLatin1(format).toLower()); } return formatsStringList.join(" "); diff --git a/src/core/Uuid.cpp b/src/core/Uuid.cpp index e832d1e84..700f59641 100644 --- a/src/core/Uuid.cpp +++ b/src/core/Uuid.cpp @@ -42,12 +42,12 @@ Uuid Uuid::random() QString Uuid::toBase64() const { - return QString::fromAscii(m_data.toBase64()); + return QString::fromLatin1(m_data.toBase64()); } QString Uuid::toHex() const { - return QString::fromAscii(m_data.toHex()); + return QString::fromLatin1(m_data.toHex()); } QByteArray Uuid::toByteArray() const @@ -85,7 +85,7 @@ bool Uuid::operator!=(const Uuid& other) const Uuid Uuid::fromBase64(const QString& str) { - QByteArray data = QByteArray::fromBase64(str.toAscii()); + QByteArray data = QByteArray::fromBase64(str.toLatin1()); return Uuid(data); } diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index 6e9aa582d..383269f68 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -779,7 +779,7 @@ void KeePass2XmlReader::parseEntryString(Entry* entry) if (isProtected && !value.isEmpty()) { if (m_randomStream) { - value = QString::fromUtf8(m_randomStream->process(QByteArray::fromBase64(value.toAscii()))); + value = QString::fromUtf8(m_randomStream->process(QByteArray::fromBase64(value.toLatin1()))); } else { raiseError("Unable to decrypt entry string"); @@ -1053,7 +1053,7 @@ Uuid KeePass2XmlReader::readUuid() QByteArray KeePass2XmlReader::readBinary() { - return QByteArray::fromBase64(readString().toAscii()); + return QByteArray::fromBase64(readString().toLatin1()); } QByteArray KeePass2XmlReader::readCompressedBinary() diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp index fa7c4d956..603649812 100644 --- a/src/format/KeePass2XmlWriter.cpp +++ b/src/format/KeePass2XmlWriter.cpp @@ -192,7 +192,7 @@ void KeePass2XmlWriter::writeBinaries() } if (!data.isEmpty()) { - m_xml.writeCharacters(QString::fromAscii(data.toBase64())); + m_xml.writeCharacters(QString::fromLatin1(data.toBase64())); } m_xml.writeEndElement(); } @@ -341,7 +341,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) if (m_randomStream) { m_xml.writeAttribute("Protected", "True"); QByteArray rawData = m_randomStream->process(entry->attributes()->value(key).toUtf8()); - value = QString::fromAscii(rawData.toBase64()); + value = QString::fromLatin1(rawData.toBase64()); } else { m_xml.writeAttribute("ProtectInMemory", "True"); @@ -485,7 +485,7 @@ void KeePass2XmlWriter::writeUuid(const QString& qualifiedName, const Entry* ent void KeePass2XmlWriter::writeBinary(const QString& qualifiedName, const QByteArray& ba) { - writeString(qualifiedName, QString::fromAscii(ba.toBase64())); + writeString(qualifiedName, QString::fromLatin1(ba.toBase64())); } void KeePass2XmlWriter::writeColor(const QString& qualifiedName, const QColor& color) diff --git a/src/keys/FileKey.cpp b/src/keys/FileKey.cpp index e8cf2697e..f03a69536 100644 --- a/src/keys/FileKey.cpp +++ b/src/keys/FileKey.cpp @@ -122,7 +122,7 @@ void FileKey::create(QIODevice* device) xmlWriter.writeStartElement("Key"); QByteArray data = randomGen()->randomArray(32); - xmlWriter.writeTextElement("Data", QString::fromAscii(data.toBase64())); + xmlWriter.writeTextElement("Data", QString::fromLatin1(data.toBase64())); xmlWriter.writeEndElement(); @@ -211,7 +211,7 @@ QByteArray FileKey::loadXmlKey(QXmlStreamReader& xmlReader) while (!xmlReader.error() && xmlReader.readNextStartElement()) { if (xmlReader.name() == "Data") { // TODO: do we need to enforce a specific data.size()? - data = QByteArray::fromBase64(xmlReader.readElementText().toAscii()); + data = QByteArray::fromBase64(xmlReader.readElementText().toLatin1()); } } diff --git a/tests/TestCryptoHash.cpp b/tests/TestCryptoHash.cpp index 8ff3c367d..4f258a179 100644 --- a/tests/TestCryptoHash.cpp +++ b/tests/TestCryptoHash.cpp @@ -37,13 +37,13 @@ void TestCryptoHash::test() QCOMPARE(cryptoHash1.result(), QByteArray::fromHex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")); - QByteArray source2 = QString("KeePassX").toAscii(); + QByteArray source2 = QString("KeePassX").toLatin1(); QByteArray result2 = CryptoHash::hash(source2, CryptoHash::Sha256); QCOMPARE(result2, QByteArray::fromHex("0b56e5f65263e747af4a833bd7dd7ad26a64d7a4de7c68e52364893dca0766b4")); CryptoHash cryptoHash3(CryptoHash::Sha256); - cryptoHash3.addData(QString("KeePa").toAscii()); - cryptoHash3.addData(QString("ssX").toAscii()); + cryptoHash3.addData(QString("KeePa").toLatin1()); + cryptoHash3.addData(QString("ssX").toLatin1()); QCOMPARE(cryptoHash3.result(), QByteArray::fromHex("0b56e5f65263e747af4a833bd7dd7ad26a64d7a4de7c68e52364893dca0766b4")); } diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index 3f338fd46..ca57db958 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -33,7 +33,7 @@ namespace QTest { char* toString(const Uuid& uuid) { QByteArray ba = "Uuid("; - ba += uuid.toBase64().toAscii().constData(); + ba += uuid.toBase64().toLatin1().constData(); ba += ")"; return qstrdup(ba.constData()); } @@ -296,7 +296,7 @@ void TestKeePass2XmlReader::testEntry2() QVERIFY(attrs.isEmpty()); QCOMPARE(entry->attachments()->keys().size(), 1); - QCOMPARE(QString::fromAscii(entry->attachments()->value("myattach.txt")), QString("abcdefghijk")); + QCOMPARE(QString::fromLatin1(entry->attachments()->value("myattach.txt")), QString("abcdefghijk")); QCOMPARE(entry->autoTypeEnabled(), true); QCOMPARE(entry->autoTypeObfuscation(), 1); From 2fcc369c414f5d218bf8789774fd4caa5474bc9c Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Sun, 24 Nov 2013 21:40:19 +0100 Subject: [PATCH 09/10] Enable the foritfy source build flag only for optimized builds. https://github.com/keepassx/keepassx/pull/27 --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ec602313..b128c85dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ endmacro(add_gcc_compiler_flags) add_definitions(-DQT_NO_KEYWORDS -DQT_NO_EXCEPTIONS -DQT_NO_STL -DQT_STRICT_ITERATORS -DQT_NO_CAST_TO_ASCII) -add_gcc_compiler_flags("-fno-common -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2") +add_gcc_compiler_flags("-fno-common -fstack-protector --param=ssp-buffer-size=4") add_gcc_compiler_flags("-Wall -Wextra -Wundef -Wpointer-arith -Wno-long-long") add_gcc_compiler_flags("-Wformat=2 -Wmissing-format-attribute") add_gcc_compiler_flags("-fvisibility=hidden") @@ -68,6 +68,11 @@ add_gcc_compiler_cxxflags("-fno-exceptions -fno-rtti") add_gcc_compiler_cxxflags("-Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual") add_gcc_compiler_cflags("-Wchar-subscripts -Wwrite-strings") +string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) +if (CMAKE_BUILD_TYPE_LOWER MATCHES (release|relwithdebinfo|minsizerel)) + add_gcc_compiler_flags("-D_FORTIFY_SOURCE=2") +endif() + check_c_compiler_flag("-Werror=format-security -Werror=implicit-function-declaration" WERROR_C_AVAILABLE) check_cxx_compiler_flag("-Werror=format-security" WERROR_CXX_AVAILABLE) if(WERROR_C_AVAILABLE AND WERROR_CXX_AVAILABLE) From 47b7befd2fb5b006b64f73399a433a6c89eabf1c Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Sun, 24 Nov 2013 22:09:52 +0100 Subject: [PATCH 10/10] Set default build type to RelWithDebInfo. --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b128c85dc..eccd81490 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo Debug Debugfull Profile MinSizeRel." + FORCE) +endif() + project(KeePassX) cmake_minimum_required(VERSION 2.6.4)