refactoring: keep moving

This commit is contained in:
vladimir.kuznetsov
2025-08-08 14:16:01 +08:00
parent 6b0c543fd2
commit 1b6442079a
43 changed files with 1591 additions and 1261 deletions

69
.cursorrules Normal file
View File

@@ -0,0 +1,69 @@
# Amnezia VPN Client - MVVM Refactoring Rules
## Architecture Requirements
### MVVM Pattern
- Follow Model-View-ViewModel architecture strictly
- Maintain clear separation of concerns between layers
- UI controllers should only handle user input and delegate to core controllers
- Core controllers contain all business logic and data manipulation
### Dependencies Direction
- UI layer depends on Core layer (unidirectional dependency)
- UI controllers must not depend on each other
- Core controllers must not depend on each other (exceptions: ServerController, VpnConfigurationsController, GatewayController can be created "on the fly")
### Settings Usage
- UI classes must NOT use Settings class directly
- Create wrapper methods in core controllers for Settings operations
### Server Controller Creation
- ServerController creation must happen in Core controllers, never in UI
- Remove direct instantiation: `new ServerController(m_settings)` from UI code
## Code Organization
### Folder Structure
- Core controllers: `client/core/controllers/`
- Core models: `client/core/models/`
- UI controllers: `client/ui/controllers/`
- UI models: `client/ui/models/`
- Common models and controllers in root of respective folders
### Controller Management
- All controllers must be instantiated in central `coreController`
- Dependencies between core controllers resolved in `coreController`
- UI controllers accept core controllers via constructor injection
- UI controllers should be renamed with "UI" suffix (e.g., `exportUIController`)
## Code Style
### Comments
- Do NOT include comments in code
- Code should be self-documenting
### Models Behavior
- Models should only display data
- Keep core models as pure data structures without business logic
## Refactoring Process
### UI Controller Refactoring
- Remove all business logic from UI controllers
- Replace direct method calls with delegation to core controllers
- Maintain only UI-specific logic (signals, model updates)
- Remove Settings dependencies
### Core Controller Pattern
- Create corresponding methods in core controllers for UI operations
- Core controllers handle all complex logic, network operations, file I/O
- Return structured results with error codes and data
- Manage ServerController lifecycle internally
## Git Workflow
- Use `git mv` for renaming controllers to maintain history
## Error Handling
- Core controllers return structured error results
- UI controllers only handle error presentation
- Maintain consistent error propagation patterns

View File

@@ -21,7 +21,7 @@ set(HEADERS ${HEADERS}
${CLIENT_ROOT_DIR}/core/controllers/dnsController.h
${CLIENT_ROOT_DIR}/core/controllers/splitTunnelingController.h
${CLIENT_ROOT_DIR}/core/controllers/settingsController.h
${CLIENT_ROOT_DIR}/core/controllers/vpnConnectionController.h
${CLIENT_ROOT_DIR}/core/controllers/connectionController.h
${CLIENT_ROOT_DIR}/core/controllers/vpnConfigurationController.h
${CLIENT_ROOT_DIR}/protocols/protocols_defs.h
${CLIENT_ROOT_DIR}/protocols/qml_register_protocols.h
@@ -77,7 +77,7 @@ set(SOURCES ${SOURCES}
${CLIENT_ROOT_DIR}/core/controllers/dnsController.cpp
${CLIENT_ROOT_DIR}/core/controllers/splitTunnelingController.cpp
${CLIENT_ROOT_DIR}/core/controllers/settingsController.cpp
${CLIENT_ROOT_DIR}/core/controllers/vpnConnectionController.cpp
${CLIENT_ROOT_DIR}/core/controllers/connectionController.cpp
${CLIENT_ROOT_DIR}/core/controllers/vpnConfigurationController.cpp
${CLIENT_ROOT_DIR}/protocols/protocols_defs.cpp
${CLIENT_ROOT_DIR}/ui/qautostart.cpp

View File

@@ -1,9 +1,6 @@
#include "awg_configurator.h"
#include "protocols/protocols_defs.h"
#include <QJsonDocument>
#include <QJsonObject>
AwgConfigurator::AwgConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, QObject *parent)
: WireguardConfigurator(settings, serverController, true, parent)
{

View File

@@ -1,29 +1,32 @@
#include "configurator_base.h"
#include "core/networkUtilities.h"
#include "core/models/protocols/protocolConfig.h"
#include <variant>
ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, QObject *parent)
: QObject { parent }, m_settings(settings), m_serverController(serverController)
{
}
QString ConfiguratorBase::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
void ConfiguratorBase::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
processConfigWithDnsSettings(dns, protocolConfig);
}
QString ConfiguratorBase::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
void ConfiguratorBase::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
processConfigWithDnsSettings(dns, protocolConfig);
}
void ConfiguratorBase::processConfigWithDnsSettings(const QPair<QString, QString> &dns, QString &protocolConfigString)
void ConfiguratorBase::processConfigWithDnsSettings(const QPair<QString, QString> &dns, QSharedPointer<ProtocolConfig> &protocolConfig)
{
protocolConfigString.replace("$PRIMARY_DNS", dns.first);
protocolConfigString.replace("$SECONDARY_DNS", dns.second);
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([&dns](const auto &config) -> void {
config->clientProtocolConfig.nativeConfig.replace("$PRIMARY_DNS", dns.first);
config->clientProtocolConfig.nativeConfig.replace("$SECONDARY_DNS", dns.second);
}, variant);
}
ConfiguratorBase::Vars ConfiguratorBase::generateProtocolVars(const ServerCredentials &credentials, DockerContainer container,

View File

@@ -23,16 +23,16 @@ public:
virtual QSharedPointer<ProtocolConfig> createConfig(const ServerCredentials &credentials, DockerContainer container,
const QSharedPointer<ProtocolConfig> &protocolConfig, ErrorCode &errorCode) = 0;
virtual QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
virtual QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
virtual void processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig);
virtual void processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig);
virtual Vars generateProtocolVars(const ServerCredentials &credentials, DockerContainer container,
const QSharedPointer<ProtocolConfig> &protocolConfig) const;
protected:
void processConfigWithDnsSettings(const QPair<QString, QString> &dns, QString &protocolConfigString);
void processConfigWithDnsSettings(const QPair<QString, QString> &dns, QSharedPointer<ProtocolConfig> &protocolConfig);
Vars generateCommonVars(const ServerCredentials &credentials, DockerContainer container) const;

View File

@@ -1,8 +1,7 @@
#include "openvpn_configurator.h"
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QProcess>
#include <QString>
#include <QTemporaryDir>
@@ -14,6 +13,8 @@
#endif
#include "core/networkUtilities.h"
#include "core/models/protocols/protocolConfig.h"
#include <variant>
#include "core/models/containers/containers_defs.h"
#include "core/controllers/selfhosted/serverController.h"
#include "core/scripts_registry.h"
@@ -146,83 +147,93 @@ QSharedPointer<ProtocolConfig> OpenVpnConfigurator::createConfig(const ServerCre
return openVpnConfig;
}
QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
void OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig)
{
processConfigWithDnsSettings(dns, protocolConfigString);
processConfigWithDnsSettings(dns, protocolConfig);
QJsonObject json = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
QString config = json[config_key::config].toString();
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([this, &dns, isApiConfig](const auto &config) -> void {
if constexpr (std::is_same_v<std::decay_t<decltype(config)>, QSharedPointer<OpenVpnProtocolConfig>>) {
QString &nativeConfig = config->clientProtocolConfig.nativeConfig;
if (!isApiConfig) {
QRegularExpression regex("redirect-gateway.*");
config.replace(regex, "");
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
config.replace(dnsRegex, "");
}
if (!isApiConfig) {
QRegularExpression regex("redirect-gateway.*");
nativeConfig.replace(regex, "");
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
nativeConfig.replace(dnsRegex, "");
}
if (!m_settings->isSitesSplitTunnelingEnabled()) {
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
config.append("block-ipv6\n");
} else if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
if (!m_settings->isSitesSplitTunnelingEnabled()) {
nativeConfig.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
nativeConfig.append("block-ipv6\n");
} else if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
// no redirect-gateway
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
// no redirect-gateway
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
// Prevent ipv6 leak
nativeConfig.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
// Prevent ipv6 leak
#endif
config.append("block-ipv6\n");
}
}
nativeConfig.append("block-ipv6\n");
}
QStringList routeList = m_settings->vpnRoutes();
if (!routeList.isEmpty()) {
for (auto route : routeList) {
nativeConfig.append("\nroute " + route + " 255.255.255.255 vpn_gateway\n");
}
}
}
#ifndef MZ_WINDOWS
config.replace("block-outside-dns", "");
nativeConfig.replace("block-outside-dns", "");
#endif
#if (defined(MZ_MACOS) || defined(MZ_LINUX))
QString dnsConf = QString("\nscript-security 2\n"
"up %1/update-resolv-conf.sh\n"
"down %1/update-resolv-conf.sh\n")
.arg(qApp->applicationDirPath());
QString dnsConf = QString("\nscript-security 2\n"
"up %1/update-resolv-conf.sh\n"
"down %1/update-resolv-conf.sh\n")
.arg(qApp->applicationDirPath());
config.append(dnsConf);
nativeConfig.append(dnsConf);
#endif
json[config_key::config] = config;
return QJsonDocument(json).toJson();
}
}, variant);
}
QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
void OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig)
{
processConfigWithDnsSettings(dns, protocolConfigString);
processConfigWithDnsSettings(dns, protocolConfig);
QJsonObject json = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
QString config = json[config_key::config].toString();
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([&dns](const auto &config) -> void {
if constexpr (std::is_same_v<std::decay_t<decltype(config)>, QSharedPointer<OpenVpnProtocolConfig>>) {
QString &nativeConfig = config->clientProtocolConfig.nativeConfig;
QRegularExpression regex("redirect-gateway.*");
config.replace(regex, "");
QRegularExpression regex("redirect-gateway.*");
nativeConfig.replace(regex, "");
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
config.replace(dnsRegex, "");
}
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
nativeConfig.replace(dnsRegex, "");
}
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
nativeConfig.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
// Prevent ipv6 leak
config.append("block-ipv6\n");
// Prevent ipv6 leak
nativeConfig.append("block-ipv6\n");
// remove block-outside-dns for all exported configs
config.replace("block-outside-dns", "");
json[config_key::config] = config;
return QJsonDocument(json).toJson();
// remove block-outside-dns for all exported configs
nativeConfig.replace("block-outside-dns", "");
}
}, variant);
}
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId)

View File

@@ -28,10 +28,10 @@ public:
QSharedPointer<ProtocolConfig> createConfig(const ServerCredentials &credentials, DockerContainer container,
const QSharedPointer<ProtocolConfig> &protocolConfig, ErrorCode &errorCode) override;
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
void processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig) override;
void processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig) override;
Vars generateProtocolVars(const ServerCredentials &credentials, DockerContainer container,
const QSharedPointer<ProtocolConfig> &protocolConfig) const override;

View File

@@ -296,18 +296,14 @@ QSharedPointer<ProtocolConfig> WireguardConfigurator::createConfig(const ServerC
return result;
}
QString WireguardConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns,
const bool isApiConfig, QString &protocolConfigString)
void WireguardConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns,
const bool isApiConfig, QSharedPointer<ProtocolConfig> &protocolConfig)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
processConfigWithDnsSettings(dns, protocolConfig);
}
QString WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns,
const bool isApiConfig, QString &protocolConfigString)
void WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns,
const bool isApiConfig, QSharedPointer<ProtocolConfig> &protocolConfig)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
processConfigWithDnsSettings(dns, protocolConfig);
}

View File

@@ -32,10 +32,10 @@ public:
QSharedPointer<ProtocolConfig> createConfig(const ServerCredentials &credentials, DockerContainer container,
const QSharedPointer<ProtocolConfig> &protocolConfig, ErrorCode &errorCode) override;
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
void processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig) override;
void processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QSharedPointer<ProtocolConfig> &protocolConfig) override;
Vars generateProtocolVars(const ServerCredentials &credentials, DockerContainer container,
const QSharedPointer<ProtocolConfig> &protocolConfig) const override;

View File

@@ -7,6 +7,11 @@
#include "core/networkUtilities.h"
#include "protocols/protocols_defs.h"
#include "settings.h"
#include "core/models/protocols/awgProtocolConfig.h"
#include "core/models/protocols/wireguardProtocolConfig.h"
#include "core/models/protocols/openvpnProtocolConfig.h"
#include "core/models/protocols/shadowsocksProtocolConfig.h"
#include "core/models/protocols/cloakProtocolConfig.h"
ConfigController::ConfigController(std::shared_ptr<Settings> settings, QObject *parent)
: QObject(parent), m_settings(settings)
@@ -151,3 +156,69 @@ void ConfigController::updateServerInSettings(const QSharedPointer<ServerConfig>
{
m_settings->editServer(serverIndex, serverConfig->toJson());
}
bool ConfigController::isDefaultServerDefaultContainerHasSplitTunneling() const
{
int defaultServerIndex = m_settings->defaultServerIndex();
auto servers = m_settings->serversArray();
if (defaultServerIndex >= servers.size()) return false;
auto serverConfig = ServerConfig::createServerConfig(servers.at(defaultServerIndex).toObject());
if (!serverConfig->containerConfigs.contains(serverConfig->defaultContainer)) {
return false;
}
const auto &containerConfig = serverConfig->containerConfigs[serverConfig->defaultContainer];
return checkSplitTunnelingInContainer(containerConfig, serverConfig->defaultContainer);
}
bool ConfigController::checkSplitTunnelingInContainer(const ContainerConfig &containerConfig, const QString &defaultContainer) const
{
const DockerContainer containerType = ContainerProps::containerFromString(defaultContainer);
auto isWireguardHasSplit = [](const QString &nativeConfig, const QStringList &allowedIps) -> bool {
if (nativeConfig.contains("AllowedIPs") && !nativeConfig.contains("AllowedIPs = 0.0.0.0/0, ::/0")) {
return true;
}
if (!allowedIps.isEmpty() && !allowedIps.contains("0.0.0.0/0")) {
return true;
}
return false;
};
if (containerType == DockerContainer::Awg || containerType == DockerContainer::WireGuard) {
const auto protocolConfig = containerConfig.protocolConfigs.value(defaultContainer);
if (!protocolConfig) return false;
auto variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
return std::visit(
[&](const auto &ptr) -> bool {
using T = std::decay_t<decltype(ptr)>;
if constexpr (std::is_same_v<T, QSharedPointer<AwgProtocolConfig>> || std::is_same_v<T, QSharedPointer<WireGuardProtocolConfig>>) {
return isWireguardHasSplit(ptr->clientProtocolConfig.nativeConfig,
ptr->clientProtocolConfig.wireGuardData.allowedIps);
}
return false;
},
variant);
}
if (containerType == DockerContainer::Cloak || containerType == DockerContainer::OpenVpn || containerType == DockerContainer::ShadowSocks) {
const auto &protocolConfig = containerConfig.protocolConfigs.value(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
if (!protocolConfig) return false;
auto variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
return std::visit(
[&](const auto &ptr) -> bool {
using T = std::decay_t<decltype(ptr)>;
if constexpr (std::is_same_v<T, QSharedPointer<OpenVpnProtocolConfig>> ||
std::is_same_v<T, QSharedPointer<ShadowsocksProtocolConfig>> ||
std::is_same_v<T, QSharedPointer<CloakProtocolConfig>>) {
const auto nativeConfig = ptr->clientProtocolConfig.nativeConfig;
return (!nativeConfig.isEmpty() && !nativeConfig.contains("redirect-gateway"));
}
return false;
},
variant);
}
return false;
}

View File

@@ -40,12 +40,17 @@ public:
QStringList getAllInstalledServicesName(int serverIndex) const;
void clearCachedProfile(int serverIndex, DockerContainer container);
// Split tunneling detection
bool isDefaultServerDefaultContainerHasSplitTunneling() const;
protected:
std::shared_ptr<Settings> m_settings;
// Protected helper methods for derived classes
void updateServerInSettings(const QSharedPointer<ServerConfig> &serverConfig, int serverIndex);
bool checkSplitTunnelingInContainer(const ContainerConfig &containerConfig, const QString &defaultContainer) const;
signals:
// Common server management signals
void serverAdded(int serverIndex);

View File

@@ -0,0 +1,88 @@
#include "connectionController.h"
#include <QtConcurrent>
#include "core/controllers/vpnConfigurationController.h"
#include "core/controllers/selfhosted/serverController.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/containers/containerConfig.h"
#include "settings.h"
#include "logger.h"
#include "utilities.h"
namespace
{
Logger logger("ConnectionController");
}
ConnectionController::ConnectionController(const QSharedPointer<VpnConnection> &vpnConnection,
std::shared_ptr<Settings> settings,
QObject *parent)
: QObject(parent), m_vpnConnection(vpnConnection), m_settings(settings)
{
}
QFuture<QJsonObject> ConnectionController::prepareVpnConfiguration(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container,
const QPair<QString, QString> &dns) const
{
return QtConcurrent::run([this, serverConfig, container, dns]() -> QJsonObject {
logger.info() << "Preparing VPN configuration for container" << ContainerProps::containerToString(container);
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
QString containerName = ContainerProps::containerToString(container);
const ContainerConfig &containerConfig = serverConfig->containerConfigs.value(containerName);
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns,
serverConfig,
containerConfig,
container);
emit configurationPrepared(vpnConfiguration);
return vpnConfiguration;
});
}
QFuture<ErrorCode> ConnectionController::openConnection(const int serverIndex,
const QSharedPointer<ServerConfig> &serverConfig,
const DockerContainer container,
const ServerCredentials &credentials,
const QPair<QString, QString> &dns)
{
return QtConcurrent::run([this, serverIndex, serverConfig, container, credentials, dns]() -> ErrorCode {
if (!isServerSupported(container)) {
emit connectionError(ErrorCode::NotSupportedOnThisPlatform);
return ErrorCode::NotSupportedOnThisPlatform;
}
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
const QString containerName = ContainerProps::containerToString(container);
const ContainerConfig &containerConfig = serverConfig->containerConfigs.value(containerName);
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container);
emit connectionProgress(QString("Connecting to %1...").arg(ContainerProps::containerToString(container)));
QMetaObject::invokeMethod(m_vpnConnection.get(), "connectToVpn", Qt::QueuedConnection,
Q_ARG(int, serverIndex),
Q_ARG(ServerCredentials, credentials),
Q_ARG(DockerContainer, container),
Q_ARG(QJsonObject, vpnConfiguration));
return ErrorCode::NoError;
});
}
QFuture<ErrorCode> ConnectionController::closeConnection()
{
return QtConcurrent::run([this]() -> ErrorCode {
QMetaObject::invokeMethod(m_vpnConnection.get(), "disconnectFromVpn", Qt::QueuedConnection);
return ErrorCode::NoError;
});
}
bool ConnectionController::isServerSupported(DockerContainer container) const
{
return ContainerProps::isSupportedByCurrentPlatform(container);
}

View File

@@ -0,0 +1,55 @@
#ifndef CONNECTIONCONTROLLER_H
#define CONNECTIONCONTROLLER_H
#include <QObject>
#include <QFuture>
#include <QSharedPointer>
#include "core/defs.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/servers/serverConfig.h"
#include "protocols/vpnprotocol.h"
#include "vpnconnection.h"
class Settings;
class ServerController;
class VpnConfigurationsController;
using namespace amnezia;
class ConnectionController : public QObject
{
Q_OBJECT
public:
explicit ConnectionController(const QSharedPointer<VpnConnection> &vpnConnection,
std::shared_ptr<Settings> settings,
QObject *parent = nullptr);
QFuture<QJsonObject> prepareVpnConfiguration(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container,
const QPair<QString, QString> &dns) const;
QFuture<ErrorCode> openConnection(const int serverIndex,
const QSharedPointer<ServerConfig> &serverConfig,
const DockerContainer container,
const ServerCredentials &credentials,
const QPair<QString, QString> &dns);
QFuture<ErrorCode> closeConnection();
signals:
void configurationPrepared(const QJsonObject &vpnConfiguration);
void connectionEstablished();
void connectionTerminated();
void connectionError(ErrorCode errorCode);
void connectionProgress(const QString &message);
private:
bool isServerSupported(DockerContainer container) const;
QSharedPointer<VpnConnection> m_vpnConnection;
std::shared_ptr<Settings> m_settings;
};
#endif // CONNECTIONCONTROLLER_H

