diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp index 06bddb8a..048eadb0 100644 --- a/client/ui/controllers/exportController.cpp +++ b/client/ui/controllers/exportController.cpp @@ -8,10 +8,10 @@ #include #include -#include "configurators/openvpn_configurator.h" -#include "configurators/wireguard_configurator.h" -#include "configurators/shadowsocks_configurator.h" #include "configurators/cloak_configurator.h" +#include "configurators/openvpn_configurator.h" +#include "configurators/shadowsocks_configurator.h" +#include "configurators/wireguard_configurator.h" #include "core/errorstrings.h" #include "systemController.h" #ifdef Q_OS_ANDROID @@ -157,8 +157,6 @@ void ExportController::generateOpenVpnConfig() m_config.append(line + "\n"); } - m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); - emit exportConfigChanged(); } @@ -191,7 +189,8 @@ void ExportController::generateWireGuardConfig() m_config.append(line + "\n"); } - m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW); + m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1))); emit exportConfigChanged(); } @@ -211,7 +210,8 @@ void ExportController::generateShadowSocksConfig() containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); ErrorCode errorCode = ErrorCode::NoError; - QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, &errorCode); + QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container, + containerConfig, &errorCode); if (errorCode) { emit exportErrorOccurred(errorString(errorCode)); @@ -220,15 +220,20 @@ void ExportController::generateShadowSocksConfig() 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()); + QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n"); + for (const QString &line : lines) { + m_config.append(line + "\n"); + } - m_config = "ss://" + m_config.toUtf8().toBase64(); + 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_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); + m_nativeConfigString = "ss://" + m_config.toUtf8().toBase64(); + + qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_nativeConfigString.toUtf8(), qrcodegen::QrCode::Ecc::LOW); + m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1))); emit exportConfigChanged(); } @@ -248,7 +253,8 @@ void ExportController::generateCloakConfig() containerConfig.insert(config_key::container, ContainerProps::containerToString(container)); ErrorCode errorCode = ErrorCode::NoError; - QString config = m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode); + QString config = + m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode); if (errorCode) { emit exportErrorOccurred(errorString(errorCode)); @@ -265,8 +271,6 @@ void ExportController::generateCloakConfig() m_config.append(line + "\n"); } - m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8()); - emit exportConfigChanged(); } @@ -275,6 +279,11 @@ QString ExportController::getConfig() return m_config; } +QString ExportController::getNativeConfigString() +{ + return m_nativeConfigString; +} + QList ExportController::getQrCodes() { return m_qrCodes; @@ -299,7 +308,7 @@ QList ExportController::generateQrCodeImageSeries(const QByteArray &dat QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW); - QString svg = QString::fromStdString(toSvgString(qr, 0)); + QString svg = QString::fromStdString(toSvgString(qr, 1)); chunks.append(svgToBase64(svg)); } @@ -319,5 +328,6 @@ int ExportController::getQrCodesCount() void ExportController::clearPreviousConfig() { m_config.clear(); + m_nativeConfigString.clear(); m_qrCodes.clear(); } diff --git a/client/ui/controllers/exportController.h b/client/ui/controllers/exportController.h index ee94e741..25658529 100644 --- a/client/ui/controllers/exportController.h +++ b/client/ui/controllers/exportController.h @@ -22,6 +22,7 @@ public: Q_PROPERTY(QList qrCodes READ getQrCodes NOTIFY exportConfigChanged) Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged) Q_PROPERTY(QString config READ getConfig NOTIFY exportConfigChanged) + Q_PROPERTY(QString nativeConfigString READ getNativeConfigString NOTIFY exportConfigChanged) public slots: void generateFullAccessConfig(); @@ -35,6 +36,7 @@ public slots: void generateCloakConfig(); QString getConfig(); + QString getNativeConfigString(); QList getQrCodes(); void exportConfig(const QString &fileName); @@ -61,6 +63,7 @@ private: std::shared_ptr m_configurator; QString m_config; + QString m_nativeConfigString; QList m_qrCodes; #ifdef Q_OS_ANDROID diff --git a/client/ui/qml/Components/ShareConnectionDrawer.qml b/client/ui/qml/Components/ShareConnectionDrawer.qml index 1158dadc..e354e951 100644 --- a/client/ui/qml/Components/ShareConnectionDrawer.qml +++ b/client/ui/qml/Components/ShareConnectionDrawer.qml @@ -112,6 +112,30 @@ DrawerType { } } + BasicButtonType { + Layout.fillWidth: true + Layout.topMargin: 8 + + visible: nativeConfigString.text !== "" + + defaultColor: "transparent" + hoveredColor: Qt.rgba(1, 1, 1, 0.08) + pressedColor: Qt.rgba(1, 1, 1, 0.12) + disabledColor: "#878B91" + textColor: "#D7D8DB" + borderWidth: 1 + + text: qsTr("Copy config string") + imageSource: "qrc:/images/controls/copy.svg" + + onClicked: { + nativeConfigString.selectAll() + nativeConfigString.copy() + nativeConfigString.select(0, 0) + PageController.showNotificationMessage(qsTr("Copied")) + } + } + BasicButtonType { Layout.fillWidth: true Layout.topMargin: 24 @@ -170,6 +194,12 @@ DrawerType { } TextField { + id: nativeConfigString + visible: false + text: ExportController.nativeConfigString + } + + TextArea { id: configText Layout.fillWidth: true @@ -213,7 +243,6 @@ DrawerType { Image { anchors.fill: parent - anchors.margins: 2 smooth: false source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""