From 9cfcb714aebfd7c31a105e647621479dd1068946 Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Mon, 30 Oct 2023 14:20:21 +0500 Subject: [PATCH] added native config generation for ss and cloak --- client/ui/controllers/exportController.cpp | 80 +++++++++++++++++++ client/ui/controllers/exportController.h | 2 + .../qml/Pages2/PageSetupWizardCredentials.qml | 10 ++- client/ui/qml/Pages2/PageShare.qml | 43 ++++++++-- 4 files changed, 127 insertions(+), 8 deletions(-) diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp index ef5cc4e3..06bddb8a 100644 --- a/client/ui/controllers/exportController.cpp +++ b/client/ui/controllers/exportController.cpp @@ -10,6 +10,8 @@ #include "configurators/openvpn_configurator.h" #include "configurators/wireguard_configurator.h" +#include "configurators/shadowsocks_configurator.h" +#include "configurators/cloak_configurator.h" #include "core/errorstrings.h" #include "systemController.h" #ifdef Q_OS_ANDROID @@ -155,6 +157,8 @@ void ExportController::generateOpenVpnConfig() m_config.append(line + "\n"); } + m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + emit exportConfigChanged(); } @@ -187,6 +191,82 @@ void ExportController::generateWireGuardConfig() m_config.append(line + "\n"); } + m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + + emit exportConfigChanged(); +} + +void ExportController::generateShadowSocksConfig() +{ + clearPreviousConfig(); + + int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); + ServerCredentials credentials = + qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); + + DockerContainer container = static_cast(m_containersModel->getCurrentlyProcessedContainerIndex()); + QModelIndex containerModelIndex = m_containersModel->index(container); + QJsonObject containerConfig = + qvariant_cast(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole)); + containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); + + ErrorCode errorCode = ErrorCode::NoError; + QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, &errorCode); + + if (errorCode) { + emit exportErrorOccurred(errorString(errorCode)); + return; + } + config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::ShadowSocks, config); + QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object(); + + m_config = QString("%1:%2@%3:%4") + .arg(configJson.value("method").toString(), + configJson.value("password").toString(), + configJson.value("server").toString(), + configJson.value("server_port").toString()); + + m_config = "ss://" + m_config.toUtf8().toBase64(); + + m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + + emit exportConfigChanged(); +} + +void ExportController::generateCloakConfig() +{ + clearPreviousConfig(); + + int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); + ServerCredentials credentials = + qvariant_cast(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); + + DockerContainer container = static_cast(m_containersModel->getCurrentlyProcessedContainerIndex()); + QModelIndex containerModelIndex = m_containersModel->index(container); + QJsonObject containerConfig = + qvariant_cast(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole)); + containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); + + ErrorCode errorCode = ErrorCode::NoError; + QString config = m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode); + + 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"); + + QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n"); + for (const QString &line : lines) { + m_config.append(line + "\n"); + } + + m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + emit exportConfigChanged(); } diff --git a/client/ui/controllers/exportController.h b/client/ui/controllers/exportController.h index 24eaa5c8..ee94e741 100644 --- a/client/ui/controllers/exportController.h +++ b/client/ui/controllers/exportController.h @@ -31,6 +31,8 @@ public slots: void generateConnectionConfig(); void generateOpenVpnConfig(); void generateWireGuardConfig(); + void generateShadowSocksConfig(); + void generateCloakConfig(); QString getConfig(); QList getQrCodes(); diff --git a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml index 5c32b0c5..3eadb647 100644 --- a/client/ui/qml/Pages2/PageSetupWizardCredentials.qml +++ b/client/ui/qml/Pages2/PageSetupWizardCredentials.qml @@ -54,7 +54,7 @@ PageType { regularExpression: InstallController.ipAddressPortRegExp() } - onTextFieldTextChanged: { + onFocusChanged: { textField.text = textField.text.replace(/^\s+|\s+$/g, ''); } } @@ -81,6 +81,10 @@ PageType { clickedFunc: function() { hidePassword = !hidePassword } + + onFocusChanged: { + textField.text = textField.text.replace(/^\s+|\s+$/g, ''); + } } BasicButtonType { @@ -90,6 +94,7 @@ PageType { text: qsTr("Continue") onClicked: function() { + forceActiveFocus() if (!isCredentialsFilled()) { return } @@ -112,8 +117,7 @@ PageType { Layout.fillWidth: true Layout.topMargin: 12 - text: qsTr("All data you enter will remain strictly confidential -and will not be shared or disclosed to the Amnezia or any third parties") + text: qsTr("All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties") } } } diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index ced7a5ff..577a9b3a 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -20,7 +20,9 @@ PageType { AmneziaConnection, AmneziaFullAccess, OpenVpn, - WireGuard + WireGuard, + ShadowSocks, + Cloak } Connections { @@ -44,18 +46,32 @@ PageType { break; } case PageShare.ConfigType.OpenVpn: { - ExportController.generateOpenVpnConfig(); + ExportController.generateOpenVpnConfig() shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config") shareConnectionDrawer.configExtension = ".ovpn" shareConnectionDrawer.configFileName = "amnezia_for_openvpn" - break; + break } case PageShare.ConfigType.WireGuard: { - ExportController.generateWireGuardConfig(); + ExportController.generateWireGuardConfig() shareConnectionDrawer.configCaption = qsTr("Save WireGuard config") shareConnectionDrawer.configExtension = ".conf" shareConnectionDrawer.configFileName = "amnezia_for_wireguard" - break; + break + } + case PageShare.ConfigType.ShadowSocks: { + ExportController.generateShadowSocksConfig() + shareConnectionDrawer.configCaption = qsTr("Save ShadowSocks config") + shareConnectionDrawer.configExtension = ".json" + shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks" + break + } + case PageShare.ConfigType.Cloak: { + ExportController.generateCloakConfig() + shareConnectionDrawer.configCaption = qsTr("Save Cloak config") + shareConnectionDrawer.configExtension = ".json" + shareConnectionDrawer.configFileName = "amnezia_for_cloak" + break } } @@ -96,6 +112,16 @@ PageType { property string name: qsTr("WireGuard native format") property var type: PageShare.ConfigType.WireGuard } + QtObject { + id: shadowSocksConnectionFormat + property string name: qsTr("ShadowSocks native format") + property var type: PageShare.ConfigType.ShadowSocks + } + QtObject { + id: cloakConnectionFormat + property string name: qsTr("Cloak native format") + property var type: PageShare.ConfigType.Cloak + } FlickableType { anchors.top: parent.top @@ -322,6 +348,13 @@ PageType { root.connectionTypesModel.push(openVpnConnectionFormat) } else if (index === ContainerProps.containerFromString("amnezia-wireguard")) { root.connectionTypesModel.push(wireGuardConnectionFormat) + } else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) { + root.connectionTypesModel.push(openVpnConnectionFormat) + root.connectionTypesModel.push(shadowSocksConnectionFormat) + } else if (index === ContainerProps.containerFromString("amnezia-openvpn-cloak")) { + root.connectionTypesModel.push(openVpnConnectionFormat) + root.connectionTypesModel.push(shadowSocksConnectionFormat) + root.connectionTypesModel.push(cloakConnectionFormat) } } }