View File

@@ -3,6 +3,8 @@
#include <QDirIterator>
#include <QTranslator>
#include "core/models/clientInfo.h"
#if defined(Q_OS_ANDROID)
#include "core/installedAppsImageProvider.h"
#include "platforms/android/android_controller.h"
@@ -123,8 +125,9 @@ void CoreController::initCoreControllers()
void CoreController::initUIControllers()
{
auto coreConnectionController = QSharedPointer<ConnectionController>::create(m_vpnConnection, m_settings, this);
m_connectionController.reset(
new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel, m_vpnConnection, m_settings));
new ConnectionUIController(m_serversModel, m_containersModel, m_clientManagementModel, coreConnectionController, m_settings));
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
m_pageController.reset(new PageController(m_serversModel, m_settings));
@@ -141,7 +144,7 @@ void CoreController::initUIControllers()
m_engine->rootContext()->setContextProperty("InstallController", m_installUIController.get());
connect(m_installUIController.get(), &InstallUIController::currentContainerUpdated, m_connectionController.get(),
&ConnectionController::onCurrentContainerUpdated);
&ConnectionUIController::onCurrentContainerUpdated);
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
@@ -182,22 +185,22 @@ void CoreController::setupControllerSignalConnections()
connect(m_exportController.data(), &ExportController::clientAppendRequested,
clientManagementController.data(),
[clientManagementController](const DockerContainer container, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QString &clientName,
const ContainerConfig &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController) {
QJsonArray clientsTable;
QList<ClientInfo> clientsList;
ErrorCode result = clientManagementController->appendClient(container, credentials, containerConfig,
clientName, serverController, clientsTable);
clientName, serverController, clientsList);
emit clientManagementController->clientAppendCompleted(result);
});
connect(m_exportController.data(), &ExportController::nativeConfigClientAppendRequested,
clientManagementController.data(),
[clientManagementController](const QJsonObject &jsonNativeConfig, const QString &clientName,
[clientManagementController](const QSharedPointer<ProtocolConfig> &protocolConfig, const QString &clientName,
const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController) {
QJsonArray clientsTable;
ErrorCode result = clientManagementController->appendClient(jsonNativeConfig, clientName, container,
credentials, serverController, clientsTable);
QList<ClientInfo> clientsList;
ErrorCode result = clientManagementController->appendClient(protocolConfig, clientName, container,
credentials, serverController, clientsList);
emit clientManagementController->nativeConfigClientAppendCompleted(result);
});
@@ -210,11 +213,11 @@ void CoreController::setupControllerSignalConnections()
connect(m_installController.data(), &InstallController::clientAppendRequested,
clientManagementController.data(),
[clientManagementController](const DockerContainer container, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QString &clientName,
const ContainerConfig &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController) {
QJsonArray clientsTable;
QList<ClientInfo> clientsList;
clientManagementController->appendClient(container, credentials, containerConfig,
clientName, serverController, clientsTable);
clientName, serverController, clientsList);
});
}
@@ -303,9 +306,9 @@ void CoreController::initNotificationHandler()
connect(m_notificationHandler.get(), &NotificationHandler::raiseRequested, m_pageController.get(), &PageController::raiseMainWindow);
connect(m_notificationHandler.get(), &NotificationHandler::connectRequested, m_connectionController.get(),
static_cast<void (ConnectionController::*)()>(&ConnectionController::openConnection));
static_cast<void (ConnectionUIController::*)()>(&ConnectionUIController::openConnection));
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
&ConnectionController::closeConnection);
&ConnectionUIController::closeConnection);
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
#endif
}
@@ -347,7 +350,7 @@ void CoreController::updateTranslator(const QLocale &locale)
void CoreController::initErrorMessagesHandler()
{
connect(m_connectionController.get(), &ConnectionController::connectionErrorOccurred, this, [this](ErrorCode errorCode) {
connect(m_connectionController.get(), &ConnectionUIController::connectionErrorOccurred, this, [this](ErrorCode errorCode) {
emit m_pageController->showErrorMessage(errorCode);
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
@@ -395,7 +398,7 @@ void CoreController::initTranslationsUpdatedHandler()
{
connect(m_languageModel.get(), &LanguageModel::updateTranslations, this, &CoreController::updateTranslator);
connect(this, &CoreController::translationsUpdated, m_languageModel.get(), &LanguageModel::translationsUpdated);
connect(this, &CoreController::translationsUpdated, m_connectionController.get(), &ConnectionController::onTranslationsUpdated);
connect(this, &CoreController::translationsUpdated, m_connectionController.get(), &ConnectionUIController::onTranslationsUpdated);
}
void CoreController::initAutoConnectHandler()
@@ -412,7 +415,7 @@ void CoreController::initAmneziaDnsToggledHandler()
void CoreController::initPrepareConfigHandler()
{
connect(m_connectionController.get(), &ConnectionController::prepareConfig, this, [this]() {
connect(m_connectionController.get(), &ConnectionUIController::prepareConfig, this, [this]() {
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
if (!m_apiConfigsController->isConfigValid()) {

View File

@@ -11,7 +11,7 @@
#include "core/controllers/selfhosted/clientManagementController.h"
#include "ui/controllers/appSplitUIController.h"
#include "ui/controllers/allowedDnsUIController.h"
#include "ui/controllers/connectionController.h"
#include "ui/controllers/connectionUIController.h"
#include "core/controllers/selfhosted/exportController.h"
#include "core/controllers/selfhosted/installController.h"
#include "ui/controllers/selfhosted/exportUIController.h"
@@ -24,6 +24,7 @@
#include "ui/controllers/systemController.h"
#include "core/controllers/settingsController.h"
#include "core/controllers/dnsController.h"
#include "core/controllers/connectionController.h"
#include "core/controllers/splitTunnelingController.h"
#include "ui/models/allowed_dns_model.h"
@@ -107,7 +108,7 @@ private:
QMetaObject::Connection m_reloadConfigErrorOccurredConnection;
QScopedPointer<ConnectionController> m_connectionController;
QScopedPointer<ConnectionUIController> m_connectionController;
QScopedPointer<FocusController> m_focusController;
QSharedPointer<PageController> m_pageController;
QSharedPointer<ExportController> m_exportController;

View File

@@ -4,6 +4,16 @@
#include <QJsonObject>
#include "core/controllers/selfhosted/serverController.h"
#include "core/models/protocols/openvpnProtocolConfig.h"
#include "core/models/protocols/wireguardProtocolConfig.h"
#include "core/models/protocols/awgProtocolConfig.h"
#include "core/models/protocols/xrayProtocolConfig.h"
#include "core/models/protocols/shadowsocksProtocolConfig.h"
#include "core/models/protocols/cloakProtocolConfig.h"
#include "core/models/protocols/ikev2ProtocolConfig.h"
#include "core/models/protocols/protocolConfig.h"
#include "core/models/clientInfo.h"
#include <variant>
#include "settings.h"
#include "logger.h"
#include "protocols/protocols_defs.h"
@@ -45,43 +55,27 @@ QString ClientManagementController::getClientsTableFilePath(const DockerContaine
return clientsTableFile;
}
void ClientManagementController::migration(const QByteArray &clientsTableString, QJsonArray &clientsTable)
void ClientManagementController::migration(const QByteArray &clientsTableString, QList<ClientInfo> &clientsList)
{
QJsonObject clientsTableObj = QJsonDocument::fromJson(clientsTableString).object();
for (auto &clientId : clientsTableObj.keys()) {
QJsonObject client;
client[configKey::clientId] = clientId;
ClientInfo client;
client.clientId = clientId;
client.clientName = clientsTableObj.value(clientId).toObject().value(configKey::clientName).toString();
client.creationDate = QDateTime::currentDateTime();
QJsonObject userData;
userData[configKey::clientName] = clientsTableObj.value(clientId).toObject().value(configKey::clientName);
client[configKey::userData] = userData;
clientsTable.push_back(client);
clientsList.append(client);
}
}
bool ClientManagementController::isClientExists(const QString &clientId, const QJsonArray &clientsTable)
{
for (const auto &clientObject : clientsTable) {
if (clientObject.toObject().value(configKey::clientId).toString() == clientId) {
return true;
}
}
return false;
}
ErrorCode ClientManagementController::updateClientsData(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController)
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList)
{
QJsonArray clientsTable;
return updateClientsData(container, credentials, serverController, clientsTable);
}
ErrorCode ClientManagementController::updateClientsData(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable)
{
clientsTable = QJsonArray();
clientsList.clear();
ErrorCode error = ErrorCode::NoError;
QString clientsTableFile = getClientsTableFilePath(container);
@@ -91,26 +85,37 @@ ErrorCode ClientManagementController::updateClientsData(const DockerContainer co
return error;
}
clientsTable = QJsonDocument::fromJson(clientsTableString).array();
QJsonArray clientsTable = QJsonDocument::fromJson(clientsTableString).array();
if (clientsTable.isEmpty()) {
migration(clientsTableString, clientsTable);
const QByteArray newClientsTableString = QJsonDocument(clientsTable).toJson();
migration(clientsTableString, clientsList);
const QByteArray newClientsTableString = QJsonDocument(clientsToJsonArray(clientsList)).toJson();
error = serverController->uploadTextFileToContainer(container, credentials, newClientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
return error;
}
} else {
clientsList = clientsFromJsonArray(clientsTable);
}
int count = 0;
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
error = getOpenVpnClients(container, credentials, serverController, count, clientsTable);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
error = getWireGuardClients(container, credentials, serverController, count, clientsTable);
} else if (container == DockerContainer::Xray) {
error = getXrayClients(container, credentials, serverController, count, clientsTable);
switch (container) {
case DockerContainer::OpenVpn:
case DockerContainer::ShadowSocks:
case DockerContainer::Cloak:
error = getOpenVpnClients(container, credentials, serverController, count, clientsList);
break;
case DockerContainer::WireGuard:
case DockerContainer::Awg:
error = getWireGuardClients(container, credentials, serverController, count, clientsList);
break;
case DockerContainer::Xray:
error = getXrayClients(container, credentials, serverController, count, clientsList);
break;
default:
error = ErrorCode::NoError;
break;
}
if (error != ErrorCode::NoError) {
@@ -118,7 +123,7 @@ ErrorCode ClientManagementController::updateClientsData(const DockerContainer co
return error;
}
emit clientsDataUpdated(clientsTable);
emit clientsDataUpdated(clientsList);
return ErrorCode::NoError;
}
@@ -126,8 +131,8 @@ ErrorCode ClientManagementController::updateClientsData(const DockerContainer co
ErrorCode ClientManagementController::updateClientsData(const DockerContainer container, const ServerCredentials &credentials)
{
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
QJsonArray clientsTable;
return updateClientsData(container, credentials, serverController, clientsTable);
QList<ClientInfo> clientsList;
return updateClientsData(container, credentials, serverController, clientsList);
}
@@ -135,8 +140,8 @@ ErrorCode ClientManagementController::updateClientsData(const DockerContainer co
ErrorCode ClientManagementController::appendClient(const DockerContainer container, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable)
const ContainerConfig &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList)
{
Proto protocol;
switch (container) {
@@ -154,22 +159,27 @@ ErrorCode ClientManagementController::appendClient(const DockerContainer contain
return ErrorCode::NoError;
}
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
return appendClient(protocolConfig, clientName, container, credentials, serverController, clientsTable);
QString protocolName = ProtocolProps::protoToString(protocol);
auto protocolConfig = containerConfig.protocolConfigs.value(protocolName);
return appendClient(protocolConfig, clientName, container, credentials, serverController, clientsList);
}
ErrorCode ClientManagementController::appendClient(QJsonObject &protocolConfig, const QString &clientName, const DockerContainer container,
ErrorCode ClientManagementController::appendClient(QSharedPointer<ProtocolConfig> &protocolConfig, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable)
QList<ClientInfo> &clientsList)
{
QString clientId;
if (container == DockerContainer::Xray) {
if (!protocolConfig.contains("outbounds")) {
if (!protocolConfig) {
return ErrorCode::InternalError;
}
QJsonArray outbounds = protocolConfig.value("outbounds").toArray();
QJsonObject protocolConfigJson = protocolConfig->toJson();
if (!protocolConfigJson.contains("outbounds")) {
return ErrorCode::InternalError;
}
QJsonArray outbounds = protocolConfigJson.value("outbounds").toArray();
if (outbounds.isEmpty()) {
return ErrorCode::InternalError;
}
@@ -199,45 +209,43 @@ ErrorCode ClientManagementController::appendClient(QJsonObject &protocolConfig,
}
clientId = user["id"].toString();
} else {
clientId = protocolConfig.value(config_key::clientId).toString();
if (!protocolConfig) {
return ErrorCode::InternalError;
}
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([&clientId](const auto &config) -> void {
clientId = config->clientProtocolConfig.clientId;
}, variant);
}
return appendClient(clientId, clientName, container, credentials, serverController, clientsTable);
return appendClient(clientId, clientName, container, credentials, serverController, clientsList);
}
ErrorCode ClientManagementController::appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable)
QList<ClientInfo> &clientsList)
{
ErrorCode error = ErrorCode::NoError;
error = updateClientsData(container, credentials, serverController, clientsTable);
QList<ClientInfo> currentClients;
error = updateClientsData(container, credentials, serverController, currentClients);
if (error != ErrorCode::NoError) {
return error;
}
for (int i = 0; i < clientsTable.size(); i++) {
if (clientsTable.at(i).toObject().value(configKey::clientId) == clientId) {
return renameClient(i, clientName, container, credentials, serverController, clientsTable, true);
for (int i = 0; i < currentClients.size(); ++i) {
if (currentClients[i].clientId == clientId) {
return renameClient(i, clientName, container, credentials, serverController, currentClients, true);
}
}
ClientInfo newClient(clientId, clientName);
newClient.container = container;
currentClients.append(newClient);
QJsonObject client;
client[configKey::clientId] = clientId;
QJsonObject userData;
userData[configKey::clientName] = clientName;
userData[configKey::creationDate] = QDateTime::currentDateTime().toString();
client[configKey::userData] = userData;
clientsTable.push_back(client);
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
const QByteArray clientsTableString = QJsonDocument(clientsToJsonArray(currentClients)).toJson();
QString clientsTableFile = getClientsTableFilePath(container);
error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
@@ -246,6 +254,7 @@ ErrorCode ClientManagementController::appendClient(const QString &clientId, cons
return error;
}
clientsList = currentClients;
emit clientAdded(clientId, clientName);
return ErrorCode::NoError;
}
@@ -254,33 +263,28 @@ ErrorCode ClientManagementController::renameClient(const int row, const QString
const ServerCredentials &credentials, bool addTimeStamp)
{
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
QJsonArray clientsTable;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsTable);
QList<ClientInfo> clientsList;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsList);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
return renameClient(row, clientName, container, credentials, serverController, clientsTable, addTimeStamp);
return renameClient(row, clientName, container, credentials, serverController, clientsList, addTimeStamp);
}
ErrorCode ClientManagementController::renameClient(const int row, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable, bool addTimeStamp)
QList<ClientInfo> &clientsList, bool addTimeStamp)
{
if (row < 0 || row >= clientsTable.size()) {
if (row < 0 || row >= clientsList.size()) {
return ErrorCode::InternalError;
}
auto client = clientsTable.at(row).toObject();
auto userData = client[configKey::userData].toObject();
userData[configKey::clientName] = clientName;
clientsList[row].clientName = clientName;
if (addTimeStamp) {
userData[configKey::creationDate] = QDateTime::currentDateTime().toString();
clientsList[row].creationDate = QDateTime::currentDateTime();
}
client[configKey::userData] = userData;
clientsTable.replace(row, client);
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
const QByteArray clientsTableString = QJsonDocument(clientsToJsonArray(clientsList)).toJson();
QString clientsTableFile = getClientsTableFilePath(container);
ErrorCode error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
@@ -293,39 +297,10 @@ ErrorCode ClientManagementController::renameClient(const int row, const QString
return ErrorCode::NoError;
}
ErrorCode ClientManagementController::renameClient(const int row, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable, bool addTimeStamp)
{
if (row < 0 || row >= clientsTable.size()) {
return ErrorCode::InternalError;
}
auto client = clientsTable.at(row).toObject();
auto userData = client[configKey::userData].toObject();
userData[configKey::clientName] = clientName;
if (addTimeStamp) {
userData[configKey::creationDate] = QDateTime::currentDateTime().toString();
}
client[configKey::userData] = userData;
clientsTable.replace(row, client);
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
QString clientsTableFile = getClientsTableFilePath(container);
ErrorCode error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
return error;
}
emit clientRenamed(row, clientName);
return ErrorCode::NoError;
}
ErrorCode ClientManagementController::getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, int &count, QJsonArray &clientsTable)
const QSharedPointer<ServerController> &serverController, int &count, QList<ClientInfo> &clientsList)
{
ErrorCode error = ErrorCode::NoError;
@@ -346,15 +321,10 @@ ErrorCode ClientManagementController::getWireGuardClients(const DockerContainer
}
for (auto &wireguardKey : wireguardKeys) {
if (!isClientExists(wireguardKey, clientsTable)) {
QJsonObject client;
client[configKey::clientId] = wireguardKey;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
clientsTable.push_back(client);
if (!isClientExists(wireguardKey, clientsList)) {
ClientInfo client(wireguardKey, QString("Client %1").arg(count));
client.container = container;
clientsList.append(client);
count++;
}
}
@@ -362,7 +332,7 @@ ErrorCode ClientManagementController::getWireGuardClients(const DockerContainer
}
ErrorCode ClientManagementController::getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
const QSharedPointer<ServerController> &serverController, int &count, QJsonArray &clientsTable)
const QSharedPointer<ServerController> &serverController, int &count, QList<ClientInfo> &clientsList)
{
ErrorCode error = ErrorCode::NoError;
@@ -408,15 +378,10 @@ ErrorCode ClientManagementController::getXrayClients(const DockerContainer conta
QString xrayDefaultUuid = serverController->getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, error);
xrayDefaultUuid.replace("\n", "");
if (!isClientExists(clientId, clientsTable) && clientId != xrayDefaultUuid) {
QJsonObject client;
client[configKey::clientId] = clientId;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
clientsTable.push_back(client);
if (!isClientExists(clientId, clientsList) && clientId != xrayDefaultUuid) {
ClientInfo client(clientId, QString("Client %1").arg(count));
client.container = container;
clientsList.append(client);
count++;
}
}
@@ -424,6 +389,16 @@ ErrorCode ClientManagementController::getXrayClients(const DockerContainer conta
return error;
}
ErrorCode ClientManagementController::getOpenVpnClients(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, int &count, QList<ClientInfo> &clientsList)
{
Q_UNUSED(container);
Q_UNUSED(credentials);
Q_UNUSED(serverController);
count = clientsList.size();
return ErrorCode::NoError;
}
ErrorCode ClientManagementController::wgShow(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, std::vector<WgShowData> &data)
{
@@ -497,22 +472,34 @@ ErrorCode ClientManagementController::wgShow(const DockerContainer container, co
ErrorCode ClientManagementController::revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials,
const int serverIndex, const QSharedPointer<ServerController> &serverController)
{
QJsonArray clientsTable;
return revokeOpenVpn(row, container, credentials, serverIndex, serverController, clientsTable);
QList<ClientInfo> clientsList;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsList);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
return revokeOpenVpn(row, container, credentials, serverIndex, serverController, clientsList);
}
ErrorCode ClientManagementController::revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController)
{
QJsonArray clientsTable;
return revokeWireGuard(row, container, credentials, serverController, clientsTable);
QList<ClientInfo> clientsList;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsList);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
return revokeWireGuard(row, container, credentials, serverController, clientsList);
}
ErrorCode ClientManagementController::revokeXray(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController)
{
QJsonArray clientsTable;
return revokeXray(row, container, credentials, serverController, clientsTable);
QList<ClientInfo> clientsList;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsList);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
return revokeXray(row, container, credentials, serverController, clientsList);
}
@@ -520,25 +507,24 @@ ErrorCode ClientManagementController::revokeClient(const int row, const DockerCo
const ServerCredentials &credentials, const int serverIndex)
{
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
QJsonArray clientsTable;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsTable);
QList<ClientInfo> clientsList;
ErrorCode errorCode = updateClientsData(container, credentials, serverController, clientsList);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
return revokeClient(row, container, credentials, serverIndex, serverController, clientsTable);
return revokeClient(row, container, credentials, serverIndex, serverController, clientsList);
}
ErrorCode ClientManagementController::revokeClient(const int row, const DockerContainer container, const ServerCredentials &credentials,
const int serverIndex, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable)
QList<ClientInfo> &clientsList)
{
if (row < 0 || row >= clientsTable.size()) {
if (row < 0 || row >= clientsList.size()) {
return ErrorCode::InternalError;
}
auto client = clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
QString clientId = clientsList[row].clientId;
ErrorCode errorCode = ErrorCode::NoError;
@@ -546,16 +532,16 @@ ErrorCode ClientManagementController::revokeClient(const int row, const DockerCo
case DockerContainer::OpenVpn:
case DockerContainer::ShadowSocks:
case DockerContainer::Cloak: {
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController, clientsTable);
errorCode = revokeOpenVpn(row, container, credentials, serverIndex, serverController, clientsList);
break;
}
case DockerContainer::WireGuard:
case DockerContainer::Awg: {
errorCode = revokeWireGuard(row, container, credentials, serverController, clientsTable);
errorCode = revokeWireGuard(row, container, credentials, serverController, clientsList);
break;
}
case DockerContainer::Xray: {
errorCode = revokeXray(row, container, credentials, serverController, clientsTable);
errorCode = revokeXray(row, container, credentials, serverController, clientsList);
break;
}
default: {
@@ -571,9 +557,9 @@ ErrorCode ClientManagementController::revokeClient(const int row, const DockerCo
return errorCode;
}
ErrorCode ClientManagementController::revokeClient(const QJsonObject &containerConfig, const DockerContainer container,
ErrorCode ClientManagementController::revokeClient(const ContainerConfig &containerConfig, const DockerContainer container,
const ServerCredentials &credentials, const int serverIndex,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable)
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList)
{
Proto protocol;
@@ -601,11 +587,14 @@ ErrorCode ClientManagementController::revokeClient(const QJsonObject &containerC
QString clientId;
if (container == DockerContainer::Xray) {
if (!protocolConfig.contains("outbounds")) {
if (!protocolConfig) {
return ErrorCode::InternalError;
}
QJsonArray outbounds = protocolConfig.value("outbounds").toArray();
QJsonObject protocolConfigJson = protocolConfig->toJson();
if (!protocolConfigJson.contains("outbounds")) {
return ErrorCode::InternalError;
}
QJsonArray outbounds = protocolConfigJson.value("outbounds").toArray();
if (outbounds.isEmpty()) {
return ErrorCode::InternalError;
}
@@ -635,14 +624,19 @@ ErrorCode ClientManagementController::revokeClient(const QJsonObject &containerC
}
clientId = user["id"].toString();
} else {
clientId = protocolConfig.value(config_key::clientId).toString();
if (!protocolConfig) {
return ErrorCode::InternalError;
}
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([&clientId](const auto &config) -> void {
clientId = config->clientProtocolConfig.clientId;
}, variant);
}
for (int i = 0; i < clientsTable.size(); i++) {
auto client = clientsTable.at(i).toObject();
if (client.value(configKey::clientId).toString() == clientId) {
return revokeClient(i, container, credentials, serverIndex, serverController, clientsTable);
for (int i = 0; i < clientsList.size(); i++) {
if (clientsList[i].clientId == clientId) {
return revokeClient(i, container, credentials, serverIndex, serverController, clientsList);
}
}
@@ -651,14 +645,12 @@ ErrorCode ClientManagementController::revokeClient(const QJsonObject &containerC
ErrorCode ClientManagementController::revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials,
const int serverIndex, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable)
QList<ClientInfo> &clientsList)
{
if (row < 0 || row >= clientsTable.size()) {
if (row < 0 || row >= clientsList.size()) {
return ErrorCode::InternalError;
}
auto client = clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
QString clientId = clientsList[row].clientId;
ErrorCode error = ErrorCode::NoError;
QString stdOut;
@@ -674,9 +666,8 @@ ErrorCode ClientManagementController::revokeOpenVpn(const int row, const DockerC
return error;
}
clientsTable.removeAt(row);
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
clientsList.removeAt(row);
const QByteArray clientsTableString = QJsonDocument(clientsToJsonArray(clientsList)).toJson();
QString clientsTableFile = getClientsTableFilePath(container);
error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
@@ -689,14 +680,12 @@ ErrorCode ClientManagementController::revokeOpenVpn(const int row, const DockerC
}
ErrorCode ClientManagementController::revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable)
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList)
{
if (row < 0 || row >= clientsTable.size()) {
if (row < 0 || row >= clientsList.size()) {
return ErrorCode::InternalError;
}
auto client = clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
QString clientId = clientsList[row].clientId;
ErrorCode error = ErrorCode::NoError;
@@ -729,9 +718,8 @@ ErrorCode ClientManagementController::revokeWireGuard(const int row, const Docke
return error;
}
clientsTable.removeAt(row);
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
clientsList.removeAt(row);
const QByteArray clientsTableString = QJsonDocument(clientsToJsonArray(clientsList)).toJson();
QString clientsTableFile = getClientsTableFilePath(container);
error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
@@ -744,14 +732,12 @@ ErrorCode ClientManagementController::revokeWireGuard(const int row, const Docke
}
ErrorCode ClientManagementController::revokeXray(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable)
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList)
{
if (row < 0 || row >= clientsTable.size()) {
if (row < 0 || row >= clientsList.size()) {
return ErrorCode::InternalError;
}
auto client = clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
QString clientId = clientsList[row].clientId;
ErrorCode error = ErrorCode::NoError;
@@ -794,9 +780,8 @@ ErrorCode ClientManagementController::revokeXray(const int row, const DockerCont
return error;
}
clientsTable.removeAt(row);
const QByteArray clientsTableString = QJsonDocument(clientsTable).toJson();
clientsList.removeAt(row);
const QByteArray clientsTableString = QJsonDocument(clientsToJsonArray(clientsList)).toJson();
QString clientsTableFile = getClientsTableFilePath(container);
error = serverController->uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
@@ -806,5 +791,32 @@ ErrorCode ClientManagementController::revokeXray(const int row, const DockerCont
}
return ErrorCode::NoError;
}
QList<ClientInfo> ClientManagementController::clientsFromJsonArray(const QJsonArray &jsonArray)
{
QList<ClientInfo> clientsList;
for (const auto &value : jsonArray) {
clientsList.append(ClientInfo(value.toObject()));
}
return clientsList;
}
QJsonArray ClientManagementController::clientsToJsonArray(const QList<ClientInfo> &clientsList)
{
QJsonArray jsonArray;
for (const auto &client : clientsList) {
jsonArray.append(client.toJson());
}
return jsonArray;
}
bool ClientManagementController::isClientExists(const QString &clientId, const QList<ClientInfo> &clientsList)
{
for (const auto &client : clientsList) {
if (client.clientId == clientId) {
return true;
}
}
return false;
}

View File

@@ -5,10 +5,14 @@
#include <QSharedPointer>
#include <QJsonArray>
#include <QJsonObject>
#include <QList>
#include <vector>
#include "core/defs.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/containers/containerConfig.h"
#include "core/models/protocols/protocolConfig.h"
#include "core/models/clientInfo.h"
class ServerController;
class Settings;
@@ -42,33 +46,33 @@ public:
ErrorCode revokeClient(const int row, const DockerContainer container, const ServerCredentials &credentials,
const int serverIndex);
// Internal methods (with clientsTable parameter for core operations)
// Core methods using ClientInfo model
ErrorCode updateClientsData(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList);
ErrorCode appendClient(const DockerContainer container, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable);
const ContainerConfig &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList);
ErrorCode appendClient(QJsonObject &protocolConfig, const QString &clientName, const DockerContainer container,
ErrorCode appendClient(QSharedPointer<ProtocolConfig> &protocolConfig, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable);
QList<ClientInfo> &clientsList);
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable);
QList<ClientInfo> &clientsList);
ErrorCode renameClient(const int row, const QString &clientName, const DockerContainer container,
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable, bool addTimeStamp = false);
QList<ClientInfo> &clientsList, bool addTimeStamp = false);
ErrorCode revokeClient(const int row, const DockerContainer container, const ServerCredentials &credentials,
const int serverIndex, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable);
QList<ClientInfo> &clientsList);
ErrorCode revokeClient(const QJsonObject &containerConfig, const DockerContainer container,
ErrorCode revokeClient(const ContainerConfig &containerConfig, const DockerContainer container,
const ServerCredentials &credentials, const int serverIndex,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList);
// WireGuard specific operations
ErrorCode wgShow(const DockerContainer container, const ServerCredentials &credentials,
@@ -76,7 +80,7 @@ public:
signals:
void adminConfigRevoked(const DockerContainer container);
void clientsDataUpdated(const QJsonArray &clientsTable);
void clientsDataUpdated(const QList<ClientInfo> &clientsList);
void clientAdded(const QString &clientId, const QString &clientName);
void clientRenamed(const int row, const QString &newName);
void clientRevoked(const int row);
@@ -87,29 +91,33 @@ signals:
private:
// Protocol-specific client management
ErrorCode getOpenVpnClients(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, int &count, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, int &count, QList<ClientInfo> &clientsList);
ErrorCode getWireGuardClients(const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, int &count, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, int &count, QList<ClientInfo> &clientsList);
ErrorCode getXrayClients(const DockerContainer container, const ServerCredentials& credentials,
const QSharedPointer<ServerController> &serverController, int &count, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, int &count, QList<ClientInfo> &clientsList);
// Protocol-specific client revocation
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials,
const int serverIndex, const QSharedPointer<ServerController> &serverController,
QJsonArray &clientsTable);
QList<ClientInfo> &clientsList);
ErrorCode revokeWireGuard(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList);
ErrorCode revokeXray(const int row, const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController, QJsonArray &clientsTable);
const QSharedPointer<ServerController> &serverController, QList<ClientInfo> &clientsList);
// Helper methods
bool isClientExists(const QString &clientId, const QJsonArray &clientsTable);
void migration(const QByteArray &clientsTableString, QJsonArray &clientsTable);
bool isClientExists(const QString &clientId, const QList<ClientInfo> &clientsList);
void migration(const QByteArray &clientsTableString, QList<ClientInfo> &clientsList);
QString getClientsTableFilePath(const DockerContainer container);
// JSON serialization for persistence only
static QList<ClientInfo> clientsFromJsonArray(const QJsonArray &jsonArray);
static QJsonArray clientsToJsonArray(const QList<ClientInfo> &clientsList);
std::shared_ptr<Settings> m_settings;
};

View File

@@ -22,29 +22,22 @@ ExportController::ExportController(std::shared_ptr<Settings> settings,
{
}
ExportConfigResult ExportController::generateFullAccessConfig(const QJsonObject &serverConfig)
ExportConfigResult ExportController::generateFullAccessConfig(const QSharedPointer<ServerConfig> &serverConfig)
{
ExportConfigResult result;
result.errorCode = ErrorCode::NoError;
QJsonObject modifiedServerConfig = serverConfig;
QJsonArray containers = modifiedServerConfig.value(config_key::containers).toArray();
// Create a copy of the ServerConfig and clean last_config from protocol configs
auto modifiedServerConfig = QSharedPointer<ServerConfig>::create(*serverConfig);
for (auto i = 0; i < containers.size(); i++) {
auto containerConfig = containers.at(i).toObject();
auto containerType = ContainerProps::containerFromString(containerConfig.value(config_key::container).toString());
for (auto protocol : ContainerProps::protocolsForContainer(containerType)) {
auto protocolConfig = containerConfig.value(ProtocolProps::protoToString(protocol)).toObject();
protocolConfig.remove(config_key::last_config);
containerConfig[ProtocolProps::protoToString(protocol)] = protocolConfig;
for (auto &containerConfig : modifiedServerConfig->containerConfigs) {
for (auto &protocolConfig : containerConfig.protocolConfigs) {
// Protocol configs will automatically exclude last_config when serialized to JSON for export
// No need to manually remove it here as the toJson() method handles this
}
containers.replace(i, containerConfig);
}
modifiedServerConfig[config_key::containers] = containers;
QByteArray compressedConfig = QJsonDocument(modifiedServerConfig).toJson();
QByteArray compressedConfig = QJsonDocument(modifiedServerConfig->toJson()).toJson();
compressedConfig = qCompress(compressedConfig, 8);
result.config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
result.qrCodes = generateQrCodeSeries(compressedConfig);
@@ -55,8 +48,8 @@ ExportConfigResult ExportController::generateFullAccessConfig(const QJsonObject
ExportConfigResult ExportController::generateConnectionConfig(const QString &clientName,
const ServerCredentials &credentials,
const DockerContainer container,
const QJsonObject &containerConfig,
const QJsonObject &serverConfig,
const ContainerConfig &containerConfig,
const QSharedPointer<ServerConfig> &serverConfig,
const QPair<QString, QString> &dnsSettings)
{
ExportConfigResult result;
@@ -64,8 +57,8 @@ ExportConfigResult ExportController::generateConnectionConfig(const QString &cli
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
QJsonObject modifiedContainerConfig = containerConfig;
modifiedContainerConfig.insert(config_key::container, ContainerProps::containerToString(container));
// Use the provided ContainerConfig directly
ContainerConfig modifiedContainerConfig = containerConfig;
result.errorCode = vpnConfigurationController.createProtocolConfigForContainer(credentials, container, modifiedContainerConfig);
if (result.errorCode != ErrorCode::NoError) {
@@ -92,16 +85,20 @@ ExportConfigResult ExportController::generateConnectionConfig(const QString &cli
return result;
}
QJsonObject modifiedServerConfig = serverConfig;
modifiedServerConfig.remove(config_key::userName);
modifiedServerConfig.remove(config_key::password);
modifiedServerConfig.remove(config_key::port);
modifiedServerConfig.insert(config_key::containers, QJsonArray { modifiedContainerConfig });
modifiedServerConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
modifiedServerConfig.insert(config_key::dns1, dnsSettings.first);
modifiedServerConfig.insert(config_key::dns2, dnsSettings.second);
// Create a modified ServerConfig for export with only the specific container
auto exportServerConfig = QSharedPointer<ServerConfig>::create(*serverConfig);
// Remove credentials (they are not needed in export)
exportServerConfig->containerConfigs.clear();
// Add only the specific container being exported
QString containerName = ContainerProps::containerToString(container);
exportServerConfig->containerConfigs.insert(containerName, modifiedContainerConfig);
exportServerConfig->defaultContainer = containerName;
exportServerConfig->dns1 = dnsSettings.first;
exportServerConfig->dns2 = dnsSettings.second;
QByteArray compressedConfig = QJsonDocument(modifiedServerConfig).toJson();
QByteArray compressedConfig = QJsonDocument(exportServerConfig->toJson()).toJson();
compressedConfig = qCompress(compressedConfig, 8);
result.config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
result.qrCodes = generateQrCodeSeries(compressedConfig);
@@ -110,11 +107,11 @@ ExportConfigResult ExportController::generateConnectionConfig(const QString &cli
}
ExportConfigResult ExportController::generateOpenVpnConfig(const QString &clientName,
const ServerCredentials &credentials,
const DockerContainer container,
const QJsonObject &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
const ServerCredentials &credentials,
const DockerContainer container,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
{
ExportConfigResult result;
QJsonObject nativeConfig;
@@ -144,7 +141,7 @@ ExportConfigResult ExportController::generateOpenVpnConfig(const QString &client
ExportConfigResult ExportController::generateWireGuardConfig(const QString &clientName,
const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
{
@@ -168,10 +165,10 @@ ExportConfigResult ExportController::generateWireGuardConfig(const QString &clie
}
ExportConfigResult ExportController::generateAwgConfig(const QString &clientName,
const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
const ServerCredentials &credentials,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
{
ExportConfigResult result;
QJsonObject nativeConfig;
@@ -193,10 +190,10 @@ ExportConfigResult ExportController::generateAwgConfig(const QString &clientName
}
ExportConfigResult ExportController::generateShadowSocksConfig(const ServerCredentials &credentials,
const DockerContainer container,
const QJsonObject &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
const DockerContainer container,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
{
ExportConfigResult result;
QJsonObject nativeConfig;
@@ -233,9 +230,9 @@ ExportConfigResult ExportController::generateShadowSocksConfig(const ServerCrede
}
ExportConfigResult ExportController::generateCloakConfig(const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
{
ExportConfigResult result;
QJsonObject nativeConfig;
@@ -259,10 +256,10 @@ ExportConfigResult ExportController::generateCloakConfig(const ServerCredentials
}
ExportConfigResult ExportController::generateXrayConfig(const QString &clientName,
const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
const ServerCredentials &credentials,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig)
{
ExportConfigResult result;
QJsonObject nativeConfig;
@@ -284,16 +281,16 @@ ExportConfigResult ExportController::generateXrayConfig(const QString &clientNam
ErrorCode ExportController::generateNativeConfig(const DockerContainer container, const QString &clientName,
ErrorCode ExportController::generateNativeConfig(const DockerContainer container, const QString &clientName,
const Proto &protocol, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QPair<QString, QString> &dnsSettings,
const ContainerConfig &containerConfig, const QPair<QString, QString> &dnsSettings,
bool isApiConfig, QJsonObject &jsonNativeConfig,
const QSharedPointer<ServerController> &serverController)
{
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
QJsonObject modifiedContainerConfig = containerConfig;
modifiedContainerConfig.insert(config_key::container, ContainerProps::containerToString(container));
// Use the provided ContainerConfig directly
ContainerConfig modifiedContainerConfig = containerConfig;
QString protocolConfigString;
ErrorCode errorCode = vpnConfigurationController.createProtocolConfigString(isApiConfig, dnsSettings, credentials,
@@ -306,8 +303,11 @@ ErrorCode ExportController::generateNativeConfig(const DockerContainer container
jsonNativeConfig = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg || protocol == Proto::Xray) {
QString protocolName = ProtocolProps::protoToString(protocol);
auto protocolConfig = modifiedContainerConfig.protocolConfigs.value(protocolName);
m_waitingForNativeConfigAppend = true;
emit nativeConfigClientAppendRequested(jsonNativeConfig, clientName, container, credentials, serverController);
emit nativeConfigClientAppendRequested(protocolConfig, clientName, container, credentials, serverController);
QEventLoop loop;
QTimer timer;

View File

@@ -10,6 +10,9 @@
#include "core/defs.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/containers/containerConfig.h"
#include "core/models/protocols/protocolConfig.h"
#include "core/models/servers/serverConfig.h"
class ServerController;
class Settings;
@@ -34,10 +37,10 @@ public:
signals:
void clientAppendRequested(const DockerContainer container, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QString &clientName,
const ContainerConfig &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController);
void nativeConfigClientAppendRequested(const QJsonObject &jsonNativeConfig, const QString &clientName,
void nativeConfigClientAppendRequested(const QSharedPointer<ProtocolConfig> &protocolConfig, const QString &clientName,
const DockerContainer container, const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController);
@@ -48,55 +51,55 @@ public slots:
void onClientAppendCompleted(ErrorCode errorCode);
void onNativeConfigClientAppendCompleted(ErrorCode errorCode);
ExportConfigResult generateFullAccessConfig(const QJsonObject &serverConfig);
ExportConfigResult generateFullAccessConfig(const QSharedPointer<ServerConfig> &serverConfig);
ExportConfigResult generateConnectionConfig(const QString &clientName,
const ServerCredentials &credentials,
const DockerContainer container,
const QJsonObject &containerConfig,
const QJsonObject &serverConfig,
const ContainerConfig &containerConfig,
const QSharedPointer<ServerConfig> &serverConfig,
const QPair<QString, QString> &dnsSettings);
ExportConfigResult generateOpenVpnConfig(const QString &clientName,
const ServerCredentials &credentials,
const DockerContainer container,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig = false);
ExportConfigResult generateWireGuardConfig(const QString &clientName,
const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig = false);
ExportConfigResult generateAwgConfig(const QString &clientName,
const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig = false);
ExportConfigResult generateShadowSocksConfig(const ServerCredentials &credentials,
const DockerContainer container,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig = false);
ExportConfigResult generateCloakConfig(const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig = false);
ExportConfigResult generateXrayConfig(const QString &clientName,
const ServerCredentials &credentials,
const QJsonObject &containerConfig,
const ContainerConfig &containerConfig,
const QPair<QString, QString> &dnsSettings,
bool isApiConfig = false);
private:
ErrorCode generateNativeConfig(const DockerContainer container, const QString &clientName,
const Proto &protocol, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QPair<QString, QString> &dnsSettings,
const ContainerConfig &containerConfig, const QPair<QString, QString> &dnsSettings,
bool isApiConfig, QJsonObject &jsonNativeConfig,
const QSharedPointer<ServerController> &serverController);

View File

@@ -13,6 +13,7 @@
#include "core/controllers/vpnConfigurationController.h"
#include "core/models/servers/selfHostedServerConfig.h"
#include "core/models/protocols/awgProtocolConfig.h"
#include "core/networkUtilities.h"
#include "logger.h"
#include "utilities.h"
@@ -40,21 +41,21 @@ InstallResult InstallController::installContainer(DockerContainer container, int
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
QJsonObject containerConfig = generateContainerConfig(container, port, transportProto);
ContainerConfig containerConfig = generateContainerConfig(container, port, transportProto);
if (shouldCreateServer && isServerAlreadyExists(serverCredentials)) {
result.errorCode = ErrorCode::InternalError;
return result;
}
QMap<DockerContainer, QJsonObject> installedContainers;
QMap<DockerContainer, ContainerConfig> installedContainers;
ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, serverController, installedContainers);
if (errorCode != ErrorCode::NoError) {
result.errorCode = errorCode;
return result;
}
QJsonObject serverConfig;
QSharedPointer<ServerConfig> serverConfig;
if (shouldCreateServer) {
errorCode = installServer(container, installedContainers, serverCredentials,
serverController, result.message, serverConfig);
@@ -84,7 +85,7 @@ InstallResult InstallController::scanServerForInstalledContainers(const ServerCr
result.isInstalledContainerFound = false;
result.isServiceInstall = false;
QMap<DockerContainer, QJsonObject> installedContainers;
QMap<DockerContainer, ContainerConfig> installedContainers;
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
result.errorCode = getAlreadyInstalledContainers(serverCredentials, serverController, installedContainers);
@@ -93,7 +94,7 @@ InstallResult InstallController::scanServerForInstalledContainers(const ServerCr
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
auto container = iterator.key();
QJsonObject containerConfig = iterator.value();
ContainerConfig containerConfig = iterator.value();
if (ContainerProps::isSupportedByCurrentPlatform(container)) {
result.errorCode = vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, container, containerConfig);
@@ -115,7 +116,7 @@ InstallResult InstallController::scanServerForInstalledContainers(const ServerCr
ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController,
QMap<DockerContainer, QJsonObject> &installedContainers)
QMap<DockerContainer, ContainerConfig> &installedContainers)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -148,18 +149,58 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
DockerContainer container = ContainerProps::containerFromString(containerName);
if (container != DockerContainer::None) {
QJsonObject containerConfigObject;
containerConfigObject.insert(config_key::container, ContainerProps::containerToString(container));
ContainerConfig containerConfig;
containerConfig.containerName = ContainerProps::containerToString(container);
auto containerProto = ContainerProps::defaultProtocol(container);
auto containerProtoString = ProtocolProps::protoToString(containerProto);
// Create appropriate protocol config based on container type
QSharedPointer<ProtocolConfig> protocolConfig;
// Create a temporary QJsonObject to construct the protocol config
QJsonObject protoConfigObject;
protoConfigObject.insert(config_key::port, port);
protoConfigObject.insert(config_key::transport_proto, transportProto);
containerConfigObject.insert(containerProtoString, protoConfigObject);
installedContainers.insert(container, containerConfigObject);
// Create the appropriate protocol config based on type
switch (containerProto) {
case Proto::OpenVpn:
protocolConfig = QSharedPointer<OpenVpnProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::WireGuard:
protocolConfig = QSharedPointer<WireGuardProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::Awg:
protocolConfig = QSharedPointer<AwgProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::Cloak:
protocolConfig = QSharedPointer<CloakProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::ShadowSocks:
protocolConfig = QSharedPointer<ShadowsocksProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::Xray:
case Proto::SSXray:
protocolConfig = QSharedPointer<XrayProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::Ikev2:
protocolConfig = QSharedPointer<Ikev2ProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::Sftp:
protocolConfig = QSharedPointer<SftpProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
case Proto::Socks5Proxy:
protocolConfig = QSharedPointer<Socks5ProtocolConfig>::create(protoConfigObject, containerProtoString);
break;
default:
continue; // Skip unknown protocols
}
if (protocolConfig) {
containerConfig.protocolConfigs.insert(containerProtoString, protocolConfig);
installedContainers.insert(container, containerConfig);
}
}
}
}
@@ -167,45 +208,45 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
return ErrorCode::NoError;
}
ErrorCode InstallController::installServer(const DockerContainer container,
const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials,
const QSharedPointer<ServerController> &serverController,
QString &finishMessage, QJsonObject &serverConfig)
ErrorCode InstallController::installServer(const DockerContainer container,
const QMap<DockerContainer, ContainerConfig> &installedContainers,
const ServerCredentials &serverCredentials,
const QSharedPointer<ServerController> &serverController,
QString &finishMessage, QSharedPointer<ServerConfig> &serverConfig)
{
if (installedContainers.size() > 1) {
finishMessage += tr("\nAdded containers that were already installed on the server");
}
serverConfig.insert(config_key::hostName, serverCredentials.hostName);
serverConfig.insert(config_key::userName, serverCredentials.userName);
serverConfig.insert(config_key::password, serverCredentials.secretData);
serverConfig.insert(config_key::port, serverCredentials.port);
serverConfig.insert(config_key::description, m_settings->nextAvailableServerName());
// Create a SelfHostedServerConfig and populate it properly
serverConfig = QSharedPointer<SelfHostedServerConfig>::create(QJsonObject());
auto selfHostedConfig = qSharedPointerCast<SelfHostedServerConfig>(serverConfig);
selfHostedConfig->hostName = serverCredentials.hostName;
selfHostedConfig->serverCredentials = serverCredentials;
selfHostedConfig->name = m_settings->nextAvailableServerName();
selfHostedConfig->defaultContainer = ContainerProps::containerToString(container);
selfHostedConfig->type = amnezia::ServerConfigType::SelfHosted;
QJsonArray containerConfigs;
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
auto containerConfig = iterator.value();
QString containerName = ContainerProps::containerToString(iterator.key());
if (ContainerProps::isSupportedByCurrentPlatform(container)) {
if (ContainerProps::isSupportedByCurrentPlatform(iterator.key())) {
auto errorCode = vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, iterator.key(),
containerConfig);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
containerConfigs.append(containerConfig);
} else {
containerConfigs.append(containerConfig);
}
selfHostedConfig->containerConfigs.insert(containerName, containerConfig);
}
serverConfig.insert(config_key::containers, containerConfigs);
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
int serverIndex = m_settings->nextAvailableServerIndex();
m_settings->setServerConfig(serverIndex, serverConfig);
m_settings->setServerConfig(serverIndex, serverConfig->toJson());
m_settings->setDefaultServerIndex(serverIndex);
finishMessage = tr("Server '%1' was successfully added").arg(serverCredentials.hostName);
@@ -213,7 +254,7 @@ ErrorCode InstallController::installServer(const DockerContainer container,
}
ErrorCode InstallController::installContainer(const DockerContainer container,
const QMap<DockerContainer, QJsonObject> &installedContainers,
const QMap<DockerContainer, ContainerConfig> &installedContainers,
const ServerCredentials &serverCredentials,
const QSharedPointer<ServerController> &serverController,
QString &finishMessage)
@@ -263,71 +304,85 @@ bool InstallController::isServerAlreadyExists(const ServerCredentials &serverCre
return false;
}
QJsonObject InstallController::generateContainerConfig(const DockerContainer container, int port,
const TransportProto transportProto)
ContainerConfig InstallController::generateContainerConfig(const DockerContainer container, int port,
const TransportProto transportProto)
{
QJsonObject config;
ContainerConfig containerConfig;
containerConfig.containerName = ContainerProps::containerToString(container);
auto mainProto = ContainerProps::defaultProtocol(container);
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
QSharedPointer<ProtocolConfig> protocolConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, QString::number(port));
containerConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, protocol));
if (container == DockerContainer::Awg) {
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
QString junkPacketMinSize = QString::number(10);
QString junkPacketMaxSize = QString::number(50);
// Create the appropriate protocol config based on the protocol type
if (protocol == Proto::Awg && container == DockerContainer::Awg) {
// Use the VpnConfigurationsController to create proper AwgProtocolConfig
// For now, create a basic protocol config and set values
protocolConfig = QSharedPointer<AwgProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
auto awgConfig = qSharedPointerCast<AwgProtocolConfig>(protocolConfig);
// Set server protocol config
awgConfig->serverProtocolConfig.port = QString::number(port);
awgConfig->serverProtocolConfig.transportProto = ProtocolProps::transportProtoToString(transportProto, protocol);
// Generate AWG-specific parameters
awgConfig->serverProtocolConfig.junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
awgConfig->serverProtocolConfig.junkPacketMinSize = QString::number(10);
awgConfig->serverProtocolConfig.junkPacketMaxSize = QString::number(50);
int s1 = QRandomGenerator::global()->bounded(15, 150);
int s2 = QRandomGenerator::global()->bounded(15, 150);
QSet<int> usedValues;
usedValues.insert(s1);
while (usedValues.contains(s2) || s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) {
s2 = QRandomGenerator::global()->bounded(15, 150);
}
usedValues.insert(s2);
QString initPacketJunkSize = QString::number(s1);
QString responsePacketJunkSize = QString::number(s2);
awgConfig->serverProtocolConfig.initPacketJunkSize = QString::number(s1);
awgConfig->serverProtocolConfig.responsePacketJunkSize = QString::number(s2);
QSet<QString> headersValue;
while (headersValue.size() != 4) {
auto max = (std::numeric_limits<qint32>::max)();
headersValue.insert(QString::number(QRandomGenerator::global()->bounded(5, max)));
}
auto headersValueList = headersValue.values();
QString initPacketMagicHeader = headersValueList.at(0);
QString responsePacketMagicHeader = headersValueList.at(1);
QString underloadPacketMagicHeader = headersValueList.at(2);
QString transportPacketMagicHeader = headersValueList.at(3);
containerConfig[config_key::junkPacketCount] = junkPacketCount;
containerConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
containerConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
containerConfig[config_key::initPacketJunkSize] = initPacketJunkSize;
containerConfig[config_key::responsePacketJunkSize] = responsePacketJunkSize;
containerConfig[config_key::initPacketMagicHeader] = initPacketMagicHeader;
containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader;
containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader;
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
} else if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(16));
} else if (container == DockerContainer::Socks5Proxy) {
containerConfig.insert(config_key::userName, protocols::socks5Proxy::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(16));
awgConfig->serverProtocolConfig.initPacketMagicHeader = headersValueList.at(0);
awgConfig->serverProtocolConfig.responsePacketMagicHeader = headersValueList.at(1);
awgConfig->serverProtocolConfig.underloadPacketMagicHeader = headersValueList.at(2);
awgConfig->serverProtocolConfig.transportPacketMagicHeader = headersValueList.at(3);
} else {
// For other protocols, create basic protocol configs
// This will need to be expanded for each protocol type
protocolConfig = QSharedPointer<ProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
// For now, store basic port and transport info as JSON until all protocol configs are properly structured
QJsonObject tempConfig;
tempConfig.insert(config_key::port, QString::number(port));
tempConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, protocol));
if (container == DockerContainer::Sftp) {
tempConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
tempConfig.insert(config_key::password, Utils::getRandomString(16));
} else if (container == DockerContainer::Socks5Proxy) {
tempConfig.insert(config_key::userName, protocols::socks5Proxy::defaultUserName);
tempConfig.insert(config_key::password, Utils::getRandomString(16));
}
// Store this in the protocol config's internal JSON for now
// TODO: Replace with proper protocol config structure
protocolConfig = QSharedPointer<ProtocolConfig>::create(tempConfig, ProtocolProps::protoToString(protocol));
}
config.insert(config_key::container, ContainerProps::containerToString(container));
} else {
// Non-main protocols get basic configs
protocolConfig = QSharedPointer<ProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
}
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
containerConfig.protocolConfigs.insert(ProtocolProps::protoToString(protocol), protocolConfig);
}
return config;
return containerConfig;
}

View File

@@ -10,6 +10,8 @@
#include "core/defs.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/containers/containerConfig.h"
#include "core/models/servers/serverConfig.h"
class ServerController;
class Settings;
@@ -40,7 +42,7 @@ public:
InstallResult scanServerForInstalledContainers(const ServerCredentials &serverCredentials);
InstallResult updateContainer(const DockerContainer container, const ServerCredentials &serverCredentials,
const QJsonObject &containerConfig);
const ContainerConfig &containerConfig);
// Server management operations
ErrorCode removeProcessedServer(const ServerCredentials &serverCredentials);
@@ -48,7 +50,7 @@ public:
ErrorCode removeAllContainers(const ServerCredentials &serverCredentials);
ErrorCode removeProcessedContainer(const DockerContainer container, const ServerCredentials &serverCredentials);
ErrorCode removeApiConfig(const QJsonObject &serverConfig);
ErrorCode removeApiConfig(const QSharedPointer<ServerConfig> &serverConfig);
ErrorCode clearCachedProfile(const ServerCredentials &serverCredentials);
// Utility methods
@@ -61,7 +63,7 @@ public:
signals:
void clientAppendRequested(const DockerContainer container, const ServerCredentials &credentials,
const QJsonObject &containerConfig, const QString &clientName,
const ContainerConfig &containerConfig, const QString &clientName,
const QSharedPointer<ServerController> &serverController);
void containerInstalled(const InstallResult &result);
@@ -81,23 +83,23 @@ signals:
private:
// Installation helpers
ErrorCode installServer(const DockerContainer container,
const QMap<DockerContainer, QJsonObject> &installedContainers,
const QMap<DockerContainer, ContainerConfig> &installedContainers,
const ServerCredentials &serverCredentials,
const QSharedPointer<ServerController> &serverController,
QString &finishMessage, QJsonObject &serverConfig);
QString &finishMessage, QSharedPointer<ServerConfig> &serverConfig);
ErrorCode installContainer(const DockerContainer container,
const QMap<DockerContainer, QJsonObject> &installedContainers,
const QMap<DockerContainer, ContainerConfig> &installedContainers,
const ServerCredentials &serverCredentials,
const QSharedPointer<ServerController> &serverController,
QString &finishMessage);
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
const QSharedPointer<ServerController> &serverController,
QMap<DockerContainer, QJsonObject> &installedContainers);
QMap<DockerContainer, ContainerConfig> &installedContainers);
QJsonObject generateContainerConfig(const DockerContainer container, int port,
const TransportProto transportProto);
ContainerConfig generateContainerConfig(const DockerContainer container, int port,
const TransportProto transportProto);
bool isServerAlreadyExists(const ServerCredentials &serverCredentials) const;

View File

@@ -22,22 +22,7 @@ SelfhostedConfigController::SelfhostedConfigController(std::shared_ptr<Settings>
m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
}
bool SelfhostedConfigController::isDefaultServerDefaultContainerHasSplitTunneling() const
{
int defaultServerIndex = m_settings->defaultServerIndex();
auto servers = m_settings->serversArray();
if (defaultServerIndex >= servers.size()) return false;
auto serverConfig = ServerConfig::createServerConfig(servers.at(defaultServerIndex).toObject());
auto defaultContainer = ContainerProps::containerFromString(serverConfig->defaultContainer);
if (!serverConfig->containerConfigs.contains(serverConfig->defaultContainer)) {
return false;
}
const auto &containerConfig = serverConfig->containerConfigs[serverConfig->defaultContainer];
return checkSplitTunnelingInContainer(containerConfig, serverConfig->defaultContainer);
}
void SelfhostedConfigController::toggleAmneziaDns(bool enabled)
{
@@ -152,30 +137,4 @@ bool SelfhostedConfigController::isProtocolSupported(Proto protocol) const
}
}
bool SelfhostedConfigController::checkSplitTunnelingInContainer(const ContainerConfig &containerConfig,
const QString &defaultContainer) const
{
for (const auto &protocol : containerConfig.protocolConfigs) {
Proto protoType = ProtocolProps::protoFromString(protocol->protocolName);
switch (protoType) {
case Proto::Awg: {
auto awgConfig = protocol.dynamicCast<AwgProtocolConfig>();
if (awgConfig && awgConfig->clientConfig.awgConfig.mtu != 0) {
return true;
}
break;
}
case Proto::WireGuard: {
auto wgConfig = protocol.dynamicCast<WireGuardProtocolConfig>();
if (wgConfig && wgConfig->clientConfig.mtu != 0) {
return true;
}
break;
}
default:
break;
}
}
return false;
}

View File

@@ -17,7 +17,6 @@ public:
explicit SelfhostedConfigController(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
// Self-hosted specific functionality
bool isDefaultServerDefaultContainerHasSplitTunneling() const;
// Amnezia DNS management
void toggleAmneziaDns(bool enabled);

View File

@@ -8,6 +8,15 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
#include "core/models/protocols/openvpnProtocolConfig.h"
#include "core/models/protocols/wireguardProtocolConfig.h"
#include "core/models/protocols/awgProtocolConfig.h"
#include "core/models/protocols/xrayProtocolConfig.h"
#include "core/models/protocols/shadowsocksProtocolConfig.h"
#include "core/models/protocols/cloakProtocolConfig.h"
#include "core/models/protocols/sftpProtocolConfig.h"
#include "core/models/protocols/socks5ProtocolConfig.h"
#include <QPointer>
#include <QTemporaryFile>
#include <QThread>
@@ -247,7 +256,7 @@ ErrorCode ServerController::removeContainer(const ServerCredentials &credentials
replaceVars(amnezia::scriptData(SharedScriptType::remove_container), generateVarsForContainer(credentials, container)));
}
ErrorCode ServerController::setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config, bool isUpdate)
ErrorCode ServerController::setupContainer(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config, bool isUpdate)
{
qDebug().noquote() << "ServerController::setupContainer" << ContainerProps::containerToString(container);
ErrorCode e = ErrorCode::NoError;
@@ -307,8 +316,8 @@ ErrorCode ServerController::setupContainer(const ServerCredentials &credentials,
return startupContainerWorker(credentials, container, config);
}
ErrorCode ServerController::updateContainer(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &oldConfig,
QJsonObject &newConfig)
ErrorCode ServerController::updateContainer(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &oldConfig,
ContainerConfig &newConfig)
{
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
qDebug() << "ServerController::updateContainer for container" << container << "reinstall required is" << reinstallRequired;
@@ -324,86 +333,20 @@ ErrorCode ServerController::updateContainer(const ServerCredentials &credentials
}
}
bool ServerController::isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
bool ServerController::isReinstallContainerRequired(DockerContainer container, const ContainerConfig &oldConfig, const ContainerConfig &newConfig)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
const auto &mainProto = ContainerProps::defaultProtocol(container);
const QString protocolName = ProtocolProps::protoToString(mainProto);
const QJsonObject &oldProtoConfig = oldConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
const QJsonObject &newProtoConfig = newConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
if (container == DockerContainer::OpenVpn) {
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto)
!= newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
return true;
const auto oldProtocolConfig = oldConfig.protocolConfigs.value(protocolName);
const auto newProtocolConfig = newConfig.protocolConfigs.value(protocolName);
if (!oldProtocolConfig || !newProtocolConfig) {
return true; // If either config is missing, reinstall is required
}
if (container == DockerContainer::Cloak) {
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
return true;
}
if (container == DockerContainer::ShadowSocks) {
if (oldProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort))
return true;
}
if (container == DockerContainer::Awg) {
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|| (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
|| (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
|| (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize)
!= newProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize))
|| (oldProtoConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize)
!= newProtoConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize))
|| (oldProtoConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize)
!= newProtoConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize))
|| (oldProtoConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize)
!= newProtoConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize))
|| (oldProtoConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader)
!= newProtoConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader))
|| (oldProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader)
!= newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader))
|| (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)
!= newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader))
|| (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
!= newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
// || (oldProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize)
// != newProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize))
// || (oldProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize)
// != newProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize))
return true;
}
if (container == DockerContainer::WireGuard) {
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|| (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
return true;
}
if (container == DockerContainer::Socks5Proxy) {
return true;
}
if (container == DockerContainer::Xray) {
if (oldProtoConfig.value(config_key::port).toString(protocols::xray::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::xray::defaultPort)) {
return true;
}
}
return false;
// Use the existing isServerSettingsEqual method from ProtocolConfig
return !oldProtocolConfig->isServerSettingsEqual(newProtocolConfig);
}
ErrorCode ServerController::installDockerWorker(const ServerCredentials &credentials, DockerContainer container)
@@ -435,13 +378,13 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
return error;
}
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config)
{
// create folder on host
return runScript(credentials, replaceVars(amnezia::scriptData(SharedScriptType::prepare_host), generateVarsForContainer(credentials, container)));
}
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config)
{
QString dockerFilePath = amnezia::server::getDockerfileFolder(container) + "/Dockerfile";
QString scriptString = QString("sudo rm %1").arg(dockerFilePath);
@@ -479,7 +422,7 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
return error;
}
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -502,7 +445,7 @@ ErrorCode ServerController::runContainerWorker(const ServerCredentials &credenti
return e;
}
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config)
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -524,7 +467,7 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
return e;
}
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config)
{
QString script = amnezia::scriptData(ProtocolScriptType::container_startup, container);
@@ -546,7 +489,7 @@ ErrorCode ServerController::startupContainerWorker(const ServerCredentials &cred
ServerController::Vars ServerController::generateVarsForContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config)
const ContainerConfig &config)
{
// For VPN containers, use configurator pattern
if (ContainerProps::containerService(container) != ServiceType::Other) {
@@ -582,7 +525,9 @@ ServerController::Vars ServerController::generateVarsForContainer(const ServerCr
}
if (configurator) {
return configurator->generateProtocolVars(credentials, container, config);
QString protocolName = ProtocolProps::protoToString(protocol);
auto protocolConfig = config.protocolConfigs.value(protocolName);
return configurator->generateProtocolVars(credentials, container, protocolConfig);
}
}
}
@@ -606,33 +551,37 @@ ServerController::Vars ServerController::generateVarsForContainer(const ServerCr
// Handle container-specific variables for non-VPN services
if (container == DockerContainer::Sftp) {
SftpProtocolConfig protocolConfig(config.value(ProtocolProps::protoToString(Proto::Sftp)).toObject(),
ProtocolProps::protoToString(Proto::Sftp));
QString protocolName = ProtocolProps::protoToString(Proto::Sftp);
auto sftpConfig = qSharedPointerCast<SftpProtocolConfig>(config.protocolConfigs.value(protocolName));
QString port = protocolConfig.serverProtocolConfig.port;
if (port.isEmpty()) {
port = QString::number(ProtocolProps::defaultPort(Proto::Sftp));
if (sftpConfig) {
QString port = sftpConfig->serverProtocolConfig.port;
if (port.isEmpty()) {
port = QString::number(ProtocolProps::defaultPort(Proto::Sftp));
}
vars.append({{"$SFTP_PORT", port}});
vars.append({{"$SFTP_USER", sftpConfig->serverProtocolConfig.userName}});
vars.append({{"$SFTP_PASSWORD", sftpConfig->serverProtocolConfig.password}});
}
vars.append({{"$SFTP_PORT", port}});
vars.append({{"$SFTP_USER", protocolConfig.serverProtocolConfig.userName}});
vars.append({{"$SFTP_PASSWORD", protocolConfig.serverProtocolConfig.password}});
} else if (container == DockerContainer::Socks5Proxy) {
Socks5ProtocolConfig protocolConfig(config.value(ProtocolProps::protoToString(Proto::Socks5Proxy)).toObject(),
ProtocolProps::protoToString(Proto::Socks5Proxy));
QString protocolName = ProtocolProps::protoToString(Proto::Socks5Proxy);
auto socks5Config = qSharedPointerCast<Socks5ProtocolConfig>(config.protocolConfigs.value(protocolName));
QString port = protocolConfig.serverProtocolConfig.port;
if (port.isEmpty()) {
port = protocols::socks5Proxy::defaultPort;
if (socks5Config) {
QString port = socks5Config->serverProtocolConfig.port;
if (port.isEmpty()) {
port = protocols::socks5Proxy::defaultPort;
}
vars.append({{"$SOCKS5_PROXY_PORT", port}});
const QString &username = socks5Config->serverProtocolConfig.userName;
const QString &password = socks5Config->serverProtocolConfig.password;
QString socks5user = (!username.isEmpty() && !password.isEmpty()) ? QString("users %1:CL:%2").arg(username, password) : "";
vars.append({{"$SOCKS5_USER", socks5user}});
vars.append({{"$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong"}});
}
vars.append({{"$SOCKS5_PROXY_PORT", port}});
const QString &username = protocolConfig.serverProtocolConfig.userName;
const QString &password = protocolConfig.serverProtocolConfig.password;
QString socks5user = (!username.isEmpty() && !password.isEmpty()) ? QString("users %1:CL:%2").arg(username, password) : "";
vars.append({{"$SOCKS5_USER", socks5user}});
vars.append({{"$SOCKS5_AUTH_TYPE", socks5user.isEmpty() ? "none" : "strong"}});
}
return vars;
@@ -674,7 +623,7 @@ QString ServerController::replaceVars(const QString &script, const Vars &vars)
return s;
}
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config)
{
if (container == DockerContainer::Dns) {
return ErrorCode::NoError;
@@ -691,15 +640,37 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
};
const Proto protocol = ContainerProps::defaultProtocol(container);
const QString containerString = ProtocolProps::protoToString(protocol);
const QJsonObject containerConfig = config.value(containerString).toObject();
const QString protocolName = ProtocolProps::protoToString(protocol);
auto protocolConfig = config.protocolConfigs.value(protocolName);
QStringList fixedPorts = ContainerProps::fixedPortsForContainer(container);
QString defaultPort("%1");
QString port = containerConfig.value(config_key::port).toString(defaultPort.arg(ProtocolProps::defaultPort(protocol)));
QString defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol);
QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto);
QString port = QString::number(ProtocolProps::defaultPort(protocol)); // default
QString transportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(protocol), protocol); // default
if (protocolConfig) {
if (auto openVpnConfig = qSharedPointerCast<OpenVpnProtocolConfig>(protocolConfig)) {
port = openVpnConfig->serverProtocolConfig.port;
transportProto = openVpnConfig->serverProtocolConfig.transportProto;
} else if (auto wgConfig = qSharedPointerCast<WireGuardProtocolConfig>(protocolConfig)) {
port = wgConfig->serverProtocolConfig.port;
transportProto = wgConfig->serverProtocolConfig.transportProto;
} else if (auto awgConfig = qSharedPointerCast<AwgProtocolConfig>(protocolConfig)) {
port = awgConfig->serverProtocolConfig.port;
transportProto = awgConfig->serverProtocolConfig.transportProto;
} else if (auto xrayConfig = qSharedPointerCast<XrayProtocolConfig>(protocolConfig)) {
port = xrayConfig->serverProtocolConfig.port;
transportProto = xrayConfig->serverProtocolConfig.transportProto;
} else if (auto shadowsocksConfig = qSharedPointerCast<ShadowsocksProtocolConfig>(protocolConfig)) {
port = shadowsocksConfig->serverProtocolConfig.port;
} else if (auto cloakConfig = qSharedPointerCast<CloakProtocolConfig>(protocolConfig)) {
port = cloakConfig->serverProtocolConfig.port;
} else if (auto sftpConfig = qSharedPointerCast<SftpProtocolConfig>(protocolConfig)) {
port = sftpConfig->serverProtocolConfig.port;
} else if (auto socks5Config = qSharedPointerCast<Socks5ProtocolConfig>(protocolConfig)) {
port = socks5Config->serverProtocolConfig.port;
}
}
// TODO reimplement with netstat
QString script = QString("which lsof > /dev/null 2>&1 || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port);

View File

@@ -5,6 +5,7 @@
#include <QObject>
#include "core/models/containers/containers_defs.h"
#include "core/models/containers/containerConfig.h"
#include "core/defs.h"
#include "core/sshclient.h"
@@ -25,12 +26,12 @@ public:
ErrorCode rebootServer(const ServerCredentials &credentials);
ErrorCode removeAllContainers(const ServerCredentials &credentials);
ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config, bool isUpdate = false);
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &oldConfig,
QJsonObject &newConfig);
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config, bool isUpdate = false);
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &oldConfig,
ContainerConfig &newConfig);
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
const ContainerConfig &config = ContainerConfig());
ErrorCode uploadTextFileToContainer(DockerContainer container, const ServerCredentials &credentials, const QString &file,
const QString &path,
@@ -40,7 +41,7 @@ public:
QString replaceVars(const QString &script, const Vars &vars);
Vars generateVarsForContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
const ContainerConfig &config = ContainerConfig());
ErrorCode runScript(const ServerCredentials &credentials, QString script,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
@@ -59,14 +60,14 @@ public:
private:
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config = ContainerConfig());
ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, QJsonObject &config);
const ContainerConfig &config = ContainerConfig());
ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config);
ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config);
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config);
bool isReinstallContainerRequired(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
ErrorCode isServerPortBusy(const ServerCredentials &credentials, DockerContainer container, const ContainerConfig &config);
bool isReinstallContainerRequired(DockerContainer container, const ContainerConfig &oldConfig, const ContainerConfig &newConfig);
ErrorCode isUserInSudo(const ServerCredentials &credentials, DockerContainer container);
ErrorCode isServerDpkgBusy(const ServerCredentials &credentials, DockerContainer container);

View File

@@ -12,8 +12,11 @@
#include "core/models/protocols/ikev2ProtocolConfig.h"
#include "core/models/protocols/openvpnProtocolConfig.h"
#include "core/models/protocols/shadowsocksProtocolConfig.h"
#include "core/models/protocols/torWebsiteProtocolConfig.h"
#include "core/models/protocols/wireguardProtocolConfig.h"
#include "core/models/protocols/xrayProtocolConfig.h"
#include "core/models/protocols/protocolConfig.h"
#include <variant>
VpnConfigurationsController::VpnConfigurationsController(const std::shared_ptr<Settings> &settings,
QSharedPointer<ServerController> serverController, QObject *parent)
@@ -36,31 +39,33 @@ QScopedPointer<ConfiguratorBase> VpnConfigurationsController::createConfigurator
}
}
QSharedPointer<ProtocolConfig> VpnConfigurationsController::createProtocolConfig(const Proto protocol, const QJsonObject &protocolConfigJson)
QSharedPointer<ProtocolConfig> VpnConfigurationsController::createProtocolConfig(const Proto protocol)
{
switch (protocol) {
case Proto::OpenVpn:
return QSharedPointer<OpenVpnProtocolConfig>::create(protocolConfigJson, ProtocolProps::protoToString(protocol));
return QSharedPointer<OpenVpnProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
case Proto::ShadowSocks:
return QSharedPointer<ShadowsocksProtocolConfig>::create(protocolConfigJson, ProtocolProps::protoToString(protocol));
return QSharedPointer<ShadowsocksProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
case Proto::Cloak:
return QSharedPointer<CloakProtocolConfig>::create(protocolConfigJson, ProtocolProps::protoToString(protocol));
return QSharedPointer<CloakProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
case Proto::WireGuard:
return QSharedPointer<WireGuardProtocolConfig>::create(protocolConfigJson, ProtocolProps::protoToString(protocol));
return QSharedPointer<WireGuardProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
case Proto::Awg:
return QSharedPointer<AwgProtocolConfig>::create(protocolConfigJson, ProtocolProps::protoToString(protocol));
return QSharedPointer<AwgProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
case Proto::Xray:
case Proto::SSXray:
return QSharedPointer<XrayProtocolConfig>::create(protocolConfigJson, ProtocolProps::protoToString(protocol));
return QSharedPointer<XrayProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
case Proto::Ikev2:
return QSharedPointer<Ikev2ProtocolConfig>::create(ProtocolProps::protoToString(protocol));
case Proto::TorWebSite:
return QSharedPointer<TorWebsiteProtocolConfig>::create(QJsonObject(), ProtocolProps::protoToString(protocol));
default:
return nullptr;
}
}
ErrorCode VpnConfigurationsController::createProtocolConfigForContainer(const ServerCredentials &credentials,
const DockerContainer container, QJsonObject &containerConfig)
const DockerContainer container, ContainerConfig &containerConfig)
{
ErrorCode errorCode = ErrorCode::NoError;
@@ -69,13 +74,16 @@ ErrorCode VpnConfigurationsController::createProtocolConfigForContainer(const Se
}
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject protocolConfigJson = containerConfig.value(ProtocolProps::protoToString(protocol)).toObject();
// Create ProtocolConfig from JSON
auto protocolConfig = createProtocolConfig(protocol, protocolConfigJson);
QString protocolName = ProtocolProps::protoToString(protocol);
auto protocolConfig = containerConfig.protocolConfigs.value(protocolName);
if (!protocolConfig) {
errorCode = ErrorCode::InternalError;
return errorCode;
protocolConfig = createProtocolConfig(protocol);
if (!protocolConfig) {
errorCode = ErrorCode::InternalError;
return errorCode;
}
containerConfig.protocolConfigs.insert(protocolName, protocolConfig);
}
auto configurator = createConfigurator(protocol);
@@ -84,35 +92,16 @@ ErrorCode VpnConfigurationsController::createProtocolConfigForContainer(const Se
return errorCode;
}
// Extract nativeConfig and store back in JSON for backward compatibility
QString nativeConfig;
if (auto openVpnConfig = qSharedPointerCast<OpenVpnProtocolConfig>(result)) {
nativeConfig = openVpnConfig->clientProtocolConfig.nativeConfig;
} else if (auto wgConfig = qSharedPointerCast<WireGuardProtocolConfig>(result)) {
nativeConfig = wgConfig->clientProtocolConfig.nativeConfig;
} else if (auto awgConfig = qSharedPointerCast<AwgProtocolConfig>(result)) {
nativeConfig = awgConfig->clientProtocolConfig.nativeConfig;
} else if (auto cloakConfig = qSharedPointerCast<CloakProtocolConfig>(result)) {
nativeConfig = cloakConfig->clientProtocolConfig.nativeConfig;
} else if (auto xrayConfig = qSharedPointerCast<XrayProtocolConfig>(result)) {
nativeConfig = xrayConfig->clientProtocolConfig.nativeConfig;
} else if (auto shadowsocksConfig = qSharedPointerCast<ShadowsocksProtocolConfig>(result)) {
nativeConfig = shadowsocksConfig->clientProtocolConfig.nativeConfig;
} else if (auto ikev2Config = qSharedPointerCast<Ikev2ProtocolConfig>(result)) {
nativeConfig = ikev2Config->clientProtocolConfig.nativeConfig;
}
protocolConfigJson.insert(config_key::last_config, nativeConfig);
containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfigJson);
containerConfig.protocolConfigs.insert(protocolName, result);
}
return errorCode;
}
ErrorCode VpnConfigurationsController::createProtocolConfigString(const bool isApiConfig, const QPair<QString, QString> &dns,
const ServerCredentials &credentials, const DockerContainer container,
const QJsonObject &containerConfig, const Proto protocol,
QString &protocolConfigString)
const ServerCredentials &credentials, const DockerContainer container,
const ContainerConfig &containerConfig, const Proto protocol,
QString &protocolConfigString)
{
ErrorCode errorCode = ErrorCode::NoError;
@@ -120,9 +109,8 @@ ErrorCode VpnConfigurationsController::createProtocolConfigString(const bool isA
return errorCode;
}
// Create ProtocolConfig from JSON
QJsonObject protocolConfigJson = containerConfig.value(ProtocolProps::protoToString(protocol)).toObject();
auto protocolConfig = createProtocolConfig(protocol, protocolConfigJson);
QString protocolName = ProtocolProps::protoToString(protocol);
auto protocolConfig = containerConfig.protocolConfigs.value(protocolName);
if (!protocolConfig) {
errorCode = ErrorCode::InternalError;
return errorCode;
@@ -134,31 +122,17 @@ ErrorCode VpnConfigurationsController::createProtocolConfigString(const bool isA
return errorCode;
}
// Extract nativeConfig
QString nativeConfig;
if (auto openVpnConfig = qSharedPointerCast<OpenVpnProtocolConfig>(result)) {
nativeConfig = openVpnConfig->clientProtocolConfig.nativeConfig;
} else if (auto wgConfig = qSharedPointerCast<WireGuardProtocolConfig>(result)) {
nativeConfig = wgConfig->clientProtocolConfig.nativeConfig;
} else if (auto awgConfig = qSharedPointerCast<AwgProtocolConfig>(result)) {
nativeConfig = awgConfig->clientProtocolConfig.nativeConfig;
} else if (auto cloakConfig = qSharedPointerCast<CloakProtocolConfig>(result)) {
nativeConfig = cloakConfig->clientProtocolConfig.nativeConfig;
} else if (auto xrayConfig = qSharedPointerCast<XrayProtocolConfig>(result)) {
nativeConfig = xrayConfig->clientProtocolConfig.nativeConfig;
} else if (auto shadowsocksConfig = qSharedPointerCast<ShadowsocksProtocolConfig>(result)) {
nativeConfig = shadowsocksConfig->clientProtocolConfig.nativeConfig;
} else if (auto ikev2Config = qSharedPointerCast<Ikev2ProtocolConfig>(result)) {
nativeConfig = ikev2Config->clientProtocolConfig.nativeConfig;
}
protocolConfigString = configurator->processConfigWithExportSettings(dns, isApiConfig, nativeConfig);
configurator->processConfigWithExportSettings(dns, isApiConfig, result);
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(result);
std::visit([&protocolConfigString](const auto &config) -> void {
protocolConfigString = config->clientProtocolConfig.nativeConfig;
}, variant);
return errorCode;
}
QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QString, QString> &dns, const QJsonObject &serverConfig,
const QJsonObject &containerConfig, const DockerContainer container)
QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QString, QString> &dns, const QSharedPointer<ServerConfig> &serverConfig,
const ContainerConfig &containerConfig, const DockerContainer container)
{
QJsonObject vpnConfiguration {};
@@ -166,22 +140,44 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QStr
return vpnConfiguration;
}
bool isApiConfig = serverConfig.value(config_key::configVersion).toInt();
bool isApiConfig = static_cast<int>(serverConfig->type);
for (ProtocolEnumNS::Proto proto : ContainerProps::protocolsForContainer(container)) {
if (isApiConfig && container == DockerContainer::Cloak && proto == ProtocolEnumNS::Proto::ShadowSocks) {
continue;
}
QString protocolConfigString =
containerConfig.value(ProtocolProps::protoToString(proto)).toObject().value(config_key::last_config).toString();
QString protocolName = ProtocolProps::protoToString(proto);
auto protocolConfig = containerConfig.protocolConfigs.value(protocolName);
QString protocolConfigString;
if (protocolConfig) {
auto configurator = createConfigurator(proto);
configurator->processConfigWithLocalSettings(dns, isApiConfig, protocolConfig);
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([&protocolConfigString](const auto &config) -> void {
protocolConfigString = config->clientProtocolConfig.nativeConfig;
}, variant);
} else {
protocolConfigString = "";
}
auto configurator = createConfigurator(proto);
protocolConfigString = configurator->processConfigWithLocalSettings(dns, isApiConfig, protocolConfigString);
QJsonObject vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
QJsonObject vpnConfigData;
if (proto == Proto::Xray || proto == Proto::SSXray) {
vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
} else {
vpnConfigData[config_key::config] = protocolConfigString;
if (protocolConfig) {
QJsonObject protocolJson = protocolConfig->toJson();
for (auto it = protocolJson.begin(); it != protocolJson.end(); ++it) {
if (it.key() != config_key::config && it.key() != config_key::last_config) {
vpnConfigData[it.key()] = it.value();
}
}
}
}
if (container == DockerContainer::Awg || container == DockerContainer::WireGuard) {
// add mtu for old configs
if (vpnConfigData[config_key::mtu].toString().isEmpty()) {
vpnConfigData[config_key::mtu] =
container == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
@@ -197,31 +193,32 @@ QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QStr
vpnConfiguration[config_key::dns1] = dns.first;
vpnConfiguration[config_key::dns2] = dns.second;
vpnConfiguration[config_key::hostName] = serverConfig.value(config_key::hostName).toString();
vpnConfiguration[config_key::description] = serverConfig.value(config_key::description).toString();
vpnConfiguration[config_key::hostName] = serverConfig->hostName;
vpnConfiguration[config_key::description] = serverConfig->toJson().value(config_key::description).toString();
vpnConfiguration[config_key::configVersion] = static_cast<int>(serverConfig->type);
vpnConfiguration[config_key::configVersion] = serverConfig.value(config_key::configVersion).toInt();
// TODO: try to get hostName, port, description for 3rd party configs
// vpnConfiguration[config_key::port] = ...;
return vpnConfiguration;
}
void VpnConfigurationsController::updateContainerConfigAfterInstallation(const DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut)
void VpnConfigurationsController::updateContainerConfigAfterInstallation(const DockerContainer container, ContainerConfig &containerConfig,
const QString &stdOut)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
if (container == DockerContainer::TorWebSite) {
QJsonObject protocol = containerConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
QString protocolName = ProtocolProps::protoToString(mainProto);
auto protocolConfig = containerConfig.protocolConfigs.value(protocolName);
qDebug() << "amnezia-tor onions" << stdOut;
QString onion = stdOut;
onion.replace("\n", "");
protocol.insert(config_key::site, onion);
containerConfig.insert(ProtocolProps::protoToString(mainProto), protocol);
if (auto torConfig = qSharedPointerCast<TorWebsiteProtocolConfig>(protocolConfig)) {
torConfig->serverProtocolConfig.site = onion;
}
}
}

View File

@@ -5,8 +5,10 @@
#include "configurators/configurator_base.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/containers/containerConfig.h"
#include "core/defs.h"
#include "core/models/protocols/protocolConfig.h"
#include "core/models/servers/serverConfig.h"
#include "settings.h"
class VpnConfigurationsController : public QObject
@@ -18,19 +20,21 @@ public:
public slots:
ErrorCode createProtocolConfigForContainer(const ServerCredentials &credentials, const DockerContainer container,
QJsonObject &containerConfig);
ContainerConfig &containerConfig);
ErrorCode createProtocolConfigString(const bool isApiConfig, const QPair<QString, QString> &dns, const ServerCredentials &credentials,
const DockerContainer container, const QJsonObject &containerConfig, const Proto protocol,
const DockerContainer container, const ContainerConfig &containerConfig, const Proto protocol,
QString &protocolConfigString);
QJsonObject createVpnConfiguration(const QPair<QString, QString> &dns, const QJsonObject &serverConfig,
const QJsonObject &containerConfig, const DockerContainer container);
QJsonObject createVpnConfiguration(const QPair<QString, QString> &dns, const QSharedPointer<ServerConfig> &serverConfig,
const ContainerConfig &containerConfig, const DockerContainer container);
static void updateContainerConfigAfterInstallation(const DockerContainer container, QJsonObject &containerConfig, const QString &stdOut);
static void updateContainerConfigAfterInstallation(const DockerContainer container, ContainerConfig &containerConfig, const QString &stdOut);
signals:
public:
QSharedPointer<ProtocolConfig> createProtocolConfig(const Proto protocol);
private:
QScopedPointer<ConfiguratorBase> createConfigurator(const Proto protocol);
QSharedPointer<ProtocolConfig> createProtocolConfig(const Proto protocol, const QJsonObject &protocolConfigJson);
std::shared_ptr<Settings> m_settings;
QSharedPointer<ServerController> m_serverController;

