diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 327a83f6..a13afb5f 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -27,6 +27,9 @@ add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}") add_definitions(-DPROD_PROXY_STORAGE_KEY="$ENV{PROD_PROXY_STORAGE_KEY}") +add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}") +add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}") + if(IOS) set(PACKAGES ${PACKAGES} Multimedia) endif() diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp index 8e5f8ed5..3f8684e0 100644 --- a/client/core/controllers/apiController.cpp +++ b/client/core/controllers/apiController.cpp @@ -9,8 +9,8 @@ #include "QRsa.h" #include "amnezia_application.h" -#include "core/enums/apiEnums.h" #include "configurators/wireguard_configurator.h" +#include "core/enums/apiEnums.h" #include "version.h" namespace @@ -42,7 +42,7 @@ namespace constexpr char keyPayload[] = "key_payload"; } - const QStringList proxyStorageUrl = {""}; + const QStringList proxyStorageUrl = { "" }; ErrorCode checkErrors(const QList &sslErrors, QNetworkReply *reply) { @@ -65,7 +65,8 @@ namespace } } -ApiController::ApiController(const QString &gatewayEndpoint, QObject *parent) : QObject(parent), m_gatewayEndpoint(gatewayEndpoint) +ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent) + : QObject(parent), m_gatewayEndpoint(gatewayEndpoint), m_isDevEnvironment(isDevEnvironment) { } @@ -143,7 +144,7 @@ QStringList ApiController::getProxyUrls() QEventLoop wait; QList sslErrors; - QNetworkReply* reply; + QNetworkReply *reply; for (const auto &proxyStorageUrl : proxyStorageUrl) { request.setUrl(proxyStorageUrl); @@ -281,7 +282,7 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody) request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint)); - QNetworkReply* reply; + QNetworkReply *reply; reply = amnApp->manager()->get(request); QEventLoop wait; @@ -300,7 +301,8 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody) QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit); connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); wait.exec(); - if (reply->error() != QNetworkReply::NetworkError::TimeoutError && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) { + if (reply->error() != QNetworkReply::NetworkError::TimeoutError + && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) { break; } reply->deleteLater(); @@ -355,7 +357,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co EVP_PKEY *publicKey = nullptr; try { - QByteArray key = PROD_AGW_PUBLIC_KEY; + QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY; QSimpleCrypto::QRsa rsa; publicKey = rsa.getPublicKeyFromByteArray(key); } catch (...) { @@ -375,7 +377,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64()); requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64()); - QNetworkReply* reply = manager.post(request, QJsonDocument(requestBody).toJson()); + QNetworkReply *reply = manager.post(request, QJsonDocument(requestBody).toJson()); QEventLoop wait; connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit); @@ -395,7 +397,8 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit); connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; }); wait.exec(); - if (reply->error() != QNetworkReply::NetworkError::TimeoutError && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) { + if (reply->error() != QNetworkReply::NetworkError::TimeoutError + && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) { break; } reply->deleteLater(); diff --git a/client/core/controllers/apiController.h b/client/core/controllers/apiController.h index 6cfde983..a094233b 100644 --- a/client/core/controllers/apiController.h +++ b/client/core/controllers/apiController.h @@ -14,7 +14,7 @@ class ApiController : public QObject Q_OBJECT public: - explicit ApiController(const QString &gatewayEndpoint, QObject *parent = nullptr); + explicit ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent = nullptr); public slots: void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig); @@ -44,6 +44,7 @@ private: QString m_gatewayEndpoint; QStringList m_proxyUrls; + bool m_isDevEnvironment; }; #endif // APICONTROLLER_H diff --git a/client/settings.cpp b/client/settings.cpp index 490ede52..8faf00c2 100644 --- a/client/settings.cpp +++ b/client/settings.cpp @@ -519,7 +519,22 @@ void Settings::setGatewayEndpoint(const QString &endpoint) m_gatewayEndpoint = endpoint; } +void Settings::setDevGatewayEndpoint() +{ + m_gatewayEndpoint = DEV_AGW_ENDPOINT; +} + QString Settings::getGatewayEndpoint() { return m_gatewayEndpoint; } + +bool Settings::isDevGatewayEnv() +{ + return m_isDevGatewayEnv; +} + +void Settings::toggleDevGatewayEnv(bool enabled) +{ + m_isDevGatewayEnv = enabled; +} diff --git a/client/settings.h b/client/settings.h index 55a3d057..c0ab0559 100644 --- a/client/settings.h +++ b/client/settings.h @@ -217,7 +217,10 @@ public: void resetGatewayEndpoint(); void setGatewayEndpoint(const QString &endpoint); + void setDevGatewayEndpoint(); QString getGatewayEndpoint(); + bool isDevGatewayEnv(); + void toggleDevGatewayEnv(bool enabled); signals: void saveLogsChanged(bool enabled); @@ -234,6 +237,7 @@ private: mutable SecureQSettings m_settings; QString m_gatewayEndpoint; + bool m_isDevGatewayEnv; }; #endif // SETTINGS_H diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp index 66e04520..c6f17057 100644 --- a/client/ui/controllers/installController.cpp +++ b/client/ui/controllers/installController.cpp @@ -799,7 +799,7 @@ void InstallController::addEmptyServer() bool InstallController::fillAvailableServices() { - ApiController apiController(m_settings->getGatewayEndpoint()); + ApiController apiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv()); QByteArray responseBody; ErrorCode errorCode = apiController.getServicesList(responseBody); @@ -821,7 +821,7 @@ bool InstallController::installServiceFromApi() return false; } - ApiController apiController(m_settings->getGatewayEndpoint()); + ApiController apiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv()); QJsonObject serverConfig; ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(), @@ -849,7 +849,7 @@ bool InstallController::installServiceFromApi() bool InstallController::updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool reloadServiceConfig) { - ApiController apiController(m_settings->getGatewayEndpoint()); + ApiController apiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv()); auto serverConfig = m_serversModel->getServerConfig(serverIndex); auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); @@ -885,7 +885,7 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin void InstallController::updateServiceFromTelegram(const int serverIndex) { - ApiController *apiController = new ApiController(m_settings->getGatewayEndpoint()); + ApiController *apiController = new ApiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv()); auto serverConfig = m_serversModel->getServerConfig(serverIndex); diff --git a/client/ui/controllers/settingsController.cpp b/client/ui/controllers/settingsController.cpp index 911bcb16..7a95589b 100644 --- a/client/ui/controllers/settingsController.cpp +++ b/client/ui/controllers/settingsController.cpp @@ -283,7 +283,24 @@ void SettingsController::setGatewayEndpoint(const QString &endpoint) QString SettingsController::getGatewayEndpoint() { - return m_settings->getGatewayEndpoint(); + return m_settings->isDevGatewayEnv() ? "Dev endpoint" : m_settings->getGatewayEndpoint(); +} + +bool SettingsController::isDevGatewayEnv() +{ + return m_settings->isDevGatewayEnv(); +} + +void SettingsController::toggleDevGatewayEnv(bool enabled) +{ + m_settings->toggleDevGatewayEnv(enabled); + if (enabled) { + m_settings->setDevGatewayEndpoint(); + } else { + m_settings->resetGatewayEndpoint(); + } + emit gatewayEndpointChanged(m_settings->getGatewayEndpoint()); + emit devGatewayEnvChanged(enabled); } bool SettingsController::isOnTv() diff --git a/client/ui/controllers/settingsController.h b/client/ui/controllers/settingsController.h index 89de1bf8..d64e63cf 100644 --- a/client/ui/controllers/settingsController.h +++ b/client/ui/controllers/settingsController.h @@ -27,6 +27,7 @@ public: Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled) Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged) + Q_PROPERTY(bool isDevGatewayEnv READ isDevGatewayEnv WRITE toggleDevGatewayEnv NOTIFY devGatewayEnvChanged) public slots: void toggleAmneziaDns(bool enable); @@ -81,6 +82,8 @@ public slots: void resetGatewayEndpoint(); void setGatewayEndpoint(const QString &endpoint); QString getGatewayEndpoint(); + bool isDevGatewayEnv(); + void toggleDevGatewayEnv(bool enabled); bool isOnTv(); @@ -105,6 +108,7 @@ signals: void devModeEnabled(); void gatewayEndpointChanged(const QString &endpoint); + void devGatewayEnvChanged(bool enabled); private: QSharedPointer m_serversModel; diff --git a/client/ui/models/apiServicesModel.cpp b/client/ui/models/apiServicesModel.cpp index 3e74d259..2a87bde3 100644 --- a/client/ui/models/apiServicesModel.cpp +++ b/client/ui/models/apiServicesModel.cpp @@ -25,6 +25,8 @@ namespace constexpr char availableCountries[] = "available_countries"; constexpr char storeEndpoint[] = "store_endpoint"; + + constexpr char isAvailable[] = "is_available"; } namespace serviceType @@ -63,8 +65,12 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const return tr("Classic VPN for comfortable work, downloading large files and watching videos. " "Works for any sites. Speed up to %1 MBit/s") .arg(speed); - } else { - return tr("VPN to access blocked sites in regions with high levels of Internet censorship. "); + } else if (serviceType == serviceType::amneziaFree){ + QString description = tr("VPN to access blocked sites in regions with high levels of Internet censorship. "); + if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) { + description += tr("

Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again."); + } + return description; } } case ServiceDescriptionRole: { @@ -75,6 +81,14 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const return tr("Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship"); } } + case IsServiceAvailableRole: { + if (serviceType == serviceType::amneziaFree) { + if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) { + return false; + } + } + return true; + } case SpeedRole: { auto speed = serviceInfo.value(configKey::speed).toString(); return tr("%1 MBit/s").arg(speed); @@ -193,6 +207,7 @@ QHash ApiServicesModel::roleNames() const roles[NameRole] = "name"; roles[CardDescriptionRole] = "cardDescription"; roles[ServiceDescriptionRole] = "serviceDescription"; + roles[IsServiceAvailableRole] = "isServiceAvailable"; roles[SpeedRole] = "speed"; roles[WorkPeriodRole] = "workPeriod"; roles[RegionRole] = "region"; diff --git a/client/ui/models/apiServicesModel.h b/client/ui/models/apiServicesModel.h index 64676be6..49918940 100644 --- a/client/ui/models/apiServicesModel.h +++ b/client/ui/models/apiServicesModel.h @@ -13,6 +13,7 @@ public: NameRole = Qt::UserRole + 1, CardDescriptionRole, ServiceDescriptionRole, + IsServiceAvailableRole, SpeedRole, WorkPeriodRole, RegionRole, diff --git a/client/ui/qml/Controls2/CardWithIconsType.qml b/client/ui/qml/Controls2/CardWithIconsType.qml index 8630434b..fea65116 100644 --- a/client/ui/qml/Controls2/CardWithIconsType.qml +++ b/client/ui/qml/Controls2/CardWithIconsType.qml @@ -79,6 +79,7 @@ Button { visible: text !== "" color: AmneziaStyle.color.mutedGray + textFormat: Text.RichText Layout.fillWidth: true Layout.rightMargin: 16 diff --git a/client/ui/qml/Pages2/PageDevMenu.qml b/client/ui/qml/Pages2/PageDevMenu.qml index af6f773a..5da40eff 100644 --- a/client/ui/qml/Pages2/PageDevMenu.qml +++ b/client/ui/qml/Pages2/PageDevMenu.qml @@ -89,6 +89,21 @@ PageType { // KeyNavigation.tab: saveButton } + + SwitcherType { + id: switcher + + Layout.fillWidth: true + Layout.rightMargin: 16 + Layout.leftMargin: 16 + Layout.topMargin: 16 + + text: qsTr("Dev gateway environment") + checked: SettingsController.isDevGatewayEnv + onToggled: function() { + SettingsController.isDevGatewayEnv = checked + } + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml index cb79f19e..85a50393 100644 --- a/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml +++ b/client/ui/qml/Pages2/PageSetupWizardApiServicesList.qml @@ -88,8 +88,10 @@ PageType { rightImageSource: "qrc:/images/controls/chevron-right.svg" onClicked: { - ApiServicesModel.setServiceIndex(index) - PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) + if (isServiceAvailable) { + ApiServicesModel.setServiceIndex(index) + PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo) + } } } } diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml index 3febca4c..3c56b52e 100644 --- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml +++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml @@ -119,8 +119,6 @@ PageType { CardWithIconsType { id: apiInstalling - visible: false - Layout.fillWidth: true Layout.rightMargin: 16 Layout.leftMargin: 16