mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-20 02:00:55 +07:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3b3e937e9 | |||
| 92492952e9 | |||
| 3d152adf5f | |||
| 9be3221cbe | |||
| d47e37e04f | |||
| 5e27f0c8f0 | |||
| c7a48aeabc | |||
| ca1bf0d6cd | |||
| 96f26d5a01 |
+1
-1
Submodule client/3rd-prebuilt updated: c38a587fcd...a1d0c22a6f
+10
-2
@@ -241,8 +241,14 @@ file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/services/*.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h)
|
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS
|
||||||
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
|
${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/localServices/*.h
|
||||||
|
)
|
||||||
|
file(GLOB UI_CONTROLLERS_CPP CONFIGURE_DEPENDS
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/ui/models/localServices/*.cpp
|
||||||
|
)
|
||||||
|
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${COMMON_FILES_H}
|
${COMMON_FILES_H}
|
||||||
@@ -267,10 +273,12 @@ if(WIN32)
|
|||||||
|
|
||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(RESOURCES ${RESOURCES}
|
set(RESOURCES ${RESOURCES}
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ void AmneziaApplication::registerTypes()
|
|||||||
|
|
||||||
Vpn::declareQmlVpnConnectionStateEnum();
|
Vpn::declareQmlVpnConnectionStateEnum();
|
||||||
PageLoader::declareQmlPageEnum();
|
PageLoader::declareQmlPageEnum();
|
||||||
|
PageLoader::declareQmlFolderEnum();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmneziaApplication::loadFonts()
|
void AmneziaApplication::loadFonts()
|
||||||
@@ -455,4 +456,13 @@ void AmneziaApplication::initControllers()
|
|||||||
|
|
||||||
m_systemController.reset(new SystemController(m_settings));
|
m_systemController.reset(new SystemController(m_settings));
|
||||||
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
|
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
|
||||||
|
|
||||||
|
m_localServicesController.reset(new LocalServicesController(m_serversModel, m_settings));
|
||||||
|
m_engine->rootContext()->setContextProperty("LocalServicesController", m_localServicesController.get());
|
||||||
|
connect(m_connectionController.get(), &ConnectionController::startLocalService, m_localServicesController.get(),
|
||||||
|
&LocalServicesController::start);
|
||||||
|
connect(m_connectionController.get(), &ConnectionController::stopLocalService, m_localServicesController.get(),
|
||||||
|
&LocalServicesController::stop);
|
||||||
|
connect(m_localServicesController.get(), &LocalServicesController::serviceStateChanged, m_connectionController.get(),
|
||||||
|
&ConnectionController::connectionStateChanged);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "ui/controllers/sitesController.h"
|
#include "ui/controllers/sitesController.h"
|
||||||
#include "ui/controllers/systemController.h"
|
#include "ui/controllers/systemController.h"
|
||||||
#include "ui/controllers/appSplitTunnelingController.h"
|
#include "ui/controllers/appSplitTunnelingController.h"
|
||||||
|
#include "ui/controllers/localServicesController.h"
|
||||||
#include "ui/models/containers_model.h"
|
#include "ui/models/containers_model.h"
|
||||||
#include "ui/models/languageModel.h"
|
#include "ui/models/languageModel.h"
|
||||||
#include "ui/models/protocols/cloakConfigModel.h"
|
#include "ui/models/protocols/cloakConfigModel.h"
|
||||||
@@ -136,6 +137,7 @@ private:
|
|||||||
QScopedPointer<SitesController> m_sitesController;
|
QScopedPointer<SitesController> m_sitesController;
|
||||||
QScopedPointer<SystemController> m_systemController;
|
QScopedPointer<SystemController> m_systemController;
|
||||||
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
|
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
|
||||||
|
QScopedPointer<LocalServicesController> m_localServicesController;
|
||||||
|
|
||||||
QNetworkAccessManager *m_nam;
|
QNetworkAccessManager *m_nam;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "containers_defs.h"
|
#include "containers_defs.h"
|
||||||
|
|
||||||
#include "QJsonObject"
|
|
||||||
#include "QJsonDocument"
|
#include "QJsonDocument"
|
||||||
|
#include "QJsonObject"
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
|
QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
|
||||||
{
|
{
|
||||||
@@ -96,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
|
|||||||
{ DockerContainer::Awg, "AmneziaWG" },
|
{ DockerContainer::Awg, "AmneziaWG" },
|
||||||
{ DockerContainer::Xray, "XRay" },
|
{ DockerContainer::Xray, "XRay" },
|
||||||
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
|
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
|
||||||
{ DockerContainer::SSXray, "Shadowsocks"},
|
{ DockerContainer::SSXray, "Shadowsocks" },
|
||||||
|
|
||||||
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
||||||
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
|
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
|
||||||
@@ -124,27 +124,24 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
|
|||||||
"but very resistant to blockages. "
|
"but very resistant to blockages. "
|
||||||
"Recommended for regions with high levels of censorship.") },
|
"Recommended for regions with high levels of censorship.") },
|
||||||
{ DockerContainer::Xray,
|
{ DockerContainer::Xray,
|
||||||
QObject::tr("XRay with REALITY - Suitable for countries with the highest level of internet censorship. "
|
QObject::tr(
|
||||||
"Traffic masking as web traffic at the TLS level, and protection against detection by active probing methods.") },
|
"XRay with REALITY - Suitable for countries with the highest level of internet censorship. "
|
||||||
|
"Traffic masking as web traffic at the TLS level, and protection against detection by active probing methods.") },
|
||||||
{ DockerContainer::Ipsec,
|
{ DockerContainer::Ipsec,
|
||||||
QObject::tr("IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after "
|
QObject::tr("IKEv2/IPsec - Modern stable protocol, a bit faster than others, restores connection after "
|
||||||
"signal loss. It has native support on the latest versions of Android and iOS.") },
|
"signal loss. It has native support on the latest versions of Android and iOS.") },
|
||||||
|
|
||||||
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
|
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
|
||||||
{ DockerContainer::Dns,
|
{ DockerContainer::Dns, QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
|
||||||
QObject::tr("Replace the current DNS server with your own. This will increase your privacy level.") },
|
{ DockerContainer::Sftp, QObject::tr("Create a file vault on your server to securely store and transfer files.") },
|
||||||
{ DockerContainer::Sftp,
|
{ DockerContainer::Socks5Proxy, QObject::tr("") } };
|
||||||
QObject::tr("Create a file vault on your server to securely store and transfer files.") },
|
|
||||||
{ DockerContainer::Socks5Proxy,
|
|
||||||
QObject::tr("") } };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
{ DockerContainer::OpenVpn,
|
{ DockerContainer::OpenVpn,
|
||||||
QObject::tr(
|
QObject::tr("OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
|
||||||
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
|
|
||||||
"It employs its unique security protocol, "
|
"It employs its unique security protocol, "
|
||||||
"leveraging the strength of SSL/TLS for encryption and key exchange. "
|
"leveraging the strength of SSL/TLS for encryption and key exchange. "
|
||||||
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
|
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
|
||||||
@@ -160,7 +157,8 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
|||||||
"* Can operate over both TCP and UDP network protocols.") },
|
"* Can operate over both TCP and UDP network protocols.") },
|
||||||
{ DockerContainer::ShadowSocks,
|
{ DockerContainer::ShadowSocks,
|
||||||
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
|
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
|
||||||
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection."
|
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS "
|
||||||
|
"connection."
|
||||||
"However, certain traffic analysis systems might still detect a Shadowsocks connection. "
|
"However, certain traffic analysis systems might still detect a Shadowsocks connection. "
|
||||||
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
|
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
|
||||||
"* Available in the AmneziaVPN only on desktop platforms\n"
|
"* Available in the AmneziaVPN only on desktop platforms\n"
|
||||||
@@ -217,15 +215,18 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
|||||||
"* Works over UDP network protocol.") },
|
"* Works over UDP network protocol.") },
|
||||||
{ DockerContainer::Xray,
|
{ DockerContainer::Xray,
|
||||||
QObject::tr("The REALITY protocol, a pioneering development by the creators of XRay, "
|
QObject::tr("The REALITY protocol, a pioneering development by the creators of XRay, "
|
||||||
"is specifically designed to counteract the highest levels of internet censorship through its novel approach to evasion.\n"
|
"is specifically designed to counteract the highest levels of internet censorship through its novel approach to "
|
||||||
"It uniquely identifies censors during the TLS handshake phase, seamlessly operating as a proxy for legitimate clients while diverting censors to genuine websites like google.com, "
|
"evasion.\n"
|
||||||
|
"It uniquely identifies censors during the TLS handshake phase, seamlessly operating as a proxy for legitimate "
|
||||||
|
"clients while diverting censors to genuine websites like google.com, "
|
||||||
"thus presenting an authentic TLS certificate and data. \n"
|
"thus presenting an authentic TLS certificate and data. \n"
|
||||||
"This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as coming from random, "
|
"This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as "
|
||||||
|
"coming from random, "
|
||||||
"legitimate sites without the need for specific configurations. \n"
|
"legitimate sites without the need for specific configurations. \n"
|
||||||
"Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, "
|
"Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, "
|
||||||
"REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection by sophisticated DPI systems employing active probing techniques. "
|
"REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection "
|
||||||
"This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.")
|
"by sophisticated DPI systems employing active probing techniques. "
|
||||||
},
|
"This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.") },
|
||||||
{ DockerContainer::Ipsec,
|
{ DockerContainer::Ipsec,
|
||||||
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
|
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
|
||||||
"One of its distinguishing features is its ability to swiftly switch between networks and devices, "
|
"One of its distinguishing features is its ability to swiftly switch between networks and devices, "
|
||||||
@@ -287,7 +288,8 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
|||||||
case DockerContainer::Awg: return true;
|
case DockerContainer::Awg: return true;
|
||||||
case DockerContainer::Xray: return true;
|
case DockerContainer::Xray: return true;
|
||||||
case DockerContainer::Cloak: return true;
|
case DockerContainer::Cloak: return true;
|
||||||
case DockerContainer::SSXray: return true;
|
case DockerContainer::SSXray:
|
||||||
|
return true;
|
||||||
// case DockerContainer::ShadowSocks: return true;
|
// case DockerContainer::ShadowSocks: return true;
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
@@ -383,10 +385,8 @@ bool ContainerProps::isShareable(DockerContainer container)
|
|||||||
|
|
||||||
QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
|
QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
|
||||||
{
|
{
|
||||||
QString protocolConfigString = containerConfig.value(ProtocolProps::protoToString(protocol))
|
QString protocolConfigString =
|
||||||
.toObject()
|
containerConfig.value(ProtocolProps::protoToString(protocol)).toObject().value(config_key::last_config).toString();
|
||||||
.value(config_key::last_config)
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ namespace amnezia
|
|||||||
ExecutableMissing = 604,
|
ExecutableMissing = 604,
|
||||||
XrayExecutableMissing = 605,
|
XrayExecutableMissing = 605,
|
||||||
Tun2SockExecutableMissing = 606,
|
Tun2SockExecutableMissing = 606,
|
||||||
|
GoodByeDPIExecutableMissing = 607,
|
||||||
|
|
||||||
// VPN errors
|
// VPN errors
|
||||||
OpenVpnAdaptersInUseError = 700,
|
OpenVpnAdaptersInUseError = 700,
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ QString errorString(ErrorCode code) {
|
|||||||
case (ErrorCode::CloakExecutableMissing): errorMessage = QObject::tr("Cloak (ck-client) executable missing"); break;
|
case (ErrorCode::CloakExecutableMissing): errorMessage = QObject::tr("Cloak (ck-client) executable missing"); break;
|
||||||
case (ErrorCode::AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break;
|
case (ErrorCode::AmneziaServiceConnectionFailed): errorMessage = QObject::tr("Amnezia helper service error"); break;
|
||||||
case (ErrorCode::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break;
|
case (ErrorCode::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break;
|
||||||
|
case (ErrorCode::GoodByeDPIExecutableMissing): errorMessage = QObject::tr("GoodbyeDPI executable missing"); break;
|
||||||
|
|
||||||
// VPN errors
|
// VPN errors
|
||||||
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
|
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#include "goodByeDpi.h"
|
||||||
|
|
||||||
|
#include "core/ipcclient.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
GoodByeDpi::GoodByeDpi(QObject *parent) : QObject { parent }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
amnezia::ErrorCode GoodByeDpi::start(const QString &blackListFile, const int modset)
|
||||||
|
{
|
||||||
|
if (!QFileInfo::exists(Utils::goodbyedpiPath())) {
|
||||||
|
return amnezia::ErrorCode::GoodByeDPIExecutableMissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_goodbyeDPIProcess = IpcClient::CreatePrivilegedProcess();
|
||||||
|
|
||||||
|
if (!m_goodbyeDPIProcess) {
|
||||||
|
return amnezia::ErrorCode::AmneziaServiceConnectionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_goodbyeDPIProcess->waitForSource(1000);
|
||||||
|
if (!m_goodbyeDPIProcess->isInitialized()) {
|
||||||
|
qWarning() << "IpcProcess replica is not connected!";
|
||||||
|
return amnezia::ErrorCode::AmneziaServiceConnectionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_goodbyeDPIProcess->setProgram(amnezia::PermittedProcess::GoodbyeDPI);
|
||||||
|
|
||||||
|
QStringList arguments;
|
||||||
|
arguments << QString("-%1").arg(modset);
|
||||||
|
arguments << QString("--blacklist %1").arg(blackListFile);
|
||||||
|
|
||||||
|
m_goodbyeDPIProcess->setArguments(arguments);
|
||||||
|
qDebug() << arguments.join(" ");
|
||||||
|
|
||||||
|
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::errorOccurred,
|
||||||
|
[&](QProcess::ProcessError error) { qDebug() << "PrivilegedProcess errorOccurred" << error; });
|
||||||
|
|
||||||
|
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::stateChanged, [&](QProcess::ProcessState newState) {
|
||||||
|
qDebug() << "PrivilegedProcess stateChanged" << newState;
|
||||||
|
if (newState == QProcess::Running) {
|
||||||
|
qDebug() << "PrivilegedProcess running";
|
||||||
|
emit serviceStateChanged(Vpn::ConnectionState::Connected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_goodbyeDPIProcess.data(), &PrivilegedProcess::finished, this, [&]() {
|
||||||
|
qDebug() << "PrivilegedProcess finished";
|
||||||
|
emit serviceStateChanged(Vpn::ConnectionState::Disconnected);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_goodbyeDPIProcess->start();
|
||||||
|
return amnezia::ErrorCode::NoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoodByeDpi::stop()
|
||||||
|
{
|
||||||
|
if (m_goodbyeDPIProcess) {
|
||||||
|
m_goodbyeDPIProcess->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef GOODBYEDPI_H
|
||||||
|
#define GOODBYEDPI_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "core/defs.h"
|
||||||
|
#include "core/privileged_process.h"
|
||||||
|
#include "protocols/vpnprotocol.h"
|
||||||
|
|
||||||
|
class GoodByeDpi : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit GoodByeDpi(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
amnezia::ErrorCode start(const QString &blackListFile, const int modset);
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedPointer<PrivilegedProcess> m_goodbyeDPIProcess;
|
||||||
|
signals:
|
||||||
|
void serviceStateChanged(Vpn::ConnectionState state);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GOODBYEDPI_H
|
||||||
@@ -100,6 +100,8 @@ namespace amnezia
|
|||||||
|
|
||||||
constexpr char clientId[] = "clientId";
|
constexpr char clientId[] = "clientId";
|
||||||
|
|
||||||
|
constexpr char isGoodbyeDpi[] = "is_goodbye_dpi";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace protocols
|
namespace protocols
|
||||||
@@ -254,7 +256,8 @@ namespace amnezia
|
|||||||
TorWebSite,
|
TorWebSite,
|
||||||
Dns,
|
Dns,
|
||||||
Sftp,
|
Sftp,
|
||||||
Socks5Proxy
|
Socks5Proxy,
|
||||||
|
GoodyeDPI
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(Proto)
|
Q_ENUM_NS(Proto)
|
||||||
|
|
||||||
|
|||||||
@@ -218,6 +218,7 @@
|
|||||||
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
|
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
|
||||||
<file>images/controls/archive-restore.svg</file>
|
<file>images/controls/archive-restore.svg</file>
|
||||||
<file>images/controls/help-circle.svg</file>
|
<file>images/controls/help-circle.svg</file>
|
||||||
|
<file>ui/qml/Pages2/LocalServices/PageGoodByeDpiSettings.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/countriesFlags">
|
<qresource prefix="/countriesFlags">
|
||||||
<file>images/flagKit/ZW.svg</file>
|
<file>images/flagKit/ZW.svg</file>
|
||||||
|
|||||||
@@ -538,3 +538,33 @@ void Settings::toggleDevGatewayEnv(bool enabled)
|
|||||||
{
|
{
|
||||||
m_isDevGatewayEnv = enabled;
|
m_isDevGatewayEnv = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Settings::setGoodbyeDpiBlackListFile(const QString &file)
|
||||||
|
{
|
||||||
|
setValue("Conf/goodbyeDpiBlackListFile", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Settings::getGoodbyeDpiBlackListFile() const
|
||||||
|
{
|
||||||
|
return value("Conf/goodbyeDpiBlackListFile").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::toggleGoodbyeDpi(bool enable)
|
||||||
|
{
|
||||||
|
setValue("Conf/isGoodbyeDpiEnabled", enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::isGoodbyeDpiEnabled() const
|
||||||
|
{
|
||||||
|
return value("Conf/isGoodbyeDpiEnabled", false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setGoodbyeDpiModset(const int modset)
|
||||||
|
{
|
||||||
|
setValue("Conf/goodbyeDpiModset", modset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Settings::getGoodbyeDpiModset() const
|
||||||
|
{
|
||||||
|
return value("Conf/goodbyeDpiModset", 9).toInt();
|
||||||
|
}
|
||||||
|
|||||||
+13
-1
@@ -113,7 +113,10 @@ public:
|
|||||||
QString routeModeString(RouteMode mode) const;
|
QString routeModeString(RouteMode mode) const;
|
||||||
|
|
||||||
RouteMode routeMode() const;
|
RouteMode routeMode() const;
|
||||||
void setRouteMode(RouteMode mode) { setValue("Conf/routeMode", mode); }
|
void setRouteMode(RouteMode mode)
|
||||||
|
{
|
||||||
|
setValue("Conf/routeMode", mode);
|
||||||
|
}
|
||||||
|
|
||||||
bool isSitesSplitTunnelingEnabled() const;
|
bool isSitesSplitTunnelingEnabled() const;
|
||||||
void setSitesSplitTunnelingEnabled(bool enabled);
|
void setSitesSplitTunnelingEnabled(bool enabled);
|
||||||
@@ -222,6 +225,15 @@ public:
|
|||||||
bool isDevGatewayEnv();
|
bool isDevGatewayEnv();
|
||||||
void toggleDevGatewayEnv(bool enabled);
|
void toggleDevGatewayEnv(bool enabled);
|
||||||
|
|
||||||
|
void setGoodbyeDpiBlackListFile(const QString &file);
|
||||||
|
QString getGoodbyeDpiBlackListFile() const;
|
||||||
|
|
||||||
|
void toggleGoodbyeDpi(bool enable);
|
||||||
|
bool isGoodbyeDpiEnabled() const;
|
||||||
|
|
||||||
|
void setGoodbyeDpiModset(const int modset);
|
||||||
|
int getGoodbyeDpiModset() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void saveLogsChanged(bool enabled);
|
void saveLogsChanged(bool enabled);
|
||||||
void screenshotsEnabledChanged(bool enabled);
|
void screenshotsEnabledChanged(bool enabled);
|
||||||
|
|||||||
@@ -44,6 +44,13 @@ void ConnectionController::openConnection()
|
|||||||
|
|
||||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
|
|
||||||
|
const auto isGoodbyeDpi = serverConfig.value(config_key::isGoodbyeDpi).toBool(false);
|
||||||
|
if (isGoodbyeDpi) {
|
||||||
|
emit startLocalService();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto configVersion = serverConfig.value(config_key::configVersion).toInt();
|
auto configVersion = serverConfig.value(config_key::configVersion).toInt();
|
||||||
|
|
||||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
|
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
|
||||||
@@ -65,6 +72,15 @@ void ConnectionController::openConnection()
|
|||||||
|
|
||||||
void ConnectionController::closeConnection()
|
void ConnectionController::closeConnection()
|
||||||
{
|
{
|
||||||
|
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||||
|
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
|
|
||||||
|
const auto isGoodbyeDpi = serverConfig.value(config_key::isGoodbyeDpi).toBool(false);
|
||||||
|
if (isGoodbyeDpi) {
|
||||||
|
emit stopLocalService();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emit disconnectFromVpn();
|
emit disconnectFromVpn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ signals:
|
|||||||
void updateApiConfigFromTelegram();
|
void updateApiConfigFromTelegram();
|
||||||
void configFromApiUpdated();
|
void configFromApiUpdated();
|
||||||
|
|
||||||
|
void startLocalService();
|
||||||
|
void stopLocalService();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vpn::ConnectionState getCurrentConnectionState();
|
Vpn::ConnectionState getCurrentConnectionState();
|
||||||
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
|
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#include "localServicesController.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Logger logger("ServerController");
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServicesController::LocalServicesController(const QSharedPointer<ServersModel> &serversModel,
|
||||||
|
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||||
|
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
connect(&m_goodbyeDpiService, &GoodByeDpi::serviceStateChanged, this, &LocalServicesController::serviceStateChanged);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalServicesController::~LocalServicesController()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
m_goodbyeDpiService.stop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServicesController::toggleGoodbyeDpi(bool enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
QJsonObject server;
|
||||||
|
server.insert(config_key::isGoodbyeDpi, true);
|
||||||
|
server.insert(config_key::description, "GoodbyeDPI service");
|
||||||
|
server.insert(config_key::name, "GoodbyeDPI");
|
||||||
|
m_serversModel->addServer(server);
|
||||||
|
m_serversModel->setDefaultServerIndex(m_serversModel->getServersCount() - 1);
|
||||||
|
|
||||||
|
m_settings->toggleGoodbyeDpi(true);
|
||||||
|
emit toggleGoodbyeDpiFinished(tr("GoodbyeDPI added to home page"));
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < m_serversModel->getServersCount(); i++) {
|
||||||
|
if (m_serversModel->getServerConfig(i).value(config_key::isGoodbyeDpi).toBool(false)) {
|
||||||
|
m_serversModel->setProcessedServerIndex(i);
|
||||||
|
m_serversModel->removeServer();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_settings->toggleGoodbyeDpi(false);
|
||||||
|
emit toggleGoodbyeDpiFinished("GoodbyeDPI removed from home page");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LocalServicesController::isGoodbyeDpiEnabled()
|
||||||
|
{
|
||||||
|
return m_settings->isGoodbyeDpiEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServicesController::setGoodbyeDpiBlackListFile(const QString &file)
|
||||||
|
{
|
||||||
|
m_settings->setGoodbyeDpiBlackListFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LocalServicesController::getGoodbyeDpiBlackListFile()
|
||||||
|
{
|
||||||
|
auto file = m_settings->getGoodbyeDpiBlackListFile();
|
||||||
|
if (file.isEmpty()) {
|
||||||
|
return m_defaultBlackListFile;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServicesController::resetGoodbyeDpiBlackListFile()
|
||||||
|
{
|
||||||
|
m_settings->setGoodbyeDpiBlackListFile(m_defaultBlackListFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServicesController::setGoodbyeDpiModset(const int modset)
|
||||||
|
{
|
||||||
|
m_settings->setGoodbyeDpiModset(modset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LocalServicesController::getGoodbyeDpiModset()
|
||||||
|
{
|
||||||
|
return m_settings->getGoodbyeDpiModset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServicesController::start()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
auto errorCode = m_goodbyeDpiService.start(getGoodbyeDpiBlackListFile(), getGoodbyeDpiModset());
|
||||||
|
if (errorCode != ErrorCode::NoError) {
|
||||||
|
emit errorOccurred(errorCode);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalServicesController::stop()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
m_goodbyeDpiService.stop();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef LOCALSERVICESCONTROLLER_H
|
||||||
|
#define LOCALSERVICESCONTROLLER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
#include "localServices/goodByeDpi.h"
|
||||||
|
#endif
|
||||||
|
#include "protocols/vpnprotocol.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "ui/models/servers_model.h"
|
||||||
|
|
||||||
|
class LocalServicesController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LocalServicesController(const QSharedPointer<ServersModel> &serversModel, const std::shared_ptr<Settings> &settings,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
~LocalServicesController();
|
||||||
|
|
||||||
|
Q_PROPERTY(bool isGoodbyeDpiEnabled READ isGoodbyeDpiEnabled NOTIFY toggleGoodbyeDpiFinished)
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void toggleGoodbyeDpi(bool enable);
|
||||||
|
bool isGoodbyeDpiEnabled();
|
||||||
|
|
||||||
|
void setGoodbyeDpiBlackListFile(const QString &file);
|
||||||
|
QString getGoodbyeDpiBlackListFile();
|
||||||
|
void resetGoodbyeDpiBlackListFile();
|
||||||
|
|
||||||
|
void setGoodbyeDpiModset(const int modset);
|
||||||
|
int getGoodbyeDpiModset();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void errorOccurred(ErrorCode errorCode);
|
||||||
|
void toggleGoodbyeDpiFinished(const QString &message);
|
||||||
|
void serviceStateChanged(Vpn::ConnectionState state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Settings> m_settings;
|
||||||
|
QSharedPointer<ServersModel> m_serversModel;
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
GoodByeDpi m_goodbyeDpiService;
|
||||||
|
#endif
|
||||||
|
bool m_isGoodbyeDpiServiceEnabled = false;
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
QString m_defaultBlackListFile = QCoreApplication::applicationDirPath() + "/goodbyedpi/blacklist.txt";
|
||||||
|
#else
|
||||||
|
QString m_defaultBlackListFile;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOCALSERVICESCONTROLLER_H
|
||||||
@@ -47,11 +47,19 @@ bool PageController::isStartPageVisible()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PageController::getPagePath(PageLoader::PageEnum page)
|
QString PageController::getPagePath(PageLoader::PageEnum page, PageLoader::FolderEnum folder)
|
||||||
{
|
{
|
||||||
QMetaEnum metaEnum = QMetaEnum::fromType<PageLoader::PageEnum>();
|
QMetaEnum metaEnum = QMetaEnum::fromType<PageLoader::PageEnum>();
|
||||||
QString pageName = metaEnum.valueToKey(static_cast<int>(page));
|
QString pageName = metaEnum.valueToKey(static_cast<int>(page));
|
||||||
return "qrc:/ui/qml/Pages2/" + pageName + ".qml";
|
|
||||||
|
metaEnum = QMetaEnum::fromType<PageLoader::FolderEnum>();
|
||||||
|
QString folderName = "";
|
||||||
|
if (metaEnum.value(static_cast<int>(folder)) != static_cast<int>(PageLoader::FolderEnum::Root)) {
|
||||||
|
folderName = metaEnum.valueToKey(static_cast<int>(folder));
|
||||||
|
folderName += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "qrc:/ui/qml/Pages2/" + folderName + pageName + ".qml";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageController::closeWindow()
|
void PageController::closeWindow()
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ namespace PageLoader
|
|||||||
|
|
||||||
PageShareFullAccess,
|
PageShareFullAccess,
|
||||||
|
|
||||||
PageDevMenu
|
PageDevMenu,
|
||||||
|
|
||||||
|
PageGoodByeDpiSettings
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(PageEnum)
|
Q_ENUM_NS(PageEnum)
|
||||||
|
|
||||||
@@ -69,6 +71,19 @@ namespace PageLoader
|
|||||||
{
|
{
|
||||||
qmlRegisterUncreatableMetaObject(PageLoader::staticMetaObject, "PageEnum", 1, 0, "PageEnum", "Error: only enums");
|
qmlRegisterUncreatableMetaObject(PageLoader::staticMetaObject, "PageEnum", 1, 0, "PageEnum", "Error: only enums");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_NAMESPACE
|
||||||
|
enum class FolderEnum {
|
||||||
|
Root = 0,
|
||||||
|
LocalServices
|
||||||
|
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(FolderEnum)
|
||||||
|
|
||||||
|
static void declareQmlFolderEnum()
|
||||||
|
{
|
||||||
|
qmlRegisterUncreatableMetaObject(PageLoader::staticMetaObject, "FolderEnum", 1, 0, "FolderEnum", "Error: only enums");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PageController : public QObject
|
class PageController : public QObject
|
||||||
@@ -80,7 +95,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool isStartPageVisible();
|
bool isStartPageVisible();
|
||||||
QString getPagePath(PageLoader::PageEnum page);
|
QString getPagePath(PageLoader::PageEnum page, PageLoader::FolderEnum folder = PageLoader::FolderEnum::Root);
|
||||||
|
|
||||||
void closeWindow();
|
void closeWindow();
|
||||||
void hideWindow();
|
void hideWindow();
|
||||||
@@ -103,7 +118,7 @@ public slots:
|
|||||||
void onShowErrorMessage(amnezia::ErrorCode errorCode);
|
void onShowErrorMessage(amnezia::ErrorCode errorCode);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void goToPage(PageLoader::PageEnum page, bool slide = true);
|
void goToPage(PageLoader::PageEnum page, PageLoader::FolderEnum folder = PageLoader::FolderEnum::Root, bool slide = true);
|
||||||
void goToStartPage();
|
void goToStartPage();
|
||||||
void goToPageHome();
|
void goToPageHome();
|
||||||
void goToPageSettings();
|
void goToPageSettings();
|
||||||
|
|||||||
@@ -16,8 +16,7 @@
|
|||||||
|
|
||||||
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
|
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
|
||||||
const QSharedPointer<ContainersModel> &containersModel,
|
const QSharedPointer<ContainersModel> &containersModel,
|
||||||
const QSharedPointer<LanguageModel> &languageModel,
|
const QSharedPointer<LanguageModel> &languageModel, const QSharedPointer<SitesModel> &sitesModel,
|
||||||
const QSharedPointer<SitesModel> &sitesModel,
|
|
||||||
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
|
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
|
||||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
@@ -31,7 +30,8 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
|
|||||||
m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
|
m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
|
||||||
checkIfNeedDisableLogs();
|
checkIfNeedDisableLogs();
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged);
|
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this,
|
||||||
|
&SettingsController::onNotificationStateChanged);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,8 +145,7 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
|||||||
bool ok = m_settings->restoreAppConfig(data);
|
bool ok = m_settings->restoreAppConfig(data);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
m_serversModel->resetModel();
|
m_serversModel->resetModel();
|
||||||
m_languageModel->changeLanguage(
|
m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
|
||||||
emit restoreBackupFinished();
|
emit restoreBackupFinished();
|
||||||
} else {
|
} else {
|
||||||
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
||||||
@@ -162,8 +161,7 @@ void SettingsController::clearSettings()
|
|||||||
{
|
{
|
||||||
m_settings->clearSettings();
|
m_settings->clearSettings();
|
||||||
m_serversModel->resetModel();
|
m_serversModel->resetModel();
|
||||||
m_languageModel->changeLanguage(
|
m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
|
||||||
|
|
||||||
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
||||||
m_sitesModel->toggleSplitTunneling(false);
|
m_sitesModel->toggleSplitTunneling(false);
|
||||||
|
|||||||
@@ -88,9 +88,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
|||||||
const QJsonObject server = m_servers.at(index.row()).toObject();
|
const QJsonObject server = m_servers.at(index.row()).toObject();
|
||||||
const auto apiConfig = server.value(configKey::apiConfig).toObject();
|
const auto apiConfig = server.value(configKey::apiConfig).toObject();
|
||||||
const auto configVersion = server.value(config_key::configVersion).toInt();
|
const auto configVersion = server.value(config_key::configVersion).toInt();
|
||||||
|
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case NameRole: {
|
case NameRole: {
|
||||||
if (configVersion) {
|
if (configVersion || isGoodbyeDpi) {
|
||||||
return server.value(config_key::name).toString();
|
return server.value(config_key::name).toString();
|
||||||
}
|
}
|
||||||
auto name = server.value(config_key::description).toString();
|
auto name = server.value(config_key::description).toString();
|
||||||
@@ -100,6 +101,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
case ServerDescriptionRole: {
|
case ServerDescriptionRole: {
|
||||||
|
if (isGoodbyeDpi) {
|
||||||
|
return server.value(config_key::description).toString();
|
||||||
|
}
|
||||||
|
|
||||||
auto description = getServerDescription(server, index.row());
|
auto description = getServerDescription(server, index.row());
|
||||||
return configVersion ? description : description + server.value(config_key::hostName).toString();
|
return configVersion ? description : description + server.value(config_key::hostName).toString();
|
||||||
}
|
}
|
||||||
@@ -144,6 +149,9 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
|||||||
QString primaryDns = server.value(config_key::dns1).toString();
|
QString primaryDns = server.value(config_key::dns1).toString();
|
||||||
return primaryDns == protocols::dns::amneziaDnsIp;
|
return primaryDns == protocols::dns::amneziaDnsIp;
|
||||||
}
|
}
|
||||||
|
case IsGoodByeDpiRole: {
|
||||||
|
return isGoodbyeDpi;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@@ -208,6 +216,12 @@ QString ServersModel::getServerDescription(const QJsonObject &server, const int
|
|||||||
const QString ServersModel::getDefaultServerDescriptionCollapsed()
|
const QString ServersModel::getDefaultServerDescriptionCollapsed()
|
||||||
{
|
{
|
||||||
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
|
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
|
||||||
|
|
||||||
|
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
|
||||||
|
if (isGoodbyeDpi) {
|
||||||
|
return server.value(config_key::description).toString();
|
||||||
|
}
|
||||||
|
|
||||||
const auto configVersion = server.value(config_key::configVersion).toInt();
|
const auto configVersion = server.value(config_key::configVersion).toInt();
|
||||||
auto description = getServerDescription(server, m_defaultServerIndex);
|
auto description = getServerDescription(server, m_defaultServerIndex);
|
||||||
if (configVersion) {
|
if (configVersion) {
|
||||||
@@ -222,6 +236,12 @@ const QString ServersModel::getDefaultServerDescriptionCollapsed()
|
|||||||
const QString ServersModel::getDefaultServerDescriptionExpanded()
|
const QString ServersModel::getDefaultServerDescriptionExpanded()
|
||||||
{
|
{
|
||||||
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
|
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
|
||||||
|
|
||||||
|
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
|
||||||
|
if (isGoodbyeDpi) {
|
||||||
|
return server.value(config_key::description).toString();
|
||||||
|
}
|
||||||
|
|
||||||
const auto configVersion = server.value(config_key::configVersion).toInt();
|
const auto configVersion = server.value(config_key::configVersion).toInt();
|
||||||
auto description = getServerDescription(server, m_defaultServerIndex);
|
auto description = getServerDescription(server, m_defaultServerIndex);
|
||||||
if (configVersion) {
|
if (configVersion) {
|
||||||
@@ -370,6 +390,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
|
|||||||
roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable";
|
roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable";
|
||||||
roles[ApiAvailableCountriesRole] = "apiAvailableCountries";
|
roles[ApiAvailableCountriesRole] = "apiAvailableCountries";
|
||||||
roles[ApiServerCountryCodeRole] = "apiServerCountryCode";
|
roles[ApiServerCountryCodeRole] = "apiServerCountryCode";
|
||||||
|
|
||||||
|
roles[IsGoodByeDpiRole] = "isGoodbyeDpi";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ public:
|
|||||||
ApiAvailableCountriesRole,
|
ApiAvailableCountriesRole,
|
||||||
ApiServerCountryCodeRole,
|
ApiServerCountryCodeRole,
|
||||||
|
|
||||||
HasAmneziaDns
|
HasAmneziaDns,
|
||||||
|
|
||||||
|
IsGoodByeDpiRole
|
||||||
};
|
};
|
||||||
|
|
||||||
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import PageEnum 1.0
|
||||||
|
import Style 1.0
|
||||||
|
|
||||||
|
import "./"
|
||||||
|
import "../../Controls2"
|
||||||
|
import "../../Config"
|
||||||
|
import "../../Controls2/TextTypes"
|
||||||
|
import "../../Components"
|
||||||
|
|
||||||
|
PageType {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
BackButtonType {
|
||||||
|
id: backButton
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
FlickableType {
|
||||||
|
id: fl
|
||||||
|
anchors.top: backButton.bottom
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
contentHeight: content.height
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: content
|
||||||
|
|
||||||
|
property bool isGoodbyeDpiEnabled: LocalServicesController.isGoodbyeDpiEnabled
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
|
HeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
headerText: qsTr("GoodbyeDPI settings")
|
||||||
|
descriptionText: qsTr("Deep Packet Inspection circumvention utility")
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitcherType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: qsTr("Enable GoodbyeDPI")
|
||||||
|
|
||||||
|
checked: LocalServicesController.isGoodbyeDpiEnabled
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (checked !== LocalServicesController.isGoodbyeDpiEnabled) {
|
||||||
|
LocalServicesController.toggleGoodbyeDpi(checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
enabled: !content.isGoodbyeDpiEnabled
|
||||||
|
|
||||||
|
ListItemTitleType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
text: LocalServicesController.getGoodbyeDpiBlackListFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButtonType {
|
||||||
|
image: "qrc:/images/controls/folder-search-2.svg"
|
||||||
|
imageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
var fileName = SystemController.getFileName(qsTr("Open black list file"),
|
||||||
|
qsTr("Text files (*.txt)"))
|
||||||
|
|
||||||
|
LocalServicesController.setGoodbyeDpiBlackListFile(fileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageButtonType {
|
||||||
|
image: "qrc:/images/controls/trash.svg"
|
||||||
|
imageColor: AmneziaStyle.color.paleGray
|
||||||
|
|
||||||
|
onClicked: function() {
|
||||||
|
LocalServicesController.resetGoodbyeDpiBlackListFile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDownType {
|
||||||
|
id: modsetDropDown
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
descriptionText: qsTr("Setup templates")
|
||||||
|
headerText: qsTr("Modset")
|
||||||
|
|
||||||
|
drawerParent: root
|
||||||
|
|
||||||
|
enabled: !content.isGoodbyeDpiEnabled
|
||||||
|
|
||||||
|
listView: ListViewWithRadioButtonType {
|
||||||
|
id: modsetListView
|
||||||
|
|
||||||
|
rootWidth: root.width
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
ListElement { name : "-p -r -s -f 2 -k 2 -n -e 2" }
|
||||||
|
ListElement { name : "-p -r -s -f 2 -k 2 -n -e 40" }
|
||||||
|
ListElement { name : "-p -r -s -e 40" }
|
||||||
|
ListElement { name : "-p -r -s" }
|
||||||
|
ListElement { name : "-f 2 -e 2 --auto-ttl --reverse-frag --max-payload" }
|
||||||
|
ListElement { name : "-f 2 -e 2 --wrong-seq --reverse-frag --max-payload" }
|
||||||
|
ListElement { name : "-f 2 -e 2 --wrong-chksum --reverse-frag --max-payload" }
|
||||||
|
ListElement { name : "-f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload" }
|
||||||
|
ListElement { name : "-f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload -q" }
|
||||||
|
}
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
modsetDropDown.text = selectedText
|
||||||
|
LocalServicesController.setGoodbyeDpiModset(currentIndex + 1)
|
||||||
|
modsetDropDown.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
modsetListView.currentIndex = (LocalServicesController.getGoodbyeDpiModset() - 1)
|
||||||
|
modsetListView.triggerCurrentItem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicButtonType {
|
||||||
|
id: detailedInstructionsButton
|
||||||
|
implicitHeight: 32
|
||||||
|
|
||||||
|
defaultColor: AmneziaStyle.color.transparent
|
||||||
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
|
disabledColor: AmneziaStyle.color.mutedGray
|
||||||
|
textColor: AmneziaStyle.color.goldenApricot
|
||||||
|
|
||||||
|
text: qsTr("Description of options")
|
||||||
|
|
||||||
|
clickedFunc: function() {
|
||||||
|
Qt.openUrlExternally("https://github.com/ValdikSS/GoodbyeDPI?tab=readme-ov-file#how-to-use")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -105,6 +105,8 @@ PageType {
|
|||||||
buttonTextLabel.font.pixelSize: 14
|
buttonTextLabel.font.pixelSize: 14
|
||||||
buttonTextLabel.font.weight: 500
|
buttonTextLabel.font.weight: 500
|
||||||
|
|
||||||
|
visible: !ServersModel.getDefaultServerData("isGoodbyeDpi")
|
||||||
|
|
||||||
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
|
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
|
||||||
ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||||
|
|
||||||
@@ -304,7 +306,7 @@ PageType {
|
|||||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
visible: !ServersModel.isDefaultServerFromApi
|
visible: !ServersModel.isDefaultServerFromApi && !ServersModel.getDefaultServerData("isGoodbyeDpi")
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: focusItem1
|
id: focusItem1
|
||||||
@@ -535,8 +537,12 @@ PageType {
|
|||||||
Keys.onReturnPressed: serverInfoButton.clicked()
|
Keys.onReturnPressed: serverInfoButton.clicked()
|
||||||
|
|
||||||
onClicked: function() {
|
onClicked: function() {
|
||||||
ServersModel.processedIndex = index
|
if (ServersModel.getDefaultServerData("isGoodbyeDpi")) {
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
PageController.goToPage(PageEnum.PageGoodByeDpiSettings, PageEnum.LocalServices)
|
||||||
|
} else {
|
||||||
|
ServersModel.processedIndex = index
|
||||||
|
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||||
|
}
|
||||||
drawer.close()
|
drawer.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,22 @@ PageType {
|
|||||||
|
|
||||||
DividerType {}
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: Qt.platform.os === "windows"
|
||||||
|
|
||||||
|
text: qsTr("Local bypass services")
|
||||||
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
leftImageSource: "qrc:/images/controls/app.svg"
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
PageController.goToPage(PageEnum.PageGoodByeDpiSettings, PageEnum.LocalServices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
LabelWithButtonType {
|
LabelWithButtonType {
|
||||||
id: backup
|
id: backup
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ PageType {
|
|||||||
id: server
|
id: server
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
visible: !isGoodbyeDpi
|
||||||
|
|
||||||
text: name
|
text: name
|
||||||
parentFlickable: fl
|
parentFlickable: fl
|
||||||
descriptionText: {
|
descriptionText: {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ PageType {
|
|||||||
function onServerAlreadyExists(serverIndex) {
|
function onServerAlreadyExists(serverIndex) {
|
||||||
PageController.goToStartPage()
|
PageController.goToStartPage()
|
||||||
ServersModel.processedIndex = serverIndex
|
ServersModel.processedIndex = serverIndex
|
||||||
PageController.goToPage(PageEnum.PageSettingsServerInfo, false)
|
PageController.goToPage(PageEnum.PageSettingsServerInfo, PageEnum.LocalServices, false)
|
||||||
|
|
||||||
PageController.showErrorMessage(qsTr("The server has already been added to the application"))
|
PageController.showErrorMessage(qsTr("The server has already been added to the application"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ PageType {
|
|||||||
tabBarStackView.pop()
|
tabBarStackView.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onGoToPage(page, slide) {
|
function onGoToPage(page, folder, slide) {
|
||||||
var pagePath = PageController.getPagePath(page)
|
var pagePath = PageController.getPagePath(page, folder)
|
||||||
|
|
||||||
if (slide) {
|
if (slide) {
|
||||||
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
|
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
|
||||||
@@ -212,6 +212,14 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: LocalServicesController
|
||||||
|
|
||||||
|
function onErrorOccurred(error) {
|
||||||
|
PageController.showErrorMessage(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StackViewType {
|
StackViewType {
|
||||||
id: tabBarStackView
|
id: tabBarStackView
|
||||||
|
|
||||||
|
|||||||
@@ -198,6 +198,15 @@ QString Utils::certUtilPath()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Utils::goodbyedpiPath()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
return Utils::executable("goodbyedpi/goodbyedpi", true);
|
||||||
|
#else
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
QString Utils::tun2socksPath()
|
QString Utils::tun2socksPath()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public:
|
|||||||
static QString wireguardExecPath();
|
static QString wireguardExecPath();
|
||||||
static QString certUtilPath();
|
static QString certUtilPath();
|
||||||
static QString tun2socksPath();
|
static QString tun2socksPath();
|
||||||
|
static QString goodbyedpiPath();
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
|
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ enum PermittedProcess {
|
|||||||
OpenVPN,
|
OpenVPN,
|
||||||
Wireguard,
|
Wireguard,
|
||||||
Tun2Socks,
|
Tun2Socks,
|
||||||
CertUtil
|
CertUtil,
|
||||||
|
GoodbyeDPI
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QString permittedProcessPath(PermittedProcess pid)
|
inline QString permittedProcessPath(PermittedProcess pid)
|
||||||
@@ -27,6 +28,8 @@ inline QString permittedProcessPath(PermittedProcess pid)
|
|||||||
return Utils::certUtilPath();
|
return Utils::certUtilPath();
|
||||||
} else if (pid == PermittedProcess::Tun2Socks) {
|
} else if (pid == PermittedProcess::Tun2Socks) {
|
||||||
return Utils::tun2socksPath();
|
return Utils::tun2socksPath();
|
||||||
|
} else if (pid == PermittedProcess::GoodbyeDPI){
|
||||||
|
return Utils::goodbyedpiPath();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user