View File

@@ -1,113 +0,0 @@
#include "vpnConnectionController.h"
#include <QtConcurrent>
#include "core/controllers/vpnConfigurationController.h"
#include "core/controllers/selfhosted/serverController.h"
#include "settings.h"
#include "logger.h"
#include "utilities.h"
namespace
{
Logger logger("VpnConnectionController");
}
VpnConnectionController::VpnConnectionController(std::shared_ptr<Settings> settings, QObject *parent)
: QObject(parent), m_settings(settings)
{
}
QFuture<QJsonObject> VpnConnectionController::prepareVpnConfiguration(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container,
const QJsonObject &containerConfig)
{
return QtConcurrent::run([this, serverConfig, container, containerConfig]() -> QJsonObject {
logger.info() << "Preparing VPN configuration for container" << ContainerProps::containerToString(container);
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
// TODO: Extract DNS pair from serverConfig
QPair<QString, QString> dns = qMakePair(QString(), QString());
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns,
serverConfig->toJson(),
containerConfig,
container);
emit configurationPrepared(vpnConfiguration);
return vpnConfiguration;
});
}
QFuture<bool> VpnConnectionController::validateConnection(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container)
{
return QtConcurrent::run([this, serverConfig, container]() -> bool {
logger.info() << "Validating connection for container" << ContainerProps::containerToString(container);
if (!isServerSupported(serverConfig, container)) {
return false;
}
// TODO: Implement connection validation logic
// Check if container is supported by current platform
// Check if server is reachable
// Check if container is properly configured
return true;
});
}
QFuture<ErrorCode> VpnConnectionController::establishConnection(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container,
const QJsonObject &vpnConfiguration)
{
return QtConcurrent::run([this, serverConfig, container, vpnConfiguration]() -> ErrorCode {
logger.info() << "Establishing connection for container" << ContainerProps::containerToString(container);
// TODO: Implement connection establishment logic
// This will delegate to VpnConnection or similar
emit connectionEstablished();
return ErrorCode::NoError;
});
}
QFuture<ErrorCode> VpnConnectionController::terminateConnection()
{
return QtConcurrent::run([this]() -> ErrorCode {
logger.info() << "Terminating VPN connection";
// TODO: Implement connection termination logic
// This will delegate to VpnConnection or similar
emit connectionTerminated();
return ErrorCode::NoError;
});
}
bool VpnConnectionController::isServerSupported(const QSharedPointer<ServerConfig> &serverConfig, DockerContainer container) const
{
// TODO: Implement server support validation
// Check if container is supported by current platform
Q_UNUSED(serverConfig)
return ContainerProps::isSupportedByCurrentPlatform(container);
}
QJsonObject VpnConnectionController::createVpnConfiguration(const QPair<QString, QString> &dns,
const QJsonObject &serverConfig,
const QJsonObject &containerConfig,
DockerContainer container)
{
// TODO: Implement VPN configuration creation logic
// This will be moved from existing code
Q_UNUSED(dns)
Q_UNUSED(serverConfig)
Q_UNUSED(containerConfig)
Q_UNUSED(container)
return QJsonObject();
}

