Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into chore/global-network-manager
This commit is contained in:
commit
4e5daf22a3
4 changed files with 87 additions and 23 deletions
|
@ -1,5 +1,8 @@
|
||||||
#include "apiController.h"
|
#include "apiController.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
@ -11,8 +14,8 @@
|
||||||
#include "amnezia_application.h"
|
#include "amnezia_application.h"
|
||||||
#include "configurators/wireguard_configurator.h"
|
#include "configurators/wireguard_configurator.h"
|
||||||
#include "core/enums/apiEnums.h"
|
#include "core/enums/apiEnums.h"
|
||||||
#include "version.h"
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -65,6 +68,28 @@ namespace
|
||||||
return ErrorCode::ApiConfigDownloadError;
|
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<void>(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)
|
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<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
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();
|
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) {
|
for (const QString &proxyUrl : m_proxyUrls) {
|
||||||
|
qDebug() << "Go to the next endpoint";
|
||||||
request.setUrl(QString("%1v1/services").arg(proxyUrl));
|
request.setUrl(QString("%1v1/services").arg(proxyUrl));
|
||||||
|
reply->deleteLater(); // delete the previous reply
|
||||||
reply = amnApp->manager()->get(request);
|
reply = amnApp->manager()->get(request);
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
|
|
||||||
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
responseBody = reply->readAll();
|
||||||
|
if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, responseBody, false)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBody = reply->readAll();
|
|
||||||
auto errorCode = checkErrors(sslErrors, reply);
|
auto errorCode = checkErrors(sslErrors, reply);
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
return errorCode;
|
return errorCode;
|
||||||
|
@ -418,32 +449,36 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
|
|
||||||
if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
|
auto encryptedResponseBody = reply->readAll();
|
||||||
if (m_proxyUrls.isEmpty()) {
|
|
||||||
m_proxyUrls = getProxyUrls();
|
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) {
|
for (const QString &proxyUrl : m_proxyUrls) {
|
||||||
|
qDebug() << "Go to the next endpoint";
|
||||||
request.setUrl(QString("%1v1/config").arg(proxyUrl));
|
request.setUrl(QString("%1v1/config").arg(proxyUrl));
|
||||||
|
reply->deleteLater(); // delete the previous reply
|
||||||
reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
|
reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
|
||||||
|
|
||||||
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
|
|
||||||
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
encryptedResponseBody = reply->readAll();
|
||||||
|
if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, encryptedResponseBody, false)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto errorCode = checkErrors(sslErrors, reply);
|
auto errorCode = checkErrors(sslErrors, reply);
|
||||||
|
reply->deleteLater();
|
||||||
if (errorCode) {
|
if (errorCode) {
|
||||||
return errorCode;
|
return errorCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto encryptedResponseBody = reply->readAll();
|
|
||||||
reply->deleteLater();
|
|
||||||
try {
|
try {
|
||||||
auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
|
auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
|
||||||
fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
|
fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
|
||||||
|
|
|
@ -248,7 +248,7 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) {
|
||||||
}
|
}
|
||||||
if (result != NO_ERROR) {
|
if (result != NO_ERROR) {
|
||||||
logger.error() << "Failed to create route to"
|
logger.error() << "Failed to create route to"
|
||||||
<< logger.sensitive(prefix.toString())
|
<< prefix.toString()
|
||||||
<< "result:" << result;
|
<< "result:" << result;
|
||||||
}
|
}
|
||||||
return result == NO_ERROR;
|
return result == NO_ERROR;
|
||||||
|
@ -265,7 +265,7 @@ bool WireguardUtilsWindows::deleteRoutePrefix(const IPAddress& prefix) {
|
||||||
}
|
}
|
||||||
if (result != NO_ERROR) {
|
if (result != NO_ERROR) {
|
||||||
logger.error() << "Failed to delete route to"
|
logger.error() << "Failed to delete route to"
|
||||||
<< logger.sensitive(prefix.toString())
|
<< prefix.toString()
|
||||||
<< "result:" << result;
|
<< "result:" << result;
|
||||||
}
|
}
|
||||||
return result == NO_ERROR;
|
return result == NO_ERROR;
|
||||||
|
|
|
@ -49,6 +49,8 @@ PageType {
|
||||||
|
|
||||||
|
|
||||||
HeaderType {
|
HeaderType {
|
||||||
|
property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 24
|
Layout.topMargin: 24
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
@ -56,7 +58,7 @@ PageType {
|
||||||
|
|
||||||
headerText: qsTr("Connection")
|
headerText: qsTr("Connection")
|
||||||
|
|
||||||
actionButtonImage: PageController.isStartPageVisible() ? "qrc:/images/controls/more-vertical.svg" : ""
|
actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : ""
|
||||||
actionButtonFunction: function() {
|
actionButtonFunction: function() {
|
||||||
moreActionsDrawer.open()
|
moreActionsDrawer.open()
|
||||||
}
|
}
|
||||||
|
@ -67,18 +69,19 @@ PageType {
|
||||||
parent: root
|
parent: root
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
expandedHeight: root.height * 0.35
|
expandedHeight: root.height * 0.5
|
||||||
|
|
||||||
expandedContent: ColumnLayout {
|
expandedContent: ColumnLayout {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.leftMargin: 16
|
spacing: 0
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
HeaderType {
|
HeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 32
|
Layout.topMargin: 32
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Settings")
|
headerText: qsTr("Settings")
|
||||||
}
|
}
|
||||||
|
@ -87,9 +90,12 @@ PageType {
|
||||||
id: switcher
|
id: switcher
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Enable logs")
|
text: qsTr("Enable logs")
|
||||||
|
|
||||||
|
visible: PageController.isStartPageVisible()
|
||||||
checked: SettingsController.isLoggingEnabled
|
checked: SettingsController.isLoggingEnabled
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isLoggingEnabled) {
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,15 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
QString proto = m_settings->defaultContainerName(m_settings->defaultServerIndex());
|
auto container = m_settings->defaultContainer(m_settings->defaultServerIndex());
|
||||||
|
|
||||||
if (IpcClient::Interface()) {
|
if (IpcClient::Interface()) {
|
||||||
if (state == Vpn::ConnectionState::Connected) {
|
if (state == Vpn::ConnectionState::Connected) {
|
||||||
IpcClient::Interface()->resetIpStack();
|
IpcClient::Interface()->resetIpStack();
|
||||||
IpcClient::Interface()->flushDns();
|
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 dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||||
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue