From c5a5bfde696667dde0011fc231651f0fdc19eb55 Mon Sep 17 00:00:00 2001 From: Nethius Date: Thu, 14 Mar 2024 04:22:10 +0700 Subject: [PATCH] extended the validation of the contents of the imported file (#670) Extended the validation of the contents of the imported file --- client/ui/controllers/importController.cpp | 119 +++++++++++------- client/ui/controllers/importController.h | 11 +- client/ui/controllers/settingsController.cpp | 5 + client/ui/controllers/settingsController.h | 1 + .../Pages2/PageSetupWizardConfigSource.qml | 7 +- client/ui/qml/Pages2/PageSetupWizardStart.qml | 14 +++ .../ui/qml/Pages2/PageSetupWizardTextKey.qml | 2 +- client/ui/qml/Pages2/PageStart.qml | 8 ++ 8 files changed, 109 insertions(+), 58 deletions(-) diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index f7c1ea20..b33954bf 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -18,7 +18,9 @@ namespace enum class ConfigTypes { Amnezia, OpenVpn, - WireGuard + WireGuard, + Backup, + Invalid }; ConfigTypes checkConfigFormat(const QString &config) @@ -32,15 +34,23 @@ namespace const QString wireguardConfigPatternSectionInterface = "[Interface]"; const QString wireguardConfigPatternSectionPeer = "[Peer]"; - if (config.contains(openVpnConfigPatternCli) - && (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) - && (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) { + const QString amneziaConfigPattern = "containers"; + const QString amneziaFreeConfigPattern = "api_key"; + const QString backupPattern = "Servers/serversList"; + + if (config.contains(backupPattern)) { + return ConfigTypes::Backup; + } else if (config.contains(amneziaConfigPattern) || config.contains(amneziaFreeConfigPattern)) { + return ConfigTypes::Amnezia; + } else if (config.contains(openVpnConfigPatternCli) + && (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) + && (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) { return ConfigTypes::OpenVpn; } else if (config.contains(wireguardConfigPatternSectionInterface) && config.contains(wireguardConfigPatternSectionPeer)) { return ConfigTypes::WireGuard; } - return ConfigTypes::Amnezia; + return ConfigTypes::Invalid; } #if defined Q_OS_ANDROID @@ -58,34 +68,65 @@ ImportController::ImportController(const QSharedPointer &serversMo #endif } -void ImportController::extractConfigFromFile(const QString &fileName) +bool ImportController::extractConfigFromFile(const QString &fileName) { QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QString data = file.readAll(); - extractConfigFromData(data); m_configFileName = QFileInfo(file.fileName()).fileName(); + return extractConfigFromData(data); } + + emit importErrorOccurred(tr("Unable to open file")); + return false; } -void ImportController::extractConfigFromData(QString data) +bool ImportController::extractConfigFromData(QString data) { - auto configFormat = checkConfigFormat(data); - if (configFormat == ConfigTypes::OpenVpn) { - m_config = extractOpenVpnConfig(data); - } else if (configFormat == ConfigTypes::WireGuard) { - m_config = extractWireGuardConfig(data); - } else { - m_config = extractAmneziaConfig(data); - } -} + QString config = data; + auto configFormat = checkConfigFormat(config); + if (configFormat == ConfigTypes::Invalid) { + data.replace("vpn://", ""); + QByteArray ba = + QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); + QByteArray ba_uncompressed = qUncompress(ba); + if (!ba_uncompressed.isEmpty()) { + ba = ba_uncompressed; + } -void ImportController::extractConfigFromCode(QString code) -{ - m_config = extractAmneziaConfig(code); - m_configFileName = ""; + config = ba; + configFormat = checkConfigFormat(config); + } + + switch (configFormat) { + case ConfigTypes::OpenVpn: { + m_config = extractOpenVpnConfig(config); + return true; + } + case ConfigTypes::WireGuard: { + m_config = extractWireGuardConfig(config); + return true; + } + case ConfigTypes::Amnezia: { + m_config = QJsonDocument::fromJson(config.toUtf8()).object(); + return true; + } + case ConfigTypes::Backup: { + if (!m_serversModel->getServersCount()) { + emit restoreAppConfig(config.toUtf8()); + } else { + emit importErrorOccurred(tr("Invalid configuration file")); + } + break; + } + case ConfigTypes::Invalid: { + emit importErrorOccurred(tr("Invalid configuration file")); + break; + } + } + return false; } bool ImportController::extractConfigFromQr(const QByteArray &data) @@ -139,28 +180,13 @@ void ImportController::importConfig() } else { qDebug() << "Failed to import profile"; qDebug().noquote() << QJsonDocument(m_config).toJson(); - emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError)); + emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError), false); } m_config = {}; m_configFileName.clear(); } -QJsonObject ImportController::extractAmneziaConfig(QString &data) -{ - data.replace("vpn://", ""); - QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); - - QByteArray ba_uncompressed = qUncompress(ba); - if (!ba_uncompressed.isEmpty()) { - ba = ba_uncompressed; - } - - QJsonObject config = QJsonDocument::fromJson(ba).object(); - - return config; -} - QJsonObject ImportController::extractOpenVpnConfig(const QString &data) { QJsonObject openVpnConfig; @@ -229,8 +255,8 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) if (hostNameAndPortMatch.hasCaptured(1)) { hostName = hostNameAndPortMatch.captured(1); } else { - qDebug() << "Failed to import profile"; - emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError)); + qDebug() << "Key parameter 'Endpoint' is missing"; + emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError), false); } if (hostNameAndPortMatch.hasCaptured(2)) { @@ -242,10 +268,11 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) lastConfig[config_key::hostName] = hostName; lastConfig[config_key::port] = port.toInt(); -// if (!configMap.value("PrivateKey").isEmpty() && !configMap.value("Address").isEmpty() -// && !configMap.value("PresharedKey").isEmpty() && !configMap.value("PublicKey").isEmpty()) { + if (!configMap.value("PrivateKey").isEmpty() && !configMap.value("Address").isEmpty() + && !configMap.value("PublicKey").isEmpty()) { lastConfig[config_key::client_priv_key] = configMap.value("PrivateKey"); lastConfig[config_key::client_ip] = configMap.value("Address"); + if (!configMap.value("PresharedKey").isEmpty()) { lastConfig[config_key::psk_key] = configMap.value("PresharedKey"); } else if (!configMap.value("PreSharedKey").isEmpty()) { @@ -253,11 +280,11 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data) } lastConfig[config_key::server_pub_key] = configMap.value("PublicKey"); -// } else { -// qDebug() << "Failed to import profile"; -// emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError)); -// return QJsonObject(); -// } + } else { + qDebug() << "One of the key parameters is missing (PrivateKey, Address, PublicKey)"; + emit importErrorOccurred(errorString(ErrorCode::ImportInvalidConfigError)); + return QJsonObject(); + } QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(",")); diff --git a/client/ui/controllers/importController.h b/client/ui/controllers/importController.h index 5731cae8..a8d91124 100644 --- a/client/ui/controllers/importController.h +++ b/client/ui/controllers/importController.h @@ -18,9 +18,8 @@ public: public slots: void importConfig(); - void extractConfigFromFile(const QString &fileName); - void extractConfigFromData(QString data); - void extractConfigFromCode(QString code); + bool extractConfigFromFile(const QString &fileName); + bool extractConfigFromData(QString data); bool extractConfigFromQr(const QByteArray &data); QString getConfig(); QString getConfigFileName(); @@ -39,12 +38,14 @@ public slots: signals: void importFinished(); - void importErrorOccurred(const QString &errorMessage, bool goToPageHome = false); + void importErrorOccurred(const QString &errorMessage, bool goToPageHome); + void importErrorOccurred(const QString &errorMessage); void qrDecodingFinished(); + void restoreAppConfig(const QByteArray &data); + private: - QJsonObject extractAmneziaConfig(QString &data); QJsonObject extractOpenVpnConfig(const QString &data); QJsonObject extractWireGuardConfig(const QString &data); diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index 658bbb19..f559f1df 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -113,6 +113,11 @@ void SettingsController::restoreAppConfig(const QString &fileName) QByteArray data = file.readAll(); + restoreAppConfigFromData(data); +} + +void SettingsController::restoreAppConfigFromData(const QByteArray &data) +{ bool ok = m_settings->restoreAppConfig(data); if (ok) { m_serversModel->resetModel(); diff --git a/client/ui/controllers/settingsController.h b/client/ui/controllers/settingsController.h index 5b30b095..36247a55 100644 --- a/client/ui/controllers/settingsController.h +++ b/client/ui/controllers/settingsController.h @@ -41,6 +41,7 @@ public slots: void backupAppConfig(const QString &fileName); void restoreAppConfig(const QString &fileName); + void restoreAppConfigFromData(const QByteArray &data); QString getAppVersion(); diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 33aee0f1..6ed8f5ab 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -73,12 +73,7 @@ PageType { "Config files (*.vpn *.ovpn *.conf)" var fileName = SystemController.getFileName(qsTr("Open config file"), nameFilter) if (fileName !== "") { - if (fileName.indexOf(".backup") !== -1 && !ServersModel.getServersCount()) { - PageController.showBusyIndicator(true) - SettingsController.restoreAppConfig(fileName) - PageController.showBusyIndicator(false) - } else { - ImportController.extractConfigFromFile(fileName) + if (ImportController.extractConfigFromFile(fileName)) { PageController.goToPage(PageEnum.PageSetupWizardViewConfig) } } diff --git a/client/ui/qml/Pages2/PageSetupWizardStart.qml b/client/ui/qml/Pages2/PageSetupWizardStart.qml index 89d4dc12..b12589c8 100644 --- a/client/ui/qml/Pages2/PageSetupWizardStart.qml +++ b/client/ui/qml/Pages2/PageSetupWizardStart.qml @@ -81,6 +81,20 @@ PageType { } } + Connections { + target: ImportController + + function onRestoreAppConfig(data) { + PageController.showBusyIndicator(true) + SettingsController.restoreAppConfigFromData(data) + PageController.showBusyIndicator(false) + } + + function onImportErrorOccurred(errorMessage) { + PageController.showErrorMessage(errorMessage) + } + } + FlickableType { id: fl anchors.top: parent.top diff --git a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml index 4a322042..30cd8b89 100644 --- a/client/ui/qml/Pages2/PageSetupWizardTextKey.qml +++ b/client/ui/qml/Pages2/PageSetupWizardTextKey.qml @@ -77,7 +77,7 @@ PageType { text: qsTr("Continue") clickedFunc: function() { - ImportController.extractConfigFromCode(textKey.textFieldText) + ImportController.extractConfigFromData(textKey.textFieldText) PageController.goToPage(PageEnum.PageSetupWizardViewConfig) } } diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml index 3fd2d73c..44a2453d 100644 --- a/client/ui/qml/Pages2/PageStart.qml +++ b/client/ui/qml/Pages2/PageStart.qml @@ -121,6 +121,14 @@ PageType { } } + Connections { + target: ImportController + + function onImportErrorOccurred(errorMessage) { + PageController.showErrorMessage(errorMessage) + } + } + StackViewType { id: tabBarStackView