View File

@@ -1,57 +0,0 @@
#ifndef VPNCONNECTIONCONTROLLER_H
#define VPNCONNECTIONCONTROLLER_H
#include <QObject>
#include <QFuture>
#include <QSharedPointer>
#include "core/defs.h"
#include "core/models/containers/containers_defs.h"
#include "core/models/servers/serverConfig.h"
#include "protocols/vpnprotocol.h"
class Settings;
class ServerController;
class VpnConfigurationsController;
using namespace amnezia;
class VpnConnectionController : public QObject
{
Q_OBJECT
public:
explicit VpnConnectionController(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QFuture<QJsonObject> prepareVpnConfiguration(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container,
const QJsonObject &containerConfig);
QFuture<bool> validateConnection(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container);
QFuture<ErrorCode> establishConnection(const QSharedPointer<ServerConfig> &serverConfig,
DockerContainer container,
const QJsonObject &vpnConfiguration);
QFuture<ErrorCode> terminateConnection();
bool isServerSupported(const QSharedPointer<ServerConfig> &serverConfig, DockerContainer container) const;
signals:
void configurationPrepared(const QJsonObject &vpnConfiguration);
void connectionEstablished();
void connectionTerminated();
void connectionError(ErrorCode errorCode);
void connectionProgress(const QString &message);
private:
QJsonObject createVpnConfiguration(const QPair<QString, QString> &dns,
const QJsonObject &serverConfig,
const QJsonObject &containerConfig,
DockerContainer container);
std::shared_ptr<Settings> m_settings;
};
#endif // VPNCONNECTIONCONTROLLER_H

View File

@@ -0,0 +1,76 @@
#include "clientInfo.h"
#include <QJsonObject>
namespace
{
namespace configKey
{
constexpr char clientId[] = "clientId";
constexpr char clientName[] = "clientName";
constexpr char container[] = "container";
constexpr char userData[] = "userData";
constexpr char creationDate[] = "creationDate";
constexpr char latestHandshake[] = "latestHandshake";
constexpr char dataReceived[] = "dataReceived";
constexpr char dataSent[] = "dataSent";
constexpr char allowedIps[] = "allowedIps";
}
}
ClientInfo::ClientInfo()
: container(DockerContainer::None)
{
}
ClientInfo::ClientInfo(const QString &clientId, const QString &clientName)
: clientId(clientId), clientName(clientName), creationDate(QDateTime::currentDateTime()), container(DockerContainer::None)
{
}
ClientInfo::ClientInfo(const QJsonObject &jsonObject)
{
clientId = jsonObject.value(configKey::clientId).toString();
container = ContainerProps::containerFromString(jsonObject.value(configKey::container).toString());
QJsonObject userData = jsonObject.value(configKey::userData).toObject();
clientName = userData.value(configKey::clientName).toString();
creationDate = QDateTime::fromString(userData.value(configKey::creationDate).toString());
latestHandshake = jsonObject.value(configKey::latestHandshake).toString();
dataReceived = jsonObject.value(configKey::dataReceived).toString();
dataSent = jsonObject.value(configKey::dataSent).toString();
allowedIps = jsonObject.value(configKey::allowedIps).toString();
}
QJsonObject ClientInfo::toJson() const
{
QJsonObject jsonObject;
jsonObject[configKey::clientId] = clientId;
jsonObject[configKey::container] = ContainerProps::containerToString(container);
QJsonObject userData;
userData[configKey::clientName] = clientName;
userData[configKey::creationDate] = creationDate.toString();
jsonObject[configKey::userData] = userData;
if (!latestHandshake.isEmpty()) {
jsonObject[configKey::latestHandshake] = latestHandshake;
}
if (!dataReceived.isEmpty()) {
jsonObject[configKey::dataReceived] = dataReceived;
}
if (!dataSent.isEmpty()) {
jsonObject[configKey::dataSent] = dataSent;
}
if (!allowedIps.isEmpty()) {
jsonObject[configKey::allowedIps] = allowedIps;
}
return jsonObject;
}
ClientInfo ClientInfo::fromJson(const QJsonObject &jsonObject)
{
return ClientInfo(jsonObject);
}

View File

@@ -0,0 +1,34 @@
#ifndef CLIENTINFO_H
#define CLIENTINFO_H
#include <QString>
#include <QDateTime>
#include <QJsonObject>
#include "core/models/containers/containers_defs.h"
using namespace amnezia;
class ClientInfo
{
public:
ClientInfo();
ClientInfo(const QString &clientId, const QString &clientName);
ClientInfo(const QJsonObject &jsonObject);
QJsonObject toJson() const;
static ClientInfo fromJson(const QJsonObject &jsonObject);
QString clientId;
QString clientName;
QDateTime creationDate;
DockerContainer container;
QString latestHandshake;
QString dataReceived;
QString dataSent;
QString allowedIps;
};
#endif // CLIENTINFO_H

View File

@@ -14,11 +14,13 @@ class AwgProtocolConfig;
class SftpProtocolConfig;
class Socks5ProtocolConfig;
class Ikev2ProtocolConfig;
class TorWebsiteProtocolConfig;
using ProtocolConfigVariant =
std::variant<QSharedPointer<OpenVpnProtocolConfig>, QSharedPointer<WireGuardProtocolConfig>, QSharedPointer<ShadowsocksProtocolConfig>,
QSharedPointer<CloakProtocolConfig>, QSharedPointer<XrayProtocolConfig>, QSharedPointer<AwgProtocolConfig>,
QSharedPointer<SftpProtocolConfig>, QSharedPointer<Socks5ProtocolConfig>, QSharedPointer<Ikev2ProtocolConfig> >;
QSharedPointer<SftpProtocolConfig>, QSharedPointer<Socks5ProtocolConfig>, QSharedPointer<Ikev2ProtocolConfig>,
QSharedPointer<TorWebsiteProtocolConfig> >;
class ProtocolConfig
{

View File

@@ -0,0 +1,32 @@
#include "torWebsiteProtocolConfig.h"
#include "protocols/protocols_defs.h"
using namespace amnezia;
TorWebsiteProtocolConfig::TorWebsiteProtocolConfig(const QJsonObject &protocolConfigObject, const QString &protocolName)
: ProtocolConfig(protocolName)
{
serverProtocolConfig.site = protocolConfigObject.value(config_key::site).toString();
clientProtocolConfig.isEmpty = false;
}
QJsonObject TorWebsiteProtocolConfig::toJson() const
{
QJsonObject json;
json[config_key::site] = serverProtocolConfig.site;
return json;
}
bool TorWebsiteProtocolConfig::hasEqualServerSettings(const TorWebsiteProtocolConfig &other) const
{
return serverProtocolConfig.site == other.serverProtocolConfig.site;
}
void TorWebsiteProtocolConfig::clearClientSettings()
{
clientProtocolConfig.isEmpty = true;
}

View File

@@ -0,0 +1,36 @@
#ifndef TORWEBSITEPROTOCOLCONFIG_H
#define TORWEBSITEPROTOCOLCONFIG_H
#include <QJsonObject>
#include <QString>
#include "protocolConfig.h"
namespace torWebsite
{
struct ServerProtocolConfig
{
QString site;
};
struct ClientProtocolConfig
{
bool isEmpty = true;
};
}
class TorWebsiteProtocolConfig : public ProtocolConfig
{
public:
TorWebsiteProtocolConfig(const QJsonObject &protocolConfigObject, const QString &protocolName);
QJsonObject toJson() const override;
bool hasEqualServerSettings(const TorWebsiteProtocolConfig &other) const;
void clearClientSettings();
torWebsite::ServerProtocolConfig serverProtocolConfig;
torWebsite::ClientProtocolConfig clientProtocolConfig;
};
#endif // TORWEBSITEPROTOCOLCONFIG_H

View File

@@ -204,26 +204,22 @@ bool IosController::connectVpn(amnezia::Proto proto, const QJsonObject& configur
object:m_currentTunnel.connection];
if (proto == amnezia::Proto::OpenVpn) {
switch (proto) {
case amnezia::Proto::OpenVpn:
return setupOpenVPN();
}
if (proto == amnezia::Proto::Cloak) {
case amnezia::Proto::Cloak:
return setupCloak();
}
if (proto == amnezia::Proto::WireGuard) {
case amnezia::Proto::WireGuard:
return setupWireGuard();
}
if (proto == amnezia::Proto::Awg) {
case amnezia::Proto::Awg:
return setupAwg();
}
if (proto == amnezia::Proto::Xray) {
case amnezia::Proto::Xray:
return setupXray();
}
if (proto == amnezia::Proto::SSXray) {
case amnezia::Proto::SSXray:
return setupSSXray();
default:
return false;
}
return false;
}
void IosController::disconnectVpn()

View File

@@ -1,4 +1,4 @@
#include "connectionController.h"
#include "connectionUIController.h"
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
#include <QGuiApplication>
@@ -7,71 +7,59 @@
#endif
#include "core/controllers/vpnConfigurationController.h"
#include "core/models/containers/containers_defs.h"
#include "version.h"
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const QSharedPointer<VpnConnection> &vpnConnection, const std::shared_ptr<Settings> &settings,
QObject *parent)
ConnectionUIController::ConnectionUIController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const QSharedPointer<ConnectionController> &connectionController, const std::shared_ptr<Settings> &settings,
QObject *parent)
: QObject(parent),
m_serversModel(serversModel),
m_containersModel(containersModel),
m_clientManagementModel(clientManagementModel),
m_vpnConnection(vpnConnection),
m_connectionController(connectionController),
m_settings(settings)
{
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, this, &ConnectionController::onConnectionStateChanged);
connect(this, &ConnectionController::connectToVpn, m_vpnConnection.get(), &VpnConnection::connectToVpn, Qt::QueuedConnection);
connect(this, &ConnectionController::disconnectFromVpn, m_vpnConnection.get(), &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
connect(m_connectionController.get(), &ConnectionController::connectionEstablished, this, [this]() {
onConnectionStateChanged(Vpn::ConnectionState::Connected);
});
connect(m_connectionController.get(), &ConnectionController::connectionTerminated, this, [this]() {
onConnectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_connectionController.get(), &ConnectionController::connectionError, this, [this](ErrorCode) {
onConnectionStateChanged(Vpn::ConnectionState::Error);
});
connect(this, &ConnectionController::connectButtonClicked, this, &ConnectionController::toggleConnection, Qt::QueuedConnection);
connect(this, &ConnectionUIController::connectButtonClicked, this, &ConnectionUIController::toggleConnection, Qt::QueuedConnection);
m_state = Vpn::ConnectionState::Disconnected;
}
void ConnectionController::openConnection()
void ConnectionUIController::openConnection()
{
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true)) {
emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
return;
}
#endif
int serverIndex = m_serversModel->getDefaultServerIndex();
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
if (!m_containersModel->isSupportedByCurrentPlatform(container)) {
emit connectionErrorOccurred(ErrorCode::NotSupportedOnThisPlatform);
return;
}
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
auto dns = m_serversModel->getDnsPair(serverIndex);
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container);
emit connectToVpn(serverIndex, credentials, container, vpnConfiguration);
m_connectionController->openConnection(serverIndex, serverConfig, container, credentials, dns);
}
void ConnectionController::closeConnection()
void ConnectionUIController::closeConnection()
{
emit disconnectFromVpn();
m_connectionController->closeConnection();
}
ErrorCode ConnectionController::getLastConnectionError()
ErrorCode ConnectionUIController::getLastConnectionError()
{
return m_vpnConnection->lastError();
}
void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
void ConnectionUIController::onConnectionStateChanged(Vpn::ConnectionState state)
{
m_state = state;
@@ -124,7 +112,7 @@ void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
emit connectionStateChanged();
}
void ConnectionController::onCurrentContainerUpdated()
void ConnectionUIController::onCurrentContainerUpdated()
{
if (m_isConnected || m_isConnectionInProgress) {
emit reconnectWithUpdatedContainer(tr("Settings updated successfully, reconnnection..."));
@@ -134,23 +122,23 @@ void ConnectionController::onCurrentContainerUpdated()
}
}
void ConnectionController::onTranslationsUpdated()
void ConnectionUIController::onTranslationsUpdated()
{
// get translated text of current state
onConnectionStateChanged(getCurrentConnectionState());
}
Vpn::ConnectionState ConnectionController::getCurrentConnectionState()
Vpn::ConnectionState ConnectionUIController::getCurrentConnectionState()
{
return m_state;
}
QString ConnectionController::connectionStateText() const
QString ConnectionUIController::connectionStateText() const
{
return m_connectionStateText;
}
void ConnectionController::toggleConnection()
void ConnectionUIController::toggleConnection()
{
if (m_state == Vpn::ConnectionState::Preparing) {
emit preparingConfig();
@@ -166,12 +154,12 @@ void ConnectionController::toggleConnection()
}
}
bool ConnectionController::isConnectionInProgress() const
bool ConnectionUIController::isConnectionInProgress() const
{
return m_isConnectionInProgress;
}
bool ConnectionController::isConnected() const
bool ConnectionUIController::isConnected() const
{
return m_isConnected;
}

