mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-20 02:00:55 +07:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0c4e2d914 | |||
| 7fe6e283ba | |||
| a296f1b5c9 | |||
| d8e644b032 | |||
| b64b589acd | |||
| fc50835ccb | |||
| 6c467bdb53 |
+2
-2
@@ -4,7 +4,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
set(AMNEZIAVPN_VERSION 4.9.0.2)
|
||||
set(AMNEZIAVPN_VERSION 4.9.0.1)
|
||||
|
||||
set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE)
|
||||
set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES
|
||||
@@ -28,7 +28,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(APP_ANDROID_VERSION_CODE 2123)
|
||||
set(APP_ANDROID_VERSION_CODE 2122)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
|
||||
@@ -260,6 +260,16 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(APPLE AND NOT IOS AND NOT MACOS_NE)
|
||||
set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/core/protocols/ikev2VpnProtocolMacos.h
|
||||
)
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/core/protocols/ikev2VpnProtocolMacos.mm
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
message("Client desktop build")
|
||||
add_compile_definitions(AMNEZIA_DESKTOP)
|
||||
|
||||
@@ -49,92 +49,14 @@ void ConnectionController::setConnectionState(Vpn::ConnectionState state)
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode ConnectionController::defaultContainerForServer(const QString &serverId, DockerContainer &container) const
|
||||
{
|
||||
const auto kind = m_serversRepository->serverKind(serverId);
|
||||
switch (kind) {
|
||||
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!cfg.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
container = cfg->defaultContainer;
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
||||
if (!cfg.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
container = cfg->defaultContainer;
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
case serverConfigUtils::ConfigType::Native: {
|
||||
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
||||
if (!cfg.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
container = cfg->defaultContainer;
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
||||
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
||||
case serverConfigUtils::ConfigType::ExternalPremium: {
|
||||
const auto cfg = m_serversRepository->apiV2Config(serverId);
|
||||
if (!cfg.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
container = cfg->defaultContainer;
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
||||
case serverConfigUtils::ConfigType::AmneziaFreeV2:
|
||||
return ErrorCode::LegacyApiV1NotSupportedError;
|
||||
case serverConfigUtils::ConfigType::Invalid:
|
||||
default:
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode ConnectionController::isConnectionSupported(const QString &serverId) const
|
||||
{
|
||||
if (serverId.isEmpty()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
if (!isServiceReady()) {
|
||||
return ErrorCode::AmneziaServiceNotRunning;
|
||||
}
|
||||
|
||||
if (serverConfigUtils::isLegacyApiSubscription(m_serversRepository->serverKind(serverId))) {
|
||||
return ErrorCode::LegacyApiV1NotSupportedError;
|
||||
}
|
||||
|
||||
DockerContainer container = DockerContainer::None;
|
||||
const ErrorCode errorCode = defaultContainerForServer(serverId, container);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::None) {
|
||||
return ErrorCode::NoInstalledContainersError;
|
||||
}
|
||||
|
||||
if (ContainerUtils::isUnsupportedContainer(container)) {
|
||||
return ErrorCode::LegacyContainerNotSupportedError;
|
||||
}
|
||||
|
||||
if (!isContainerSupported(container)) {
|
||||
return ErrorCode::NotSupportedOnThisPlatform;
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode ConnectionController::prepareConnection(const QString &serverId,
|
||||
QJsonObject& vpnConfiguration,
|
||||
DockerContainer& container)
|
||||
{
|
||||
if (!isServiceReady()) {
|
||||
return ErrorCode::AmneziaServiceNotRunning;
|
||||
}
|
||||
|
||||
ContainerConfig containerConfigModel;
|
||||
QPair<QString, QString> dns;
|
||||
QString hostName;
|
||||
@@ -198,6 +120,10 @@ ErrorCode ConnectionController::prepareConnection(const QString &serverId,
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
if (!isContainerSupported(container)) {
|
||||
return ErrorCode::NotSupportedOnThisPlatform;
|
||||
}
|
||||
|
||||
vpnConfiguration = createConnectionConfiguration(dns, isApiConfig, hostName, description, configVersion,
|
||||
containerConfigModel, container);
|
||||
|
||||
|
||||
@@ -34,8 +34,6 @@ public:
|
||||
QJsonObject& vpnConfiguration,
|
||||
DockerContainer& container);
|
||||
|
||||
ErrorCode isConnectionSupported(const QString &serverId) const;
|
||||
|
||||
ErrorCode openConnection(const QString &serverId);
|
||||
|
||||
void closeConnection();
|
||||
@@ -75,8 +73,6 @@ signals:
|
||||
#endif
|
||||
|
||||
private:
|
||||
ErrorCode defaultContainerForServer(const QString &serverId, DockerContainer &container) const;
|
||||
|
||||
SecureServersRepository* m_serversRepository;
|
||||
SecureAppSettingsRepository* m_appSettingsRepository;
|
||||
VpnConnection* m_vpnConnection;
|
||||
|
||||
@@ -191,7 +191,7 @@ void CoreController::initControllers()
|
||||
m_languageUiController = new LanguageUiController(m_settingsController, m_languageModel, this);
|
||||
setQmlContextProperty("LanguageUiController", m_languageUiController);
|
||||
|
||||
m_settingsUiController = new SettingsUiController(m_settingsController, m_serversController, this);
|
||||
m_settingsUiController = new SettingsUiController(m_settingsController, m_serversController, m_languageUiController, this);
|
||||
setQmlContextProperty("SettingsController", m_settingsUiController);
|
||||
|
||||
m_pageController = new PageController(m_serversController, m_settingsController, this);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "core/controllers/connectionController.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#include "ui/controllers/api/apiNewsUiController.h"
|
||||
#include "ui/models/api/apiCountryModel.h"
|
||||
#include "ui/models/containersModel.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
|
||||
@@ -155,17 +156,15 @@ void CoreSignalHandlers::initExportControllerHandler()
|
||||
void CoreSignalHandlers::initImportControllerHandler()
|
||||
{
|
||||
connect(m_coreController->m_importCoreController, &ImportController::importFinished, this, [this]() {
|
||||
if (m_coreController->m_connectionUiController->isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int newServerIndex = m_coreController->m_serversController->getServersCount() - 1;
|
||||
const QString serverId = m_coreController->m_serversController->getServerId(newServerIndex);
|
||||
if (!serverId.isEmpty()) {
|
||||
m_coreController->m_serversController->setDefaultServer(serverId);
|
||||
}
|
||||
if (m_coreController->m_serversUiController) {
|
||||
m_coreController->m_serversUiController->setProcessedServerId(serverId);
|
||||
if (!m_coreController->m_connectionController->isConnected()) {
|
||||
int newServerIndex = m_coreController->m_serversController->getServersCount() - 1;
|
||||
const QString serverId = m_coreController->m_serversController->getServerId(newServerIndex);
|
||||
if (!serverId.isEmpty()) {
|
||||
m_coreController->m_serversController->setDefaultServer(serverId);
|
||||
}
|
||||
if (m_coreController->m_serversUiController) {
|
||||
m_coreController->m_serversUiController->setProcessedServerId(serverId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -177,14 +176,17 @@ void CoreSignalHandlers::initApiCountryModelUpdateHandler()
|
||||
if (processedServerId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonArray availableCountries;
|
||||
QString serverCountryCode;
|
||||
|
||||
const auto apiV2 = m_coreController->m_serversRepository->apiV2Config(processedServerId);
|
||||
if (!apiV2.has_value()) {
|
||||
return;
|
||||
if (apiV2.has_value()) {
|
||||
availableCountries = apiV2->apiConfig.availableCountries;
|
||||
serverCountryCode = apiV2->apiConfig.serverCountryCode;
|
||||
}
|
||||
|
||||
m_coreController->m_apiCountryModel->updateModel(apiV2->apiConfig.availableCountries,
|
||||
apiV2->apiConfig.serverCountryCode);
|
||||
|
||||
m_coreController->m_apiCountryModel->updateModel(availableCountries, serverCountryCode);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -235,16 +237,13 @@ void CoreSignalHandlers::initLanguageHandler()
|
||||
connect(m_coreController->m_settingsUiController, &SettingsUiController::resetLanguageToSystem, m_coreController->m_languageUiController, [this]() {
|
||||
m_coreController->m_languageUiController->changeLanguage(m_coreController->m_languageUiController->getSystemLanguageEnum());
|
||||
});
|
||||
connect(m_coreController->m_settingsUiController, &SettingsUiController::appLanguageChanged, m_coreController->m_languageUiController, [this]() {
|
||||
m_coreController->m_languageUiController->onAppLanguageChanged(m_coreController->m_settingsController->getAppLanguage());
|
||||
});
|
||||
}
|
||||
|
||||
void CoreSignalHandlers::initAutoConnectHandler()
|
||||
{
|
||||
if (m_coreController->m_settingsUiController->isAutoConnectEnabled()
|
||||
&& !m_coreController->m_serversController->getDefaultServerId().isEmpty()) {
|
||||
QTimer::singleShot(1000, this, [this]() { m_coreController->m_connectionUiController->toggleConnection(); });
|
||||
QTimer::singleShot(1000, this, [this]() { m_coreController->m_connectionUiController->openConnection(); });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,9 +348,6 @@ void CoreSignalHandlers::initUnsupportedConnectDrawerHandler()
|
||||
{
|
||||
connect(m_coreController->m_subscriptionUiController, &SubscriptionUiController::unsupportedConnectDrawerRequested,
|
||||
m_coreController->m_pageController, &PageController::unsupportedConnectDrawerRequested);
|
||||
|
||||
connect(m_coreController->m_connectionUiController, &ConnectionUiController::unsupportedConnectDrawerRequested,
|
||||
m_coreController->m_pageController, &PageController::unsupportedConnectDrawerRequested);
|
||||
}
|
||||
|
||||
void CoreSignalHandlers::initStrictKillSwitchHandler()
|
||||
|
||||
@@ -72,16 +72,6 @@ namespace
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString buildRemoveContainerScript(const amnezia::ScriptVars &vars, bool removeDataVolume)
|
||||
{
|
||||
QString script = SshSession::replaceVars(amnezia::scriptData(SharedScriptType::remove_container), vars);
|
||||
if (removeDataVolume) {
|
||||
script += QLatin1String("\nsudo docker volume rm -f $CONTAINER_NAME-data 2>/dev/null || true");
|
||||
script = SshSession::replaceVars(script, vars);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
InstallController::InstallController(SecureServersRepository *serversRepository,
|
||||
@@ -130,10 +120,14 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
||||
return e;
|
||||
qDebug().noquote() << "InstallController::setupContainer prepareHostWorker finished";
|
||||
|
||||
const amnezia::ScriptVars removeContainerVars =
|
||||
amnezia::ScriptVars removeContainerVars =
|
||||
amnezia::genBaseVars(credentials, container, QString(), QString());
|
||||
const bool removeDataVolume = !isUpdate && (container == DockerContainer::MtProxy || container == DockerContainer::Telemt);
|
||||
sshSession.runScript(credentials, buildRemoveContainerScript(removeContainerVars, removeDataVolume));
|
||||
if (!isUpdate) {
|
||||
removeContainerVars.append({ { "$REMOVE_CONTAINER_DATA", QStringLiteral("1") } });
|
||||
}
|
||||
sshSession.runScript(credentials,
|
||||
sshSession.replaceVars(amnezia::scriptData(SharedScriptType::remove_container),
|
||||
removeContainerVars));
|
||||
qDebug().noquote() << "InstallController::setupContainer removeContainer finished";
|
||||
|
||||
qDebug().noquote() << "buildContainerWorker start";
|
||||
@@ -158,8 +152,8 @@ ErrorCode InstallController::setupContainer(const ServerCredentials &credentials
|
||||
return startupContainerWorker(credentials, container, config, sshSession);
|
||||
}
|
||||
|
||||
ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig,
|
||||
ContainerConfig &newConfig)
|
||||
ErrorCode InstallController::updateContainer(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig,
|
||||
ContainerConfig &newConfig)
|
||||
{
|
||||
if (!isUpdateDockerContainerRequired(container, oldConfig, newConfig)) {
|
||||
auto adminConfig = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
@@ -191,7 +185,7 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
SshSession sshSession(this);
|
||||
|
||||
bool reinstallRequired = isReinstallContainerRequired(container, oldConfig, newConfig);
|
||||
qDebug() << "InstallController::updateServerConfig for container" << container << "reinstall required is" << reinstallRequired;
|
||||
qDebug() << "InstallController::updateContainer for container" << container << "reinstall required is" << reinstallRequired;
|
||||
|
||||
bool xrayServerSettingsChanged = false;
|
||||
if (container == DockerContainer::Xray || container == DockerContainer::SSXray) {
|
||||
@@ -219,11 +213,11 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
if (errorCode == ErrorCode::NoError && xrayServerSettingsChanged && !skipXrayInboundSync) {
|
||||
DnsSettings dnsSettings = { m_appSettingsRepository->primaryDns(), m_appSettingsRepository->secondaryDns() };
|
||||
XrayConfigurator xrayConfigurator(&sshSession);
|
||||
qDebug() << "InstallController::updateServerConfig applying Xray server inbound sync, reinstall="
|
||||
qDebug() << "InstallController::updateContainer applying Xray server inbound sync, reinstall="
|
||||
<< reinstallRequired;
|
||||
errorCode = xrayConfigurator.applyServerSettingsToRemote(credentials, container, newConfig, dnsSettings, false);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
qDebug() << "InstallController::updateServerConfig Xray inbound sync failed, error="
|
||||
qDebug() << "InstallController::updateContainer Xray inbound sync failed, error="
|
||||
<< static_cast<int>(errorCode);
|
||||
}
|
||||
}
|
||||
@@ -242,41 +236,6 @@ ErrorCode InstallController::updateServerConfig(const QString &serverId, DockerC
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
ErrorCode InstallController::updateClientConfig(const QString &serverId, DockerContainer container, ContainerConfig &newConfig)
|
||||
{
|
||||
switch (m_serversRepository->serverKind(serverId)) {
|
||||
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
||||
auto config = m_serversRepository->selfHostedAdminConfig(serverId);
|
||||
if (!config.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
config->updateContainerConfig(container, newConfig);
|
||||
m_serversRepository->editServer(serverId, config->toJson(), serverConfigUtils::ConfigType::SelfHostedAdmin);
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
||||
auto config = m_serversRepository->selfHostedUserConfig(serverId);
|
||||
if (!config.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
config->updateContainerConfig(container, newConfig);
|
||||
m_serversRepository->editServer(serverId, config->toJson(), serverConfigUtils::ConfigType::SelfHostedUser);
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
case serverConfigUtils::ConfigType::Native: {
|
||||
auto config = m_serversRepository->nativeConfig(serverId);
|
||||
if (!config.has_value()) {
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
config->updateContainerConfig(container, newConfig);
|
||||
m_serversRepository->editServer(serverId, config->toJson(), serverConfigUtils::ConfigType::Native);
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
default:
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
}
|
||||
|
||||
void InstallController::clearCachedProfile(const QString &serverId, DockerContainer container)
|
||||
{
|
||||
if (ContainerUtils::containerService(container) == ServiceType::Other) {
|
||||
@@ -1021,11 +980,12 @@ ErrorCode InstallController::removeContainer(const QString &serverId, DockerCont
|
||||
return ErrorCode::InternalError;
|
||||
}
|
||||
SshSession sshSession(this);
|
||||
const amnezia::ScriptVars removeContainerVars =
|
||||
amnezia::ScriptVars removeContainerVars =
|
||||
amnezia::genBaseVars(credentials, container, QString(), QString());
|
||||
const bool removeDataVolume = (container == DockerContainer::MtProxy || container == DockerContainer::Telemt);
|
||||
ErrorCode errorCode =
|
||||
sshSession.runScript(credentials, buildRemoveContainerScript(removeContainerVars, removeDataVolume));
|
||||
removeContainerVars.append({ { "$REMOVE_CONTAINER_DATA", QStringLiteral("1") } });
|
||||
ErrorCode errorCode = sshSession.runScript(
|
||||
credentials,
|
||||
sshSession.replaceVars(amnezia::scriptData(SharedScriptType::remove_container), removeContainerVars));
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
QMap<DockerContainer, ContainerConfig> containers = adminConfig->containers;
|
||||
@@ -1503,7 +1463,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
QString transportProtoStr = containerAndPortMatch.captured(3);
|
||||
DockerContainer container = ContainerUtils::containerFromString(name);
|
||||
|
||||
if (container == DockerContainer::None || ContainerUtils::isUnsupportedContainer(container)) {
|
||||
if (container == DockerContainer::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1528,7 +1488,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
QString transportProtoStr = torOrDnsRegMatch.captured(3);
|
||||
DockerContainer container = ContainerUtils::containerFromString(name);
|
||||
|
||||
if (container == DockerContainer::None || ContainerUtils::isUnsupportedContainer(container)) {
|
||||
if (container == DockerContainer::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,7 @@ public:
|
||||
~InstallController();
|
||||
|
||||
ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, ContainerConfig &config, bool isUpdate = false);
|
||||
|
||||
// Updates server-side container settings (admin self-hosted only): reconfigures the container over SSH.
|
||||
ErrorCode updateServerConfig(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig, ContainerConfig &newConfig);
|
||||
|
||||
// Updates client-local settings only: rewrites the stored container config for any self-hosted/native server. No SSH.
|
||||
ErrorCode updateClientConfig(const QString &serverId, DockerContainer container, ContainerConfig &newConfig);
|
||||
ErrorCode updateContainer(const QString &serverId, DockerContainer container, const ContainerConfig &oldConfig, ContainerConfig &newConfig);
|
||||
|
||||
ErrorCode rebootServer(const QString &serverId);
|
||||
ErrorCode removeAllContainers(const QString &serverId);
|
||||
|
||||
@@ -29,11 +29,6 @@ ContainerConfig NativeServerConfig::containerConfig(DockerContainer container) c
|
||||
return containers.value(container);
|
||||
}
|
||||
|
||||
void NativeServerConfig::updateContainerConfig(DockerContainer container, const ContainerConfig &config)
|
||||
{
|
||||
containers[container] = config;
|
||||
}
|
||||
|
||||
QPair<QString, QString> NativeServerConfig::getDnsPair(const QString &primaryDns, const QString &secondaryDns) const
|
||||
{
|
||||
QString d1 = dns1;
|
||||
|
||||
@@ -27,8 +27,6 @@ struct NativeServerConfig {
|
||||
bool hasContainers() const;
|
||||
ContainerConfig containerConfig(DockerContainer container) const;
|
||||
|
||||
void updateContainerConfig(DockerContainer container, const ContainerConfig &config);
|
||||
|
||||
QPair<QString, QString> getDnsPair(const QString &primaryDns, const QString &secondaryDns) const;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
|
||||
@@ -43,11 +43,6 @@ ContainerConfig SelfHostedUserServerConfig::containerConfig(DockerContainer cont
|
||||
return containers.value(container);
|
||||
}
|
||||
|
||||
void SelfHostedUserServerConfig::updateContainerConfig(DockerContainer container, const ContainerConfig &config)
|
||||
{
|
||||
containers[container] = config;
|
||||
}
|
||||
|
||||
QPair<QString, QString> SelfHostedUserServerConfig::getDnsPair(const QString &primaryDns,
|
||||
const QString &secondaryDns) const
|
||||
{
|
||||
|
||||
@@ -32,8 +32,6 @@ struct SelfHostedUserServerConfig {
|
||||
bool hasContainers() const;
|
||||
ContainerConfig containerConfig(DockerContainer container) const;
|
||||
|
||||
void updateContainerConfig(DockerContainer container, const ContainerConfig &config);
|
||||
|
||||
QPair<QString, QString> getDnsPair(const QString &primaryDns, const QString &secondaryDns) const;
|
||||
|
||||
QJsonObject toJson() const;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef IKEV2_VPN_PROTOCOL_MACOS_H
|
||||
#define IKEV2_VPN_PROTOCOL_MACOS_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
#include "vpnProtocol.h"
|
||||
|
||||
#if defined(__OBJC__)
|
||||
#include <NetworkExtension/NetworkExtension.h>
|
||||
#endif
|
||||
|
||||
class Ikev2ProtocolMacos : public VpnProtocol
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Ikev2ProtocolMacos(const QJsonObject &configuration, QObject *parent = nullptr);
|
||||
~Ikev2ProtocolMacos() override;
|
||||
|
||||
ErrorCode start() override;
|
||||
void stop() override;
|
||||
|
||||
static QString tunnelName() { return "AmneziaVPN IKEv2"; }
|
||||
|
||||
private:
|
||||
void readIkev2Configuration(const QJsonObject &configuration);
|
||||
|
||||
bool storeClientIdentity();
|
||||
|
||||
void handleStatusChange(int rawStatus);
|
||||
void startTunnelNow();
|
||||
void reportError(ErrorCode code);
|
||||
|
||||
void startHandshakeTimeoutTimer();
|
||||
void stopHandshakeTimeoutTimer();
|
||||
|
||||
void removeStatusObserver();
|
||||
|
||||
private:
|
||||
QJsonObject m_config;
|
||||
|
||||
QString m_hostName;
|
||||
QString m_clientId;
|
||||
QString m_clientCertBase64;
|
||||
QString m_clientCertPassword;
|
||||
|
||||
QTimer *m_handshakeTimeoutTimer { nullptr };
|
||||
bool m_handshakeTimedOut { false };
|
||||
bool m_startWhenDisconnected { false };
|
||||
bool m_tunnelStarted { false };
|
||||
int m_startRetries { 0 };
|
||||
|
||||
void *m_statusObserver { nullptr };
|
||||
|
||||
int m_lastVpnStatus { 0 };
|
||||
|
||||
static constexpr int HANDSHAKE_TIMEOUT_SEC = 20;
|
||||
static constexpr int MAX_START_RETRIES = 5;
|
||||
};
|
||||
|
||||
#endif // IKEV2_VPN_PROTOCOL_MACOS_H
|
||||
@@ -0,0 +1,666 @@
|
||||
#include "ikev2VpnProtocolMacos.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QPointer>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#include "core/protocols/protocolUtils.h"
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/ipcClient.h"
|
||||
#include "ipc.h"
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <NetworkExtension/NetworkExtension.h>
|
||||
#import <Security/Security.h>
|
||||
|
||||
namespace {
|
||||
|
||||
const char *kRepackedP12Password = "amnezia";
|
||||
|
||||
const char *kVpnSystemKeychainPath = "/Library/Keychains/System.keychain";
|
||||
|
||||
const char *vpnStatusName(int status)
|
||||
{
|
||||
switch (status) {
|
||||
case NEVPNStatusInvalid: return "Invalid";
|
||||
case NEVPNStatusDisconnected: return "Disconnected";
|
||||
case NEVPNStatusConnecting: return "Connecting";
|
||||
case NEVPNStatusConnected: return "Connected";
|
||||
case NEVPNStatusReasserting: return "Reasserting";
|
||||
case NEVPNStatusDisconnecting: return "Disconnecting";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
bool prepareIdentity(const QByteArray &source, const QString &friendlyName, QByteArray &repackedP12, QByteArray &caCertDer)
|
||||
{
|
||||
const unsigned char *cursor = reinterpret_cast<const unsigned char *>(source.constData());
|
||||
PKCS12 *sourceP12 = d2i_PKCS12(nullptr, &cursor, source.size());
|
||||
if (!sourceP12) {
|
||||
qCritical() << "[IKEv2-mac] failed to parse client p12 container";
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_PKEY *privateKey = nullptr;
|
||||
X509 *certificate = nullptr;
|
||||
STACK_OF(X509) *caChain = nullptr;
|
||||
int parsed = PKCS12_parse(sourceP12, "", &privateKey, &certificate, &caChain);
|
||||
PKCS12_free(sourceP12);
|
||||
|
||||
if (!parsed || !privateKey || !certificate) {
|
||||
qCritical() << "[IKEv2-mac] failed to extract key/certificate from client p12";
|
||||
if (privateKey) EVP_PKEY_free(privateKey);
|
||||
if (certificate) X509_free(certificate);
|
||||
if (caChain) sk_X509_pop_free(caChain, X509_free);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int caCount = caChain ? sk_X509_num(caChain) : 0;
|
||||
qInfo() << "[IKEv2-mac] CA certificates bundled in client p12:" << caCount;
|
||||
if (caCount > 0) {
|
||||
X509 *caCert = sk_X509_value(caChain, caCount - 1);
|
||||
unsigned char *caEncoded = nullptr;
|
||||
int caLength = i2d_X509(caCert, &caEncoded);
|
||||
if (caLength > 0 && caEncoded) {
|
||||
caCertDer = QByteArray(reinterpret_cast<const char *>(caEncoded), caLength);
|
||||
OPENSSL_free(caEncoded);
|
||||
}
|
||||
}
|
||||
|
||||
PKCS12 *repacked = PKCS12_create(kRepackedP12Password,
|
||||
friendlyName.toUtf8().constData(),
|
||||
privateKey,
|
||||
certificate,
|
||||
caChain,
|
||||
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
|
||||
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
|
||||
PKCS12_DEFAULT_ITER,
|
||||
PKCS12_DEFAULT_ITER,
|
||||
0);
|
||||
EVP_PKEY_free(privateKey);
|
||||
X509_free(certificate);
|
||||
if (caChain) sk_X509_pop_free(caChain, X509_free);
|
||||
|
||||
if (!repacked) {
|
||||
qCritical() << "[IKEv2-mac] failed to repackage client p12";
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char *encoded = nullptr;
|
||||
int encodedLength = i2d_PKCS12(repacked, &encoded);
|
||||
PKCS12_free(repacked);
|
||||
|
||||
if (encodedLength <= 0 || !encoded) {
|
||||
qCritical() << "[IKEv2-mac] failed to serialize repackaged client p12";
|
||||
return false;
|
||||
}
|
||||
|
||||
repackedP12 = QByteArray(reinterpret_cast<const char *>(encoded), encodedLength);
|
||||
OPENSSL_free(encoded);
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeIdentityFromLoginKeychain(const QString &label)
|
||||
{
|
||||
NSDictionary *query = @{
|
||||
(__bridge id)kSecClass : (__bridge id)kSecClassIdentity,
|
||||
(__bridge id)kSecAttrLabel : label.toNSString(),
|
||||
(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitAll,
|
||||
};
|
||||
SecItemDelete((__bridge CFDictionaryRef)query);
|
||||
}
|
||||
|
||||
bool importIdentityToLoginKeychain(const QByteArray &p12, const QString &label)
|
||||
{
|
||||
SecKeychainRef loginKeychain = NULL;
|
||||
if (SecKeychainCopyDefault(&loginKeychain) != errSecSuccess || loginKeychain == NULL) {
|
||||
qCritical() << "[IKEv2-mac] cannot open the login keychain";
|
||||
return false;
|
||||
}
|
||||
|
||||
CFMutableArrayRef trustedApps = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
|
||||
SecTrustedApplicationRef selfApp = NULL;
|
||||
if (SecTrustedApplicationCreateFromPath(NULL, &selfApp) == errSecSuccess) {
|
||||
CFArrayAppendValue(trustedApps, selfApp);
|
||||
CFRelease(selfApp);
|
||||
}
|
||||
SecTrustedApplicationRef neAgent = NULL;
|
||||
if (SecTrustedApplicationCreateFromPath("/usr/libexec/neagent", &neAgent) == errSecSuccess) {
|
||||
CFArrayAppendValue(trustedApps, neAgent);
|
||||
CFRelease(neAgent);
|
||||
}
|
||||
|
||||
SecAccessRef access = NULL;
|
||||
OSStatus accessStatus = SecAccessCreate((__bridge CFStringRef)label.toNSString(), trustedApps, &access);
|
||||
CFRelease(trustedApps);
|
||||
if (accessStatus != errSecSuccess || access == NULL) {
|
||||
qCritical() << "[IKEv2-mac] SecAccessCreate failed, status" << (int)accessStatus;
|
||||
CFRelease(loginKeychain);
|
||||
return false;
|
||||
}
|
||||
|
||||
NSData *p12Data = [NSData dataWithBytes:p12.constData() length:p12.size()];
|
||||
NSDictionary *options = @{
|
||||
(__bridge id)kSecImportExportPassphrase : [NSString stringWithUTF8String:kRepackedP12Password],
|
||||
(__bridge id)kSecImportExportKeychain : (__bridge id)loginKeychain,
|
||||
(__bridge id)kSecImportExportAccess : (__bridge id)access,
|
||||
};
|
||||
|
||||
CFArrayRef items = NULL;
|
||||
OSStatus importStatus = SecPKCS12Import((__bridge CFDataRef)p12Data, (__bridge CFDictionaryRef)options, &items);
|
||||
if (items) {
|
||||
CFRelease(items);
|
||||
}
|
||||
CFRelease(access);
|
||||
CFRelease(loginKeychain);
|
||||
|
||||
if (importStatus != errSecSuccess) {
|
||||
qCritical() << "[IKEv2-mac] SecPKCS12Import into login keychain failed, status" << (int)importStatus;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NSData *copyIdentityPersistentRef(const QString &label)
|
||||
{
|
||||
SecKeychainRef loginKeychain = NULL;
|
||||
SecKeychainCopyDefault(&loginKeychain);
|
||||
|
||||
NSMutableDictionary *query = [@{
|
||||
(__bridge id)kSecClass : (__bridge id)kSecClassIdentity,
|
||||
(__bridge id)kSecAttrLabel : label.toNSString(),
|
||||
(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitOne,
|
||||
(__bridge id)kSecReturnPersistentRef : @YES,
|
||||
} mutableCopy];
|
||||
if (loginKeychain) {
|
||||
query[(__bridge id)kSecMatchSearchList] = @[ (__bridge id)loginKeychain ];
|
||||
}
|
||||
|
||||
CFTypeRef persistentRef = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &persistentRef);
|
||||
if (loginKeychain) {
|
||||
CFRelease(loginKeychain);
|
||||
}
|
||||
|
||||
if (status != errSecSuccess || persistentRef == NULL) {
|
||||
qDebug() << "[IKEv2-mac] client identity not present in login keychain, status" << (int)status;
|
||||
return nil;
|
||||
}
|
||||
|
||||
return (NSData *)CFAutorelease(persistentRef);
|
||||
}
|
||||
|
||||
void runPrivilegedSecurity(const QString &label, const QStringList &arguments)
|
||||
{
|
||||
auto process = IpcClient::CreatePrivilegedProcess();
|
||||
if (!process) {
|
||||
qCritical() << "[IKEv2-mac] privileged service is unavailable for" << label;
|
||||
return;
|
||||
}
|
||||
|
||||
process->setProgram(PermittedProcess::Security);
|
||||
process->setArguments(arguments);
|
||||
process->start();
|
||||
|
||||
bool started = false;
|
||||
{
|
||||
auto reply = process->waitForStarted(5000);
|
||||
reply.waitForFinished();
|
||||
started = reply.returnValue();
|
||||
}
|
||||
|
||||
bool finished = false;
|
||||
{
|
||||
auto reply = process->waitForFinished(15000);
|
||||
reply.waitForFinished();
|
||||
finished = reply.returnValue();
|
||||
}
|
||||
|
||||
QByteArray out;
|
||||
QByteArray err;
|
||||
{
|
||||
auto reply = process->readAllStandardOutput();
|
||||
reply.waitForFinished();
|
||||
out = reply.returnValue();
|
||||
}
|
||||
{
|
||||
auto reply = process->readAllStandardError();
|
||||
reply.waitForFinished();
|
||||
err = reply.returnValue();
|
||||
}
|
||||
|
||||
qInfo() << "[IKEv2-mac]" << label << "started" << started << "finished" << finished
|
||||
<< "| out:" << out.trimmed() << "| err:" << err.trimmed();
|
||||
}
|
||||
|
||||
void disableVpnConfiguration()
|
||||
{
|
||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||
if (!manager.enabled) {
|
||||
return;
|
||||
}
|
||||
manager.enabled = NO;
|
||||
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
|
||||
if (error) {
|
||||
qWarning() << "[IKEv2-mac] failed to disable VPN configuration:"
|
||||
<< QString::fromNSString(error.localizedDescription);
|
||||
} else {
|
||||
qInfo() << "[IKEv2-mac] VPN configuration disabled";
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Ikev2ProtocolMacos::Ikev2ProtocolMacos(const QJsonObject &configuration, QObject *parent)
|
||||
: VpnProtocol(configuration, parent)
|
||||
{
|
||||
readIkev2Configuration(configuration);
|
||||
}
|
||||
|
||||
Ikev2ProtocolMacos::~Ikev2ProtocolMacos()
|
||||
{
|
||||
qInfo() << "[IKEv2-mac] ~Ikev2ProtocolMacos()";
|
||||
if (m_handshakeTimeoutTimer) {
|
||||
m_handshakeTimeoutTimer->stop();
|
||||
m_handshakeTimeoutTimer = nullptr;
|
||||
}
|
||||
removeStatusObserver();
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::readIkev2Configuration(const QJsonObject &configuration)
|
||||
{
|
||||
m_config = configuration.value(ProtocolUtils::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||
|
||||
m_hostName = m_config.value(configKey::hostName).toString();
|
||||
m_clientId = m_config.value(configKey::userName).toString();
|
||||
m_clientCertBase64 = m_config.value(configKey::cert).toString();
|
||||
m_clientCertPassword = m_config.value(configKey::password).toString();
|
||||
}
|
||||
|
||||
bool Ikev2ProtocolMacos::storeClientIdentity()
|
||||
{
|
||||
if (copyIdentityPersistentRef(m_clientId) != nil) {
|
||||
qInfo() << "[IKEv2-mac] client identity already in login keychain, reusing it";
|
||||
return true;
|
||||
}
|
||||
|
||||
qInfo() << "[IKEv2-mac] installing client identity into login keychain";
|
||||
|
||||
QByteArray sourceP12 = QByteArray::fromBase64(m_clientCertBase64.toUtf8());
|
||||
QByteArray repackedP12;
|
||||
QByteArray caCertDer;
|
||||
if (!prepareIdentity(sourceP12, m_clientId, repackedP12, caCertDer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeIdentityFromLoginKeychain(m_clientId);
|
||||
if (!importIdentityToLoginKeychain(repackedP12, m_clientId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!caCertDer.isEmpty()) {
|
||||
QTemporaryFile caFile(QDir::tempPath() + "/amnezia-ikev2-ca-XXXXXX.cer");
|
||||
caFile.setAutoRemove(false);
|
||||
if (caFile.open()) {
|
||||
const QString caPath = caFile.fileName();
|
||||
caFile.write(caCertDer);
|
||||
caFile.close();
|
||||
runPrivilegedSecurity("CA trust", { "add-trusted-cert", "-d", "-r", "trustRoot",
|
||||
"-k", QString::fromLatin1(kVpnSystemKeychainPath), caPath });
|
||||
QFile::remove(caPath);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[IKEv2-mac] no CA certificate in client p12; server validation may fail";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::reportError(ErrorCode code)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, [this, code]() { setLastError(code); }, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::removeStatusObserver()
|
||||
{
|
||||
if (m_statusObserver) {
|
||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:(id)m_statusObserver
|
||||
name:NEVPNStatusDidChangeNotification
|
||||
object:manager.connection];
|
||||
m_statusObserver = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode Ikev2ProtocolMacos::start()
|
||||
{
|
||||
qInfo() << "[IKEv2-mac] start() requested, host =" << m_hostName << ", clientId =" << m_clientId;
|
||||
|
||||
if (m_hostName.isEmpty() || m_clientCertBase64.isEmpty()) {
|
||||
qCritical() << "[IKEv2-mac] missing server address or client certificate";
|
||||
setLastError(ErrorCode::IKEv2ConfigError);
|
||||
return ErrorCode::IKEv2ConfigError;
|
||||
}
|
||||
|
||||
if (!storeClientIdentity()) {
|
||||
setLastError(ErrorCode::IKEv2ConfigError);
|
||||
return ErrorCode::IKEv2ConfigError;
|
||||
}
|
||||
|
||||
m_handshakeTimedOut = false;
|
||||
m_lastVpnStatus = NEVPNStatusInvalid;
|
||||
m_startRetries = 0;
|
||||
m_tunnelStarted = false;
|
||||
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
|
||||
NSString *nsServerAddress = m_hostName.toNSString();
|
||||
NSString *nsLocalIdentifier = m_clientId.toNSString();
|
||||
QString clientId = m_clientId;
|
||||
|
||||
QPointer<Ikev2ProtocolMacos> self = this;
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!self) return;
|
||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||
|
||||
[manager loadFromPreferencesWithCompletionHandler:^(NSError *loadError) {
|
||||
if (!self) return;
|
||||
if (loadError) {
|
||||
qCritical() << "[IKEv2-mac] loading VPN preferences failed:"
|
||||
<< QString::fromNSString(loadError.localizedDescription);
|
||||
self->reportError(ErrorCode::IKEv2LoadError);
|
||||
return;
|
||||
}
|
||||
|
||||
NSData *identityReference = copyIdentityPersistentRef(clientId);
|
||||
if (identityReference == nil) {
|
||||
self->reportError(ErrorCode::IKEv2ConfigError);
|
||||
return;
|
||||
}
|
||||
|
||||
NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];
|
||||
|
||||
protocol.serverAddress = nsServerAddress;
|
||||
protocol.remoteIdentifier = nsServerAddress;
|
||||
protocol.localIdentifier = nsLocalIdentifier;
|
||||
|
||||
protocol.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
|
||||
protocol.certificateType = NEVPNIKEv2CertificateTypeRSA;
|
||||
protocol.identityReference = identityReference;
|
||||
protocol.useExtendedAuthentication = NO;
|
||||
protocol.enablePFS = NO;
|
||||
protocol.disconnectOnSleep = NO;
|
||||
protocol.deadPeerDetectionRate = NEVPNIKEv2DeadPeerDetectionRateMedium;
|
||||
|
||||
protocol.IKESecurityAssociationParameters.encryptionAlgorithm = NEVPNIKEv2EncryptionAlgorithmAES256;
|
||||
protocol.IKESecurityAssociationParameters.integrityAlgorithm = NEVPNIKEv2IntegrityAlgorithmSHA256;
|
||||
protocol.IKESecurityAssociationParameters.diffieHellmanGroup = NEVPNIKEv2DiffieHellmanGroup14;
|
||||
protocol.IKESecurityAssociationParameters.lifetimeMinutes = 1410;
|
||||
|
||||
protocol.childSecurityAssociationParameters.encryptionAlgorithm = NEVPNIKEv2EncryptionAlgorithmAES128GCM;
|
||||
protocol.childSecurityAssociationParameters.diffieHellmanGroup = NEVPNIKEv2DiffieHellmanGroup14;
|
||||
protocol.childSecurityAssociationParameters.lifetimeMinutes = 1410;
|
||||
|
||||
[manager setProtocolConfiguration:protocol];
|
||||
[manager setLocalizedDescription:Ikev2ProtocolMacos::tunnelName().toNSString()];
|
||||
[manager setEnabled:YES];
|
||||
[manager setOnDemandEnabled:NO];
|
||||
|
||||
[manager saveToPreferencesWithCompletionHandler:^(NSError *firstSaveError) {
|
||||
if (!self) return;
|
||||
if (firstSaveError) {
|
||||
qCritical() << "[IKEv2-mac] saving VPN preferences failed:"
|
||||
<< QString::fromNSString(firstSaveError.localizedDescription);
|
||||
self->reportError(ErrorCode::IKEv2SaveError);
|
||||
return;
|
||||
}
|
||||
|
||||
[manager loadFromPreferencesWithCompletionHandler:^(NSError *reloadError) {
|
||||
if (!self) return;
|
||||
if (reloadError) {
|
||||
qCritical() << "[IKEv2-mac] reloading VPN preferences failed:"
|
||||
<< QString::fromNSString(reloadError.localizedDescription);
|
||||
self->reportError(ErrorCode::IKEv2LoadError);
|
||||
return;
|
||||
}
|
||||
|
||||
[manager saveToPreferencesWithCompletionHandler:^(NSError *resaveError) {
|
||||
if (!self) return;
|
||||
if (resaveError) {
|
||||
qCritical() << "[IKEv2-mac] re-saving VPN preferences failed:"
|
||||
<< QString::fromNSString(resaveError.localizedDescription);
|
||||
self->reportError(ErrorCode::IKEv2SaveError);
|
||||
return;
|
||||
}
|
||||
|
||||
self->removeStatusObserver();
|
||||
self->m_statusObserver = (void *)[[NSNotificationCenter defaultCenter]
|
||||
addObserverForName:NEVPNStatusDidChangeNotification
|
||||
object:manager.connection
|
||||
queue:nil
|
||||
usingBlock:^(NSNotification *notification) {
|
||||
if (!self) return;
|
||||
NEVPNConnection *connection = notification.object;
|
||||
int rawStatus = (int)connection.status;
|
||||
QMetaObject::invokeMethod(
|
||||
self, [self, rawStatus]() { if (self) self->handleStatusChange(rawStatus); },
|
||||
Qt::QueuedConnection);
|
||||
}];
|
||||
|
||||
NEVPNStatus current = manager.connection.status;
|
||||
if (current == NEVPNStatusDisconnected || current == NEVPNStatusInvalid) {
|
||||
qInfo() << "[IKEv2-mac] preferences saved, connection is"
|
||||
<< vpnStatusName(current) << "- starting tunnel now";
|
||||
self->m_startWhenDisconnected = false;
|
||||
self->startTunnelNow();
|
||||
} else {
|
||||
qInfo() << "[IKEv2-mac] preferences saved, connection is"
|
||||
<< vpnStatusName(current) << "- waiting for it to disconnect first";
|
||||
self->m_startWhenDisconnected = true;
|
||||
[manager.connection stopVPNTunnel];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
});
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::stop()
|
||||
{
|
||||
qInfo() << "[IKEv2-mac] stop() requested";
|
||||
|
||||
stopHandshakeTimeoutTimer();
|
||||
m_startWhenDisconnected = false;
|
||||
|
||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||
NEVPNStatus status = manager.connection.status;
|
||||
qInfo() << "[IKEv2-mac] stop(): current NEVPNStatus =" << (int)status;
|
||||
|
||||
removeStatusObserver();
|
||||
|
||||
if (status != NEVPNStatusDisconnected && status != NEVPNStatusInvalid) {
|
||||
[manager.connection stopVPNTunnel];
|
||||
qInfo() << "[IKEv2-mac] stop(): stopVPNTunnel issued";
|
||||
}
|
||||
|
||||
disableVpnConfiguration();
|
||||
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::startTunnelNow()
|
||||
{
|
||||
qInfo() << "[IKEv2-mac] startVPNTunnel (attempt" << (m_startRetries + 1) << ")";
|
||||
NEVPNManager *manager = [NEVPNManager sharedManager];
|
||||
NSError *startError = nil;
|
||||
[manager.connection startVPNTunnelAndReturnError:&startError];
|
||||
|
||||
if (!startError) {
|
||||
m_startRetries = 0;
|
||||
m_tunnelStarted = true;
|
||||
QMetaObject::invokeMethod(this, [this]() { startHandshakeTimeoutTimer(); }, Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_startRetries < MAX_START_RETRIES) {
|
||||
m_startRetries++;
|
||||
qWarning() << "[IKEv2-mac] startVPNTunnel failed, will retry (" << m_startRetries << "):"
|
||||
<< QString::fromNSString(startError.localizedDescription);
|
||||
QPointer<Ikev2ProtocolMacos> self = this;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (!self) return;
|
||||
[[NEVPNManager sharedManager] loadFromPreferencesWithCompletionHandler:^(NSError *reloadError) {
|
||||
if (!self) return;
|
||||
self->startTunnelNow();
|
||||
}];
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
qCritical() << "[IKEv2-mac] starting the tunnel failed:"
|
||||
<< QString::fromNSString(startError.localizedDescription);
|
||||
disableVpnConfiguration();
|
||||
reportError(ErrorCode::IKEv2ConnectError);
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::handleStatusChange(int rawStatus)
|
||||
{
|
||||
NEVPNStatus vpnStatus = static_cast<NEVPNStatus>(rawStatus);
|
||||
const Vpn::ConnectionState currentState = connectionState();
|
||||
|
||||
qInfo() << "[IKEv2-mac] status ->" << vpnStatusName(rawStatus)
|
||||
<< "| uiState:" << textConnectionState()
|
||||
<< "| lastStatus:" << vpnStatusName(m_lastVpnStatus)
|
||||
<< "| waitingToStart:" << m_startWhenDisconnected;
|
||||
|
||||
if (m_startWhenDisconnected) {
|
||||
if (vpnStatus == NEVPNStatusDisconnecting) {
|
||||
return;
|
||||
}
|
||||
if (vpnStatus == NEVPNStatusDisconnected) {
|
||||
m_startWhenDisconnected = false;
|
||||
m_lastVpnStatus = NEVPNStatusDisconnected;
|
||||
QPointer<Ikev2ProtocolMacos> self = this;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (self) self->startTunnelNow();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (vpnStatus) {
|
||||
case NEVPNStatusConnecting:
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
break;
|
||||
|
||||
case NEVPNStatusConnected:
|
||||
stopHandshakeTimeoutTimer();
|
||||
m_lastVpnStatus = vpnStatus;
|
||||
m_tunnelStarted = true;
|
||||
qInfo() << "[IKEv2-mac] tunnel established";
|
||||
setConnectionState(Vpn::ConnectionState::Connected);
|
||||
break;
|
||||
|
||||
case NEVPNStatusReasserting:
|
||||
m_lastVpnStatus = vpnStatus;
|
||||
setConnectionState(Vpn::ConnectionState::Reconnecting);
|
||||
break;
|
||||
|
||||
case NEVPNStatusDisconnecting:
|
||||
if (!m_tunnelStarted) {
|
||||
return;
|
||||
}
|
||||
stopHandshakeTimeoutTimer();
|
||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||
break;
|
||||
|
||||
case NEVPNStatusDisconnected: {
|
||||
if (!m_tunnelStarted) {
|
||||
m_lastVpnStatus = vpnStatus;
|
||||
return;
|
||||
}
|
||||
|
||||
stopHandshakeTimeoutTimer();
|
||||
removeStatusObserver();
|
||||
|
||||
if (m_handshakeTimedOut) {
|
||||
qCritical() << "[IKEv2-mac] connection failed: handshake timed out";
|
||||
setLastError(ErrorCode::IKEv2TimeoutError);
|
||||
} else if (m_lastVpnStatus == NEVPNStatusInvalid && currentState == Vpn::ConnectionState::Connecting) {
|
||||
qCritical() << "[IKEv2-mac] connection failed: server rejected the configuration";
|
||||
setLastError(ErrorCode::IKEv2ConfigError);
|
||||
} else if (m_lastVpnStatus == NEVPNStatusReasserting
|
||||
&& (currentState == Vpn::ConnectionState::Connecting
|
||||
|| currentState == Vpn::ConnectionState::Connected)) {
|
||||
qWarning() << "[IKEv2-mac] connection lost (network unavailable)";
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
} else if (m_lastVpnStatus == NEVPNStatusConnected
|
||||
&& (currentState == Vpn::ConnectionState::Connecting
|
||||
|| currentState == Vpn::ConnectionState::Connected)) {
|
||||
qWarning() << "[IKEv2-mac] tunnel turned off outside the app (system settings)";
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
} else {
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
m_lastVpnStatus = vpnStatus;
|
||||
|
||||
disableVpnConfiguration();
|
||||
break;
|
||||
}
|
||||
|
||||
case NEVPNStatusInvalid:
|
||||
if (!m_tunnelStarted) {
|
||||
m_lastVpnStatus = vpnStatus;
|
||||
return;
|
||||
}
|
||||
stopHandshakeTimeoutTimer();
|
||||
removeStatusObserver();
|
||||
qCritical() << "[IKEv2-mac] VPN profile became invalid";
|
||||
m_lastVpnStatus = vpnStatus;
|
||||
setLastError(ErrorCode::IKEv2ConfigError);
|
||||
disableVpnConfiguration();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::startHandshakeTimeoutTimer()
|
||||
{
|
||||
stopHandshakeTimeoutTimer();
|
||||
|
||||
m_handshakeTimeoutTimer = new QTimer(this);
|
||||
m_handshakeTimeoutTimer->setSingleShot(true);
|
||||
m_handshakeTimeoutTimer->setInterval(HANDSHAKE_TIMEOUT_SEC * 1000);
|
||||
connect(m_handshakeTimeoutTimer, &QTimer::timeout, this, [this]() {
|
||||
if (connectionState() == Vpn::ConnectionState::Connecting) {
|
||||
m_handshakeTimedOut = true;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NEVPNManager sharedManager].connection stopVPNTunnel];
|
||||
});
|
||||
}
|
||||
});
|
||||
m_handshakeTimeoutTimer->start();
|
||||
}
|
||||
|
||||
void Ikev2ProtocolMacos::stopHandshakeTimeoutTimer()
|
||||
{
|
||||
if (m_handshakeTimeoutTimer) {
|
||||
m_handshakeTimeoutTimer->stop();
|
||||
m_handshakeTimeoutTimer->deleteLater();
|
||||
m_handshakeTimeoutTimer = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -39,44 +39,33 @@ QString OpenVpnProtocol::defaultConfigPath()
|
||||
return p;
|
||||
}
|
||||
|
||||
void OpenVpnProtocol::cleanupResources()
|
||||
void OpenVpnProtocol::stop()
|
||||
{
|
||||
if (m_openVpnProcess || openVpnProcessIsRunning()) {
|
||||
qDebug() << "OpenVpnProtocol::stop()";
|
||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||
|
||||
// TODO: need refactoring
|
||||
// sendTermSignal() will even return true while server connected ???
|
||||
if ((m_connectionState == Vpn::ConnectionState::Preparing) || (m_connectionState == Vpn::ConnectionState::Connecting)
|
||||
|| (m_connectionState == Vpn::ConnectionState::Connected)
|
||||
|| (m_connectionState == Vpn::ConnectionState::Reconnecting)) {
|
||||
if (!sendTermSignal()) {
|
||||
killOpenVpnProcess();
|
||||
}
|
||||
QThread::msleep(10);
|
||||
m_managementServer.stop();
|
||||
}
|
||||
m_managementServer.stop();
|
||||
|
||||
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
|
||||
QRemoteObjectPendingReply<bool> reply = iface->disableKillSwitch();
|
||||
if (!reply.waitForFinished(1000) && !reply.returnValue()) {
|
||||
qWarning() << "OpenVpnProtocol::cleanupResources(): Failed to disable killswitch";
|
||||
qWarning() << "OpenVpnProtocol::stop(): Failed to disable killswitch";
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenVpnProtocol::stop()
|
||||
{
|
||||
qDebug() << "OpenVpnProtocol::stop()";
|
||||
|
||||
const bool wasActive = m_connectionState == Vpn::ConnectionState::Preparing
|
||||
|| m_connectionState == Vpn::ConnectionState::Connecting
|
||||
|| m_connectionState == Vpn::ConnectionState::Connected
|
||||
|| m_connectionState == Vpn::ConnectionState::Reconnecting;
|
||||
|
||||
if (wasActive) {
|
||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||
}
|
||||
|
||||
cleanupResources();
|
||||
|
||||
if (wasActive || m_connectionState == Vpn::ConnectionState::Disconnecting) {
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
|
||||
ErrorCode OpenVpnProtocol::prepare()
|
||||
@@ -179,7 +168,7 @@ void OpenVpnProtocol::updateRouteGateway(QString line)
|
||||
|
||||
ErrorCode OpenVpnProtocol::start()
|
||||
{
|
||||
cleanupResources();
|
||||
OpenVpnProtocol::stop();
|
||||
|
||||
if (!QFileInfo::exists(configPath())) {
|
||||
setLastError(ErrorCode::OpenVpnConfigMissing);
|
||||
|
||||
@@ -29,7 +29,6 @@ protected slots:
|
||||
void onReadyReadDataFromManagementServer();
|
||||
|
||||
private:
|
||||
void cleanupResources();
|
||||
QString configPath() const;
|
||||
bool openVpnProcessIsRunning() const;
|
||||
bool sendTermSignal();
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#include "ikev2VpnProtocolWindows.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MACX) && !defined(MACOS_NE)
|
||||
#include "ikev2VpnProtocolMacos.h"
|
||||
#endif
|
||||
|
||||
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_connectionState(Vpn::ConnectionState::Unknown),
|
||||
@@ -111,6 +115,8 @@ VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &
|
||||
switch (container) {
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#elif defined(Q_OS_MACX) && !defined(MACOS_NE)
|
||||
case DockerContainer::Ipsec: return new Ikev2ProtocolMacos(configuration);
|
||||
#endif
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
case DockerContainer::OpenVpn: return new OpenVpnProtocol(configuration);
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace amnezia
|
||||
Awg2,
|
||||
WireGuard,
|
||||
OpenVpn,
|
||||
Cloak,
|
||||
ShadowSocks,
|
||||
Ipsec,
|
||||
Xray,
|
||||
SSXray,
|
||||
|
||||
@@ -21,8 +21,6 @@ QString ContainerUtils::containerToString(DockerContainer c)
|
||||
{
|
||||
if (c == DockerContainer::None)
|
||||
return "none";
|
||||
if (c == DockerContainer::Cloak)
|
||||
return "amnezia-openvpn-cloak";
|
||||
if (c == DockerContainer::Awg)
|
||||
return "amnezia-awg";
|
||||
if (c == DockerContainer::Awg2)
|
||||
@@ -64,8 +62,6 @@ QMap<DockerContainer, QString> ContainerUtils::containerHumanNames()
|
||||
{
|
||||
return { { DockerContainer::None, "Not installed" },
|
||||
{ DockerContainer::OpenVpn, "OpenVPN" },
|
||||
{ DockerContainer::ShadowSocks, "OpenVPN over SS" },
|
||||
{ DockerContainer::Cloak, "OpenVPN over Cloak" },
|
||||
{ DockerContainer::WireGuard, "WireGuard" },
|
||||
{ DockerContainer::Awg, "AmneziaWG" },
|
||||
{ DockerContainer::Awg2, "AmneziaWG" },
|
||||
@@ -87,10 +83,6 @@ QMap<DockerContainer, QString> ContainerUtils::containerDescriptions()
|
||||
return { { DockerContainer::OpenVpn,
|
||||
QObject::tr("OpenVPN is the most popular VPN protocol, with flexible configuration options. It uses its "
|
||||
"own security protocol with SSL/TLS for key exchange.") },
|
||||
{ DockerContainer::ShadowSocks,
|
||||
QObject::tr("This protocol is no longer supported.") },
|
||||
{ DockerContainer::Cloak,
|
||||
QObject::tr("This protocol is no longer supported.") },
|
||||
{ DockerContainer::WireGuard,
|
||||
QObject::tr("WireGuard - popular VPN protocol with high performance, high speed and low power "
|
||||
"consumption.") },
|
||||
@@ -202,9 +194,6 @@ QMap<DockerContainer, QString> ContainerUtils::containerDetailedDescriptions()
|
||||
|
||||
ServiceType ContainerUtils::containerService(DockerContainer c)
|
||||
{
|
||||
if (isUnsupportedContainer(c)) {
|
||||
return ServiceType::Vpn;
|
||||
}
|
||||
return ProtocolUtils::protocolService(defaultProtocol(c));
|
||||
}
|
||||
|
||||
@@ -213,8 +202,6 @@ Proto ContainerUtils::defaultProtocol(DockerContainer c)
|
||||
switch (c) {
|
||||
case DockerContainer::None: return Proto::Unknown;
|
||||
case DockerContainer::OpenVpn: return Proto::OpenVpn;
|
||||
case DockerContainer::Cloak:
|
||||
case DockerContainer::ShadowSocks: return Proto::Unknown;
|
||||
case DockerContainer::WireGuard: return Proto::WireGuard;
|
||||
case DockerContainer::Awg2: return Proto::Awg;
|
||||
case DockerContainer::Awg: return Proto::Awg;
|
||||
@@ -265,8 +252,6 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
// macOS build using Network Extension – allow OpenVPN for parity with iOS.
|
||||
switch (c) {
|
||||
case DockerContainer::OpenVpn: return true;
|
||||
case DockerContainer::Cloak: return false;
|
||||
case DockerContainer::ShadowSocks: return false;
|
||||
case DockerContainer::WireGuard: return true;
|
||||
case DockerContainer::Awg2: return true;
|
||||
case DockerContainer::Awg: return true;
|
||||
@@ -280,7 +265,7 @@ bool ContainerUtils::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
#elif defined(Q_OS_MAC)
|
||||
switch (c) {
|
||||
case DockerContainer::WireGuard: return true;
|
||||
case DockerContainer::Ipsec: return false;
|
||||
case DockerContainer::Ipsec: return true;
|
||||
default: return true;
|
||||
}
|
||||
|
||||
@@ -351,10 +336,6 @@ int ContainerUtils::easySetupOrder(DockerContainer container)
|
||||
|
||||
bool ContainerUtils::isShareable(DockerContainer container)
|
||||
{
|
||||
if (isUnsupportedContainer(container)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (container) {
|
||||
case DockerContainer::TorWebSite: return false;
|
||||
case DockerContainer::Dns: return false;
|
||||
@@ -371,11 +352,6 @@ bool ContainerUtils::isAwgContainer(DockerContainer container)
|
||||
return container == DockerContainer::Awg || container == DockerContainer::Awg2;
|
||||
}
|
||||
|
||||
bool ContainerUtils::isUnsupportedContainer(DockerContainer container)
|
||||
{
|
||||
return container == DockerContainer::Cloak || container == DockerContainer::ShadowSocks;
|
||||
}
|
||||
|
||||
QJsonObject ContainerUtils::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
|
||||
{
|
||||
QString protocolConfigString = containerConfig.value(ProtocolUtils::protoToString(protocol))
|
||||
|
||||
@@ -45,8 +45,6 @@ namespace amnezia
|
||||
|
||||
bool isAwgContainer(DockerContainer container);
|
||||
|
||||
bool isUnsupportedContainer(DockerContainer container);
|
||||
|
||||
QJsonObject getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig);
|
||||
|
||||
int installPageOrder(DockerContainer container);
|
||||
|
||||
@@ -66,6 +66,11 @@ namespace amnezia
|
||||
OpenVpnUnknownError = 701,
|
||||
OpenVpnTapAdapterError = 702,
|
||||
AddressPoolError = 703,
|
||||
IKEv2ConfigError = 710,
|
||||
IKEv2LoadError = 711,
|
||||
IKEv2SaveError = 712,
|
||||
IKEv2ConnectError = 713,
|
||||
IKEv2TimeoutError = 714,
|
||||
|
||||
// 3rd party utils errors
|
||||
OpenSslFailed = 800,
|
||||
@@ -79,7 +84,6 @@ namespace amnezia
|
||||
ImportBackupFileUseRestoreInstead = 903,
|
||||
RestoreBackupInvalidError = 904,
|
||||
LegacyApiV1NotSupportedError = 905,
|
||||
LegacyContainerNotSupportedError = 906,
|
||||
|
||||
// Android errors
|
||||
AndroidError = 1000,
|
||||
|
||||
@@ -64,12 +64,16 @@ QString errorString(ErrorCode code) {
|
||||
case (ErrorCode::OpenVpnAdaptersInUseError): errorMessage = QObject::tr("Can't connect: another VPN connection is active"); break;
|
||||
case (ErrorCode::OpenVpnTapAdapterError): errorMessage = QObject::tr("Can't setup OpenVPN TAP network adapter"); break;
|
||||
case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
|
||||
case (ErrorCode::IKEv2ConfigError): errorMessage = QObject::tr("Can't connect: invalid IKEv2 configuration"); break;
|
||||
case (ErrorCode::IKEv2LoadError): errorMessage = QObject::tr("Can't connect: failed to load IKEv2 VPN preferences"); break;
|
||||
case (ErrorCode::IKEv2SaveError): errorMessage = QObject::tr("Can't connect: failed to save IKEv2 VPN preferences"); break;
|
||||
case (ErrorCode::IKEv2ConnectError): errorMessage = QObject::tr("Can't connect: failed to start IKEv2 connection"); break;
|
||||
case (ErrorCode::IKEv2TimeoutError): errorMessage = QObject::tr("Can't connect: IKEv2 connection timeout"); break;
|
||||
|
||||
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
|
||||
case (ErrorCode::ImportBackupFileUseRestoreInstead): errorMessage = QObject::tr("Backup files cannot be imported here. Use 'Restore from backup' instead."); break;
|
||||
case (ErrorCode::RestoreBackupInvalidError): errorMessage = QObject::tr("Backup file is corrupted or has invalid format"); break;
|
||||
case (ErrorCode::LegacyApiV1NotSupportedError): errorMessage = QObject::tr("This legacy Amnezia subscription format is no longer supported"); break;
|
||||
case (ErrorCode::LegacyContainerNotSupportedError): errorMessage = QObject::tr("This protocol is no longer supported. Please select another protocol or remove this container from the server settings."); break;
|
||||
case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
|
||||
case (ErrorCode::NoInstalledContainersError): errorMessage = QObject::tr("VPN Protocols is not installed.\n Please install VPN container at first"); break;
|
||||
|
||||
|
||||
@@ -290,6 +290,11 @@ QString Utils::tun2socksPath()
|
||||
return Utils::executable("tun2socks", true);
|
||||
}
|
||||
|
||||
QString Utils::securityPath()
|
||||
{
|
||||
return "/usr/bin/security";
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// Inspired from http://stackoverflow.com/a/15281070/1529139
|
||||
// and http://stackoverflow.com/q/40059902/1529139
|
||||
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
static QString wireguardExecPath();
|
||||
static QString certUtilPath();
|
||||
static QString tun2socksPath();
|
||||
static QString securityPath();
|
||||
|
||||
static void logException(const std::exception &e);
|
||||
static void logException(const std::exception_ptr &eptr = std::current_exception());
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
sudo docker stop $CONTAINER_NAME;\
|
||||
sudo docker rm -fv $CONTAINER_NAME;\
|
||||
sudo docker rmi $CONTAINER_NAME;
|
||||
sudo docker rmi $CONTAINER_NAME;\
|
||||
test "$REMOVE_CONTAINER_DATA" = "1" && sudo docker volume rm -f ${CONTAINER_NAME}-data 2>/dev/null || true
|
||||
|
||||
@@ -475,7 +475,8 @@ bool SubscriptionUiController::deactivateExternalDevice(const QString &serverId,
|
||||
void SubscriptionUiController::validateConfig()
|
||||
{
|
||||
const QString serverId = m_serversController->getDefaultServerId();
|
||||
if (serverId.isEmpty()) {
|
||||
if (!serverId.isEmpty() && m_serversController->isLegacyApiV1Server(serverId)) {
|
||||
emit unsupportedConnectDrawerRequested();
|
||||
emit configValidated(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
#include "amneziaApplication.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
#include "core/models/containerConfig.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
|
||||
ConnectionUiController::ConnectionUiController(ConnectionController* connectionController,
|
||||
ServersController* serversController,
|
||||
@@ -35,7 +33,7 @@ void ConnectionUiController::openConnection()
|
||||
ErrorCode errorCode = m_connectionController->openConnection(serverId);
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
notifyConnectionBlocked(errorCode);
|
||||
emit connectionErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -132,36 +130,10 @@ void ConnectionUiController::toggleConnection()
|
||||
} else if (isConnected()) {
|
||||
closeConnection();
|
||||
} else {
|
||||
const QString serverId = m_serversController->getDefaultServerId();
|
||||
if (serverId.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ErrorCode errorCode = m_connectionController->isConnectionSupported(serverId);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
notifyConnectionBlocked(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
emit prepareConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionUiController::notifyConnectionBlocked(ErrorCode errorCode)
|
||||
{
|
||||
if (errorCode == ErrorCode::LegacyApiV1NotSupportedError) {
|
||||
emit unsupportedConnectDrawerRequested();
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorCode == ErrorCode::NoInstalledContainersError) {
|
||||
emit noInstalledContainers();
|
||||
return;
|
||||
}
|
||||
|
||||
emit connectionErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
bool ConnectionUiController::isConnectionInProgress() const
|
||||
{
|
||||
return m_isConnectionInProgress;
|
||||
@@ -171,32 +143,3 @@ bool ConnectionUiController::isConnected() const
|
||||
{
|
||||
return m_isConnected;
|
||||
}
|
||||
|
||||
bool ConnectionUiController::isRevokeBlockedDuringActiveConnection(const QString &serverId, int containerIndex,
|
||||
const QString &clientId) const
|
||||
{
|
||||
if (clientId.isEmpty() || (!isConnected() && !isConnectionInProgress())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_serversController->getDefaultServerId() != serverId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<int>(m_serversController->getDefaultContainer(serverId)) != containerIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto adminConfig = m_serversController->selfHostedAdminConfig(serverId);
|
||||
if (!adminConfig.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QString connectionClientId =
|
||||
adminConfig->containerConfig(static_cast<DockerContainer>(containerIndex)).protocolConfig.clientId();
|
||||
if (connectionClientId.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return connectionClientId == clientId || connectionClientId.contains(clientId);
|
||||
}
|
||||
|
||||
@@ -35,8 +35,6 @@ public slots:
|
||||
void openConnection();
|
||||
void closeConnection();
|
||||
|
||||
bool isRevokeBlockedDuringActiveConnection(const QString &serverId, int containerIndex, const QString &clientId) const;
|
||||
|
||||
ErrorCode getLastConnectionError();
|
||||
void onConnectionStateChanged(Vpn::ConnectionState state);
|
||||
|
||||
@@ -50,12 +48,9 @@ signals:
|
||||
void connectButtonClicked();
|
||||
void preparingConfig();
|
||||
void prepareConfig();
|
||||
void unsupportedConnectDrawerRequested();
|
||||
void noInstalledContainers();
|
||||
|
||||
private:
|
||||
Vpn::ConnectionState getCurrentConnectionState();
|
||||
void notifyConnectionBlocked(ErrorCode errorCode);
|
||||
|
||||
ConnectionController* m_connectionController;
|
||||
ServersController* m_serversController;
|
||||
|
||||
@@ -75,7 +75,13 @@ InstallUiController::InstallUiController(InstallController *installController,
|
||||
m_connectionController(connectionController)
|
||||
{
|
||||
connect(m_installController, &InstallController::configValidated, this, &InstallUiController::configValidated);
|
||||
connect(m_installController, &InstallController::validationErrorOccurred, this, &InstallUiController::installationErrorOccurred);
|
||||
connect(m_installController, &InstallController::validationErrorOccurred, this, [this](ErrorCode errorCode) {
|
||||
if (errorCode == ErrorCode::NoInstalledContainersError) {
|
||||
emit noInstalledContainers();
|
||||
} else {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InstallUiController::~InstallUiController()
|
||||
@@ -211,13 +217,15 @@ void InstallUiController::scanServerForInstalledContainers(const QString &server
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
bool InstallUiController::buildContainerConfigFromModel(int containerIndex, int protocolIndex, ContainerConfig &containerConfig)
|
||||
void InstallUiController::updateContainer(const QString &serverId, int containerIndex, int protocolIndex, bool closePage)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
|
||||
Proto protocolType = static_cast<Proto>(protocolIndex);
|
||||
|
||||
|
||||
ContainerConfig containerConfig;
|
||||
containerConfig.container = container;
|
||||
|
||||
|
||||
switch (protocolType) {
|
||||
case Proto::Awg: {
|
||||
containerConfig.protocolConfig = m_awgConfigModel->getProtocolConfig();
|
||||
@@ -263,41 +271,6 @@ bool InstallUiController::buildContainerConfigFromModel(int containerIndex, int
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstallUiController::updateClientConfig(const QString &serverId, int containerIndex, int protocolIndex, bool closePage)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
Proto protocolType = static_cast<Proto>(protocolIndex);
|
||||
|
||||
ContainerConfig containerConfig;
|
||||
if (!buildContainerConfigFromModel(containerIndex, protocolIndex, containerConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_installController->updateClientConfig(serverId, container, containerConfig);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
ContainerConfig updatedConfig = m_serversController->getContainerConfig(serverId, container);
|
||||
m_protocolModel->updateModel(updatedConfig);
|
||||
updateProtocolConfigModel(serverId, static_cast<int>(container), static_cast<int>(protocolType));
|
||||
emit updateContainerFinished(tr("Settings updated successfully"), closePage);
|
||||
return;
|
||||
}
|
||||
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
void InstallUiController::updateServerConfig(const QString &serverId, int containerIndex, int protocolIndex, bool closePage)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
Proto protocolType = static_cast<Proto>(protocolIndex);
|
||||
|
||||
ContainerConfig containerConfig;
|
||||
if (!buildContainerConfigFromModel(containerIndex, protocolIndex, containerConfig)) {
|
||||
return;
|
||||
}
|
||||
ContainerConfig oldContainerConfig = m_serversController->getContainerConfig(serverId, container);
|
||||
@@ -332,13 +305,13 @@ void InstallUiController::updateServerConfig(const QString &serverId, int contai
|
||||
QFuture<ErrorCode> future =
|
||||
QtConcurrent::run([installController, serverId, container, oldConfigCopy,
|
||||
newConfigCopy]() mutable -> ErrorCode {
|
||||
return installController->updateServerConfig(serverId, container, oldConfigCopy, newConfigCopy);
|
||||
return installController->updateContainer(serverId, container, oldConfigCopy, newConfigCopy);
|
||||
});
|
||||
watcher->setFuture(future);
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_installController->updateServerConfig(serverId, container, oldContainerConfig, containerConfig);
|
||||
ErrorCode errorCode = m_installController->updateContainer(serverId, container, oldContainerConfig, containerConfig);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
ContainerConfig updatedConfig = m_serversController->getContainerConfig(serverId, container);
|
||||
|
||||
@@ -64,8 +64,7 @@ public slots:
|
||||
|
||||
void scanServerForInstalledContainers(const QString &serverId);
|
||||
|
||||
void updateServerConfig(const QString &serverId, int containerIndex, int protocolIndex, bool closePage = true);
|
||||
void updateClientConfig(const QString &serverId, int containerIndex, int protocolIndex, bool closePage = true);
|
||||
void updateContainer(const QString &serverId, int containerIndex, int protocolIndex, bool closePage = true);
|
||||
|
||||
void removeServer(const QString &serverId);
|
||||
void rebootServer(const QString &serverId);
|
||||
@@ -133,6 +132,7 @@ signals:
|
||||
void cachedProfileCleared(const QString &message);
|
||||
void apiConfigRemoved(const QString &message);
|
||||
|
||||
void noInstalledContainers();
|
||||
void configValidated(bool isValid);
|
||||
|
||||
private:
|
||||
@@ -162,8 +162,6 @@ private:
|
||||
QString m_privateKeyPassphrase;
|
||||
|
||||
void updateProtocolConfigModel(const QString &serverId, int containerIndex, int protocolIndex);
|
||||
|
||||
bool buildContainerConfigFromModel(int containerIndex, int protocolIndex, ContainerConfig &containerConfig);
|
||||
};
|
||||
|
||||
#endif // INSTALLUICONTROLLER_H
|
||||
|
||||
@@ -156,17 +156,7 @@ void ServersUiController::updateModel()
|
||||
|
||||
m_serversModel->updateModel(m_orderedServerDescriptions, defaultServerId);
|
||||
|
||||
if (!m_processedServerId.isEmpty()) {
|
||||
if (isServerFromApi(m_processedServerId)) {
|
||||
const auto &description = serverDescriptionById(m_processedServerId);
|
||||
if (description.isApiV2 && description.isCountrySelectionAvailable
|
||||
&& !description.apiAvailableCountries.isEmpty()) {
|
||||
emit updateApiCountryModel();
|
||||
}
|
||||
} else {
|
||||
updateContainersModel();
|
||||
}
|
||||
}
|
||||
updateContainersModel();
|
||||
updateDefaultServerContainersModel();
|
||||
|
||||
if (hadServersFromGatewayBefore != hasServersFromGatewayNow) {
|
||||
@@ -360,14 +350,19 @@ void ServersUiController::setProcessedServerId(const QString &serverId)
|
||||
m_processedServerId = normalizedServerId;
|
||||
|
||||
if (newIndex >= 0) {
|
||||
if (isServerFromApi(m_processedServerId)) {
|
||||
const auto &description = serverDescriptionById(m_processedServerId);
|
||||
if (description.isApiV2 && description.isCountrySelectionAvailable
|
||||
&& !description.apiAvailableCountries.isEmpty()) {
|
||||
emit updateApiCountryModel();
|
||||
updateContainersModel();
|
||||
|
||||
for (const auto &description : m_orderedServerDescriptions) {
|
||||
if (description.serverId != normalizedServerId) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
updateContainersModel();
|
||||
if (description.isApiV2) {
|
||||
if (description.isCountrySelectionAvailable && !description.apiAvailableCountries.isEmpty()) {
|
||||
emit updateApiCountryModel();
|
||||
}
|
||||
emit updateApiServicesModel();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ signals:
|
||||
void processedContainerIndexChanged(int index);
|
||||
void hasServersFromGatewayApiChanged();
|
||||
void updateApiCountryModel();
|
||||
void updateApiServicesModel();
|
||||
|
||||
public:
|
||||
void updateModel();
|
||||
|
||||
@@ -22,10 +22,12 @@
|
||||
|
||||
SettingsUiController::SettingsUiController(SettingsController* settingsController,
|
||||
ServersController* serversController,
|
||||
LanguageUiController* languageUiController,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_settingsController(settingsController),
|
||||
m_serversController(serversController)
|
||||
m_serversController(serversController),
|
||||
m_languageUiController(languageUiController)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsUiController::onNotificationStateChanged);
|
||||
@@ -155,13 +157,13 @@ void SettingsUiController::restoreAppConfigFromData(const QByteArray &data)
|
||||
{
|
||||
ErrorCode errorCode = m_settingsController->restoreAppConfigFromData(data);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
emit appLanguageChanged();
|
||||
emit appLanguageChanged(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageUiController->getCurrentLanguageIndex()));
|
||||
|
||||
bool amneziaDnsEnabled = m_settingsController->isAmneziaDnsEnabled();
|
||||
emit amneziaDnsToggled(amneziaDnsEnabled);
|
||||
|
||||
emit restoreBackupFinished();
|
||||
emit autoStartChanged();
|
||||
emit startMinimizedChanged();
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
@@ -176,7 +178,6 @@ QString SettingsUiController::getAppVersion()
|
||||
void SettingsUiController::clearSettings()
|
||||
{
|
||||
m_settingsController->clearSettings();
|
||||
emit autoStartChanged();
|
||||
emit startMinimizedChanged();
|
||||
emit resetLanguageToSystem();
|
||||
|
||||
@@ -205,8 +206,9 @@ bool SettingsUiController::isAutoStartEnabled()
|
||||
void SettingsUiController::toggleAutoStart(bool enable)
|
||||
{
|
||||
m_settingsController->toggleAutoStart(enable);
|
||||
emit autoStartChanged();
|
||||
emit startMinimizedChanged();
|
||||
if (!enable) {
|
||||
emit startMinimizedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsUiController::isStartMinimizedEnabled()
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
#include "ui/controllers/languageUiController.h"
|
||||
#include "ui/models/languageModel.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
@@ -15,6 +17,7 @@ class SettingsUiController : public QObject
|
||||
public:
|
||||
explicit SettingsUiController(SettingsController* settingsController,
|
||||
ServersController* serversController,
|
||||
LanguageUiController* languageUiController,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QString primaryDns READ getPrimaryDns WRITE setPrimaryDns NOTIFY primaryDnsChanged)
|
||||
@@ -29,7 +32,6 @@ public:
|
||||
Q_PROPERTY(bool isDevGatewayEnv READ isDevGatewayEnv WRITE toggleDevGatewayEnv NOTIFY devGatewayEnvChanged)
|
||||
|
||||
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
|
||||
Q_PROPERTY(bool autoStartEnabled READ isAutoStartEnabled NOTIFY autoStartChanged)
|
||||
Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged)
|
||||
|
||||
public slots:
|
||||
@@ -120,7 +122,7 @@ signals:
|
||||
|
||||
void loggingDisableByWatcher();
|
||||
|
||||
void appLanguageChanged();
|
||||
void appLanguageChanged(const LanguageSettings::AvailableLanguageEnum language);
|
||||
void resetLanguageToSystem();
|
||||
|
||||
void onNotificationStateChanged();
|
||||
@@ -133,12 +135,12 @@ signals:
|
||||
void activityResumed();
|
||||
|
||||
void isHomeAdLabelVisibleChanged(bool visible);
|
||||
void autoStartChanged();
|
||||
void startMinimizedChanged();
|
||||
|
||||
private:
|
||||
SettingsController* m_settingsController;
|
||||
ServersController* m_serversController;
|
||||
LanguageUiController* m_languageUiController;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
|
||||
switch (role) {
|
||||
case SubscriptionStatusRole: {
|
||||
if (m_accountInfoData.configType == serverConfigUtils::ConfigType::AmneziaFreeV3) {
|
||||
return QStringLiteral("<p><a style=\"color: #28c840;\">%1</a>").arg(tr("Active"));
|
||||
return tr("Active");
|
||||
}
|
||||
|
||||
return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate)
|
||||
|
||||
@@ -27,7 +27,6 @@ QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
|
||||
auto userData = client.value(configKey::userData).toObject();
|
||||
|
||||
switch (role) {
|
||||
case ClientIdRole: return client.value(configKey::clientId).toString();
|
||||
case ClientNameRole: return userData.value(configKey::clientName).toString();
|
||||
case CreationDateRole: return userData.value(configKey::creationDate).toString();
|
||||
case LatestHandshakeRole: return userData.value(configKey::latestHandshake).toString();
|
||||
@@ -63,7 +62,6 @@ void ClientManagementModel::updateClientName(int row, const QString &newName)
|
||||
QHash<int, QByteArray> ClientManagementModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[ClientIdRole] = "clientId";
|
||||
roles[ClientNameRole] = "clientName";
|
||||
roles[CreationDateRole] = "creationDate";
|
||||
roles[LatestHandshakeRole] = "latestHandshake";
|
||||
|
||||
@@ -10,8 +10,7 @@ class ClientManagementModel : public QAbstractListModel
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
ClientIdRole = Qt::UserRole + 1,
|
||||
ClientNameRole,
|
||||
ClientNameRole = Qt::UserRole + 1,
|
||||
CreationDateRole,
|
||||
LatestHandshakeRole,
|
||||
DataReceivedRole,
|
||||
|
||||
@@ -23,10 +23,6 @@ public:
|
||||
Q_INVOKABLE int containerFromString(const QString &container) const {
|
||||
return static_cast<int>(amnezia::ContainerUtils::containerFromString(container));
|
||||
}
|
||||
|
||||
Q_INVOKABLE bool isUnsupportedContainer(int containerIndex) const {
|
||||
return amnezia::ContainerUtils::isUnsupportedContainer(static_cast<amnezia::DockerContainer>(containerIndex));
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CONTAINERPROPS_H
|
||||
|
||||
@@ -67,7 +67,6 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
|
||||
case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_processedContainerIndex);
|
||||
case IsSupportedRole: return ContainerUtils::isSupportedByCurrentPlatform(container);
|
||||
case IsShareableRole: return ContainerUtils::isShareable(container);
|
||||
case IsUnsupportedContainerRole: return ContainerUtils::isUnsupportedContainer(container);
|
||||
case IsVpnContainerRole: return ContainerUtils::containerService(container) == ServiceType::Vpn;
|
||||
case IsServiceContainerRole: return ContainerUtils::containerService(container) == ServiceType::Other;
|
||||
case IsIpsecRole: return container == DockerContainer::Ipsec;
|
||||
@@ -143,8 +142,7 @@ bool ContainersModel::hasInstalledProtocols()
|
||||
|
||||
bool ContainersModel::isInstallationAllowed(DockerContainer container)
|
||||
{
|
||||
return container != DockerContainer::Awg
|
||||
&& !ContainerUtils::isUnsupportedContainer(container);
|
||||
return container != DockerContainer::Awg;
|
||||
}
|
||||
|
||||
void ContainersModel::openContainerSettings(int containerIndex)
|
||||
@@ -178,7 +176,6 @@ QHash<int, QByteArray> ContainersModel::roleNames() const
|
||||
roles[IsCurrentlyProcessedRole] = "isCurrentlyProcessed";
|
||||
roles[IsSupportedRole] = "isSupported";
|
||||
roles[IsShareableRole] = "isShareable";
|
||||
roles[IsUnsupportedContainerRole] = "isUnsupportedContainer";
|
||||
roles[IsInstallationAllowedRole] = "isInstallationAllowed";
|
||||
roles[InstallPageOrderRole] = "installPageOrder";
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@ public:
|
||||
IsSupportedRole,
|
||||
IsShareableRole,
|
||||
|
||||
IsUnsupportedContainerRole,
|
||||
|
||||
InstallPageOrderRole,
|
||||
|
||||
// Container type check roles
|
||||
|
||||
@@ -56,17 +56,14 @@ ListViewType {
|
||||
return
|
||||
}
|
||||
|
||||
var containerIndex = proxyDefaultServerContainersModel.mapToSource(index)
|
||||
|
||||
if (!isInstalled) {
|
||||
ServersUiController.processedContainerIndex = containerIndex
|
||||
if (checked) {
|
||||
containersDropDown.closeTriggered()
|
||||
ServersUiController.setDefaultContainer(ServersUiController.defaultServerId, proxyDefaultServerContainersModel.mapToSource(index))
|
||||
} else {
|
||||
ServersUiController.processedContainerIndex = proxyDefaultServerContainersModel.mapToSource(index)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
|
||||
containersDropDown.closeTriggered()
|
||||
return
|
||||
}
|
||||
|
||||
containersDropDown.closeTriggered()
|
||||
ServersUiController.setDefaultContainer(ServersUiController.defaultServerId, containerIndex)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
||||
@@ -5,6 +5,7 @@ import QtQuick.Layouts
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
@@ -6,36 +6,8 @@ Menu {
|
||||
|
||||
popupType: Popup.Native
|
||||
|
||||
property Item inputBlocker: null
|
||||
|
||||
Component {
|
||||
id: inputBlockerComponent
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
preventStealing: true
|
||||
}
|
||||
}
|
||||
|
||||
onAboutToShow: {
|
||||
if (!textObj || !textObj.window) {
|
||||
return
|
||||
}
|
||||
|
||||
const contentItem = textObj.window.contentItem
|
||||
if (!inputBlocker) {
|
||||
inputBlocker = inputBlockerComponent.createObject(contentItem)
|
||||
} else {
|
||||
inputBlocker.parent = contentItem
|
||||
}
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
if (inputBlocker) {
|
||||
inputBlocker.destroy()
|
||||
inputBlocker = null
|
||||
}
|
||||
}
|
||||
onAboutToShow: blocker.enabled = true
|
||||
onClosed: blocker.enabled = false
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("C&ut")
|
||||
@@ -59,4 +31,11 @@ Menu {
|
||||
enabled: textObj.length > 0
|
||||
onTriggered: textObj.selectAll()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: blocker
|
||||
z: 2
|
||||
enabled: false
|
||||
preventStealing: true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ PageType {
|
||||
|
||||
filters: [
|
||||
ValueFilter {
|
||||
roleName: "serverId"
|
||||
value: ServersUiController.processedServerId
|
||||
roleName: "isCurrentlyProcessed"
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -440,7 +440,8 @@ PageType {
|
||||
return
|
||||
}
|
||||
|
||||
InstallController.updateClientConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Awg)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Awg)
|
||||
}
|
||||
|
||||
var noButtonFunction = function() {}
|
||||
|
||||
@@ -561,7 +561,7 @@ PageType {
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Awg)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Awg)
|
||||
}
|
||||
|
||||
var noButtonFunction = function() {}
|
||||
|
||||
@@ -434,7 +434,7 @@ PageType {
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.OpenVpn)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.OpenVpn)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
|
||||
@@ -128,7 +128,8 @@ PageType {
|
||||
return
|
||||
}
|
||||
|
||||
InstallController.updateClientConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.WireGuard)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.WireGuard)
|
||||
}
|
||||
var noButtonFunction = function() {}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
|
||||
@@ -129,7 +129,7 @@ PageType {
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.WireGuard)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.WireGuard)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
|
||||
@@ -112,7 +112,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function () {
|
||||
if (typeof GC !== "undefined" && !GC.isMobile()) {
|
||||
|
||||
@@ -279,7 +279,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function () {
|
||||
if (typeof GC !== "undefined" && !GC.isMobile()) {
|
||||
|
||||
@@ -213,7 +213,7 @@ PageType {
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) saveButton.forceActiveFocus()
|
||||
|
||||
@@ -742,7 +742,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function () {
|
||||
if (typeof GC !== "undefined" && !GC.isMobile()) {
|
||||
|
||||
@@ -95,7 +95,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function () {
|
||||
if (typeof GC !== "undefined" && !GC.isMobile()) {
|
||||
|
||||
@@ -211,7 +211,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function () {
|
||||
if (typeof GC !== "undefined" && !GC.isMobile()) {
|
||||
|
||||
@@ -208,7 +208,7 @@ PageType {
|
||||
return
|
||||
}
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Xray)
|
||||
}
|
||||
var noButtonFunction = function () {
|
||||
if (typeof GC !== "undefined" && !GC.isMobile()) {
|
||||
|
||||
@@ -179,7 +179,7 @@ PageType {
|
||||
function mtProxyScheduleUpdate(closePage) {
|
||||
var cp = closePage === undefined ? false : closePage
|
||||
Qt.callLater(function () {
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.MtProxy, cp)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.MtProxy, cp)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -285,7 +285,7 @@ PageType {
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Socks5Proxy)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Socks5Proxy)
|
||||
tempPort = portTextField.textField.text
|
||||
tempUsername = usernameTextField.textField.text
|
||||
tempPassword = passwordTextField.textField.text
|
||||
|
||||
@@ -154,7 +154,7 @@ PageType {
|
||||
function telemtScheduleUpdate(closePage) {
|
||||
var cp = closePage === undefined ? false : closePage
|
||||
Qt.callLater(function () {
|
||||
InstallController.updateServerConfig(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Telemt, cp)
|
||||
InstallController.updateContainer(ServersUiController.processedServerId, ServersUiController.processedContainerIndex, ProtocolEnum.Telemt, cp)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -100,12 +100,6 @@ PageType {
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
textFormat: Text.RichText
|
||||
text: qsTr("Use <a href=\"https://www.torproject.org/download/\" style=\"color: #FBB26A;\">Tor Browser</a> to open this URL.")
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
|
||||
@@ -30,16 +30,6 @@ PageType {
|
||||
root.isInAppPurchase = ApiAccountInfoModel.data("isInAppPurchase")
|
||||
}
|
||||
|
||||
function selectConnectionCountry(countryIndex, countryCode, countryName) {
|
||||
if (countryIndex === ApiCountryModel.currentIndex) {
|
||||
return
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(true)
|
||||
SubscriptionUiController.updateServiceFromGateway(ServersUiController.processedServerId, countryCode, countryName)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.updateSubscriptionState()
|
||||
}
|
||||
@@ -93,7 +83,7 @@ PageType {
|
||||
|
||||
model: ApiCountryModel
|
||||
|
||||
currentIndex: ApiCountryModel.currentIndex
|
||||
currentIndex: 0
|
||||
|
||||
ButtonGroup {
|
||||
id: containersRadioButtonGroup
|
||||
@@ -214,7 +204,15 @@ PageType {
|
||||
return
|
||||
}
|
||||
|
||||
root.selectConnectionCountry(index, countryCode, countryName)
|
||||
if (index !== ApiCountryModel.currentIndex) {
|
||||
PageController.showBusyIndicator(true)
|
||||
var prevIndex = ApiCountryModel.currentIndex
|
||||
ApiCountryModel.currentIndex = index
|
||||
if (!SubscriptionUiController.updateServiceFromGateway(ServersUiController.processedServerId, countryCode, countryName)) {
|
||||
ApiCountryModel.currentIndex = prevIndex
|
||||
}
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
|
||||
@@ -108,9 +108,9 @@ PageType {
|
||||
text: qsTr("Auto start")
|
||||
descriptionText: qsTr("Launch the application every time the device is starts")
|
||||
|
||||
checked: SettingsController.autoStartEnabled
|
||||
checked: SettingsController.isAutoStartEnabled()
|
||||
onToggled: function() {
|
||||
if (checked !== SettingsController.autoStartEnabled) {
|
||||
if (checked !== SettingsController.isAutoStartEnabled()) {
|
||||
SettingsController.toggleAutoStart(checked)
|
||||
}
|
||||
}
|
||||
@@ -154,10 +154,10 @@ PageType {
|
||||
text: qsTr("Start minimized")
|
||||
descriptionText: qsTr("Launch application minimized (works with autostart option turned on)")
|
||||
|
||||
enabled: SettingsController.autoStartEnabled
|
||||
enabled: SettingsController.isAutoStartEnabled()
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
|
||||
checked: SettingsController.autoStartEnabled && SettingsController.startMinimized
|
||||
checked: SettingsController.isAutoStartEnabled() && SettingsController.startMinimized
|
||||
onToggled: function() {
|
||||
if (checked !== SettingsController.startMinimized) {
|
||||
SettingsController.toggleStartMinimized(checked)
|
||||
@@ -166,7 +166,7 @@ PageType {
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: !GC.isMobile() && ServersUiController.hasServersFromGatewayApi
|
||||
visible: !GC.isMobile()
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
|
||||
@@ -36,6 +36,17 @@ PageType {
|
||||
function onRebootServerFinished(finishedMessage) {
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
|
||||
function onRemoveAllContainersFinished(finishedMessage) {
|
||||
PageController.closePage() // close deInstalling page
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
|
||||
function onRemoveContainerFinished(finishedMessage) {
|
||||
PageController.closePage() // close deInstalling page
|
||||
PageController.closePage() // close page with remove button
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -17,8 +17,7 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property bool isUnsupportedContainer: ContainerProps.isUnsupportedContainer(ServersUiController.processedContainerIndex)
|
||||
property bool isClearCacheVisible: !isUnsupportedContainer && ServersUiController.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ServersUiController.processedContainerIndex)
|
||||
property bool isClearCacheVisible: ServersUiController.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ServersUiController.processedContainerIndex)
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
@@ -53,11 +52,10 @@ PageType {
|
||||
Layout.bottomMargin: 32
|
||||
|
||||
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
|
||||
descriptionText: root.isUnsupportedContainer ? qsTr("This protocol is no longer supported.") : ""
|
||||
}
|
||||
}
|
||||
|
||||
model: root.isUnsupportedContainer ? null : ProtocolsModel
|
||||
model: ProtocolsModel
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
@@ -29,10 +29,6 @@ PageType {
|
||||
ValueFilter {
|
||||
roleName: "isInstallationAllowed"
|
||||
value: true
|
||||
},
|
||||
ValueFilter {
|
||||
roleName: "isUnsupportedContainer"
|
||||
value: false
|
||||
}
|
||||
]
|
||||
sorters: RoleSorter {
|
||||
|
||||
@@ -382,10 +382,6 @@ PageType {
|
||||
ValueFilter {
|
||||
roleName: "isShareable"
|
||||
value: true
|
||||
},
|
||||
ValueFilter {
|
||||
roleName: "isUnsupportedContainer"
|
||||
value: false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -400,19 +396,9 @@ PageType {
|
||||
target: serverSelector
|
||||
|
||||
function onServerSelectorIndexChanged() {
|
||||
if (!proxyContainersModel.count) {
|
||||
root.shareButtonEnabled = false
|
||||
return
|
||||
}
|
||||
|
||||
var defaultContainer = proxyContainersModel.mapFromSource(
|
||||
ServersUiController.serverDefaultContainer(ServersUiController.processedServerId))
|
||||
if (defaultContainer < 0) {
|
||||
defaultContainer = 0
|
||||
}
|
||||
|
||||
var defaultContainer = proxyContainersModel.mapFromSource(ServersUiController.serverDefaultContainer(ServersUiController.processedServerId))
|
||||
containerSelectorListView.selectedIndex = defaultContainer
|
||||
containerSelectorListView.positionViewAtIndex(defaultContainer, ListView.Beginning)
|
||||
containerSelectorListView.positionViewAtIndex(selectedIndex, ListView.Beginning)
|
||||
containerSelectorListView.triggerCurrentItem()
|
||||
}
|
||||
}
|
||||
@@ -851,10 +837,11 @@ PageType {
|
||||
var noButtonFunction = function() {
|
||||
}
|
||||
|
||||
if (ConnectionController.isRevokeBlockedDuringActiveConnection(
|
||||
ServersUiController.processedServerId,
|
||||
ServersUiController.processedContainerIndex,
|
||||
clientId)) {
|
||||
var isActiveConfigForCurrentClient = ServersUiController.isDefaultServerCurrentlyProcessed()
|
||||
&& ServersUiController.serverDefaultContainer(ServersUiController.defaultServerId) === ServersUiController.processedContainerIndex
|
||||
|
||||
if ((ConnectionController.isConnectionInProgress || ConnectionController.isConnected)
|
||||
&& isActiveConfigForCurrentClient) {
|
||||
PageController.showNotificationMessage("Unable to revoke current config during active connection")
|
||||
} else {
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
|
||||
@@ -105,19 +105,6 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
objectName: "connectionControllerConnections"
|
||||
|
||||
target: ConnectionController
|
||||
|
||||
function onNoInstalledContainers() {
|
||||
PageController.setTriggeredByConnectButton(true)
|
||||
|
||||
ServersUiController.setProcessedServerId(ServersUiController.defaultServerId)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardEasy)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
objectName: "installControllerConnections"
|
||||
|
||||
@@ -166,19 +153,11 @@ PageType {
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
|
||||
function onRemoveAllContainersFinished(finishedMessage) {
|
||||
if (tabBarStackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageDeinstalling)) {
|
||||
PageController.closePage()
|
||||
}
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
function onNoInstalledContainers() {
|
||||
PageController.setTriggeredByConnectButton(true)
|
||||
|
||||
function onRemoveContainerFinished(finishedMessage) {
|
||||
if (tabBarStackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageDeinstalling)) {
|
||||
PageController.closePage()
|
||||
}
|
||||
PageController.closePage()
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
ServersUiController.setProcessedServerId(ServersUiController.defaultServerId)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardEasy)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,8 +234,6 @@ Window {
|
||||
DrawerType2 {
|
||||
id: privateKeyPassphraseDrawer
|
||||
|
||||
property bool isCloseByUser: false
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: root.height * 0.35 + PageController.safeAreaBottomMargin + PageController.imeHeight
|
||||
|
||||
@@ -255,11 +253,6 @@ Window {
|
||||
}
|
||||
|
||||
function onAboutToHide() {
|
||||
if (privateKeyPassphraseDrawer.isCloseByUser === false) {
|
||||
privateKeyPassphraseDrawer.isCloseByUser = true
|
||||
PageController.passphraseRequestDrawerClosed("")
|
||||
}
|
||||
|
||||
if (passphrase.textField.text !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
}
|
||||
@@ -300,7 +293,6 @@ Window {
|
||||
text: qsTr("Save")
|
||||
|
||||
clickedFunc: function() {
|
||||
privateKeyPassphraseDrawer.isCloseByUser = true
|
||||
privateKeyPassphraseDrawer.closeTriggered()
|
||||
PageController.passphraseRequestDrawerClosed(passphrase.textField.text)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ enum PermittedProcess {
|
||||
OpenVPN,
|
||||
Wireguard,
|
||||
Tun2Socks,
|
||||
CertUtil
|
||||
CertUtil,
|
||||
Security
|
||||
};
|
||||
|
||||
inline QString permittedProcessPath(PermittedProcess pid)
|
||||
@@ -29,6 +30,8 @@ inline QString permittedProcessPath(PermittedProcess pid)
|
||||
return Utils::certUtilPath();
|
||||
case PermittedProcess::Tun2Socks:
|
||||
return Utils::tun2socksPath();
|
||||
case PermittedProcess::Security:
|
||||
return Utils::securityPath();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ bool KillSwitch::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIn
|
||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("100.blockAll"), blockAll);
|
||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("110.allowNets"), allowNets);
|
||||
LinuxFirewall::updateAllowNets(allownets);
|
||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("120.blockNets"), blockNets);
|
||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("120.blockNets"), blockAll);
|
||||
LinuxFirewall::updateBlockNets(blocknets);
|
||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("130.allowMarkedXray"), true);
|
||||
LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("200.allowVPN"), true);
|
||||
|
||||
Reference in New Issue
Block a user