Change updater downloading method to retrieving link from the gateway

This commit is contained in:
aiamnezia 2025-05-22 16:50:16 +04:00
parent 22bf2fbc1d
commit 68708114d5

View file

@ -4,12 +4,14 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QVersionNumber> #include <QVersionNumber>
#include <QtConcurrent> #include <QtConcurrent>
#include <QUrl>
#include "amnezia_application.h" #include "amnezia_application.h"
#include "core/errorstrings.h" #include "core/errorstrings.h"
#include "core/scripts_registry.h" #include "core/scripts_registry.h"
#include "logger.h" #include "logger.h"
#include "version.h" #include "version.h"
#include "core/controllers/gatewayController.h"
namespace namespace
{ {
@ -67,76 +69,110 @@ QString UpdateController::getChangelogText()
void UpdateController::checkForUpdates() void UpdateController::checkForUpdates()
{ {
QNetworkRequest request; qDebug() << "checkForUpdates";
request.setTransferTimeout(7000); GatewayController gatewayController(m_settings->getGatewayEndpoint(),
QString endpoint = "https://api.github.com/repos/amnezia-vpn/amnezia-client/releases/latest"; m_settings->isDevGatewayEnv(),
request.setUrl(endpoint); 7000,
m_settings->isStrictKillSwitchEnabled());
QNetworkReply *reply = amnApp->networkManager()->get(request); QByteArray gatewayResponse;
auto err = gatewayController.get(QStringLiteral("%1v1/updater_endpoint"), gatewayResponse);
QObject::connect(reply, &QNetworkReply::finished, [this, reply]() { if (err != ErrorCode::NoError) {
if (reply->error() == QNetworkReply::NoError) { logger.error() << errorString(err);
QString contents = QString::fromUtf8(reply->readAll()); return;
QJsonObject data = QJsonDocument::fromJson(contents.toUtf8()).object(); }
m_version = data.value("tag_name").toString(); QJsonObject gatewayData = QJsonDocument::fromJson(gatewayResponse).object();
qDebug() << "gatewayData:" << gatewayData;
QString baseUrl = gatewayData.value("url").toString();
if (baseUrl.endsWith('/')) {
baseUrl.chop(1);
}
// Fetch version file
QNetworkRequest versionReq;
versionReq.setTransferTimeout(7000);
versionReq.setUrl(QUrl(baseUrl + "/VERSION"));
QNetworkReply* versionReply = amnApp->networkManager()->get(versionReq);
// Handle network and SSL errors for VERSION fetch
QObject::connect(versionReply, &QNetworkReply::errorOccurred, [this, versionReply](QNetworkReply::NetworkError error) {
logger.error() << "Network error occurred while fetching VERSION:" << versionReply->errorString() << error;
});
QObject::connect(versionReply, &QNetworkReply::sslErrors, [this, versionReply](const QList<QSslError> &errors) {
QStringList errorStrings;
for (const QSslError &err : errors) errorStrings << err.errorString();
logger.error() << "SSL errors while fetching VERSION:" << errorStrings;
});
QObject::connect(versionReply, &QNetworkReply::finished, [this, versionReply, baseUrl]() {
if (versionReply->error() == QNetworkReply::NoError) {
QByteArray versionData = versionReply->readAll();
qDebug() << "versionReply data:" << QString::fromUtf8(versionData);
m_version = QString::fromUtf8(versionData).trimmed();
auto currentVersion = QVersionNumber::fromString(QString(APP_VERSION)); auto currentVersion = QVersionNumber::fromString(QString(APP_VERSION));
auto newVersion = QVersionNumber::fromString(m_version); auto newVersion = QVersionNumber::fromString(m_version);
if (newVersion > currentVersion) { if (newVersion > currentVersion) {
m_changelogText = data.value("body").toString(); // Fetch changelog file
QNetworkRequest changelogReq;
QString dateString = data.value("published_at").toString(); changelogReq.setTransferTimeout(7000);
QDateTime dateTime = QDateTime::fromString(dateString, "yyyy-MM-ddTHH:mm:ssZ"); changelogReq.setUrl(QUrl(baseUrl + "/CHANGELOG"));
m_releaseDate = dateTime.toString("MMM dd yyyy"); QNetworkReply* changelogReply = amnApp->networkManager()->get(changelogReq);
// Handle network and SSL errors for CHANGELOG fetch
QJsonArray assets = data.value("assets").toArray(); QObject::connect(changelogReply, &QNetworkReply::errorOccurred, [this, changelogReply](QNetworkReply::NetworkError error) {
logger.error() << "Network error occurred while fetching CHANGELOG:" << changelogReply->errorString() << error;
for (auto asset : assets) { });
QJsonObject assetObject = asset.toObject(); QObject::connect(changelogReply, &QNetworkReply::sslErrors, [this, changelogReply](const QList<QSslError> &errors) {
#ifdef Q_OS_WINDOWS QStringList errorStrings;
if (assetObject.value("name").toString().endsWith(".exe")) { for (const QSslError &err : errors) errorStrings << err.errorString();
m_downloadUrl = assetObject.value("browser_download_url").toString(); logger.error() << "SSL errors while fetching CHANGELOG:" << errorStrings;
});
QObject::connect(changelogReply, &QNetworkReply::finished, [this, changelogReply, baseUrl]() {
if (changelogReply->error() == QNetworkReply::NoError) {
m_changelogText = QString::fromUtf8(changelogReply->readAll());
} else {
if (changelogReply->error() == QNetworkReply::NetworkError::OperationCanceledError
|| changelogReply->error() == QNetworkReply::NetworkError::TimeoutError) {
logger.error() << errorString(ErrorCode::ApiConfigTimeoutError);
} else {
QString err = changelogReply->errorString();
logger.error() << QString::fromUtf8(changelogReply->readAll());
logger.error() << "Network error code:" << QString::number(static_cast<int>(changelogReply->error()));
logger.error() << "Error message:" << err;
logger.error() << "HTTP status:" << changelogReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
logger.error() << errorString(ErrorCode::ApiConfigDownloadError);
}
m_changelogText = tr("Failed to load changelog text");
} }
changelogReply->deleteLater();
m_releaseDate = QStringLiteral("TBD");
QString fileName;
#if defined(Q_OS_WINDOWS)
fileName = QString("AmneziaVPN_%1_x64.exe").arg(m_version);
#elif defined(Q_OS_MACOS) #elif defined(Q_OS_MACOS)
if (assetObject.value("name").toString().endsWith(".dmg")) { fileName = QString("AmneziaVPN_%1_macos.dmg").arg(m_version);
m_downloadUrl = assetObject.value("browser_download_url").toString();
}
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) #elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
if (assetObject.value("name").toString().contains(".tar.zip")) { fileName = QString("AmneziaVPN_%1_linux.tar.zip").arg(m_version);
m_downloadUrl = assetObject.value("browser_download_url").toString();
}
#endif #endif
} m_downloadUrl = baseUrl + "/" + fileName;
qDebug() << "m_downloadUrl:" << m_downloadUrl;
emit updateFound(); emit updateFound();
});
} }
} else { } else {
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError // Detailed error logging for VERSION fetch
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) { if (versionReply->error() == QNetworkReply::NetworkError::OperationCanceledError
|| versionReply->error() == QNetworkReply::NetworkError::TimeoutError) {
logger.error() << errorString(ErrorCode::ApiConfigTimeoutError); logger.error() << errorString(ErrorCode::ApiConfigTimeoutError);
} else { } else {
QString err = reply->errorString(); QString err = versionReply->errorString();
logger.error() << QString::fromUtf8(reply->readAll()); logger.error() << QString::fromUtf8(versionReply->readAll());
logger.error() << "Network error code:" << QString::number(static_cast<int>(reply->error())); logger.error() << "Network error code:" << QString::number(static_cast<int>(versionReply->error()));
logger.error() << "Error message:" << err; logger.error() << "Error message:" << err;
logger.error() << "HTTP status:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); logger.error() << "HTTP status:" << versionReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
logger.error() << errorString(ErrorCode::ApiConfigDownloadError); logger.error() << errorString(ErrorCode::ApiConfigDownloadError);
} }
} }
versionReply->deleteLater();
reply->deleteLater();
});
QObject::connect(reply, &QNetworkReply::errorOccurred, [this, reply](QNetworkReply::NetworkError error) {
logger.error() << "Network error occurred:" << reply->errorString() << error;
});
connect(reply, &QNetworkReply::sslErrors, [this, reply](const QList<QSslError> &errors) {
QStringList errorStrings;
for (const QSslError &error : errors) {
errorStrings << error.errorString();
}
logger.error() << "SSL errors:" << errorStrings;
logger.error() << errorString(ErrorCode::ApiConfigSslError);
}); });
} }