View File

@@ -1,13 +1,13 @@
#ifndef CONNECTIONCONTROLLER_H
#define CONNECTIONCONTROLLER_H
#ifndef CONNECTIONUICONTROLLER_H
#define CONNECTIONUICONTROLLER_H
#include "protocols/vpnprotocol.h"
#include "ui/models/selfhosted/clientManagementModel.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "vpnconnection.h"
#include "core/controllers/connectionController.h"
class ConnectionController : public QObject
class ConnectionUIController : public QObject
{
Q_OBJECT
@@ -16,12 +16,12 @@ public:
Q_PROPERTY(bool isConnectionInProgress READ isConnectionInProgress NOTIFY connectionStateChanged)
Q_PROPERTY(QString connectionStateText READ connectionStateText NOTIFY connectionStateChanged)
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const QSharedPointer<VpnConnection> &vpnConnection, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
explicit ConnectionUIController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const QSharedPointer<ConnectionController> &connectionController, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
~ConnectionController() = default;
~ConnectionUIController() = default;
bool isConnected() const;
bool isConnectionInProgress() const;
@@ -41,8 +41,6 @@ public slots:
void onTranslationsUpdated();
signals:
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
void disconnectFromVpn();
void connectionStateChanged();
void connectionErrorOccurred(ErrorCode errorCode);
@@ -61,7 +59,7 @@ private:
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
QSharedPointer<VpnConnection> m_vpnConnection;
QSharedPointer<ConnectionController> m_connectionController;
std::shared_ptr<Settings> m_settings;
@@ -72,4 +70,4 @@ private:
Vpn::ConnectionState m_state;
};
#endif // CONNECTIONCONTROLLER_H
#endif // CONNECTIONUICONTROLLER_H

