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/scripts_registry.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/vpnConfigurationController.h
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.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/scripts_registry.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/vpnConfigurationController.cpp
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/notificationhandler.cpp
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.cpp
+37 -43
View File
@@ -14,10 +14,12 @@
#include "logger.h"
#include "version.h"
#include "ui/models/installedAppsModel.h"
#include "platforms/ios/QRCodeReaderBase.h"
#if defined(Q_OS_ANDROID)
#include "platforms/android/android_controller.h"
#include "core/installedAppsImageProvider.h"
#endif
#include "protocols/qml_register_protocols.h"
@@ -82,8 +84,7 @@ void AmneziaApplication::init()
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_configurator));
m_vpnConnection.reset(new VpnConnection(m_settings));
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start();
@@ -96,18 +97,16 @@ void AmneziaApplication::init()
qFatal("Android logging initialization failed");
}
AndroidController::instance()->setSaveLogs(m_settings->isSaveLogs());
connect(m_settings.get(), &Settings::saveLogsChanged,
AndroidController::instance(), &AndroidController::setSaveLogs);
connect(m_settings.get(), &Settings::saveLogsChanged, AndroidController::instance(), &AndroidController::setSaveLogs);
AndroidController::instance()->setScreenshotsEnabled(m_settings->isScreenshotsEnabled());
connect(m_settings.get(), &Settings::screenshotsEnabledChanged,
AndroidController::instance(), &AndroidController::setScreenshotsEnabled);
connect(m_settings.get(), &Settings::screenshotsEnabledChanged, AndroidController::instance(),
&AndroidController::setScreenshotsEnabled);
connect(m_settings.get(), &Settings::serverRemoved,
AndroidController::instance(), &AndroidController::resetLastServer);
connect(m_settings.get(), &Settings::serverRemoved, AndroidController::instance(),
&AndroidController::resetLastServer);
connect(m_settings.get(), &Settings::settingsCleared,
[](){ AndroidController::instance()->resetLastServer(-1); });
connect(m_settings.get(), &Settings::settingsCleared, []() { AndroidController::instance()->resetLastServer(-1); });
connect(AndroidController::instance(), &AndroidController::initConnectionState, this,
[this](Vpn::ConnectionState state) {
@@ -124,8 +123,12 @@ void AmneziaApplication::init()
m_importController->extractConfigFromData(data);
m_pageController->goToPageViewConfig();
});
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
#endif
#ifdef Q_OS_IOS
IosController::Instance()->initialize();
connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
@@ -140,13 +143,10 @@ void AmneziaApplication::init()
m_settingsController->importBackupFromOutside(filePath);
});
QTimer::singleShot(0, this, [this](){
AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled());
});
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
connect(m_settings.get(), &Settings::screenshotsEnabledChanged, [](bool enabled) {
AmneziaVPN::toggleScreenshots(enabled);
});
connect(m_settings.get(), &Settings::screenshotsEnabledChanged,
[](bool enabled) { AmneziaVPN::toggleScreenshots(enabled); });
#endif
m_notificationHandler.reset(NotificationHandler::create(nullptr));
@@ -234,7 +234,8 @@ void AmneziaApplication::registerTypes()
qmlRegisterSingletonType(QUrl("qrc:/ui/qml/Filters/ContainersModelFilters.qml"), "ContainersModelFilters", 1, 0,
"ContainersModelFilters");
//
qmlRegisterType<InstalledAppsModel>("InstalledAppsModel", 1, 0, "InstalledAppsModel");
Vpn::declareQmlVpnConnectionStateEnum();
PageLoader::declareQmlPageEnum();
}
@@ -325,6 +326,9 @@ void AmneziaApplication::initModels()
m_sitesModel.reset(new SitesModel(m_settings, this));
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_engine->rootContext()->setContextProperty("ProtocolsModel", m_protocolsModel.get());
@@ -358,28 +362,30 @@ void AmneziaApplication::initModels()
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, m_serversModel.get(),
&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()
{
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());
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(),
&ConnectionController::onTranslationsUpdated);
m_pageController.reset(new PageController(m_serversModel, m_settings));
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());
connect(m_installController.get(), &InstallController::passphraseRequestStarted, m_pageController.get(),
&PageController::showPassphraseRequestDrawer);
@@ -391,8 +397,7 @@ void AmneziaApplication::initControllers()
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel,
m_settings, m_configurator));
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings));
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
m_settingsController.reset(
@@ -407,20 +412,9 @@ void AmneziaApplication::initControllers()
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
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_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 "vpnconnection.h"
#include "configurators/vpn_configurator.h"
#include "core/controllers/apiController.h"
#include "ui/controllers/connectionController.h"
#include "ui/controllers/exportController.h"
@@ -24,7 +24,7 @@
#include "ui/controllers/settingsController.h"
#include "ui/controllers/sitesController.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/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h"
@@ -42,6 +42,7 @@
#include "ui/models/services/sftpConfigModel.h"
#include "ui/models/sites_model.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/appSplitTunnelingModel.h"
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
@@ -84,7 +85,6 @@ private:
QQmlApplicationEngine *m_engine {};
std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
QSharedPointer<ContainerProps> m_containerProps;
QSharedPointer<ProtocolProps> m_protocolProps;
@@ -98,6 +98,7 @@ private:
QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel;
QSharedPointer<SitesModel> m_sitesModel;
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
@@ -125,6 +126,7 @@ private:
QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController;
QScopedPointer<ApiController> m_apiController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
};
#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_SYSTEM_EXEMPTED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- Enable when VPN-per-app mode will be implemented -->
<!-- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
<application
android:name=".AmneziaApplication"
@@ -66,6 +66,7 @@ class Awg : Wireguard() {
return AwgConfig.build {
configWireguard(configData, configDataJson)
configSplitTunneling(config)
configAppSplitTunneling(config)
configData["Jc"]?.let { setJc(it.toInt()) }
configData["Jmin"]?.let { setJmin(it.toInt()) }
configData["Jmax"]?.let { setJmax(it.toInt()) }
@@ -79,6 +79,7 @@ open class OpenVpn : Protocol() {
}
configPluggableTransport(configBuilder, config)
configBuilder.configSplitTunneling(config)
configBuilder.configAppSplitTunneling(config)
scope.launch {
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) {
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) {
Log.d(TAG, "addDisallowedApplication: $app")
vpnBuilder.addDisallowedApplication(app)
@@ -16,6 +16,7 @@ open class ProtocolConfig protected constructor(
val excludedRoutes: Set<InetNetwork>,
val includedAddresses: Set<InetNetwork>,
val excludedAddresses: Set<InetNetwork>,
val includedApplications: Set<String>,
val excludedApplications: Set<String>,
val httpProxy: ProxyInfo?,
val allowAllAF: Boolean,
@@ -31,6 +32,7 @@ open class ProtocolConfig protected constructor(
builder.excludedRoutes,
builder.includedAddresses,
builder.excludedAddresses,
builder.includedApplications,
builder.excludedApplications,
builder.httpProxy,
builder.allowAllAF,
@@ -45,6 +47,7 @@ open class ProtocolConfig protected constructor(
internal val excludedRoutes: MutableSet<InetNetwork> = hashSetOf()
internal val includedAddresses: MutableSet<InetNetwork> = hashSetOf()
internal val excludedAddresses: MutableSet<InetNetwork> = hashSetOf()
internal val includedApplications: MutableSet<String> = hashSetOf()
internal val excludedApplications: MutableSet<String> = hashSetOf()
internal var searchDomain: String? = null
@@ -88,6 +91,9 @@ open class ProtocolConfig protected constructor(
fun excludeAddress(addr: InetNetwork) = apply { this.excludedAddresses += addr }
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 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.ServiceConnection
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.net.VpnService
import android.os.Bundle
@@ -24,12 +25,15 @@ import androidx.core.content.ContextCompat
import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE
import kotlin.text.RegexOption.IGNORE_CASE
import AppListProvider
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.amnezia.vpn.protocol.getStatistics
import org.amnezia.vpn.protocol.getStatus
import org.amnezia.vpn.qt.QtAndroidController
@@ -476,4 +480,32 @@ class AmneziaActivity : QtActivity() {
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 {
configWireguard(configData, configDataJson)
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
# 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)
@@ -30,6 +30,7 @@ set(HEADERS ${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.h
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.h
)
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/authResultReceiver.cpp
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
)
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,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
QString AwgConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
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();
QString awgConfig = jsonConfig.value(config_key::config).toString();
+2 -2
View File
@@ -11,8 +11,8 @@ class AwgConfigurator : public WireguardConfigurator
public:
AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode);
};
#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,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString CloakConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode)
{
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
QString cloakPublicKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::cloak::ckPublicKeyPath, &e);
amnezia::protocols::cloak::ckPublicKeyPath, errorCode);
cloakPublicKey.replace("\n", "");
if (errorCode != ErrorCode::NoError) {
return "";
}
QString cloakBypassUid = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::cloak::ckBypassUidKeyPath, &e);
amnezia::protocols::cloak::ckBypassUidKeyPath, errorCode);
cloakBypassUid.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
if (errorCode != ErrorCode::NoError) {
return "";
}
+3 -3
View File
@@ -7,14 +7,14 @@
using namespace amnezia;
class CloakConfigurator : ConfiguratorBase
class CloakConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
CloakConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode);
};
#endif // CLOAK_CONFIGURATOR_H
+21 -3
View File
@@ -1,8 +1,26 @@
#include "configurator_base.h"
ConfiguratorBase::ConfiguratorBase(std::shared_ptr<Settings> settings, QObject *parent)
: QObject{parent},
m_settings(settings)
: QObject { parent }, 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>
class Settings;
#include "containers/containers_defs.h"
#include "core/defs.h"
#include "settings.h"
class ConfiguratorBase : public QObject
{
@@ -14,7 +13,17 @@ class ConfiguratorBase : public QObject
public:
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:
void processConfigWithDnsSettings(const QPair<QString, QString> &dns, QString &protocolConfigString);
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,
DockerContainer container, ErrorCode *errorCode)
DockerContainer container, ErrorCode errorCode)
{
Ikev2Configurator::ConnectionData connData;
connData.host = credentials.hostName;
@@ -40,17 +40,17 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
.arg(connData.clientId);
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\"")
.arg(connData.password)
.arg(connData.clientId)
.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 =
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 ca cert size:" << connData.caCert.size();
@@ -58,13 +58,13 @@ Ikev2Configurator::ConnectionData Ikev2Configurator::prepareIkev2Config(const Se
return connData;
}
QString Ikev2Configurator::genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode)
QString Ikev2Configurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode)
{
Q_UNUSED(containerConfig)
ConnectionData connData = prepareIkev2Config(credentials, container, errorCode);
if (errorCode && *errorCode) {
if (errorCode != ErrorCode::NoError) {
return "";
}
+4 -4
View File
@@ -7,7 +7,7 @@
#include "configurator_base.h"
#include "core/defs.h"
class Ikev2Configurator : ConfiguratorBase
class Ikev2Configurator : public ConfiguratorBase
{
Q_OBJECT
public:
@@ -21,15 +21,15 @@ public:
QString host; // host ip
};
QString genIkev2Config(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode);
QString genIkev2Config(const ConnectionData &connData);
QString genMobileConfig(const ConnectionData &connData);
QString genStrongSwanConfig(const ConnectionData &connData);
ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr);
DockerContainer container, ErrorCode errorCode);
};
#endif // IKEV2_CONFIGURATOR_H
+29 -31
View File
@@ -14,9 +14,9 @@
#endif
#include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
#include "core/server_defs.h"
#include "core/controllers/serverController.h"
#include "settings.h"
#include "utilities.h"
@@ -31,59 +31,51 @@ OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, QOb
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container,
ErrorCode *errorCode)
ErrorCode errorCode)
{
OpenVpnConfigurator::ConnectionData connData = OpenVpnConfigurator::createCertRequest();
connData.host = credentials.hostName;
if (connData.privKey.isEmpty() || connData.request.isEmpty()) {
if (errorCode)
*errorCode = ErrorCode::OpenSslFailed;
errorCode = ErrorCode::OpenSslFailed;
return connData;
}
QString reqFileName = QString("%1/%2.req").arg(amnezia::protocols::openvpn::clientsDirPath).arg(connData.clientId);
ServerController serverController(m_settings);
ErrorCode e = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
if (e) {
if (errorCode)
*errorCode = e;
errorCode = serverController.uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
if (errorCode != ErrorCode::NoError) {
return connData;
}
e = signCert(container, credentials, connData.clientId);
if (e) {
if (errorCode)
*errorCode = e;
errorCode = signCert(container, credentials, connData.clientId);
if (errorCode != ErrorCode::NoError) {
return connData;
}
connData.caCert = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::openvpn::caCertPath, &e);
amnezia::protocols::openvpn::caCertPath, errorCode);
connData.clientCert = serverController.getTextFileFromContainer(
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 = e;
if (errorCode != ErrorCode::NoError) {
return connData;
}
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 (errorCode)
*errorCode = ErrorCode::SshScpFailureError;
errorCode = ErrorCode::SshScpFailureError;
}
return connData;
}
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
QString OpenVpnConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode)
{
ServerController serverController(m_settings);
QString config =
@@ -91,7 +83,7 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
if (errorCode && *errorCode) {
if (errorCode != ErrorCode::NoError) {
return "";
}
@@ -113,17 +105,20 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
QJsonObject jConfig;
jConfig[config_key::config] = config;
clientId = connData.clientId;
jConfig[config_key::clientId] = connData.clientId;
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();
if (!m_settings->server(serverIndex).value(config_key::configVersion).toInt()) {
if (!isApiConfig) {
QRegularExpression regex("redirect-gateway.*");
config.replace(regex, "");
@@ -138,9 +133,9 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig,
// no redirect-gateway
}
if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#ifndef Q_OS_ANDROID
#ifndef Q_OS_ANDROID
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
#endif
#endif
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
config.append("block-ipv6\n");
@@ -164,9 +159,12 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(QString jsonConfig,
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();
QRegularExpression regex("redirect-gateway.*");
+17 -17
View File
@@ -7,37 +7,37 @@
#include "configurator_base.h"
#include "core/defs.h"
class OpenVpnConfigurator : ConfiguratorBase
class OpenVpnConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
OpenVpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
struct ConnectionData {
struct ConnectionData
{
QString clientId;
QString request; // certificate request
QString privKey; // client private key
QString request; // certificate request
QString privKey; // client private key
QString clientCert; // client signed certificate
QString caCert; // server certificate
QString taKey; // tls-auth key
QString host; // host ip
QString caCert; // server certificate
QString taKey; // tls-auth key
QString host; // host ip
};
QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode);
QString processConfigWithLocalSettings(QString jsonConfig, const int serverIndex);
QString processConfigWithExportSettings(QString jsonConfig);
ErrorCode signCert(DockerContainer container,
const ServerCredentials &credentials, QString clientId);
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
static ConnectionData createCertRequest();
private:
ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode = nullptr);
ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
ErrorCode errorCode);
ErrorCode signCert(DockerContainer container, const ServerCredentials &credentials, QString clientId);
};
#endif // OPENVPN_CONFIGURATOR_H
@@ -13,18 +13,16 @@ ShadowSocksConfigurator::ShadowSocksConfigurator(std::shared_ptr<Settings> setti
}
QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
QString ShadowSocksConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode)
{
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
QString ssKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::shadowsocks::ssKeyPath, &e);
amnezia::protocols::shadowsocks::ssKeyPath, errorCode);
ssKey.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
if (errorCode != ErrorCode::NoError) {
return "";
}
@@ -6,14 +6,14 @@
#include "configurator_base.h"
#include "core/defs.h"
class ShadowSocksConfigurator : ConfiguratorBase
class ShadowSocksConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
ShadowSocksConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode);
};
#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 "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
#include "core/server_defs.h"
#include "core/controllers/serverController.h"
#include "settings.h"
#include "utilities.h"
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, bool isAwg, QObject *parent)
: ConfiguratorBase(settings, parent), m_isAwg(isAwg)
{
m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath
: amnezia::protocols::wireguard::serverConfigPath;
m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath
: amnezia::protocols::wireguard::serverPublicKeyPath;
m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath
: amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template
: ProtocolScriptType::wireguard_template;
m_serverConfigPath =
m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath;
m_serverPublicKeyPath =
m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath;
m_serverPskKeyPath =
m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template : ProtocolScriptType::wireguard_template;
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
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,
DockerContainer container,
const QJsonObject &containerConfig,
ErrorCode *errorCode)
ErrorCode errorCode)
{
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName;
connData.port = containerConfig.value(m_protocolName).toObject().value(config_key::port).toString(m_defaultPort);
if (connData.clientPrivKey.isEmpty() || connData.clientPubKey.isEmpty()) {
if (errorCode)
*errorCode = ErrorCode::InternalError;
errorCode = ErrorCode::InternalError;
return connData;
}
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
// Get list of already created clients (only IP addresses)
@@ -94,9 +91,8 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return ErrorCode::NoError;
};
e = serverController.runContainerScript(credentials, container, script, cbReadStdOut);
if (errorCode && e) {
*errorCode = e;
errorCode = serverController.runContainerScript(credentials, container, script, cbReadStdOut);
if (errorCode != ErrorCode::NoError) {
return connData;
}
@@ -110,8 +106,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
} else {
int next = ips.last().split(".").last().toInt() + 1;
if (next > 254) {
if (errorCode)
*errorCode = ErrorCode::AddressPoolError;
errorCode = ErrorCode::AddressPoolError;
return connData;
}
nextIpNumber = QString::number(next);
@@ -123,8 +118,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
{
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts);
if (l.isEmpty()) {
if (errorCode)
*errorCode = ErrorCode::AddressPoolError;
errorCode = ErrorCode::AddressPoolError;
return connData;
}
l.removeLast();
@@ -134,20 +128,17 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
}
// Get keys
connData.serverPubKey = serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, &e);
connData.serverPubKey =
serverController.getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode);
connData.serverPubKey.replace("\n", "");
if (e) {
if (errorCode)
*errorCode = e;
if (errorCode != ErrorCode::NoError) {
return connData;
}
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, &e);
connData.pskKey = serverController.getTextFileFromContainer(container, credentials, m_serverPskKeyPath, errorCode);
connData.pskKey.replace("\n", "");
if (e) {
if (errorCode)
*errorCode = e;
if (errorCode != ErrorCode::NoError) {
return connData;
}
@@ -158,26 +149,24 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
"AllowedIPs = %3/32\n\n")
.arg(connData.clientPubKey, connData.pskKey, connData.clientIP);
e = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath,
libssh::ScpOverwriteMode::ScpAppendToExisting);
errorCode = serverController.uploadTextFileToContainer(container, credentials, configPart, m_serverConfigPath,
libssh::ScpOverwriteMode::ScpAppendToExisting);
if (e) {
if (errorCode)
*errorCode = e;
if (errorCode != ErrorCode::NoError) {
return connData;
}
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
.arg(m_serverConfigPath);
e = serverController.runScript(
errorCode = serverController.runScript(
credentials, serverController.replaceVars(script, serverController.genVarsForScript(credentials, container)));
return connData;
}
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
QString WireguardConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode)
{
ServerController serverController(m_settings);
QString scriptData = amnezia::scriptData(m_configTemplate, container);
@@ -185,7 +174,7 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
scriptData, serverController.genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
if (errorCode && *errorCode) {
if (errorCode != ErrorCode::NoError) {
return "";
}
@@ -205,30 +194,25 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
jConfig[config_key::client_pub_key] = connData.clientPubKey;
jConfig[config_key::psk_key] = connData.pskKey;
jConfig[config_key::server_pub_key] = connData.serverPubKey;
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();
}
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
config.replace("$PRIMARY_DNS", m_settings->primaryDns());
config.replace("$SECONDARY_DNS", m_settings->secondaryDns());
processConfigWithDnsSettings(dns, protocolConfigString);
QJsonObject jConfig;
jConfig[config_key::config] = config;
return QJsonDocument(jConfig).toJson();
return protocolConfigString;
}
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());
config.replace("$SECONDARY_DNS", m_settings->secondaryDns());
processConfigWithDnsSettings(dns, protocolConfigString);
return config;
return protocolConfigString;
}
@@ -25,18 +25,20 @@ public:
QString port;
};
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode errorCode);
QString processConfigWithLocalSettings(QString config);
QString processConfigWithExportSettings(QString config);
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
static ConnectionData genClientKeys();
private:
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode errorCode);
bool m_isAwg;
QString m_serverConfigPath;
QString m_serverPublicKeyPath;
+12 -19
View File
@@ -1,43 +1,36 @@
#include "xray_configurator.h"
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonObject>
#include "core/scripts_registry.h"
#include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent):
ConfiguratorBase(settings, parent)
XrayConfigurator::XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent) : ConfiguratorBase(settings, parent)
{
}
QString XrayConfigurator::genXrayConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
QString XrayConfigurator::createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
ErrorCode errorCode)
{
ErrorCode e = ErrorCode::NoError;
ServerController serverController(m_settings);
QString config =
serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
QString config = serverController.replaceVars(amnezia::scriptData(ProtocolScriptType::xray_template, container),
serverController.genVarsForScript(credentials, container, containerConfig));
QString xrayPublicKey = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::xray::PublicKeyPath, &e);
QString xrayPublicKey =
serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::xray::PublicKeyPath, errorCode);
xrayPublicKey.replace("\n", "");
QString xrayUuid = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::xray::uuidPath, &e);
QString xrayUuid = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::xray::uuidPath, errorCode);
xrayUuid.replace("\n", "");
QString xrayShortId = serverController.getTextFileFromContainer(container, credentials,
amnezia::protocols::xray::shortidPath, &e);
QString xrayShortId = serverController.getTextFileFromContainer(container, credentials, amnezia::protocols::xray::shortidPath, errorCode);
xrayShortId.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
if (errorCode != ErrorCode::NoError) {
return "";
}
+3 -3
View File
@@ -6,14 +6,14 @@
#include "configurator_base.h"
#include "core/defs.h"
class XrayConfigurator : ConfiguratorBase
class XrayConfigurator : public ConfiguratorBase
{
Q_OBJECT
public:
XrayConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
QString genXrayConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig,
ErrorCode errorCode);
};
#endif // XRAY_CONFIGURATOR_H
+13
View File
@@ -1,5 +1,8 @@
#include "containers_defs.h"
#include "QJsonObject"
#include "QJsonDocument"
QDebug operator<<(QDebug debug, const amnezia::DockerContainer &c)
{
QDebugStateSaver saver(debug);
@@ -363,3 +366,13 @@ bool ContainerProps::isShareable(DockerContainer container)
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 bool isShareable(amnezia::DockerContainer container);
static QJsonObject getProtocolConfigFromContainer(const amnezia::Proto protocol, const QJsonObject &containerConfig);
};
static void declareQmlContainerEnum()
@@ -5,9 +5,8 @@
#include <QNetworkReply>
#include <QtConcurrent>
#include "configurators/openvpn_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h"
#include "configurators/wireguard_configurator.h"
namespace
{
@@ -24,9 +23,7 @@ namespace
}
}
ApiController::ApiController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel)
ApiController::ApiController(QObject *parent) : QObject(parent)
{
}
@@ -67,21 +64,14 @@ QJsonObject ApiController::fillApiPayload(const QString &protocol, const ApiCont
return obj;
}
void ApiController::updateServerConfigFromApi()
ErrorCode ApiController::updateServerConfigFromApi(QJsonObject &serverConfig)
{
QtConcurrent::run([this]() {
if (m_isConfigUpdateStarted) {
emit updateFinished(false);
return;
}
QFutureWatcher<ErrorCode> watcher;
auto serverConfig = m_serversModel->getDefaultServerConfig();
QFuture<ErrorCode> future = QtConcurrent::run([this, &serverConfig]() {
auto containerConfig = serverConfig.value(config_key::containers).toArray();
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
emit updateStarted();
m_isConfigUpdateStarted = true;
if (serverConfig.value(config_key::configVersion).toInt()) {
QNetworkAccessManager manager;
QNetworkRequest request;
@@ -114,9 +104,7 @@ void ApiController::updateServerConfigFromApi()
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
return ErrorCode::ApiConfigDownloadError;
}
QByteArray ba_uncompressed = qUncompress(ba);
@@ -136,35 +124,22 @@ void ApiController::updateServerConfigFromApi()
auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig, m_serversModel->getDefaultServerIndex());
} else {
QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll());
qDebug() << reply->error();
qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(errorString(ApiConfigDownloadError));
m_isConfigUpdateStarted = false;
return;
return ErrorCode::ApiConfigDownloadError;
}
}
emit updateFinished(m_isConfigUpdateStarted);
m_isConfigUpdateStarted = false;
return;
return ErrorCode::NoError;
});
}
void ApiController::clearApiConfig()
{
auto serverConfig = m_serversModel->getDefaultServerConfig();
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());
QEventLoop wait;
connect(&watcher, &QFutureWatcher<ErrorCode>::finished, &wait, &QEventLoop::quit);
watcher.setFuture(future);
wait.exec();
return watcher.result();
}
@@ -4,26 +4,16 @@
#include <QObject>
#include "configurators/openvpn_configurator.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
class ApiController : public QObject
{
Q_OBJECT
public:
explicit ApiController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, QObject *parent = nullptr);
explicit ApiController(QObject *parent = nullptr);
public slots:
void updateServerConfigFromApi();
void clearApiConfig();
signals:
void updateStarted();
void updateFinished(bool isConfigUpdateStarted);
void errorOccurred(const QString &errorMessage);
ErrorCode updateServerConfigFromApi(QJsonObject &serverConfig);
private:
struct ApiPayloadData {
@@ -36,11 +26,6 @@ private:
ApiPayloadData generateApiPayloadData(const QString &protocol);
QJsonObject fillApiPayload(const QString &protocol, const ApiController::ApiPayloadData &apiPayloadData);
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
+7 -154
View File
@@ -29,8 +29,7 @@
#include "core/networkUtilities.h"
#include "settings.h"
#include "utilities.h"
#include <configurators/vpn_configurator.h>
#include "vpnConfigurationController.h"
namespace
{
@@ -179,11 +178,10 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
}
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\'\"")
.arg(ContainerProps::containerToString(container))
@@ -195,7 +193,7 @@ QByteArray ServerController::getTextFileFromContainer(DockerContainer container,
return ErrorCode::NoError;
};
*errorCode = runScript(credentials, script, cbReadStdOut);
errorCode = runScript(credentials, script, cbReadStdOut);
return QByteArray::fromHex(stdOut.toUtf8());
}
@@ -498,7 +496,7 @@ ErrorCode ServerController::configureContainerWorker(const ServerCredentials &cr
genVarsForScript(credentials, container, config)),
cbReadStdOut, cbReadStdErr);
m_configurator->updateContainerConfigAfterInstallation(container, config, stdOut);
VpnConfigurationsController::updateContainerConfigAfterInstallation(container, config, stdOut);
return e;
}
@@ -662,7 +660,7 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
return vars;
}
QString ServerController::checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode)
QString ServerController::checkSshConnection(const ServerCredentials &credentials, ErrorCode errorCode)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
@@ -674,11 +672,7 @@ QString ServerController::checkSshConnection(const ServerCredentials &credential
return ErrorCode::NoError;
};
ErrorCode e =
runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
if (errorCode)
*errorCode = e;
errorCode = runScript(credentials, amnezia::scriptData(SharedScriptType::check_connection), cbReadStdOut, cbReadStdErr);
return stdOut;
}
@@ -839,147 +833,6 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
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,
const std::function<QString()> &callback)
{
+2 -5
View File
@@ -30,9 +30,6 @@ public:
ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, QJsonObject &newConfig);
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials,
QMap<DockerContainer, QJsonObject> &installedContainers);
ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &config = QJsonObject());
@@ -40,7 +37,7 @@ public:
DockerContainer container, const ServerCredentials &credentials, const QString &file, const QString &path,
libssh::ScpOverwriteMode overwriteMode = libssh::ScpOverwriteMode::ScpOverwriteExisting);
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);
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 &)> &cbReadStdErr = nullptr);
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr);
QString checkSshConnection(const ServerCredentials &credentials, ErrorCode errorCode);
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 {
// General error codes
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 <WinSock2.h>
#include <winsock.h>
#include <QNetworkInterface>
#include "qendian.h"
#endif
#ifdef Q_OS_LINUX
#include <arpa/inet.h>
@@ -159,6 +161,27 @@ bool NetworkUtilities::checkIpSubnetFormat(const QString &ip)
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
DWORD GetAdaptersAddressesWrapper(const ULONG Family,
const ULONG Flags,
+4
View File
@@ -4,6 +4,8 @@
#include <QRegularExpression>
#include <QRegExp>
#include <QString>
#include <QHostAddress>
class NetworkUtilities : public QObject
{
@@ -14,6 +16,8 @@ public:
static bool checkIPv4Format(const QString &ip);
static bool checkIpSubnetFormat(const QString &ip);
static QString getGatewayAndIface();
// Returns the Interface Index that could Route to dst
static int AdapterIndexTo(const QHostAddress& dst);
static QRegularExpression ipAddressRegExp();
static QRegularExpression ipAddressPortRegExp();
+4 -2
View File
@@ -35,8 +35,10 @@ class Daemon : public QObject {
virtual QJsonObject getStatus();
// Callback before any Activating measure is done
virtual void prepareActivation(const InterfaceConfig& config){
Q_UNUSED(config)};
virtual void prepareActivation(const InterfaceConfig& config, int inetAdapterIndex = 0) {
Q_UNUSED(config) };
virtual void activateSplitTunnel(const InterfaceConfig& config, int vpnAdapterIndex = 0) {
Q_UNUSED(config) };
QString logs();
void cleanLogs();
+4 -6
View File
@@ -117,6 +117,9 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
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 json;
@@ -217,12 +220,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
json.insert("excludedAddresses", jsExcludedAddresses);
// QJsonArray splitTunnelApps;
// for (const auto& uri : hop.m_vpnDisabledApps) {
// splitTunnelApps.append(QJsonValue(uri));
// }
// json.insert("vpnDisabledApps", splitTunnelApps);
json.insert("vpnDisabledApps", splitTunnelApps);
if (protocolName == amnezia::config_key::awg) {
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
@@ -2,6 +2,9 @@
#include <QJsonDocument>
#include <QQmlFile>
#include <QEventLoop>
#include <QImage>
#include <android/bitmap.h>
#include "android_controller.h"
#include "android_utils.h"
@@ -209,6 +212,51 @@ void AndroidController::setScreenshotsEnabled(bool 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
jclass AndroidController::log;
jmethodID AndroidController::logDebug;
@@ -2,6 +2,7 @@
#define ANDROID_CONTROLLER_H
#include <QJniObject>
#include <QPixmap>
#include "protocols/vpnprotocol.h"
@@ -40,6 +41,9 @@ public:
void exportLogsFile(const QString &fileName);
void clearLogs();
void setScreenshotsEnabled(bool enabled);
void minimizeApp();
QJsonArray getAppList();
QPixmap getAppIcon(const QString &package, QSize *size, const QSize &requestedSize);
static bool initLogging();
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
@@ -18,6 +18,7 @@
#include "dnsutilswindows.h"
#include "leakdetector.h"
#include "logger.h"
#include "core/networkUtilities.h"
#include "platforms/windows/windowscommons.h"
#include "platforms/windows/windowsservicemanager.h"
#include "windowsfirewall.h"
@@ -43,11 +44,24 @@ WindowsDaemon::~WindowsDaemon() {
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
// routes to the server endpoint
auto serveraddr = QHostAddress(config.m_serverIpv4AddrIn);
m_inetAdapterIndex = WindowsCommons::AdapterIndexTo(serveraddr);
if (inetAdapterIndex == 0) {
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) {
@@ -64,12 +78,8 @@ bool WindowsDaemon::run(Op op, const InterfaceConfig& config) {
}
}
if (config.m_vpnDisabledApps.length() > 0) {
m_splitTunnelManager.start(m_inetAdapterIndex);
m_splitTunnelManager.setRules(config.m_vpnDisabledApps);
} else {
m_splitTunnelManager.stop();
}
activateSplitTunnel(config);
return true;
}
@@ -20,7 +20,8 @@ class WindowsDaemon final : public Daemon {
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:
bool run(Op op, const InterfaceConfig& config) override;
@@ -134,7 +134,7 @@ void WindowsSplitTunnel::setRules(const QStringList& appPaths) {
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:
// Network info (what is vpn what is network)
logger.debug() << "Starting SplitTunnel";
@@ -171,7 +171,7 @@ void WindowsSplitTunnel::start(int inetAdapterIndex) {
}
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],
(DWORD)config.size(), nullptr, 0, &bytesReturned,
nullptr);
@@ -270,14 +270,19 @@ std::vector<uint8_t> WindowsSplitTunnel::generateAppConfiguration(
}
std::vector<uint8_t> WindowsSplitTunnel::generateIPConfiguration(
int inetAdapterIndex) {
int inetAdapterIndex, int vpnAdapterIndex) {
std::vector<uint8_t> out(sizeof(IP_ADDRESSES_CONFIG));
auto config = reinterpret_cast<IP_ADDRESSES_CONFIG*>(&out[0]);
auto ifaces = QNetworkInterface::allInterfaces();
if (vpnAdapterIndex == 0) {
vpnAdapterIndex = WindowsCommons::VPNAdapterIndex();
}
// Always the VPN
getAddress(WindowsCommons::VPNAdapterIndex(), &config->TunnelIpv4,
getAddress(vpnAdapterIndex, &config->TunnelIpv4,
&config->TunnelIpv6);
// 2nd best route
getAddress(inetAdapterIndex, &config->InternetIpv4, &config->InternetIpv6);
@@ -132,7 +132,7 @@ class WindowsSplitTunnel final : public QObject {
void setRules(const QStringList& appPaths);
// 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
void stop();
// Resets the Whole Driver
@@ -164,7 +164,7 @@ class WindowsSplitTunnel final : public QObject {
// Generates a Configuration for Each APP
std::vector<uint8_t> generateAppConfiguration(const QStringList& appPaths);
// 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();
void getAddress(int adapterIndex, IN_ADDR* out_ipv4, IN6_ADDR* out_ipv6);
@@ -88,24 +88,6 @@ QString WindowsCommons::tunnelLogFile() {
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
int WindowsCommons::VPNAdapterIndex() {
// 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
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
static QString getCurrentPath();
};
+3
View File
@@ -331,13 +331,16 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
m_vpnLocalAddress = l.split(" ").at(1);
m_vpnGateway = l.split(" ").at(2);
#ifdef Q_OS_WIN
QThread::msleep(300);
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
for (int i = 0; i < netInterfaces.size(); i++) {
for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++)
{
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
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("vpnServer", m_configData.value(amnezia::config_key::hostName).toString());
IpcClient::Interface()->enablePeerTraffic(m_configData);
}
}
+5
View File
@@ -89,8 +89,13 @@ namespace amnezia
constexpr char splitTunnelSites[] = "splitTunnelSites";
constexpr char splitTunnelType[] = "splitTunnelType";
constexpr char splitTunnelApps[] = "splitTunnelApps";
constexpr char appSplitTunnelType[] = "appSplitTunnelType";
constexpr char crc[] = "crc";
constexpr char clientId[] = "clientId";
}
namespace protocols
+3
View File
@@ -112,6 +112,7 @@ ErrorCode XrayProtocol::startTun2Sock()
m_t2sProcess->setProgram(PermittedProcess::Tun2Socks);
#ifdef Q_OS_WIN
m_configData.insert("inetAdapterIndex", NetworkUtilities::AdapterIndexTo(QHostAddress(m_remoteAddress)));
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)});
#endif
@@ -166,7 +167,9 @@ ErrorCode XrayProtocol::startTun2Sock()
{
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
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("vpnServer", m_remoteAddress);
IpcClient::Interface()->enablePeerTraffic(m_configData);
}
}
+2
View File
@@ -234,6 +234,8 @@
<file>ui/qml/Components/HomeSplitTunnelingDrawer.qml</file>
<file>images/controls/split-tunneling.svg</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/file-check-2.svg</file>
<file>ui/qml/Controls2/WarningType.qml</file>
+7 -1
View File
@@ -16,6 +16,12 @@
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)
: 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
retVal = m_settings.value(key);
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()) {
qCritical() << "SecureQSettings::setValue Decryption requested, but key is empty";
+1 -5
View File
@@ -8,10 +8,6 @@
#include "keychain.h"
constexpr const char *settingsKeyTag = "settingsKeyTag";
constexpr const char *settingsIvTag = "settingsIvTag";
constexpr const char *keyChainName = "AmneziaVPN-Keychain";
class SecureQSettings : public QObject
{
Q_OBJECT
@@ -44,7 +40,7 @@ public:
private:
QSettings m_settings;
mutable QMap<QString, QVariant> m_cache;
mutable QHash<QString, QVariant> m_cache;
QStringList encryptedKeys; // encode only key listed here
+48
View File
@@ -355,6 +355,54 @@ void Settings::clearSettings()
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
{
return serverCredentials(defaultServerIndex());
+15
View File
@@ -193,6 +193,21 @@ public:
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:
void saveLogsChanged(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
#include <QApplication>
#endif
#include <QtConcurrent>
#include "core/controllers/apiController.h"
#include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<VpnConnection> &vpnConnection, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_vpnConnection(vpnConnection)
const QSharedPointer<ClientManagementModel> &clientManagementModel,
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,
&ConnectionController::onConnectionStateChanged);
@@ -26,16 +36,31 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
void ConnectionController::openConnection()
{
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()) {
emit noInstalledContainers();
emit m_vpnConnection->connectionStateChanged(Vpn::ConnectionState::Disconnected);
return;
}
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container);
DockerContainer container =
qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
if (container == DockerContainer::None) {
emit connectionErrorOccurred(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
@@ -44,7 +69,27 @@ void ConnectionController::openConnection()
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()
@@ -91,6 +136,7 @@ void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
}
case Vpn::ConnectionState::Preparing: {
m_isConnectionInProgress = true;
m_connectionStateText = tr("Preparing...");
break;
}
case Vpn::ConnectionState::Error: {
@@ -135,9 +181,14 @@ QString ConnectionController::connectionStateText() const
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();
} else if (isConnected()) {
closeConnection();
@@ -155,3 +206,51 @@ bool ConnectionController::isConnected() const
{
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
#include "protocols/vpnprotocol.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "vpnconnection.h"
@@ -17,7 +18,9 @@ public:
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel,
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;
@@ -26,7 +29,7 @@ public:
QString connectionStateText() const;
public slots:
void toggleConnection(bool skipConnectionInProgressCheck);
void toggleConnection();
void openConnection();
void closeConnection();
@@ -38,9 +41,12 @@ public slots:
void onTranslationsUpdated();
ErrorCode updateProtocolConfig(const DockerContainer container, const ServerCredentials &credentials,
QJsonObject &containerConfig);
signals:
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig);
const QJsonObject &vpnConfiguration);
void disconnectFromVpn();
void connectionStateChanged();
@@ -49,14 +55,21 @@ signals:
void noInstalledContainers();
void connectButtonClicked();
void preparingConfig();
private:
Vpn::ConnectionState getCurrentConnectionState();
bool isProtocolConfigExists(const QJsonObject &containerConfig, const DockerContainer container);
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
QSharedPointer<VpnConnection> m_vpnConnection;
std::shared_ptr<Settings> m_settings;
bool m_isConnected = false;
bool m_isConnectionInProgress = false;
QString m_connectionStateText = tr("Connect");
+96 -172
View File
@@ -8,11 +8,7 @@
#include <QImage>
#include <QStandardPaths>
#include "configurators/awg_configurator.h"
#include "configurators/cloak_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
#include "systemController.h"
#ifdef Q_OS_ANDROID
@@ -20,25 +16,20 @@
#endif
#include "qrcodegen.hpp"
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent)
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent),
m_serversModel(serversModel),
m_containersModel(containersModel),
m_clientManagementModel(clientManagementModel),
m_settings(settings),
m_configurator(configurator)
m_settings(settings)
{
#ifdef Q_OS_ANDROID
m_authResultNotifier.reset(new AuthResultNotifier);
m_authResultReceiver.reset(new AuthResultReceiver(m_authResultNotifier));
connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this,
[this]() { emit exportErrorOccurred(tr("Access error!")); });
connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this,
&ExportController::generateFullAccessConfig);
connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this, [this]() { emit exportErrorOccurred(tr("Access error!")); });
connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this, &ExportController::generateFullAccessConfig);
#endif
}
@@ -47,9 +38,9 @@ void ExportController::generateFullAccessConfig()
clearPreviousConfig();
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++) {
auto containerConfig = containers.at(i).toObject();
auto containerType = ContainerProps::containerFromString(containerConfig.value(config_key::container).toString());
@@ -63,13 +54,11 @@ void ExportController::generateFullAccessConfig()
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);
m_config = QString("vpn://%1")
.arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding
| QByteArray::OmitTrailingEquals)));
m_config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
m_qrCodes = generateQrCodeImageSeries(compressedConfig);
emit exportConfigChanged();
@@ -83,8 +72,7 @@ void ExportController::generateFullAccessConfigAndroid()
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
if (appContext.isValid()) {
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
"(Landroid/content/Context;)Landroid/content/Intent;",
appContext.object());
"(Landroid/content/Context;)Landroid/content/Intent;", appContext.object());
if (intent.isValid()) {
if (intent.object<jobject>() != nullptr) {
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, m_authResultReceiver.get());
@@ -103,116 +91,108 @@ void ExportController::generateConnectionConfig(const QString &clientName)
int serverIndex = m_serversModel->getProcessedServerIndex();
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);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol);
VpnConfigurationsController vpnConfigurationController(m_settings);
ErrorCode errorCode = vpnConfigurationController.createProtocolConfigForContainer(credentials, container, containerConfig);
QString clientId;
QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol,
clientId, &errorCode);
if (errorCode) {
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;
}
}
errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig, clientName);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
QJsonObject config = m_settings->server(serverIndex); // todo change to servers_model
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
if (!errorCode) {
config.remove(config_key::userName);
config.remove(config_key::password);
config.remove(config_key::port);
config.insert(config_key::containers, QJsonArray { containerConfig });
config.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
serverConfig.remove(config_key::userName);
serverConfig.remove(config_key::password);
serverConfig.remove(config_key::port);
serverConfig.insert(config_key::containers, QJsonArray { containerConfig });
serverConfig.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
auto dns = m_configurator->getDnsForConfig(serverIndex);
config.insert(config_key::dns1, dns.first);
config.insert(config_key::dns2, dns.second);
auto dns = m_serversModel->getDnsPair(serverIndex);
serverConfig.insert(config_key::dns1, dns.first);
serverConfig.insert(config_key::dns2, dns.second);
}
QByteArray compressedConfig = QJsonDocument(config).toJson();
QByteArray compressedConfig = QJsonDocument(serverConfig).toJson();
compressedConfig = qCompress(compressedConfig, 8);
m_config = QString("vpn://%1")
.arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding
| QByteArray::OmitTrailingEquals)));
m_config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
m_qrCodes = generateQrCodeImageSeries(compressedConfig);
emit exportConfigChanged();
}
void ExportController::generateOpenVpnConfig(const QString &clientName)
ErrorCode ExportController::generateNativeConfig(const DockerContainer container, const QString &clientName, const Proto &protocol,
QJsonObject &jsonNativeConfig)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getProcessedServerIndex();
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);
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;
QString clientId;
QString config = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (container == DockerContainer::Cloak || container == DockerContainer::ShadowSocks) {
errorCode = generateNativeConfig(container, clientName, Proto::OpenVpn, nativeConfig);
} else {
errorCode = generateNativeConfig(container, clientName, ContainerProps::defaultProtocol(container), nativeConfig);
}
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8());
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged();
}
void ExportController::generateWireGuardConfig(const QString &clientName)
{
clearPreviousConfig();
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);
QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::WireGuard, clientName, Proto::WireGuard, nativeConfig);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
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);
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();
}
void ExportController::generateAwgConfig(const QString &clientName)
{
clearPreviousConfig();
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);
QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Awg, clientName, Proto::Awg, nativeConfig);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Awg, config);
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
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);
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();
}
void ExportController::generateShadowSocksConfig()
{
clearPreviousConfig();
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));
QJsonObject nativeConfig;
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container,
containerConfig, &errorCode);
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::ShadowSocks, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
if (container == DockerContainer::Cloak) {
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) {
m_config.append(line + "\n");
}
m_nativeConfigString =
QString("%1:%2@%3:%4")
.arg(configJson.value("method").toString(), configJson.value("password").toString(),
configJson.value("server").toString(), configJson.value("server_port").toString());
m_nativeConfigString = QString("%1:%2@%3:%4")
.arg(nativeConfig.value("method").toString(), nativeConfig.value("password").toString(),
nativeConfig.value("server").toString(), nativeConfig.value("server_port").toString());
m_nativeConfigString = "ss://" + m_nativeConfigString.toUtf8().toBase64();
@@ -306,30 +259,17 @@ void ExportController::generateShadowSocksConfig()
void ExportController::generateCloakConfig()
{
clearPreviousConfig();
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);
QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Cloak, "", Proto::Cloak, nativeConfig);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Cloak, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
configJson.remove(config_key::transport_proto);
configJson.insert("ProxyMethod", "shadowsocks");
nativeConfig.remove(config_key::transport_proto);
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) {
m_config.append(line + "\n");
}
@@ -339,29 +279,14 @@ void ExportController::generateCloakConfig()
void ExportController::generateXrayConfig()
{
clearPreviousConfig();
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);
QJsonObject nativeConfig;
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, "", Proto::Xray, nativeConfig);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
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) {
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)
{
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials,
m_serversModel->getProcessedServerIndex());
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex());
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
+7 -8
View File
@@ -3,10 +3,9 @@
#include <QObject>
#include "configurators/vpn_configurator.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/clientManagementModel.h"
#ifdef Q_OS_ANDROID
#include "platforms/android/authResultReceiver.h"
#endif
@@ -15,11 +14,9 @@ class ExportController : public QObject
{
Q_OBJECT
public:
explicit ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent = nullptr);
explicit ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged)
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged)
@@ -65,11 +62,13 @@ private:
void clearPreviousConfig();
ErrorCode generateNativeConfig(const DockerContainer container, const QString &clientName, const Proto &protocol,
QJsonObject &jsonNativeConfig);
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
QString m_config;
QString m_nativeConfigString;
+327 -118
View File
@@ -4,11 +4,13 @@
#include <QDir>
#include <QEventLoop>
#include <QJsonObject>
#include <QStandardPaths>
#include <QRandomGenerator>
#include <QStandardPaths>
#include "core/errorstrings.h"
#include "core/controllers/serverController.h"
#include "core/controllers/vpnConfigurationController.h"
#include "core/errorstrings.h"
#include "logger.h"
#include "core/networkUtilities.h"
#include "utilities.h"
#include "ui/models/protocols/awgConfigModel.h"
@@ -16,6 +18,8 @@
namespace
{
Logger logger("ServerController");
#ifdef Q_OS_WINDOWS
QString getNextDriverLetter()
{
@@ -42,14 +46,15 @@ namespace
#endif
}
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
InstallController::InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ProtocolsModel> &protocolsModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent),
m_serversModel(serversModel),
m_containersModel(containersModel),
m_protocolModel(protocolsModel),
m_clientManagementModel(clientManagementModel),
m_settings(settings)
{
}
@@ -74,8 +79,7 @@ void InstallController::install(DockerContainer container, int port, TransportPr
if (protocol == mainProto) {
containerConfig.insert(config_key::port, QString::number(port));
containerConfig.insert(config_key::transport_proto,
ProtocolProps::transportProtoToString(transportProto, protocol));
containerConfig.insert(config_key::transport_proto, ProtocolProps::transportProtoToString(transportProto, protocol));
if (container == DockerContainer::Awg) {
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::underloadPacketMagicHeader] = underloadPacketMagicHeader;
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
}
if (container == DockerContainer::Sftp) {
} else if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
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);
}
ServerCredentials serverCredentials;
if (m_shouldCreateServer) {
if (isServerAlreadyExists()) {
return;
}
installServer(container, config);
serverCredentials = m_processedServerCredentials;
} 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);
connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy);
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode =
serverController.getAlreadyInstalledContainers(m_currentlyInstalledServerCredentials, installedContainers);
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);
ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, installedContainers);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
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 = "";
if (!installedContainers.contains(container)) {
errorCode = serverController.setupContainer(serverCredentials, container, config);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
return;
}
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));
}
bool isInstalledContainerAddedToGui = false;
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);
if (errorCode) {
emit installationErrorOccurred(errorString(errorCode));
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()
@@ -230,8 +255,7 @@ bool InstallController::isServerAlreadyExists()
auto modelIndex = m_serversModel->index(i);
const ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(modelIndex, ServersModel::Roles::CredentialsRole));
if (m_currentlyInstalledServerCredentials.hostName == credentials.hostName
&& m_currentlyInstalledServerCredentials.port == credentials.port) {
if (m_processedServerCredentials.hostName == credentials.hostName && m_processedServerCredentials.port == credentials.port) {
emit serverAlreadyExists(i);
return true;
}
@@ -248,15 +272,31 @@ void InstallController::scanServerForInstalledContainers()
ServerController serverController(m_settings);
QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode = serverController.getAlreadyInstalledContainers(serverCredentials, installedContainers);
ErrorCode errorCode = getAlreadyInstalledContainers(serverCredentials, installedContainers);
if (errorCode == ErrorCode::NoError) {
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()) {
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;
}
}
@@ -268,6 +308,151 @@ void InstallController::scanServerForInstalledContainers()
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)
{
int serverIndex = m_serversModel->getProcessedServerIndex();
@@ -284,6 +469,7 @@ void InstallController::updateContainer(QJsonObject config)
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
errorCode = serverController.updateContainer(serverCredentials, container, oldContainerConfig, config);
clearCachedProfile();
}
if (errorCode == ErrorCode::NoError) {
@@ -334,23 +520,51 @@ void InstallController::removeAllContainers()
emit installationErrorOccurred(errorString(errorCode));
}
void InstallController::removeCurrentlyProcessedContainer()
void InstallController::removeProcessedContainer()
{
int serverIndex = m_serversModel->getProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
int container = m_containersModel->getCurrentlyProcessedContainerIndex();
QString containerName = m_containersModel->getCurrentlyProcessedContainerName();
int container = m_containersModel->getProcessedContainerIndex();
QString containerName = m_containersModel->getProcessedContainerName();
ErrorCode errorCode = m_serversModel->removeContainer(container);
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;
}
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()
{
return NetworkUtilities::ipAddressPortRegExp();
@@ -361,17 +575,15 @@ QRegularExpression InstallController::ipAddressRegExp()
return NetworkUtilities::ipAddressRegExp();
}
void InstallController::setCurrentlyInstalledServerCredentials(const QString &hostName, const QString &userName,
const QString &secretData)
void InstallController::setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData)
{
m_currentlyInstalledServerCredentials.hostName = hostName;
if (m_currentlyInstalledServerCredentials.hostName.contains(":")) {
m_currentlyInstalledServerCredentials.port =
m_currentlyInstalledServerCredentials.hostName.split(":").at(1).toInt();
m_currentlyInstalledServerCredentials.hostName = m_currentlyInstalledServerCredentials.hostName.split(":").at(0);
m_processedServerCredentials.hostName = hostName;
if (m_processedServerCredentials.hostName.contains(":")) {
m_processedServerCredentials.port = m_processedServerCredentials.hostName.split(":").at(1).toInt();
m_processedServerCredentials.hostName = m_processedServerCredentials.hostName.split(":").at(0);
}
m_currentlyInstalledServerCredentials.userName = userName;
m_currentlyInstalledServerCredentials.secretData = secretData;
m_processedServerCredentials.userName = userName;
m_processedServerCredentials.secretData = secretData;
}
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";
#elif defined AMNEZIA_DESKTOP
mountPath =
QString("%1/sftp:%2:%3").arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation), hostname, port);
mountPath = QString("%1/sftp:%2:%3").arg(QStandardPaths::writableLocation(QStandardPaths::HomeLocation), hostname, port);
QDir dir(mountPath);
if (!dir.exists()) {
dir.mkpath(mountPath);
@@ -461,8 +672,7 @@ bool InstallController::checkSshConnection()
ErrorCode errorCode = ErrorCode::NoError;
m_privateKeyPassphrase = "";
if (m_currentlyInstalledServerCredentials.secretData.contains("BEGIN")
&& m_currentlyInstalledServerCredentials.secretData.contains("PRIVATE KEY")) {
if (m_processedServerCredentials.secretData.contains("BEGIN") && m_processedServerCredentials.secretData.contains("PRIVATE KEY")) {
auto passphraseCallback = [this]() {
emit passphraseRequestStarted();
QEventLoop loop;
@@ -473,10 +683,9 @@ bool InstallController::checkSshConnection()
};
QString decryptedPrivateKey;
errorCode = serverController.getDecryptedPrivateKey(m_currentlyInstalledServerCredentials, decryptedPrivateKey,
passphraseCallback);
errorCode = serverController.getDecryptedPrivateKey(m_processedServerCredentials, decryptedPrivateKey, passphraseCallback);
if (errorCode == ErrorCode::NoError) {
m_currentlyInstalledServerCredentials.secretData = decryptedPrivateKey;
m_processedServerCredentials.secretData = decryptedPrivateKey;
} else {
emit installationErrorOccurred(errorString(errorCode));
return false;
@@ -484,7 +693,7 @@ bool InstallController::checkSshConnection()
}
QString output;
output = serverController.checkSshConnection(m_currentlyInstalledServerCredentials, &errorCode);
output = serverController.checkSshConnection(m_processedServerCredentials, errorCode);
if (errorCode != ErrorCode::NoError) {
emit installationErrorOccurred(errorString(errorCode));
@@ -508,10 +717,10 @@ void InstallController::setEncryptedPassphrase(QString passphrase)
void InstallController::addEmptyServer()
{
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::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());
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 newConfig(newProtoConfig);
if (!oldConfig.hasEqualServerSettings(newConfig)) {
return true;
if (oldConfig.hasEqualServerSettings(newConfig)) {
return false;
}
} else if (container == DockerContainer::WireGuard) {
const WgConfig oldConfig(oldProtoConfig);
const WgConfig newConfig(newProtoConfig);
if (!oldConfig.hasEqualServerSettings(newConfig)) {
return true;
if (oldConfig.hasEqualServerSettings(newConfig)) {
return false;
}
}
return false;
return true;
}
+21 -11
View File
@@ -6,24 +6,24 @@
#include "containers/containers_defs.h"
#include "core/defs.h"
#include "ui/models/clientManagementModel.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/protocols_model.h"
#include "ui/models/servers_model.h"
class InstallController : public QObject
{
Q_OBJECT
public:
explicit InstallController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
explicit InstallController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ProtocolsModel> &protocolsModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
~InstallController();
public slots:
void install(DockerContainer container, int port, TransportProto transportProto);
void setCurrentlyInstalledServerCredentials(const QString &hostName, const QString &userName,
const QString &secretData);
void setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData);
void setShouldCreateServer(bool shouldCreateServer);
void scanServerForInstalledContainers();
@@ -33,7 +33,11 @@ public slots:
void removeProcessedServer();
void rebootProcessedServer();
void removeAllContainers();
void removeCurrentlyProcessedContainer();
void removeProcessedContainer();
void removeApiConfig();
void clearCachedProfile();
QRegularExpression ipAddressPortRegExp();
QRegularExpression ipAddressRegExp();
@@ -50,14 +54,14 @@ signals:
void installContainerFinished(const QString &finishMessage, bool isServiceInstall);
void installServerFinished(const QString &finishMessage);
void updateContainerFinished(const QString& message);
void updateContainerFinished(const QString &message);
void scanServerFinished(bool isInstalledContainerFound);
void rebootProcessedServerFinished(const QString &finishedMessage);
void removeProcessedServerFinished(const QString &finishedMessage);
void removeAllContainersFinished(const QString &finishedMessage);
void removeCurrentlyProcessedContainerFinished(const QString &finishedMessage);
void removeProcessedContainerFinished(const QString &finishedMessage);
void installationErrorOccurred(const QString &errorMessage);
@@ -71,19 +75,25 @@ signals:
void currentContainerUpdated();
void cachedProfileCleared(const QString &message);
private:
void installServer(DockerContainer container, QJsonObject &config);
void installContainer(DockerContainer container, QJsonObject &config);
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials, QString &finishMessage);
void installContainer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
const ServerCredentials &serverCredentials, QString &finishMessage);
bool isServerAlreadyExists();
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, QMap<DockerContainer, QJsonObject> &installedContainers);
bool isUpdateDockerContainerRequired(const DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ProtocolsModel> m_protocolModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
std::shared_ptr<Settings> m_settings;
ServerCredentials m_currentlyInstalledServerCredentials;
ServerCredentials m_processedServerCredentials;
bool m_shouldCreateServer;
+8
View File
@@ -7,6 +7,7 @@
#endif
#ifdef Q_OS_ANDROID
#include "platforms/android/android_controller.h"
#include "platforms/android/android_utils.h"
#include <QJniObject>
#endif
@@ -74,6 +75,13 @@ void PageController::closeWindow()
#endif
}
void PageController::hideWindow()
{
#ifdef Q_OS_ANDROID
AndroidController::instance()->minimizeApp();
#endif
}
void PageController::keyPressEvent(Qt::Key key)
{
switch (key) {
+2
View File
@@ -29,6 +29,7 @@ namespace PageLoader
PageSettingsAbout,
PageSettingsLogging,
PageSettingsSplitTunneling,
PageSettingsAppSplitTunneling,
PageServiceSftpSettings,
PageServiceTorWebsiteSettings,
@@ -76,6 +77,7 @@ public slots:
QString getPagePath(PageLoader::PageEnum page);
void closeWindow();
void hideWindow();
void keyPressEvent(Qt::Key key);
unsigned int getInitialPageNavigationBarColor();
@@ -153,12 +153,6 @@ void SettingsController::clearSettings()
#endif
}
void SettingsController::clearCachedProfiles()
{
m_serversModel->clearCachedProfiles();
emit changeSettingsFinished(tr("Cached profiles cleared"));
}
bool SettingsController::isAutoConnectEnabled()
{
return m_settings->isAutoConnect();
@@ -46,7 +46,6 @@ public slots:
QString getAppVersion();
void clearSettings();
void clearCachedProfiles();
bool isAutoConnectEnabled();
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");
namespace configKey {
namespace configKey
{
constexpr char clientId[] = "clientId";
constexpr char clientName[] = "clientName";
constexpr char container[] = "container";
@@ -61,7 +62,6 @@ void ClientManagementModel::migration(const QByteArray &clientsTableString)
m_clientsTable.push_back(client);
}
}
ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials)
@@ -74,15 +74,13 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
ErrorCode error = ErrorCode::NoError;
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
}
const QByteArray clientsTableString =
serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error);
const QByteArray clientsTableString = serverController.getTextFileFromContainer(container, credentials, clientsTableFile, error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the clientsTable file from the server";
endResetModel();
@@ -96,8 +94,7 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
int count = 0;
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
error = getOpenVpnClients(serverController, container, credentials, count);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
error = getWireGuardClients(serverController, container, credentials, count);
@@ -109,8 +106,7 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson();
if (clientsTableString != newClientsTableString) {
error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString,
clientsTableFile);
error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
@@ -121,7 +117,8 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr
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;
QString stdOut;
@@ -130,10 +127,8 @@ ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverContr
return ErrorCode::NoError;
};
const QString getOpenVpnClientsList =
"sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'";
QString script = serverController.replaceVars(getOpenVpnClientsList,
serverController.genVarsForScript(credentials, container));
const QString getOpenVpnClientsList = "sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'";
QString script = serverController.replaceVars(getOpenVpnClientsList, serverController.genVarsForScript(credentials, container));
error = serverController.runScript(credentials, script, cbReadStdOut);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to retrieve the list of issued certificates on the server";
@@ -163,14 +158,13 @@ ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverContr
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;
const QString wireGuardConfigFile =
QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString =
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
const QString wireGuardConfigFile = QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString = serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server";
return error;
@@ -215,10 +209,27 @@ bool ClientManagementModel::isClientExists(const QString &clientId)
return false;
}
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName,
const DockerContainer container, ServerCredentials credentials)
ErrorCode ClientManagementModel::appendClient(const DockerContainer container, const 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);
if (error != ErrorCode::NoError) {
@@ -246,8 +257,7 @@ ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QSt
ServerController serverController(m_settings);
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
@@ -279,15 +289,13 @@ ErrorCode ClientManagementModel::renameClient(const int row, const QString &clie
ServerController serverController(m_settings);
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container));
}
ErrorCode error =
serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
ErrorCode error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
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;
}
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container,
ServerCredentials credentials, const int serverIndex)
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container, ServerCredentials credentials,
const int serverIndex)
{
ErrorCode errorCode = ErrorCode::NoError;
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
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);
@@ -333,8 +340,50 @@ ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContain
return errorCode;
}
ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container,
ServerCredentials credentials, const int serverIndex)
ErrorCode ClientManagementModel::revokeClient(const QJsonObject &containerConfig, const DockerContainer container, ServerCredentials credentials,
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();
QString clientId = client.value(configKey::clientId).toString();
@@ -348,8 +397,7 @@ ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContai
.arg(clientId);
ServerController serverController(m_settings);
const QString script =
serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
const QString script = serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
ErrorCode error = serverController.runScript(credentials, script);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to revoke the certificate";
@@ -373,16 +421,14 @@ ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContai
return ErrorCode::NoError;
}
ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container,
ServerCredentials credentials)
ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials)
{
ErrorCode error;
ErrorCode error = ErrorCode::NoError;
ServerController serverController(m_settings);
const QString wireGuardConfigFile =
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) {
logger.error() << "Failed to get the wg conf file from the server";
return error;
@@ -413,8 +459,7 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable");
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn));
} else {
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)'";
error = serverController.runScript(
credentials,
serverController.replaceVars(script.arg(wireGuardConfigFile),
serverController.genVarsForScript(credentials, container)));
serverController.replaceVars(script.arg(wireGuardConfigFile), serverController.genVarsForScript(credentials, container)));
if (error != ErrorCode::NoError) {
logger.error() << "Failed to execute the command 'wg syncconf' on the server";
return error;
+5 -2
View File
@@ -24,11 +24,14 @@ public:
public slots:
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,
ServerCredentials credentials);
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container,
ServerCredentials credentials, bool addTimeStamp = false);
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, ServerCredentials credentials,
bool addTimeStamp = false);
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:
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 EasySetupOrderRole: return ContainerProps::easySetupOrder(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 IsShareableRole: return ContainerProps::isShareable(container);
}
@@ -63,19 +63,19 @@ void ContainersModel::updateModel(const QJsonArray &containers)
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)
+4 -4
View File
@@ -42,10 +42,10 @@ public:
public slots:
void updateModel(const QJsonArray &containers);
void setCurrentlyProcessedContainerIndex(int containerIndex);
int getCurrentlyProcessedContainerIndex();
void setProcessedContainerIndex(int containerIndex);
int getProcessedContainerIndex();
QString getCurrentlyProcessedContainerName();
QString getProcessedContainerName();
QJsonObject getContainerConfig(const int containerIndex);
@@ -58,7 +58,7 @@ signals:
private:
QMap<DockerContainer, QJsonObject> m_containers;
int m_currentlyProcessedContainerIndex;
int m_processedContainerIndex;
};
#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::CipherRole:
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();
@@ -71,6 +73,8 @@ QHash<int, QByteArray> ShadowSocksConfigModel::roleNames() const
roles[PortRole] = "port";
roles[CipherRole] = "cipher";
roles[IsPortEditableRole] = "isPortEditable";
roles[IsCipherEditableRole] = "isCipherEditable";
return roles;
}
@@ -13,7 +13,9 @@ class ShadowSocksConfigModel : public QAbstractListModel
public:
enum Roles {
PortRole = Qt::UserRole + 1,
CipherRole
CipherRole,
IsPortEditableRole,
IsCipherEditableRole
};
explicit ShadowSocksConfigModel(QObject *parent = nullptr);
@@ -63,7 +63,7 @@ void WireGuardConfigModel::updateModel(const QJsonObject &config)
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);
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::ShadowSocks: return PageLoader::PageEnum::PageProtocolShadowSocksSettings;
case Proto::WireGuard: return PageLoader::PageEnum::PageProtocolWireGuardSettings;
case Proto::Awg: return PageLoader::PageEnum::PageProtocolAwgSettings;
case Proto::Ikev2: return PageLoader::PageEnum::PageProtocolIKev2Settings;
case Proto::L2tp: return PageLoader::PageEnum::PageProtocolIKev2Settings;
case Proto::Xray: return PageLoader::PageEnum::PageProtocolXraySettings;
+48 -27
View File
@@ -1,14 +1,17 @@
#include "servers_model.h"
#include "core/controllers/serverController.h"
#include "core/networkUtilities.h"
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings), QAbstractListModel(parent)
{
m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged);
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::defaultServerNameChanged();
updateDefaultServerContainersModel();
@@ -336,9 +339,9 @@ void ServersModel::updateDefaultServerContainersModel()
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()
@@ -378,7 +381,8 @@ void ServersModel::updateContainerConfig(const int containerIndex, const QJsonOb
server.insert(config_key::containers, containers);
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));
}
@@ -396,7 +400,8 @@ void ServersModel::addContainerConfig(const int containerIndex, const QJsonObjec
server.insert(config_key::containers, containers);
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));
}
@@ -408,7 +413,7 @@ void ServersModel::setDefaultContainer(const int serverIndex, const int containe
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject s = m_servers.at(serverIndex).toObject();
s.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
editServer(s, serverIndex); //check
editServer(s, serverIndex); // check
}
const QString ServersModel::getDefaultServerDefaultContainerName()
@@ -420,8 +425,7 @@ const QString ServersModel::getDefaultServerDefaultContainerName()
ErrorCode ServersModel::removeAllContainers()
{
ServerController serverController(m_settings);
ErrorCode errorCode =
serverController.removeAllContainers(m_settings->serverCredentials(m_processedServerIndex));
ErrorCode errorCode = serverController.removeAllContainers(m_settings->serverCredentials(m_processedServerIndex));
if (errorCode == ErrorCode::NoError) {
QJsonObject s = m_servers.at(m_processedServerIndex).toObject();
@@ -468,7 +472,8 @@ ErrorCode ServersModel::removeContainer(const int containerIndex)
if (containers.empty()) {
defaultContainer = DockerContainer::None;
} 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));
}
@@ -478,24 +483,9 @@ ErrorCode ServersModel::removeContainer(const int containerIndex)
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)
{
m_settings->clearLastConnectionConfig(m_processedServerIndex, container);
m_servers.replace(m_processedServerIndex, m_settings->server(m_processedServerIndex));
if (m_processedServerIndex == m_defaultServerIndex) {
updateDefaultServerContainersModel();
@@ -515,6 +505,36 @@ bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex) const
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 servicesName;
@@ -598,7 +618,8 @@ bool ServersModel::isDefaultServerDefaultContainerHasSplitTunneling()
if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
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"));
}
+2 -2
View File
@@ -80,13 +80,12 @@ public slots:
void editServer(const QJsonObject &server, const int serverIndex);
void removeServer();
QJsonObject getDefaultServerConfig();
QJsonObject getServerConfig(const int serverIndex);
void reloadDefaultServerContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config);
void addContainerConfig(const int containerIndex, const QJsonObject config);
void clearCachedProfiles();
void clearCachedProfile(const DockerContainer container);
ErrorCode removeContainer(const int containerIndex);
@@ -98,6 +97,7 @@ public slots:
QStringList getAllInstalledServicesName(const int serverIndex);
void toggleAmneziaDns(bool enabled);
QPair<QString, QString> getDnsPair(const int serverIndex);
bool isServerFromApiAlreadyExists(const quint16 crc);
+5 -5
View File
@@ -17,16 +17,16 @@ Button {
implicitWidth: 190
implicitHeight: 190
text: ConnectionController.connectionStateText
Connections {
target: ConnectionController
function onConnectionErrorOccurred(errorMessage) {
PageController.showErrorMessage(errorMessage)
function onPreparingConfig() {
PageController.showNotificationMessage(qsTr("Unable to disconnect during configuration preparation"))
}
}
text: ConnectionController.connectionStateText
// enabled: !ConnectionController.isConnectionInProgress
background: Item {
@@ -139,6 +139,6 @@ Button {
onClicked: {
ServersModel.setProcessedServerIndex(ServersModel.defaultIndex)
ApiController.updateServerConfigFromApi()
ConnectionController.connectButtonClicked()
}
}
@@ -69,7 +69,7 @@ ListView {
return
}
ContainersModel.setCurrentlyProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
ContainersModel.setProcessedContainerIndex(proxyDefaultServerContainersModel.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
containersDropDown.close()
@@ -11,6 +11,8 @@ import "../Config"
DrawerType2 {
id: root
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
anchors.fill: parent
expandedHeight: parent.height * 0.7
@@ -57,7 +59,7 @@ DrawerType2 {
Layout.fillWidth: true
Layout.topMargin: 16
enabled: ! ServersModel.isDefaultServerDefaultContainerHasSplitTunneling || !ServersModel.getDefaultServerData("isServerFromApi")
enabled: !ServersModel.isDefaultServerDefaultContainerHasSplitTunneling || !ServersModel.getDefaultServerData("isServerFromApi")
text: qsTr("Site-based split tunneling")
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
@@ -73,20 +75,22 @@ DrawerType2 {
}
LabelWithButtonType {
visible: isAppSplitTinnelingEnabled
Layout.fillWidth: true
visible: false
text: qsTr("App-based split tunneling")
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
// PageController.goToPage(PageEnum.PageSetupWizardConfigSource)
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
root.close()
}
}
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() {
if (isInstalled) {
var containerIndex = root.model.mapToSource(index)
ContainersModel.setCurrentlyProcessedContainerIndex(containerIndex)
ContainersModel.setProcessedContainerIndex(containerIndex)
if (serviceType !== ProtocolEnum.Other) {
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
@@ -52,27 +52,6 @@ ListView {
}
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: {
ProtocolsModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolRaw)
@@ -98,7 +77,7 @@ ListView {
}
} else {
ContainersModel.setCurrentlyProcessedContainerIndex(root.model.mapToSource(index))
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
}
+4 -4
View File
@@ -90,12 +90,12 @@ CheckBox {
}
contentItem: Item {
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
anchors.fill: parent
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 8 + background.width
implicitHeight: content.implicitHeight
ColumnLayout {
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 {
id: background
@@ -186,7 +179,7 @@ Item {
y: root.height - drawerContent.height
state: root.drawerCollapsed
implicitHeight: root.isCollapsed ? collapsedLoader.implicitHeight : expandedLoader.implicitHeight
implicitHeight: root.isCollapsed ? collapsedHeight : expandedHeight
onStateChanged: {
if (root.isCollapsed) {
@@ -246,7 +239,6 @@ Item {
Loader {
id: collapsedLoader
visible: root.isCollapsed
sourceComponent: root.collapsedContent
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) {
return textField.focus ? root.borderFocusedColor : noneFocusedColor
}
+95 -99
View File
@@ -82,7 +82,7 @@ PageType {
leftImageColor: "transparent"
borderWidth: 0
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled ||
property bool isSplitTunnelingEnabled: SitesModel.isTunnelingEnabled || AppSplitTunnelingModel.isTunnelingEnabled ||
(ServersModel.isDefaultServerDefaultContainerHasSplitTunneling && ServersModel.getDefaultServerData("isServerFromApi"))
text: isSplitTunnelingEnabled ? qsTr("Split tunneling enabled") : qsTr("Split tunneling disabled")
@@ -107,131 +107,128 @@ PageType {
id: drawer
anchors.fill: parent
collapsedContent: ColumnLayout {
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
collapsedContent: Item {
implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
Component.onCompleted: {
drawer.expandedHeight = implicitHeight
}
ColumnLayout {
id: collapsed
RowLayout {
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
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
}
Component.onCompleted: {
drawer.collapsedHeight = collapsed.implicitHeight
}
Header1TextType {
id: collapsedButtonHeader
Layout.maximumWidth: drawer.width - 48 - 18 - 12 // todo
maximumLineCount: 2
elide: Qt.ElideRight
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
PropertyAnimation { duration: 200 }
}
DividerType {
Layout.topMargin: 10
Layout.fillWidth: false
Layout.preferredWidth: 20
Layout.preferredHeight: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
ImageButtonType {
id: collapsedButtonChevron
RowLayout {
Layout.topMargin: 14
Layout.leftMargin: 24
Layout.rightMargin: 24
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: 8
spacing: 0
hoverEnabled: false
image: "qrc:/images/controls/chevron-down.svg"
imageColor: "#d7d8db"
Connections {
target: drawer
function onEntered() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.hoveredColor
collapsedButtonHeader.opacity = 0.8
} else {
collapsedButtonHeader.opacity = 1
}
}
icon.width: 18
icon.height: 18
backgroundRadius: 16
horizontalPadding: 4
topPadding: 4
bottomPadding: 3
function onExited() {
if (drawer.isCollapsed) {
collapsedButtonChevron.backgroundColor = collapsedButtonChevron.defaultColor
collapsedButtonHeader.opacity = 1
} else {
collapsedButtonHeader.opacity = 1
}
}
onClicked: {
if (drawer.isCollapsed) {
drawer.open()
function onPressed(pressed, entered) {
if (drawer.isCollapsed) {
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 {
id: collapsedServerMenuDescription
Layout.bottomMargin: 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionCollapsed
}
}
expandedContent: Item {
id: serverMenuContainer
implicitHeight: Qt.platform.os !== "ios" ? root.height * 0.9 : screen.height * 0.77
Component.onCompleted: {
drawer.expandedHeight = serverMenuContainer.implicitHeight
LabelTextType {
id: collapsedServerMenuDescription
Layout.bottomMargin: drawer.isCollapsed ? 44 : ServersModel.isDefaultServerFromApi ? 89 : 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
text: drawer.isCollapsed ? ServersModel.defaultServerDescriptionCollapsed : ServersModel.defaultServerDescriptionExpanded
}
}
ColumnLayout {
id: serversMenuHeader
anchors.top: parent.top
anchors.top: collapsed.bottom
anchors.right: parent.right
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 {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: 8
visible: !ServersModel.isDefaultServerFromApi
onVisibleChanged: expandedServersMenuDescription.Layout
DropDownType {
id: containersDropDown
@@ -299,7 +296,6 @@ PageType {
}
}
ButtonGroup {
id: serversRadioButtonGroup
}
@@ -311,34 +311,6 @@ PageType {
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 {
id: saveRestartButton
@@ -129,7 +129,6 @@ PageType {
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
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 {
id: saveRestartButton
+4 -4
View File
@@ -35,7 +35,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: ContainersModel.getCurrentlyProcessedContainerName() + qsTr(" settings")
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
}
}
@@ -177,18 +177,18 @@ PageType {
visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ") + ContainersModel.getCurrentlyProcessedContainerName()
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: "#EB5757"
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 yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeCurrentlyProcessedContainer()
InstallController.removeProcessedContainer()
}
var noButtonFunction = function() {
}
@@ -86,6 +86,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 40
enabled: isPortEditable
headerText: qsTr("Port")
textFieldText: port
textField.maximumLength: 5
@@ -105,6 +107,8 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 20
enabled: isCipherEditable
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
@@ -148,6 +152,8 @@ PageType {
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: isPortEditable | isCipherEditable
text: qsTr("Save")
clickedFunc: function() {

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