diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp index 31a561d8..1f8257ee 100644 --- a/client/core/controllers/apiController.cpp +++ b/client/core/controllers/apiController.cpp @@ -11,8 +11,8 @@ #include "amnezia_application.h" #include "configurators/wireguard_configurator.h" #include "core/enums/apiEnums.h" -#include "version.h" #include "utilities.h" +#include "version.h" namespace { @@ -65,6 +65,28 @@ namespace return ErrorCode::ApiConfigDownloadError; } } + + bool shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key = "", + const QByteArray &iv = "", const QByteArray &salt = "") + { + if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError + || reply->error() == QNetworkReply::NetworkError::TimeoutError) { + qDebug() << "Timeout occurred"; + return true; + } else if (responseBody.contains("html")) { + qDebug() << "The response contains an html tag"; + return true; + } else if (checkEncryption) { + try { + QSimpleCrypto::QBlockCipher blockCipher; + static_cast(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt)); + } catch (...) { + qDebug() << "Failed to decrypt the data"; + return true; + } + } + return false; + } } ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent) @@ -320,24 +342,27 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody) connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); wait.exec(); - if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) { + responseBody = reply->readAll(); + + if (sslErrors.isEmpty() && shouldBypassProxy(reply, responseBody, false)) { m_proxyUrls = getProxyUrls(); for (const QString &proxyUrl : m_proxyUrls) { + qDebug() << "Go to the next endpoint"; request.setUrl(QString("%1v1/services").arg(proxyUrl)); + reply->deleteLater(); // delete the previous reply reply = amnApp->manager()->get(request); QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit); connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); wait.exec(); - if (reply->error() != QNetworkReply::NetworkError::TimeoutError - && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) { + + responseBody = reply->readAll(); + if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, responseBody, false)) { break; } - reply->deleteLater(); } } - responseBody = reply->readAll(); auto errorCode = checkErrors(sslErrors, reply); reply->deleteLater(); return errorCode; @@ -419,32 +444,33 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); wait.exec(); - if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) { - if (m_proxyUrls.isEmpty()) { - m_proxyUrls = getProxyUrls(); - } + auto encryptedResponseBody = reply->readAll(); + + if (sslErrors.isEmpty() && shouldBypassProxy(reply, encryptedResponseBody, true)) { + m_proxyUrls = getProxyUrls(); for (const QString &proxyUrl : m_proxyUrls) { + qDebug() << "Go to the next endpoint"; request.setUrl(QString("%1v1/config").arg(proxyUrl)); + reply->deleteLater(); // delete the previous reply reply = manager.post(request, QJsonDocument(requestBody).toJson()); QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit); connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); wait.exec(); - if (reply->error() != QNetworkReply::NetworkError::TimeoutError - && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) { + + encryptedResponseBody = reply->readAll(); + if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, encryptedResponseBody, false)) { break; } - reply->deleteLater(); } } auto errorCode = checkErrors(sslErrors, reply); + reply->deleteLater(); if (errorCode) { return errorCode; } - auto encryptedResponseBody = reply->readAll(); - reply->deleteLater(); try { auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt); fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);