diff --git a/README.md b/README.md index ded021d4b..d15ddccac 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,13 @@ The following libraries are required: * zlib * libmicrohttpd * QJSON +* libxtst (optional for auto-type on X11) + +On Debian you can install them with: + +```bash +sudo apt-get install build-essential cmake libqt4-dev libgcrypt11-dev zlib1g-dev +``` #### Build Steps diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index 0e2b7fa99..6a276d97c 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -20,12 +20,12 @@ file(GLOB DATABASE_ICONS icons/database/*.png) install(FILES ${DATABASE_ICONS} DESTINATION ${DATA_INSTALL_DIR}/icons/database) if(UNIX AND NOT APPLE) - install(DIRECTORY icons/application/ DESTINATION share/icons/hicolor + install(DIRECTORY icons/application/ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor FILES_MATCHING PATTERN "keepassx.png" PATTERN "keepassx.svgz") - install(DIRECTORY icons/application/ DESTINATION share/icons/hicolor + install(DIRECTORY icons/application/ DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor FILES_MATCHING PATTERN "application-x-keepassx.png" PATTERN "application-x-keepassx.svgz") - install(FILES linux/keepassx.desktop DESTINATION share/applications) - install(FILES linux/keepassx.xml DESTINATION share/mime/packages) + install(FILES linux/keepassx.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) + install(FILES linux/keepassx.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages) endif(UNIX AND NOT APPLE) if(APPLE) diff --git a/src/core/Config.cpp b/src/core/Config.cpp index 48ea9f333..046a0fe50 100644 --- a/src/core/Config.cpp +++ b/src/core/Config.cpp @@ -89,6 +89,7 @@ void Config::init(const QString& fileName) m_settings.reset(new QSettings(fileName, QSettings::IniFormat)); m_defaults.insert("RememberLastDatabases", true); + m_defaults.insert("RememberLastKeyFiles", true); m_defaults.insert("OpenPreviousDatabasesOnStartup", true); m_defaults.insert("AutoSaveAfterEveryChange", false); m_defaults.insert("AutoSaveOnExit", false); diff --git a/src/core/Database.h b/src/core/Database.h index 0ee9a9659..3e0c675df 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -69,7 +69,7 @@ public: * Sets group as the root group and takes ownership of it. * Warning: Be careful when calling this method as it doesn't * emit any notifications so e.g. models aren't updated. - * The caller is responsible for cleaning up the pervious + * The caller is responsible for cleaning up the previous root group. */ void setRootGroup(Group* group); diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index 13c3c20ee..bf3076e85 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -173,6 +173,24 @@ bool Crypto::selfTest() return false; } + // Twofish + cipherText = QByteArray::fromHex("e0227c3cc80f3cb1b2ed847cc6f57d3c"); + cipherText.append(QByteArray::fromHex("657b1e7960b30fb7c8d62e72ae37c3a0")); + + SymmetricCipher twofishEncrypt(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, key, iv); + if (twofishEncrypt.process(plainText) != cipherText) { + m_errorStr = "Twofish encryption mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + + SymmetricCipher twofishDecrypt(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, key, iv); + if (twofishDecrypt.process(cipherText) != plainText) { + m_errorStr = "Twofish decryption mismatch."; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + return false; + } + QByteArray salsa20Key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112"); QByteArray salsa20iv = QByteArray::fromHex("0000000000000000"); QByteArray salsa20Plain = QByteArray::fromHex("00000000000000000000000000000000"); diff --git a/src/crypto/salsa20/ecrypt-config.h b/src/crypto/salsa20/ecrypt-config.h index 57c33a42c..0914fbc76 100644 --- a/src/crypto/salsa20/ecrypt-config.h +++ b/src/crypto/salsa20/ecrypt-config.h @@ -9,50 +9,13 @@ /* Guess the endianness of the target architecture. */ -/* - * The LITTLE endian machines: - */ -#if defined(__ultrix) /* Older MIPS */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__alpha) /* Alpha */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(i386) /* x86 (gcc) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__i386) /* x86 (gcc) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__x86_64) /* x86_64 (gcc) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(_M_IX86) /* x86 (MSC, Borland) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(_MSC_VER) /* x86 (surely MSC) */ -#define ECRYPT_LITTLE_ENDIAN -#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ -#define ECRYPT_LITTLE_ENDIAN +#include -/* - * The BIG endian machines: - */ -#elif defined(__sparc) /* Newer Sparc's */ +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN +#define ECRYPT_LITTLE_ENDIAN +#elif Q_BYTE_ORDER == Q_BIG_ENDIAN #define ECRYPT_BIG_ENDIAN -#elif defined(__powerpc__) /* PowerPC */ -#define ECRYPT_BIG_ENDIAN -#elif defined(__ppc__) /* PowerPC */ -#define ECRYPT_BIG_ENDIAN -#elif defined(__hppa) /* HP-PA */ -#define ECRYPT_BIG_ENDIAN - -/* - * Finally machines with UNKNOWN endianness: - */ -#elif defined (_AIX) /* RS6000 */ -#define ECRYPT_UNKNOWN -#elif defined(__aux) /* 68K */ -#define ECRYPT_UNKNOWN -#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ -#define ECRYPT_UNKNOWN -#elif defined(__sgi) /* Newer MIPS */ -#define ECRYPT_UNKNOWN -#else /* Any other processor */ +#else #define ECRYPT_UNKNOWN #endif diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index d1737d52a..a5ceb2186 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -699,7 +699,7 @@ Entry* KeePass2XmlReader::parseEntry(bool history) int iconId = readNumber(); if (iconId < 0) { if (m_strictMode) { - raiseError("Invalud entry icon number"); + raiseError("Invalid entry icon number"); } } else { @@ -862,7 +862,7 @@ QPair KeePass2XmlReader::parseEntryBinary(Entry* entry) m_xml.skipCurrentElement(); } else { - // format compatbility + // format compatibility value = readBinary(); bool isProtected = attr.hasAttribute("Protected") && (attr.value("Protected") == "True"); diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 81c195712..717326a98 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -67,10 +67,12 @@ void DatabaseOpenWidget::load(const QString& filename) m_ui->labelFilename->setText(filename); - QHash lastKeyFiles = config()->get("LastKeyFiles").toHash(); - if (lastKeyFiles.contains(m_filename)) { - m_ui->checkKeyFile->setChecked(true); - m_ui->comboKeyFile->addItem(lastKeyFiles[m_filename].toString()); + if (config()->get("RememberLastKeyFiles").toBool()) { + QHash lastKeyFiles = config()->get("LastKeyFiles").toHash(); + if (lastKeyFiles.contains(m_filename)) { + m_ui->checkKeyFile->setChecked(true); + m_ui->comboKeyFile->addItem(lastKeyFiles[m_filename].toString()); + } } m_ui->editPassword->setFocus(); @@ -148,7 +150,9 @@ CompositeKey DatabaseOpenWidget::databaseKey() lastKeyFiles.remove(m_filename); } - config()->set("LastKeyFiles", lastKeyFiles); + if (config()->get("RememberLastKeyFiles").toBool()) { + config()->set("LastKeyFiles", lastKeyFiles); + } return masterKey; } diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index db9e034a7..f55269fd5 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -563,7 +563,7 @@ void DatabaseTabWidget::lockDatabases() QMessageBox::StandardButton result = MessageBox::question( this, tr("Lock database"), - tr("This database has never been saved.\nYou can save the dabatase or stop locking it."), + tr("This database has never been saved.\nYou can save the database or stop locking it."), QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel); if (result == QMessageBox::Save) { if (!saveDatabase(db)) { diff --git a/src/gui/DialogyWidget.cpp b/src/gui/DialogyWidget.cpp index 349a5eea4..d8e05a911 100644 --- a/src/gui/DialogyWidget.cpp +++ b/src/gui/DialogyWidget.cpp @@ -46,7 +46,9 @@ void DialogyWidget::keyPressEvent(QKeyEvent* e) break; case Qt::Key_Escape: if (!clickButton(QDialogButtonBox::Cancel)) { - e->ignore(); + if (!clickButton(QDialogButtonBox::Close)) { + e->ignore(); + } } break; default: diff --git a/src/gui/EditWidget.cpp b/src/gui/EditWidget.cpp index 831db54b4..b3d9842be 100644 --- a/src/gui/EditWidget.cpp +++ b/src/gui/EditWidget.cpp @@ -23,6 +23,7 @@ EditWidget::EditWidget(QWidget* parent) , m_ui(new Ui::EditWidget()) { m_ui->setupUi(this); + setReadOnly(false); QFont headerLabelFont = m_ui->headerLabel->font(); headerLabelFont.setBold(true); @@ -68,3 +69,20 @@ QLabel* EditWidget::headlineLabel() { return m_ui->headerLabel; } + +void EditWidget::setReadOnly(bool readOnly) +{ + m_readOnly = readOnly; + + if (readOnly) { + m_ui->buttonBox->setStandardButtons(QDialogButtonBox::Close); + } + else { + m_ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + } +} + +bool EditWidget::readOnly() const +{ + return m_readOnly; +} diff --git a/src/gui/EditWidget.h b/src/gui/EditWidget.h index c99acfb1b..d27abe9ba 100644 --- a/src/gui/EditWidget.h +++ b/src/gui/EditWidget.h @@ -41,6 +41,8 @@ public: void setCurrentRow(int index); void setHeadline(const QString& text); QLabel* headlineLabel(); + void setReadOnly(bool readOnly); + bool readOnly() const; Q_SIGNALS: void accepted(); @@ -48,6 +50,7 @@ Q_SIGNALS: private: const QScopedPointer m_ui; + bool m_readOnly; Q_DISABLE_COPY(EditWidget) }; diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index a881e6d78..5b8e9e484 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -105,6 +105,8 @@ MainWindow::MainWindow() autoType()->registerGlobalShortcut(globalAutoTypeKey, globalAutoTypeModifiers); } + m_ui->actionEntryAutoType->setVisible(autoType()->isAvailable()); + m_inactivityTimer = new InactivityTimer(this); connect(m_inactivityTimer, SIGNAL(inactivityDetected()), m_ui->tabWidget, SLOT(lockDatabases())); diff --git a/src/gui/SettingsWidget.cpp b/src/gui/SettingsWidget.cpp index 275720629..01099559c 100644 --- a/src/gui/SettingsWidget.cpp +++ b/src/gui/SettingsWidget.cpp @@ -96,6 +96,7 @@ void SettingsWidget::addSettingsPage(ISettingsPage *page) void SettingsWidget::loadSettings() { m_generalUi->rememberLastDatabasesCheckBox->setChecked(config()->get("RememberLastDatabases").toBool()); + m_generalUi->rememberLastKeyFilesCheckBox->setChecked(config()->get("RememberLastKeyFiles").toBool()); m_generalUi->openPreviousDatabasesOnStartupCheckBox->setChecked( config()->get("OpenPreviousDatabasesOnStartup").toBool()); m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool()); @@ -144,6 +145,7 @@ void SettingsWidget::loadSettings() void SettingsWidget::saveSettings() { config()->set("RememberLastDatabases", m_generalUi->rememberLastDatabasesCheckBox->isChecked()); + config()->set("RememberLastKeyFiles", m_generalUi->rememberLastKeyFilesCheckBox->isChecked()); config()->set("OpenPreviousDatabasesOnStartup", m_generalUi->openPreviousDatabasesOnStartupCheckBox->isChecked()); config()->set("AutoSaveAfterEveryChange", diff --git a/src/gui/SettingsWidgetGeneral.ui b/src/gui/SettingsWidgetGeneral.ui index 04c603a34..6f4ee660c 100644 --- a/src/gui/SettingsWidgetGeneral.ui +++ b/src/gui/SettingsWidgetGeneral.ui @@ -25,75 +25,85 @@ + + + Remember last key files + + + true + + + + Open previous databases on startup - + Automatically save on exit - + Automatically save after every change - + Minimize when copying to clipboard - + Use group icon on entry creation - + Global Auto-Type shortcut - + - + Use entry title to match windows for global auto-type - + Language - + - + Show a system tray icon - + false @@ -114,6 +124,7 @@ rememberLastDatabasesCheckBox + rememberLastKeyFilesCheckBox openPreviousDatabasesOnStartupCheckBox autoSaveOnExitCheckBox autoSaveAfterEveryChangeCheckBox diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index e95f2e79d..beeda2ab8 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -277,6 +277,7 @@ void EditEntryWidget::loadEntry(Entry* entry, bool create, bool history, const Q } setForms(entry); + setReadOnly(m_history); setCurrentRow(0); setRowHidden(m_historyWidget, m_history); @@ -384,10 +385,7 @@ void EditEntryWidget::setForms(const Entry* entry, bool restore) void EditEntryWidget::saveEntry() { if (m_history) { - m_entry = Q_NULLPTR; - m_database = Q_NULLPTR; - m_entryAttributes->clear(); - m_entryAttachments->clear(); + clear(); Q_EMIT editFinished(false); return; } @@ -463,6 +461,7 @@ void EditEntryWidget::cancel() if (m_history) { clear(); Q_EMIT editFinished(false); + return; } if (!m_entry->iconUuid().isNull() && diff --git a/src/streams/qtiocompressor.cpp b/src/streams/qtiocompressor.cpp index 5d815297a..be6ac5dfd 100644 --- a/src/streams/qtiocompressor.cpp +++ b/src/streams/qtiocompressor.cpp @@ -147,7 +147,7 @@ void QtIOCompressorPrivate::flushZlib(int flushMode) /*! \internal - Writes outputSize bytes from buffer to the inderlying device. + Writes outputSize bytes from buffer to the underlying device. */ bool QtIOCompressorPrivate::writeBytes(ZlibByte *buffer, ZlibSize outputSize) { @@ -192,7 +192,7 @@ void QtIOCompressorPrivate::setZlibError(const QString &errorMessage, int zlibEr A QtIOCompressor object is constructed with a pointer to an underlying QIODevice. Data written to the QtIOCompressor object will be compressed before it is written to the underlying - QIODevice. Similary, if you read from the QtIOCompressor object, + QIODevice. Similarly, if you read from the QtIOCompressor object, the data will be read from the underlying device and then decompressed. @@ -251,14 +251,14 @@ void QtIOCompressorPrivate::setZlibError(const QString &errorMessage, int zlibEr \a bufferSize specifies the size of the internal buffer used when reading from and writing to the underlying device. The default value is 65KB. Using a larger value allows for faster compression and - deompression at the expense of memory usage. + decompression at the expense of memory usage. */ QtIOCompressor::QtIOCompressor(QIODevice *device, int compressionLevel, int bufferSize) :d_ptr(new QtIOCompressorPrivate(this, device, compressionLevel, bufferSize)) {} /*! - Destroys the QtIOCompressor, closing it if neccesary. + Destroys the QtIOCompressor, closing it if necessary. */ QtIOCompressor::~QtIOCompressor() { @@ -313,12 +313,12 @@ bool QtIOCompressor::isSequential() const /*! Opens the QtIOCompressor in \a mode. Only ReadOnly and WriteOnly is supported. - This functon will return false if you try to open in other modes. + This function will return false if you try to open in other modes. If the underlying device is not opened, this function will open it in a suitable mode. If this happens the device will also be closed when close() is called. - If the underlying device is already opened, its openmode must be compatable with \a mode. + If the underlying device is already opened, its openmode must be compatible with \a mode. Returns true on success, false on error. @@ -513,7 +513,7 @@ qint64 QtIOCompressor::readData(char *data, qint64 maxSize) if (d->state == QtIOCompressorPrivate::Error) return -1; - // We are ging to try to fill the data buffer + // We are going to try to fill the data buffer d->zlibStream.next_out = reinterpret_cast(data); d->zlibStream.avail_out = maxSize; @@ -550,7 +550,7 @@ qint64 QtIOCompressor::readData(char *data, qint64 maxSize) d->state = QtIOCompressorPrivate::Error; d->setZlibError(QT_TRANSLATE_NOOP("QtIOCompressor", "Internal zlib error when decompressing: "), status); return -1; - case Z_BUF_ERROR: // No more input and zlib can not privide more output - Not an error, we can try to read again when we have more input. + case Z_BUF_ERROR: // No more input and zlib can not provide more output - Not an error, we can try to read again when we have more input. return 0; } // Loop util data buffer is full or we reach the end of the input stream. diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c094f8235..9b4b7b3c7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -64,12 +64,10 @@ macro(add_unit_test) endif(NOT TEST_OUTPUT) set(TEST_OUTPUT ${TEST_OUTPUT} CACHE STRING "The output to generate when running the QTest unit tests") - get_target_property(loc ${_test_NAME} LOCATION) - if(KDE4_TEST_OUTPUT STREQUAL "xml") - add_test(${_test_NAME} ${loc} -xml -o ${_test_NAME}.tml) + add_test(${_test_NAME} ${_test_NAME} -xml -o ${_test_NAME}.tml) else(KDE4_TEST_OUTPUT STREQUAL "xml") - add_test(${_test_NAME} ${loc}) + add_test(${_test_NAME} ${_test_NAME}) endif(KDE4_TEST_OUTPUT STREQUAL "xml") if(NOT MSVC_IDE) #not needed for the ide diff --git a/tests/TestCryptoHash.cpp b/tests/TestCryptoHash.cpp index eb26ca83f..4002aea6b 100644 --- a/tests/TestCryptoHash.cpp +++ b/tests/TestCryptoHash.cpp @@ -32,9 +32,6 @@ void TestCryptoHash::initTestCase() void TestCryptoHash::test() { - // TODO: move somewhere else - QVERIFY(Crypto::backendSelfTest()); - CryptoHash cryptoHash1(CryptoHash::Sha256); QCOMPARE(cryptoHash1.result(), QByteArray::fromHex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"));