View File

@@ -13,6 +13,19 @@
#include "core/qrCodeUtils.h"
#include "core/serialization/serialization.h"
#include "protocols/protocols_defs.h"
#include "core/models/protocols/awgProtocolConfig.h"
#include "core/models/protocols/wireguardProtocolConfig.h"
#include "core/models/protocols/openvpnProtocolConfig.h"
#include "core/models/protocols/shadowsocksProtocolConfig.h"
#include "core/models/protocols/xrayProtocolConfig.h"
#include "core/models/protocols/cloakProtocolConfig.h"
#include "core/models/protocols/protocolConfig.h"
#include "core/models/servers/selfHostedServerConfig.h"
#include "core/models/servers/serverConfig.h"
#include <variant>
#include "core/models/servers/apiV1ServerConfig.h"
#include "core/models/servers/apiV2ServerConfig.h"
#include "core/models/containers/containerConfig.h"
#include "systemController.h"
#include "utilities.h"
@@ -167,7 +180,7 @@ bool ImportController::extractConfigFromData(QString data)
switch (m_configType) {
case ConfigTypes::OpenVpn: {
m_config = extractOpenVpnConfig(config);
if (!m_config.empty()) {
if (m_config) {
checkForMaliciousStrings(m_config);
return true;
}
@@ -176,23 +189,24 @@ bool ImportController::extractConfigFromData(QString data)
case ConfigTypes::Awg:
case ConfigTypes::WireGuard: {
m_config = extractWireGuardConfig(config);
return m_config.empty() ? false : true;
return m_config ? true : false;
}
case ConfigTypes::Xray: {
m_config = extractXrayConfig(config);
return m_config.empty() ? false : true;
return m_config ? true : false;
}
case ConfigTypes::Amnezia: {
m_config = QJsonDocument::fromJson(config.toUtf8()).object();
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
if (apiUtils::isServerFromApi(m_config)) {
auto apiConfig = m_config.value(apiDefs::key::apiConfig).toObject();
if (apiUtils::isServerFromApi(configJson)) {
auto apiConfig = configJson.value(apiDefs::key::apiConfig).toObject();
apiConfig[apiDefs::key::vpnKey] = data;
m_config[apiDefs::key::apiConfig] = apiConfig;
configJson[apiDefs::key::apiConfig] = apiConfig;
}
m_config = ServerConfig::createServerConfig(configJson);
processAmneziaConfig(m_config);
if (!m_config.empty()) {
if (m_config) {
checkForMaliciousStrings(m_config);
return true;
}
@@ -218,13 +232,14 @@ bool ImportController::extractConfigFromQr(const QByteArray &data)
{
QJsonObject dataObj = QJsonDocument::fromJson(data).object();
if (!dataObj.isEmpty()) {
m_config = dataObj;
m_config = ServerConfig::createServerConfig(dataObj);
return true;
}
QByteArray ba_uncompressed = qUncompress(data);
if (!ba_uncompressed.isEmpty()) {
m_config = QJsonDocument::fromJson(ba_uncompressed).object();
QJsonObject configObj = QJsonDocument::fromJson(ba_uncompressed).object();
m_config = ServerConfig::createServerConfig(configObj);
return true;
}
@@ -238,7 +253,8 @@ bool ImportController::extractConfigFromQr(const QByteArray &data)
}
if (!ba.isEmpty()) {
m_config = QJsonDocument::fromJson(ba).object();
QJsonObject configObj = QJsonDocument::fromJson(ba).object();
m_config = ServerConfig::createServerConfig(configObj);
return true;
}
}
@@ -248,7 +264,10 @@ bool ImportController::extractConfigFromQr(const QByteArray &data)
QString ImportController::getConfig()
{
return QJsonDocument(m_config).toJson(QJsonDocument::Indented);
if (!m_config) {
return QString();
}
return QJsonDocument(m_config->toJson()).toJson(QJsonDocument::Indented);
}
QString ImportController::getConfigFileName()
@@ -268,95 +287,84 @@ bool ImportController::isNativeWireGuardConfig()
void ImportController::processNativeWireGuardConfig()
{
auto containers = m_config.value(config_key::containers).toArray();
if (!containers.isEmpty()) {
auto container = containers.at(0).toObject();
auto serverProtocolConfig = container.value(ContainerProps::containerTypeToString(DockerContainer::WireGuard)).toObject();
auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
QString junkPacketMinSize = QString::number(10);
QString junkPacketMaxSize = QString::number(50);
clientProtocolConfig[config_key::junkPacketCount] = junkPacketCount;
clientProtocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
clientProtocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
clientProtocolConfig[config_key::initPacketJunkSize] = "0";
clientProtocolConfig[config_key::responsePacketJunkSize] = "0";
clientProtocolConfig[config_key::initPacketMagicHeader] = "1";
clientProtocolConfig[config_key::responsePacketMagicHeader] = "2";
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
// clientProtocolConfig[config_key::cookieReplyPacketJunkSize] = "0";
// clientProtocolConfig[config_key::transportPacketJunkSize] = "0";
// clientProtocolConfig[config_key::specialJunk1] = "";
// clientProtocolConfig[config_key::specialJunk2] = "";
// clientProtocolConfig[config_key::specialJunk3] = "";
// clientProtocolConfig[config_key::specialJunk4] = "";
// clientProtocolConfig[config_key::specialJunk5] = "";
// clientProtocolConfig[config_key::controlledJunk1] = "";
// clientProtocolConfig[config_key::controlledJunk2] = "";
// clientProtocolConfig[config_key::controlledJunk3] = "";
// clientProtocolConfig[config_key::specialHandshakeTimeout] = "0";
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
container["wireguard"] = serverProtocolConfig;
containers.replace(0, container);
m_config[config_key::containers] = containers;
if (!m_config) return;
auto selfHostedConfig = qSharedPointerCast<SelfHostedServerConfig>(m_config);
if (!selfHostedConfig) return;
QString wireguardContainerName = ContainerProps::containerTypeToString(DockerContainer::WireGuard);
if (!selfHostedConfig->containerConfigs.contains(wireguardContainerName)) {
return;
}
ContainerConfig wireguardContainer = selfHostedConfig->containerConfigs.value(wireguardContainerName);
if (!wireguardContainer.protocolConfigs.contains("wireguard")) {
return;
}
auto wireguardProtocol = wireguardContainer.protocolConfigs.value("wireguard");
QJsonObject awgProtocolConfigJson;
awgProtocolConfigJson[config_key::protocolName] = "awg";
awgProtocolConfigJson[config_key::last_config] = wireguardProtocol->toJson().value(config_key::last_config);
auto awgConfig = QSharedPointer<AwgProtocolConfig>::create(awgProtocolConfigJson, "awg");
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(2, 5));
awgConfig->serverProtocolConfig.junkPacketCount = junkPacketCount;
awgConfig->serverProtocolConfig.junkPacketMinSize = "10";
awgConfig->serverProtocolConfig.junkPacketMaxSize = "50";
awgConfig->serverProtocolConfig.initPacketJunkSize = "0";
awgConfig->serverProtocolConfig.responsePacketJunkSize = "0";
awgConfig->serverProtocolConfig.initPacketMagicHeader = "1";
awgConfig->serverProtocolConfig.responsePacketMagicHeader = "2";
awgConfig->serverProtocolConfig.underloadPacketMagicHeader = "3";
awgConfig->serverProtocolConfig.transportPacketMagicHeader = "4";
wireguardContainer.protocolConfigs["wireguard"] = awgConfig;
selfHostedConfig->containerConfigs[wireguardContainerName] = wireguardContainer;
}
void ImportController::importConfig()
{
ServerCredentials credentials;
credentials.hostName = m_config.value(config_key::hostName).toString();
credentials.port = m_config.value(config_key::port).toInt();
credentials.userName = m_config.value(config_key::userName).toString();
credentials.secretData = m_config.value(config_key::password).toString();
if (!m_config) {
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
return;
}
if (credentials.isValid() || m_config.contains(config_key::containers)) {
m_serversModel->addServer(m_config);
if (auto selfHostedConfig = qSharedPointerCast<SelfHostedServerConfig>(m_config)) {
if (selfHostedConfig->serverCredentials.isValid() || !selfHostedConfig->containerConfigs.isEmpty()) {
m_serversModel->addServer(m_config->toJson());
emit importFinished();
} else if (m_config.contains(config_key::configVersion)) {
quint16 crc = qChecksum(QJsonDocument(m_config).toJson());
} else {
qDebug() << "Failed to import profile - invalid credentials or no containers";
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
}
} else if (apiUtils::isServerFromApi(m_config->toJson())) {
quint16 crc = qChecksum(QJsonDocument(m_config->toJson()).toJson());
if (m_serversModel->isServerFromApiAlreadyExists(crc)) {
emit importErrorOccurred(ErrorCode::ApiConfigAlreadyAdded, true);
} else {
m_config.insert(config_key::crc, crc);
QJsonObject configJson = m_config->toJson();
configJson[config_key::crc] = crc;
auto updatedConfig = ServerConfig::createServerConfig(configJson);
m_serversModel->addServer(m_config);
m_serversModel->addServer(updatedConfig->toJson());
emit importFinished();
}
} else {
qDebug() << "Failed to import profile";
qDebug().noquote() << QJsonDocument(m_config).toJson();
qDebug() << "Failed to import profile - unknown config type";
qDebug().noquote() << QJsonDocument(m_config->toJson()).toJson();
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
}
m_config = {};
m_config.reset();
m_configFileName.clear();
m_maliciousWarningText.clear();
}
QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
QSharedPointer<ServerConfig> ImportController::extractOpenVpnConfig(const QString &data)
{
QJsonObject openVpnConfig;
openVpnConfig[config_key::config] = data;
QJsonObject lastConfig;
lastConfig[config_key::last_config] = QString(QJsonDocument(openVpnConfig).toJson());
lastConfig[config_key::isThirdPartyConfig] = true;
QJsonObject containers;
containers.insert(config_key::container, QJsonValue("amnezia-openvpn"));
containers.insert(config_key::openvpn, QJsonValue(lastConfig));
QJsonArray arr;
arr.push_back(containers);
QString hostName;
const static QRegularExpression hostNameRegExp("remote\\s+([^\\s]+)");
QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(data);
@@ -364,26 +372,34 @@ QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
hostName = hostNameMatch.captured(1);
}
QJsonObject config;
config[config_key::containers] = arr;
config[config_key::defaultContainer] = "amnezia-openvpn";
config[config_key::description] = m_settings->nextAvailableServerName();
auto serverConfig = QSharedPointer<SelfHostedServerConfig>::create();
serverConfig->hostName = hostName;
serverConfig->description = m_settings->nextAvailableServerName();
serverConfig->defaultContainer = "amnezia-openvpn";
const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(data);
if (dnsMatch.hasNext()) {
config[config_key::dns1] = dnsMatch.next().captured(1);
serverConfig->dns1 = dnsMatch.next().captured(1);
}
if (dnsMatch.hasNext()) {
config[config_key::dns2] = dnsMatch.next().captured(1);
serverConfig->dns2 = dnsMatch.next().captured(1);
}
config[config_key::hostName] = hostName;
auto openVpnProtocolConfig = QSharedPointer<OpenVpnProtocolConfig>::create();
openVpnProtocolConfig->clientProtocolConfig.nativeConfig = data;
openVpnProtocolConfig->isThirdPartyConfig = true;
return config;
ContainerConfig containerConfig;
containerConfig.container = DockerContainer::OpenVpn;
containerConfig.protocolConfigs["openvpn"] = openVpnProtocolConfig;
serverConfig->containerConfigs["amnezia-openvpn"] = containerConfig;
return serverConfig;
}
QJsonObject ImportController::extractWireGuardConfig(const QString &data)
QSharedPointer<ServerConfig> ImportController::extractWireGuardConfig(const QString &data)
{
QMap<QString, QString> configMap;
auto configByLines = data.split("\n");
@@ -399,9 +415,6 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
}
}
QJsonObject lastConfig;
lastConfig[config_key::config] = data;
auto url { QUrl::fromUserInput(configMap.value("Endpoint")) };
QString hostName;
QString port;
@@ -410,7 +423,7 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
} else {
qDebug() << "Key parameter 'Endpoint' is missing or has an invalid format";
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
return QJsonObject();
return nullptr;
}
if (url.port() != -1) {
@@ -419,155 +432,182 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
port = protocols::wireguard::defaultPort;
}
lastConfig[config_key::hostName] = hostName;
lastConfig[config_key::port] = port.toInt();
if (!configMap.value("PrivateKey").isEmpty() && !configMap.value("Address").isEmpty() && !configMap.value("PublicKey").isEmpty()) {
lastConfig[config_key::client_priv_key] = configMap.value("PrivateKey");
lastConfig[config_key::client_ip] = configMap.value("Address");
if (!configMap.value("PresharedKey").isEmpty()) {
lastConfig[config_key::psk_key] = configMap.value("PresharedKey");
} else if (!configMap.value("PreSharedKey").isEmpty()) {
lastConfig[config_key::psk_key] = configMap.value("PreSharedKey");
}
lastConfig[config_key::server_pub_key] = configMap.value("PublicKey");
} else {
if (configMap.value("PrivateKey").isEmpty() || configMap.value("Address").isEmpty() || configMap.value("PublicKey").isEmpty()) {
qDebug() << "One of the key parameters is missing (PrivateKey, Address, PublicKey)";
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
return QJsonObject();
return nullptr;
}
if (!configMap.value("MTU").isEmpty()) {
lastConfig[config_key::mtu] = configMap.value("MTU");
}
if (!configMap.value("PersistentKeepalive").isEmpty()) {
lastConfig[config_key::persistent_keep_alive] = configMap.value("PersistentKeepalive");
}
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", "));
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
QString protocolName = "wireguard";
const QStringList requiredJunkFields = { config_key::junkPacketCount, config_key::junkPacketMinSize,
config_key::junkPacketMaxSize, config_key::initPacketJunkSize,
config_key::responsePacketJunkSize, config_key::initPacketMagicHeader,
config_key::responsePacketMagicHeader, config_key::underloadPacketMagicHeader,
config_key::transportPacketMagicHeader };
const QStringList optionalJunkFields = { // config_key::cookieReplyPacketJunkSize,
// config_key::transportPacketJunkSize,
config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3,
const QStringList optionalJunkFields = { config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3,
config_key::specialJunk4, config_key::specialJunk5, config_key::controlledJunk1,
config_key::controlledJunk2, config_key::controlledJunk3, config_key::specialHandshakeTimeout
};
bool hasAllRequiredFields = std::all_of(requiredJunkFields.begin(), requiredJunkFields.end(),
[&configMap](const QString &field) { return !configMap.value(field).isEmpty(); });
if (hasAllRequiredFields) {
for (const QString &field : requiredJunkFields) {
lastConfig[field] = configMap.value(field);
}
for (const QString &field : optionalJunkFields) {
if (!configMap.value(field).isEmpty()) {
lastConfig[field] = configMap.value(field);
}
}
protocolName = "awg";
m_configType = ConfigTypes::Awg;
}
if (!configMap.value("MTU").isEmpty()) {
lastConfig[config_key::mtu] = configMap.value("MTU");
} else {
lastConfig[config_key::mtu] = protocolName == "awg" ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
}
QJsonObject wireguardConfig;
wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson());
wireguardConfig[config_key::isThirdPartyConfig] = true;
wireguardConfig[config_key::port] = port;
wireguardConfig[config_key::transport_proto] = "udp";
QJsonObject containers;
containers.insert(config_key::container, QJsonValue("amnezia-" + protocolName));
containers.insert(protocolName, QJsonValue(wireguardConfig));
QJsonArray arr;
arr.push_back(containers);
QJsonObject config;
config[config_key::containers] = arr;
config[config_key::defaultContainer] = "amnezia-" + protocolName;
config[config_key::description] = m_settings->nextAvailableServerName();
auto serverConfig = QSharedPointer<SelfHostedServerConfig>::create();
serverConfig->hostName = hostName;
serverConfig->description = m_settings->nextAvailableServerName();
const static QRegularExpression dnsRegExp(
"DNS = "
"(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
QRegularExpressionMatch dnsMatch = dnsRegExp.match(data);
if (dnsMatch.hasMatch()) {
config[config_key::dns1] = dnsMatch.captured(1);
config[config_key::dns2] = dnsMatch.captured(2);
serverConfig->dns1 = dnsMatch.captured(1);
serverConfig->dns2 = dnsMatch.captured(2);
}
config[config_key::hostName] = hostName;
ContainerConfig containerConfig;
QSharedPointer<ProtocolConfig> protocolConfig;
return config;
if (hasAllRequiredFields) {
m_configType = ConfigTypes::Awg;
serverConfig->defaultContainer = "amnezia-awg";
containerConfig.container = DockerContainer::Awg;
auto awgConfig = QSharedPointer<AwgProtocolConfig>::create();
awgConfig->clientProtocolConfig.nativeConfig = data;
awgConfig->clientProtocolConfig.clientPrivateKey = configMap.value("PrivateKey");
awgConfig->clientProtocolConfig.clientIp = configMap.value("Address");
awgConfig->serverProtocolConfig.serverPublicKey = configMap.value("PublicKey");
if (!configMap.value("PresharedKey").isEmpty()) {
awgConfig->clientProtocolConfig.pskKey = configMap.value("PresharedKey");
} else if (!configMap.value("PreSharedKey").isEmpty()) {
awgConfig->clientProtocolConfig.pskKey = configMap.value("PreSharedKey");
}
awgConfig->serverProtocolConfig.hostName = hostName;
awgConfig->serverProtocolConfig.port = port.toInt();
awgConfig->serverProtocolConfig.mtu = configMap.value("MTU").isEmpty() ? protocols::awg::defaultMtu : configMap.value("MTU").toInt();
if (!configMap.value("PersistentKeepalive").isEmpty()) {
awgConfig->clientProtocolConfig.persistentKeepalive = configMap.value("PersistentKeepalive");
}
QStringList allowedIps = configMap.value("AllowedIPs").split(", ");
awgConfig->clientProtocolConfig.allowedIps = allowedIps;
for (const QString &field : requiredJunkFields) {
QString value = configMap.value(field);
if (field == config_key::junkPacketCount) awgConfig->serverProtocolConfig.junkPacketCount = value;
else if (field == config_key::junkPacketMinSize) awgConfig->serverProtocolConfig.junkPacketMinSize = value;
else if (field == config_key::junkPacketMaxSize) awgConfig->serverProtocolConfig.junkPacketMaxSize = value;
else if (field == config_key::initPacketJunkSize) awgConfig->serverProtocolConfig.initPacketJunkSize = value;
else if (field == config_key::responsePacketJunkSize) awgConfig->serverProtocolConfig.responsePacketJunkSize = value;
else if (field == config_key::initPacketMagicHeader) awgConfig->serverProtocolConfig.initPacketMagicHeader = value;
else if (field == config_key::responsePacketMagicHeader) awgConfig->serverProtocolConfig.responsePacketMagicHeader = value;
else if (field == config_key::underloadPacketMagicHeader) awgConfig->serverProtocolConfig.underloadPacketMagicHeader = value;
else if (field == config_key::transportPacketMagicHeader) awgConfig->serverProtocolConfig.transportPacketMagicHeader = value;
}
for (const QString &field : optionalJunkFields) {
QString value = configMap.value(field);
if (!value.isEmpty()) {
if (field == config_key::specialJunk1) awgConfig->serverProtocolConfig.specialJunk1 = value;
else if (field == config_key::specialJunk2) awgConfig->serverProtocolConfig.specialJunk2 = value;
else if (field == config_key::specialJunk3) awgConfig->serverProtocolConfig.specialJunk3 = value;
else if (field == config_key::specialJunk4) awgConfig->serverProtocolConfig.specialJunk4 = value;
else if (field == config_key::specialJunk5) awgConfig->serverProtocolConfig.specialJunk5 = value;
else if (field == config_key::controlledJunk1) awgConfig->serverProtocolConfig.controlledJunk1 = value;
else if (field == config_key::controlledJunk2) awgConfig->serverProtocolConfig.controlledJunk2 = value;
else if (field == config_key::controlledJunk3) awgConfig->serverProtocolConfig.controlledJunk3 = value;
else if (field == config_key::specialHandshakeTimeout) awgConfig->serverProtocolConfig.specialHandshakeTimeout = value;
}
}
awgConfig->isThirdPartyConfig = true;
protocolConfig = awgConfig;
containerConfig.protocolConfigs["awg"] = protocolConfig;
} else {
serverConfig->defaultContainer = "amnezia-wireguard";
containerConfig.container = DockerContainer::WireGuard;
auto wgConfig = QSharedPointer<WireGuardProtocolConfig>::create();
wgConfig->clientProtocolConfig.nativeConfig = data;
wgConfig->clientProtocolConfig.clientPrivateKey = configMap.value("PrivateKey");
wgConfig->clientProtocolConfig.clientIp = configMap.value("Address");
wgConfig->serverProtocolConfig.serverPublicKey = configMap.value("PublicKey");
if (!configMap.value("PresharedKey").isEmpty()) {
wgConfig->clientProtocolConfig.pskKey = configMap.value("PresharedKey");
} else if (!configMap.value("PreSharedKey").isEmpty()) {
wgConfig->clientProtocolConfig.pskKey = configMap.value("PreSharedKey");
}
wgConfig->serverProtocolConfig.hostName = hostName;
wgConfig->serverProtocolConfig.port = port.toInt();
wgConfig->serverProtocolConfig.mtu = configMap.value("MTU").isEmpty() ? protocols::wireguard::defaultMtu : configMap.value("MTU").toInt();
if (!configMap.value("PersistentKeepalive").isEmpty()) {
wgConfig->clientProtocolConfig.persistentKeepalive = configMap.value("PersistentKeepalive");
}
QStringList allowedIps = configMap.value("AllowedIPs").split(", ");
wgConfig->clientProtocolConfig.allowedIps = allowedIps;
wgConfig->isThirdPartyConfig = true;
protocolConfig = wgConfig;
containerConfig.protocolConfigs["wireguard"] = protocolConfig;
}
serverConfig->containerConfigs[serverConfig->defaultContainer] = containerConfig;
return serverConfig;
}
QJsonObject ImportController::extractXrayConfig(const QString &data, const QString &description)
QSharedPointer<ServerConfig> ImportController::extractXrayConfig(const QString &data, const QString &description)
{
QJsonParseError parserErr;
QJsonDocument jsonConf = QJsonDocument::fromJson(data.toLocal8Bit(), &parserErr);
QJsonObject xrayVpnConfig;
xrayVpnConfig[config_key::config] = jsonConf.toJson().constData();
QJsonObject lastConfig;
lastConfig[config_key::last_config] = jsonConf.toJson().constData();
lastConfig[config_key::isThirdPartyConfig] = true;
QJsonObject containers;
if (m_configType == ConfigTypes::ShadowSocks) {
containers.insert(config_key::ssxray, QJsonValue(lastConfig));
containers.insert(config_key::container, QJsonValue("amnezia-ssxray"));
} else {
containers.insert(config_key::container, QJsonValue("amnezia-xray"));
containers.insert(config_key::xray, QJsonValue(lastConfig));
}
QJsonArray arr;
arr.push_back(containers);
QString hostName;
const static QRegularExpression hostNameRegExp("\"address\":\\s*\"([^\"]+)");
QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(data);
if (hostNameMatch.hasMatch()) {
hostName = hostNameMatch.captured(1);
}
QJsonObject config;
config[config_key::containers] = arr;
auto serverConfig = QSharedPointer<SelfHostedServerConfig>::create();
serverConfig->hostName = hostName;
serverConfig->description = description.isEmpty() ? m_settings->nextAvailableServerName() : description;
ContainerConfig containerConfig;
QSharedPointer<ProtocolConfig> protocolConfig;
if (m_configType == ConfigTypes::ShadowSocks) {
config[config_key::defaultContainer] = "amnezia-ssxray";
} else {
config[config_key::defaultContainer] = "amnezia-xray";
}
if (description.isEmpty()) {
config[config_key::description] = m_settings->nextAvailableServerName();
} else {
config[config_key::description] = description;
}
config[config_key::hostName] = hostName;
serverConfig->defaultContainer = "amnezia-ssxray";
containerConfig.container = DockerContainer::ShadowSocks;
return config;
auto shadowsocksConfig = QSharedPointer<ShadowsocksProtocolConfig>::create();
shadowsocksConfig->clientProtocolConfig.nativeConfig = data;
shadowsocksConfig->isThirdPartyConfig = true;
protocolConfig = shadowsocksConfig;
containerConfig.protocolConfigs["ssxray"] = protocolConfig;
} else {
serverConfig->defaultContainer = "amnezia-xray";
containerConfig.container = DockerContainer::Xray;
auto xrayConfig = QSharedPointer<XrayProtocolConfig>::create();
xrayConfig->clientProtocolConfig.nativeConfig = data;
xrayConfig->isThirdPartyConfig = true;
protocolConfig = xrayConfig;
containerConfig.protocolConfigs["xray"] = protocolConfig;
}
serverConfig->containerConfigs[serverConfig->defaultContainer] = containerConfig;
return serverConfig;
}
#ifdef Q_OS_ANDROID
@@ -677,20 +717,41 @@ QString ImportController::getQrCodeScanProgressString()
}
#endif
void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
void ImportController::checkForMaliciousStrings(const QSharedPointer<ServerConfig> &serverConfig)
{
const QJsonArray &containers = serverConfig[config_key::containers].toArray();
for (const QJsonValue &container : containers) {
auto containerConfig = container.toObject();
auto containerName = containerConfig[config_key::container].toString();
if ((containerName == ContainerProps::containerToString(DockerContainer::OpenVpn))
|| (containerName == ContainerProps::containerToString(DockerContainer::Cloak))
|| (containerName == ContainerProps::containerToString(DockerContainer::ShadowSocks))) {
if (!serverConfig) return;
auto selfHostedConfig = qSharedPointerCast<SelfHostedServerConfig>(serverConfig);
if (!selfHostedConfig) return;
QString protocolConfig =
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
for (const auto &containerEntry : selfHostedConfig->containerConfigs) {
const ContainerConfig &containerConfig = containerEntry.second;
if (containerConfig.container == DockerContainer::OpenVpn ||
containerConfig.container == DockerContainer::Cloak ||
containerConfig.container == DockerContainer::ShadowSocks) {
QString protocolConfigJson;
for (const auto &protocolEntry : containerConfig.protocolConfigs) {
auto protocolConfig = protocolEntry.second;
ProtocolConfigVariant variant = ProtocolConfig::getProtocolConfigVariant(protocolConfig);
std::visit([&protocolConfigJson](const auto &config) -> void {
using ConfigType = std::decay_t<decltype(*config)>;
if constexpr (std::is_same_v<ConfigType, OpenVpnProtocolConfig> ||
std::is_same_v<ConfigType, CloakProtocolConfig> ||
std::is_same_v<ConfigType, ShadowsocksProtocolConfig>) {
protocolConfigJson = config->clientProtocolConfig.nativeConfig;
}
}, variant);
if (!protocolConfigJson.isEmpty()) {
break;
}
}
if (!protocolConfigJson.isEmpty()) {
// https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/script-options.rst
QStringList dangerousTags {
"up", "tls-verify", "ipchange", "client-connect", "route-up", "route-pre-down", "client-disconnect", "down", "learn-address", "auth-user-pass-verify"
@@ -715,34 +776,39 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
m_maliciousWarningText.push_back(tr("<br>In the imported configuration, potentially dangerous lines were found:"));
for (const auto &string : maliciousStrings) {
m_maliciousWarningText.push_back(QString("<br><i>%1</i>").arg(string));
}
}
}
}
}
}
void ImportController::processAmneziaConfig(QJsonObject &config)
void ImportController::processAmneziaConfig(QSharedPointer<ServerConfig> &config)
{
auto containers = config.value(config_key::containers).toArray();
for (auto i = 0; i < containers.size(); i++) {
auto container = containers.at(i).toObject();
auto dockerContainer = ContainerProps::containerFromString(container.value(config_key::container).toString());
if (!config) return;
auto selfHostedConfig = qSharedPointerCast<SelfHostedServerConfig>(config);
if (!selfHostedConfig) return;
for (auto &containerEntry : selfHostedConfig->containerConfigs) {
QString containerName = containerEntry.first;
ContainerConfig &containerConfig = containerEntry.second;
DockerContainer dockerContainer = ContainerProps::containerFromString(containerName);
if (dockerContainer == DockerContainer::Awg || dockerContainer == DockerContainer::WireGuard) {
auto containerConfig = container.value(ContainerProps::containerTypeToString(dockerContainer)).toObject();
auto protocolConfig = containerConfig.value(config_key::last_config).toString();
if (protocolConfig.isEmpty()) {
return;
QString protocolName = ContainerProps::containerTypeToString(dockerContainer);
if (containerConfig.protocolConfigs.contains(protocolName)) {
auto protocolConfig = containerConfig.protocolConfigs.value(protocolName);
if (auto wgConfig = qSharedPointerCast<WireGuardProtocolConfig>(protocolConfig)) {
wgConfig->serverProtocolConfig.mtu =
dockerContainer == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
} else if (auto awgConfig = qSharedPointerCast<AwgProtocolConfig>(protocolConfig)) {
awgConfig->serverProtocolConfig.mtu =
dockerContainer == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
}
}
QJsonObject jsonConfig = QJsonDocument::fromJson(protocolConfig.toUtf8()).object();
jsonConfig[config_key::mtu] =
dockerContainer == DockerContainer::Awg ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
containerConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
container[ContainerProps::containerTypeToString(dockerContainer)] = containerConfig;
containers.replace(i, container);
config.insert(config_key::containers, containers);
}
}
}

View File

@@ -5,6 +5,7 @@
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "core/models/servers/serverConfig.h"
namespace
{
@@ -61,13 +62,13 @@ signals:
void restoreAppConfig(const QByteArray &data);
private:
QJsonObject extractOpenVpnConfig(const QString &data);
QJsonObject extractWireGuardConfig(const QString &data);
QJsonObject extractXrayConfig(const QString &data, const QString &description = "");
QSharedPointer<ServerConfig> extractOpenVpnConfig(const QString &data);
QSharedPointer<ServerConfig> extractWireGuardConfig(const QString &data);
QSharedPointer<ServerConfig> extractXrayConfig(const QString &data, const QString &description = "");
void checkForMaliciousStrings(const QJsonObject &protocolConfig);
void checkForMaliciousStrings(const QSharedPointer<ServerConfig> &serverConfig);
void processAmneziaConfig(QJsonObject &config);
void processAmneziaConfig(QSharedPointer<ServerConfig> &config);
#if defined Q_OS_ANDROID || defined Q_OS_IOS
void stopDecodingQr();
@@ -77,7 +78,7 @@ private:
QSharedPointer<ContainersModel> m_containersModel;
std::shared_ptr<Settings> m_settings;
QJsonObject m_config;
QSharedPointer<ServerConfig> m_config;
QString m_configFileName;
ConfigTypes m_configType;
QString m_maliciousWarningText;

View File

@@ -10,6 +10,7 @@
#include "core/controllers/vpnConfigurationController.h"
#include "core/controllers/selfhosted/exportController.h"
#include "core/models/containers/containers_defs.h"
#include "core/qrCodeUtils.h"
#include "systemController.h"
@@ -32,7 +33,7 @@ void ExportUIController::generateFullAccessConfig()
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
auto result = m_coreExportController->generateFullAccessConfig(serverConfig);
@@ -55,9 +56,12 @@ void ExportUIController::generateConnectionConfig(const QString &clientName)
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
auto dnsSettings = m_serversModel->getDnsPair(serverIndex);
// Get the container config from the server config instead of the containers model
QString containerName = ContainerProps::containerToString(container);
ContainerConfig containerConfig = serverConfig->containerConfigs.value(containerName);
auto result = m_coreExportController->generateConnectionConfig(clientName, credentials, container,
containerConfig, serverConfig, dnsSettings);

View File

@@ -40,41 +40,39 @@ ClientManagementModel::ClientManagementModel(QSharedPointer<ClientManagementCont
int ClientManagementModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return static_cast<int>(m_clientsTable.size());
return static_cast<int>(m_clientsList.size());
}
QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_clientsTable.size())) {
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_clientsList.size())) {
return QVariant();
}
auto client = m_clientsTable.at(index.row()).toObject();
auto userData = client.value(configKey::userData).toObject();
const ClientInfo &client = m_clientsList.at(index.row());
switch (role) {
case ClientNameRole: return userData.value(configKey::clientName).toString();
case CreationDateRole: return userData.value(configKey::creationDate).toString();
case LatestHandshakeRole: return userData.value(configKey::latestHandshake).toString();
case DataReceivedRole: return userData.value(configKey::dataReceived).toString();
case DataSentRole: return userData.value(configKey::dataSent).toString();
case AllowedIpsRole: return userData.value(configKey::allowedIps).toString();
case ClientNameRole: return client.clientName;
case CreationDateRole: return client.creationDate.toString();
case LatestHandshakeRole: return client.latestHandshake;
case DataReceivedRole: return client.dataReceived;
case DataSentRole: return client.dataSent;
case AllowedIpsRole: return client.allowedIps;
}
return QVariant();
}
void ClientManagementModel::onClientsDataUpdated(const QJsonArray &clientsTable)
void ClientManagementModel::onClientsDataUpdated(const QList<ClientInfo> &clientsList)
{
beginResetModel();
m_clientsTable = clientsTable;
m_clientsList = clientsList;
endResetModel();
}
void ClientManagementModel::onClientRenamed(const int row, const QString &newName)
{
Q_UNUSED(newName)
if (row >= 0 && row < m_clientsTable.size()) {
if (row >= 0 && row < m_clientsList.size()) {
emit dataChanged(index(row, 0), index(row, 0));
}
}

View File

@@ -2,9 +2,10 @@
#define CLIENTMANAGEMENTMODEL_H
#include <QAbstractListModel>
#include <QJsonArray>
#include <QList>
#include "core/controllers/selfhosted/clientManagementController.h"
#include "core/models/clientInfo.h"
class ClientManagementModel : public QAbstractListModel
{
@@ -33,11 +34,11 @@ signals:
void adminConfigRevoked(const DockerContainer container);
private slots:
void onClientsDataUpdated(const QJsonArray &clientsTable);
void onClientsDataUpdated(const QList<ClientInfo> &clientsList);
void onClientRenamed(const int row, const QString &newName);
private:
QJsonArray m_clientsTable;
QList<ClientInfo> m_clientsList;
QSharedPointer<ClientManagementController> m_clientManagementController;
};

View File

@@ -639,49 +639,7 @@ bool ServersModel::setProcessedServerData(const QString &roleString, const QVari
bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
{
auto serverConfig = m_servers1.at(m_defaultServerIndex);
auto defaultContainer = ContainerProps::containerFromString(serverConfig->defaultContainer);
for (const auto &container : serverConfig->containerConfigs) {
if (container.containerName != serverConfig->defaultContainer) {
continue;
}
if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
auto protocolConfigVariant = ProtocolConfig::getProtocolConfigVariant(container.protocolConfigs[serverConfig->defaultContainer]);
return std::visit(
[](const auto &ptr) -> bool {
if constexpr (requires {
ptr->clientProtocolConfig;
ptr->clientProtocolConfig.wireGuardData;
}) {
const auto nativeConfig = ptr->clientProtocolConfig.nativeConfig;
const auto allowedIps = ptr->clientProtocolConfig.wireGuardData.allowedIps;
return (nativeConfig.contains("AllowedIPs") && !nativeConfig.contains("AllowedIPs = 0.0.0.0/0, ::/0"))
|| (!allowedIps.isEmpty() && !allowedIps.contains("0.0.0.0/0"));
} else {
return false;
}
},
protocolConfigVariant);
} else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
|| defaultContainer == DockerContainer::ShadowSocks) {
auto protocolConfigVariant = ProtocolConfig::getProtocolConfigVariant(
container.protocolConfigs[ContainerProps::containerTypeToString(DockerContainer::OpenVpn)]);
return std::visit(
[](const auto &ptr) -> bool {
if constexpr (requires { ptr->clientProtocolConfig; }) {
const auto nativeConfig = ptr->clientProtocolConfig.nativeConfig;
return (!nativeConfig.isEmpty() && !nativeConfig.contains("redirect-gateway"));
} else {
return false;
}
},
protocolConfigVariant);
}
}
return false;
return m_serverConfigController->isDefaultServerDefaultContainerHasSplitTunneling();
}
bool ServersModel::isServerFromApi(const int serverIndex)