Compare commits

...

19 Commits

Author SHA1 Message Date
Aleksandar Dimov 477a2f3591 fix macOS command 2024-04-01 18:23:35 +02:00
Aleksandar Dimov 3c3870f270 Merge branch 'dev' into feature/add-uninstaller-checkbox 2024-04-01 18:10:11 +02:00
Nethius a6ca1b12da moved protocol config generation to VpnConfigirationsController (#665)
Moved protocol config generation to VpnConfigurationsController
2024-04-01 14:20:02 +01:00
pokamest 82a9e7e27d Merge pull request #720 from amnezia-vpn/feature/app-split-tunneling-page-home
Added app split tunneling on home page
2024-04-01 13:33:10 +01:00
vladimir.kuznetsov f5301e1315 added app split tunneling on home page 2024-04-01 17:07:33 +05:00
Nethius adab30fc81 feature/app-split-tunneling (#702)
App Split Tunneling for Windows and Android
2024-04-01 12:45:00 +01:00
pokamest e7bd24f065 Merge pull request #718 from amnezia-vpn/bugfix/cancel-button-on-install-page
fixed display of cancel button on install/uninstall pages
2024-03-31 16:03:32 +01:00
pokamest 2ec448ba13 Merge pull request #717 from amnezia-vpn/feature/page-home-drawer
changed the way the drawer is displayed on the pageHome
2024-03-31 12:15:21 +01:00
albexk c6e6f2ae84 Add a function that minimizes the Android app (#692)
Add a function that minimizes the Android app
2024-03-31 12:14:12 +01:00
vladimir.kuznetsov 45de951897 changed the way the drawer is displayed on the pageHome 2024-03-30 16:10:37 +05:00
Aleksandar Dimov ee7ac389a4 add minor improvements 2024-03-27 23:41:28 +01:00
Aleksandar Dimov bd414191e9 remove onNextButtonClicked 2024-03-27 23:38:39 +01:00
Aleksandar Dimov 4eebb6673a Merge branch 'dev' into feature/add-uninstaller-checkbox 2024-03-27 22:38:16 +01:00
Aleksandar Dimov a36585d035 update linux command 2024-03-22 19:51:45 +01:00
Aleksandar Dimov c4de28bb3b refactor 2024-03-22 00:19:53 +01:00
Aleksandar Dimov dcf1989414 fix linux command 2024-03-21 22:55:32 +01:00
Aleksandar Dimov bd2288c239 Merge branch 'dev' into feature/add-uninstaller-checkbox 2024-03-21 22:16:49 +01:00
Aleksandar Dimov 781dba61f1 Merge branch 'dev' into feature/add-uninstaller-checkbox 2024-03-20 20:10:35 +01:00
Aleksandar Dimov 926d3643a4 add checkbox on uninstaller 2024-03-19 22:54:51 +01:00
121 changed files with 2702 additions and 1677 deletions
+4
View File
@@ -119,7 +119,9 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.h ${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.h
${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.h ${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.h
${CMAKE_CURRENT_LIST_DIR}/core/server_defs.h ${CMAKE_CURRENT_LIST_DIR}/core/server_defs.h
${CMAKE_CURRENT_LIST_DIR}/core/controllers/apiController.h
${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.h ${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.h
${CMAKE_CURRENT_LIST_DIR}/core/controllers/vpnConfigurationController.h
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h ${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h ${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h ${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.h
@@ -159,7 +161,9 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.cpp ${CMAKE_CURRENT_LIST_DIR}/core/errorstrings.cpp
${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.cpp ${CMAKE_CURRENT_LIST_DIR}/core/scripts_registry.cpp
${CMAKE_CURRENT_LIST_DIR}/core/server_defs.cpp ${CMAKE_CURRENT_LIST_DIR}/core/server_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/core/controllers/apiController.cpp
${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.cpp ${CMAKE_CURRENT_LIST_DIR}/core/controllers/serverController.cpp
${CMAKE_CURRENT_LIST_DIR}/core/controllers/vpnConfigurationController.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp ${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp ${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp ${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
+37 -43
View File
@@ -14,10 +14,12 @@
#include "logger.h" #include "logger.h"
#include "version.h" #include "version.h"
#include "ui/models/installedAppsModel.h"
#include "platforms/ios/QRCodeReaderBase.h" #include "platforms/ios/QRCodeReaderBase.h"
#if defined(Q_OS_ANDROID) #if defined(Q_OS_ANDROID)
#include "platforms/android/android_controller.h" #include "platforms/android/android_controller.h"
#include "core/installedAppsImageProvider.h"
#endif #endif
#include "protocols/qml_register_protocols.h" #include "protocols/qml_register_protocols.h"
@@ -82,8 +84,7 @@ void AmneziaApplication::init()
m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance()); m_engine->rootContext()->setContextProperty("Debug", &Logger::Instance());
m_configurator = std::shared_ptr<VpnConfigurator>(new VpnConfigurator(m_settings, this)); m_vpnConnection.reset(new VpnConnection(m_settings));
m_vpnConnection.reset(new VpnConnection(m_settings, m_configurator));
m_vpnConnection->moveToThread(&m_vpnConnectionThread); m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start(); m_vpnConnectionThread.start();
@@ -96,18 +97,16 @@ void AmneziaApplication::init()
qFatal("Android logging initialization failed"); qFatal("Android logging initialization failed");
} }
AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs()); AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs());
connect(m_settings.get(), &Settings::saveLogsChanged, connect(m_settings.get(), &Settings::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
AndroidController::instance(), &AndroidController::setSaveLogs);
AndroidController::instance()->setScreenshotsEnabled(m_settings->isScreenshotsEnabled()); AndroidController::instance()->setScreenshotsEnabled(m_settings->isScreenshotsEnabled());
connect(m_settings.get(), &Settings::screenshotsEnabledChanged, connect(m_settings.get(), &Settings::screenshotsEnabledChanged, AndroidController::instance(),
AndroidController::instance(), &AndroidController::setScreenshotsEnabled); &AndroidController::setScreenshotsEnabled);
connect(m_settings.get(), &Settings::serverRemoved, connect(m_settings.get(), &Settings::serverRemoved, AndroidController::instance(),
AndroidController::instance(), &AndroidController::resetLastServer); &AndroidController::resetLastServer);
connect(m_settings.get(), &Settings::settingsCleared, connect(m_settings.get(), &Settings::settingsCleared, []() { AndroidController::instance()->resetLastServer(-1); });
[](){ AndroidController::instance()->resetLastServer(-1); });
connect(AndroidController::instance(), &AndroidController::initConnectionState, this, connect(AndroidController::instance(), &AndroidController::initConnectionState, this,
[this](Vpn::ConnectionState state) { [this](Vpn::ConnectionState state) {
@@ -124,8 +123,12 @@ void AmneziaApplication::init()
m_importController->extractConfigFromData(data); m_importController->extractConfigFromData(data);
m_pageController->goToPageViewConfig(); m_pageController->goToPageViewConfig();
}); });
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
#endif #endif
#ifdef Q_OS_IOS #ifdef Q_OS_IOS
IosController::Instance()->initialize(); IosController::Instance()->initialize();
connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) { connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
@@ -140,13 +143,10 @@ void AmneziaApplication::init()
m_settingsController->importBackupFromOutside(filePath); m_settingsController->importBackupFromOutside(filePath);
}); });
QTimer::singleShot(0, this, [this](){ QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled());
});
connect(m_settings.get(), &Settings::screenshotsEnabledChanged, [](bool enabled) { connect(m_settings.get(), &Settings::screenshotsEnabledChanged,
AmneziaVPN::toggleScreenshots(enabled); [](bool enabled) { AmneziaVPN::toggleScreenshots(enabled); });
});
#endif #endif
m_notificationHandler.reset(NotificationHandler::create(nullptr)); m_notificationHandler.reset(NotificationHandler::create(nullptr));
@@ -234,7 +234,8 @@ void AmneziaApplication::registerTypes()
qmlRegisterSingletonType(QUrl("qrc:/ui/qml/Filters/ContainersModelFilters.qml"), "ContainersModelFilters", 1, 0, qmlRegisterSingletonType(QUrl("qrc:/ui/qml/Filters/ContainersModelFilters.qml"), "ContainersModelFilters", 1, 0,
"ContainersModelFilters"); "ContainersModelFilters");
// qmlRegisterType<InstalledAppsModel>("InstalledAppsModel", 1, 0, "InstalledAppsModel");
Vpn::declareQmlVpnConnectionStateEnum(); Vpn::declareQmlVpnConnectionStateEnum();
PageLoader::declareQmlPageEnum(); PageLoader::declareQmlPageEnum();
} }
@@ -325,6 +326,9 @@ void AmneziaApplication::initModels()
m_sitesModel.reset(new SitesModel(m_settings, this)); m_sitesModel.reset(new SitesModel(m_settings, this));
m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get()); m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
m_appSplitTunnelingModel.reset(new AppSplitTunnelingModel(m_settings, this));
m_engine->rootContext()->setContextProperty("AppSplitTunnelingModel", m_appSplitTunnelingModel.get());
m_protocolsModel.reset(new ProtocolsModel(m_settings, this)); m_protocolsModel.reset(new ProtocolsModel(m_settings, this));
m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get()); m_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
@@ -358,28 +362,30 @@ void AmneziaApplication::initModels()
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get()); m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(), connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
&ServersModel::clearCachedProfile); &ServersModel::clearCachedProfile);
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this,
[this](const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials) {
m_serversModel->reloadDefaultServerContainerConfig();
m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
emit m_configurator->clientModelUpdated();
});
} }
void AmneziaApplication::initControllers() void AmneziaApplication::initControllers()
{ {
m_connectionController.reset(new ConnectionController(m_serversModel, m_containersModel, m_vpnConnection)); m_connectionController.reset(new ConnectionController(m_serversModel, m_containersModel, m_clientManagementModel,
m_vpnConnection, m_settings));
m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get()); m_engine->rootContext()->setContextProperty("ConnectionController", m_connectionController.get());
connect(m_connectionController.get(), &ConnectionController::connectionErrorOccurred, this,
[this](const QString &errorMessage) {
emit m_pageController->showErrorMessage(errorMessage);
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_connectionController.get(), &ConnectionController::connectButtonClicked, m_connectionController.get(),
&ConnectionController::toggleConnection, Qt::QueuedConnection);
connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(), connect(this, &AmneziaApplication::translationsUpdated, m_connectionController.get(),
&ConnectionController::onTranslationsUpdated); &ConnectionController::onTranslationsUpdated);
m_pageController.reset(new PageController(m_serversModel, m_settings)); m_pageController.reset(new PageController(m_serversModel, m_settings));
m_engine->rootContext()->setContextProperty("PageController", m_pageController.get()); m_engine->rootContext()->setContextProperty("PageController", m_pageController.get());
m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel, m_settings)); m_installController.reset(new InstallController(m_serversModel, m_containersModel, m_protocolsModel,
m_clientManagementModel, m_settings));
m_engine->rootContext()->setContextProperty("InstallController", m_installController.get()); m_engine->rootContext()->setContextProperty("InstallController", m_installController.get());
connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(), connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
&PageController::showPassphraseRequestDrawer); &PageController::showPassphraseRequestDrawer);
@@ -391,8 +397,7 @@ void AmneziaApplication::initControllers()
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings)); m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get()); m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings));
m_settings, m_configurator));
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get()); m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
m_settingsController.reset( m_settingsController.reset(
@@ -407,20 +412,9 @@ void AmneziaApplication::initControllers()
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel)); m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get()); m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
m_appSplitTunnelingController.reset(new AppSplitTunnelingController(m_settings, m_appSplitTunnelingModel));
m_engine->rootContext()->setContextProperty("AppSplitTunnelingController", m_appSplitTunnelingController.get());
m_systemController.reset(new SystemController(m_settings)); m_systemController.reset(new SystemController(m_settings));
m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get()); m_engine->rootContext()->setContextProperty("SystemController", m_systemController.get());
m_apiController.reset(new ApiController(m_serversModel, m_containersModel));
m_engine->rootContext()->setContextProperty("ApiController", m_apiController.get());
connect(m_apiController.get(), &ApiController::updateStarted, this,
[this]() { emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Connecting); });
connect(m_apiController.get(), &ApiController::errorOccurred, this, [this](const QString &errorMessage) {
if (m_connectionController->isConnectionInProgress()) {
emit m_pageController->showErrorMessage(errorMessage);
}
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
});
connect(m_apiController.get(), &ApiController::updateFinished, m_connectionController.get(),
&ConnectionController::toggleConnection);
} }
+5 -3
View File
@@ -14,7 +14,7 @@
#include "settings.h" #include "settings.h"
#include "vpnconnection.h" #include "vpnconnection.h"
#include "configurators/vpn_configurator.h" #include "core/controllers/apiController.h"
#include "ui/controllers/connectionController.h" #include "ui/controllers/connectionController.h"
#include "ui/controllers/exportController.h" #include "ui/controllers/exportController.h"
@@ -24,7 +24,7 @@
#include "ui/controllers/settingsController.h" #include "ui/controllers/settingsController.h"
#include "ui/controllers/sitesController.h" #include "ui/controllers/sitesController.h"
#include "ui/controllers/systemController.h" #include "ui/controllers/systemController.h"
#include "ui/controllers/apiController.h" #include "ui/controllers/appSplitTunnelingController.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/languageModel.h" #include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h" #include "ui/models/protocols/cloakConfigModel.h"
@@ -42,6 +42,7 @@
#include "ui/models/services/sftpConfigModel.h" #include "ui/models/services/sftpConfigModel.h"
#include "ui/models/sites_model.h" #include "ui/models/sites_model.h"
#include "ui/models/clientManagementModel.h" #include "ui/models/clientManagementModel.h"
#include "ui/models/appSplitTunnelingModel.h"
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance())) #define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
@@ -84,7 +85,6 @@ private:
QQmlApplicationEngine *m_engine {}; QQmlApplicationEngine *m_engine {};
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
QSharedPointer<ContainerProps> m_containerProps; QSharedPointer<ContainerProps> m_containerProps;
QSharedPointer<ProtocolProps> m_protocolProps; QSharedPointer<ProtocolProps> m_protocolProps;
@@ -98,6 +98,7 @@ private:
QSharedPointer<LanguageModel> m_languageModel; QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel; QSharedPointer<ProtocolsModel> m_protocolsModel;
QSharedPointer<SitesModel> m_sitesModel; QSharedPointer<SitesModel> m_sitesModel;
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel; QSharedPointer<ClientManagementModel> m_clientManagementModel;
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel; QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
@@ -125,6 +126,7 @@ private:
QScopedPointer<SitesController> m_sitesController; QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController; QScopedPointer<SystemController> m_systemController;
QScopedPointer<ApiController> m_apiController; QScopedPointer<ApiController> m_apiController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
}; };
#endif // AMNEZIA_APPLICATION_H #endif // AMNEZIA_APPLICATION_H
+1 -3
View File
@@ -24,9 +24,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
<!-- Enable when VPN-per-app mode will be implemented -->
<!-- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> -->
<application <application
android:name=".AmneziaApplication" android:name=".AmneziaApplication"
@@ -66,6 +66,7 @@ class Awg : Wireguard() {
return AwgConfig.build { return AwgConfig.build {
configWireguard(configData, configDataJson) configWireguard(configData, configDataJson)
configSplitTunneling(config) configSplitTunneling(config)
configAppSplitTunneling(config)
configData["Jc"]?.let { setJc(it.toInt()) } configData["Jc"]?.let { setJc(it.toInt()) }
configData["Jmin"]?.let { setJmin(it.toInt()) } configData["Jmin"]?.let { setJmin(it.toInt()) }
configData["Jmax"]?.let { setJmax(it.toInt()) } configData["Jmax"]?.let { setJmax(it.toInt()) }
@@ -79,6 +79,7 @@ open class OpenVpn : Protocol() {
} }
configPluggableTransport(configBuilder, config) configPluggableTransport(configBuilder, config)
configBuilder.configSplitTunneling(config) configBuilder.configSplitTunneling(config)
configBuilder.configAppSplitTunneling(config)
scope.launch { scope.launch {
val status = client.connect() val status = client.connect()
@@ -64,6 +64,22 @@ abstract class Protocol {
} }
} }
protected fun ProtocolConfig.Builder.configAppSplitTunneling(config: JSONObject) {
val splitTunnelType = config.optInt("appSplitTunnelType")
if (splitTunnelType == SPLIT_TUNNEL_DISABLE) return
val splitTunnelApps = config.getJSONArray("splitTunnelApps")
val appHandlerFunc = when (splitTunnelType) {
SPLIT_TUNNEL_INCLUDE -> ::includeApplication
SPLIT_TUNNEL_EXCLUDE -> ::excludeApplication
else -> throw BadConfigException("Unexpected value of the 'appSplitTunnelType' parameter: $splitTunnelType")
}
for (i in 0 until splitTunnelApps.length()) {
appHandlerFunc(splitTunnelApps.getString(i))
}
}
protected open fun buildVpnInterface(config: ProtocolConfig, vpnBuilder: Builder) { protected open fun buildVpnInterface(config: ProtocolConfig, vpnBuilder: Builder) {
vpnBuilder.setSession(VPN_SESSION_NAME) vpnBuilder.setSession(VPN_SESSION_NAME)
@@ -101,6 +117,11 @@ abstract class Protocol {
} }
} }
for (app in config.includedApplications) {
Log.d(TAG, "addAllowedApplication: $app")
vpnBuilder.addAllowedApplication(app)
}
for (app in config.excludedApplications) { for (app in config.excludedApplications) {
Log.d(TAG, "addDisallowedApplication: $app") Log.d(TAG, "addDisallowedApplication: $app")
vpnBuilder.addDisallowedApplication(app) vpnBuilder.addDisallowedApplication(app)
@@ -16,6 +16,7 @@ open class ProtocolConfig protected constructor(
val excludedRoutes: Set<InetNetwork>, val excludedRoutes: Set<InetNetwork>,
val includedAddresses: Set<InetNetwork>, val includedAddresses: Set<InetNetwork>,
val excludedAddresses: Set<InetNetwork>, val excludedAddresses: Set<InetNetwork>,
val includedApplications: Set<String>,
val excludedApplications: Set<String>, val excludedApplications: Set<String>,
val httpProxy: ProxyInfo?, val httpProxy: ProxyInfo?,
val allowAllAF: Boolean, val allowAllAF: Boolean,
@@ -31,6 +32,7 @@ open class ProtocolConfig protected constructor(
builder.excludedRoutes, builder.excludedRoutes,
builder.includedAddresses, builder.includedAddresses,
builder.excludedAddresses, builder.excludedAddresses,
builder.includedApplications,
builder.excludedApplications, builder.excludedApplications,
builder.httpProxy, builder.httpProxy,
builder.allowAllAF, builder.allowAllAF,
@@ -45,6 +47,7 @@ open class ProtocolConfig protected constructor(
internal val excludedRoutes: MutableSet<InetNetwork> = hashSetOf() internal val excludedRoutes: MutableSet<InetNetwork> = hashSetOf()
internal val includedAddresses: MutableSet<InetNetwork> = hashSetOf() internal val includedAddresses: MutableSet<InetNetwork> = hashSetOf()
internal val excludedAddresses: MutableSet<InetNetwork> = hashSetOf() internal val excludedAddresses: MutableSet<InetNetwork> = hashSetOf()
internal val includedApplications: MutableSet<String> = hashSetOf()
internal val excludedApplications: MutableSet<String> = hashSetOf() internal val excludedApplications: MutableSet<String> = hashSetOf()
internal var searchDomain: String? = null internal var searchDomain: String? = null
@@ -88,6 +91,9 @@ open class ProtocolConfig protected constructor(
fun excludeAddress(addr: InetNetwork) = apply { this.excludedAddresses += addr } fun excludeAddress(addr: InetNetwork) = apply { this.excludedAddresses += addr }
fun excludeAddresses(addresses: Collection<InetNetwork>) = apply { this.excludedAddresses += addresses } fun excludeAddresses(addresses: Collection<InetNetwork>) = apply { this.excludedAddresses += addresses }
fun includeApplication(application: String) = apply { this.includedApplications += application }
fun includeApplications(applications: Collection<String>) = apply { this.includedApplications += applications }
fun excludeApplication(application: String) = apply { this.excludedApplications += application } fun excludeApplication(application: String) = apply { this.excludedApplications += application }
fun excludeApplications(applications: Collection<String>) = apply { this.excludedApplications += applications } fun excludeApplications(applications: Collection<String>) = apply { this.excludedApplications += applications }
@@ -7,6 +7,7 @@ import android.content.Intent.EXTRA_MIME_TYPES
import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
import android.content.ServiceConnection import android.content.ServiceConnection
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.net.VpnService import android.net.VpnService
import android.os.Bundle import android.os.Bundle
@@ -24,12 +25,15 @@ import androidx.core.content.ContextCompat
import java.io.IOException import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
import kotlin.text.RegexOption.IGNORE_CASE import kotlin.text.RegexOption.IGNORE_CASE
import AppListProvider
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.amnezia.vpn.protocol.getStatistics import org.amnezia.vpn.protocol.getStatistics
import org.amnezia.vpn.protocol.getStatus import org.amnezia.vpn.protocol.getStatus
import org.amnezia.vpn.qt.QtAndroidController import org.amnezia.vpn.qt.QtAndroidController
@@ -476,4 +480,32 @@ class AmneziaActivity : QtActivity() {
window.setFlags(flag, LayoutParams.FLAG_SECURE) window.setFlags(flag, LayoutParams.FLAG_SECURE)
} }
} }
@Suppress("unused")
fun minimizeApp() {
Log.v(TAG, "Minimize application")
mainScope.launch {
moveTaskToBack(false)
}
}
@Suppress("unused")
fun getAppList(): String {
Log.v(TAG, "Get app list")
var appList = ""
runBlocking {
mainScope.launch {
withContext(Dispatchers.IO) {
appList = AppListProvider.getAppList(packageManager, packageName)
}
}.join()
}
return appList
}
@Suppress("unused")
fun getAppIcon(packageName: String, width: Int, height: Int): Bitmap {
Log.v(TAG, "Get app icon: $packageName")
return AppListProvider.getAppIcon(packageManager, packageName, width, height)
}
} }
@@ -0,0 +1,73 @@
import android.Manifest.permission.INTERNET
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import android.graphics.Bitmap
import android.graphics.Bitmap.Config.ARGB_8888
import androidx.core.graphics.drawable.toBitmapOrNull
import org.amnezia.vpn.util.Log
import org.json.JSONArray
import org.json.JSONObject
private const val TAG = "AppListProvider"
object AppListProvider {
fun getAppList(pm: PackageManager, selfPackageName: String): String {
val jsonArray = JSONArray()
pm.getPackagesHoldingPermissions(arrayOf(INTERNET), 0)
.filter { it.packageName != selfPackageName }
.map { App(it, pm) }
.sortedWith(App::compareTo)
.map(App::toJson)
.forEach(jsonArray::put)
return jsonArray.toString()
}
fun getAppIcon(pm: PackageManager, packageName: String, width: Int, height: Int): Bitmap {
val icon = try {
pm.getApplicationIcon(packageName)
} catch (e: NameNotFoundException) {
Log.e(TAG, "Package $packageName was not found: $e")
pm.defaultActivityIcon
}
val w: Int = if (width > 0) width else icon.intrinsicWidth
val h: Int = if (height > 0) height else icon.intrinsicHeight
return icon.toBitmapOrNull(w, h, ARGB_8888)
?: Bitmap.createBitmap(w, h, ARGB_8888)
}
}
private class App(pi: PackageInfo, pm: PackageManager, ai: ApplicationInfo = pi.applicationInfo) : Comparable<App> {
val name: String?
val packageName: String = pi.packageName
val icon: Boolean = ai.icon != 0
val isLaunchable: Boolean = pm.getLaunchIntentForPackage(packageName) != null
init {
val name = ai.loadLabel(pm).toString()
this.name = if (name != packageName) name else null
}
override fun compareTo(other: App): Int {
val r = other.isLaunchable.compareTo(isLaunchable)
if (r != 0) return r
if (name != other.name) {
return when {
name == null -> 1
other.name == null -> -1
else -> String.CASE_INSENSITIVE_ORDER.compare(name, other.name)
}
}
return String.CASE_INSENSITIVE_ORDER.compare(packageName, other.packageName)
}
fun toJson(): JSONObject {
val jsonObject = JSONObject()
jsonObject.put("package", packageName)
jsonObject.put("name", name)
jsonObject.put("icon", icon)
jsonObject.put("launchable", isLaunchable)
return jsonObject
}
}
@@ -95,6 +95,7 @@ open class Wireguard : Protocol() {
return WireguardConfig.build { return WireguardConfig.build {
configWireguard(configData, configDataJson) configWireguard(configData, configDataJson)
configSplitTunneling(config) configSplitTunneling(config)
configAppSplitTunneling(config)
} }
} }
+3 -1
View File
@@ -20,7 +20,7 @@ set(QT_ANDROID_MULTI_ABI_FORWARD_VARS "QT_NO_GLOBAL_APK_TARGET_PART_OF_ALL;CMAKE
# We need to include qtprivate api's # We need to include qtprivate api's
# As QAndroidBinder is not yet implemented with a public api # As QAndroidBinder is not yet implemented with a public api
set(LIBS ${LIBS} Qt6::CorePrivate) set(LIBS ${LIBS} Qt6::CorePrivate -ljnigraphics)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/platforms/android) link_directories(${CMAKE_CURRENT_SOURCE_DIR}/platforms/android)
@@ -30,6 +30,7 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.h ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h ${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.h
) )
set(SOURCES ${SOURCES} set(SOURCES ${SOURCES}
@@ -38,6 +39,7 @@ set(SOURCES ${SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp ${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
) )
foreach(abi IN ITEMS ${QT_ANDROID_ABIS}) foreach(abi IN ITEMS ${QT_ANDROID_ABIS})
+3 -3
View File
@@ -10,10 +10,10 @@ AwgConfigurator::AwgConfigurator(std::shared_ptr<Settings> settings, QObject *pa
{ {
} }
QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials, DockerContainer container, QString AwgConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) const QJsonObject &containerConfig, ErrorCode errorCode)
{ {
QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, clientId, errorCode); QString config = WireguardConfigurator::createConfig(credentials, container, containerConfig, errorCode);
QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object(); QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object();
QString awgConfig = jsonConfig.value(config_key::config).toString(); QString awgConfig = jsonConfig.value(config_key::config).toString();
+2 -2
View File
@@ -11,8 +11,8 @@ class AwgConfigurator : public WireguardConfigurator
public: public:
AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr); AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
}; };
#endif // AWGCONFIGURATOR_H #endif // AWGCONFIGURATOR_H
+9 -7
View File
@@ -13,22 +13,24 @@ CloakConfigurator::CloakConfigurator(std::shared_ptr<Settings> settings, QObject
} }
QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials, QString CloakConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) const QJsonObject &containerConfig, ErrorCode errorCode)
{ {
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString cloakPublicKey = serverController.getTextFileFromContainer(container, credentials, QString cloakPublicKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::cloak::ckPublicKeyPath, &e); amnezia::protocols::cloak::ckPublicKeyPath, errorCode);
cloakPublicKey.replace("\n", ""); cloakPublicKey.replace("\n", "");
if (errorCode != ErrorCode::NoError) {
return "";
}
QString cloakBypassUid = serverController.getTextFileFromContainer(container, credentials, QString cloakBypassUid = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::cloak::ckBypassUidKeyPath, &e); amnezia::protocols::cloak::ckBypassUidKeyPath, errorCode);
cloakBypassUid.replace("\n", ""); cloakBypassUid.replace("\n", "");
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode) *errorCode = e;
return ""; return "";
} }
+3 -3
View File
@@ -7,14 +7,14 @@
using namespace amnezia; using namespace amnezia;
class CloakConfigurator : ConfiguratorBase class CloakConfigurator : public ConfiguratorBase
{ {
Q_OBJECT Q_OBJECT
public: public:
CloakConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr); CloakConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
}; };
#endif // CLOAK_CONFIGURATOR_H #endif // CLOAK_CONFIGURATOR_H
+21 -3
View File
@@ -1,8 +1,26 @@
#include "configurator_base.h" #include "configurator_base.h"
ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings, QObject *parent) ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings, QObject *parent)
: QObject{parent}, : QObject { parent }, m_settings(settings)
m_settings(settings)
{ {
}
QString ConfiguratorBase::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
}
QString ConfiguratorBase::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
{
processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString;
}
void ConfiguratorBase::processConfigWithDnsSettings(const QPair<QString, QString> &dns, QString &protocolConfigString)
{
protocolConfigString.replace("$PRIMARY_DNS", dns.first);
protocolConfigString.replace("$SECONDARY_DNS", dns.second);
} }
+11 -2
View File
@@ -3,10 +3,9 @@
#include <QObject> #include <QObject>
class Settings;
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "core/defs.h" #include "core/defs.h"
#include "settings.h"
class ConfiguratorBase : public QObject class ConfiguratorBase : public QObject
{ {
@@ -14,7 +13,17 @@ class ConfiguratorBase : public QObject
public: public:
explicit ConfiguratorBase(std::shared_ptr<Settings> settings, QObject *parent = nullptr); explicit ConfiguratorBase(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
virtual QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode) = 0;
virtual QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
virtual QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
protected: protected:
void processConfigWithDnsSettings(const QPair<QString, QString> &dns, QString &protocolConfigString);
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
}; };
+8 -8
View File
@@ -20,7 +20,7 @@ Ikev2Configurator::Ikev2Configurator(std::shared_ptr<Settings> settings, QObject
} }
Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials, Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode) DockerContainer container, ErrorCode errorCode)
{ {
Ikev2Configurator::ConnectionData connData; Ikev2Configurator::ConnectionData connData;
connData.host = credentials.hostName; connData.host = credentials.hostName;
@@ -40,17 +40,17 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
.arg(connData.clientId); .arg(connData.clientId);
ServerController serverController(m_settings); ServerController serverController(m_settings);
ErrorCode e = serverController.runContainerScript(credentials, container, scriptCreateCert); errorCode = serverController.runContainerScript(credentials, container, scriptCreateCert);
QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"") QString scriptExportCert = QString("pk12util -W \"%1\" -d sql:/etc/ipsec.d -n \"%2\" -o \"%3\"")
.arg(connData.password) .arg(connData.password)
.arg(connData.clientId) .arg(connData.clientId)
.arg(certFileName); .arg(certFileName);
e = serverController.runContainerScript(credentials, container, scriptExportCert); errorCode = serverController.runContainerScript(credentials, container, scriptExportCert);
connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, &e); connData.clientCert = serverController.getTextFileFromContainer(container, credentials, certFileName, errorCode);
connData.caCert = connData.caCert =
serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", &e); serverController.getTextFileFromContainer(container, credentials, "/etc/ipsec.d/ca_cert_base64.p12", errorCode);
qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size(); qDebug() << "Ikev2Configurator::ConnectionData client cert size:" << connData.clientCert.size();
qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size(); qDebug() << "Ikev2Configurator::ConnectionData ca cert size:" << connData.caCert.size();
@@ -58,13 +58,13 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
return connData; return connData;
} }
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials, DockerContainer container, QString Ikev2Configurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode) const QJsonObject &containerConfig, ErrorCode errorCode)
{ {
Q_UNUSED(containerConfig) Q_UNUSED(containerConfig)
ConnectionData connData = prepareIkev2Config(credentials, container, errorCode); ConnectionData connData = prepareIkev2Config(credentials, container, errorCode);
if (errorCode && *errorCode) { if (errorCode != ErrorCode::NoError) {
return ""; return "";
} }
+4 -4
View File
@@ -7,7 +7,7 @@
#include "configurator_base.h" #include "configurator_base.h"
#include "core/defs.h" #include "core/defs.h"
class Ikev2Configurator : ConfiguratorBase class Ikev2Configurator : public ConfiguratorBase
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -21,15 +21,15 @@ public:
QString host; // host ip QString host; // host ip
}; };
QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
QString genIkev2Config(const ConnectionData &connData); QString genIkev2Config(const ConnectionData &connData);
QString genMobileConfig(const ConnectionData &connData); QString genMobileConfig(const ConnectionData &connData);
QString genStrongSwanConfig(const ConnectionData &connData); QString genStrongSwanConfig(const ConnectionData &connData);
ConnectionData prepareIkev2Config(const ServerCredentials &credentials, ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr); DockerContainer container, ErrorCode errorCode);
}; };
#endif // IKEV2_CONFIGURATOR_H #endif // IKEV2_CONFIGURATOR_H
+29 -31
View File
@@ -14,9 +14,9 @@
#endif #endif
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h" #include "core/scripts_registry.h"
#include "core/server_defs.h" #include "core/server_defs.h"
#include "core/controllers/serverController.h"
#include "settings.h" #include "settings.h"
#include "utilities.h" #include "utilities.h"
@@ -31,59 +31,51 @@ OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QOb
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials, OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, DockerContainer container,
ErrorCode *errorCode) ErrorCode errorCode)
{ {
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest(); OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
connData.host = credentials.hostName; connData.host = credentials.hostName;
if (connData.privKey.isEmpty() || connData.request.isEmpty()) { if (connData.privKey.isEmpty() || connData.request.isEmpty()) {
if (errorCode) errorCode = ErrorCode::OpenSslFailed;
*errorCode = ErrorCode::OpenSslFailed;
return connData; return connData;
} }
QString reqFileName = QString("%1/%2.req").arg(amnezia::protocols::openvpn::clientsDirPath).arg(connData.clientId); QString reqFileName = QString("%1/%2.req").arg(amnezia::protocols::openvpn::clientsDirPath).arg(connData.clientId);
ServerController serverController(m_settings); ServerController serverController(m_settings);
ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName); errorCode = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode)
*errorCode = e;
return connData; return connData;
} }
e = signCert(container, credentials, connData.clientId); errorCode = signCert(container, credentials, connData.clientId);
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode)
*errorCode = e;
return connData; return connData;
} }
connData.caCert = serverController.getTextFileFromContainer(container, credentials, connData.caCert = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::openvpn::caCertPath, &e); amnezia::protocols::openvpn::caCertPath, errorCode);
connData.clientCert = serverController.getTextFileFromContainer( connData.clientCert = serverController.getTextFileFromContainer(
container, credentials, container, credentials,
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), &e); QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath).arg(connData.clientId), errorCode);
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode)
*errorCode = e;
return connData; return connData;
} }
connData.taKey = serverController.getTextFileFromContainer(container, credentials, connData.taKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::openvpn::taKeyPath, &e); amnezia::protocols::openvpn::taKeyPath, errorCode);
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) { if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
if (errorCode) errorCode = ErrorCode::SshScpFailureError;
*errorCode = ErrorCode::SshScpFailureError;
} }
return connData; return connData;
} }
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, QString OpenVpnConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) const QJsonObject &containerConfig, ErrorCode errorCode)
{ {
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString config = QString config =
@@ -91,7 +83,7 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
serverController.genVarsForScript(credentials, container, containerConfig)); serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode); ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
if (errorCode && *errorCode) { if (errorCode != ErrorCode::NoError) {
return ""; return "";
} }
@@ -113,17 +105,20 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
QJsonObject jConfig; QJsonObject jConfig;
jConfig[config_key::config] = config; jConfig[config_key::config] = config;
clientId = connData.clientId; jConfig[config_key::clientId] = connData.clientId;
return QJsonDocument(jConfig).toJson(); return QJsonDocument(jConfig).toJson();
} }
QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig, const int serverIndex) QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
{ {
QJsonObject json = QJsonDocument::fromJson(jsonConfig.toUtf8()).object(); processConfigWithDnsSettings(dns, protocolConfigString);
QJsonObject json = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
QString config = json[config_key::config].toString(); QString config = json[config_key::config].toString();
if (!m_settings->server(serverIndex).value(config_key::configVersion).toInt()) { if (!isApiConfig) {
QRegularExpression regex("redirect-gateway.*"); QRegularExpression regex("redirect-gateway.*");
config.replace(regex, ""); config.replace(regex, "");
@@ -138,9 +133,9 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig,
// no redirect-gateway // no redirect-gateway
} }
if (m_settings->routeMode() == Settings::VpnAllExceptSites) { if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#ifndef Q_OS_ANDROID #ifndef Q_OS_ANDROID
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n"); config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
#endif #endif
// Prevent ipv6 leak // Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n"); config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
config.append("block-ipv6\n"); config.append("block-ipv6\n");
@@ -164,9 +159,12 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig,
return QJsonDocument(json).toJson(); return QJsonDocument(json).toJson();
} }
QString OpenVpnConfigurator::processConfigWithExportSettings(QString jsonConfig) QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString)
{ {
QJsonObject json = QJsonDocument::fromJson(jsonConfig.toUtf8()).object(); processConfigWithDnsSettings(dns, protocolConfigString);
QJsonObject json = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
QString config = json[config_key::config].toString(); QString config = json[config_key::config].toString();
QRegularExpression regex("redirect-gateway.*"); QRegularExpression regex("redirect-gateway.*");
+17 -17
View File
@@ -7,37 +7,37 @@
#include "configurator_base.h" #include "configurator_base.h"
#include "core/defs.h" #include "core/defs.h"
class OpenVpnConfigurator : ConfiguratorBase class OpenVpnConfigurator : public ConfiguratorBase
{ {
Q_OBJECT Q_OBJECT
public: public:
OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr); OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
struct ConnectionData { struct ConnectionData
{
QString clientId; QString clientId;
QString request; // certificate request QString request; // certificate request
QString privKey; // client private key QString privKey; // client private key
QString clientCert; // client signed certificate QString clientCert; // client signed certificate
QString caCert; // server certificate QString caCert; // server certificate
QString taKey; // tls-auth key QString taKey; // tls-auth key
QString host; // host ip QString host; // host ip
}; };
QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
QString processConfigWithLocalSettings(QString jsonConfig, const int serverIndex); QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString processConfigWithExportSettings(QString jsonConfig); QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
ErrorCode signCert(DockerContainer container, QString &protocolConfigString);
const ServerCredentials &credentials, QString clientId);
static ConnectionData createCertRequest(); static ConnectionData createCertRequest();
private: private:
ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
DockerContainer container, ErrorCode *errorCode = nullptr); ErrorCode errorCode);
ErrorCode signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId);
}; };
#endif // OPENVPN_CONFIGURATOR_H #endif // OPENVPN_CONFIGURATOR_H
@@ -13,18 +13,16 @@ ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr<Settings> setti
} }
QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials, QString ShadowSocksConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode) const QJsonObject &containerConfig, ErrorCode errorCode)
{ {
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString ssKey = serverController.getTextFileFromContainer(container, credentials, QString ssKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::shadowsocks::ssKeyPath, &e); amnezia::protocols::shadowsocks::ssKeyPath, errorCode);
ssKey.replace("\n", ""); ssKey.replace("\n", "");
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode) *errorCode = e;
return ""; return "";
} }
@@ -6,14 +6,14 @@
#include "configurator_base.h" #include "configurator_base.h"
#include "core/defs.h" #include "core/defs.h"
class ShadowSocksConfigurator : ConfiguratorBase class ShadowSocksConfigurator : public ConfiguratorBase
{ {
Q_OBJECT Q_OBJECT
public: public:
ShadowSocksConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr); ShadowSocksConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
}; };
#endif // SHADOWSOCKS_CONFIGURATOR_H #endif // SHADOWSOCKS_CONFIGURATOR_H
-131
View File
@@ -1,131 +0,0 @@
#include "vpn_configurator.h"
#include "cloak_configurator.h"
#include "ikev2_configurator.h"
#include "openvpn_configurator.h"
#include "shadowsocks_configurator.h"
#include "ssh_configurator.h"
#include "wireguard_configurator.h"
#include "awg_configurator.h"
#include "xray_configurator.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include "containers/containers_defs.h"
#include "settings.h"
#include "core/networkUtilities.h"
VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent)
: ConfiguratorBase(settings, parent)
{
openVpnConfigurator = std::shared_ptr<OpenVpnConfigurator>(new OpenVpnConfigurator(settings, this));
shadowSocksConfigurator = std::shared_ptr<ShadowSocksConfigurator>(new ShadowSocksConfigurator(settings, this));
cloakConfigurator = std::shared_ptr<CloakConfigurator>(new CloakConfigurator(settings, this));
wireguardConfigurator = std::shared_ptr<WireguardConfigurator>(new WireguardConfigurator(settings, false, this));
ikev2Configurator = std::shared_ptr<Ikev2Configurator>(new Ikev2Configurator(settings, this));
sshConfigurator = std::shared_ptr<SshConfigurator>(new SshConfigurator(settings, this));
awgConfigurator = std::shared_ptr<AwgConfigurator>(new AwgConfigurator(settings, this));
xrayConfigurator = std::shared_ptr<XrayConfigurator>(new XrayConfigurator(settings, this));
}
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, QString &clientId, ErrorCode *errorCode)
{
switch (proto) {
case Proto::OpenVpn:
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, clientId, errorCode);
case Proto::ShadowSocks:
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
case Proto::Cloak: return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
case Proto::WireGuard:
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, clientId, errorCode);
case Proto::Awg:
return awgConfigurator->genAwgConfig(credentials, container, containerConfig, clientId, errorCode);
case Proto::Xray:
return xrayConfigurator->genXrayConfig(credentials, container, containerConfig, clientId, errorCode);
case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
default: return "";
}
}
QPair<QString, QString> VpnConfigurator::getDnsForConfig(int serverIndex)
{
QPair<QString, QString> dns;
bool useAmneziaDns = m_settings->useAmneziaDns();
const QJsonObject &server = m_settings->server(serverIndex);
dns.first = server.value(config_key::dns1).toString();
dns.second = server.value(config_key::dns2).toString();
if (dns.first.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.first)) {
if (useAmneziaDns && m_settings->containers(serverIndex).contains(DockerContainer::Dns)) {
dns.first = protocols::dns::amneziaDnsIp;
} else
dns.first = m_settings->primaryDns();
}
if (dns.second.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.second)) {
dns.second = m_settings->secondaryDns();
}
qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second;
return dns;
}
QString &VpnConfigurator::processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
{
auto dns = getDnsForConfig(serverIndex);
config.replace("$PRIMARY_DNS", dns.first);
config.replace("$SECONDARY_DNS", dns.second);
return config;
}
QString &VpnConfigurator::processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
if (proto == Proto::OpenVpn) {
config = openVpnConfigurator->processConfigWithLocalSettings(config, serverIndex);
}
return config;
}
QString &VpnConfigurator::processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto,
QString &config)
{
processConfigWithDnsSettings(serverIndex, container, proto, config);
if (proto == Proto::OpenVpn) {
config = openVpnConfigurator->processConfigWithExportSettings(config);
}
return config;
}
void VpnConfigurator::updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
if (container == DockerContainer::TorWebSite) {
QJsonObject protocol = containerConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
qDebug() << "amnezia-tor onions" << stdOut;
QString onion = stdOut;
onion.replace("\n", "");
protocol.insert(config_key::site, onion);
containerConfig.insert(ProtocolProps::protoToString(mainProto), protocol);
}
}
-54
View File
@@ -1,54 +0,0 @@
#ifndef VPN_CONFIGURATOR_H
#define VPN_CONFIGURATOR_H
#include <QObject>
#include "configurator_base.h"
#include "core/defs.h"
class OpenVpnConfigurator;
class ShadowSocksConfigurator;
class CloakConfigurator;
class WireguardConfigurator;
class Ikev2Configurator;
class SshConfigurator;
class AwgConfigurator;
class XrayConfigurator;
// Retrieve connection settings from server
class VpnConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
explicit VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, Proto proto, QString &clientId,
ErrorCode *errorCode = nullptr);
QPair<QString, QString> getDnsForConfig(int serverIndex);
QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
QString &processConfigWithLocalSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
// workaround for containers which is not support normal configuration
void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut);
std::shared_ptr<OpenVpnConfigurator> openVpnConfigurator;
std::shared_ptr<ShadowSocksConfigurator> shadowSocksConfigurator;
std::shared_ptr<CloakConfigurator> cloakConfigurator;
std::shared_ptr<WireguardConfigurator> wireguardConfigurator;
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
std::shared_ptr<SshConfigurator> sshConfigurator;
std::shared_ptr<AwgConfigurator> awgConfigurator;
std::shared_ptr<XrayConfigurator> xrayConfigurator;
signals:
void newVpnConfigCreated(const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials);
void clientModelUpdated();
};
#endif // VPN_CONFIGURATOR_H
+35 -51
View File
@@ -13,23 +13,22 @@
#include <openssl/x509.h> #include <openssl/x509.h>
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h" #include "core/scripts_registry.h"
#include "core/server_defs.h" #include "core/server_defs.h"
#include "core/controllers/serverController.h"
#include "settings.h" #include "settings.h"
#include "utilities.h" #include "utilities.h"
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent) WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent)
: ConfiguratorBase(settings, parent), m_isAwg(isAwg) : ConfiguratorBase(settings, parent), m_isAwg(isAwg)
{ {
m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath m_serverConfigPath =
: amnezia::protocols::wireguard::serverConfigPath; m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath;
m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath m_serverPublicKeyPath =
: amnezia::protocols::wireguard::serverPublicKeyPath; m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath;
m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath m_serverPskKeyPath =
: amnezia::protocols::wireguard::serverPskKeyPath; m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template : ProtocolScriptType::wireguard_template;
: ProtocolScriptType::wireguard_template;
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard; m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
m_defaultPort = m_isAwg ? protocols::wireguard::defaultPort : protocols::awg::defaultPort; m_defaultPort = m_isAwg ? protocols::wireguard::defaultPort : protocols::awg::defaultPort;
@@ -69,19 +68,17 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials, WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, DockerContainer container,
const QJsonObject &containerConfig, const QJsonObject &containerConfig,
ErrorCode *errorCode) ErrorCode errorCode)
{ {
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys(); WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName; connData.host = credentials.hostName;
connData.port = containerConfig.value(m_protocolName).toObject().value(config_key::port).toString(m_defaultPort); connData.port = containerConfig.value(m_protocolName).toObject().value(config_key::port).toString(m_defaultPort);
if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) { if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) {
if (errorCode) errorCode = ErrorCode::InternalError;
*errorCode = ErrorCode::InternalError;
return connData; return connData;
} }
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings); ServerController serverController(m_settings);
// Get list of already created clients (only IP addresses) // Get list of already created clients (only IP addresses)
@@ -94,9 +91,8 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return ErrorCode::NoError; return ErrorCode::NoError;
}; };
e = serverController.runContainerScript(credentials, container, script, cbReadStdOut); errorCode = serverController.runContainerScript(credentials, container, script, cbReadStdOut);
if (errorCode && e) { if (errorCode != ErrorCode::NoError) {
*errorCode = e;
return connData; return connData;
} }
@@ -110,8 +106,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
} else { } else {
int next = ips.last().split(".").last().toInt() + 1; int next = ips.last().split(".").last().toInt() + 1;
if (next > 254) { if (next > 254) {
if (errorCode) errorCode = ErrorCode::AddressPoolError;
*errorCode = ErrorCode::AddressPoolError;
return connData; return connData;
} }
nextIpNumber = QString::number(next); nextIpNumber = QString::number(next);
@@ -123,8 +118,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
{ {
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts); QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
if (l.isEmpty()) { if (l.isEmpty()) {
if (errorCode) errorCode = ErrorCode::AddressPoolError;
*errorCode = ErrorCode::AddressPoolError;
return connData; return connData;
} }
l.removeLast(); l.removeLast();
@@ -134,20 +128,17 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
} }
// Get keys // Get keys
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, &e); connData.serverPubKey =
serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode);
connData.serverPubKey.replace("\n", ""); connData.serverPubKey.replace("\n", "");
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode)
*errorCode = e;
return connData; return connData;
} }
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, &e); connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, errorCode);
connData.pskKey.replace("\n", ""); connData.pskKey.replace("\n", "");
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode)
*errorCode = e;
return connData; return connData;
} }
@@ -158,26 +149,24 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
"AllowedIPs = %3/32\n\n") "AllowedIPs = %3/32\n\n")
.arg(connData.clientPubKey, connData.pskKey, connData.clientIP); .arg(connData.clientPubKey, connData.pskKey, connData.clientIP);
e = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath, errorCode = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath,
libssh::ScpOverwriteMode::ScpAppendToExisting); libssh::ScpOverwriteMode::ScpAppendToExisting);
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode)
*errorCode = e;
return connData; return connData;
} }
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'") QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
.arg(m_serverConfigPath); .arg(m_serverConfigPath);
e = serverController.runScript( errorCode = serverController.runScript(
credentials, serverController.replaceVars(script, serverController.genVarsForScript(credentials, container))); credentials, serverController.replaceVars(script, serverController.genVarsForScript(credentials, container)));
return connData; return connData;
} }
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, QString WireguardConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) const QJsonObject &containerConfig, ErrorCode errorCode)
{ {
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString scriptData = amnezia::scriptData(m_configTemplate, container); QString scriptData = amnezia::scriptData(m_configTemplate, container);
@@ -185,7 +174,7 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
scriptData, serverController.genVarsForScript(credentials, container, containerConfig)); scriptData, serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode); ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
if (errorCode && *errorCode) { if (errorCode != ErrorCode::NoError) {
return ""; return "";
} }
@@ -205,30 +194,25 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
jConfig[config_key::client_pub_key] = connData.clientPubKey; jConfig[config_key::client_pub_key] = connData.clientPubKey;
jConfig[config_key::psk_key] = connData.pskKey; jConfig[config_key::psk_key] = connData.pskKey;
jConfig[config_key::server_pub_key] = connData.serverPubKey; jConfig[config_key::server_pub_key] = connData.serverPubKey;
jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu); jConfig[config_key::mtu] = wireguarConfig.value(config_key::mtu).toString(protocols::wireguard::defaultMtu);
clientId = connData.clientPubKey; jConfig[config_key::clientId] = connData.clientPubKey;
return QJsonDocument(jConfig).toJson(); return QJsonDocument(jConfig).toJson();
} }
QString WireguardConfigurator::processConfigWithLocalSettings(QString config) QString WireguardConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns,
const bool isApiConfig, QString &protocolConfigString)
{ {
// TODO replace DNS if it already set processConfigWithDnsSettings(dns, protocolConfigString);
config.replace("$PRIMARY_DNS", m_settings->primaryDns());
config.replace("$SECONDARY_DNS", m_settings->secondaryDns());
QJsonObject jConfig; return protocolConfigString;
jConfig[config_key::config] = config;
return QJsonDocument(jConfig).toJson();
} }
QString WireguardConfigurator::processConfigWithExportSettings(QString config) QString WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns,
const bool isApiConfig, QString &protocolConfigString)
{ {
config.replace("$PRIMARY_DNS", m_settings->primaryDns()); processConfigWithDnsSettings(dns, protocolConfigString);
config.replace("$SECONDARY_DNS", m_settings->secondaryDns());
return config; return protocolConfigString;
} }
@@ -25,18 +25,20 @@ public:
QString port; QString port;
}; };
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
QString processConfigWithLocalSettings(QString config); QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString processConfigWithExportSettings(QString config); QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
static ConnectionData genClientKeys(); static ConnectionData genClientKeys();
private: private:
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container, ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr); const QJsonObject &containerConfig, ErrorCode errorCode);
bool m_isAwg; bool m_isAwg;
QString m_serverConfigPath; QString m_serverConfigPath;
QString m_serverPublicKeyPath; QString m_serverPublicKeyPath;
+12 -19
View File
@@ -1,43 +1,36 @@
#include "xray_configurator.h" #include "xray_configurator.h"
#include <QFile> #include <QFile>
#include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject>
#include "core/scripts_registry.h"
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "core/controllers/serverController.h" #include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent): XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent) : ConfiguratorBase(settings, parent)
ConfiguratorBase(settings, parent)
{ {
} }
QString XrayConfigurator::genXrayConfig(const ServerCredentials &credentials, QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
DockerContainer container, const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode) ErrorCode errorCode)
{ {
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString config = QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container), serverController.genVarsForScript(credentials, container, containerConfig));
serverController.genVarsForScript(credentials, container, containerConfig));
QString xrayPublicKey = serverController.getTextFileFromContainer(container, credentials, QString xrayPublicKey =
amnezia::protocols::xray::PublicKeyPath, &e); serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::xray::PublicKeyPath, errorCode);
xrayPublicKey.replace("\n", ""); xrayPublicKey.replace("\n", "");
QString xrayUuid = serverController.getTextFileFromContainer(container, credentials, QString xrayUuid = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, errorCode);
amnezia::protocols::xray::uuidPath, &e);
xrayUuid.replace("\n", ""); xrayUuid.replace("\n", "");
QString xrayShortId = serverController.getTextFileFromContainer(container, credentials, QString xrayShortId = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::xray::shortidPath, errorCode);
amnezia::protocols::xray::shortidPath, &e);
xrayShortId.replace("\n", ""); xrayShortId.replace("\n", "");
if (e) { if (errorCode != ErrorCode::NoError) {
if (errorCode) *errorCode = e;
return ""; return "";
} }
+3 -3
View File
@@ -6,14 +6,14 @@
#include "configurator_base.h" #include "configurator_base.h"
#include "core/defs.h" #include "core/defs.h"
class XrayConfigurator : ConfiguratorBase class XrayConfigurator : public ConfiguratorBase
{ {
Q_OBJECT Q_OBJECT
public: public:
XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr); XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genXrayConfig(const ServerCredentials &credentials, DockerContainer container, QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr); ErrorCode errorCode);
}; };
#endif // XRAY_CONFIGURATOR_H #endif // XRAY_CONFIGURATOR_H
+13
View File
@@ -1,5 +1,8 @@
#include "containers_defs.h" #include "containers_defs.h"
#include "QJsonObject"
#include "QJsonDocument"
QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c) QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
{ {
QDebugStateSaver saver(debug); QDebugStateSaver saver(debug);
@@ -363,3 +366,13 @@ bool ContainerProps::isShareable(DockerContainer container)
default: return true; default: return true;
} }
} }
QJsonObject ContainerProps::getProtocolConfigFromContainer(const Proto protocol, const QJsonObject &containerConfig)
{
QString protocolConfigString = containerConfig.value(ProtocolProps::protoToString(protocol))
.toObject()
.value(config_key::last_config)
.toString();
return QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
}
+2
View File
@@ -68,6 +68,8 @@ namespace amnezia
static int easySetupOrder(amnezia::DockerContainer container); static int easySetupOrder(amnezia::DockerContainer container);
static bool isShareable(amnezia::DockerContainer container); static bool isShareable(amnezia::DockerContainer container);
static QJsonObject getProtocolConfigFromContainer(const amnezia::Proto protocol, const QJsonObject &containerConfig);
}; };
static void declareQmlContainerEnum() static void declareQmlContainerEnum()
@@ -5,9 +5,8 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QtConcurrent> #include <QtConcurrent>
#include "configurators/openvpn_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h" #include "core/errorstrings.h"
#include "configurators/wireguard_configurator.h"
namespace namespace
{ {
@@ -24,9 +23,7 @@ namespace
} }
} }
ApiController::ApiController(const QSharedPointer<ServersModel> &serversModel, ApiController::ApiController(QObject *parent) : QObject(parent)
const QSharedPointer<ContainersModel> &containersModel, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel)
{ {
} }
@@ -67,21 +64,14 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
return obj; return obj;
} }
void ApiController::updateServerConfigFromApi() ErrorCode ApiController::updateServerConfigFromApi(QJsonObject &serverConfig)
{ {
QtConcurrent::run([this]() { QFutureWatcher<ErrorCode> watcher;
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
auto serverConfig = m_serversModel->getDefaultServerConfig(); QFuture<ErrorCode> future = QtConcurrent::run([this, &serverConfig]() {
auto containerConfig = serverConfig.value(config_key::containers).toArray(); auto containerConfig = serverConfig.value(config_key::containers).toArray();
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) { if (serverConfig.value(config_key::configVersion).toInt()) {
emit updateStarted();
m_isConfigUpdateStarted = true;
QNetworkAccessManager manager; QNetworkAccessManager manager;
QNetworkRequest request; QNetworkRequest request;
@@ -114,9 +104,7 @@ void ApiController::updateServerConfigFromApi()
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) { if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError)); return ErrorCode::ApiConfigDownloadError;
m_isConfigUpdateStarted = false;
return;
} }
QByteArray ba_uncompressed = qUncompress(ba); QByteArray ba_uncompressed = qUncompress(ba);
@@ -136,35 +124,22 @@ void ApiController::updateServerConfigFromApi()
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString(); auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer); serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
} else { } else {
QString err = reply->errorString(); QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll()); qDebug() << QString::fromUtf8(reply->readAll());
qDebug() << reply->error(); qDebug() << reply->error();
qDebug() << err; qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError)); return ErrorCode::ApiConfigDownloadError;
m_isConfigUpdateStarted = false;
return;
} }
} }
return ErrorCode::NoError;
emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
return;
}); });
}
QEventLoop wait;
void ApiController::clearApiConfig() connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
{ watcher.setFuture(future);
auto serverConfig = m_serversModel->getDefaultServerConfig(); wait.exec();
serverConfig.remove(config_key::dns1); return watcher.result();
serverConfig.remove(config_key::dns2);
serverConfig.remove(config_key::containers);
serverConfig.remove(config_key::hostName);
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
} }
@@ -4,26 +4,16 @@
#include <QObject> #include <QObject>
#include "configurators/openvpn_configurator.h" #include "configurators/openvpn_configurator.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
class ApiController : public QObject class ApiController : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ApiController(const QSharedPointer<ServersModel> &serversModel, explicit ApiController(QObject *parent = nullptr);
const QSharedPointer<ContainersModel> &containersModel, QObject *parent = nullptr);
public slots: public slots:
void updateServerConfigFromApi(); ErrorCode updateServerConfigFromApi(QJsonObject &serverConfig);
void clearApiConfig();
signals:
void updateStarted();
void updateFinished(bool isConfigUpdateStarted);
void errorOccurred(const QString &errorMessage);
private: private:
struct ApiPayloadData { struct ApiPayloadData {
@@ -36,11 +26,6 @@ private:
ApiPayloadData generateApiPayloadData(const QString &protocol); ApiPayloadData generateApiPayloadData(const QString &protocol);
QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData); QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData);
void processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config); void processApiConfig(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData, QString &config);
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
bool m_isConfigUpdateStarted = false;
}; };
#endif // APICONTROLLER_H #endif // APICONTROLLER_H
+7 -154
View File
@@ -29,8 +29,7 @@
#include "core/networkUtilities.h" #include "core/networkUtilities.h"
#include "settings.h" #include "settings.h"
#include "utilities.h" #include "utilities.h"
#include "vpnConfigurationController.h"
#include <configurators/vpn_configurator.h>
namespace namespace
{ {
@@ -179,11 +178,10 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
} }
QByteArray ServerController::getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials, QByteArray ServerController::getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &path, ErrorCode *errorCode) const QString &path, ErrorCode errorCode)
{ {
if (errorCode) errorCode = ErrorCode::NoError;
*errorCode = ErrorCode::NoError;
QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"") QString script = QString("sudo docker exec -i %1 sh -c \"xxd -p \'%2\'\"")
.arg(ContainerProps::containerToString(container)) .arg(ContainerProps::containerToString(container))
@@ -195,7 +193,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
return ErrorCode::NoError; return ErrorCode::NoError;
}; };
*errorCode = runScript(credentials, script, cbReadStdOut); errorCode = runScript(credentials, script, cbReadStdOut);
return QByteArray::fromHex(stdOut.toUtf8()); return QByteArray::fromHex(stdOut.toUtf8());
} }
@@ -498,7 +496,7 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
genVarsForScript(credentials, container, config)), genVarsForScript(credentials, container, config)),
cbReadStdOut, cbReadStdErr); cbReadStdOut, cbReadStdErr);
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut); VpnConfigurationsController::updateContainerConfigAfterInstallation(container, config, stdOut);
return e; return e;
} }
@@ -662,7 +660,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
return vars; return vars;
} }
QString ServerController::checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode) QString ServerController::checkSshConnection(const ServerCredentials &credentials, ErrorCode errorCode)
{ {
QString stdOut; QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) { auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -674,11 +672,7 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential
return ErrorCode::NoError; return ErrorCode::NoError;
}; };
ErrorCode e = errorCode = runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
if (errorCode)
*errorCode = e;
return stdOut; return stdOut;
} }
@@ -839,147 +833,6 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
return future.result(); return future.result();
} }
ErrorCode ServerController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
auto cbReadStdErr = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
QString script = QString("sudo docker ps --format '{{.Names}} {{.Ports}}'");
ErrorCode errorCode = runScript(credentials, script, cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
auto containersInfo = stdOut.split("\n");
for (auto &containerInfo : containersInfo) {
if (containerInfo.isEmpty()) {
continue;
}
const static QRegularExpression containerAndPortRegExp("(amnezia[-a-z]*).*?:([0-9]*)->[0-9]*/(udp|tcp).*");
QRegularExpressionMatch containerAndPortMatch = containerAndPortRegExp.match(containerInfo);
if (containerAndPortMatch.hasMatch()) {
QString name = containerAndPortMatch.captured(1);
QString port = containerAndPortMatch.captured(2);
QString transportProto = containerAndPortMatch.captured(3);
DockerContainer container = ContainerProps::containerFromString(name);
QJsonObject config;
Proto mainProto = ContainerProps::defaultProtocol(container);
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, port);
containerConfig.insert(config_key::transport_proto, transportProto);
if (protocol == Proto::Awg) {
QString serverConfig = getTextFileFromContainer(container, credentials, protocols::awg::serverConfigPath, &errorCode);
QMap<QString, QString> serverConfigMap;
auto serverConfigLines = serverConfig.split("\n");
for (auto &line : serverConfigLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
serverConfigMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
containerConfig[config_key::junkPacketCount] = serverConfigMap.value(config_key::junkPacketCount);
containerConfig[config_key::junkPacketMinSize] = serverConfigMap.value(config_key::junkPacketMinSize);
containerConfig[config_key::junkPacketMaxSize] = serverConfigMap.value(config_key::junkPacketMaxSize);
containerConfig[config_key::initPacketJunkSize] = serverConfigMap.value(config_key::initPacketJunkSize);
containerConfig[config_key::responsePacketJunkSize] = serverConfigMap.value(config_key::responsePacketJunkSize);
containerConfig[config_key::initPacketMagicHeader] = serverConfigMap.value(config_key::initPacketMagicHeader);
containerConfig[config_key::responsePacketMagicHeader] = serverConfigMap.value(config_key::responsePacketMagicHeader);
containerConfig[config_key::underloadPacketMagicHeader] = serverConfigMap.value(config_key::underloadPacketMagicHeader);
containerConfig[config_key::transportPacketMagicHeader] = serverConfigMap.value(config_key::transportPacketMagicHeader);
} else if (protocol == Proto::Sftp) {
stdOut.clear();
script = QString("sudo docker inspect --format '{{.Config.Cmd}}' %1").arg(name);
ErrorCode errorCode = runScript(credentials, script, cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
auto sftpInfo = stdOut.split(":");
if (sftpInfo.size() < 2) {
logger.error() << "Key parameters for the sftp container are missing";
continue;
}
auto userName = sftpInfo.at(0);
userName = userName.remove(0, 1);
auto password = sftpInfo.at(1);
containerConfig.insert(config_key::userName, userName);
containerConfig.insert(config_key::password, password);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
}
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
}
installedContainers.insert(container, config);
}
const static QRegularExpression torOrDnsRegExp("(amnezia-(?:torwebsite|dns)).*?([0-9]*)/(udp|tcp).*");
QRegularExpressionMatch torOrDnsRegMatch = torOrDnsRegExp.match(containerInfo);
if (torOrDnsRegMatch.hasMatch()) {
QString name = torOrDnsRegMatch.captured(1);
QString port = torOrDnsRegMatch.captured(2);
QString transportProto = torOrDnsRegMatch.captured(3);
DockerContainer container = ContainerProps::containerFromString(name);
QJsonObject config;
Proto mainProto = ContainerProps::defaultProtocol(container);
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, port);
containerConfig.insert(config_key::transport_proto, transportProto);
if (protocol == Proto::TorWebSite) {
stdOut.clear();
script = QString("sudo docker exec -i %1 sh -c 'cat /var/lib/tor/hidden_service/hostname'").arg(name);
ErrorCode errorCode = runScript(credentials, script, cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
if (stdOut.isEmpty()) {
logger.error() << "Key parameters for the tor container are missing";
continue;
}
QString onion = stdOut;
onion.replace("\n", "");
containerConfig.insert(config_key::site, onion);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
}
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
}
installedContainers.insert(container, config);
}
}
return ErrorCode::NoError;
}
ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey, ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
const std::function<QString()> &callback) const std::function<QString()> &callback)
{ {
+2 -5
View File
@@ -30,9 +30,6 @@ public:
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container, ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, QJsonObject &newConfig); const QJsonObject &oldConfig, QJsonObject &newConfig);
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers);
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject()); const QJsonObject &config = QJsonObject());
@@ -40,7 +37,7 @@ public:
DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path, DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path,
libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting); libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting);
QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials, QByteArray getTextFileFromContainer(DockerContainer container, const ServerCredentials &credentials,
const QString &path, ErrorCode *errorCode = nullptr); const QString &path, ErrorCode errorCode);
QString replaceVars(const QString &script, const Vars &vars); QString replaceVars(const QString &script, const Vars &vars);
Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None, Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None,
@@ -55,7 +52,7 @@ public:
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr, const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdOut = nullptr,
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr); const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr = nullptr);
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); QString checkSshConnection(const ServerCredentials &credentials, ErrorCode errorCode);
void cancelInstallation(); void cancelInstallation();
@@ -0,0 +1,137 @@
#include "vpnConfigurationController.h"
#include "configurators/awg_configurator.h"
#include "configurators/cloak_configurator.h"
#include "configurators/ikev2_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "configurators/xray_configurator.h"
VpnConfigurationsController::VpnConfigurationsController(const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject { parent }, m_settings(settings)
{
}
QScopedPointer<ConfiguratorBase> VpnConfigurationsController::createConfigurator(const Proto protocol)
{
switch (protocol) {
case Proto::OpenVpn: return QScopedPointer<ConfiguratorBase>(new OpenVpnConfigurator(m_settings));
case Proto::ShadowSocks: return QScopedPointer<ConfiguratorBase>(new ShadowSocksConfigurator(m_settings));
case Proto::Cloak: return QScopedPointer<ConfiguratorBase>(new CloakConfigurator(m_settings));
case Proto::WireGuard: return QScopedPointer<ConfiguratorBase>(new WireguardConfigurator(m_settings, false));
case Proto::Awg: return QScopedPointer<ConfiguratorBase>(new AwgConfigurator(m_settings));
case Proto::Ikev2: return QScopedPointer<ConfiguratorBase>(new Ikev2Configurator(m_settings));
case Proto::Xray: return QScopedPointer<ConfiguratorBase>(new XrayConfigurator(m_settings));
default: return QScopedPointer<ConfiguratorBase>();
}
}
ErrorCode VpnConfigurationsController::createProtocolConfigForContainer(const ServerCredentials &credentials,
const DockerContainer container, QJsonObject &containerConfig)
{
ErrorCode errorCode = ErrorCode::NoError;
if (ContainerProps::containerService(container) == ServiceType::Other) {
return errorCode;
}
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject protocolConfig = containerConfig.value(ProtocolProps::protoToString(protocol)).toObject();
auto configurator = createConfigurator(protocol);
QString protocolConfigString = configurator->createConfig(credentials, container, containerConfig, errorCode);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
protocolConfig.insert(config_key::last_config, protocolConfigString);
containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfig);
}
return errorCode;
}
ErrorCode VpnConfigurationsController::createProtocolConfigString(const bool isApiConfig, const QPair<QString, QString> &dns,
const ServerCredentials &credentials, const DockerContainer container,
const QJsonObject &containerConfig, const Proto protocol,
QString &protocolConfigString)
{
ErrorCode errorCode = ErrorCode::NoError;
if (ContainerProps::containerService(container) == ServiceType::Other) {
return errorCode;
}
auto configurator = createConfigurator(protocol);
protocolConfigString = configurator->createConfig(credentials, container, containerConfig, errorCode);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
protocolConfigString = configurator->processConfigWithExportSettings(dns, isApiConfig, protocolConfigString);
return errorCode;
}
QJsonObject VpnConfigurationsController::createVpnConfiguration(const QPair<QString, QString> &dns, const QJsonObject &serverConfig,
const QJsonObject &containerConfig, const DockerContainer container,
ErrorCode errorCode)
{
QJsonObject vpnConfiguration {};
if (ContainerProps::containerService(container) == ServiceType::Other) {
return vpnConfiguration;
}
bool isApiConfig = serverConfig.value(config_key::configVersion).toInt();
for (ProtocolEnumNS::Proto proto : ContainerProps::protocolsForContainer(container)) {
if (isApiConfig && container == DockerContainer::Cloak && proto == ProtocolEnumNS::Proto::ShadowSocks) {
continue;
}
QString protocolConfigString =
containerConfig.value(ProtocolProps::protoToString(proto)).toObject().value(config_key::last_config).toString();
auto configurator = createConfigurator(proto);
protocolConfigString = configurator->processConfigWithLocalSettings(dns, isApiConfig, protocolConfigString);
QJsonObject vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
vpnConfigData = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
vpnConfiguration.insert(ProtocolProps::key_proto_config_data(proto), vpnConfigData);
}
Proto proto = ContainerProps::defaultProtocol(container);
vpnConfiguration[config_key::vpnproto] = ProtocolProps::protoToString(proto);
vpnConfiguration[config_key::dns1] = dns.first;
vpnConfiguration[config_key::dns2] = dns.second;
vpnConfiguration[config_key::hostName] = serverConfig.value(config_key::hostName).toString();
vpnConfiguration[config_key::description] = serverConfig.value(config_key::description).toString();
vpnConfiguration[config_key::configVersion] = serverConfig.value(config_key::configVersion).toInt();
// TODO: try to get hostName, port, description for 3rd party configs
// vpnConfiguration[config_key::port] = ...;
return vpnConfiguration;
}
void VpnConfigurationsController::updateContainerConfigAfterInstallation(const DockerContainer container, QJsonObject &containerConfig,
const QString &stdOut)
{
Proto mainProto = ContainerProps::defaultProtocol(container);
if (container == DockerContainer::TorWebSite) {
QJsonObject protocol = containerConfig.value(ProtocolProps::protoToString(mainProto)).toObject();
qDebug() << "amnezia-tor onions" << stdOut;
QString onion = stdOut;
onion.replace("\n", "");
protocol.insert(config_key::site, onion);
containerConfig.insert(ProtocolProps::protoToString(mainProto), protocol);
}
}
@@ -0,0 +1,35 @@
#ifndef VPNCONFIGIRATIONSCONTROLLER_H
#define VPNCONFIGIRATIONSCONTROLLER_H
#include <QObject>
#include "configurators/configurator_base.h"
#include "containers/containers_defs.h"
#include "core/defs.h"
#include "settings.h"
class VpnConfigurationsController : public QObject
{
Q_OBJECT
public:
explicit VpnConfigurationsController(const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
public slots:
ErrorCode createProtocolConfigForContainer(const ServerCredentials &credentials, const DockerContainer container,
QJsonObject &containerConfig);
ErrorCode createProtocolConfigString(const bool isApiConfig, const QPair<QString, QString> &dns, const ServerCredentials &credentials,
const DockerContainer container, const QJsonObject &containerConfig, const Proto protocol,
QString &protocolConfigString);
QJsonObject createVpnConfiguration(const QPair<QString, QString> &dns, const QJsonObject &serverConfig,
const QJsonObject &containerConfig, const DockerContainer container, ErrorCode errorCode);
static void updateContainerConfigAfterInstallation(const DockerContainer container, QJsonObject &containerConfig, const QString &stdOut);
signals:
private:
QScopedPointer<ConfiguratorBase> createConfigurator(const Proto protocol);
std::shared_ptr<Settings> m_settings;
};
#endif // VPNCONFIGIRATIONSCONTROLLER_H
+14
View File
@@ -22,6 +22,20 @@ namespace amnezia
} }
}; };
struct InstalledAppInfo {
QString appName;
QString packageName;
QString appPath;
bool operator==(const InstalledAppInfo& other) const {
if (!packageName.isEmpty()) {
return packageName == other.packageName;
} else {
return appPath == other.appPath;
}
}
};
enum ErrorCode { enum ErrorCode {
// General error codes // General error codes
NoError = 0, NoError = 0,
@@ -0,0 +1,12 @@
#include "installedAppsImageProvider.h"
#include "platforms/android/android_controller.h"
InstalledAppsImageProvider::InstalledAppsImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}
QPixmap InstalledAppsImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
return AndroidController::instance()->getAppIcon(id, size, requestedSize);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef INSTALLEDAPPSIMAGEPROVIDER_H
#define INSTALLEDAPPSIMAGEPROVIDER_H
#include <QObject>
#include <QQuickImageProvider>
class InstalledAppsImageProvider : public QQuickImageProvider
{
public:
InstalledAppsImageProvider();
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
};
#endif // INSTALLEDAPPSIMAGEPROVIDER_H
+23
View File
@@ -10,6 +10,8 @@
#include <Iptypes.h> #include <Iptypes.h>
#include <WinSock2.h> #include <WinSock2.h>
#include <winsock.h> #include <winsock.h>
#include <QNetworkInterface>
#include "qendian.h"
#endif #endif
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
#include <arpa/inet.h> #include <arpa/inet.h>
@@ -159,6 +161,27 @@ bool NetworkUtilities::checkIpSubnetFormat(const QString &ip)
return false; return false;
} }
// static
int NetworkUtilities::AdapterIndexTo(const QHostAddress& dst) {
#ifdef Q_OS_WIN
qDebug() << "Getting Current Internet Adapter that routes to"
<< dst.toString();
quint32_be ipBigEndian;
quint32 ip = dst.toIPv4Address();
qToBigEndian(ip, &ipBigEndian);
_MIB_IPFORWARDROW routeInfo;
auto result = GetBestRoute(ipBigEndian, 0, &routeInfo);
if (result != NO_ERROR) {
return -1;
}
auto adapter =
QNetworkInterface::interfaceFromIndex(routeInfo.dwForwardIfIndex);
qDebug() << "Internet Adapter:" << adapter.name();
return routeInfo.dwForwardIfIndex;
#endif
return 0;
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
DWORD GetAdaptersAddressesWrapper(const ULONG Family, DWORD GetAdaptersAddressesWrapper(const ULONG Family,
const ULONG Flags, const ULONG Flags,
+4
View File
@@ -4,6 +4,8 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <QRegExp> #include <QRegExp>
#include <QString> #include <QString>
#include <QHostAddress>
class NetworkUtilities : public QObject class NetworkUtilities : public QObject
{ {
@@ -14,6 +16,8 @@ public:
static bool checkIPv4Format(const QString &ip); static bool checkIPv4Format(const QString &ip);
static bool checkIpSubnetFormat(const QString &ip); static bool checkIpSubnetFormat(const QString &ip);
static QString getGatewayAndIface(); static QString getGatewayAndIface();
// Returns the Interface Index that could Route to dst
static int AdapterIndexTo(const QHostAddress& dst);
static QRegularExpression ipAddressRegExp(); static QRegularExpression ipAddressRegExp();
static QRegularExpression ipAddressPortRegExp(); static QRegularExpression ipAddressPortRegExp();
+4 -2
View File
@@ -35,8 +35,10 @@ class Daemon : public QObject {
virtual QJsonObject getStatus(); virtual QJsonObject getStatus();
// Callback before any Activating measure is done // Callback before any Activating measure is done
virtual void prepareActivation(const InterfaceConfig& config){ virtual void prepareActivation(const InterfaceConfig& config, int inetAdapterIndex = 0) {
Q_UNUSED(config)}; Q_UNUSED(config) };
virtual void activateSplitTunnel(const InterfaceConfig& config, int vpnAdapterIndex = 0) {
Q_UNUSED(config) };
QString logs(); QString logs();
void cleanLogs(); void cleanLogs();
+4 -6
View File
@@ -117,6 +117,9 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
int splitTunnelType = rawConfig.value("splitTunnelType").toInt(); int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
QJsonArray splitTunnelSites = rawConfig.value("splitTunnelSites").toArray(); QJsonArray splitTunnelSites = rawConfig.value("splitTunnelSites").toArray();
int appSplitTunnelType = rawConfig.value(amnezia::config_key::appSplitTunnelType).toInt();
QJsonArray splitTunnelApps = rawConfig.value(amnezia::config_key::splitTunnelApps).toArray();
QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject(); QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject();
QJsonObject json; QJsonObject json;
@@ -217,12 +220,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
json.insert("excludedAddresses", jsExcludedAddresses); json.insert("excludedAddresses", jsExcludedAddresses);
json.insert("vpnDisabledApps", splitTunnelApps);
// QJsonArray splitTunnelApps;
// for (const auto& uri : hop.m_vpnDisabledApps) {
// splitTunnelApps.append(QJsonValue(uri));
// }
// json.insert("vpnDisabledApps", splitTunnelApps);
if (protocolName == amnezia::config_key::awg) { if (protocolName == amnezia::config_key::awg) {
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount)); json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
@@ -2,6 +2,9 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QQmlFile> #include <QQmlFile>
#include <QEventLoop> #include <QEventLoop>
#include <QImage>
#include <android/bitmap.h>
#include "android_controller.h" #include "android_controller.h"
#include "android_utils.h" #include "android_utils.h"
@@ -209,6 +212,51 @@ void AndroidController::setScreenshotsEnabled(bool enabled)
callActivityMethod("setScreenshotsEnabled", "(Z)V", enabled); callActivityMethod("setScreenshotsEnabled", "(Z)V", enabled);
} }
void AndroidController::minimizeApp()
{
callActivityMethod("minimizeApp", "()V");
}
QJsonArray AndroidController::getAppList()
{
QJniObject appList = callActivityMethod<jstring>("getAppList", "()Ljava/lang/String;");
QJsonArray jsonAppList = QJsonDocument::fromJson(appList.toString().toUtf8()).array();
return jsonAppList;
}
QPixmap AndroidController::getAppIcon(const QString &package, QSize *size, const QSize &requestedSize)
{
QJniObject bitmap = callActivityMethod<jobject>("getAppIcon", "(Ljava/lang/String;II)Landroid/graphics/Bitmap;",
QJniObject::fromString(package).object<jstring>(),
requestedSize.width(), requestedSize.height());
QJniEnvironment env;
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env.jniEnv(), bitmap.object(), &info) != ANDROID_BITMAP_RESULT_SUCCESS) return {};
void *pixels;
if (AndroidBitmap_lockPixels(env.jniEnv(), bitmap.object(), &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) return {};
int width = info.width;
int height = info.height;
size->setWidth(width);
size->setHeight(height);
QImage image(width, height, QImage::Format_RGBA8888);
if (info.stride == uint32_t(image.bytesPerLine())) {
memcpy((void *) image.constBits(), pixels, info.stride * height);
} else {
auto *bmpPtr = static_cast<uchar *>(pixels);
for (int i = 0; i < height; i++, bmpPtr += info.stride)
memcpy((void *) image.constScanLine(i), bmpPtr, width);
}
if (AndroidBitmap_unlockPixels(env.jniEnv(), bitmap.object()) != ANDROID_BITMAP_RESULT_SUCCESS) return {};
return QPixmap::fromImage(image);
}
// Moving log processing to the Android side // Moving log processing to the Android side
jclass AndroidController::log; jclass AndroidController::log;
jmethodID AndroidController::logDebug; jmethodID AndroidController::logDebug;
@@ -2,6 +2,7 @@
#define ANDROID_CONTROLLER_H #define ANDROID_CONTROLLER_H
#include <QJniObject> #include <QJniObject>
#include <QPixmap>
#include "protocols/vpnprotocol.h" #include "protocols/vpnprotocol.h"
@@ -40,6 +41,9 @@ public:
void exportLogsFile(const QString &fileName); void exportLogsFile(const QString &fileName);
void clearLogs(); void clearLogs();
void setScreenshotsEnabled(bool enabled); void setScreenshotsEnabled(bool enabled);
void minimizeApp();
QJsonArray getAppList();
QPixmap getAppIcon(const QString &package, QSize *size, const QSize &requestedSize);
static bool initLogging(); static bool initLogging();
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message); static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
@@ -18,6 +18,7 @@
#include "dnsutilswindows.h" #include "dnsutilswindows.h"
#include "leakdetector.h" #include "leakdetector.h"
#include "logger.h" #include "logger.h"
#include "core/networkUtilities.h"
#include "platforms/windows/windowscommons.h" #include "platforms/windows/windowscommons.h"
#include "platforms/windows/windowsservicemanager.h" #include "platforms/windows/windowsservicemanager.h"
#include "windowsfirewall.h" #include "windowsfirewall.h"
@@ -43,11 +44,24 @@ WindowsDaemon::~WindowsDaemon() {
logger.debug() << "Daemon released"; logger.debug() << "Daemon released";
} }
void WindowsDaemon::prepareActivation(const InterfaceConfig& config) { void WindowsDaemon::prepareActivation(const InterfaceConfig& config, int inetAdapterIndex) {
// Before creating the interface we need to check which adapter // Before creating the interface we need to check which adapter
// routes to the server endpoint // routes to the server endpoint
auto serveraddr = QHostAddress(config.m_serverIpv4AddrIn); if (inetAdapterIndex == 0) {
m_inetAdapterIndex = WindowsCommons::AdapterIndexTo(serveraddr); auto serveraddr = QHostAddress(config.m_serverIpv4AddrIn);
m_inetAdapterIndex = NetworkUtilities::AdapterIndexTo(serveraddr);
} else {
m_inetAdapterIndex = inetAdapterIndex;
}
}
void WindowsDaemon::activateSplitTunnel(const InterfaceConfig& config, int vpnAdapterIndex) {
if (config.m_vpnDisabledApps.length() > 0) {
m_splitTunnelManager.start(m_inetAdapterIndex, vpnAdapterIndex);
m_splitTunnelManager.setRules(config.m_vpnDisabledApps);
} else {
m_splitTunnelManager.stop();
}
} }
bool WindowsDaemon::run(Op op, const InterfaceConfig& config) { bool WindowsDaemon::run(Op op, const InterfaceConfig& config) {
@@ -64,12 +78,8 @@ bool WindowsDaemon::run(Op op, const InterfaceConfig& config) {
} }
} }
if (config.m_vpnDisabledApps.length() > 0) { activateSplitTunnel(config);
m_splitTunnelManager.start(m_inetAdapterIndex);
m_splitTunnelManager.setRules(config.m_vpnDisabledApps);
} else {
m_splitTunnelManager.stop();
}
return true; return true;
} }
@@ -20,7 +20,8 @@ class WindowsDaemon final : public Daemon {
WindowsDaemon(); WindowsDaemon();
~WindowsDaemon(); ~WindowsDaemon();
void prepareActivation(const InterfaceConfig& config) override; void prepareActivation(const InterfaceConfig& config, int inetAdapterIndex = 0) override;
void activateSplitTunnel(const InterfaceConfig& config, int vpnAdapterIndex = 0) override;
protected: protected:
bool run(Op op, const InterfaceConfig& config) override; bool run(Op op, const InterfaceConfig& config) override;
@@ -134,7 +134,7 @@ void WindowsSplitTunnel::setRules(const QStringList& appPaths) {
logger.debug() << "New Configuration applied: " << getState(); logger.debug() << "New Configuration applied: " << getState();
} }
void WindowsSplitTunnel::start(int inetAdapterIndex) { void WindowsSplitTunnel::start(int inetAdapterIndex, int vpnAdapterIndex) {
// To Start we need to send 2 things: // To Start we need to send 2 things:
// Network info (what is vpn what is network) // Network info (what is vpn what is network)
logger.debug() << "Starting SplitTunnel"; logger.debug() << "Starting SplitTunnel";
@@ -171,7 +171,7 @@ void WindowsSplitTunnel::start(int inetAdapterIndex) {
} }
logger.debug() << "Driver is ready || new State:" << getState(); logger.debug() << "Driver is ready || new State:" << getState();
auto config = generateIPConfiguration(inetAdapterIndex); auto config = generateIPConfiguration(inetAdapterIndex, vpnAdapterIndex);
auto ok = DeviceIoControl(m_driver, IOCTL_REGISTER_IP_ADDRESSES, &config[0], auto ok = DeviceIoControl(m_driver, IOCTL_REGISTER_IP_ADDRESSES, &config[0],
(DWORD)config.size(), nullptr, 0, &bytesReturned, (DWORD)config.size(), nullptr, 0, &bytesReturned,
nullptr); nullptr);
@@ -270,14 +270,19 @@ std::vector<uint8_t> WindowsSplitTunnel::generateAppConfiguration(
} }
std::vector<uint8_t> WindowsSplitTunnel::generateIPConfiguration( std::vector<uint8_t> WindowsSplitTunnel::generateIPConfiguration(
int inetAdapterIndex) { int inetAdapterIndex, int vpnAdapterIndex) {
std::vector<uint8_t> out(sizeof(IP_ADDRESSES_CONFIG)); std::vector<uint8_t> out(sizeof(IP_ADDRESSES_CONFIG));
auto config = reinterpret_cast<IP_ADDRESSES_CONFIG*>(&out[0]); auto config = reinterpret_cast<IP_ADDRESSES_CONFIG*>(&out[0]);
auto ifaces = QNetworkInterface::allInterfaces(); auto ifaces = QNetworkInterface::allInterfaces();
if (vpnAdapterIndex == 0) {
vpnAdapterIndex = WindowsCommons::VPNAdapterIndex();
}
// Always the VPN // Always the VPN
getAddress(WindowsCommons::VPNAdapterIndex(), &config->TunnelIpv4, getAddress(vpnAdapterIndex, &config->TunnelIpv4,
&config->TunnelIpv6); &config->TunnelIpv6);
// 2nd best route // 2nd best route
getAddress(inetAdapterIndex, &config->InternetIpv4, &config->InternetIpv6); getAddress(inetAdapterIndex, &config->InternetIpv4, &config->InternetIpv6);
@@ -132,7 +132,7 @@ class WindowsSplitTunnel final : public QObject {
void setRules(const QStringList& appPaths); void setRules(const QStringList& appPaths);
// Fetches and Pushed needed info to move to engaged mode // Fetches and Pushed needed info to move to engaged mode
void start(int inetAdapterIndex); void start(int inetAdapterIndex, int vpnAdapterIndex = 0);
// Deletes Rules and puts the driver into passive mode // Deletes Rules and puts the driver into passive mode
void stop(); void stop();
// Resets the Whole Driver // Resets the Whole Driver
@@ -164,7 +164,7 @@ class WindowsSplitTunnel final : public QObject {
// Generates a Configuration for Each APP // Generates a Configuration for Each APP
std::vector<uint8_t> generateAppConfiguration(const QStringList& appPaths); std::vector<uint8_t> generateAppConfiguration(const QStringList& appPaths);
// Generates a Configuration which IP's are VPN and which network // Generates a Configuration which IP's are VPN and which network
std::vector<uint8_t> generateIPConfiguration(int inetAdapterIndex); std::vector<uint8_t> generateIPConfiguration(int inetAdapterIndex, int vpnAdapterIndex = 0);
std::vector<uint8_t> generateProcessBlob(); std::vector<uint8_t> generateProcessBlob();
void getAddress(int adapterIndex, IN_ADDR* out_ipv4, IN6_ADDR* out_ipv6); void getAddress(int adapterIndex, IN_ADDR* out_ipv4, IN6_ADDR* out_ipv6);
@@ -88,24 +88,6 @@ QString WindowsCommons::tunnelLogFile() {
return QString(); return QString();
} }
// static
int WindowsCommons::AdapterIndexTo(const QHostAddress& dst) {
logger.debug() << "Getting Current Internet Adapter that routes to"
<< logger.sensitive(dst.toString());
quint32_be ipBigEndian;
quint32 ip = dst.toIPv4Address();
qToBigEndian(ip, &ipBigEndian);
_MIB_IPFORWARDROW routeInfo;
auto result = GetBestRoute(ipBigEndian, 0, &routeInfo);
if (result != NO_ERROR) {
return -1;
}
auto adapter =
QNetworkInterface::interfaceFromIndex(routeInfo.dwForwardIfIndex);
logger.debug() << "Internet Adapter:" << adapter.name();
return routeInfo.dwForwardIfIndex;
}
// static // static
int WindowsCommons::VPNAdapterIndex() { int WindowsCommons::VPNAdapterIndex() {
// For someReason QNetworkInterface::fromName(MozillaVPN) does not work >:( // For someReason QNetworkInterface::fromName(MozillaVPN) does not work >:(
+1 -2
View File
@@ -19,8 +19,7 @@ class WindowsCommons final {
// Returns the Interface Index of the VPN Adapter // Returns the Interface Index of the VPN Adapter
static int VPNAdapterIndex(); static int VPNAdapterIndex();
// Returns the Interface Index that could Route to dst
static int AdapterIndexTo(const QHostAddress& dst);
// Returns the Path of the Current process // Returns the Path of the Current process
static QString getCurrentPath(); static QString getCurrentPath();
}; };
+3
View File
@@ -331,13 +331,16 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
m_vpnLocalAddress = l.split(" ").at(1); m_vpnLocalAddress = l.split(" ").at(1);
m_vpnGateway = l.split(" ").at(2); m_vpnGateway = l.split(" ").at(2);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QThread::msleep(300);
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces(); QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
for (int i = 0; i < netInterfaces.size(); i++) { for (int i = 0; i < netInterfaces.size(); i++) {
for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++) for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++)
{ {
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway); m_configData.insert("vpnGateway", m_vpnGateway);
m_configData.insert("vpnServer", m_configData.value(amnezia::config_key::hostName).toString());
IpcClient::Interface()->enablePeerTraffic(m_configData); IpcClient::Interface()->enablePeerTraffic(m_configData);
} }
} }
+5
View File
@@ -89,8 +89,13 @@ namespace amnezia
constexpr char splitTunnelSites[] = "splitTunnelSites"; constexpr char splitTunnelSites[] = "splitTunnelSites";
constexpr char splitTunnelType[] = "splitTunnelType"; constexpr char splitTunnelType[] = "splitTunnelType";
constexpr char splitTunnelApps[] = "splitTunnelApps";
constexpr char appSplitTunnelType[] = "appSplitTunnelType";
constexpr char crc[] = "crc"; constexpr char crc[] = "crc";
constexpr char clientId[] = "clientId";
} }
namespace protocols namespace protocols
+3
View File
@@ -112,6 +112,7 @@ ErrorCode XrayProtocol::startTun2Sock()
m_t2sProcess->setProgram(PermittedProcess::Tun2Socks); m_t2sProcess->setProgram(PermittedProcess::Tun2Socks);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up", QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up",
QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255").arg(amnezia::protocols::xray::defaultLocalAddr)}); QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255").arg(amnezia::protocols::xray::defaultLocalAddr)});
#endif #endif
@@ -166,7 +167,9 @@ ErrorCode XrayProtocol::startTun2Sock()
{ {
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index()); IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway); m_configData.insert("vpnGateway", m_vpnGateway);
m_configData.insert("vpnServer", m_remoteAddress);
IpcClient::Interface()->enablePeerTraffic(m_configData); IpcClient::Interface()->enablePeerTraffic(m_configData);
} }
} }
+2
View File
@@ -234,6 +234,8 @@
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file> <file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>images/controls/split-tunneling.svg</file> <file>images/controls/split-tunneling.svg</file>
<file>ui/qml/Controls2/DrawerType2.qml</file> <file>ui/qml/Controls2/DrawerType2.qml</file>
<file>ui/qml/Pages2/PageSettingsAppSplitTunneling.qml</file>
<file>ui/qml/Components/InstalledAppsDrawer.qml</file>
<file>images/controls/alert-circle.svg</file> <file>images/controls/alert-circle.svg</file>
<file>images/controls/file-check-2.svg</file> <file>images/controls/file-check-2.svg</file>
<file>ui/qml/Controls2/WarningType.qml</file> <file>ui/qml/Controls2/WarningType.qml</file>
+7 -1
View File
@@ -16,6 +16,12 @@
using namespace QKeychain; using namespace QKeychain;
namespace {
constexpr auto settingsKeyTag{"settingsKeyTag"};
constexpr auto settingsIvTag{"settingsIvTag"};
constexpr auto keyChainName{"AmneziaVPN-Keychain"};
}
SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent) SecureQSettings::SecureQSettings(const QString &organization, const QString &application, QObject *parent)
: QObject { parent }, m_settings(organization, application, parent), encryptedKeys({ "Servers/serversList" }) : QObject { parent }, m_settings(organization, application, parent), encryptedKeys({ "Servers/serversList" })
{ {
@@ -50,7 +56,7 @@ QVariant SecureQSettings::value(const QString &key, const QVariant &defaultValue
// check if value is not encrypted, v. < 2.0.x // check if value is not encrypted, v. < 2.0.x
retVal = m_settings.value(key); retVal = m_settings.value(key);
if (retVal.isValid()) { if (retVal.isValid()) {
if (retVal.userType() == QVariant::ByteArray && retVal.toByteArray().mid(0, magicString.size()) == magicString) { if (retVal.userType() == QMetaType::QByteArray && retVal.toByteArray().mid(0, magicString.size()) == magicString) {
if (getEncKey().isEmpty() || getEncIv().isEmpty()) { if (getEncKey().isEmpty() || getEncIv().isEmpty()) {
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty"; qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
+1 -5
View File
@@ -8,10 +8,6 @@
#include "keychain.h" #include "keychain.h"
constexpr const char *settingsKeyTag = "settingsKeyTag";
constexpr const char *settingsIvTag = "settingsIvTag";
constexpr const char *keyChainName = "AmneziaVPN-Keychain";
class SecureQSettings : public QObject class SecureQSettings : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -44,7 +40,7 @@ public:
private: private:
QSettings m_settings; QSettings m_settings;
mutable QMap<QString, QVariant> m_cache; mutable QHash<QString, QVariant> m_cache;
QStringList encryptedKeys; // encode only key listed here QStringList encryptedKeys; // encode only key listed here
+48
View File
@@ -355,6 +355,54 @@ void Settings::clearSettings()
emit settingsCleared(); emit settingsCleared();
} }
QString Settings::appsRouteModeString(AppsRouteMode mode) const
{
switch (mode) {
case VpnAllApps: return "AllApps";
case VpnOnlyForwardApps: return "ForwardApps";
case VpnAllExceptApps: return "ExceptApps";
}
}
Settings::AppsRouteMode Settings::getAppsRouteMode() const
{
return static_cast<AppsRouteMode>(value("Conf/appsRouteMode", 0).toInt());
}
void Settings::setAppsRouteMode(AppsRouteMode mode)
{
setValue("Conf/appsRouteMode", mode);
}
QVector<InstalledAppInfo> Settings::getVpnApps(AppsRouteMode mode) const
{
QVector<InstalledAppInfo> apps;
auto appsArray = value("Conf/" + appsRouteModeString(mode)).toJsonArray();
for (const auto &app : appsArray) {
InstalledAppInfo appInfo;
appInfo.appName = app.toObject().value("appName").toString();
appInfo.packageName = app.toObject().value("packageName").toString();
appInfo.appPath = app.toObject().value("appPath").toString();
apps.push_back(appInfo);
}
return apps;
}
void Settings::setVpnApps(AppsRouteMode mode, const QVector<InstalledAppInfo> &apps)
{
QJsonArray appsArray;
for (const auto &app : apps) {
QJsonObject appInfo;
appInfo.insert("appName", app.appName);
appInfo.insert("packageName", app.packageName);
appInfo.insert("appPath", app.appPath);
appsArray.push_back(appInfo);
}
setValue("Conf/" + appsRouteModeString(mode), appsArray);
m_settings.sync();
}
ServerCredentials Settings::defaultServerCredentials() const ServerCredentials Settings::defaultServerCredentials() const
{ {
return serverCredentials(defaultServerIndex()); return serverCredentials(defaultServerIndex());
+15
View File
@@ -193,6 +193,21 @@ public:
void clearSettings(); void clearSettings();
enum AppsRouteMode {
VpnAllApps,
VpnOnlyForwardApps,
VpnAllExceptApps
};
Q_ENUM(AppsRouteMode)
QString appsRouteModeString(AppsRouteMode mode) const;
AppsRouteMode getAppsRouteMode() const;
void setAppsRouteMode(AppsRouteMode mode);
QVector<InstalledAppInfo> getVpnApps(AppsRouteMode mode) const;
void setVpnApps(AppsRouteMode mode, const QVector<InstalledAppInfo> &apps);
signals: signals:
void saveLogsChanged(bool enabled); void saveLogsChanged(bool enabled);
void screenshotsEnabledChanged(bool enabled); void screenshotsEnabledChanged(bool enabled);
@@ -0,0 +1,50 @@
#include "appSplitTunnelingController.h"
#include <QFileInfo>
#include "core/defs.h"
AppSplitTunnelingController::AppSplitTunnelingController(const std::shared_ptr<Settings> &settings,
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel, QObject *parent)
: QObject(parent), m_settings(settings), m_appSplitTunnelingModel(appSplitTunnelingModel)
{
}
void AppSplitTunnelingController::addApp(const QString &appPath)
{
InstalledAppInfo appInfo { "", "", appPath };
if (!appPath.isEmpty()) {
QFileInfo fileInfo(appPath);
appInfo.appName = fileInfo.fileName();
}
if (m_appSplitTunnelingModel->addApp(appInfo)) {
emit finished(tr("Application added: %1").arg(appInfo.appName));
} else {
emit errorOccurred(tr("The application has already been added"));
}
}
void AppSplitTunnelingController::addApps(QVector<QPair<QString, QString>> apps)
{
qDebug() << apps;
for (const auto &app : apps) {
InstalledAppInfo appInfo { app.first, app.second, "" };
m_appSplitTunnelingModel->addApp(appInfo);
}
emit finished(tr("The selected applications have been added"));
}
void AppSplitTunnelingController::removeApp(const int index)
{
auto modelIndex = m_appSplitTunnelingModel->index(index);
auto appPath = m_appSplitTunnelingModel->data(modelIndex, AppSplitTunnelingModel::Roles::AppPathRole).toString();
m_appSplitTunnelingModel->removeApp(modelIndex);
QFileInfo fileInfo(appPath);
emit finished(tr("Application removed: %1").arg(fileInfo.fileName()));
}
@@ -0,0 +1,31 @@
#ifndef APPSPLITTUNNELINGCONTROLLER_H
#define APPSPLITTUNNELINGCONTROLLER_H
#include <QObject>
#include "settings.h"
#include "ui/models/appSplitTunnelingModel.h"
class AppSplitTunnelingController : public QObject
{
Q_OBJECT
public:
explicit AppSplitTunnelingController(const std::shared_ptr<Settings> &settings,
const QSharedPointer<AppSplitTunnelingModel> &sitesModel, QObject *parent = nullptr);
public slots:
void addApp(const QString &appPath);
void addApps(QVector<QPair<QString, QString>> apps);
void removeApp(const int index);
signals:
void errorOccurred(const QString &errorMessage);
void finished(const QString &message);
private:
std::shared_ptr<Settings> m_settings;
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
};
#endif // APPSPLITTUNNELINGCONTROLLER_H
+108 -9
View File
@@ -5,13 +5,23 @@
#else #else
#include <QApplication> #include <QApplication>
#endif #endif
#include <QtConcurrent>
#include "core/controllers/apiController.h"
#include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h" #include "core/errorstrings.h"
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel, ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<VpnConnection> &vpnConnection, QObject *parent) const QSharedPointer<ClientManagementModel> &clientManagementModel,
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_vpnConnection(vpnConnection) const QSharedPointer<VpnConnection> &vpnConnection,
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent),
m_serversModel(serversModel),
m_containersModel(containersModel),
m_clientManagementModel(clientManagementModel),
m_vpnConnection(vpnConnection),
m_settings(settings)
{ {
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, this, connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, this,
&ConnectionController::onConnectionStateChanged); &ConnectionController::onConnectionStateChanged);
@@ -26,16 +36,31 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
void ConnectionController::openConnection() void ConnectionController::openConnection()
{ {
int serverIndex = m_serversModel->getDefaultServerIndex(); int serverIndex = m_serversModel->getDefaultServerIndex();
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
ErrorCode errorCode = ErrorCode::NoError;
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Preparing);
if (serverConfig.value(config_key::configVersion).toInt()
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
ApiController apiController;
errorCode = apiController.updateServerConfigFromApi(serverConfig);
if (errorCode != ErrorCode::NoError) {
emit connectionErrorOccurred(errorString(errorCode));
return;
}
m_serversModel->editServer(serverConfig, serverIndex);
}
if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) { if (!m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
emit noInstalledContainers(); emit noInstalledContainers();
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
return; return;
} }
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); DockerContainer container =
qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container);
if (container == DockerContainer::None) { if (container == DockerContainer::None) {
emit connectionErrorOccurred(tr("VPN Protocols is not installed.\n Please install VPN container at first")); emit connectionErrorOccurred(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
@@ -44,7 +69,27 @@ void ConnectionController::openConnection()
qApp->processEvents(); qApp->processEvents();
emit connectToVpn(serverIndex, credentials, container, containerConfig); VpnConfigurationsController vpnConfigurationController(m_settings);
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
errorCode = updateProtocolConfig(container, credentials, containerConfig);
if (errorCode != ErrorCode::NoError) {
emit connectionErrorOccurred(errorString(errorCode));
return;
}
auto dns = m_serversModel->getDnsPair(serverIndex);
serverConfig = m_serversModel->getServerConfig(serverIndex);
auto vpnConfiguration =
vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container, errorCode);
if (errorCode != ErrorCode::NoError) {
emit connectionErrorOccurred(tr("unable to create configuration"));
return;
}
emit connectToVpn(serverIndex, credentials, container, vpnConfiguration);
} }
void ConnectionController::closeConnection() void ConnectionController::closeConnection()
@@ -91,6 +136,7 @@ void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
} }
case Vpn::ConnectionState::Preparing: { case Vpn::ConnectionState::Preparing: {
m_isConnectionInProgress = true; m_isConnectionInProgress = true;
m_connectionStateText = tr("Preparing...");
break; break;
} }
case Vpn::ConnectionState::Error: { case Vpn::ConnectionState::Error: {
@@ -135,9 +181,14 @@ QString ConnectionController::connectionStateText() const
return m_connectionStateText; return m_connectionStateText;
} }
void ConnectionController::toggleConnection(bool skipConnectionInProgressCheck) void ConnectionController::toggleConnection()
{ {
if (!skipConnectionInProgressCheck && isConnectionInProgress()) { if (m_state == Vpn::ConnectionState::Preparing) {
emit preparingConfig();
return;
}
if (isConnectionInProgress()) {
closeConnection(); closeConnection();
} else if (isConnected()) { } else if (isConnected()) {
closeConnection(); closeConnection();
@@ -155,3 +206,51 @@ bool ConnectionController::isConnected() const
{ {
return m_isConnected; return m_isConnected;
} }
bool ConnectionController::isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container)
{
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
QString protocolConfig = containerConfig.value(ProtocolProps::protoToString(protocol))
.toObject()
.value(config_key::last_config)
.toString();
if (protocolConfig.isEmpty()) {
return false;
}
}
return true;
}
ErrorCode ConnectionController::updateProtocolConfig(const DockerContainer container,
const ServerCredentials &credentials, QJsonObject &containerConfig)
{
QFutureWatcher<ErrorCode> watcher;
QFuture<ErrorCode> future = QtConcurrent::run([this, container, &credentials, &containerConfig]() {
ErrorCode errorCode = ErrorCode::NoError;
if (!isProtocolConfigExists(containerConfig, container)) {
VpnConfigurationsController vpnConfigurationController(m_settings);
errorCode =
vpnConfigurationController.createProtocolConfigForContainer(credentials, container, containerConfig);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
m_serversModel->updateContainerConfig(container, containerConfig);
errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig,
QString("Admin [%1]").arg(QSysInfo::prettyProductName()));
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
}
return errorCode;
});
QEventLoop wait;
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
watcher.setFuture(future);
wait.exec();
return watcher.result();
}
+16 -3
View File
@@ -2,6 +2,7 @@
#define CONNECTIONCONTROLLER_H #define CONNECTIONCONTROLLER_H
#include "protocols/vpnprotocol.h" #include "protocols/vpnprotocol.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/servers_model.h" #include "ui/models/servers_model.h"
#include "vpnconnection.h" #include "vpnconnection.h"
@@ -17,7 +18,9 @@ public:
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel, explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<VpnConnection> &vpnConnection, QObject *parent = nullptr); const QSharedPointer<ClientManagementModel> &clientManagementModel,
const QSharedPointer<VpnConnection> &vpnConnection,
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
~ConnectionController() = default; ~ConnectionController() = default;
@@ -26,7 +29,7 @@ public:
QString connectionStateText() const; QString connectionStateText() const;
public slots: public slots:
void toggleConnection(bool skipConnectionInProgressCheck); void toggleConnection();
void openConnection(); void openConnection();
void closeConnection(); void closeConnection();
@@ -38,9 +41,12 @@ public slots:
void onTranslationsUpdated(); void onTranslationsUpdated();
ErrorCode updateProtocolConfig(const DockerContainer container, const ServerCredentials &credentials,
QJsonObject &containerConfig);
signals: signals:
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig); const QJsonObject &vpnConfiguration);
void disconnectFromVpn(); void disconnectFromVpn();
void connectionStateChanged(); void connectionStateChanged();
@@ -49,14 +55,21 @@ signals:
void noInstalledContainers(); void noInstalledContainers();
void connectButtonClicked();
void preparingConfig();
private: private:
Vpn::ConnectionState getCurrentConnectionState(); Vpn::ConnectionState getCurrentConnectionState();
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
QSharedPointer<VpnConnection> m_vpnConnection; QSharedPointer<VpnConnection> m_vpnConnection;
std::shared_ptr<Settings> m_settings;
bool m_isConnected = false; bool m_isConnected = false;
bool m_isConnectionInProgress = false; bool m_isConnectionInProgress = false;
QString m_connectionStateText = tr("Connect"); QString m_connectionStateText = tr("Connect");
+96 -172
View File
@@ -8,11 +8,7 @@
#include <QImage> #include <QImage>
#include <QStandardPaths> #include <QStandardPaths>
#include "configurators/awg_configurator.h" #include "core/controllers/vpnConfigurationController.h"
#include "configurators/cloak_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h" #include "core/errorstrings.h"
#include "systemController.h" #include "systemController.h"
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
@@ -20,25 +16,20 @@
#endif #endif
#include "qrcodegen.hpp" #include "qrcodegen.hpp"
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel, ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel, const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings, const std::shared_ptr<Settings> &settings, QObject *parent)
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent)
: QObject(parent), : QObject(parent),
m_serversModel(serversModel), m_serversModel(serversModel),
m_containersModel(containersModel), m_containersModel(containersModel),
m_clientManagementModel(clientManagementModel), m_clientManagementModel(clientManagementModel),
m_settings(settings), m_settings(settings)
m_configurator(configurator)
{ {
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
m_authResultNotifier.reset(new AuthResultNotifier); m_authResultNotifier.reset(new AuthResultNotifier);
m_authResultReceiver.reset(new AuthResultReceiver(m_authResultNotifier)); m_authResultReceiver.reset(new AuthResultReceiver(m_authResultNotifier));
connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this, connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this, [this]() { emit exportErrorOccurred(tr("Access error!")); });
[this]() { emit exportErrorOccurred(tr("Access error!")); }); connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this, &ExportController::generateFullAccessConfig);
connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this,
&ExportController::generateFullAccessConfig);
#endif #endif
} }
@@ -47,9 +38,9 @@ void ExportController::generateFullAccessConfig()
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QJsonObject config = m_settings->server(serverIndex); QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
QJsonArray containers = config.value(config_key::containers).toArray(); QJsonArray containers = serverConfig.value(config_key::containers).toArray();
for (auto i = 0; i < containers.size(); i++) { for (auto i = 0; i < containers.size(); i++) {
auto containerConfig = containers.at(i).toObject(); auto containerConfig = containers.at(i).toObject();
auto containerType = ContainerProps::containerFromString(containerConfig.value(config_key::container).toString()); auto containerType = ContainerProps::containerFromString(containerConfig.value(config_key::container).toString());
@@ -63,13 +54,11 @@ void ExportController::generateFullAccessConfig()
containers.replace(i, containerConfig); containers.replace(i, containerConfig);
} }
config[config_key::containers] = containers; serverConfig[config_key::containers] = containers;
QByteArray compressedConfig = QJsonDocument(config).toJson(); QByteArray compressedConfig = QJsonDocument(serverConfig).toJson();
compressedConfig = qCompress(compressedConfig, 8); compressedConfig = qCompress(compressedConfig, 8);
m_config = QString("vpn://%1") m_config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
.arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding
| QByteArray::OmitTrailingEquals)));
m_qrCodes = generateQrCodeImageSeries(compressedConfig); m_qrCodes = generateQrCodeImageSeries(compressedConfig);
emit exportConfigChanged(); emit exportConfigChanged();
@@ -83,8 +72,7 @@ void ExportController::generateFullAccessConfigAndroid()
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;"); auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
if (appContext.isValid()) { if (appContext.isValid()) {
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent", auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
"(Landroid/content/Context;)Landroid/content/Intent;", "(Landroid/content/Context;)Landroid/content/Intent;", appContext.object());
appContext.object());
if (intent.isValid()) { if (intent.isValid()) {
if (intent.object<jobject>() != nullptr) { if (intent.object<jobject>() != nullptr) {
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, m_authResultReceiver.get()); QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, m_authResultReceiver.get());
@@ -103,116 +91,108 @@ void ExportController::generateConnectionConfig(const QString &clientName)
int serverIndex = m_serversModel->getProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex()); DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container); QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError; VpnConfigurationsController vpnConfigurationController(m_settings);
for (Proto protocol : ContainerProps::protocolsForContainer(container)) { ErrorCode errorCode = vpnConfigurationController.createProtocolConfigForContainer(credentials, container, containerConfig);
QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol);
QString clientId; errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig, clientName);
QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, if (errorCode != ErrorCode::NoError) {
clientId, &errorCode); emit exportErrorOccurred(errorString(errorCode));
if (errorCode) { return;
emit exportErrorOccurred(errorString(errorCode));
return;
}
protocolConfig.insert(config_key::last_config, vpnConfig);
containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfig);
if (protocol == Proto::OpenVpn || protocol == Proto::Awg || protocol == Proto::WireGuard) {
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
}
} }
QJsonObject config = m_settings->server(serverIndex); // todo change to servers_model QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
if (!errorCode) { if (!errorCode) {
config.remove(config_key::userName); serverConfig.remove(config_key::userName);
config.remove(config_key::password); serverConfig.remove(config_key::password);
config.remove(config_key::port); serverConfig.remove(config_key::port);
config.insert(config_key::containers, QJsonArray { containerConfig }); serverConfig.insert(config_key::containers, QJsonArray { containerConfig });
config.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
auto dns = m_configurator->getDnsForConfig(serverIndex); auto dns = m_serversModel->getDnsPair(serverIndex);
config.insert(config_key::dns1, dns.first); serverConfig.insert(config_key::dns1, dns.first);
config.insert(config_key::dns2, dns.second); serverConfig.insert(config_key::dns2, dns.second);
} }
QByteArray compressedConfig = QJsonDocument(config).toJson(); QByteArray compressedConfig = QJsonDocument(serverConfig).toJson();
compressedConfig = qCompress(compressedConfig, 8); compressedConfig = qCompress(compressedConfig, 8);
m_config = QString("vpn://%1") m_config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
.arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding
| QByteArray::OmitTrailingEquals)));
m_qrCodes = generateQrCodeImageSeries(compressedConfig); m_qrCodes = generateQrCodeImageSeries(compressedConfig);
emit exportConfigChanged(); emit exportConfigChanged();
} }
void ExportController::generateOpenVpnConfig(const QString &clientName) ErrorCode ExportController::generateNativeConfig(const DockerContainer container, const QString &clientName, const Proto &protocol,
QJsonObject &jsonNativeConfig)
{ {
clearPreviousConfig(); clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex); ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
auto dns = m_serversModel->getDnsPair(serverIndex);
bool isApiConfig = qvariant_cast<bool>(m_serversModel->data(serverIndex, ServersModel::IsServerFromApiRole));
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container); QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
VpnConfigurationsController vpnConfigurationController(m_settings);
QString protocolConfigString;
ErrorCode errorCode = vpnConfigurationController.createProtocolConfigString(isApiConfig, dns, credentials, container, containerConfig,
protocol, protocolConfigString);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
jsonNativeConfig = QJsonDocument::fromJson(protocolConfigString.toUtf8()).object();
if (protocol == Proto::OpenVpn || protocol == Proto::WireGuard || protocol == Proto::Awg) {
auto clientId = jsonNativeConfig.value(config_key::clientId).toString();
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
}
return errorCode;
}
void ExportController::generateOpenVpnConfig(const QString &clientName)
{
QJsonObject nativeConfig;
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
ErrorCode errorCode = ErrorCode::NoError; ErrorCode errorCode = ErrorCode::NoError;
QString clientId;
QString config = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, if (container == DockerContainer::Cloak || container == DockerContainer::ShadowSocks) {
clientId, &errorCode); errorCode = generateNativeConfig(container, clientName, Proto::OpenVpn, nativeConfig);
} else {
errorCode = generateNativeConfig(container, clientName, ContainerProps::defaultProtocol(container), nativeConfig);
}
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
return; return;
} }
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object(); QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8());
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged(); emit exportConfigChanged();
} }
void ExportController::generateWireGuardConfig(const QString &clientName) void ExportController::generateWireGuardConfig(const QString &clientName)
{ {
clearPreviousConfig(); QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::WireGuard, clientName, Proto::WireGuard, nativeConfig);
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
QString clientId;
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
return; return;
} }
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object(); QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -220,38 +200,19 @@ void ExportController::generateWireGuardConfig(const QString &clientName)
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW); qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1))); m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged(); emit exportConfigChanged();
} }
void ExportController::generateAwgConfig(const QString &clientName) void ExportController::generateAwgConfig(const QString &clientName)
{ {
clearPreviousConfig(); QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Awg, clientName, Proto::Awg, nativeConfig);
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
QString clientId;
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->awgConfigurator->genAwgConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
return; return;
} }
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Awg, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object(); QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -259,42 +220,34 @@ void ExportController::generateAwgConfig(const QString &clientName)
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW); qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1))); m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged(); emit exportConfigChanged();
} }
void ExportController::generateShadowSocksConfig() void ExportController::generateShadowSocksConfig()
{ {
clearPreviousConfig(); QJsonObject nativeConfig;
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError; ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container,
containerConfig, &errorCode);
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::ShadowSocks, config); if (container == DockerContainer::Cloak) {
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object(); errorCode = generateNativeConfig(container, "", Proto::ShadowSocks, nativeConfig);
} else {
errorCode = generateNativeConfig(container, "", ContainerProps::defaultProtocol(container), nativeConfig);
}
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n"); if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
for (const QString &line : lines) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
m_nativeConfigString = m_nativeConfigString = QString("%1:%2@%3:%4")
QString("%1:%2@%3:%4") .arg(nativeConfig.value("method").toString(), nativeConfig.value("password").toString(),
.arg(configJson.value("method").toString(), configJson.value("password").toString(), nativeConfig.value("server").toString(), nativeConfig.value("server_port").toString());
configJson.value("server").toString(), configJson.value("server_port").toString());
m_nativeConfigString = "ss://" + m_nativeConfigString.toUtf8().toBase64(); m_nativeConfigString = "ss://" + m_nativeConfigString.toUtf8().toBase64();
@@ -306,30 +259,17 @@ void ExportController::generateShadowSocksConfig()
void ExportController::generateCloakConfig() void ExportController::generateCloakConfig()
{ {
clearPreviousConfig(); QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Cloak, "", Proto::Cloak, nativeConfig);
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config =
m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
return; return;
} }
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Cloak, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
configJson.remove(config_key::transport_proto); nativeConfig.remove(config_key::transport_proto);
configJson.insert("ProxyMethod", "shadowsocks"); nativeConfig.insert("ProxyMethod", "shadowsocks");
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n"); QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
for (const QString &line : lines) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -339,29 +279,14 @@ void ExportController::generateCloakConfig()
void ExportController::generateXrayConfig() void ExportController::generateXrayConfig()
{ {
clearPreviousConfig(); QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig);
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString clientId;
QString config =
m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, Proto::Xray, clientId, &errorCode);
if (errorCode) { if (errorCode) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
return; return;
} }
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Xray, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n"); QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
for (const QString &line : lines) { for (const QString &line : lines) {
m_config.append(line + "\n"); m_config.append(line + "\n");
} }
@@ -399,8 +324,7 @@ void ExportController::updateClientManagementModel(const DockerContainer contain
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials) void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
{ {
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials, ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex());
m_serversModel->getProcessedServerIndex());
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode)); emit exportErrorOccurred(errorString(errorCode));
} }
+7 -8
View File
@@ -3,10 +3,9 @@
#include <QObject> #include <QObject>
#include "configurators/vpn_configurator.h" #include "ui/models/clientManagementModel.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/servers_model.h" #include "ui/models/servers_model.h"
#include "ui/models/clientManagementModel.h"
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include "platforms/android/authResultReceiver.h" #include "platforms/android/authResultReceiver.h"
#endif #endif
@@ -15,11 +14,9 @@ class ExportController : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ExportController(const QSharedPointer<ServersModel> &serversModel, explicit ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ClientManagementModel> &clientManagementModel, const std::shared_ptr<Settings> &settings,
const QSharedPointer<ClientManagementModel> &clientManagementModel, QObject *parent = nullptr);
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent = nullptr);
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged) Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged)
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged) Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged)
@@ -65,11 +62,13 @@ private:
void clearPreviousConfig(); void clearPreviousConfig();
ErrorCode generateNativeConfig(const DockerContainer container, const QString &clientName, const Proto &protocol,
QJsonObject &jsonNativeConfig);
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel; QSharedPointer<ClientManagementModel> m_clientManagementModel;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
QString m_config; QString m_config;
QString m_nativeConfigString; QString m_nativeConfigString;
+327 -118
View File
@@ -4,11 +4,13 @@
#include <QDir> #include <QDir>
#include <QEventLoop> #include <QEventLoop>
#include <QJsonObject> #include <QJsonObject>
#include <QStandardPaths>
#include <QRandomGenerator> #include <QRandomGenerator>
#include <QStandardPaths>
#include "core/errorstrings.h"
#include "core/controllers/serverController.h" #include "core/controllers/serverController.h"
#include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
#include "logger.h"
#include "core/networkUtilities.h" #include "core/networkUtilities.h"
#include "utilities.h" #include "utilities.h"
#include "ui/models/protocols/awgConfigModel.h" #include "ui/models/protocols/awgConfigModel.h"
@@ -16,6 +18,8 @@
namespace namespace
{ {
Logger logger("ServerController");
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
QString getNextDriverLetter() QString getNextDriverLetter()
{ {
@@ -42,14 +46,15 @@ namespace
#endif #endif
} }
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel, InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ProtocolsModel> &protocolsModel, const QSharedPointer<ProtocolsModel> &protocolsModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings, QObject *parent) const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent), : QObject(parent),
m_serversModel(serversModel), m_serversModel(serversModel),
m_containersModel(containersModel), m_containersModel(containersModel),
m_protocolModel(protocolsModel), m_protocolModel(protocolsModel),
m_clientManagementModel(clientManagementModel),
m_settings(settings) m_settings(settings)
{ {
} }
@@ -74,8 +79,7 @@ void InstallController::install(DockerContainer container, int port, TransportPr
if (protocol == mainProto) { if (protocol == mainProto) {
containerConfig.insert(config_key::port, QString::number(port)); containerConfig.insert(config_key::port, QString::number(port));
containerConfig.insert(config_key::transport_proto, containerConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, protocol));
ProtocolProps::transportProtoToString(transportProto, protocol));
if (container == DockerContainer::Awg) { if (container == DockerContainer::Awg) {
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(3, 10)); QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(3, 10));
@@ -107,9 +111,7 @@ void InstallController::install(DockerContainer container, int port, TransportPr
containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader; containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader;
containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader; containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader;
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader; containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
} } else if (container == DockerContainer::Sftp) {
if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName); containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(10)); containerConfig.insert(config_key::password, Utils::getRandomString(10));
} }
@@ -119,109 +121,132 @@ void InstallController::install(DockerContainer container, int port, TransportPr
config.insert(ProtocolProps::protoToString(protocol), containerConfig); config.insert(ProtocolProps::protoToString(protocol), containerConfig);
} }
ServerCredentials serverCredentials;
if (m_shouldCreateServer) { if (m_shouldCreateServer) {
if (isServerAlreadyExists()) { if (isServerAlreadyExists()) {
return; return;
} }
installServer(container, config); serverCredentials = m_processedServerCredentials;
} else { } else {
installContainer(container, config); int serverIndex = m_serversModel->getProcessedServerIndex();
serverCredentials = qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
} }
}
void InstallController::installServer(DockerContainer container, QJsonObject &config)
{
ServerController serverController(m_settings); ServerController serverController(m_settings);
connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy); connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy);
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation); connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
QMap<DockerContainer, QJsonObject> installedContainers; QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode = ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, installedContainers);
serverController.getAlreadyInstalledContainers(m_currentlyInstalledServerCredentials, installedContainers); if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
QString finishMessage = "";
if (!installedContainers.contains(container)) {
errorCode = serverController.setupContainer(m_currentlyInstalledServerCredentials, container, config);
installedContainers.insert(container, config);
finishMessage = tr("%1 installed successfully. ").arg(ContainerProps::containerHumanNames().value(container));
} else {
finishMessage = tr("%1 is already installed on the server. ").arg(ContainerProps::containerHumanNames().value(container));
}
if (installedContainers.size() > 1) {
finishMessage += tr("\nAdded containers that were already installed on the server");
}
if (errorCode == ErrorCode::NoError) {
QJsonObject server;
server.insert(config_key::hostName, m_currentlyInstalledServerCredentials.hostName);
server.insert(config_key::userName, m_currentlyInstalledServerCredentials.userName);
server.insert(config_key::password, m_currentlyInstalledServerCredentials.secretData);
server.insert(config_key::port, m_currentlyInstalledServerCredentials.port);
server.insert(config_key::description, m_settings->nextAvailableServerName());
QJsonArray containerConfigs;
for (const QJsonObject &containerConfig : qAsConst(installedContainers)) {
containerConfigs.append(containerConfig);
}
server.insert(config_key::containers, containerConfigs);
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
m_serversModel->addServer(server);
emit installServerFinished(finishMessage);
return; return;
} }
emit installationErrorOccurred(errorString(errorCode));
}
void InstallController::installContainer(DockerContainer container, QJsonObject &config)
{
int serverIndex = m_serversModel->getProcessedServerIndex();
ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
ServerController serverController(m_settings);
connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy);
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode = serverController.getAlreadyInstalledContainers(serverCredentials, installedContainers);
QString finishMessage = ""; QString finishMessage = "";
if (!installedContainers.contains(container)) { if (!installedContainers.contains(container)) {
errorCode = serverController.setupContainer(serverCredentials, container, config); errorCode = serverController.setupContainer(serverCredentials, container, config);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
installedContainers.insert(container, config); installedContainers.insert(container, config);
finishMessage = tr("%1 installed successfully. ").arg(ContainerProps::containerHumanNames().value(container)); finishMessage = tr("%1 installed successfully. ").arg(ContainerProps::containerHumanNames().value(container));
} else { } else {
finishMessage = tr("%1 is already installed on the server. ").arg(ContainerProps::containerHumanNames().value(container)); finishMessage = tr("%1 is already installed on the server. ").arg(ContainerProps::containerHumanNames().value(container));
} }
bool isInstalledContainerAddedToGui = false; if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
if (errorCode == ErrorCode::NoError) {
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
QJsonObject containerConfig = m_containersModel->getContainerConfig(iterator.key());
if (containerConfig.isEmpty()) {
m_serversModel->addContainerConfig(iterator.key(), iterator.value());
if (container != iterator.key()) { // skip the newly installed container
isInstalledContainerAddedToGui = true;
}
}
}
if (isInstalledContainerAddedToGui) {
finishMessage += tr("\nAlready installed containers were found on the server. "
"All installed containers have been added to the application");
}
emit installContainerFinished(finishMessage, ContainerProps::containerService(container) == ServiceType::Other);
return; return;
} }
emit installationErrorOccurred(errorString(errorCode)); if (m_shouldCreateServer) {
installServer(container, installedContainers, serverCredentials, finishMessage);
} else {
installContainer(container, installedContainers, serverCredentials, finishMessage);
}
}
void InstallController::installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials, QString &finishMessage)
{
if (installedContainers.size() > 1) {
finishMessage += tr("\nAdded containers that were already installed on the server");
}
QJsonObject server;
server.insert(config_key::hostName, m_processedServerCredentials.hostName);
server.insert(config_key::userName, m_processedServerCredentials.userName);
server.insert(config_key::password, m_processedServerCredentials.secretData);
server.insert(config_key::port, m_processedServerCredentials.port);
server.insert(config_key::description, m_settings->nextAvailableServerName());
QJsonArray containerConfigs;
VpnConfigurationsController vpnConfigurationController(m_settings);
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
auto containerConfig = iterator.value();
auto errorCode =
vpnConfigurationController.createProtocolConfigForContainer(m_processedServerCredentials, iterator.key(), containerConfig);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
containerConfigs.append(containerConfig);
errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig,
QString("Admin [%1]").arg(QSysInfo::prettyProductName()));
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
}
server.insert(config_key::containers, containerConfigs);
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
m_serversModel->addServer(server);
emit installServerFinished(finishMessage);
}
void InstallController::installContainer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials, QString &finishMessage)
{
bool isInstalledContainerAddedToGui = false;
VpnConfigurationsController vpnConfigurationController(m_settings);
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
QJsonObject containerConfig = m_containersModel->getContainerConfig(iterator.key());
if (containerConfig.isEmpty()) {
containerConfig = iterator.value();
auto errorCode = vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, iterator.key(), containerConfig);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
m_serversModel->addContainerConfig(iterator.key(), containerConfig);
errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig,
QString("Admin [%1]").arg(QSysInfo::prettyProductName()));
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
if (container != iterator.key()) { // skip the newly installed container
isInstalledContainerAddedToGui = true;
}
}
}
if (isInstalledContainerAddedToGui) {
finishMessage += tr("\nAlready installed containers were found on the server. "
"All installed containers have been added to the application");
}
emit installContainerFinished(finishMessage, ContainerProps::containerService(container) == ServiceType::Other);
} }
bool InstallController::isServerAlreadyExists() bool InstallController::isServerAlreadyExists()
@@ -230,8 +255,7 @@ bool InstallController::isServerAlreadyExists()
auto modelIndex = m_serversModel->index(i); auto modelIndex = m_serversModel->index(i);
const ServerCredentials credentials = const ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(modelIndex, ServersModel::Roles::CredentialsRole)); qvariant_cast<ServerCredentials>(m_serversModel->data(modelIndex, ServersModel::Roles::CredentialsRole));
if (m_currentlyInstalledServerCredentials.hostName == credentials.hostName if (m_processedServerCredentials.hostName == credentials.hostName && m_processedServerCredentials.port == credentials.port) {
&& m_currentlyInstalledServerCredentials.port == credentials.port) {
emit serverAlreadyExists(i); emit serverAlreadyExists(i);
return true; return true;
} }
@@ -248,15 +272,31 @@ void InstallController::scanServerForInstalledContainers()
ServerController serverController(m_settings); ServerController serverController(m_settings);
QMap<DockerContainer, QJsonObject> installedContainers; QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode = serverController.getAlreadyInstalledContainers(serverCredentials, installedContainers); ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, installedContainers);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
bool isInstalledContainerAddedToGui = false; bool isInstalledContainerAddedToGui = false;
VpnConfigurationsController vpnConfigurationController(m_settings);
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) { for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
QJsonObject containerConfig = m_containersModel->getContainerConfig(iterator.key()); QJsonObject containerConfig = m_containersModel->getContainerConfig(iterator.key());
if (containerConfig.isEmpty()) { if (containerConfig.isEmpty()) {
m_serversModel->addContainerConfig(iterator.key(), iterator.value()); containerConfig = iterator.value();
auto errorCode =
vpnConfigurationController.createProtocolConfigForContainer(serverCredentials, iterator.key(), containerConfig);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
m_serversModel->addContainerConfig(iterator.key(), containerConfig);
errorCode = m_clientManagementModel->appendClient(iterator.key(), serverCredentials, containerConfig,
QString("Admin [%1]").arg(QSysInfo::prettyProductName()));
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
isInstalledContainerAddedToGui = true; isInstalledContainerAddedToGui = true;
} }
} }
@@ -268,6 +308,151 @@ void InstallController::scanServerForInstalledContainers()
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorString(errorCode));
} }
ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
auto cbReadStdErr = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
ServerController serverController(m_settings);
QString script = QString("sudo docker ps --format '{{.Names}} {{.Ports}}'");
ErrorCode errorCode = serverController.runScript(credentials, script, cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
auto containersInfo = stdOut.split("\n");
for (auto &containerInfo : containersInfo) {
if (containerInfo.isEmpty()) {
continue;
}
const static QRegularExpression containerAndPortRegExp("(amnezia[-a-z]*).*?:([0-9]*)->[0-9]*/(udp|tcp).*");
QRegularExpressionMatch containerAndPortMatch = containerAndPortRegExp.match(containerInfo);
if (containerAndPortMatch.hasMatch()) {
QString name = containerAndPortMatch.captured(1);
QString port = containerAndPortMatch.captured(2);
QString transportProto = containerAndPortMatch.captured(3);
DockerContainer container = ContainerProps::containerFromString(name);
QJsonObject config;
Proto mainProto = ContainerProps::defaultProtocol(container);
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, port);
containerConfig.insert(config_key::transport_proto, transportProto);
if (protocol == Proto::Awg) {
QString serverConfig = serverController.getTextFileFromContainer(container, credentials,
protocols::awg::serverConfigPath, errorCode);
QMap<QString, QString> serverConfigMap;
auto serverConfigLines = serverConfig.split("\n");
for (auto &line : serverConfigLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
serverConfigMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
containerConfig[config_key::junkPacketCount] = serverConfigMap.value(config_key::junkPacketCount);
containerConfig[config_key::junkPacketMinSize] = serverConfigMap.value(config_key::junkPacketMinSize);
containerConfig[config_key::junkPacketMaxSize] = serverConfigMap.value(config_key::junkPacketMaxSize);
containerConfig[config_key::initPacketJunkSize] = serverConfigMap.value(config_key::initPacketJunkSize);
containerConfig[config_key::responsePacketJunkSize] = serverConfigMap.value(config_key::responsePacketJunkSize);
containerConfig[config_key::initPacketMagicHeader] = serverConfigMap.value(config_key::initPacketMagicHeader);
containerConfig[config_key::responsePacketMagicHeader] = serverConfigMap.value(config_key::responsePacketMagicHeader);
containerConfig[config_key::underloadPacketMagicHeader] =
serverConfigMap.value(config_key::underloadPacketMagicHeader);
containerConfig[config_key::transportPacketMagicHeader] =
serverConfigMap.value(config_key::transportPacketMagicHeader);
} else if (protocol == Proto::Sftp) {
stdOut.clear();
script = QString("sudo docker inspect --format '{{.Config.Cmd}}' %1").arg(name);
ErrorCode errorCode = serverController.runScript(credentials, script, cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
auto sftpInfo = stdOut.split(":");
if (sftpInfo.size() < 2) {
logger.error() << "Key parameters for the sftp container are missing";
continue;
}
auto userName = sftpInfo.at(0);
userName = userName.remove(0, 1);
auto password = sftpInfo.at(1);
containerConfig.insert(config_key::userName, userName);
containerConfig.insert(config_key::password, password);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
}
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
}
installedContainers.insert(container, config);
}
const static QRegularExpression torOrDnsRegExp("(amnezia-(?:torwebsite|dns)).*?([0-9]*)/(udp|tcp).*");
QRegularExpressionMatch torOrDnsRegMatch = torOrDnsRegExp.match(containerInfo);
if (torOrDnsRegMatch.hasMatch()) {
QString name = torOrDnsRegMatch.captured(1);
QString port = torOrDnsRegMatch.captured(2);
QString transportProto = torOrDnsRegMatch.captured(3);
DockerContainer container = ContainerProps::containerFromString(name);
QJsonObject config;
Proto mainProto = ContainerProps::defaultProtocol(container);
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, port);
containerConfig.insert(config_key::transport_proto, transportProto);
if (protocol == Proto::TorWebSite) {
stdOut.clear();
script = QString("sudo docker exec -i %1 sh -c 'cat /var/lib/tor/hidden_service/hostname'").arg(name);
ErrorCode errorCode = serverController.runScript(credentials, script, cbReadStdOut, cbReadStdErr);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
if (stdOut.isEmpty()) {
logger.error() << "Key parameters for the tor container are missing";
continue;
}
QString onion = stdOut;
onion.replace("\n", "");
containerConfig.insert(config_key::site, onion);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
}
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
}
installedContainers.insert(container, config);
}
}
return ErrorCode::NoError;
}
void InstallController::updateContainer(QJsonObject config) void InstallController::updateContainer(QJsonObject config)
{ {
int serverIndex = m_serversModel->getProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
@@ -284,6 +469,7 @@ void InstallController::updateContainer(QJsonObject config)
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation); connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
errorCode = serverController.updateContainer(serverCredentials, container, oldContainerConfig, config); errorCode = serverController.updateContainer(serverCredentials, container, oldContainerConfig, config);
clearCachedProfile();
} }
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
@@ -334,23 +520,51 @@ void InstallController::removeAllContainers()
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorString(errorCode));
} }
void InstallController::removeCurrentlyProcessedContainer() void InstallController::removeProcessedContainer()
{ {
int serverIndex = m_serversModel->getProcessedServerIndex(); int serverIndex = m_serversModel->getProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString(); QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
int container = m_containersModel->getCurrentlyProcessedContainerIndex(); int container = m_containersModel->getProcessedContainerIndex();
QString containerName = m_containersModel->getCurrentlyProcessedContainerName(); QString containerName = m_containersModel->getProcessedContainerName();
ErrorCode errorCode = m_serversModel->removeContainer(container); ErrorCode errorCode = m_serversModel->removeContainer(container);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
emit removeCurrentlyProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName, serverName)); emit removeProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName, serverName));
return; return;
} }
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorString(errorCode));
} }
void InstallController::removeApiConfig()
{
auto serverConfig = m_serversModel->getServerConfig(m_serversModel->getDefaultServerIndex());
serverConfig.remove(config_key::dns1);
serverConfig.remove(config_key::dns2);
serverConfig.remove(config_key::containers);
serverConfig.remove(config_key::hostName);
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
}
void InstallController::clearCachedProfile()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
ServerCredentials serverCredentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
m_serversModel->clearCachedProfile(container);
m_clientManagementModel->revokeClient(containerConfig, container, serverCredentials, serverIndex);
emit cachedProfileCleared(tr("%1 cached profile cleared").arg(ContainerProps::containerHumanNames().value(container)));
}
QRegularExpression InstallController::ipAddressPortRegExp() QRegularExpression InstallController::ipAddressPortRegExp()
{ {
return NetworkUtilities::ipAddressPortRegExp(); return NetworkUtilities::ipAddressPortRegExp();
@@ -361,17 +575,15 @@ QRegularExpression InstallController::ipAddressRegExp()
return NetworkUtilities::ipAddressRegExp(); return NetworkUtilities::ipAddressRegExp();
} }
void InstallController::setCurrentlyInstalledServerCredentials(const QString &hostName, const QString &userName, void InstallController::setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData)
const QString &secretData)
{ {
m_currentlyInstalledServerCredentials.hostName = hostName; m_processedServerCredentials.hostName = hostName;
if (m_currentlyInstalledServerCredentials.hostName.contains(":")) { if (m_processedServerCredentials.hostName.contains(":")) {
m_currentlyInstalledServerCredentials.port = m_processedServerCredentials.port = m_processedServerCredentials.hostName.split(":").at(1).toInt();
m_currentlyInstalledServerCredentials.hostName.split(":").at(1).toInt(); m_processedServerCredentials.hostName = m_processedServerCredentials.hostName.split(":").at(0);
m_currentlyInstalledServerCredentials.hostName = m_currentlyInstalledServerCredentials.hostName.split(":").at(0);
} }
m_currentlyInstalledServerCredentials.userName = userName; m_processedServerCredentials.userName = userName;
m_currentlyInstalledServerCredentials.secretData = secretData; m_processedServerCredentials.secretData = secretData;
} }
void InstallController::setShouldCreateServer(bool shouldCreateServer) void InstallController::setShouldCreateServer(bool shouldCreateServer)
@@ -398,8 +610,7 @@ void InstallController::mountSftpDrive(const QString &port, const QString &passw
cmd = "C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe"; cmd = "C:\\Program Files\\SSHFS-Win\\bin\\sshfs.exe";
#elif defined AMNEZIA_DESKTOP #elif defined AMNEZIA_DESKTOP
mountPath = mountPath = QString("%1/sftp:%2:%3").arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation), hostname, port);
QString("%1/sftp:%2:%3").arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation), hostname, port);
QDir dir(mountPath); QDir dir(mountPath);
if (!dir.exists()) { if (!dir.exists()) {
dir.mkpath(mountPath); dir.mkpath(mountPath);
@@ -461,8 +672,7 @@ bool InstallController::checkSshConnection()
ErrorCode errorCode = ErrorCode::NoError; ErrorCode errorCode = ErrorCode::NoError;
m_privateKeyPassphrase = ""; m_privateKeyPassphrase = "";
if (m_currentlyInstalledServerCredentials.secretData.contains("BEGIN") if (m_processedServerCredentials.secretData.contains("BEGIN") && m_processedServerCredentials.secretData.contains("PRIVATE KEY")) {
&& m_currentlyInstalledServerCredentials.secretData.contains("PRIVATE KEY")) {
auto passphraseCallback = [this]() { auto passphraseCallback = [this]() {
emit passphraseRequestStarted(); emit passphraseRequestStarted();
QEventLoop loop; QEventLoop loop;
@@ -473,10 +683,9 @@ bool InstallController::checkSshConnection()
}; };
QString decryptedPrivateKey; QString decryptedPrivateKey;
errorCode = serverController.getDecryptedPrivateKey(m_currentlyInstalledServerCredentials, decryptedPrivateKey, errorCode = serverController.getDecryptedPrivateKey(m_processedServerCredentials, decryptedPrivateKey, passphraseCallback);
passphraseCallback);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
m_currentlyInstalledServerCredentials.secretData = decryptedPrivateKey; m_processedServerCredentials.secretData = decryptedPrivateKey;
} else { } else {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorString(errorCode));
return false; return false;
@@ -484,7 +693,7 @@ bool InstallController::checkSshConnection()
} }
QString output; QString output;
output = serverController.checkSshConnection(m_currentlyInstalledServerCredentials, &errorCode); output = serverController.checkSshConnection(m_processedServerCredentials, errorCode);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit installationErrorOccurred(errorString(errorCode)); emit installationErrorOccurred(errorString(errorCode));
@@ -508,10 +717,10 @@ void InstallController::setEncryptedPassphrase(QString passphrase)
void InstallController::addEmptyServer() void InstallController::addEmptyServer()
{ {
QJsonObject server; QJsonObject server;
server.insert(config_key::hostName, m_currentlyInstalledServerCredentials.hostName); server.insert(config_key::hostName, m_processedServerCredentials.hostName);
server.insert(config_key::userName, m_currentlyInstalledServerCredentials.userName); server.insert(config_key::userName, m_processedServerCredentials.userName);
server.insert(config_key::password, m_currentlyInstalledServerCredentials.secretData); server.insert(config_key::password, m_processedServerCredentials.secretData);
server.insert(config_key::port, m_currentlyInstalledServerCredentials.port); server.insert(config_key::port, m_processedServerCredentials.port);
server.insert(config_key::description, m_settings->nextAvailableServerName()); server.insert(config_key::description, m_settings->nextAvailableServerName());
server.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
@@ -532,17 +741,17 @@ bool InstallController::isUpdateDockerContainerRequired(const DockerContainer co
const AwgConfig oldConfig(oldProtoConfig); const AwgConfig oldConfig(oldProtoConfig);
const AwgConfig newConfig(newProtoConfig); const AwgConfig newConfig(newProtoConfig);
if (!oldConfig.hasEqualServerSettings(newConfig)) { if (oldConfig.hasEqualServerSettings(newConfig)) {
return true; return false;
} }
} else if (container == DockerContainer::WireGuard) { } else if (container == DockerContainer::WireGuard) {
const WgConfig oldConfig(oldProtoConfig); const WgConfig oldConfig(oldProtoConfig);
const WgConfig newConfig(newProtoConfig); const WgConfig newConfig(newProtoConfig);
if (!oldConfig.hasEqualServerSettings(newConfig)) { if (oldConfig.hasEqualServerSettings(newConfig)) {
return true; return false;
} }
} }
return false; return true;
} }
+21 -11
View File
@@ -6,24 +6,24 @@
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
#include "core/defs.h" #include "core/defs.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/containers_model.h" #include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/protocols_model.h" #include "ui/models/protocols_model.h"
#include "ui/models/servers_model.h"
class InstallController : public QObject class InstallController : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit InstallController(const QSharedPointer<ServersModel> &serversModel, explicit InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ProtocolsModel> &protocolsModel, const QSharedPointer<ProtocolsModel> &protocolsModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr); const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
~InstallController(); ~InstallController();
public slots: public slots:
void install(DockerContainer container, int port, TransportProto transportProto); void install(DockerContainer container, int port, TransportProto transportProto);
void setCurrentlyInstalledServerCredentials(const QString &hostName, const QString &userName, void setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData);
const QString &secretData);
void setShouldCreateServer(bool shouldCreateServer); void setShouldCreateServer(bool shouldCreateServer);
void scanServerForInstalledContainers(); void scanServerForInstalledContainers();
@@ -33,7 +33,11 @@ public slots:
void removeProcessedServer(); void removeProcessedServer();
void rebootProcessedServer(); void rebootProcessedServer();
void removeAllContainers(); void removeAllContainers();
void removeCurrentlyProcessedContainer(); void removeProcessedContainer();
void removeApiConfig();
void clearCachedProfile();
QRegularExpression ipAddressPortRegExp(); QRegularExpression ipAddressPortRegExp();
QRegularExpression ipAddressRegExp(); QRegularExpression ipAddressRegExp();
@@ -50,14 +54,14 @@ signals:
void installContainerFinished(const QString &finishMessage, bool isServiceInstall); void installContainerFinished(const QString &finishMessage, bool isServiceInstall);
void installServerFinished(const QString &finishMessage); void installServerFinished(const QString &finishMessage);
void updateContainerFinished(const QString& message); void updateContainerFinished(const QString &message);
void scanServerFinished(bool isInstalledContainerFound); void scanServerFinished(bool isInstalledContainerFound);
void rebootProcessedServerFinished(const QString &finishedMessage); void rebootProcessedServerFinished(const QString &finishedMessage);
void removeProcessedServerFinished(const QString &finishedMessage); void removeProcessedServerFinished(const QString &finishedMessage);
void removeAllContainersFinished(const QString &finishedMessage); void removeAllContainersFinished(const QString &finishedMessage);
void removeCurrentlyProcessedContainerFinished(const QString &finishedMessage); void removeProcessedContainerFinished(const QString &finishedMessage);
void installationErrorOccurred(const QString &errorMessage); void installationErrorOccurred(const QString &errorMessage);
@@ -71,19 +75,25 @@ signals:
void currentContainerUpdated(); void currentContainerUpdated();
void cachedProfileCleared(const QString &message);
private: private:
void installServer(DockerContainer container, QJsonObject &config); void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
void installContainer(DockerContainer container, QJsonObject &config); const ServerCredentials &serverCredentials, QString &finishMessage);
void installContainer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials, QString &finishMessage);
bool isServerAlreadyExists(); bool isServerAlreadyExists();
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
bool isUpdateDockerContainerRequired(const DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig); bool isUpdateDockerContainerRequired(const DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ProtocolsModel> m_protocolModel; QSharedPointer<ProtocolsModel> m_protocolModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
ServerCredentials m_currentlyInstalledServerCredentials; ServerCredentials m_processedServerCredentials;
bool m_shouldCreateServer; bool m_shouldCreateServer;
+8
View File
@@ -7,6 +7,7 @@
#endif #endif
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#include "platforms/android/android_utils.h" #include "platforms/android/android_utils.h"
#include <QJniObject> #include <QJniObject>
#endif #endif
@@ -74,6 +75,13 @@ void PageController::closeWindow()
#endif #endif
} }
void PageController::hideWindow()
{
#ifdef Q_OS_ANDROID
AndroidController::instance()->minimizeApp();
#endif
}
void PageController::keyPressEvent(Qt::Key key) void PageController::keyPressEvent(Qt::Key key)
{ {
switch (key) { switch (key) {
+2
View File
@@ -29,6 +29,7 @@ namespace PageLoader
PageSettingsAbout, PageSettingsAbout,
PageSettingsLogging, PageSettingsLogging,
PageSettingsSplitTunneling, PageSettingsSplitTunneling,
PageSettingsAppSplitTunneling,
PageServiceSftpSettings, PageServiceSftpSettings,
PageServiceTorWebsiteSettings, PageServiceTorWebsiteSettings,
@@ -76,6 +77,7 @@ public slots:
QString getPagePath(PageLoader::PageEnum page); QString getPagePath(PageLoader::PageEnum page);
void closeWindow(); void closeWindow();
void hideWindow();
void keyPressEvent(Qt::Key key); void keyPressEvent(Qt::Key key);
unsigned int getInitialPageNavigationBarColor(); unsigned int getInitialPageNavigationBarColor();
@@ -153,12 +153,6 @@ void SettingsController::clearSettings()
#endif #endif
} }
void SettingsController::clearCachedProfiles()
{
m_serversModel->clearCachedProfiles();
emit changeSettingsFinished(tr("Cached profiles cleared"));
}
bool SettingsController::isAutoConnectEnabled() bool SettingsController::isAutoConnectEnabled()
{ {
return m_settings->isAutoConnect(); return m_settings->isAutoConnect();
@@ -46,7 +46,6 @@ public slots:
QString getAppVersion(); QString getAppVersion();
void clearSettings(); void clearSettings();
void clearCachedProfiles();
bool isAutoConnectEnabled(); bool isAutoConnectEnabled();
void toggleAutoConnect(bool enable); void toggleAutoConnect(bool enable);
+101
View File
@@ -0,0 +1,101 @@
#include "appSplitTunnelingModel.h"
#include <QFileInfo>
AppSplitTunnelingModel::AppSplitTunnelingModel(std::shared_ptr<Settings> settings, QObject *parent)
: QAbstractListModel(parent), m_settings(settings)
{
auto routeMode = m_settings->getAppsRouteMode();
if (routeMode == Settings::AppsRouteMode::VpnAllApps) {
m_isSplitTunnelingEnabled = false;
m_currentRouteMode = Settings::AppsRouteMode::VpnAllExceptApps;
} else {
m_isSplitTunnelingEnabled = true;
m_currentRouteMode = routeMode;
}
m_apps = m_settings->getVpnApps(m_currentRouteMode);
}
int AppSplitTunnelingModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_apps.size();
}
QVariant AppSplitTunnelingModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
return QVariant();
switch (role) {
case AppPathRole: {
return m_apps.at(index.row()).appName;
}
default: {
return true;
}
}
return QVariant();
}
bool AppSplitTunnelingModel::addApp(const InstalledAppInfo &appInfo)
{
if (m_apps.contains(appInfo)) {
return false;
}
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_apps.append(appInfo);
m_settings->setVpnApps(m_currentRouteMode, m_apps);
endInsertRows();
qDebug() << "app added " << appInfo.appName;
return true;
}
void AppSplitTunnelingModel::removeApp(QModelIndex index)
{
beginRemoveRows(QModelIndex(), index.row(), index.row());
m_apps.removeAt(index.row());
m_settings->setVpnApps(m_currentRouteMode, m_apps);
endRemoveRows();
}
int AppSplitTunnelingModel::getRouteMode()
{
return m_currentRouteMode;
}
void AppSplitTunnelingModel::setRouteMode(int routeMode)
{
beginResetModel();
m_settings->setAppsRouteMode(static_cast<Settings::AppsRouteMode>(routeMode));
m_currentRouteMode = m_settings->getAppsRouteMode();
m_apps = m_settings->getVpnApps(m_currentRouteMode);
endResetModel();
emit routeModeChanged();
}
bool AppSplitTunnelingModel::isSplitTunnelingEnabled()
{
return m_isSplitTunnelingEnabled;
}
void AppSplitTunnelingModel::toggleSplitTunneling(bool enabled)
{
if (enabled) {
setRouteMode(m_currentRouteMode);
} else {
m_settings->setAppsRouteMode(Settings::AppsRouteMode::VpnAllApps);
}
m_isSplitTunnelingEnabled = enabled;
emit splitTunnelingToggled();
}
QHash<int, QByteArray> AppSplitTunnelingModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[AppPathRole] = "appPath";
return roles;
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef APPSPLITTUNNELINGMODEL_H
#define APPSPLITTUNNELINGMODEL_H
#include <QAbstractListModel>
#include "settings.h"
#include "core/defs.h"
class AppSplitTunnelingModel: public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
AppPathRole = Qt::UserRole + 1,
PackageAppNameRole,
PackageAppIconRole
};
explicit AppSplitTunnelingModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged)
Q_PROPERTY(bool isTunnelingEnabled READ isSplitTunnelingEnabled NOTIFY splitTunnelingToggled)
public slots:
bool addApp(const InstalledAppInfo &appInfo);
void removeApp(QModelIndex index);
int getRouteMode();
void setRouteMode(int routeMode);
bool isSplitTunnelingEnabled();
void toggleSplitTunneling(bool enabled);
signals:
void routeModeChanged();
void splitTunnelingToggled();
protected:
QHash<int, QByteArray> roleNames() const override;
private:
std::shared_ptr<Settings> m_settings;
bool m_isSplitTunnelingEnabled;
Settings::AppsRouteMode m_currentRouteMode;
QVector<InstalledAppInfo> m_apps;
};
#endif // APPSPLITTUNNELINGMODEL_H
+90 -46
View File
@@ -10,7 +10,8 @@ namespace
{ {
Logger logger("ClientManagementModel"); Logger logger("ClientManagementModel");
namespace configKey { namespace configKey
{
constexpr char clientId[] = "clientId"; constexpr char clientId[] = "clientId";
constexpr char clientName[] = "clientName"; constexpr char clientName[] = "clientName";
constexpr char container[] = "container"; constexpr char container[] = "container";
@@ -61,7 +62,6 @@ void ClientManagementModel::migration(const QByteArray &clientsTableString)
m_clientsTable.push_back(client); m_clientsTable.push_back(client);
} }
} }
ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials) ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials)
@@ -74,15 +74,13 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
ErrorCode error = ErrorCode::NoError; ErrorCode error = ErrorCode::NoError;
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable"); QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|| container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else { } else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
} }
const QByteArray clientsTableString = const QByteArray clientsTableString = serverController.getTextFileFromContainer(container, credentials, clientsTableFile, error);
serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the clientsTable file from the server"; logger.error() << "Failed to get the clientsTable file from the server";
endResetModel(); endResetModel();
@@ -96,8 +94,7 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
int count = 0; int count = 0;
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|| container == DockerContainer::Cloak) {
error = getOpenVpnClients(serverController, container, credentials, count); error = getOpenVpnClients(serverController, container, credentials, count);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) { } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
error = getWireGuardClients(serverController, container, credentials, count); error = getWireGuardClients(serverController, container, credentials, count);
@@ -109,8 +106,7 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson(); const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson();
if (clientsTableString != newClientsTableString) { if (clientsTableString != newClientsTableString) {
error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString, error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString, clientsTableFile);
clientsTableFile);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server"; logger.error() << "Failed to upload the clientsTable file to the server";
} }
@@ -121,7 +117,8 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
return error; return error;
} }
ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count) ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverController, DockerContainer container,
ServerCredentials credentials, int &count)
{ {
ErrorCode error = ErrorCode::NoError; ErrorCode error = ErrorCode::NoError;
QString stdOut; QString stdOut;
@@ -130,10 +127,8 @@ ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverContr
return ErrorCode::NoError; return ErrorCode::NoError;
}; };
const QString getOpenVpnClientsList = const QString getOpenVpnClientsList = "sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'";
"sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'"; QString script = serverController.replaceVars(getOpenVpnClientsList, serverController.genVarsForScript(credentials, container));
QString script = serverController.replaceVars(getOpenVpnClientsList,
serverController.genVarsForScript(credentials, container));
error = serverController.runScript(credentials, script, cbReadStdOut); error = serverController.runScript(credentials, script, cbReadStdOut);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to retrieve the list of issued certificates on the server"; logger.error() << "Failed to retrieve the list of issued certificates on the server";
@@ -163,14 +158,13 @@ ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverContr
return error; return error;
} }
ErrorCode ClientManagementModel::getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count) ErrorCode ClientManagementModel::getWireGuardClients(ServerController &serverController, DockerContainer container,
ServerCredentials credentials, int &count)
{ {
ErrorCode error = ErrorCode::NoError; ErrorCode error = ErrorCode::NoError;
const QString wireGuardConfigFile = const QString wireGuardConfigFile = QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg"); const QString wireguardConfigString = serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, error);
const QString wireguardConfigString =
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server"; logger.error() << "Failed to get the wg conf file from the server";
return error; return error;
@@ -215,10 +209,27 @@ bool ClientManagementModel::isClientExists(const QString &clientId)
return false; return false;
} }
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName, ErrorCode ClientManagementModel::appendClient(const DockerContainer container, const ServerCredentials &credentials,
const DockerContainer container, ServerCredentials credentials) const QJsonObject &containerConfig, const QString &clientName)
{ {
ErrorCode error; Proto protocol;
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
protocol = Proto::OpenVpn;
} else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
protocol = ContainerProps::defaultProtocol(container);
} else {
return ErrorCode::NoError;
}
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
return appendClient(protocolConfig.value(config_key::clientId).toString(), clientName, container, credentials);
}
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials)
{
ErrorCode error = ErrorCode::NoError;
error = updateModel(container, credentials); error = updateModel(container, credentials);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
@@ -246,8 +257,7 @@ ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QSt
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable"); QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|| container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else { } else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
@@ -279,15 +289,13 @@ ErrorCode ClientManagementModel::renameClient(const int row, const QString &clie
ServerController serverController(m_settings); ServerController serverController(m_settings);
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable"); QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|| container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else { } else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
} }
ErrorCode error = ErrorCode error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server"; logger.error() << "Failed to upload the clientsTable file to the server";
} }
@@ -295,15 +303,14 @@ ErrorCode ClientManagementModel::renameClient(const int row, const QString &clie
return error; return error;
} }
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container, ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container, ServerCredentials credentials,
ServerCredentials credentials, const int serverIndex) const int serverIndex)
{ {
ErrorCode errorCode = ErrorCode::NoError; ErrorCode errorCode = ErrorCode::NoError;
auto client = m_clientsTable.at(row).toObject(); auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString(); QString clientId = client.value(configKey::clientId).toString();
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|| container == DockerContainer::Cloak) {
errorCode = revokeOpenVpn(row, container, credentials, serverIndex); errorCode = revokeOpenVpn(row, container, credentials, serverIndex);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) { } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
errorCode = revokeWireGuard(row, container, credentials); errorCode = revokeWireGuard(row, container, credentials);
@@ -333,8 +340,50 @@ ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContain
return errorCode; return errorCode;
} }
ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container, ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig, const DockerContainer container, ServerCredentials credentials,
ServerCredentials credentials, const int serverIndex) const int serverIndex)
{
ErrorCode errorCode = ErrorCode::NoError;
errorCode = updateModel(container, credentials);
if (errorCode != ErrorCode::NoError) {
return errorCode;
}
Proto protocol;
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
protocol = Proto::OpenVpn;
} else if (container == DockerContainer::OpenVpn || container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
protocol = ContainerProps::defaultProtocol(container);
} else {
return ErrorCode::NoError;
}
auto protocolConfig = ContainerProps::getProtocolConfigFromContainer(protocol, containerConfig);
int row;
bool clientExists = false;
QString clientId = protocolConfig.value(config_key::clientId).toString();
for (row = 0; row < rowCount(); row++) {
auto client = m_clientsTable.at(row).toObject();
if (clientId == client.value(configKey::clientId).toString()) {
clientExists = true;
break;
}
}
if (!clientExists) {
return errorCode;
}
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
errorCode = revokeOpenVpn(row, container, credentials, serverIndex);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
errorCode = revokeWireGuard(row, container, credentials);
}
return errorCode;
}
ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container, ServerCredentials credentials,
const int serverIndex)
{ {
auto client = m_clientsTable.at(row).toObject(); auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString(); QString clientId = client.value(configKey::clientId).toString();
@@ -348,8 +397,7 @@ ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContai
.arg(clientId); .arg(clientId);
ServerController serverController(m_settings); ServerController serverController(m_settings);
const QString script = const QString script = serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
ErrorCode error = serverController.runScript(credentials, script); ErrorCode error = serverController.runScript(credentials, script);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to revoke the certificate"; logger.error() << "Failed to revoke the certificate";
@@ -373,16 +421,14 @@ ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContai
return ErrorCode::NoError; return ErrorCode::NoError;
} }
ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container, ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials)
ServerCredentials credentials)
{ {
ErrorCode error; ErrorCode error = ErrorCode::NoError;
ServerController serverController(m_settings); ServerController serverController(m_settings);
const QString wireGuardConfigFile = const QString wireGuardConfigFile =
QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg"); QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString = const QString wireguardConfigString = serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, error);
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server"; logger.error() << "Failed to get the wg conf file from the server";
return error; return error;
@@ -413,8 +459,7 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson(); const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable"); QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|| container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else { } else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container)); clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
@@ -428,8 +473,7 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'"; const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'";
error = serverController.runScript( error = serverController.runScript(
credentials, credentials,
serverController.replaceVars(script.arg(wireGuardConfigFile), serverController.replaceVars(script.arg(wireGuardConfigFile), serverController.genVarsForScript(credentials, container)));
serverController.genVarsForScript(credentials, container)));
if (error != ErrorCode::NoError) { if (error != ErrorCode::NoError) {
logger.error() << "Failed to execute the command 'wg syncconf' on the server"; logger.error() << "Failed to execute the command 'wg syncconf' on the server";
return error; return error;
+5 -2
View File
@@ -24,11 +24,14 @@ public:
public slots: public slots:
ErrorCode updateModel(DockerContainer container, ServerCredentials credentials); ErrorCode updateModel(DockerContainer container, ServerCredentials credentials);
ErrorCode appendClient(const DockerContainer container, const ServerCredentials &credentials, const QJsonObject &containerConfig,
const QString &clientName);
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container, ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials); ServerCredentials credentials);
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, ServerCredentials credentials,
ServerCredentials credentials, bool addTimeStamp = false); bool addTimeStamp = false);
ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials, const int serverIndex); ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials, const int serverIndex);
ErrorCode revokeClient(const QJsonObject &containerConfig, const DockerContainer container, ServerCredentials credentials, const int serverIndex);
protected: protected:
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
+7 -7
View File
@@ -38,7 +38,7 @@ QVariant ContainersModel::data(const QModelIndex &index, int role) const
case EasySetupDescriptionRole: return ContainerProps::easySetupDescription(container); case EasySetupDescriptionRole: return ContainerProps::easySetupDescription(container);
case EasySetupOrderRole: return ContainerProps::easySetupOrder(container); case EasySetupOrderRole: return ContainerProps::easySetupOrder(container);
case IsInstalledRole: return m_containers.contains(container); case IsInstalledRole: return m_containers.contains(container);
case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_currentlyProcessedContainerIndex); case IsCurrentlyProcessedRole: return container == static_cast<DockerContainer>(m_processedContainerIndex);
case IsSupportedRole: return ContainerProps::isSupportedByCurrentPlatform(container); case IsSupportedRole: return ContainerProps::isSupportedByCurrentPlatform(container);
case IsShareableRole: return ContainerProps::isShareable(container); case IsShareableRole: return ContainerProps::isShareable(container);
} }
@@ -63,19 +63,19 @@ void ContainersModel::updateModel(const QJsonArray &containers)
endResetModel(); endResetModel();
} }
void ContainersModel::setCurrentlyProcessedContainerIndex(int index) void ContainersModel::setProcessedContainerIndex(int index)
{ {
m_currentlyProcessedContainerIndex = index; m_processedContainerIndex = index;
} }
int ContainersModel::getCurrentlyProcessedContainerIndex() int ContainersModel::getProcessedContainerIndex()
{ {
return m_currentlyProcessedContainerIndex; return m_processedContainerIndex;
} }
QString ContainersModel::getCurrentlyProcessedContainerName() QString ContainersModel::getProcessedContainerName()
{ {
return ContainerProps::containerHumanNames().value(static_cast<DockerContainer>(m_currentlyProcessedContainerIndex)); return ContainerProps::containerHumanNames().value(static_cast<DockerContainer>(m_processedContainerIndex));
} }
QJsonObject ContainersModel::getContainerConfig(const int containerIndex) QJsonObject ContainersModel::getContainerConfig(const int containerIndex)
+4 -4
View File
@@ -42,10 +42,10 @@ public:
public slots: public slots:
void updateModel(const QJsonArray &containers); void updateModel(const QJsonArray &containers);
void setCurrentlyProcessedContainerIndex(int containerIndex); void setProcessedContainerIndex(int containerIndex);
int getCurrentlyProcessedContainerIndex(); int getProcessedContainerIndex();
QString getCurrentlyProcessedContainerName(); QString getProcessedContainerName();
QJsonObject getContainerConfig(const int containerIndex); QJsonObject getContainerConfig(const int containerIndex);
@@ -58,7 +58,7 @@ signals:
private: private:
QMap<DockerContainer, QJsonObject> m_containers; QMap<DockerContainer, QJsonObject> m_containers;
int m_currentlyProcessedContainerIndex; int m_processedContainerIndex;
}; };
#endif // CONTAINERS_MODEL_H #endif // CONTAINERS_MODEL_H
+96
View File
@@ -0,0 +1,96 @@
#include "installedAppsModel.h"
#include <QEventLoop>
#include <QtConcurrent>
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#endif
InstalledAppsModel::InstalledAppsModel(QObject *parent) : QAbstractListModel(parent)
{
}
int InstalledAppsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_installedApps.size();
}
QVariant InstalledAppsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
return QVariant();
switch (role) {
case AppNameRole: {
auto appName = m_installedApps.at(index.row()).toObject().value("name").toString();
auto packageName = m_installedApps.at(index.row()).toObject().value("package").toString();
if (appName.isEmpty()) {
appName = packageName;
}
return appName;
}
case AppIconRole: {
return m_installedApps.at(index.row()).toObject().value("package").toString();
}
case PackageNameRole: {
return m_installedApps.at(index.row()).toObject().value("package");
}
}
return QVariant();
}
void InstalledAppsModel::selectedStateChanged(const int index, const bool selected)
{
if (selected) {
m_selectedAppIndexes.insert(index);
} else {
m_selectedAppIndexes.remove(index);
}
}
QVector<QPair<QString, QString>> InstalledAppsModel::getSelectedAppsInfo()
{
QVector<QPair<QString, QString>> appsInfo;
for (const auto i : m_selectedAppIndexes) {
QString packageName = data(index(i, 0), PackageNameRole).toString();
QString appName = data(index(i, 0), AppNameRole).toString();
if (appName.isEmpty()) {
appName = packageName;
}
appsInfo.push_back({ appName, packageName });
}
return appsInfo;
}
void InstalledAppsModel::updateModel()
{
QFuture<void> future = QtConcurrent::run([this]() {
beginResetModel();
#ifdef Q_OS_ANDROID
m_installedApps = AndroidController::instance()->getAppList();
#endif
endResetModel();
});
QFutureWatcher<void> watcher;
QEventLoop wait;
connect(&watcher, &QFutureWatcher<void>::finished, &wait, &QEventLoop::quit);
watcher.setFuture(future);
wait.exec();
return;
}
QHash<int, QByteArray> InstalledAppsModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[AppNameRole] = "appName";
roles[AppIconRole] = "appIcon";
roles[PackageNameRole] = "packageName";
return roles;
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef INSTALLEDAPPSMODEL_H
#define INSTALLEDAPPSMODEL_H
#include <QJsonArray>
#include <QAbstractListModel>
class InstalledAppsModel: public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
AppNameRole= Qt::UserRole + 1,
PackageNameRole,
AppIconRole
};
explicit InstalledAppsModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
public slots:
void selectedStateChanged(const int index, const bool selected);
QVector<QPair<QString, QString>> getSelectedAppsInfo();
void updateModel();
protected:
QHash<int, QByteArray> roleNames() const override;
private:
QJsonArray m_installedApps;
QSet<int> m_selectedAppIndexes;
};
#endif // INSTALLEDAPPSMODEL_H
@@ -37,6 +37,8 @@ QVariant ShadowSocksConfigModel::data(const QModelIndex &index, int role) const
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort); case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::shadowsocks::defaultPort);
case Roles::CipherRole: case Roles::CipherRole:
return m_protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher); return m_protocolConfig.value(config_key::cipher).toString(protocols::shadowsocks::defaultCipher);
case Roles::IsPortEditableRole: return m_container == DockerContainer::ShadowSocks ? true : false;
case Roles::IsCipherEditableRole: return m_container == DockerContainer::ShadowSocks ? true : false;
} }
return QVariant(); return QVariant();
@@ -71,6 +73,8 @@ QHash<int, QByteArray> ShadowSocksConfigModel::roleNames() const
roles[PortRole] = "port"; roles[PortRole] = "port";
roles[CipherRole] = "cipher"; roles[CipherRole] = "cipher";
roles[IsPortEditableRole] = "isPortEditable";
roles[IsCipherEditableRole] = "isCipherEditable";
return roles; return roles;
} }
@@ -13,7 +13,9 @@ class ShadowSocksConfigModel : public QAbstractListModel
public: public:
enum Roles { enum Roles {
PortRole = Qt::UserRole + 1, PortRole = Qt::UserRole + 1,
CipherRole CipherRole,
IsPortEditableRole,
IsCipherEditableRole
}; };
explicit ShadowSocksConfigModel(QObject *parent = nullptr); explicit ShadowSocksConfigModel(QObject *parent = nullptr);
@@ -63,7 +63,7 @@ void WireGuardConfigModel::updateModel(const QJsonObject &config)
QJsonObject WireGuardConfigModel::getConfig() QJsonObject WireGuardConfigModel::getConfig()
{ {
const WgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject()); const WgConfig oldConfig(m_fullConfig.value(config_key::wireguard).toObject());
const WgConfig newConfig(m_protocolConfig); const WgConfig newConfig(m_protocolConfig);
if (!oldConfig.hasEqualServerSettings(newConfig)) { if (!oldConfig.hasEqualServerSettings(newConfig)) {
+1
View File
@@ -77,6 +77,7 @@ PageLoader::PageEnum ProtocolsModel::protocolPage(Proto protocol) const
case Proto::Cloak: return PageLoader::PageEnum::PageProtocolCloakSettings; case Proto::Cloak: return PageLoader::PageEnum::PageProtocolCloakSettings;
case Proto::ShadowSocks: return PageLoader::PageEnum::PageProtocolShadowSocksSettings; case Proto::ShadowSocks: return PageLoader::PageEnum::PageProtocolShadowSocksSettings;
case Proto::WireGuard: return PageLoader::PageEnum::PageProtocolWireGuardSettings; case Proto::WireGuard: return PageLoader::PageEnum::PageProtocolWireGuardSettings;
case Proto::Awg: return PageLoader::PageEnum::PageProtocolAwgSettings;
case Proto::Ikev2: return PageLoader::PageEnum::PageProtocolIKev2Settings; case Proto::Ikev2: return PageLoader::PageEnum::PageProtocolIKev2Settings;
case Proto::L2tp: return PageLoader::PageEnum::PageProtocolIKev2Settings; case Proto::L2tp: return PageLoader::PageEnum::PageProtocolIKev2Settings;
case Proto::Xray: return PageLoader::PageEnum::PageProtocolXraySettings; case Proto::Xray: return PageLoader::PageEnum::PageProtocolXraySettings;
+48 -27
View File
@@ -1,14 +1,17 @@
#include "servers_model.h" #include "servers_model.h"
#include "core/controllers/serverController.h" #include "core/controllers/serverController.h"
#include "core/networkUtilities.h"
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent) ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings), QAbstractListModel(parent)
: m_settings(settings), QAbstractListModel(parent)
{ {
m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged); connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged);
connect(this, &ServersModel::defaultServerIndexChanged, this, [this](const int serverIndex) { connect(this, &ServersModel::defaultServerIndexChanged, this, [this](const int serverIndex) {
auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString()); auto defaultContainer =
ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString());
emit ServersModel::defaultServerDefaultContainerChanged(defaultContainer); emit ServersModel::defaultServerDefaultContainerChanged(defaultContainer);
emit ServersModel::defaultServerNameChanged(); emit ServersModel::defaultServerNameChanged();
updateDefaultServerContainersModel(); updateDefaultServerContainersModel();
@@ -336,9 +339,9 @@ void ServersModel::updateDefaultServerContainersModel()
emit defaultServerContainersUpdated(containers); emit defaultServerContainersUpdated(containers);
} }
QJsonObject ServersModel::getDefaultServerConfig() QJsonObject ServersModel::getServerConfig(const int serverIndex)
{ {
return m_servers.at(m_defaultServerIndex).toObject(); return m_servers.at(serverIndex).toObject();
} }
void ServersModel::reloadDefaultServerContainerConfig() void ServersModel::reloadDefaultServerContainerConfig()
@@ -378,7 +381,8 @@ void ServersModel::updateContainerConfig(const int containerIndex, const QJsonOb
server.insert(config_key::containers, containers); server.insert(config_key::containers, containers);
auto defaultContainer = server.value(config_key::defaultContainer).toString(); auto defaultContainer = server.value(config_key::defaultContainer).toString();
if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) { if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None
|| ContainerProps::containerService(container) != ServiceType::Other)) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
} }
@@ -396,7 +400,8 @@ void ServersModel::addContainerConfig(const int containerIndex, const QJsonObjec
server.insert(config_key::containers, containers); server.insert(config_key::containers, containers);
auto defaultContainer = server.value(config_key::defaultContainer).toString(); auto defaultContainer = server.value(config_key::defaultContainer).toString();
if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) { if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None
|| ContainerProps::containerService(container) != ServiceType::Other)) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
} }
@@ -408,7 +413,7 @@ void ServersModel::setDefaultContainer(const int serverIndex, const int containe
auto container = static_cast<DockerContainer>(containerIndex); auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject s = m_servers.at(serverIndex).toObject(); QJsonObject s = m_servers.at(serverIndex).toObject();
s.insert(config_key::defaultContainer, ContainerProps::containerToString(container)); s.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
editServer(s, serverIndex); //check editServer(s, serverIndex); // check
} }
const QString ServersModel::getDefaultServerDefaultContainerName() const QString ServersModel::getDefaultServerDefaultContainerName()
@@ -420,8 +425,7 @@ const QString ServersModel::getDefaultServerDefaultContainerName()
ErrorCode ServersModel::removeAllContainers() ErrorCode ServersModel::removeAllContainers()
{ {
ServerController serverController(m_settings); ServerController serverController(m_settings);
ErrorCode errorCode = ErrorCode errorCode = serverController.removeAllContainers(m_settings->serverCredentials(m_processedServerIndex));
serverController.removeAllContainers(m_settings->serverCredentials(m_processedServerIndex));
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
QJsonObject s = m_servers.at(m_processedServerIndex).toObject(); QJsonObject s = m_servers.at(m_processedServerIndex).toObject();
@@ -468,7 +472,8 @@ ErrorCode ServersModel::removeContainer(const int containerIndex)
if (containers.empty()) { if (containers.empty()) {
defaultContainer = DockerContainer::None; defaultContainer = DockerContainer::None;
} else { } else {
defaultContainer = ContainerProps::containerFromString(containers.begin()->toObject().value(config_key::container).toString()); defaultContainer =
ContainerProps::containerFromString(containers.begin()->toObject().value(config_key::container).toString());
} }
server.insert(config_key::defaultContainer, ContainerProps::containerToString(defaultContainer)); server.insert(config_key::defaultContainer, ContainerProps::containerToString(defaultContainer));
} }
@@ -478,24 +483,9 @@ ErrorCode ServersModel::removeContainer(const int containerIndex)
return errorCode; return errorCode;
} }
void ServersModel::clearCachedProfiles()
{
const auto &containers = m_settings->containers(m_processedServerIndex);
for (DockerContainer container : containers.keys()) {
m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
}
m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
}
updateContainersModel();
}
void ServersModel::clearCachedProfile(const DockerContainer container) void ServersModel::clearCachedProfile(const DockerContainer container)
{ {
m_settings->clearLastConnectionConfig(m_processedServerIndex, container); m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex)); m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) { if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel(); updateDefaultServerContainersModel();
@@ -515,6 +505,36 @@ bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex) const
return false; return false;
} }
QPair<QString, QString> ServersModel::getDnsPair(int serverIndex)
{
QPair<QString, QString> dns;
const QJsonObject &server = m_servers.at(m_processedServerIndex).toObject();
const auto containers = server.value(config_key::containers).toArray();
bool isDnsContainerInstalled = false;
for (const QJsonValue &container : containers) {
if (ContainerProps::containerFromString(container.toObject().value(config_key::container).toString()) == DockerContainer::Dns) {
isDnsContainerInstalled = true;
}
}
dns.first = server.value(config_key::dns1).toString();
dns.second = server.value(config_key::dns2).toString();
if (dns.first.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.first)) {
if (m_isAmneziaDnsEnabled && isDnsContainerInstalled) {
dns.first = protocols::dns::amneziaDnsIp;
} else
dns.first = m_settings->primaryDns();
}
if (dns.second.isEmpty() || !NetworkUtilities::checkIPv4Format(dns.second)) {
dns.second = m_settings->secondaryDns();
}
qDebug() << "VpnConfigurator::getDnsForConfig" << dns.first << dns.second;
return dns;
}
QStringList ServersModel::getAllInstalledServicesName(const int serverIndex) QStringList ServersModel::getAllInstalledServicesName(const int serverIndex)
{ {
QStringList servicesName; QStringList servicesName;
@@ -598,7 +618,8 @@ bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) { if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
return !(protocolConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0")); return !(protocolConfig.value(config_key::last_config).toString().contains("AllowedIPs = 0.0.0.0/0, ::/0"));
} else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn || defaultContainer == DockerContainer::ShadowSocks) { } else if (defaultContainer == DockerContainer::Cloak || defaultContainer == DockerContainer::OpenVpn
|| defaultContainer == DockerContainer::ShadowSocks) {
return !(protocolConfig.value(config_key::last_config).toString().contains("redirect-gateway")); return !(protocolConfig.value(config_key::last_config).toString().contains("redirect-gateway"));
} }
+2 -2
View File
@@ -80,13 +80,12 @@ public slots:
void editServer(const QJsonObject &server, const int serverIndex); void editServer(const QJsonObject &server, const int serverIndex);
void removeServer(); void removeServer();
QJsonObject getDefaultServerConfig(); QJsonObject getServerConfig(const int serverIndex);
void reloadDefaultServerContainerConfig(); void reloadDefaultServerContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config); void updateContainerConfig(const int containerIndex, const QJsonObject config);
void addContainerConfig(const int containerIndex, const QJsonObject config); void addContainerConfig(const int containerIndex, const QJsonObject config);
void clearCachedProfiles();
void clearCachedProfile(const DockerContainer container); void clearCachedProfile(const DockerContainer container);
ErrorCode removeContainer(const int containerIndex); ErrorCode removeContainer(const int containerIndex);
@@ -98,6 +97,7 @@ public slots:
QStringList getAllInstalledServicesName(const int serverIndex); QStringList getAllInstalledServicesName(const int serverIndex);
void toggleAmneziaDns(bool enabled); void toggleAmneziaDns(bool enabled);
QPair<QString, QString> getDnsPair(const int serverIndex);
bool isServerFromApiAlreadyExists(const quint16 crc); bool isServerFromApiAlreadyExists(const quint16 crc);
+5 -5
View File
@@ -17,16 +17,16 @@ Button {
implicitWidth: 190 implicitWidth: 190
implicitHeight: 190 implicitHeight: 190
text: ConnectionController.connectionStateText
Connections { Connections {
target: ConnectionController target: ConnectionController
function onConnectionErrorOccurred(errorMessage) { function onPreparingConfig() {
PageController.showErrorMessage(errorMessage) PageController.showNotificationMessage(qsTr("Unable to disconnect during configuration preparation"))
} }
} }
text: ConnectionController.connectionStateText
// enabled: !ConnectionController.isConnectionInProgress // enabled: !ConnectionController.isConnectionInProgress
background: Item { background: Item {
@@ -139,6 +139,6 @@ Button {
onClicked: { onClicked: {
ServersModel.setProcessedServerIndex(ServersModel.defaultIndex) ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi() ConnectionController.connectButtonClicked()
} }
} }
@@ -69,7 +69,7 @@ ListView {
return return
} }
ContainersModel.setCurrentlyProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index)) ContainersModel.setProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false) InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.close() containersDropDown.close()
@@ -11,6 +11,8 @@ import "../Config"
DrawerType2 { DrawerType2 {
id: root id: root
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
anchors.fill: parent anchors.fill: parent
expandedHeight: parent.height * 0.7 expandedHeight: parent.height * 0.7
@@ -57,7 +59,7 @@ DrawerType2 {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
enabled: ! ServersModel.isDefaultServerDefaultContainerHasSplitTunneling || !ServersModel.getDefaultServerData("isServerFromApi") enabled: !ServersModel.isDefaultServerDefaultContainerHasSplitTunneling || !ServersModel.getDefaultServerData("isServerFromApi")
text: qsTr("Site-based split tunneling") text: qsTr("Site-based split tunneling")
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled") descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
@@ -73,20 +75,22 @@ DrawerType2 {
} }
LabelWithButtonType { LabelWithButtonType {
visible: isAppSplitTinnelingEnabled
Layout.fillWidth: true Layout.fillWidth: true
visible: false
text: qsTr("App-based split tunneling") text: qsTr("App-based split tunneling")
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() { clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSetupWizardConfigSource) PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
root.close() root.close()
} }
} }
DividerType { DividerType {
visible: false visible: isAppSplitTinnelingEnabled
} }
} }
} }
@@ -0,0 +1,136 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "../Controls2"
import "../Controls2/TextTypes"
import InstalledAppsModel 1.0
DrawerType2 {
id: root
anchors.fill: parent
expandedHeight: parent.height * 0.9
onAboutToShow: {
PageController.showBusyIndicator(true)
installedAppsModel.updateModel()
PageController.showBusyIndicator(false)
}
InstalledAppsModel {
id: installedAppsModel
}
expandedContent: Item {
id: container
implicitHeight: expandedHeight
ColumnLayout {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: addButton.top
anchors.topMargin: 16
BackButtonType {
backButtonImage: "qrc:/images/controls/arrow-left.svg"
backButtonFunction: function() {
root.close()
}
}
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
headerText: qsTr("Choose application")
}
ListView {
id: listView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.leftMargin: 16
clip: true
interactive: true
model: installedAppsModel
ScrollBar.vertical: ScrollBar {
id: scrollBar
policy: ScrollBar.AlwaysOn
}
ButtonGroup {
id: buttonGroup
}
delegate: Item {
implicitWidth: root.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
RowLayout {
CheckBoxType {
Layout.fillWidth: true
text: appName
onCheckedChanged: {
listView.model.selectedStateChanged(index, checked)
}
}
Image {
source: "image://installedAppImage/" + appIcon
sourceSize.width: 24
sourceSize.height: 24
Layout.rightMargin: 48
}
}
DividerType {}
}
}
}
}
BasicButtonType {
id: addButton
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: 16
anchors.rightMargin: 16
anchors.leftMargin: 16
text: qsTr("Add selected")
clickedFunc: function() {
PageController.showBusyIndicator(true)
AppSplitTunnelingController.addApps(listView.model.getSelectedAppsInfo())
PageController.showBusyIndicator(false)
root.close()
}
}
}
}
@@ -41,7 +41,7 @@ ListView {
clickedFunction: function() { clickedFunction: function() {
if (isInstalled) { if (isInstalled) {
var containerIndex = root.model.mapToSource(index) var containerIndex = root.model.mapToSource(index)
ContainersModel.setCurrentlyProcessedContainerIndex(containerIndex) ContainersModel.setProcessedContainerIndex(containerIndex)
if (serviceType !== ProtocolEnum.Other) { if (serviceType !== ProtocolEnum.Other) {
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) { if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
@@ -52,27 +52,6 @@ ListView {
} }
switch (containerIndex) { switch (containerIndex) {
case ContainerEnum.OpenVpn: {
OpenVpnConfigModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolOpenVpnSettings)
break
}
case ContainerEnum.Xray: {
XrayConfigModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolXraySettings)
break
}
case ContainerEnum.WireGuard: {
WireGuardConfigModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolWireGuardSettings)
break
}
case ContainerEnum.Awg: {
AwgConfigModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolAwgSettings)
break
}
case ContainerEnum.Ipsec: { case ContainerEnum.Ipsec: {
ProtocolsModel.updateModel(config) ProtocolsModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolRaw) PageController.goToPage(PageEnum.PageProtocolRaw)
@@ -98,7 +77,7 @@ ListView {
} }
} else { } else {
ContainersModel.setCurrentlyProcessedContainerIndex(root.model.mapToSource(index)) ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
InstallController.setShouldCreateServer(false) InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings) PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
} }
+4 -4
View File
@@ -90,12 +90,12 @@ CheckBox {
} }
contentItem: Item { contentItem: Item {
implicitWidth: content.implicitWidth anchors.left: parent.left
implicitHeight: content.implicitHeight anchors.right: parent.right
anchors.fill: parent
anchors.leftMargin: 8 + background.width anchors.leftMargin: 8 + background.width
implicitHeight: content.implicitHeight
ColumnLayout { ColumnLayout {
id: content id: content
+1 -9
View File
@@ -86,13 +86,6 @@ Item {
} }
} }
/** Set once based on first implicit height change once all children are layed out */
Component.onCompleted: {
if (root.isCollapsed && root.collapsedHeight == 0) {
root.collapsedHeight = drawerContent.implicitHeight
}
}
Rectangle { Rectangle {
id: background id: background
@@ -186,7 +179,7 @@ Item {
y: root.height - drawerContent.height y: root.height - drawerContent.height
state: root.drawerCollapsed state: root.drawerCollapsed
implicitHeight: root.isCollapsed ? collapsedLoader.implicitHeight : expandedLoader.implicitHeight implicitHeight: root.isCollapsed ? collapsedHeight : expandedHeight
onStateChanged: { onStateChanged: {
if (root.isCollapsed) { if (root.isCollapsed) {
@@ -246,7 +239,6 @@ Item {
Loader { Loader {
id: collapsedLoader id: collapsedLoader
visible: root.isCollapsed
sourceComponent: root.collapsedContent sourceComponent: root.collapsedContent
anchors.right: parent.right anchors.right: parent.right
@@ -126,32 +126,6 @@ Item {
} }
} }
} }
BasicButtonType {
visible: (root.buttonText !== "") || (root.buttonImageSource !== "")
// defaultColor: "transparent"
// hoveredColor: Qt.rgba(1, 1, 1, 0.08)
// pressedColor: Qt.rgba(1, 1, 1, 0.12)
// disabledColor: "#878B91"
// textColor: "#D7D8DB"
// borderWidth: 0
focusPolicy: Qt.NoFocus
text: root.buttonText
imageSource: root.buttonImageSource
// Layout.rightMargin: 24
Layout.preferredHeight: content.implicitHeight
Layout.preferredWidth: content.implicitHeight
squareLeftSide: true
clickedFunc: function() {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
}
} }
} }
@@ -187,6 +161,28 @@ Item {
} }
} }
BasicButtonType {
visible: (root.buttonText !== "") || (root.buttonImageSource !== "")
focusPolicy: Qt.NoFocus
text: root.buttonText
imageSource: root.buttonImageSource
anchors.top: content.top
anchors.bottom: content.bottom
anchors.right: content.right
height: content.implicitHeight
width: content.implicitHeight
squareLeftSide: true
clickedFunc: function() {
if (root.clickedFunc && typeof root.clickedFunc === "function") {
root.clickedFunc()
}
}
}
function getBackgroundBorderColor(noneFocusedColor) { function getBackgroundBorderColor(noneFocusedColor) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor return textField.focus ? root.borderFocusedColor : noneFocusedColor
} }
+95 -99
View File
@@ -82,7 +82,7 @@ PageType {
leftImageColor: "transparent" leftImageColor: "transparent"
borderWidth: 0 borderWidth: 0
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
(ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi")) (ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi"))
text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled") text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
@@ -107,131 +107,128 @@ PageType {
id: drawer id: drawer
anchors.fill: parent anchors.fill: parent
collapsedContent: ColumnLayout { collapsedContent: Item {
DividerType { implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
Layout.topMargin: 10 Component.onCompleted: {
Layout.fillWidth: false drawer.expandedHeight = implicitHeight
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
} }
ColumnLayout {
id: collapsed
RowLayout { anchors.left: parent.left
Layout.topMargin: 14 anchors.right: parent.right
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 0 Component.onCompleted: {
drawer.collapsedHeight = collapsed.implicitHeight
Connections {
target: drawer
function onEntered() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
}
function onExited() {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
}
function onPressed(pressed, entered) {
collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
}
} }
Header1TextType { DividerType {
id: collapsedButtonHeader Layout.topMargin: 10
Layout.maximumWidth: drawer.width - 48 - 18 - 12 // todo Layout.fillWidth: false
Layout.preferredWidth: 20
maximumLineCount: 2 Layout.preferredHeight: 2
elide: Qt.ElideRight Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
} }
ImageButtonType { RowLayout {
id: collapsedButtonChevron Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: 8 spacing: 0
hoverEnabled: false Connections {
image: "qrc:/images/controls/chevron-down.svg" target: drawer
imageColor: "#d7d8db" function onEntered() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
} else {
collapsedButtonHeader.opacity = 1
}
}
icon.width: 18 function onExited() {
icon.height: 18 if (drawer.isCollapsed) {
backgroundRadius: 16 collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
horizontalPadding: 4 collapsedButtonHeader.opacity = 1
topPadding: 4 } else {
bottomPadding: 3 collapsedButtonHeader.opacity = 1
}
}
onClicked: { function onPressed(pressed, entered) {
if (drawer.isCollapsed) { if (drawer.isCollapsed) {
drawer.open() collapsedButtonChevron.backgroundColor = pressed ? collapsedButtonChevron.pressedColor : entered ? collapsedButtonChevron.hoveredColor : collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 0.7
} else {
collapsedButtonHeader.opacity = 1
}
}
}
Header1TextType {
id: collapsedButtonHeader
Layout.maximumWidth: drawer.isCollapsed ? drawer.width - 48 - 18 - 12 : drawer.width// todo
maximumLineCount: 2
elide: Qt.ElideRight
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
}
ImageButtonType {
id: collapsedButtonChevron
Layout.leftMargin: 8
visible: drawer.isCollapsed
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: "#d7d8db"
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
onClicked: {
if (drawer.isCollapsed) {
drawer.open()
}
} }
} }
} }
}
LabelTextType { LabelTextType {
id: collapsedServerMenuDescription id: collapsedServerMenuDescription
Layout.bottomMargin: 44 Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionCollapsed text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
} }
}
expandedContent: Item {
id: serverMenuContainer
implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
Component.onCompleted: {
drawer.expandedHeight = serverMenuContainer.implicitHeight
} }
ColumnLayout { ColumnLayout {
id: serversMenuHeader id: serversMenuHeader
anchors.top: parent.top anchors.top: collapsed.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
Header1TextType {
Layout.fillWidth: true
Layout.topMargin: 14
Layout.leftMargin: 16
Layout.rightMargin: 16
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
}
LabelTextType {
id: expandedServersMenuDescription
Layout.bottomMargin: ServersModel.isDefaultServerFromApi ? 69 : 24
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionExpanded
}
RowLayout { RowLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8 spacing: 8
visible: !ServersModel.isDefaultServerFromApi visible: !ServersModel.isDefaultServerFromApi
onVisibleChanged: expandedServersMenuDescription.Layout
DropDownType { DropDownType {
id: containersDropDown id: containersDropDown
@@ -299,7 +296,6 @@ PageType {
} }
} }
ButtonGroup { ButtonGroup {
id: serversRadioButtonGroup id: serversRadioButtonGroup
} }
@@ -311,34 +311,6 @@ PageType {
KeyNavigation.tab: saveRestartButton KeyNavigation.tab: saveRestartButton
} }
BasicButtonType {
Layout.topMargin: 24
Layout.leftMargin: -8
implicitHeight: 32
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
textColor: "#EB5757"
text: qsTr("Remove AmneziaWG")
onClicked: {
var headerText = qsTr("Remove AmneziaWG from server?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
BasicButtonType { BasicButtonType {
id: saveRestartButton id: saveRestartButton
@@ -129,7 +129,6 @@ PageType {
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: portTextField id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
@@ -366,37 +365,6 @@ PageType {
} }
} }
BasicButtonType {
Layout.topMargin: 24
Layout.leftMargin: -8
implicitHeight: 32
visible: ContainersModel.getCurrentlyProcessedContainerIndex() === ContainerEnum.OpenVpn
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
textColor: "#EB5757"
text: qsTr("Remove OpenVPN")
clickedFunc: function() {
var headerText = qsTr("Remove OpenVpn from server?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
BasicButtonType { BasicButtonType {
id: saveRestartButton id: saveRestartButton
+4 -4
View File
@@ -35,7 +35,7 @@ PageType {
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
headerText: ContainersModel.getCurrentlyProcessedContainerName() + qsTr(" settings") headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
} }
} }
@@ -177,18 +177,18 @@ PageType {
visible: ServersModel.isProcessedServerHasWriteAccess() visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName() text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: "#EB5757" textColor: "#EB5757"
clickedFunction: function() { clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getCurrentlyProcessedContainerName()) var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel") var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer() InstallController.removeProcessedContainer()
} }
var noButtonFunction = function() { var noButtonFunction = function() {
} }
@@ -86,6 +86,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 40
enabled: isPortEditable
headerText: qsTr("Port") headerText: qsTr("Port")
textFieldText: port textFieldText: port
textField.maximumLength: 5 textField.maximumLength: 5
@@ -105,6 +107,8 @@ PageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 20 Layout.topMargin: 20
enabled: isCipherEditable
descriptionText: qsTr("Cipher") descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher") headerText: qsTr("Cipher")
@@ -148,6 +152,8 @@ PageType {
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
enabled: isPortEditable | isCipherEditable
text: qsTr("Save") text: qsTr("Save")
clickedFunc: function() { clickedFunc: function() {

Some files were not shown because too many files have changed in this diff Show More