mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-21 02:01:03 +07:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 477a2f3591 | |||
| 3c3870f270 | |||
| a6ca1b12da | |||
| 82a9e7e27d | |||
| f5301e1315 | |||
| adab30fc81 | |||
| e7bd24f065 | |||
| 2ec448ba13 | |||
| c6e6f2ae84 | |||
| 45de951897 | |||
| ee7ac389a4 | |||
| bd414191e9 | |||
| 4eebb6673a | |||
| a36585d035 | |||
| c4de28bb3b | |||
| dcf1989414 | |||
| bd2288c239 | |||
| 781dba61f1 | |||
| 926d3643a4 |
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
+1
@@ -95,6 +95,7 @@ open class Wireguard : Protocol() {
|
||||
return WireguardConfig.build {
|
||||
configWireguard(configData, configDataJson)
|
||||
configSplitTunneling(config)
|
||||
configAppSplitTunneling(config)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.*");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
+16
-41
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 >:(
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user