diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp index 31a561d8..dbd621a8 100644 --- a/client/core/controllers/apiController.cpp +++ b/client/core/controllers/apiController.cpp @@ -1,5 +1,8 @@ #include "apiController.h" +#include +#include + #include #include #include @@ -11,8 +14,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 +68,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 +345,30 @@ 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(); + std::random_device randomDevice; + std::mt19937 generator(randomDevice()); + std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator); 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 +450,36 @@ 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(); + std::random_device randomDevice; + std::mt19937 generator(randomDevice()); + std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator); 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); diff --git a/client/platforms/windows/daemon/wireguardutilswindows.cpp b/client/platforms/windows/daemon/wireguardutilswindows.cpp index a68551d7..1a220235 100644 --- a/client/platforms/windows/daemon/wireguardutilswindows.cpp +++ b/client/platforms/windows/daemon/wireguardutilswindows.cpp @@ -248,7 +248,7 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) { } if (result != NO_ERROR) { logger.error() << "Failed to create route to" - << logger.sensitive(prefix.toString()) + << prefix.toString() << "result:" << result; } return result == NO_ERROR; @@ -265,7 +265,7 @@ bool WireguardUtilsWindows::deleteRoutePrefix(const IPAddress& prefix) { } if (result != NO_ERROR) { logger.error() << "Failed to delete route to" - << logger.sensitive(prefix.toString()) + << prefix.toString() << "result:" << result; } return result == NO_ERROR; diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 7f7cf9e1..7c031997 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -49,6 +49,8 @@ PageType { HeaderType { + property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible() + Layout.fillWidth: true Layout.topMargin: 24 Layout.rightMargin: 16 @@ -56,7 +58,7 @@ PageType { headerText: qsTr("Connection") - actionButtonImage: PageController.isStartPageVisible() ? "qrc:/images/controls/more-vertical.svg" : "" + actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : "" actionButtonFunction: function() { moreActionsDrawer.open() } @@ -67,18 +69,19 @@ PageType { parent: root anchors.fill: parent - expandedHeight: root.height * 0.35 + expandedHeight: root.height * 0.5 expandedContent: ColumnLayout { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 + spacing: 0 HeaderType { Layout.fillWidth: true Layout.topMargin: 32 + Layout.leftMargin: 16 + Layout.rightMargin: 16 headerText: qsTr("Settings") } @@ -87,9 +90,12 @@ PageType { id: switcher Layout.fillWidth: true Layout.topMargin: 16 + Layout.leftMargin: 16 + Layout.rightMargin: 16 text: qsTr("Enable logs") + visible: PageController.isStartPageVisible() checked: SettingsController.isLoggingEnabled onCheckedChanged: { if (checked !== SettingsController.isLoggingEnabled) { @@ -98,6 +104,28 @@ PageType { } } + LabelWithButtonType { + id: supportUuid + Layout.fillWidth: true + Layout.topMargin: 16 + + text: qsTr("Support tag") + descriptionText: SettingsController.getInstallationUuid() + + descriptionOnTop: true + + rightImageSource: "qrc:/images/controls/copy.svg" + rightImageColor: AmneziaStyle.color.paleGray + + visible: SettingsController.getInstallationUuid() !== "" + clickedFunction: function() { + GC.copyToClipBoard(descriptionText) + PageController.showNotificationMessage(qsTr("Copied")) + if (!GC.isMobile()) { + this.rightButton.forceActiveFocus() + } + } + } } } } diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 591e396f..ac881bd7 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -56,14 +56,15 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state) { #ifdef AMNEZIA_DESKTOP - QString proto = m_settings->defaultContainerName(m_settings->defaultServerIndex()); + auto container = m_settings->defaultContainer(m_settings->defaultServerIndex()); if (IpcClient::Interface()) { if (state == Vpn::ConnectionState::Connected) { IpcClient::Interface()->resetIpStack(); IpcClient::Interface()->flushDns(); - if (!m_vpnConfiguration.value(config_key::configVersion).toInt()) { + if (!m_vpnConfiguration.value(config_key::configVersion).toInt() && container != DockerContainer::Awg + && container != DockerContainer::WireGuard) { QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString(); QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();