From 779b529da2f9c3d7204dcf1a32bf07feedc0d5aa Mon Sep 17 00:00:00 2001 From: Weslly Date: Wed, 30 Jan 2019 12:11:50 -0200 Subject: [PATCH] Update checking feature (#2648) * Check on startup (toggleable setting) and manually * Option to check for pre-releases (eg, 2.4.0-beta1) * Only included if WITH_XC_NETWORKING is enabled --- CMakeLists.txt | 6 +- INSTALL.md | 2 - src/CMakeLists.txt | 4 + src/gui/ApplicationSettingsWidget.cpp | 5 + src/gui/ApplicationSettingsWidgetGeneral.ui | 14 ++ src/gui/MainWindow.cpp | 58 +++++++ src/gui/MainWindow.h | 3 + src/gui/MainWindow.ui | 9 + src/gui/UpdateCheckDialog.cpp | 68 ++++++++ src/gui/UpdateCheckDialog.h | 50 ++++++ src/gui/UpdateCheckDialog.ui | 175 ++++++++++++++++++++ src/updatecheck/UpdateChecker.cpp | 148 +++++++++++++++++ src/updatecheck/UpdateChecker.h | 60 +++++++ tests/CMakeLists.txt | 5 + tests/TestUpdateCheck.cpp | 41 +++++ tests/TestUpdateCheck.h | 32 ++++ tests/gui/TestGui.cpp | 2 + 17 files changed, 677 insertions(+), 5 deletions(-) create mode 100644 src/gui/UpdateCheckDialog.cpp create mode 100644 src/gui/UpdateCheckDialog.h create mode 100644 src/gui/UpdateCheckDialog.ui create mode 100644 src/updatecheck/UpdateChecker.cpp create mode 100644 src/updatecheck/UpdateChecker.h create mode 100644 tests/TestUpdateCheck.cpp create mode 100644 tests/TestUpdateCheck.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b2ea7d12..85f27b871 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,9 +61,9 @@ if(WITH_XC_ALL) set(WITH_XC_YUBIKEY ON) set(WITH_XC_SSHAGENT ON) set(WITH_XC_KEESHARE ON) - if(APPLE) - set(WITH_XC_TOUCHID ON) - endif() + if(APPLE) + set(WITH_XC_TOUCHID ON) + endif() endif() if(WITH_XC_KEESHARE_SECURE) diff --git a/INSTALL.md b/INSTALL.md index 5267cd85a..d3927536f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -102,9 +102,7 @@ These steps place the compiled KeePassXC binary inside the `./build/src/` direct -DWITH_XC_KEESHARE=[ON|OFF] Enable/Disable KeeShare group syncronization extension (default: OFF) -DWITH_XC_TOUCHID=[ON|OFF] (macOS Only) Enable/Disable Touch ID unlock (default:OFF) -DWITH_XC_ALL=[ON|OFF] Enable/Disable compiling all plugins above (default: OFF) - -DWITH_XC_KEESHARE_SECURE=[ON|OFF] Enable/Disable KeeShare secure containers, requires libquazip5 (default: OFF) - -DWITH_TESTS=[ON|OFF] Enable/Disable building of unit tests (default: ON) -DWITH_GUI_TESTS=[ON|OFF] Enable/Disable building of GUI tests (default: OFF) -DWITH_DEV_BUILD=[ON|OFF] Enable/Disable deprecated method warnings (default: OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 854ce877f..ba38746c3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -257,6 +257,10 @@ else() list(APPEND keepassx_SOURCES keys/drivers/YubiKey.h keys/drivers/YubiKeyStub.cpp) endif() +if(WITH_XC_NETWORKING) + list(APPEND keepassx_SOURCES updatecheck/UpdateChecker.cpp gui/UpdateCheckDialog.cpp) +endif() + if(WITH_XC_TOUCHID) list(APPEND keepassx_SOURCES touchid/TouchID.mm) endif() diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp index 806512b5a..ffefe2257 100644 --- a/src/gui/ApplicationSettingsWidget.cpp +++ b/src/gui/ApplicationSettingsWidget.cpp @@ -92,6 +92,7 @@ ApplicationSettingsWidget::ApplicationSettingsWidget(QWidget* parent) // clang-format on #ifndef WITH_XC_NETWORKING + m_generalUi->checkForUpdatesOnStartupCheckBox->setVisible(false); m_secUi->privacy->setVisible(false); #endif @@ -174,6 +175,8 @@ void ApplicationSettingsWidget::loadSettings() m_generalUi->systrayMinimizeToTrayCheckBox->setChecked(config()->get("GUI/MinimizeToTray").toBool()); m_generalUi->minimizeOnCloseCheckBox->setChecked(config()->get("GUI/MinimizeOnClose").toBool()); m_generalUi->systrayMinimizeOnStartup->setChecked(config()->get("GUI/MinimizeOnStartup").toBool()); + m_generalUi->checkForUpdatesOnStartupCheckBox->setChecked(config()->get("GUI/CheckForUpdates").toBool()); + m_generalUi->checkForUpdatesIncludeBetasCheckBox->setChecked(config()->get("GUI/CheckForUpdatesIncludeBetas").toBool()); m_generalUi->autoTypeAskCheckBox->setChecked(config()->get("security/autotypeask").toBool()); if (autoType()->isAvailable()) { @@ -256,6 +259,8 @@ void ApplicationSettingsWidget::saveSettings() config()->set("GUI/MinimizeToTray", m_generalUi->systrayMinimizeToTrayCheckBox->isChecked()); config()->set("GUI/MinimizeOnClose", m_generalUi->minimizeOnCloseCheckBox->isChecked()); config()->set("GUI/MinimizeOnStartup", m_generalUi->systrayMinimizeOnStartup->isChecked()); + config()->set("GUI/CheckForUpdates", m_generalUi->checkForUpdatesOnStartupCheckBox->isChecked()); + config()->set("GUI/CheckForUpdatesIncludeBetas", m_generalUi->checkForUpdatesIncludeBetasCheckBox->isChecked()); config()->set("security/autotypeask", m_generalUi->autoTypeAskCheckBox->isChecked()); diff --git a/src/gui/ApplicationSettingsWidgetGeneral.ui b/src/gui/ApplicationSettingsWidgetGeneral.ui index 4826e09bf..798971bfe 100644 --- a/src/gui/ApplicationSettingsWidgetGeneral.ui +++ b/src/gui/ApplicationSettingsWidgetGeneral.ui @@ -83,6 +83,13 @@ + + + + Check for updates at application startup + + + @@ -179,6 +186,13 @@ General + + + + Include pre-releases when checking for updates + + + diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 8e957c926..f33341688 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -41,6 +41,12 @@ #include "keys/FileKey.h" #include "keys/PasswordKey.h" +#ifdef WITH_XC_NETWORKING +#include "updatecheck/UpdateChecker.h" +#include "gui/MessageBox.h" +#include "gui/UpdateCheckDialog.h" +#endif + #ifdef WITH_XC_SSHAGENT #include "sshagent/AgentSettingsPage.h" #include "sshagent/SSHAgent.h" @@ -282,6 +288,7 @@ MainWindow::MainWindow() m_ui->actionPasswordGenerator->setIcon(filePath()->icon("actions", "password-generator")); m_ui->actionAbout->setIcon(filePath()->icon("actions", "help-about")); + m_ui->actionCheckForUpdates->setIcon(filePath()->icon("actions", "system-software-update")); m_actionMultiplexer.connect( SIGNAL(currentModeChanged(DatabaseWidget::Mode)), this, SLOT(setMenuActionState(DatabaseWidget::Mode))); @@ -364,6 +371,15 @@ MainWindow::MainWindow() #ifdef Q_OS_MACOS setUnifiedTitleAndToolBarOnMac(true); #endif + +#ifdef WITH_XC_NETWORKING + connect(m_ui->actionCheckForUpdates, SIGNAL(triggered()), SLOT(showUpdateCheckDialog())); + connect(UpdateChecker::instance(), SIGNAL(updateCheckFinished(bool, QString, bool)), SLOT(hasUpdateAvailable(bool, QString, bool))); + QTimer::singleShot(3000, this, SLOT(showUpdateCheckStartup())); +#else + m_ui->actionCheckForUpdates->setVisible(false); +#endif + // clang-format off connect(m_ui->tabWidget, SIGNAL(messageGlobal(QString,MessageWidget::MessageType)), @@ -661,6 +677,48 @@ void MainWindow::showAboutDialog() aboutDialog->open(); } +void MainWindow::showUpdateCheckStartup() +{ +#ifdef WITH_XC_NETWORKING + if (!config()->get("UpdateCheckMessageShown", false).toBool()) { + auto result = MessageBox::question(this, + tr("Check for updates on startup?"), + tr("Would you like KeePassXC to check for updates on startup?") + "\n\n" + + tr("You can always check for updates manually from the application menu."), + MessageBox::Yes | MessageBox::No, + MessageBox::Yes); + + config()->set("GUI/CheckForUpdates", (result == MessageBox::Yes)); + config()->set("UpdateCheckMessageShown", true); + } + + if (config()->get("GUI/CheckForUpdates", false).toBool()) { + updateCheck()->checkForUpdates(false); + } + +#endif +} + +void MainWindow::hasUpdateAvailable(bool hasUpdate, const QString& version, bool isManuallyRequested) +{ +#ifdef WITH_XC_NETWORKING + if (hasUpdate && !isManuallyRequested) { + auto* updateCheckDialog = new UpdateCheckDialog(this); + updateCheckDialog->showUpdateCheckResponse(hasUpdate, version); + updateCheckDialog->show(); + } +#endif +} + +void MainWindow::showUpdateCheckDialog() +{ +#ifdef WITH_XC_NETWORKING + updateCheck()->checkForUpdates(true); + auto* updateCheckDialog = new UpdateCheckDialog(this); + updateCheckDialog->show(); +#endif +} + void MainWindow::openDonateUrl() { QDesktopServices::openUrl(QUrl("https://keepassxc.org/donate")); diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index a9a47d3d8..cd7b1a39b 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -83,6 +83,9 @@ private slots: void setMenuActionState(DatabaseWidget::Mode mode = DatabaseWidget::Mode::None); void updateWindowTitle(); void showAboutDialog(); + void showUpdateCheckStartup(); + void showUpdateCheckDialog(); + void hasUpdateAvailable(bool hasUpdate, const QString& version, bool isManuallyRequested); void openDonateUrl(); void openBugReportUrl(); void switchToDatabases(); diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index 216c7067b..004518eec 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -223,6 +223,7 @@ &Help + @@ -348,6 +349,14 @@ QAction::AboutRole + + + Check for Updates... + + + QAction::ApplicationSpecificRole + + &Open database... diff --git a/src/gui/UpdateCheckDialog.cpp b/src/gui/UpdateCheckDialog.cpp new file mode 100644 index 000000000..7b0eff53e --- /dev/null +++ b/src/gui/UpdateCheckDialog.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "UpdateCheckDialog.h" +#include "ui_UpdateCheckDialog.h" +#include "updatecheck/UpdateChecker.h" +#include "core/FilePath.h" + +UpdateCheckDialog::UpdateCheckDialog(QWidget* parent) + : QDialog(parent) + , m_ui(new Ui::UpdateCheckDialog()) +{ + m_ui->setupUi(this); + setWindowFlags(Qt::Window); + setAttribute(Qt::WA_DeleteOnClose); + + m_ui->iconLabel->setPixmap(filePath()->applicationIcon().pixmap(48)); + + connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(close())); + connect(UpdateChecker::instance(), SIGNAL(updateCheckFinished(bool, QString, bool)), SLOT(showUpdateCheckResponse(bool, QString))); +} + +void UpdateCheckDialog::showUpdateCheckResponse(bool status, const QString& version) { + m_ui->progressBar->setVisible(false); + m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close")); + + if (version == QString("error")) { + setWindowTitle(tr("Update Error!")); + + m_ui->statusLabel->setText( + "" + tr("Update Error!") + "

" + + tr("An error occurred in retrieving update information.") + "
" + + tr("Please try again later.")); + return; + } + + if (status) { + setWindowTitle(tr("Software Update")); + m_ui->statusLabel->setText( + "" + tr("A new version of KeePassXC is available!") + "

" + + tr("KeePassXC %1 is now available — you have %2.").arg(version, KEEPASSXC_VERSION) + "

" + + "" + + tr("Download it at keepassxc.org") + + ""); + } else { + setWindowTitle(tr("You're up-to-date!")); + m_ui->statusLabel->setText(tr( + "KeePassXC %1 is currently the newest version available").arg(KEEPASSXC_VERSION)); + } +} + +UpdateCheckDialog::~UpdateCheckDialog() +{ +} diff --git a/src/gui/UpdateCheckDialog.h b/src/gui/UpdateCheckDialog.h new file mode 100644 index 000000000..b601f32db --- /dev/null +++ b/src/gui/UpdateCheckDialog.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_UPDATECHECKDIALOG_H +#define KEEPASSXC_UPDATECHECKDIALOG_H + +#include +#include +#include +#include "gui/MessageBox.h" +#include "config-keepassx.h" +#include "core/Global.h" +#include "updatecheck/UpdateChecker.h" + +namespace Ui +{ + class UpdateCheckDialog; +} + +class UpdateCheckDialog : public QDialog +{ +Q_OBJECT + +public: + explicit UpdateCheckDialog(QWidget* parent = nullptr); + ~UpdateCheckDialog() override; + +public slots: + void showUpdateCheckResponse(bool status, const QString& version); + +private: + QScopedPointer m_ui; +}; + + +#endif //KEEPASSXC_UPDATECHECKDIALOG_H diff --git a/src/gui/UpdateCheckDialog.ui b/src/gui/UpdateCheckDialog.ui new file mode 100644 index 000000000..9775cbf61 --- /dev/null +++ b/src/gui/UpdateCheckDialog.ui @@ -0,0 +1,175 @@ + + + UpdateCheckDialog + + + + 0 + 0 + 375 + 136 + + + + + 0 + 0 + + + + + 50 + false + + + + Checking for updates + + + false + + + + 16 + + + 16 + + + 16 + + + 16 + + + + + + + + 0 + 0 + + + + + 60 + 60 + + + + + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + + + + 50 + false + + + + Checking for updates... + + + Qt::RichText + + + true + + + + + + + + 0 + 0 + + + + 0 + + + 0 + + + 0 + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 10 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + + + buttonBox + accepted() + UpdateCheckDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UpdateCheckDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/updatecheck/UpdateChecker.cpp b/src/updatecheck/UpdateChecker.cpp new file mode 100644 index 000000000..ff10821bb --- /dev/null +++ b/src/updatecheck/UpdateChecker.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "UpdateChecker.h" +#include "core/Config.h" +#include "config-keepassx.h" +#include +#include +#include + +UpdateChecker* UpdateChecker::m_instance(nullptr); + +UpdateChecker::UpdateChecker(QObject* parent) + : QObject(parent) + , m_netMgr(new QNetworkAccessManager(this)) + , m_reply(nullptr) +{ +} + +UpdateChecker::~UpdateChecker() +{ +} + +void UpdateChecker::checkForUpdates(bool manuallyRequested) +{ + m_isManuallyRequested = manuallyRequested; + m_bytesReceived.clear(); + + QString apiUrlStr = QString("https://api.github.com/repos/keepassxreboot/keepassxc/releases"); + + if (!config()->get("GUI/CheckForUpdatesIncludeBetas", false).toBool()) { + apiUrlStr += "/latest"; + } + + QUrl apiUrl = QUrl(apiUrlStr); + + QNetworkRequest request(apiUrl); + request.setRawHeader("Accept", "application/json"); + + m_reply = m_netMgr->get(request); + + connect(m_reply, &QNetworkReply::finished, this, &UpdateChecker::fetchFinished); + connect(m_reply, &QIODevice::readyRead, this, &UpdateChecker::fetchReadyRead); +} + +void UpdateChecker::fetchReadyRead() +{ + m_bytesReceived += m_reply->readAll(); +} + +void UpdateChecker::fetchFinished() +{ + bool error = (m_reply->error() != QNetworkReply::NoError); + bool hasNewVersion = false; + QUrl url = m_reply->url(); + QString version = ""; + + m_reply->deleteLater(); + m_reply = nullptr; + + if (!error) { + QJsonDocument jsonResponse = QJsonDocument::fromJson(m_bytesReceived); + QJsonObject jsonObject = jsonResponse.object(); + + if (config()->get("GUI/CheckForUpdatesIncludeBetas", false).toBool()) { + QJsonArray jsonArray = jsonResponse.array(); + jsonObject = jsonArray.at(0).toObject(); + } + + if (!jsonObject.value("tag_name").isUndefined()) { + version = jsonObject.value("tag_name").toString(); + hasNewVersion = compareVersions(version, QString(KEEPASSXC_VERSION)); + } + } else { + version = "error"; + } + + emit updateCheckFinished(hasNewVersion, version, m_isManuallyRequested); +} + +bool UpdateChecker::compareVersions(const QString& remoteVersion, const QString& localVersion) +{ + if (localVersion == remoteVersion) { + return false; // Currently using updated version + } + + QRegularExpression verRegex("^(\\d+(\\.\\d+){0,2})(-\\w+)?$", QRegularExpression::CaseInsensitiveOption); + + QRegularExpressionMatch lmatch = verRegex.match(localVersion); + QRegularExpressionMatch rmatch = verRegex.match(remoteVersion); + + if (!lmatch.captured(1).isNull() && !rmatch.captured(1).isNull()) { + if (lmatch.captured(1) == rmatch.captured(1) && !lmatch.captured(3).isNull()) { + // Same version, but installed version has snapshot/beta suffix and should be updated to stable + return true; + } + + QStringList lparts = lmatch.captured(1).split("."); + QStringList rparts = rmatch.captured(1).split("."); + + if (lparts.length() < 3) + lparts << "0"; + + if (rparts.length() < 3) + rparts << "0"; + + for (int i = 0; i < 3; i++) { + int l = lparts[i].toInt(); + int r = rparts[i].toInt(); + + if (l == r) + continue; + + if (l > r) { + return false; // Installed version is newer than release + } else { + return true; // Installed version is outdated + } + } + + return false; // Installed version is the same + } + + return false; // Invalid version string +} + +UpdateChecker* UpdateChecker::instance() +{ + if (!m_instance) { + m_instance = new UpdateChecker(); + } + + return m_instance; +} diff --git a/src/updatecheck/UpdateChecker.h b/src/updatecheck/UpdateChecker.h new file mode 100644 index 000000000..aa1262bd5 --- /dev/null +++ b/src/updatecheck/UpdateChecker.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_UPDATECHECK_H +#define KEEPASSXC_UPDATECHECK_H +#include +#include + +class QNetworkAccessManager; +class QNetworkReply; + +class UpdateChecker : public QObject +{ + Q_OBJECT +public: + UpdateChecker(QObject* parent = nullptr); + ~UpdateChecker() override; + + void checkForUpdates(bool manuallyRequested); + static bool compareVersions(const QString& remoteVersion, const QString& localVersion); + static UpdateChecker* instance(); + +signals: + void updateCheckFinished(bool hasNewVersion, QString version, bool isManuallyRequested); + +private slots: + void fetchFinished(); + void fetchReadyRead(); + +private: + QNetworkAccessManager* m_netMgr; + QNetworkReply* m_reply; + QByteArray m_bytesReceived; + bool m_isManuallyRequested; + + static UpdateChecker* m_instance; + + Q_DISABLE_COPY(UpdateChecker) +}; + +inline UpdateChecker* updateCheck() +{ + return UpdateChecker::instance(); +} + +#endif //KEEPASSXC_UPDATECHECK_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 390dda57b..bab810cea 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -162,6 +162,11 @@ add_unit_test(NAME testkeepass1reader SOURCES TestKeePass1Reader.cpp add_unit_test(NAME testwildcardmatcher SOURCES TestWildcardMatcher.cpp LIBS ${TEST_LIBRARIES}) +if(WITH_XC_NETWORKING) + add_unit_test(NAME testupdatecheck SOURCES TestUpdateCheck.cpp + LIBS ${TEST_LIBRARIES}) +endif() + if(WITH_XC_AUTOTYPE) add_unit_test(NAME testautotype SOURCES TestAutoType.cpp LIBS ${TEST_LIBRARIES}) diff --git a/tests/TestUpdateCheck.cpp b/tests/TestUpdateCheck.cpp new file mode 100644 index 000000000..3bde72950 --- /dev/null +++ b/tests/TestUpdateCheck.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "TestUpdateCheck.h" +#include "TestGlobal.h" +#include "updatecheck/UpdateChecker.h" +#include "crypto/Crypto.h" + +QTEST_GUILESS_MAIN(TestUpdateCheck) + +void TestUpdateCheck::initTestCase() +{ + QVERIFY(Crypto::init()); +} + +void TestUpdateCheck::testCompareVersion() +{ + // Remote Version , Installed Version + QCOMPARE(UpdateChecker::compareVersions(QString("2.4.0"), QString("2.3.4")), true); + QCOMPARE(UpdateChecker::compareVersions(QString("2.3.0"), QString("2.4.0")), false); + QCOMPARE(UpdateChecker::compareVersions(QString("2.3.0"), QString("2.3.0")), false); + QCOMPARE(UpdateChecker::compareVersions(QString("2.3.0"), QString("2.3.0-beta1")), true); + QCOMPARE(UpdateChecker::compareVersions(QString("2.3.0-beta2"), QString("2.3.0-beta1")), true); + QCOMPARE(UpdateChecker::compareVersions(QString("2.3.4"), QString("2.4.0-snapshot")), false); + QCOMPARE(UpdateChecker::compareVersions(QString("invalid"), QString("2.4.0")), false); + QCOMPARE(UpdateChecker::compareVersions(QString(""), QString("2.4.0")), false); +} diff --git a/tests/TestUpdateCheck.h b/tests/TestUpdateCheck.h new file mode 100644 index 000000000..57abd998d --- /dev/null +++ b/tests/TestUpdateCheck.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSX_TESTUPDATECHECK_H +#define KEEPASSX_TESTUPDATECHECK_H + +#include + +class TestUpdateCheck : public QObject +{ +Q_OBJECT + +private slots: + void initTestCase(); + void testCompareVersion(); +}; + +#endif // #define KEEPASSX_TESTUPDATECHECK_H diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 98a7ee012..127563798 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -86,6 +86,8 @@ void TestGui::initTestCase() config()->set("GUI/ShowTrayIcon", true); // Disable advanced settings mode (activate within individual tests to test advanced settings) config()->set("GUI/AdvancedSettings", false); + // Disable the update check first time alert + config()->set("UpdateCheckMessageShown", true); m_mainWindow.reset(new MainWindow()); Bootstrap::restoreMainWindowState(*m_mainWindow);