mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-11-29 10:56:48 -05:00
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
This commit is contained in:
parent
5c9b062f13
commit
779b529da2
17 changed files with 677 additions and 5 deletions
148
src/updatecheck/UpdateChecker.cpp
Normal file
148
src/updatecheck/UpdateChecker.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "UpdateChecker.h"
|
||||
#include "core/Config.h"
|
||||
#include "config-keepassx.h"
|
||||
#include <QJsonObject>
|
||||
#include <QtNetwork>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
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;
|
||||
}
|
||||
60
src/updatecheck/UpdateChecker.h
Normal file
60
src/updatecheck/UpdateChecker.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSXC_UPDATECHECK_H
|
||||
#define KEEPASSXC_UPDATECHECK_H
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue