mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
Compare commits
9 Commits
4.8.8.3
...
feature/go
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3b3e937e9 | ||
|
|
92492952e9 | ||
|
|
3d152adf5f | ||
|
|
9be3221cbe | ||
|
|
d47e37e04f | ||
|
|
5e27f0c8f0 | ||
|
|
c7a48aeabc | ||
|
|
ca1bf0d6cd | ||
|
|
96f26d5a01 |
Submodule client/3rd-prebuilt updated: c38a587fcd...a1d0c22a6f
@@ -241,8 +241,14 @@ file(GLOB UI_MODELS_CPP CONFIGURE_DEPENDS
|
||||
${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_CPP CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/ui/controllers/*.cpp)
|
||||
file(GLOB UI_CONTROLLERS_H CONFIGURE_DEPENDS
|
||||
${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}
|
||||
${COMMON_FILES_H}
|
||||
@@ -267,10 +273,12 @@ if(WIN32)
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.h
|
||||
)
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_windows.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/localServices/goodByeDpi.cpp
|
||||
)
|
||||
|
||||
set(RESOURCES ${RESOURCES}
|
||||
|
||||
@@ -235,6 +235,7 @@ void AmneziaApplication::registerTypes()
|
||||
|
||||
Vpn::declareQmlVpnConnectionStateEnum();
|
||||
PageLoader::declareQmlPageEnum();
|
||||
PageLoader::declareQmlFolderEnum();
|
||||
}
|
||||
|
||||
void AmneziaApplication::loadFonts()
|
||||
@@ -455,4 +456,13 @@ void AmneziaApplication::initControllers()
|
||||
|
||||
m_systemController.reset(new SystemController(m_settings));
|
||||
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/systemController.h"
|
||||
#include "ui/controllers/appSplitTunnelingController.h"
|
||||
#include "ui/controllers/localServicesController.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/languageModel.h"
|
||||
#include "ui/models/protocols/cloakConfigModel.h"
|
||||
@@ -136,6 +137,7 @@ private:
|
||||
QScopedPointer<SitesController> m_sitesController;
|
||||
QScopedPointer<SystemController> m_systemController;
|
||||
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
|
||||
QScopedPointer<LocalServicesController> m_localServicesController;
|
||||
|
||||
QNetworkAccessManager *m_nam;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "containers_defs.h"
|
||||
|
||||
#include "QJsonObject"
|
||||
#include "QJsonDocument"
|
||||
#include "QJsonObject"
|
||||
|
||||
QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
|
||||
{
|
||||
@@ -96,7 +96,7 @@ QMap<DockerContainer, QString> ContainerProps::containerHumanNames()
|
||||
{ DockerContainer::Awg, "AmneziaWG" },
|
||||
{ DockerContainer::Xray, "XRay" },
|
||||
{ DockerContainer::Ipsec, QObject::tr("IPsec") },
|
||||
{ DockerContainer::SSXray, "Shadowsocks"},
|
||||
{ DockerContainer::SSXray, "Shadowsocks" },
|
||||
|
||||
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
|
||||
{ DockerContainer::Dns, QObject::tr("AmneziaDNS") },
|
||||
@@ -124,27 +124,24 @@ QMap<DockerContainer, QString> ContainerProps::containerDescriptions()
|
||||
"but very resistant to blockages. "
|
||||
"Recommended for regions with high levels of censorship.") },
|
||||
{ DockerContainer::Xray,
|
||||
QObject::tr("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.") },
|
||||
QObject::tr(
|
||||
"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,
|
||||
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.") },
|
||||
|
||||
{ DockerContainer::TorWebSite, QObject::tr("Deploy a WordPress site on the Tor network in two clicks.") },
|
||||
{ DockerContainer::Dns,
|
||||
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::Socks5Proxy,
|
||||
QObject::tr("") } };
|
||||
{ DockerContainer::Dns, 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::Socks5Proxy, QObject::tr("") } };
|
||||
}
|
||||
|
||||
QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
||||
{
|
||||
return {
|
||||
{ DockerContainer::OpenVpn,
|
||||
QObject::tr(
|
||||
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
|
||||
QObject::tr("OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
|
||||
"It employs its unique security protocol, "
|
||||
"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, "
|
||||
@@ -160,7 +157,8 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
||||
"* Can operate over both TCP and UDP network protocols.") },
|
||||
{ DockerContainer::ShadowSocks,
|
||||
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. "
|
||||
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
|
||||
"* Available in the AmneziaVPN only on desktop platforms\n"
|
||||
@@ -217,15 +215,18 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
|
||||
"* Works over UDP network protocol.") },
|
||||
{ DockerContainer::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"
|
||||
"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, "
|
||||
"is specifically designed to counteract the highest levels of internet censorship through its novel approach to "
|
||||
"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"
|
||||
"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"
|
||||
"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. "
|
||||
"This makes REALITY a robust solution for maintaining internet freedom in environments with stringent censorship.")
|
||||
},
|
||||
"REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security and circumvents detection "
|
||||
"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,
|
||||
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, "
|
||||
@@ -287,7 +288,8 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
case DockerContainer::Awg: return true;
|
||||
case DockerContainer::Xray: return true;
|
||||
case DockerContainer::Cloak: return true;
|
||||
case DockerContainer::SSXray: return true;
|
||||
case DockerContainer::SSXray:
|
||||
return true;
|
||||
// case DockerContainer::ShadowSocks: return true;
|
||||
default: return false;
|
||||
}
|
||||
@@ -383,10 +385,8 @@ bool ContainerProps::isShareable(DockerContainer container)
|
||||
|
||||
QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
|
||||
{
|
||||
QString protocolConfigString = containerConfig.value(ProtocolProps::protoToString(protocol))
|
||||
.toObject()
|
||||
.value(config_key::last_config)
|
||||
.toString();
|
||||
QString protocolConfigString =
|
||||
containerConfig.value(ProtocolProps::protoToString(protocol)).toObject().value(config_key::last_config).toString();
|
||||
|
||||
return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ namespace amnezia
|
||||
ExecutableMissing = 604,
|
||||
XrayExecutableMissing = 605,
|
||||
Tun2SockExecutableMissing = 606,
|
||||
GoodByeDPIExecutableMissing = 607,
|
||||
|
||||
// VPN errors
|
||||
OpenVpnAdaptersInUseError = 700,
|
||||
|
||||
@@ -43,6 +43,7 @@ QString errorString(ErrorCode code) {
|
||||
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::OpenSslFailed): errorMessage = QObject::tr("OpenSSL failed"); break;
|
||||
case (ErrorCode::GoodByeDPIExecutableMissing): errorMessage = QObject::tr("GoodbyeDPI executable missing"); break;
|
||||
|
||||
// VPN errors
|
||||
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
|
||||
|
||||
62
client/localServices/goodByeDpi.cpp
Normal file
62
client/localServices/goodByeDpi.cpp
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
25
client/localServices/goodByeDpi.h
Normal file
25
client/localServices/goodByeDpi.h
Normal file
@@ -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 isGoodbyeDpi[] = "is_goodbye_dpi";
|
||||
|
||||
}
|
||||
|
||||
namespace protocols
|
||||
@@ -254,7 +256,8 @@ namespace amnezia
|
||||
TorWebSite,
|
||||
Dns,
|
||||
Sftp,
|
||||
Socks5Proxy
|
||||
Socks5Proxy,
|
||||
GoodyeDPI
|
||||
};
|
||||
Q_ENUM_NS(Proto)
|
||||
|
||||
|
||||
@@ -218,6 +218,7 @@
|
||||
<file>ui/qml/Pages2/PageSettingsApiLanguageList.qml</file>
|
||||
<file>images/controls/archive-restore.svg</file>
|
||||
<file>images/controls/help-circle.svg</file>
|
||||
<file>ui/qml/Pages2/LocalServices/PageGoodByeDpiSettings.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/countriesFlags">
|
||||
<file>images/flagKit/ZW.svg</file>
|
||||
|
||||
@@ -538,3 +538,33 @@ void Settings::toggleDevGatewayEnv(bool 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();
|
||||
}
|
||||
|
||||
@@ -113,7 +113,10 @@ public:
|
||||
QString routeModeString(RouteMode mode) const;
|
||||
|
||||
RouteMode routeMode() const;
|
||||
void setRouteMode(RouteMode mode) { setValue("Conf/routeMode", mode); }
|
||||
void setRouteMode(RouteMode mode)
|
||||
{
|
||||
setValue("Conf/routeMode", mode);
|
||||
}
|
||||
|
||||
bool isSitesSplitTunnelingEnabled() const;
|
||||
void setSitesSplitTunnelingEnabled(bool enabled);
|
||||
@@ -222,6 +225,15 @@ public:
|
||||
bool isDevGatewayEnv();
|
||||
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:
|
||||
void saveLogsChanged(bool enabled);
|
||||
void screenshotsEnabledChanged(bool enabled);
|
||||
|
||||
@@ -44,6 +44,13 @@ void ConnectionController::openConnection()
|
||||
|
||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||
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();
|
||||
|
||||
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
|
||||
@@ -65,6 +72,15 @@ void ConnectionController::openConnection()
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@ signals:
|
||||
void updateApiConfigFromTelegram();
|
||||
void configFromApiUpdated();
|
||||
|
||||
void startLocalService();
|
||||
void stopLocalService();
|
||||
|
||||
private:
|
||||
Vpn::ConnectionState getCurrentConnectionState();
|
||||
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
|
||||
|
||||
99
client/ui/controllers/localServicesController.cpp
Normal file
99
client/ui/controllers/localServicesController.cpp
Normal file
@@ -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
|
||||
}
|
||||
58
client/ui/controllers/localServicesController.h
Normal file
58
client/ui/controllers/localServicesController.h
Normal file
@@ -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>();
|
||||
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()
|
||||
|
||||
@@ -61,7 +61,9 @@ namespace PageLoader
|
||||
|
||||
PageShareFullAccess,
|
||||
|
||||
PageDevMenu
|
||||
PageDevMenu,
|
||||
|
||||
PageGoodByeDpiSettings
|
||||
};
|
||||
Q_ENUM_NS(PageEnum)
|
||||
|
||||
@@ -69,6 +71,19 @@ namespace PageLoader
|
||||
{
|
||||
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
|
||||
@@ -80,7 +95,7 @@ public:
|
||||
|
||||
public slots:
|
||||
bool isStartPageVisible();
|
||||
QString getPagePath(PageLoader::PageEnum page);
|
||||
QString getPagePath(PageLoader::PageEnum page, PageLoader::FolderEnum folder = PageLoader::FolderEnum::Root);
|
||||
|
||||
void closeWindow();
|
||||
void hideWindow();
|
||||
@@ -103,7 +118,7 @@ public slots:
|
||||
void onShowErrorMessage(amnezia::ErrorCode errorCode);
|
||||
|
||||
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 goToPageHome();
|
||||
void goToPageSettings();
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<LanguageModel> &languageModel,
|
||||
const QSharedPointer<SitesModel> &sitesModel,
|
||||
const QSharedPointer<LanguageModel> &languageModel, const QSharedPointer<SitesModel> &sitesModel,
|
||||
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
|
||||
const std::shared_ptr<Settings> &settings, 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);
|
||||
checkIfNeedDisableLogs();
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged);
|
||||
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this,
|
||||
&SettingsController::onNotificationStateChanged);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -145,8 +145,7 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
||||
bool ok = m_settings->restoreAppConfig(data);
|
||||
if (ok) {
|
||||
m_serversModel->resetModel();
|
||||
m_languageModel->changeLanguage(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
emit restoreBackupFinished();
|
||||
} else {
|
||||
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
||||
@@ -162,8 +161,7 @@ void SettingsController::clearSettings()
|
||||
{
|
||||
m_settings->clearSettings();
|
||||
m_serversModel->resetModel();
|
||||
m_languageModel->changeLanguage(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
m_languageModel->changeLanguage(static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
|
||||
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
||||
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 auto apiConfig = server.value(configKey::apiConfig).toObject();
|
||||
const auto configVersion = server.value(config_key::configVersion).toInt();
|
||||
const auto isGoodbyeDpi = server.value(config_key::isGoodbyeDpi).toBool(false);
|
||||
switch (role) {
|
||||
case NameRole: {
|
||||
if (configVersion) {
|
||||
if (configVersion || isGoodbyeDpi) {
|
||||
return server.value(config_key::name).toString();
|
||||
}
|
||||
auto name = server.value(config_key::description).toString();
|
||||
@@ -100,6 +101,10 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
|
||||
return name;
|
||||
}
|
||||
case ServerDescriptionRole: {
|
||||
if (isGoodbyeDpi) {
|
||||
return server.value(config_key::description).toString();
|
||||
}
|
||||
|
||||
auto description = getServerDescription(server, index.row());
|
||||
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();
|
||||
return primaryDns == protocols::dns::amneziaDnsIp;
|
||||
}
|
||||
case IsGoodByeDpiRole: {
|
||||
return isGoodbyeDpi;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -208,6 +216,12 @@ QString ServersModel::getServerDescription(const QJsonObject &server, const int
|
||||
const QString ServersModel::getDefaultServerDescriptionCollapsed()
|
||||
{
|
||||
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();
|
||||
auto description = getServerDescription(server, m_defaultServerIndex);
|
||||
if (configVersion) {
|
||||
@@ -222,6 +236,12 @@ const QString ServersModel::getDefaultServerDescriptionCollapsed()
|
||||
const QString ServersModel::getDefaultServerDescriptionExpanded()
|
||||
{
|
||||
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();
|
||||
auto description = getServerDescription(server, m_defaultServerIndex);
|
||||
if (configVersion) {
|
||||
@@ -370,6 +390,8 @@ QHash<int, QByteArray> ServersModel::roleNames() const
|
||||
roles[IsCountrySelectionAvailableRole] = "isCountrySelectionAvailable";
|
||||
roles[ApiAvailableCountriesRole] = "apiAvailableCountries";
|
||||
roles[ApiServerCountryCodeRole] = "apiServerCountryCode";
|
||||
|
||||
roles[IsGoodByeDpiRole] = "isGoodbyeDpi";
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ public:
|
||||
ApiAvailableCountriesRole,
|
||||
ApiServerCountryCodeRole,
|
||||
|
||||
HasAmneziaDns
|
||||
HasAmneziaDns,
|
||||
|
||||
IsGoodByeDpiRole
|
||||
};
|
||||
|
||||
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
|
||||
159
client/ui/qml/Pages2/LocalServices/PageGoodByeDpiSettings.qml
Normal file
159
client/ui/qml/Pages2/LocalServices/PageGoodByeDpiSettings.qml
Normal file
@@ -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.weight: 500
|
||||
|
||||
visible: !ServersModel.getDefaultServerData("isGoodbyeDpi")
|
||||
|
||||
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
|
||||
ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
|
||||
@@ -304,7 +306,7 @@ PageType {
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
spacing: 8
|
||||
|
||||
visible: !ServersModel.isDefaultServerFromApi
|
||||
visible: !ServersModel.isDefaultServerFromApi && !ServersModel.getDefaultServerData("isGoodbyeDpi")
|
||||
|
||||
Item {
|
||||
id: focusItem1
|
||||
@@ -535,8 +537,12 @@ PageType {
|
||||
Keys.onReturnPressed: serverInfoButton.clicked()
|
||||
|
||||
onClicked: function() {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
if (ServersModel.getDefaultServerData("isGoodbyeDpi")) {
|
||||
PageController.goToPage(PageEnum.PageGoodByeDpiSettings, PageEnum.LocalServices)
|
||||
} else {
|
||||
ServersModel.processedIndex = index
|
||||
PageController.goToPage(PageEnum.PageSettingsServerInfo)
|
||||
}
|
||||
drawer.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,22 @@ PageType {
|
||||
|
||||
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 {
|
||||
id: backup
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -111,6 +111,8 @@ PageType {
|
||||
id: server
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: !isGoodbyeDpi
|
||||
|
||||
text: name
|
||||
parentFlickable: fl
|
||||
descriptionText: {
|
||||
|
||||
@@ -54,7 +54,7 @@ PageType {
|
||||
function onServerAlreadyExists(serverIndex) {
|
||||
PageController.goToStartPage()
|
||||
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"))
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ PageType {
|
||||
tabBarStackView.pop()
|
||||
}
|
||||
|
||||
function onGoToPage(page, slide) {
|
||||
var pagePath = PageController.getPagePath(page)
|
||||
function onGoToPage(page, folder, slide) {
|
||||
var pagePath = PageController.getPagePath(page, folder)
|
||||
|
||||
if (slide) {
|
||||
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
|
||||
@@ -212,6 +212,14 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: LocalServicesController
|
||||
|
||||
function onErrorOccurred(error) {
|
||||
PageController.showErrorMessage(error)
|
||||
}
|
||||
}
|
||||
|
||||
StackViewType {
|
||||
id: tabBarStackView
|
||||
|
||||
|
||||
@@ -198,6 +198,15 @@ QString Utils::certUtilPath()
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Utils::goodbyedpiPath()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable("goodbyedpi/goodbyedpi", true);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
QString Utils::tun2socksPath()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
static QString wireguardExecPath();
|
||||
static QString certUtilPath();
|
||||
static QString tun2socksPath();
|
||||
static QString goodbyedpiPath();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
|
||||
|
||||
@@ -14,7 +14,8 @@ enum PermittedProcess {
|
||||
OpenVPN,
|
||||
Wireguard,
|
||||
Tun2Socks,
|
||||
CertUtil
|
||||
CertUtil,
|
||||
GoodbyeDPI
|
||||
};
|
||||
|
||||
inline QString permittedProcessPath(PermittedProcess pid)
|
||||
@@ -27,6 +28,8 @@ inline QString permittedProcessPath(PermittedProcess pid)
|
||||
return Utils::certUtilPath();
|
||||
} else if (pid == PermittedProcess::Tun2Socks) {
|
||||
return Utils::tun2socksPath();
|
||||
} else if (pid == PermittedProcess::GoodbyeDPI){
|
||||
return Utils::goodbyedpiPath();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user