mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
refactor: refactor the application to the mvvm architecture (#2009)
* refactor: move business logic from servers model * refactor: move containersModel initialization * refactor: added protocol ui controller and removed settings class from protocols model * refactor: moved cli management to separate controller * refactor: moved app split to separate controller * refactor: moved site split to separate controller * refactor: moved allowed dns to separate controller * refactor: moved language logic to separate ui controller * refactor: removed Settings from devices model * refactor: moved configs and services api logit to separate core controller * refactor: added a layer with a repository between the storage and controllers * refactor: use child parent system instead of smart pointers for controllers and models initialization * refactor: moved install functions from server controller to install controller * refactor: install controller refactoring * chore: renamed exportController to exportUiController * refactor: separate export controller * refactor: removed VpnConfigurationsController * chore: renamed ServerController to SshSession * refactor: replaced ServerController to SshSession * chore: moved qml controllers to separate folder * chore: include fixes * chore: moved utils from core root to core/utils * chore: include fixes * chore: rename core/utils files to camelCase foramt * chore: include fixes * chore: moved some utils to api and selfhosted folders * chore: include fixes * chore: remove unused file * chore: moved serialization folder to core/utils * chore: include fixes * chore: moved some files from client root to core/utils * chore: include fixes * chore: moved ui utils to ui/utils folder * chore: include fixes * chore: move utils from root to ui/utils * chore: include fixes * chore: moved configurators to core/configurators * chore: include fixes * refactor: moved iap logic from ui controller to core * refactor: moved remaining core logic from ApiConfigsController to SubscriptionController * chore: rename apiNewsController to apiNewsUiController * refactor: moved core logic from news ui controller to core * chore: renamed apiConfigsController to subscriptionUiController * chore: include fixes * refactor: merge ApiSettingsController with SubscriptionUiController * chore: moved ui selfhosted controllers to separate folder * chore: include fixes * chore: rename connectionController to connectiomUiController * refactor: moved core logic from connectionUiController * chore: rename settingsController to settingsUiController * refactor: move core logic from settingsUiController * refactor: moved core controller signal/slot connections to separate class * fix: newsController fixes after refactoring * chore: rename model to camelCase * chore: include fixes * chore: remove unused code * chore: move selfhosted core to separate folder * chore: include fixes * chore: rename importController to importUiController * refactor: move core logic from importUiController * chore: minor fixes * chore: remove prem v1 migration * refactor: remove openvpn over cloak and openvpn over shadowsocks * refactor: removed protocolsForContainer function * refactor: add core models * refactor: replace json with c++ structs for server config * refactor: move getDnsPair to ServerConfigUtils * feat: add admin selfhosted config export test * feat: add multi import test * refactor: use coreController for tests * feat: add few simple tests * chore: qrepos in all core controllers * feat: add test for settings * refactor: remove repo dependency from configurators * chore: moved protocols to core folder * chore: include fixes * refactor: moved containersDefs, defs, apiDefs, protocolsDefs to different places * chore: include fixes * chore: build fixes * chore: build fixes * refactor: remove q repo and interface repo * feat: add test for ui servers model and controller * chore: renamed to camelCase * chore: include fixes * refactor: moved core logic from sites ui controller * fix: fixed api config processing * fix: fixed processed server index processing * refactor: protocol models now use c++ structs instead of json configs * refactor: servers model now use c++ struct instead of json config * fix: fixed default server index processing * fix: fix logs init * fix: fix secure settings load keys * chore: build fixes * fix: fixed clear settings * fix: fixed restore backup * fix: sshSession usage * fix: fixed export functions signatures * fix: return missing part from buildContainerWorker * fix: fixed server description on page home * refactor: add container config helpers functions * refactor: c++ structs instead of json * chore: add dns protocol config struct * refactor: move config utils functions to config structs * feat: add test for selfhosted server setup * refactor: separate resources.qrc * fix: fixed server rename * chore: return nameOverriddenByUser * fix: build fixes * fix: fixed models init * refactor: cleanup models usage * fix: fixed models init * chore: cleanup connections and functions signatures * chore: cleanup updateModel calls * feat: added cache to servers repo * chore: cleanup unused functions * chore: ssxray processing * chore: remove transportProtoWithDefault and portWithDefault functions * chore: removed proto types any and l2tp * refactor: moved some constants * fix: fixed native configs export * refactor: remove json from processConfigWith functions * fix: fixed processed server index usage * fix: qml warning fixes * chore: merge fixes * chore: update tests * fix: fixed xray config processing * fix: fixed split tunneling processing * chore: rename sites controllers and model * chore: rename fixes * chore: minor fixes * chore: remove ability to load backup from "file with connection settings" button * fix: fixed api device revoke * fix: remove full model update when renaming a user * fix: fixed premium/free server rename * fix: fixed selfhosted new server install * fix: fixed updateContainer function * fix: fixed revoke for external premium configs * feat: add native configs qr processing * chore: codestyle fixes * fix: fixed admin config create * chore: again remove ability to load backup from "file with connection settings" button * chore: minor fixes * fix: fixed variables initialization * fix: fixed qml imports * fix: minor fixes * fix: fix vpnConnection function calls * feat: add buckup error handling * fix: fixed admin config revok * fix: fixed selfhosted awg installation * fix: ad visability * feat: add empty check for primary dns * chore: minor fixes
This commit is contained in:
@@ -1,35 +0,0 @@
|
||||
#ifndef ALLOWEDDNSCONTROLLER_H
|
||||
#define ALLOWEDDNSCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "settings.h"
|
||||
#include "ui/models/allowed_dns_model.h"
|
||||
|
||||
class AllowedDnsController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AllowedDnsController(const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<AllowedDnsModel> &allowedDnsModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addDns(QString ip);
|
||||
void removeDns(int index);
|
||||
|
||||
void importDns(const QString &fileName, bool replaceExisting);
|
||||
void exportDns(const QString &fileName);
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
QSharedPointer<AllowedDnsModel> m_allowedDnsModel;
|
||||
};
|
||||
|
||||
#endif // ALLOWEDDNSCONTROLLER_H
|
||||
+25
-17
@@ -1,4 +1,4 @@
|
||||
#include "allowedDnsController.h"
|
||||
#include "allowedDnsUiController.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
@@ -7,17 +7,22 @@
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "systemController.h"
|
||||
#include "core/networkUtilities.h"
|
||||
#include "core/defs.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
|
||||
AllowedDnsController::AllowedDnsController(const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<AllowedDnsModel> &allowedDnsModel,
|
||||
QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_allowedDnsModel(allowedDnsModel)
|
||||
AllowedDnsUiController::AllowedDnsUiController(AllowedDnsController* allowedDnsController,
|
||||
AllowedDnsModel* allowedDnsModel,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_allowedDnsController(allowedDnsController),
|
||||
m_allowedDnsModel(allowedDnsModel)
|
||||
{
|
||||
m_allowedDnsModel->updateModel(m_allowedDnsController->getCurrentDnsServers());
|
||||
}
|
||||
|
||||
void AllowedDnsController::addDns(QString ip)
|
||||
void AllowedDnsUiController::addDns(QString ip)
|
||||
{
|
||||
if (ip.isEmpty()) {
|
||||
return;
|
||||
@@ -28,23 +33,22 @@ void AllowedDnsController::addDns(QString ip)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_allowedDnsModel->addDns(ip)) {
|
||||
if (m_allowedDnsController->addDns(ip)) {
|
||||
emit finished(tr("New DNS server added: %1").arg(ip));
|
||||
} else {
|
||||
emit errorOccurred(tr("DNS server already exists: %1").arg(ip));
|
||||
}
|
||||
}
|
||||
|
||||
void AllowedDnsController::removeDns(int index)
|
||||
void AllowedDnsUiController::removeDns(int index)
|
||||
{
|
||||
auto modelIndex = m_allowedDnsModel->index(index);
|
||||
auto ip = m_allowedDnsModel->data(modelIndex, AllowedDnsModel::Roles::IpRole).toString();
|
||||
m_allowedDnsModel->removeDns(modelIndex);
|
||||
|
||||
m_allowedDnsController->removeDns(index);
|
||||
emit finished(tr("DNS server removed: %1").arg(ip));
|
||||
}
|
||||
|
||||
void AllowedDnsController::importDns(const QString &fileName, bool replaceExisting)
|
||||
void AllowedDnsUiController::importDns(const QString &fileName, bool replaceExisting)
|
||||
{
|
||||
QByteArray jsonData;
|
||||
if (!SystemController::readFile(fileName, jsonData)) {
|
||||
@@ -77,14 +81,13 @@ void AllowedDnsController::importDns(const QString &fileName, bool replaceExisti
|
||||
dnsServers.append(ip);
|
||||
}
|
||||
|
||||
m_allowedDnsModel->addDnsList(dnsServers, replaceExisting);
|
||||
|
||||
m_allowedDnsController->addDnsList(dnsServers, replaceExisting);
|
||||
emit finished(tr("Import completed"));
|
||||
}
|
||||
|
||||
void AllowedDnsController::exportDns(const QString &fileName)
|
||||
void AllowedDnsUiController::exportDns(const QString &fileName)
|
||||
{
|
||||
auto dnsServers = m_allowedDnsModel->getCurrentDnsServers();
|
||||
auto dnsServers = m_allowedDnsController->getCurrentDnsServers();
|
||||
|
||||
QJsonArray jsonArray;
|
||||
|
||||
@@ -98,4 +101,9 @@ void AllowedDnsController::exportDns(const QString &fileName)
|
||||
SystemController::saveFile(fileName, jsonData);
|
||||
|
||||
emit finished(tr("Export completed"));
|
||||
}
|
||||
|
||||
void AllowedDnsUiController::updateModel()
|
||||
{
|
||||
m_allowedDnsModel->updateModel(m_allowedDnsController->getCurrentDnsServers());
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef ALLOWEDDNSUICONTROLLER_H
|
||||
#define ALLOWEDDNSUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/controllers/allowedDnsController.h"
|
||||
#include "ui/models/allowedDnsModel.h"
|
||||
|
||||
class AllowedDnsUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AllowedDnsUiController(AllowedDnsController* allowedDnsController,
|
||||
AllowedDnsModel* allowedDnsModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addDns(QString ip);
|
||||
void removeDns(int index);
|
||||
|
||||
void importDns(const QString &fileName, bool replaceExisting);
|
||||
void exportDns(const QString &fileName);
|
||||
|
||||
void updateModel();
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
AllowedDnsController* m_allowedDnsController;
|
||||
AllowedDnsModel* m_allowedDnsModel;
|
||||
};
|
||||
|
||||
#endif // ALLOWEDDNSUICONTROLLER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
#ifndef APICONFIGSCONTROLLER_H
|
||||
#define APICONFIGSCONTROLLER_H
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
#include "ui/models/api/apiBenefitsModel.h"
|
||||
#include "ui/models/api/apiServicesModel.h"
|
||||
#include "ui/models/api/apiSubscriptionPlansModel.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
class ApiConfigsController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ApiConfigsController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ApiServicesModel> &apiServicesModel,
|
||||
const QSharedPointer<ApiSubscriptionPlansModel> &subscriptionPlansModel,
|
||||
const QSharedPointer<ApiBenefitsModel> &benefitsModel, const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY vpnKeyExportReady)
|
||||
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY vpnKeyExportReady)
|
||||
Q_PROPERTY(QString vpnKey READ getVpnKey NOTIFY vpnKeyExportReady)
|
||||
|
||||
public slots:
|
||||
bool exportNativeConfig(const QString &serverCountryCode, const QString &fileName);
|
||||
bool revokeNativeConfig(const QString &serverCountryCode);
|
||||
bool exportVpnKey(const QString &fileName);
|
||||
void prepareVpnKeyExport();
|
||||
void copyVpnKeyToClipboard();
|
||||
|
||||
bool fillAvailableServices();
|
||||
bool importService();
|
||||
bool importPremiumFromAppStore(const QString &storeProductId);
|
||||
bool restoreServiceFromAppStore();
|
||||
bool importFreeFromGateway();
|
||||
bool importTrialFromGateway(const QString &email);
|
||||
bool updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||
bool reloadServiceConfig = false);
|
||||
bool updateServiceFromTelegram(const int serverIndex);
|
||||
bool deactivateDevice(const bool isRemoveEvent);
|
||||
bool deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode);
|
||||
|
||||
bool isConfigValid();
|
||||
|
||||
void setCurrentProtocol(const QString &protocolName);
|
||||
bool isVlessProtocol();
|
||||
|
||||
signals:
|
||||
void errorOccurred(ErrorCode errorCode);
|
||||
void trialEmailError(const QString &message);
|
||||
void subscriptionExpiredOnServer();
|
||||
void subscriptionRefreshNeeded();
|
||||
|
||||
void installServerFromApiFinished(const QString &message, int preferredDefaultServerIndex = -1);
|
||||
void changeApiCountryFinished(const QString &message);
|
||||
void reloadServerFromApiFinished(const QString &message);
|
||||
void updateServerFromApiFinished();
|
||||
|
||||
void vpnKeyExportReady();
|
||||
|
||||
private:
|
||||
QList<QString> getQrCodes();
|
||||
int getQrCodesCount();
|
||||
QString getVpnKey();
|
||||
|
||||
ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody, bool isTestPurchase = false);
|
||||
ErrorCode importServiceFromBilling(const QByteArray &responseBody, const bool isTestPurchase, int &duplicateServerIndex);
|
||||
|
||||
QList<QString> m_qrCodes;
|
||||
QString m_vpnKey;
|
||||
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ApiServicesModel> m_apiServicesModel;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QSharedPointer<ApiSubscriptionPlansModel> m_subscriptionPlansModel;
|
||||
QSharedPointer<ApiBenefitsModel> m_benefitsModel;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "apiNewsController.h"
|
||||
|
||||
#include "core/api/apiUtils.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
}
|
||||
}
|
||||
|
||||
ApiNewsController::ApiNewsController(const QSharedPointer<NewsModel> &newsModel, const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<ServersModel> &serversModel, QObject *parent)
|
||||
: QObject(parent), m_newsModel(newsModel), m_settings(settings), m_serversModel(serversModel)
|
||||
{
|
||||
}
|
||||
|
||||
void ApiNewsController::fetchNews(bool showError)
|
||||
{
|
||||
if (m_serversModel.isNull()) {
|
||||
qWarning() << "ServersModel is null, skip fetchNews";
|
||||
return;
|
||||
}
|
||||
const auto stacks = m_serversModel->gatewayStacks();
|
||||
if (stacks.isEmpty()) {
|
||||
qDebug() << "No Gateway stacks, skip fetchNews";
|
||||
return;
|
||||
}
|
||||
|
||||
auto gatewayController = QSharedPointer<GatewayController>::create(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(),
|
||||
apiDefs::requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled());
|
||||
QJsonObject payload;
|
||||
payload.insert("locale", m_settings->getAppLanguage().name().split("_").first());
|
||||
|
||||
const QJsonObject stacksJson = stacks.toJson();
|
||||
if (stacksJson.contains(configKey::userCountryCode)) {
|
||||
payload.insert(configKey::userCountryCode, stacksJson.value(configKey::userCountryCode));
|
||||
}
|
||||
if (stacksJson.contains(configKey::serviceType)) {
|
||||
payload.insert(configKey::serviceType, stacksJson.value(configKey::serviceType));
|
||||
}
|
||||
|
||||
auto future = gatewayController->postAsync(QString("%1v1/news"), payload);
|
||||
future.then(this, [this, showError, gatewayController](QPair<ErrorCode, QByteArray> result) {
|
||||
auto [errorCode, responseBody] = result;
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode, showError);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(responseBody);
|
||||
QJsonArray newsArray;
|
||||
if (doc.isArray()) {
|
||||
newsArray = doc.array();
|
||||
} else if (doc.isObject()) {
|
||||
QJsonObject obj = doc.object();
|
||||
if (obj.value("news").isArray()) {
|
||||
newsArray = obj.value("news").toArray();
|
||||
}
|
||||
}
|
||||
|
||||
m_newsModel->updateModel(newsArray);
|
||||
emit fetchNewsFinished();
|
||||
});
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef APINEWSCONTROLLER_H
|
||||
#define APINEWSCONTROLLER_H
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <memory>
|
||||
|
||||
#include "core/api/apiDefs.h"
|
||||
#include "core/controllers/gatewayController.h"
|
||||
#include "settings.h"
|
||||
#include "ui/models/newsModel.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
class ApiNewsController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ApiNewsController(const QSharedPointer<NewsModel> &newsModel, const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<ServersModel> &serversModel, QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void fetchNews(bool showError);
|
||||
|
||||
signals:
|
||||
void errorOccurred(ErrorCode errorCode, bool showError);
|
||||
void fetchNewsFinished();
|
||||
|
||||
private:
|
||||
QSharedPointer<NewsModel> m_newsModel;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
};
|
||||
|
||||
#endif // APINEWSCONTROLLER_H
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "apiNewsUiController.h"
|
||||
|
||||
ApiNewsUiController::ApiNewsUiController(NewsModel* newsModel,
|
||||
NewsController* newsController,
|
||||
QObject *parent)
|
||||
: QObject(parent), m_newsModel(newsModel), m_newsController(newsController)
|
||||
{
|
||||
}
|
||||
|
||||
void ApiNewsUiController::fetchNews(bool showError)
|
||||
{
|
||||
if (!m_newsController) {
|
||||
qWarning() << "NewsController is null, skip fetchNews";
|
||||
return;
|
||||
}
|
||||
|
||||
auto future = m_newsController->fetchNews();
|
||||
future.then(this, [this, showError](QPair<ErrorCode, QJsonArray> result) {
|
||||
auto [errorCode, newsArray] = result;
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode, showError);
|
||||
return;
|
||||
}
|
||||
|
||||
m_newsModel->updateModel(newsArray);
|
||||
emit fetchNewsFinished();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef APINEWSUICONTROLLER_H
|
||||
#define APINEWSUICONTROLLER_H
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QObject>
|
||||
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "core/controllers/api/newsController.h"
|
||||
#include "ui/models/newsModel.h"
|
||||
|
||||
class ApiNewsUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ApiNewsUiController(NewsModel* newsModel,
|
||||
NewsController* newsController,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void fetchNews(bool showError);
|
||||
|
||||
signals:
|
||||
void errorOccurred(ErrorCode errorCode, bool showError);
|
||||
void fetchNewsFinished();
|
||||
|
||||
private:
|
||||
NewsModel* m_newsModel;
|
||||
NewsController* m_newsController;
|
||||
};
|
||||
|
||||
#endif // APINEWSUICONTROLLER_H
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "apiSettingsController.h"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QJsonDocument>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/api/apiUtils.h"
|
||||
#include "core/controllers/gatewayController.h"
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
|
||||
constexpr char apiConfig[] = "api_config";
|
||||
constexpr char authData[] = "auth_data";
|
||||
}
|
||||
|
||||
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
|
||||
|
||||
QString getSubscriptionStatusForRenewal(const QSharedPointer<ApiAccountInfoModel> &accountInfoModel)
|
||||
{
|
||||
if (!accountInfoModel.isNull() && accountInfoModel->data(QStringLiteral("isSubscriptionExpired")).toBool()) {
|
||||
return QStringLiteral("expired");
|
||||
}
|
||||
|
||||
if (!accountInfoModel.isNull() && accountInfoModel->data(QStringLiteral("isSubscriptionExpiringSoon")).toBool()) {
|
||||
return QStringLiteral("expire_soon");
|
||||
}
|
||||
|
||||
return QStringLiteral("active");
|
||||
}
|
||||
}
|
||||
|
||||
ApiSettingsController::ApiSettingsController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ApiAccountInfoModel> &apiAccountInfoModel,
|
||||
const QSharedPointer<ApiCountryModel> &apiCountryModel,
|
||||
const QSharedPointer<ApiDevicesModel> &apiDevicesModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_serversModel(serversModel),
|
||||
m_apiAccountInfoModel(apiAccountInfoModel),
|
||||
m_apiCountryModel(apiCountryModel),
|
||||
m_apiDevicesModel(apiDevicesModel),
|
||||
m_settings(settings)
|
||||
{
|
||||
}
|
||||
|
||||
ApiSettingsController::~ApiSettingsController()
|
||||
{
|
||||
}
|
||||
|
||||
bool ApiSettingsController::getAccountInfo(bool reload)
|
||||
{
|
||||
if (reload) {
|
||||
QEventLoop wait;
|
||||
QTimer::singleShot(1000, &wait, &QEventLoop::quit);
|
||||
wait.exec(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
|
||||
auto processedIndex = m_serversModel->getProcessedServerIndex();
|
||||
auto serverConfig = m_serversModel->getServerConfig(processedIndex);
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
auto authData = serverConfig.value(configKey::authData).toObject();
|
||||
|
||||
bool isTestPurchase = apiConfig.value(apiDefs::key::isTestPurchase).toBool(false);
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(isTestPurchase), m_settings->isDevGatewayEnv(isTestPurchase),
|
||||
requestTimeoutMsecs, m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
QJsonObject apiPayload;
|
||||
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
|
||||
apiPayload[configKey::serviceType] = apiConfig.value(configKey::serviceType).toString();
|
||||
apiPayload[configKey::authData] = authData;
|
||||
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||
apiPayload[apiDefs::key::appLanguage] = m_settings->getAppLanguage().name().split("_").first();
|
||||
|
||||
QByteArray responseBody;
|
||||
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject accountInfo = QJsonDocument::fromJson(responseBody).object();
|
||||
m_apiAccountInfoModel->updateModel(accountInfo, serverConfig);
|
||||
|
||||
if (reload) {
|
||||
updateApiCountryModel();
|
||||
updateApiDevicesModel();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApiSettingsController::getRenewalLink()
|
||||
{
|
||||
auto processedIndex = m_serversModel->getProcessedServerIndex();
|
||||
auto serverConfig = m_serversModel->getServerConfig(processedIndex);
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
auto authData = serverConfig.value(configKey::authData).toObject();
|
||||
|
||||
bool isTestPurchase = apiConfig.value(apiDefs::key::isTestPurchase).toBool(false);
|
||||
auto gatewayController = QSharedPointer<GatewayController>::create(m_settings->getGatewayEndpoint(isTestPurchase),
|
||||
m_settings->isDevGatewayEnv(isTestPurchase),
|
||||
requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
QJsonObject apiPayload;
|
||||
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
|
||||
apiPayload[configKey::serviceType] = apiConfig.value(configKey::serviceType).toString();
|
||||
apiPayload[configKey::authData] = authData;
|
||||
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
|
||||
apiPayload[apiDefs::key::appLanguage] = m_settings->getAppLanguage().name().split("_").first();
|
||||
apiPayload[apiDefs::key::subscriptionStatus] = getSubscriptionStatusForRenewal(m_apiAccountInfoModel);
|
||||
|
||||
auto future = gatewayController->postAsync(QString("%1v1/renewal_link"), apiPayload);
|
||||
future.then(this, [this, gatewayController](QPair<ErrorCode, QByteArray> result) {
|
||||
auto [errorCode, responseBody] = result;
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject responseJson = QJsonDocument::fromJson(responseBody).object();
|
||||
QString url = responseJson.value("renewal_url").toString();
|
||||
if (!url.isEmpty()) {
|
||||
emit renewalLinkReceived(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ApiSettingsController::updateApiCountryModel()
|
||||
{
|
||||
m_apiCountryModel->updateModel(m_apiAccountInfoModel->getAvailableCountries(), "");
|
||||
m_apiCountryModel->updateIssuedConfigsInfo(m_apiAccountInfoModel->getIssuedConfigsInfo());
|
||||
}
|
||||
|
||||
void ApiSettingsController::updateApiDevicesModel()
|
||||
{
|
||||
m_apiDevicesModel->updateModel(m_apiAccountInfoModel->getIssuedConfigsInfo());
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#ifndef APISETTINGSCONTROLLER_H
|
||||
#define APISETTINGSCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "ui/models/api/apiAccountInfoModel.h"
|
||||
#include "ui/models/api/apiCountryModel.h"
|
||||
#include "ui/models/api/apiDevicesModel.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
class ApiSettingsController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ApiSettingsController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ApiAccountInfoModel> &apiAccountInfoModel,
|
||||
const QSharedPointer<ApiCountryModel> &apiCountryModel, const QSharedPointer<ApiDevicesModel> &apiDevicesModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
~ApiSettingsController();
|
||||
|
||||
public slots:
|
||||
bool getAccountInfo(bool reload);
|
||||
void updateApiCountryModel();
|
||||
void updateApiDevicesModel();
|
||||
void getRenewalLink();
|
||||
|
||||
signals:
|
||||
void errorOccurred(ErrorCode errorCode);
|
||||
void renewalLinkReceived(const QString &url);
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ApiAccountInfoModel> m_apiAccountInfoModel;
|
||||
QSharedPointer<ApiCountryModel> m_apiCountryModel;
|
||||
QSharedPointer<ApiDevicesModel> m_apiDevicesModel;
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
};
|
||||
|
||||
#endif // APISETTINGSCONTROLLER_H
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "servicesCatalogUiController.h"
|
||||
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
|
||||
ServicesCatalogUiController::ServicesCatalogUiController(ServicesCatalogController* servicesCatalogController,
|
||||
ApiServicesModel* apiServicesModel,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_servicesCatalogController(servicesCatalogController),
|
||||
m_apiServicesModel(apiServicesModel)
|
||||
{
|
||||
}
|
||||
|
||||
bool ServicesCatalogUiController::fillAvailableServices()
|
||||
{
|
||||
QJsonObject servicesData;
|
||||
ErrorCode errorCode = m_servicesCatalogController->fillAvailableServices(servicesData);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_apiServicesModel->updateModel(servicesData);
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonObject ServicesCatalogUiController::getSelectedServiceInfo()
|
||||
{
|
||||
return m_apiServicesModel->getSelectedServiceInfo();
|
||||
}
|
||||
|
||||
QString ServicesCatalogUiController::getSelectedServiceType()
|
||||
{
|
||||
return m_apiServicesModel->getSelectedServiceType();
|
||||
}
|
||||
|
||||
QString ServicesCatalogUiController::getSelectedServiceProtocol()
|
||||
{
|
||||
return m_apiServicesModel->getSelectedServiceProtocol();
|
||||
}
|
||||
|
||||
QString ServicesCatalogUiController::getSelectedServiceName()
|
||||
{
|
||||
return m_apiServicesModel->getSelectedServiceName();
|
||||
}
|
||||
|
||||
QJsonArray ServicesCatalogUiController::getSelectedServiceCountries()
|
||||
{
|
||||
return m_apiServicesModel->getSelectedServiceCountries();
|
||||
}
|
||||
|
||||
QString ServicesCatalogUiController::getCountryCode()
|
||||
{
|
||||
return m_apiServicesModel->getCountryCode();
|
||||
}
|
||||
|
||||
QString ServicesCatalogUiController::getStoreEndpoint()
|
||||
{
|
||||
return m_apiServicesModel->getStoreEndpoint();
|
||||
}
|
||||
|
||||
QVariant ServicesCatalogUiController::getSelectedServiceData(const QString &roleString)
|
||||
{
|
||||
return m_apiServicesModel->getSelectedServiceData(roleString);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef SERVICESCATALOGUICONTROLLER_H
|
||||
#define SERVICESCATALOGUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "core/controllers/api/servicesCatalogController.h"
|
||||
#include "ui/models/api/apiServicesModel.h"
|
||||
|
||||
class ServicesCatalogUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ServicesCatalogUiController(ServicesCatalogController* servicesCatalogController,
|
||||
ApiServicesModel* apiServicesModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
bool fillAvailableServices();
|
||||
|
||||
QJsonObject getSelectedServiceInfo();
|
||||
QString getSelectedServiceType();
|
||||
QString getSelectedServiceProtocol();
|
||||
QString getSelectedServiceName();
|
||||
QJsonArray getSelectedServiceCountries();
|
||||
QString getCountryCode();
|
||||
QString getStoreEndpoint();
|
||||
QVariant getSelectedServiceData(const QString &roleString);
|
||||
|
||||
signals:
|
||||
void errorOccurred(ErrorCode errorCode);
|
||||
|
||||
private:
|
||||
ServicesCatalogController* m_servicesCatalogController;
|
||||
ApiServicesModel* m_apiServicesModel;
|
||||
};
|
||||
|
||||
#endif // SERVICESCATALOGUICONTROLLER_H
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
#include "subscriptionUiController.h"
|
||||
|
||||
#include "amneziaApplication.h"
|
||||
#include "core/configurators/wireguardConfigurator.h"
|
||||
#include "core/utils/api/apiEnums.h"
|
||||
#include "core/utils/constants/apiKeys.h"
|
||||
#include "core/utils/constants/apiConstants.h"
|
||||
#include "core/utils/api/apiUtils.h"
|
||||
#include "core/utils/qrCodeUtils.h"
|
||||
#include "ui/controllers/systemController.h"
|
||||
#include "version.h"
|
||||
#include "core/models/serverConfig.h"
|
||||
#include <QClipboard>
|
||||
#include <QDebug>
|
||||
#include <QSet>
|
||||
#include <QEventLoop>
|
||||
#include <QFutureWatcher>
|
||||
#include <QTimer>
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char awg[] = "awg";
|
||||
constexpr char vless[] = "vless";
|
||||
|
||||
constexpr char apiEndpoint[] = "api_endpoint";
|
||||
constexpr char accessToken[] = "api_key";
|
||||
constexpr char certificate[] = "certificate";
|
||||
constexpr char publicKey[] = "public_key";
|
||||
constexpr char protocol[] = "protocol";
|
||||
|
||||
constexpr char uuid[] = "installation_uuid";
|
||||
constexpr char osVersion[] = "os_version";
|
||||
constexpr char appVersion[] = "app_version";
|
||||
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
|
||||
constexpr char apiPayload[] = "api_payload";
|
||||
constexpr char keyPayload[] = "key_payload";
|
||||
|
||||
constexpr char apiConfig[] = "api_config";
|
||||
constexpr char authData[] = "auth_data";
|
||||
|
||||
constexpr char config[] = "config";
|
||||
|
||||
constexpr char subscription[] = "subscription";
|
||||
constexpr char endDate[] = "end_date";
|
||||
|
||||
constexpr char isConnectEvent[] = "is_connect_event";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SubscriptionUiController::SubscriptionUiController(ServersController* serversController,
|
||||
ApiServicesModel* apiServicesModel,
|
||||
ServicesCatalogController* servicesCatalogController,
|
||||
SubscriptionController* subscriptionController,
|
||||
ApiSubscriptionPlansModel* apiSubscriptionPlansModel,
|
||||
ApiBenefitsModel* apiBenefitsModel,
|
||||
ApiAccountInfoModel* apiAccountInfoModel,
|
||||
ApiCountryModel* apiCountryModel,
|
||||
ApiDevicesModel* apiDevicesModel,
|
||||
SettingsController* settingsController,
|
||||
QObject *parent)
|
||||
: QObject(parent), m_serversController(serversController), m_apiServicesModel(apiServicesModel), m_servicesCatalogController(servicesCatalogController), m_subscriptionController(subscriptionController), m_apiSubscriptionPlansModel(apiSubscriptionPlansModel), m_apiBenefitsModel(apiBenefitsModel), m_apiAccountInfoModel(apiAccountInfoModel), m_apiCountryModel(apiCountryModel), m_apiDevicesModel(apiDevicesModel), m_settingsController(settingsController)
|
||||
{
|
||||
connect(m_apiServicesModel, &ApiServicesModel::serviceSelectionChanged, this, [this]() {
|
||||
ApiServicesModel::ApiServicesData selectedServiceData = m_apiServicesModel->selectedServiceData();
|
||||
m_apiSubscriptionPlansModel->updateModel(selectedServiceData.subscriptionPlansJson);
|
||||
m_apiBenefitsModel->updateModel(selectedServiceData.benefits);
|
||||
});
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::exportVpnKey(int serverIndex, const QString &fileName)
|
||||
{
|
||||
if (fileName.isEmpty()) {
|
||||
emit errorOccurred(ErrorCode::PermissionsError);
|
||||
return false;
|
||||
}
|
||||
|
||||
prepareVpnKeyExport(serverIndex);
|
||||
if (m_vpnKey.isEmpty()) {
|
||||
emit errorOccurred(ErrorCode::ApiConfigEmptyError);
|
||||
return false;
|
||||
}
|
||||
|
||||
SystemController::saveFile(fileName, m_vpnKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::exportNativeConfig(int serverIndex, const QString &serverCountryCode, const QString &fileName)
|
||||
{
|
||||
if (fileName.isEmpty()) {
|
||||
emit errorOccurred(ErrorCode::PermissionsError);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString nativeConfig;
|
||||
ErrorCode errorCode = m_subscriptionController->exportNativeConfig(serverIndex, serverCountryCode, nativeConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
SystemController::saveFile(fileName, nativeConfig);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::revokeNativeConfig(int serverIndex, const QString &serverCountryCode)
|
||||
{
|
||||
ErrorCode errorCode = m_subscriptionController->revokeNativeConfig(serverIndex, serverCountryCode);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SubscriptionUiController::prepareVpnKeyExport(int serverIndex)
|
||||
{
|
||||
QString vpnKey;
|
||||
ErrorCode errorCode = m_subscriptionController->prepareVpnKeyExport(serverIndex, vpnKey);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
m_vpnKey = vpnKey;
|
||||
|
||||
QString vpnKeyForQr = vpnKey;
|
||||
vpnKeyForQr.replace("vpn://", "");
|
||||
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(vpnKeyForQr.toUtf8());
|
||||
|
||||
emit vpnKeyExportReady();
|
||||
}
|
||||
|
||||
void SubscriptionUiController::copyVpnKeyToClipboard()
|
||||
{
|
||||
auto clipboard = amnApp->getClipboard();
|
||||
clipboard->setText(m_vpnKey);
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::fillAvailableServices()
|
||||
{
|
||||
QJsonObject servicesData;
|
||||
ErrorCode errorCode = m_servicesCatalogController->fillAvailableServices(servicesData);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_apiServicesModel->updateModel(servicesData);
|
||||
if (m_apiServicesModel->rowCount() > 0) {
|
||||
m_apiServicesModel->setServiceIndex(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::importPremiumFromAppStore(const QString &storeProductId)
|
||||
{
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
QString productId = storeProductId.trimmed();
|
||||
if (productId.isEmpty()) {
|
||||
productId = QStringLiteral("amnezia_premium_6_month");
|
||||
}
|
||||
|
||||
ServerConfig serverConfig;
|
||||
int duplicateServerIndex = -1;
|
||||
ErrorCode errorCode = m_subscriptionController->processAppStorePurchase(
|
||||
m_apiServicesModel->getCountryCode(),
|
||||
m_apiServicesModel->getSelectedServiceType(),
|
||||
m_apiServicesModel->getSelectedServiceProtocol(),
|
||||
productId,
|
||||
serverConfig,
|
||||
&duplicateServerIndex);
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
if (errorCode == ErrorCode::ApiConfigAlreadyAdded) {
|
||||
emit installServerFromApiFinished(tr("This subscription has already been added"), duplicateServerIndex);
|
||||
return true;
|
||||
}
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
emit installServerFromApiFinished(tr("%1 has been added to the app").arg(m_apiServicesModel->getSelectedServiceName()));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::restoreServiceFromAppStore()
|
||||
{
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
const QString premiumServiceType = QStringLiteral("amnezia-premium");
|
||||
|
||||
if (!fillAvailableServices()) {
|
||||
qWarning().noquote() << "[IAP] Unable to fetch services list before restore";
|
||||
emit errorOccurred(ErrorCode::ApiServicesMissingError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_apiServicesModel->rowCount() <= 0) {
|
||||
emit errorOccurred(ErrorCode::ApiServicesMissingError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we have a valid premium selection for gateway requests
|
||||
bool premiumSelected = false;
|
||||
for (int i = 0; i < m_apiServicesModel->rowCount(); ++i) {
|
||||
m_apiServicesModel->setServiceIndex(i);
|
||||
if (m_apiServicesModel->getSelectedServiceType() == premiumServiceType) {
|
||||
premiumSelected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!premiumSelected) {
|
||||
emit errorOccurred(ErrorCode::ApiServicesMissingError);
|
||||
return false;
|
||||
}
|
||||
|
||||
SubscriptionController::AppStoreRestoreResult result = m_subscriptionController->processAppStoreRestore(
|
||||
m_apiServicesModel->getCountryCode(),
|
||||
m_apiServicesModel->getSelectedServiceType(),
|
||||
m_apiServicesModel->getSelectedServiceProtocol());
|
||||
|
||||
if (!result.hasInstalledConfig) {
|
||||
if (result.duplicateConfigAlreadyPresent) {
|
||||
emit installServerFromApiFinished(tr("This subscription has already been added"), result.duplicateServerIndex);
|
||||
return true;
|
||||
}
|
||||
emit errorOccurred(result.errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
emit installServerFromApiFinished(tr("Subscription restored successfully."));
|
||||
if (result.duplicateCount > 0) {
|
||||
qInfo().noquote() << "[IAP] Skipped" << result.duplicateCount
|
||||
<< "duplicate restored transactions for original transaction IDs already processed";
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::importFreeFromGateway()
|
||||
{
|
||||
QString userCountryCode = m_apiServicesModel->getCountryCode();
|
||||
QString serviceType = m_apiServicesModel->getSelectedServiceType();
|
||||
QString serviceProtocol = m_apiServicesModel->getSelectedServiceProtocol();
|
||||
|
||||
if (m_serversController->isServerFromApiAlreadyExists(userCountryCode, serviceType, serviceProtocol)) {
|
||||
emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded);
|
||||
return false;
|
||||
}
|
||||
|
||||
SubscriptionController::ProtocolData protocolData = m_subscriptionController->generateProtocolData(serviceProtocol);
|
||||
|
||||
ServerConfig serverConfig;
|
||||
ErrorCode errorCode = m_subscriptionController->importServiceFromGateway(userCountryCode, serviceType,
|
||||
serviceProtocol, protocolData,
|
||||
serverConfig);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
emit installServerFromApiFinished(tr("%1 installed successfully.").arg(m_apiServicesModel->getSelectedServiceName()));
|
||||
return true;
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::importTrialFromGateway(const QString &email)
|
||||
{
|
||||
emit trialEmailError(QString());
|
||||
ServerConfig serverConfig;
|
||||
ErrorCode errorCode = m_subscriptionController->importTrialFromGateway(m_apiServicesModel->getCountryCode(),
|
||||
m_apiServicesModel->getSelectedServiceType(),
|
||||
m_apiServicesModel->getSelectedServiceProtocol(),
|
||||
email,
|
||||
serverConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
if (errorCode == ErrorCode::ApiTrialAlreadyUsedError) {
|
||||
emit trialEmailError(
|
||||
tr("This email address has already been used to activate a trial. If you like the service, you can upgrade to Premium"));
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
emit installServerFromApiFinished(tr("%1 installed successfully.").arg(m_apiServicesModel->getSelectedServiceName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||
bool reloadServiceConfig)
|
||||
{
|
||||
bool isConnectEvent = newCountryCode.isEmpty() && newCountryName.isEmpty() && !reloadServiceConfig;
|
||||
bool wasSubscriptionExpired = false;
|
||||
ServerConfig oldServerConfig = m_serversController->getServerConfig(serverIndex);
|
||||
if (oldServerConfig.isApiV2()) {
|
||||
const ApiV2ServerConfig *oldApiV2 = oldServerConfig.as<ApiV2ServerConfig>();
|
||||
if (oldApiV2) {
|
||||
wasSubscriptionExpired = oldApiV2->apiConfig.isSubscriptionExpired();
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode errorCode = m_subscriptionController->updateServiceFromGateway(serverIndex, newCountryCode, isConnectEvent);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
if (wasSubscriptionExpired) {
|
||||
emit subscriptionRefreshNeeded();
|
||||
}
|
||||
if (reloadServiceConfig) {
|
||||
emit reloadServerFromApiFinished(tr("API config reloaded"));
|
||||
} else if (newCountryName.isEmpty()) {
|
||||
emit updateServerFromApiFinished();
|
||||
} else {
|
||||
emit changeApiCountryFinished(tr("Successfully changed the country of connection to %1").arg(newCountryName));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (errorCode == ErrorCode::ApiSubscriptionExpiredError) {
|
||||
emit subscriptionExpiredOnServer();
|
||||
}
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::updateServiceFromTelegram(const int serverIndex)
|
||||
{
|
||||
#ifdef Q_OS_IOS
|
||||
IosController::Instance()->requestInetAccess();
|
||||
QThread::msleep(10);
|
||||
#endif
|
||||
|
||||
ErrorCode errorCode = m_subscriptionController->updateServiceFromTelegram(serverIndex);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
emit updateServerFromApiFinished();
|
||||
return true;
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::deactivateDevice(int serverIndex, const bool isRemoveEvent)
|
||||
{
|
||||
|
||||
ErrorCode errorCode = m_subscriptionController->deactivateDevice(serverIndex, isRemoveEvent);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
if (errorCode == ErrorCode::ApiSubscriptionExpiredError && isRemoveEvent) {
|
||||
return true;
|
||||
}
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::deactivateExternalDevice(int serverIndex, const QString &uuid, const QString &serverCountryCode)
|
||||
{
|
||||
ErrorCode errorCode = m_subscriptionController->deactivateExternalDevice(serverIndex, uuid, serverCountryCode);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SubscriptionUiController::validateConfig()
|
||||
{
|
||||
int serverIndex = m_serversController->getDefaultServerIndex();
|
||||
bool hasInstalledContainers = m_serversController->hasInstalledContainers(serverIndex);
|
||||
|
||||
ErrorCode errorCode = m_subscriptionController->validateAndUpdateConfig(serverIndex, hasInstalledContainers);
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
emit configValidated(false);
|
||||
return;
|
||||
}
|
||||
emit configValidated(true);
|
||||
}
|
||||
|
||||
void SubscriptionUiController::setCurrentProtocol(int serverIndex, const QString &protocolName)
|
||||
{
|
||||
m_subscriptionController->setCurrentProtocol(serverIndex, protocolName);
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::isVlessProtocol(int serverIndex)
|
||||
{
|
||||
return m_subscriptionController->isVlessProtocol(serverIndex);
|
||||
}
|
||||
|
||||
void SubscriptionUiController::removeApiConfig(int serverIndex)
|
||||
{
|
||||
m_subscriptionController->removeApiConfig(serverIndex);
|
||||
emit apiConfigRemoved(tr("Api config removed"));
|
||||
}
|
||||
|
||||
QList<QString> SubscriptionUiController::getQrCodes()
|
||||
{
|
||||
return m_qrCodes;
|
||||
}
|
||||
|
||||
int SubscriptionUiController::getQrCodesCount()
|
||||
{
|
||||
return static_cast<int>(m_qrCodes.size());
|
||||
}
|
||||
|
||||
QString SubscriptionUiController::getVpnKey()
|
||||
{
|
||||
return m_vpnKey;
|
||||
}
|
||||
|
||||
bool SubscriptionUiController::getAccountInfo(int serverIndex, bool reload)
|
||||
{
|
||||
if (reload) {
|
||||
QEventLoop wait;
|
||||
QTimer::singleShot(1000, &wait, &QEventLoop::quit);
|
||||
wait.exec(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
QJsonObject accountInfo;
|
||||
ErrorCode errorCode = m_subscriptionController->getAccountInfo(serverIndex, accountInfo);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
ServerConfig serverConfig = m_serversController->getServerConfig(serverIndex);
|
||||
QJsonObject serverConfigJson = serverConfig.toJson();
|
||||
m_apiAccountInfoModel->updateModel(accountInfo, serverConfigJson);
|
||||
|
||||
if (reload) {
|
||||
updateApiCountryModel();
|
||||
updateApiDevicesModel();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SubscriptionUiController::updateApiCountryModel()
|
||||
{
|
||||
m_apiCountryModel->updateModel(m_apiAccountInfoModel->getAvailableCountries(), "");
|
||||
m_apiCountryModel->updateIssuedConfigsInfo(m_apiAccountInfoModel->getIssuedConfigsInfo());
|
||||
}
|
||||
|
||||
void SubscriptionUiController::updateApiDevicesModel()
|
||||
{
|
||||
m_apiDevicesModel->updateModel(m_apiAccountInfoModel->getIssuedConfigsInfo(), m_settingsController->getInstallationUuid(false));
|
||||
}
|
||||
|
||||
void SubscriptionUiController::getRenewalLink(int serverIndex)
|
||||
{
|
||||
if (serverIndex < 0) {
|
||||
emit errorOccurred(ErrorCode::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
auto *watcher = new QFutureWatcher<QPair<ErrorCode, QString>>(this);
|
||||
connect(watcher, &QFutureWatcher<QPair<ErrorCode, QString>>::finished, this, [this, watcher]() {
|
||||
const auto [errorCode, url] = watcher->result();
|
||||
watcher->deleteLater();
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
emit renewalLinkReceived(url);
|
||||
});
|
||||
watcher->setFuture(m_subscriptionController->getRenewalLink(serverIndex));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifndef SUBSCRIPTIONUICONTROLLER_H
|
||||
#define SUBSCRIPTIONUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/controllers/serversController.h"
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "core/controllers/api/servicesCatalogController.h"
|
||||
#include "core/controllers/api/subscriptionController.h"
|
||||
#include "ui/models/api/apiSubscriptionPlansModel.h"
|
||||
#include "ui/models/api/apiBenefitsModel.h"
|
||||
#include "ui/models/api/apiServicesModel.h"
|
||||
#include "ui/models/api/apiAccountInfoModel.h"
|
||||
#include "ui/models/api/apiCountryModel.h"
|
||||
#include "ui/models/api/apiDevicesModel.h"
|
||||
class SubscriptionUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SubscriptionUiController(ServersController* serversController,
|
||||
ApiServicesModel* apiServicesModel,
|
||||
ServicesCatalogController* servicesCatalogController,
|
||||
SubscriptionController* subscriptionController,
|
||||
ApiSubscriptionPlansModel* apiSubscriptionPlansModel,
|
||||
ApiBenefitsModel* apiBenefitsModel,
|
||||
ApiAccountInfoModel* apiAccountInfoModel,
|
||||
ApiCountryModel* apiCountryModel,
|
||||
ApiDevicesModel* apiDevicesModel,
|
||||
SettingsController* settingsController,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY vpnKeyExportReady)
|
||||
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY vpnKeyExportReady)
|
||||
Q_PROPERTY(QString vpnKey READ getVpnKey NOTIFY vpnKeyExportReady)
|
||||
|
||||
public slots:
|
||||
bool exportNativeConfig(int serverIndex, const QString &serverCountryCode, const QString &fileName);
|
||||
bool revokeNativeConfig(int serverIndex, const QString &serverCountryCode);
|
||||
bool exportVpnKey(int serverIndex, const QString &fileName);
|
||||
void prepareVpnKeyExport(int serverIndex);
|
||||
void copyVpnKeyToClipboard();
|
||||
|
||||
bool fillAvailableServices();
|
||||
bool importPremiumFromAppStore(const QString &storeProductId);
|
||||
bool importFreeFromGateway();
|
||||
bool restoreServiceFromAppStore();
|
||||
bool importTrialFromGateway(const QString &email);
|
||||
bool updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||
bool reloadServiceConfig = false);
|
||||
bool updateServiceFromTelegram(const int serverIndex);
|
||||
bool deactivateDevice(int serverIndex, const bool isRemoveEvent);
|
||||
bool deactivateExternalDevice(int serverIndex, const QString &uuid, const QString &serverCountryCode);
|
||||
|
||||
void validateConfig();
|
||||
|
||||
void setCurrentProtocol(int serverIndex, const QString &protocolName);
|
||||
bool isVlessProtocol(int serverIndex);
|
||||
|
||||
void removeApiConfig(int serverIndex);
|
||||
|
||||
bool getAccountInfo(int serverIndex, bool reload);
|
||||
void getRenewalLink(int serverIndex);
|
||||
void updateApiCountryModel();
|
||||
void updateApiDevicesModel();
|
||||
|
||||
signals:
|
||||
void configValidated(bool isValid);
|
||||
void errorOccurred(ErrorCode errorCode);
|
||||
void trialEmailError(const QString &message);
|
||||
void subscriptionExpiredOnServer();
|
||||
void renewalLinkReceived(const QString &url);
|
||||
|
||||
void installServerFromApiFinished(const QString &message, int preferredDefaultServerIndex = -1);
|
||||
void changeApiCountryFinished(const QString &message);
|
||||
void reloadServerFromApiFinished(const QString &message);
|
||||
void updateServerFromApiFinished();
|
||||
void subscriptionRefreshNeeded();
|
||||
|
||||
void apiConfigRemoved(const QString &message);
|
||||
|
||||
void vpnKeyExportReady();
|
||||
|
||||
private:
|
||||
QList<QString> getQrCodes();
|
||||
int getQrCodesCount();
|
||||
QString getVpnKey();
|
||||
|
||||
QList<QString> m_qrCodes;
|
||||
QString m_vpnKey;
|
||||
|
||||
ServersController* m_serversController;
|
||||
ApiServicesModel* m_apiServicesModel;
|
||||
ServicesCatalogController* m_servicesCatalogController;
|
||||
SubscriptionController* m_subscriptionController;
|
||||
ApiSubscriptionPlansModel* m_apiSubscriptionPlansModel;
|
||||
ApiBenefitsModel* m_apiBenefitsModel;
|
||||
ApiAccountInfoModel* m_apiAccountInfoModel;
|
||||
ApiCountryModel* m_apiCountryModel;
|
||||
ApiDevicesModel* m_apiDevicesModel;
|
||||
SettingsController* m_settingsController;
|
||||
};
|
||||
|
||||
#endif // SUBSCRIPTIONUICONTROLLER_H
|
||||
@@ -1,49 +0,0 @@
|
||||
#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)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#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
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "appSplitTunnelingUiController.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
|
||||
AppSplitTunnelingUiController::AppSplitTunnelingUiController(AppSplitTunnelingController* appSplitTunnelingController,
|
||||
AppSplitTunnelingModel* appSplitTunnelingModel,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_appSplitTunnelingController(appSplitTunnelingController),
|
||||
m_appSplitTunnelingModel(appSplitTunnelingModel)
|
||||
{
|
||||
m_appSplitTunnelingModel->updateModel(m_appSplitTunnelingController->getApps());
|
||||
}
|
||||
|
||||
void AppSplitTunnelingUiController::addApp(const QString &appPath)
|
||||
{
|
||||
amnezia::InstalledAppInfo appInfo { "", "", appPath };
|
||||
if (!appPath.isEmpty()) {
|
||||
QFileInfo fileInfo(appPath);
|
||||
appInfo.appName = fileInfo.fileName();
|
||||
}
|
||||
|
||||
if (m_appSplitTunnelingController->addApp(appInfo)) {
|
||||
emit finished(tr("Application added: %1").arg(appInfo.appName));
|
||||
} else {
|
||||
emit errorOccurred(tr("The application has already been added"));
|
||||
}
|
||||
}
|
||||
|
||||
void AppSplitTunnelingUiController::addApps(QVector<QPair<QString, QString>> apps)
|
||||
{
|
||||
for (const auto &app : apps) {
|
||||
amnezia::InstalledAppInfo appInfo { app.first, app.second, "" };
|
||||
m_appSplitTunnelingController->addApp(appInfo);
|
||||
}
|
||||
emit finished(tr("The selected applications have been added"));
|
||||
}
|
||||
|
||||
void AppSplitTunnelingUiController::removeApp(const int index)
|
||||
{
|
||||
auto modelIndex = m_appSplitTunnelingModel->index(index);
|
||||
auto appPath = m_appSplitTunnelingModel->data(modelIndex, AppSplitTunnelingModel::Roles::AppPathRole).toString();
|
||||
m_appSplitTunnelingController->removeApp(index);
|
||||
|
||||
QFileInfo fileInfo(appPath);
|
||||
emit finished(tr("Application removed: %1").arg(fileInfo.fileName()));
|
||||
}
|
||||
|
||||
void AppSplitTunnelingUiController::toggleSplitTunneling(bool enabled)
|
||||
{
|
||||
m_appSplitTunnelingController->toggleSplitTunneling(enabled);
|
||||
emit isSplitTunnelingEnabledChanged();
|
||||
}
|
||||
|
||||
void AppSplitTunnelingUiController::setRouteMode(int routeMode)
|
||||
{
|
||||
m_appSplitTunnelingController->setRouteMode(static_cast<amnezia::AppsRouteMode>(routeMode));
|
||||
emit routeModeChanged();
|
||||
}
|
||||
|
||||
int AppSplitTunnelingUiController::getRouteMode() const
|
||||
{
|
||||
return static_cast<int>(m_appSplitTunnelingController->getRouteMode());
|
||||
}
|
||||
|
||||
bool AppSplitTunnelingUiController::isSplitTunnelingEnabled() const
|
||||
{
|
||||
return m_appSplitTunnelingController->isSplitTunnelingEnabled();
|
||||
}
|
||||
|
||||
void AppSplitTunnelingUiController::updateModel()
|
||||
{
|
||||
m_appSplitTunnelingModel->updateModel(m_appSplitTunnelingController->getApps());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef APPSPLITTUNNELINGUICONTROLLER_H
|
||||
#define APPSPLITTUNNELINGUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#include "core/controllers/appSplitTunnelingController.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "ui/models/appSplitTunnelingModel.h"
|
||||
|
||||
class AppSplitTunnelingUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged)
|
||||
Q_PROPERTY(bool isSplitTunnelingEnabled READ isSplitTunnelingEnabled NOTIFY isSplitTunnelingEnabledChanged)
|
||||
|
||||
public:
|
||||
explicit AppSplitTunnelingUiController(AppSplitTunnelingController* appSplitTunnelingController,
|
||||
AppSplitTunnelingModel* appSplitTunnelingModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addApp(const QString &appPath);
|
||||
void addApps(QVector<QPair<QString, QString>> apps);
|
||||
void removeApp(const int index);
|
||||
void toggleSplitTunneling(bool enabled);
|
||||
void setRouteMode(int routeMode);
|
||||
|
||||
int getRouteMode() const;
|
||||
bool isSplitTunnelingEnabled() const;
|
||||
|
||||
void updateModel();
|
||||
|
||||
signals:
|
||||
void routeModeChanged();
|
||||
void isSplitTunnelingEnabledChanged();
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
|
||||
private:
|
||||
AppSplitTunnelingController* m_appSplitTunnelingController;
|
||||
AppSplitTunnelingModel* m_appSplitTunnelingModel;
|
||||
};
|
||||
|
||||
#endif // APPSPLITTUNNELINGUICONTROLLER_H
|
||||
@@ -1,182 +0,0 @@
|
||||
#include "connectionController.h"
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
|
||||
#include "amnezia_application.h"
|
||||
#include "utilities.h"
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "version.h"
|
||||
|
||||
ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
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);
|
||||
connect(this, &ConnectionController::connectToVpn, m_vpnConnection.get(), &VpnConnection::connectToVpn, Qt::QueuedConnection);
|
||||
connect(this, &ConnectionController::disconnectFromVpn, m_vpnConnection.get(), &VpnConnection::disconnectFromVpn, Qt::QueuedConnection);
|
||||
|
||||
connect(this, &ConnectionController::connectButtonClicked, this, &ConnectionController::toggleConnection, Qt::QueuedConnection);
|
||||
|
||||
m_state = Vpn::ConnectionState::Disconnected;
|
||||
}
|
||||
|
||||
void ConnectionController::openConnection()
|
||||
{
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
|
||||
if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
|
||||
{
|
||||
emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int serverIndex = m_serversModel->getDefaultServerIndex();
|
||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
DockerContainer container = qvariant_cast<DockerContainer>(m_serversModel->data(serverIndex, ServersModel::Roles::DefaultContainerRole));
|
||||
|
||||
if (!m_containersModel->isSupportedByCurrentPlatform(container)) {
|
||||
emit connectionErrorOccurred(ErrorCode::NotSupportedOnThisPlatform);
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
|
||||
|
||||
auto dns = m_serversModel->getDnsPair(serverIndex);
|
||||
|
||||
auto vpnConfiguration = vpnConfigurationController.createVpnConfiguration(dns, serverConfig, containerConfig, container);
|
||||
emit connectToVpn(serverIndex, credentials, container, vpnConfiguration);
|
||||
}
|
||||
|
||||
void ConnectionController::closeConnection()
|
||||
{
|
||||
emit disconnectFromVpn();
|
||||
}
|
||||
|
||||
ErrorCode ConnectionController::getLastConnectionError()
|
||||
{
|
||||
return m_vpnConnection->lastError();
|
||||
}
|
||||
|
||||
void ConnectionController::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
{
|
||||
m_state = state;
|
||||
|
||||
m_isConnected = false;
|
||||
m_connectionStateText = tr("Connecting...");
|
||||
switch (state) {
|
||||
case Vpn::ConnectionState::Connected: {
|
||||
amnApp->networkManager()->clearConnectionCache();
|
||||
|
||||
m_isConnectionInProgress = false;
|
||||
m_isConnected = true;
|
||||
m_connectionStateText = tr("Connected");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Connecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Reconnecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Reconnecting...");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Disconnected: {
|
||||
m_isConnectionInProgress = false;
|
||||
m_connectionStateText = tr("Connect");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Disconnecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Disconnecting...");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Preparing: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Preparing...");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Error: {
|
||||
m_isConnectionInProgress = false;
|
||||
m_connectionStateText = tr("Connect");
|
||||
emit connectionErrorOccurred(getLastConnectionError());
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Unknown: {
|
||||
m_isConnectionInProgress = false;
|
||||
m_connectionStateText = tr("Connect");
|
||||
emit connectionErrorOccurred(getLastConnectionError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit connectionStateChanged();
|
||||
}
|
||||
|
||||
void ConnectionController::onCurrentContainerUpdated()
|
||||
{
|
||||
if (m_isConnected || m_isConnectionInProgress) {
|
||||
emit reconnectWithUpdatedContainer(tr("Settings updated successfully, reconnnection..."));
|
||||
openConnection();
|
||||
} else {
|
||||
emit reconnectWithUpdatedContainer(tr("Settings updated successfully"));
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionController::onTranslationsUpdated()
|
||||
{
|
||||
// get translated text of current state
|
||||
onConnectionStateChanged(getCurrentConnectionState());
|
||||
}
|
||||
|
||||
Vpn::ConnectionState ConnectionController::getCurrentConnectionState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
QString ConnectionController::connectionStateText() const
|
||||
{
|
||||
return m_connectionStateText;
|
||||
}
|
||||
|
||||
void ConnectionController::toggleConnection()
|
||||
{
|
||||
if (m_state == Vpn::ConnectionState::Preparing) {
|
||||
emit preparingConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConnectionInProgress()) {
|
||||
closeConnection();
|
||||
} else if (isConnected()) {
|
||||
closeConnection();
|
||||
} else {
|
||||
emit prepareConfig();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConnectionController::isConnectionInProgress() const
|
||||
{
|
||||
return m_isConnectionInProgress;
|
||||
}
|
||||
|
||||
bool ConnectionController::isConnected() const
|
||||
{
|
||||
return m_isConnected;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#ifndef CONNECTIONCONTROLLER_H
|
||||
#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"
|
||||
|
||||
class ConnectionController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_PROPERTY(bool isConnected READ isConnected NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(bool isConnectionInProgress READ isConnectionInProgress NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(QString connectionStateText READ connectionStateText NOTIFY connectionStateChanged)
|
||||
|
||||
explicit ConnectionController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
const QSharedPointer<VpnConnection> &vpnConnection, const std::shared_ptr<Settings> &settings,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
~ConnectionController() = default;
|
||||
|
||||
bool isConnected() const;
|
||||
bool isConnectionInProgress() const;
|
||||
QString connectionStateText() const;
|
||||
|
||||
public slots:
|
||||
void toggleConnection();
|
||||
|
||||
void openConnection();
|
||||
void closeConnection();
|
||||
|
||||
ErrorCode getLastConnectionError();
|
||||
void onConnectionStateChanged(Vpn::ConnectionState state);
|
||||
|
||||
void onCurrentContainerUpdated();
|
||||
|
||||
void onTranslationsUpdated();
|
||||
|
||||
signals:
|
||||
void connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
|
||||
void disconnectFromVpn();
|
||||
void connectionStateChanged();
|
||||
|
||||
void connectionErrorOccurred(ErrorCode errorCode);
|
||||
void reconnectWithUpdatedContainer(const QString &message);
|
||||
|
||||
void connectButtonClicked();
|
||||
void preparingConfig();
|
||||
void prepareConfig();
|
||||
|
||||
private:
|
||||
Vpn::ConnectionState getCurrentConnectionState();
|
||||
|
||||
void continueConnection();
|
||||
|
||||
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");
|
||||
|
||||
Vpn::ConnectionState m_state;
|
||||
};
|
||||
|
||||
#endif // CONNECTIONCONTROLLER_H
|
||||
@@ -0,0 +1,152 @@
|
||||
#include "connectionUiController.h"
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <QGuiApplication>
|
||||
#else
|
||||
#include <QApplication>
|
||||
#endif
|
||||
|
||||
#include "amneziaApplication.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
|
||||
ConnectionUiController::ConnectionUiController(ConnectionController* connectionController,
|
||||
ServersController* serversController,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_connectionController(connectionController),
|
||||
m_serversController(serversController)
|
||||
{
|
||||
connect(m_connectionController, &ConnectionController::connectionStateChanged, this, &ConnectionUiController::onConnectionStateChanged);
|
||||
|
||||
connect(this, &ConnectionUiController::connectButtonClicked, this, &ConnectionUiController::toggleConnection, Qt::QueuedConnection);
|
||||
|
||||
m_state = Vpn::ConnectionState::Disconnected;
|
||||
}
|
||||
|
||||
void ConnectionUiController::openConnection()
|
||||
{
|
||||
int serverIndex = m_serversController->getDefaultServerIndex();
|
||||
|
||||
ErrorCode errorCode = m_connectionController->openConnection(serverIndex);
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit connectionErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionUiController::closeConnection()
|
||||
{
|
||||
m_connectionController->closeConnection();
|
||||
}
|
||||
|
||||
ErrorCode ConnectionUiController::getLastConnectionError()
|
||||
{
|
||||
return m_connectionController->lastConnectionError();
|
||||
}
|
||||
|
||||
void ConnectionUiController::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
{
|
||||
m_state = state;
|
||||
|
||||
m_isConnected = false;
|
||||
m_connectionStateText = tr("Connecting...");
|
||||
switch (state) {
|
||||
case Vpn::ConnectionState::Connected: {
|
||||
amnApp->networkManager()->clearConnectionCache();
|
||||
|
||||
m_isConnectionInProgress = false;
|
||||
m_isConnected = true;
|
||||
m_connectionStateText = tr("Connected");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Connecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Reconnecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Reconnecting...");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Disconnected: {
|
||||
m_isConnectionInProgress = false;
|
||||
m_connectionStateText = tr("Connect");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Disconnecting: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Disconnecting...");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Preparing: {
|
||||
m_isConnectionInProgress = true;
|
||||
m_connectionStateText = tr("Preparing...");
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Error: {
|
||||
m_isConnectionInProgress = false;
|
||||
m_connectionStateText = tr("Connect");
|
||||
emit connectionErrorOccurred(getLastConnectionError());
|
||||
break;
|
||||
}
|
||||
case Vpn::ConnectionState::Unknown: {
|
||||
m_isConnectionInProgress = false;
|
||||
m_connectionStateText = tr("Connect");
|
||||
emit connectionErrorOccurred(getLastConnectionError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit connectionStateChanged();
|
||||
}
|
||||
|
||||
void ConnectionUiController::onCurrentContainerUpdated()
|
||||
{
|
||||
if (m_isConnected || m_isConnectionInProgress) {
|
||||
emit reconnectWithUpdatedContainer(tr("Settings updated successfully, reconnection..."));
|
||||
openConnection();
|
||||
} else {
|
||||
emit reconnectWithUpdatedContainer(tr("Settings updated successfully"));
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionUiController::onTranslationsUpdated()
|
||||
{
|
||||
onConnectionStateChanged(getCurrentConnectionState());
|
||||
}
|
||||
|
||||
Vpn::ConnectionState ConnectionUiController::getCurrentConnectionState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
QString ConnectionUiController::connectionStateText() const
|
||||
{
|
||||
return m_connectionStateText;
|
||||
}
|
||||
|
||||
void ConnectionUiController::toggleConnection()
|
||||
{
|
||||
if (m_state == Vpn::ConnectionState::Preparing) {
|
||||
emit preparingConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConnectionInProgress()) {
|
||||
closeConnection();
|
||||
} else if (isConnected()) {
|
||||
closeConnection();
|
||||
} else {
|
||||
emit prepareConfig();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConnectionUiController::isConnectionInProgress() const
|
||||
{
|
||||
return m_isConnectionInProgress;
|
||||
}
|
||||
|
||||
bool ConnectionUiController::isConnected() const
|
||||
{
|
||||
return m_isConnected;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef CONNECTIONUICONTROLLER_H
|
||||
#define CONNECTIONUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/controllers/connectionController.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "core/protocols/vpnProtocol.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
|
||||
class ConnectionUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_PROPERTY(bool isConnected READ isConnected NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(bool isConnectionInProgress READ isConnectionInProgress NOTIFY connectionStateChanged)
|
||||
Q_PROPERTY(QString connectionStateText READ connectionStateText NOTIFY connectionStateChanged)
|
||||
|
||||
explicit ConnectionUiController(ConnectionController* connectionController,
|
||||
ServersController* serversController,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
~ConnectionUiController() = default;
|
||||
|
||||
bool isConnected() const;
|
||||
bool isConnectionInProgress() const;
|
||||
QString connectionStateText() const;
|
||||
|
||||
public slots:
|
||||
void toggleConnection();
|
||||
|
||||
void openConnection();
|
||||
void closeConnection();
|
||||
|
||||
ErrorCode getLastConnectionError();
|
||||
void onConnectionStateChanged(Vpn::ConnectionState state);
|
||||
|
||||
void onCurrentContainerUpdated();
|
||||
|
||||
void onTranslationsUpdated();
|
||||
|
||||
signals:
|
||||
void connectionStateChanged();
|
||||
|
||||
void connectionErrorOccurred(ErrorCode errorCode);
|
||||
void reconnectWithUpdatedContainer(const QString &message);
|
||||
|
||||
void connectButtonClicked();
|
||||
void preparingConfig();
|
||||
void prepareConfig();
|
||||
|
||||
private:
|
||||
Vpn::ConnectionState getCurrentConnectionState();
|
||||
|
||||
ConnectionController* m_connectionController;
|
||||
ServersController* m_serversController;
|
||||
|
||||
bool m_isConnected = false;
|
||||
bool m_isConnectionInProgress = false;
|
||||
QString m_connectionStateText = tr("Connect");
|
||||
|
||||
Vpn::ConnectionState m_state;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,392 +0,0 @@
|
||||
#include "exportController.h"
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QDataStream>
|
||||
#include <QDesktopServices>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QImage>
|
||||
#include <QStandardPaths>
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "core/qrCodeUtils.h"
|
||||
#include "core/serialization/serialization.h"
|
||||
#include "core/serialization/transfer.h"
|
||||
#include "systemController.h"
|
||||
#include <QDebug>
|
||||
|
||||
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_clientManagementModel(clientManagementModel),
|
||||
m_settings(settings)
|
||||
{
|
||||
}
|
||||
|
||||
void ExportController::generateFullAccessConfig()
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
||||
int serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
|
||||
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());
|
||||
|
||||
for (auto protocol : ContainerProps::protocolsForContainer(containerType)) {
|
||||
auto protocolConfig = containerConfig.value(ProtocolProps::protoToString(protocol)).toObject();
|
||||
|
||||
protocolConfig.remove(config_key::last_config);
|
||||
containerConfig[ProtocolProps::protoToString(protocol)] = protocolConfig;
|
||||
}
|
||||
|
||||
containers.replace(i, containerConfig);
|
||||
}
|
||||
serverConfig[config_key::containers] = containers;
|
||||
|
||||
QByteArray compressedConfig = QJsonDocument(serverConfig).toJson();
|
||||
compressedConfig = qCompress(compressedConfig, 8);
|
||||
m_config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
|
||||
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(compressedConfig);
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateConnectionConfig(const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
||||
int serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
|
||||
|
||||
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
|
||||
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
ErrorCode errorCode = vpnConfigurationController.createProtocolConfigForContainer(credentials, container, containerConfig);
|
||||
|
||||
errorCode = m_clientManagementModel->appendClient(container, credentials, containerConfig, clientName, serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
if (!errorCode) {
|
||||
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_serversModel->getDnsPair(serverIndex);
|
||||
serverConfig.insert(config_key::dns1, dns.first);
|
||||
serverConfig.insert(config_key::dns2, dns.second);
|
||||
}
|
||||
|
||||
QByteArray compressedConfig = QJsonDocument(serverConfig).toJson();
|
||||
compressedConfig = qCompress(compressedConfig, 8);
|
||||
m_config = QString("vpn://%1").arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)));
|
||||
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(compressedConfig);
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
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::IsServerFromTelegramApiRole));
|
||||
|
||||
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
|
||||
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
|
||||
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
VpnConfigurationsController vpnConfigurationController(m_settings, serverController);
|
||||
|
||||
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 || protocol == Proto::Xray) {
|
||||
errorCode = m_clientManagementModel->appendClient(jsonNativeConfig, clientName, container, credentials, serverController);
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
void ExportController::generateOpenVpnConfig(const QString &clientName)
|
||||
{
|
||||
QJsonObject nativeConfig;
|
||||
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
|
||||
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(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
|
||||
for (const QString &line : std::as_const(lines)) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(m_config.toUtf8());
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateWireGuardConfig(const QString &clientName)
|
||||
{
|
||||
QJsonObject nativeConfig;
|
||||
ErrorCode errorCode = generateNativeConfig(DockerContainer::WireGuard, clientName, Proto::WireGuard, nativeConfig);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
|
||||
for (const QString &line : std::as_const(lines)) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(m_config.toUtf8());
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateAwgConfig(const QString &clientName)
|
||||
{
|
||||
QJsonObject nativeConfig;
|
||||
ErrorCode errorCode = generateNativeConfig(static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex()), clientName,
|
||||
Proto::Awg, nativeConfig);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList lines = nativeConfig.value(config_key::config).toString().replace("\r", "").split("\n");
|
||||
for (const QString &line : std::as_const(lines)) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
m_qrCodes = qrCodeUtils::generateQrCodeImageSeries(m_config.toUtf8());
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateShadowSocksConfig()
|
||||
{
|
||||
QJsonObject nativeConfig;
|
||||
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getProcessedContainerIndex());
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
|
||||
if (container == DockerContainer::Cloak) {
|
||||
errorCode = generateNativeConfig(container, "", Proto::ShadowSocks, nativeConfig);
|
||||
} else {
|
||||
errorCode = generateNativeConfig(container, "", ContainerProps::defaultProtocol(container), nativeConfig);
|
||||
}
|
||||
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
|
||||
for (const QString &line : std::as_const(lines)) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
auto qr = qrCodeUtils::generateQrCode(m_nativeConfigString.toUtf8());
|
||||
m_qrCodes << qrCodeUtils::svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateCloakConfig()
|
||||
{
|
||||
QJsonObject nativeConfig;
|
||||
ErrorCode errorCode = generateNativeConfig(DockerContainer::Cloak, "", Proto::Cloak, nativeConfig);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
nativeConfig.remove(config_key::transport_proto);
|
||||
nativeConfig.insert("ProxyMethod", "shadowsocks");
|
||||
|
||||
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
|
||||
for (const QString &line : std::as_const(lines)) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateXrayConfig(const QString &clientName)
|
||||
{
|
||||
// Xray data
|
||||
QJsonObject nativeConfig;
|
||||
ErrorCode errorCode = generateNativeConfig(DockerContainer::Xray, clientName, Proto::Xray, nativeConfig);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList lines = QString(QJsonDocument(nativeConfig).toJson()).replace("\r", "").split("\n");
|
||||
for (const QString &line : std::as_const(lines)) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
// Xray data
|
||||
|
||||
// Parse the Xray data to extract VLESS parameters and generate string
|
||||
QString configString = QString(QJsonDocument(nativeConfig).toJson(QJsonDocument::Compact));
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(configString.toUtf8());
|
||||
if (doc.isNull() || !doc.isObject()) {
|
||||
qDebug() << "ERROR: Failed to parse config JSON";
|
||||
emit exportErrorOccurred(ErrorCode::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject xrayConfig = doc.object();
|
||||
QJsonArray outbounds = xrayConfig.value("outbounds").toArray();
|
||||
|
||||
if (outbounds.isEmpty()) {
|
||||
qDebug() << "ERROR: Outbounds array is empty";
|
||||
emit exportErrorOccurred(ErrorCode::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject outbound = outbounds[0].toObject();
|
||||
QJsonObject settings = outbound.value("settings").toObject();
|
||||
QJsonObject streamSettings = outbound.value("streamSettings").toObject();
|
||||
|
||||
QJsonArray vnext = settings.value("vnext").toArray();
|
||||
if (vnext.isEmpty()) {
|
||||
qDebug() << "ERROR: vnext array is empty";
|
||||
emit exportErrorOccurred(ErrorCode::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject server = vnext[0].toObject();
|
||||
QJsonArray users = server.value("users").toArray();
|
||||
if (users.isEmpty()) {
|
||||
qDebug() << "ERROR: users array is empty";
|
||||
emit exportErrorOccurred(ErrorCode::InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject user = users[0].toObject();
|
||||
|
||||
amnezia::serialization::VlessServerObject vlessServer;
|
||||
vlessServer.address = server.value("address").toString();
|
||||
vlessServer.port = server.value("port").toInt();
|
||||
vlessServer.id = user.value("id").toString();
|
||||
vlessServer.flow = user.value("flow").toString("xtls-rprx-vision");
|
||||
vlessServer.encryption = user.value("encryption").toString("none");
|
||||
|
||||
vlessServer.network = streamSettings.value("network").toString("tcp");
|
||||
vlessServer.security = streamSettings.value("security").toString("reality");
|
||||
|
||||
if (vlessServer.security == "reality") {
|
||||
QJsonObject realitySettings = streamSettings.value("realitySettings").toObject();
|
||||
vlessServer.serverName = realitySettings.value("serverName").toString();
|
||||
vlessServer.publicKey = realitySettings.value("publicKey").toString();
|
||||
vlessServer.shortId = realitySettings.value("shortId").toString();
|
||||
vlessServer.fingerprint = realitySettings.value("fingerprint").toString("chrome");
|
||||
vlessServer.spiderX = realitySettings.value("spiderX").toString("");
|
||||
}
|
||||
|
||||
m_nativeConfigString = amnezia::serialization::vless::Serialize(vlessServer, "AmneziaVPN");
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
QString ExportController::getConfig()
|
||||
{
|
||||
return m_config;
|
||||
}
|
||||
|
||||
QString ExportController::getNativeConfigString()
|
||||
{
|
||||
return m_nativeConfigString;
|
||||
}
|
||||
|
||||
QList<QString> ExportController::getQrCodes()
|
||||
{
|
||||
return m_qrCodes;
|
||||
}
|
||||
|
||||
void ExportController::exportConfig(const QString &fileName)
|
||||
{
|
||||
SystemController::saveFile(fileName, m_config);
|
||||
}
|
||||
|
||||
void ExportController::updateClientManagementModel(const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
ErrorCode errorCode = m_clientManagementModel->updateModel(container, credentials, serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
ErrorCode errorCode =
|
||||
m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex(), serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
}
|
||||
emit revokeConfigCompleted();
|
||||
}
|
||||
|
||||
void ExportController::renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials, serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
int ExportController::getQrCodesCount()
|
||||
{
|
||||
return m_qrCodes.size();
|
||||
}
|
||||
|
||||
void ExportController::clearPreviousConfig()
|
||||
{
|
||||
m_config.clear();
|
||||
m_nativeConfigString.clear();
|
||||
m_qrCodes.clear();
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
#ifndef EXPORTCONTROLLER_H
|
||||
#define EXPORTCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
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,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QList<QString> 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();
|
||||
void generateConnectionConfig(const QString &clientName);
|
||||
void generateOpenVpnConfig(const QString &clientName);
|
||||
void generateWireGuardConfig(const QString &clientName);
|
||||
void generateAwgConfig(const QString &clientName);
|
||||
void generateShadowSocksConfig();
|
||||
void generateCloakConfig();
|
||||
void generateXrayConfig(const QString &clientName);
|
||||
|
||||
QString getConfig();
|
||||
QString getNativeConfigString();
|
||||
QList<QString> getQrCodes();
|
||||
|
||||
void exportConfig(const QString &fileName);
|
||||
|
||||
void updateClientManagementModel(const DockerContainer container, ServerCredentials credentials);
|
||||
void revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials);
|
||||
void renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials);
|
||||
|
||||
signals:
|
||||
void generateConfig(int type);
|
||||
void revokeConfigCompleted();
|
||||
void exportErrorOccurred(const QString &errorMessage);
|
||||
void exportErrorOccurred(ErrorCode errorCode);
|
||||
|
||||
void exportConfigChanged();
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
int getQrCodesCount();
|
||||
|
||||
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;
|
||||
|
||||
QString m_config;
|
||||
QString m_nativeConfigString;
|
||||
QList<QString> m_qrCodes;
|
||||
};
|
||||
|
||||
#endif // EXPORTCONTROLLER_H
|
||||
@@ -1,773 +0,0 @@
|
||||
#include "importController.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QQuickItem>
|
||||
#include <QRandomGenerator>
|
||||
#include <QStandardPaths>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include "core/api/apiDefs.h"
|
||||
#include "core/api/apiUtils.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "core/qrCodeUtils.h"
|
||||
#include "core/serialization/serialization.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
#include "systemController.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
ConfigTypes checkConfigFormat(const QString &config)
|
||||
{
|
||||
const QString openVpnConfigPatternCli = "client";
|
||||
const QString openVpnConfigPatternDriver1 = "dev tun";
|
||||
const QString openVpnConfigPatternDriver2 = "dev tap";
|
||||
|
||||
const QString wireguardConfigPatternSectionInterface = "[Interface]";
|
||||
const QString wireguardConfigPatternSectionPeer = "[Peer]";
|
||||
|
||||
const QString xrayConfigPatternInbound = "inbounds";
|
||||
const QString xrayConfigPatternOutbound = "outbounds";
|
||||
|
||||
const QString amneziaConfigPattern = "containers";
|
||||
const QString amneziaConfigPatternHostName = "hostName";
|
||||
const QString amneziaConfigPatternUserName = "userName";
|
||||
const QString amneziaConfigPatternPassword = "password";
|
||||
const QString amneziaFreeConfigPattern = "api_key";
|
||||
const QString amneziaPremiumConfigPattern = "auth_data";
|
||||
const QString backupPattern = "Servers/serversList";
|
||||
|
||||
if (config.contains(backupPattern)) {
|
||||
return ConfigTypes::Backup;
|
||||
} else if (config.contains(amneziaConfigPattern) || config.contains(amneziaFreeConfigPattern)
|
||||
|| config.contains(amneziaPremiumConfigPattern)
|
||||
|| (config.contains(amneziaConfigPatternHostName) && config.contains(amneziaConfigPatternUserName)
|
||||
&& config.contains(amneziaConfigPatternPassword))) {
|
||||
return ConfigTypes::Amnezia;
|
||||
} else if (config.contains(wireguardConfigPatternSectionInterface) && config.contains(wireguardConfigPatternSectionPeer)) {
|
||||
return ConfigTypes::WireGuard;
|
||||
} else if ((config.contains(xrayConfigPatternInbound)) && (config.contains(xrayConfigPatternOutbound))) {
|
||||
return ConfigTypes::Xray;
|
||||
} else if (config.contains(openVpnConfigPatternCli)
|
||||
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
||||
return ConfigTypes::OpenVpn;
|
||||
}
|
||||
return ConfigTypes::Invalid;
|
||||
}
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
ImportController *mInstance = nullptr;
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
ImportController::ImportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel), m_settings(settings)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
mInstance = this;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ImportController::extractConfigFromFile(const QString &fileName)
|
||||
{
|
||||
QString data;
|
||||
if (!SystemController::readFile(fileName, data)) {
|
||||
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
|
||||
return false;
|
||||
}
|
||||
m_configFileName = QFileInfo(QFile(fileName).fileName()).fileName();
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (m_configFileName.isEmpty()) {
|
||||
m_configFileName = AndroidController::instance()->getFileName(fileName);
|
||||
}
|
||||
#endif
|
||||
return extractConfigFromData(data);
|
||||
}
|
||||
|
||||
bool ImportController::extractConfigFromData(QString data)
|
||||
{
|
||||
m_maliciousWarningText.clear();
|
||||
|
||||
QString config = data;
|
||||
QString prefix;
|
||||
QString errormsg;
|
||||
|
||||
if (config.startsWith("vless://")) {
|
||||
m_configType = ConfigTypes::Xray;
|
||||
m_config = extractXrayConfig(
|
||||
Utils::JsonToString(serialization::vless::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||
prefix);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
|
||||
if (config.startsWith("vmess://") && config.contains("@")) {
|
||||
m_configType = ConfigTypes::Xray;
|
||||
m_config = extractXrayConfig(
|
||||
Utils::JsonToString(serialization::vmess_new::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||
prefix);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
|
||||
if (config.startsWith("vmess://")) {
|
||||
m_configType = ConfigTypes::Xray;
|
||||
m_config = extractXrayConfig(
|
||||
Utils::JsonToString(serialization::vmess::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||
prefix);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
|
||||
if (config.startsWith("trojan://")) {
|
||||
m_configType = ConfigTypes::Xray;
|
||||
m_config = extractXrayConfig(
|
||||
Utils::JsonToString(serialization::trojan::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact),
|
||||
prefix);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
|
||||
if (config.startsWith("ss://") && !config.contains("plugin=")) {
|
||||
m_configType = ConfigTypes::ShadowSocks;
|
||||
m_config = extractXrayConfig(
|
||||
Utils::JsonToString(serialization::ss::Deserialize(config, &prefix, &errormsg), QJsonDocument::JsonFormat::Compact), prefix);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
|
||||
if (config.startsWith("ssd://")) {
|
||||
QStringList tmp;
|
||||
QList<std::pair<QString, QJsonObject>> servers = serialization::ssd::Deserialize(config, &prefix, &tmp);
|
||||
m_configType = ConfigTypes::ShadowSocks;
|
||||
// Took only first config from list
|
||||
if (!servers.isEmpty()) {
|
||||
m_config = extractXrayConfig(servers.first().first);
|
||||
}
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
|
||||
m_configType = checkConfigFormat(config);
|
||||
if (m_configType == ConfigTypes::Invalid) {
|
||||
config.replace("vpn://", "");
|
||||
QByteArray ba = QByteArray::fromBase64(config.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
QByteArray baUncompressed = qUncompress(ba);
|
||||
if (!baUncompressed.isEmpty()) {
|
||||
ba = baUncompressed;
|
||||
}
|
||||
|
||||
config = ba;
|
||||
m_configType = checkConfigFormat(config);
|
||||
}
|
||||
|
||||
switch (m_configType) {
|
||||
case ConfigTypes::OpenVpn: {
|
||||
m_config = extractOpenVpnConfig(config);
|
||||
if (!m_config.empty()) {
|
||||
checkForMaliciousStrings(m_config);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case ConfigTypes::Awg:
|
||||
case ConfigTypes::WireGuard: {
|
||||
m_config = extractWireGuardConfig(config);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
case ConfigTypes::Xray: {
|
||||
m_config = extractXrayConfig(config);
|
||||
return m_config.empty() ? false : true;
|
||||
}
|
||||
case ConfigTypes::Amnezia: {
|
||||
m_config = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||
|
||||
if (apiUtils::isServerFromApi(m_config)) {
|
||||
auto apiConfig = m_config.value(apiDefs::key::apiConfig).toObject();
|
||||
apiConfig[apiDefs::key::vpnKey] = data;
|
||||
m_config[apiDefs::key::apiConfig] = apiConfig;
|
||||
}
|
||||
|
||||
processAmneziaConfig(m_config);
|
||||
if (!m_config.empty()) {
|
||||
checkForMaliciousStrings(m_config);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case ConfigTypes::Backup: {
|
||||
if (!m_serversModel->getServersCount()) {
|
||||
emit restoreAppConfig(config.toUtf8());
|
||||
} else {
|
||||
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConfigTypes::Invalid: {
|
||||
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||
m_configFileName.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImportController::extractConfigFromQr(const QByteArray &data)
|
||||
{
|
||||
m_configType = checkConfigFormat(QString::fromUtf8(data));
|
||||
|
||||
QJsonObject dataObj = QJsonDocument::fromJson(data).object();
|
||||
if (!dataObj.isEmpty()) {
|
||||
m_config = dataObj;
|
||||
return true;
|
||||
}
|
||||
|
||||
QByteArray ba_uncompressed = qUncompress(data);
|
||||
if (!ba_uncompressed.isEmpty()) {
|
||||
m_config = QJsonDocument::fromJson(ba_uncompressed).object();
|
||||
if (m_config.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
m_configType = checkConfigFormat(QString::fromUtf8(ba_uncompressed));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_configType == ConfigTypes::Invalid) {
|
||||
QByteArray ba = QByteArray::fromBase64(data, QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
QByteArray baUncompressed = qUncompress(ba);
|
||||
|
||||
if (!baUncompressed.isEmpty()) {
|
||||
ba = baUncompressed;
|
||||
}
|
||||
|
||||
if (!ba.isEmpty()) {
|
||||
m_config = QJsonDocument::fromJson(ba).object();
|
||||
if (m_config.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
m_configType = checkConfigFormat(QString::fromUtf8(ba));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString ImportController::getConfig()
|
||||
{
|
||||
return QJsonDocument(m_config).toJson(QJsonDocument::Indented);
|
||||
}
|
||||
|
||||
QString ImportController::getConfigFileName()
|
||||
{
|
||||
return m_configFileName;
|
||||
}
|
||||
|
||||
QString ImportController::getMaliciousWarningText()
|
||||
{
|
||||
return m_maliciousWarningText;
|
||||
}
|
||||
|
||||
bool ImportController::isNativeWireGuardConfig()
|
||||
{
|
||||
return m_configType == ConfigTypes::WireGuard;
|
||||
}
|
||||
|
||||
void ImportController::processNativeWireGuardConfig()
|
||||
{
|
||||
auto containers = m_config.value(config_key::containers).toArray();
|
||||
if (!containers.isEmpty()) {
|
||||
auto container = containers.at(0).toObject();
|
||||
auto serverProtocolConfig = container.value(ContainerProps::containerTypeToProtocolString(DockerContainer::WireGuard)).toObject();
|
||||
auto clientProtocolConfig = QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
|
||||
|
||||
QString junkPacketCount = QString::number(QRandomGenerator::global()->bounded(4, 7));
|
||||
QString junkPacketMinSize = QString::number(10);
|
||||
QString junkPacketMaxSize = QString::number(50);
|
||||
clientProtocolConfig[config_key::junkPacketCount] = junkPacketCount;
|
||||
clientProtocolConfig[config_key::junkPacketMinSize] = junkPacketMinSize;
|
||||
clientProtocolConfig[config_key::junkPacketMaxSize] = junkPacketMaxSize;
|
||||
clientProtocolConfig[config_key::initPacketJunkSize] = "0";
|
||||
clientProtocolConfig[config_key::responsePacketJunkSize] = "0";
|
||||
clientProtocolConfig[config_key::initPacketMagicHeader] = "1";
|
||||
clientProtocolConfig[config_key::responsePacketMagicHeader] = "2";
|
||||
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
||||
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
|
||||
|
||||
clientProtocolConfig[config_key::cookieReplyPacketJunkSize] = "0";
|
||||
clientProtocolConfig[config_key::transportPacketJunkSize] = "0";
|
||||
|
||||
clientProtocolConfig[config_key::specialJunk1] = protocols::awg::defaultSpecialJunk1;
|
||||
|
||||
clientProtocolConfig[config_key::isObfuscationEnabled] = true;
|
||||
|
||||
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
|
||||
container["wireguard"] = serverProtocolConfig;
|
||||
containers.replace(0, container);
|
||||
m_config[config_key::containers] = containers;
|
||||
}
|
||||
}
|
||||
|
||||
void ImportController::importConfig()
|
||||
{
|
||||
ServerCredentials credentials;
|
||||
credentials.hostName = m_config.value(config_key::hostName).toString();
|
||||
credentials.port = m_config.value(config_key::port).toInt();
|
||||
credentials.userName = m_config.value(config_key::userName).toString();
|
||||
credentials.secretData = m_config.value(config_key::password).toString();
|
||||
|
||||
if (credentials.isValid() || m_config.contains(config_key::containers)) {
|
||||
m_serversModel->addServer(m_config);
|
||||
emit importFinished();
|
||||
} else if (m_config.contains(config_key::configVersion)) {
|
||||
quint16 crc = qChecksum(QJsonDocument(m_config).toJson());
|
||||
if (m_serversModel->isServerFromApiAlreadyExists(crc)) {
|
||||
emit importErrorOccurred(ErrorCode::ApiConfigAlreadyAdded, true);
|
||||
} else {
|
||||
m_config.insert(config_key::crc, crc);
|
||||
|
||||
m_serversModel->addServer(m_config);
|
||||
emit importFinished();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Failed to import profile";
|
||||
qDebug().noquote() << QJsonDocument(m_config).toJson();
|
||||
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||
}
|
||||
|
||||
m_config = {};
|
||||
m_configFileName.clear();
|
||||
m_maliciousWarningText.clear();
|
||||
}
|
||||
|
||||
void ImportController::clearConfigFileName()
|
||||
{
|
||||
m_configFileName.clear();
|
||||
}
|
||||
|
||||
QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
|
||||
{
|
||||
QJsonObject openVpnConfig;
|
||||
openVpnConfig[config_key::config] = data;
|
||||
|
||||
QJsonObject lastConfig;
|
||||
lastConfig[config_key::last_config] = QString(QJsonDocument(openVpnConfig).toJson());
|
||||
lastConfig[config_key::isThirdPartyConfig] = true;
|
||||
|
||||
QJsonObject containers;
|
||||
containers.insert(config_key::container, QJsonValue("amnezia-openvpn"));
|
||||
containers.insert(config_key::openvpn, QJsonValue(lastConfig));
|
||||
|
||||
QJsonArray arr;
|
||||
arr.push_back(containers);
|
||||
|
||||
QString hostName;
|
||||
const static QRegularExpression hostNameRegExp("remote\\s+([^\\s]+)");
|
||||
QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(data);
|
||||
if (hostNameMatch.hasMatch()) {
|
||||
hostName = hostNameMatch.captured(1);
|
||||
}
|
||||
|
||||
QJsonObject config;
|
||||
config[config_key::containers] = arr;
|
||||
config[config_key::defaultContainer] = "amnezia-openvpn";
|
||||
config[config_key::description] = m_settings->nextAvailableServerName();
|
||||
|
||||
const static QRegularExpression dnsRegExp("dhcp-option DNS (\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
|
||||
QRegularExpressionMatchIterator dnsMatch = dnsRegExp.globalMatch(data);
|
||||
if (dnsMatch.hasNext()) {
|
||||
config[config_key::dns1] = dnsMatch.next().captured(1);
|
||||
}
|
||||
if (dnsMatch.hasNext()) {
|
||||
config[config_key::dns2] = dnsMatch.next().captured(1);
|
||||
}
|
||||
|
||||
config[config_key::hostName] = hostName;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
||||
{
|
||||
QMap<QString, QString> configMap;
|
||||
auto configByLines = data.split("\n");
|
||||
for (const QString &line : configByLines) {
|
||||
QString trimmedLine = line.trimmed();
|
||||
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
|
||||
continue;
|
||||
} else {
|
||||
QStringList parts = trimmedLine.split(" = ");
|
||||
if (parts.count() == 2) {
|
||||
configMap[parts.at(0).trimmed()] = parts.at(1).trimmed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject lastConfig;
|
||||
lastConfig[config_key::config] = data;
|
||||
|
||||
auto url { QUrl::fromUserInput(configMap.value("Endpoint")) };
|
||||
QString hostName;
|
||||
QString port;
|
||||
if (!url.host().isEmpty()) {
|
||||
hostName = url.host();
|
||||
} else {
|
||||
qDebug() << "Key parameter 'Endpoint' is missing or has an invalid format";
|
||||
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
if (url.port() != -1) {
|
||||
port = QString::number(url.port());
|
||||
} else {
|
||||
port = protocols::wireguard::defaultPort;
|
||||
}
|
||||
|
||||
lastConfig[config_key::hostName] = hostName;
|
||||
lastConfig[config_key::port] = port.toInt();
|
||||
|
||||
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()) {
|
||||
lastConfig[config_key::psk_key] = configMap.value("PreSharedKey");
|
||||
}
|
||||
|
||||
lastConfig[config_key::server_pub_key] = configMap.value("PublicKey");
|
||||
} else {
|
||||
qDebug() << "One of the key parameters is missing (PrivateKey, Address, PublicKey)";
|
||||
emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
if (!configMap.value("MTU").isEmpty()) {
|
||||
lastConfig[config_key::mtu] = configMap.value("MTU");
|
||||
}
|
||||
|
||||
if (!configMap.value("PersistentKeepalive").isEmpty()) {
|
||||
lastConfig[config_key::persistent_keep_alive] = configMap.value("PersistentKeepalive");
|
||||
}
|
||||
|
||||
QJsonArray allowedIpsJsonArray = QJsonArray::fromStringList(configMap.value("AllowedIPs").split(", "));
|
||||
|
||||
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
||||
|
||||
QString protocolName = "wireguard";
|
||||
QString protocolVersion;
|
||||
|
||||
const QStringList requiredJunkFields = { config_key::junkPacketCount, config_key::junkPacketMinSize,
|
||||
config_key::junkPacketMaxSize, config_key::initPacketJunkSize,
|
||||
config_key::responsePacketJunkSize, config_key::initPacketMagicHeader,
|
||||
config_key::responsePacketMagicHeader, config_key::underloadPacketMagicHeader,
|
||||
config_key::transportPacketMagicHeader };
|
||||
|
||||
const QStringList optionalJunkFields = { config_key::cookieReplyPacketJunkSize,
|
||||
config_key::transportPacketJunkSize,
|
||||
config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3,
|
||||
config_key::specialJunk4, config_key::specialJunk5
|
||||
};
|
||||
|
||||
bool hasAllRequiredFields = std::all_of(requiredJunkFields.begin(), requiredJunkFields.end(),
|
||||
[&configMap](const QString &field) { return !configMap.value(field).isEmpty(); });
|
||||
if (hasAllRequiredFields) {
|
||||
for (const QString &field : requiredJunkFields) {
|
||||
lastConfig[field] = configMap.value(field);
|
||||
}
|
||||
|
||||
for (const QString &field : optionalJunkFields) {
|
||||
if (!configMap.value(field).isEmpty()) {
|
||||
lastConfig[field] = configMap.value(field);
|
||||
}
|
||||
}
|
||||
|
||||
bool hasCookieReplyPacketJunkSize = !configMap.value(config_key::cookieReplyPacketJunkSize).isEmpty();
|
||||
bool hasTransportPacketJunkSize = !configMap.value(config_key::transportPacketJunkSize).isEmpty();
|
||||
bool hasSpecialJunk = !configMap.value(config_key::specialJunk1).isEmpty() ||
|
||||
!configMap.value(config_key::specialJunk2).isEmpty() ||
|
||||
!configMap.value(config_key::specialJunk3).isEmpty() ||
|
||||
!configMap.value(config_key::specialJunk4).isEmpty() ||
|
||||
!configMap.value(config_key::specialJunk5).isEmpty();
|
||||
|
||||
if (hasCookieReplyPacketJunkSize && hasTransportPacketJunkSize) {
|
||||
protocolVersion = "2";
|
||||
} else if (hasSpecialJunk && !hasCookieReplyPacketJunkSize && !hasTransportPacketJunkSize) {
|
||||
protocolVersion = "1.5";
|
||||
}
|
||||
protocolName = "awg";
|
||||
m_configType = ConfigTypes::Awg;
|
||||
}
|
||||
|
||||
if (!configMap.value("MTU").isEmpty()) {
|
||||
lastConfig[config_key::mtu] = configMap.value("MTU");
|
||||
} else {
|
||||
lastConfig[config_key::mtu] = (protocolName == "awg")
|
||||
? protocols::awg::defaultMtu
|
||||
: protocols::wireguard::defaultMtu;
|
||||
}
|
||||
|
||||
QJsonObject wireguardConfig;
|
||||
wireguardConfig[config_key::last_config] = QString(QJsonDocument(lastConfig).toJson());
|
||||
wireguardConfig[config_key::isThirdPartyConfig] = true;
|
||||
wireguardConfig[config_key::port] = port;
|
||||
wireguardConfig[config_key::transport_proto] = "udp";
|
||||
if (protocolName == "awg" && !protocolVersion.isEmpty()) {
|
||||
wireguardConfig[config_key::protocolVersion] = protocolVersion;
|
||||
}
|
||||
|
||||
QJsonObject containers;
|
||||
containers.insert(config_key::container, QJsonValue("amnezia-" + protocolName));
|
||||
containers.insert(protocolName, QJsonValue(wireguardConfig));
|
||||
|
||||
QJsonArray arr;
|
||||
arr.push_back(containers);
|
||||
|
||||
QJsonObject config;
|
||||
config[config_key::containers] = arr;
|
||||
config[config_key::defaultContainer] = "amnezia-" + protocolName;
|
||||
config[config_key::description] = m_settings->nextAvailableServerName();
|
||||
|
||||
const static QRegularExpression dnsRegExp(
|
||||
"DNS = "
|
||||
"(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b).*(\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b)");
|
||||
QRegularExpressionMatch dnsMatch = dnsRegExp.match(data);
|
||||
if (dnsMatch.hasMatch()) {
|
||||
config[config_key::dns1] = dnsMatch.captured(1);
|
||||
config[config_key::dns2] = dnsMatch.captured(2);
|
||||
}
|
||||
|
||||
config[config_key::hostName] = hostName;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
QJsonObject ImportController::extractXrayConfig(const QString &data, const QString &description)
|
||||
{
|
||||
QJsonParseError parserErr;
|
||||
QJsonDocument jsonConf = QJsonDocument::fromJson(data.toLocal8Bit(), &parserErr);
|
||||
|
||||
QJsonObject xrayVpnConfig;
|
||||
xrayVpnConfig[config_key::config] = jsonConf.toJson().constData();
|
||||
QJsonObject lastConfig;
|
||||
lastConfig[config_key::last_config] = jsonConf.toJson().constData();
|
||||
lastConfig[config_key::isThirdPartyConfig] = true;
|
||||
|
||||
QJsonObject containers;
|
||||
if (m_configType == ConfigTypes::ShadowSocks) {
|
||||
containers.insert(config_key::ssxray, QJsonValue(lastConfig));
|
||||
containers.insert(config_key::container, QJsonValue("amnezia-ssxray"));
|
||||
} else {
|
||||
containers.insert(config_key::container, QJsonValue("amnezia-xray"));
|
||||
containers.insert(config_key::xray, QJsonValue(lastConfig));
|
||||
}
|
||||
|
||||
QJsonArray arr;
|
||||
arr.push_back(containers);
|
||||
|
||||
QString hostName;
|
||||
|
||||
const static QRegularExpression hostNameRegExp("\"address\":\\s*\"([^\"]+)");
|
||||
QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(data);
|
||||
if (hostNameMatch.hasMatch()) {
|
||||
hostName = hostNameMatch.captured(1);
|
||||
}
|
||||
|
||||
QJsonObject config;
|
||||
config[config_key::containers] = arr;
|
||||
|
||||
if (m_configType == ConfigTypes::ShadowSocks) {
|
||||
config[config_key::defaultContainer] = "amnezia-ssxray";
|
||||
} else {
|
||||
config[config_key::defaultContainer] = "amnezia-xray";
|
||||
}
|
||||
if (description.isEmpty()) {
|
||||
config[config_key::description] = m_settings->nextAvailableServerName();
|
||||
} else {
|
||||
config[config_key::description] = description;
|
||||
}
|
||||
config[config_key::hostName] = hostName;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
static QMutex qrDecodeMutex;
|
||||
|
||||
// static
|
||||
bool ImportController::decodeQrCode(const QString &code)
|
||||
{
|
||||
QMutexLocker lock(&qrDecodeMutex);
|
||||
|
||||
if (!mInstance->m_isQrCodeProcessed) {
|
||||
mInstance->m_qrCodeChunks.clear();
|
||||
mInstance->m_isQrCodeProcessed = true;
|
||||
mInstance->m_totalQrCodeChunksCount = 0;
|
||||
mInstance->m_receivedQrCodeChunksCount = 0;
|
||||
}
|
||||
return mInstance->parseQrCodeChunk(code);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void ImportController::startDecodingQr()
|
||||
{
|
||||
m_qrCodeChunks.clear();
|
||||
m_totalQrCodeChunksCount = 0;
|
||||
m_receivedQrCodeChunksCount = 0;
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
m_isQrCodeProcessed = true;
|
||||
#endif
|
||||
#if defined Q_OS_ANDROID
|
||||
AndroidController::instance()->startQrReaderActivity();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImportController::stopDecodingQr()
|
||||
{
|
||||
emit qrDecodingFinished();
|
||||
}
|
||||
|
||||
bool ImportController::parseQrCodeChunk(const QString &code)
|
||||
{
|
||||
// qDebug() << code;
|
||||
if (!m_isQrCodeProcessed)
|
||||
return false;
|
||||
|
||||
// check if chunk received
|
||||
QByteArray ba = QByteArray::fromBase64(code.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
qint16 magic;
|
||||
s >> magic;
|
||||
|
||||
if (magic == qrCodeUtils::qrMagicCode) {
|
||||
quint8 chunksCount;
|
||||
s >> chunksCount;
|
||||
if (m_totalQrCodeChunksCount != chunksCount) {
|
||||
m_qrCodeChunks.clear();
|
||||
}
|
||||
|
||||
m_totalQrCodeChunksCount = chunksCount;
|
||||
|
||||
quint8 chunkId;
|
||||
s >> chunkId;
|
||||
s >> m_qrCodeChunks[chunkId];
|
||||
m_receivedQrCodeChunksCount = m_qrCodeChunks.size();
|
||||
|
||||
if (m_qrCodeChunks.size() == m_totalQrCodeChunksCount) {
|
||||
QByteArray data;
|
||||
|
||||
for (int i = 0; i < m_totalQrCodeChunksCount; ++i) {
|
||||
data.append(m_qrCodeChunks.value(i));
|
||||
}
|
||||
|
||||
bool ok = extractConfigFromQr(data);
|
||||
if (ok) {
|
||||
m_isQrCodeProcessed = false;
|
||||
qDebug() << "stopDecodingQr";
|
||||
stopDecodingQr();
|
||||
return true;
|
||||
} else {
|
||||
qDebug() << "error while extracting data from qr";
|
||||
m_qrCodeChunks.clear();
|
||||
m_totalQrCodeChunksCount = 0;
|
||||
m_receivedQrCodeChunksCount = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool ok = extractConfigFromQr(ba);
|
||||
if (ok) {
|
||||
m_isQrCodeProcessed = false;
|
||||
qDebug() << "stopDecodingQr";
|
||||
stopDecodingQr();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double ImportController::getQrCodeScanProgressBarValue()
|
||||
{
|
||||
return (1.0 / m_totalQrCodeChunksCount) * m_receivedQrCodeChunksCount;
|
||||
}
|
||||
|
||||
QString ImportController::getQrCodeScanProgressString()
|
||||
{
|
||||
return tr("Scanned %1 of %2.").arg(m_receivedQrCodeChunksCount).arg(m_totalQrCodeChunksCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
|
||||
{
|
||||
const QJsonArray &containers = serverConfig[config_key::containers].toArray();
|
||||
for (const QJsonValue &container : containers) {
|
||||
auto containerConfig = container.toObject();
|
||||
auto containerName = containerConfig[config_key::container].toString();
|
||||
if ((containerName == ContainerProps::containerToString(DockerContainer::OpenVpn))
|
||||
|| (containerName == ContainerProps::containerToString(DockerContainer::Cloak))
|
||||
|| (containerName == ContainerProps::containerToString(DockerContainer::ShadowSocks))) {
|
||||
|
||||
QString protocolConfig =
|
||||
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
|
||||
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
|
||||
|
||||
// https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/script-options.rst
|
||||
QStringList dangerousTags {
|
||||
"up", "tls-verify", "ipchange", "client-connect", "route-up", "route-pre-down", "client-disconnect", "down", "learn-address", "auth-user-pass-verify"
|
||||
};
|
||||
|
||||
QStringList maliciousStrings;
|
||||
QStringList lines = protocolConfigJson.split('\n', Qt::SkipEmptyParts);
|
||||
|
||||
for (const QString &rawLine : lines) {
|
||||
QString line = rawLine.trimmed();
|
||||
|
||||
QString command = line.section(' ', 0, 0, QString::SectionSkipEmpty);
|
||||
if (dangerousTags.contains(command, Qt::CaseInsensitive)) {
|
||||
maliciousStrings << rawLine;
|
||||
}
|
||||
}
|
||||
|
||||
m_maliciousWarningText = tr("This configuration contains an OpenVPN setup. OpenVPN configurations can include malicious "
|
||||
"scripts, so only add it if you fully trust the provider of this config. ");
|
||||
|
||||
if (!maliciousStrings.isEmpty()) {
|
||||
m_maliciousWarningText.push_back(tr("<br>In the imported configuration, potentially dangerous lines were found:"));
|
||||
for (const auto &string : maliciousStrings) {
|
||||
m_maliciousWarningText.push_back(QString("<br><i>%1</i>").arg(string));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImportController::processAmneziaConfig(QJsonObject &config)
|
||||
{
|
||||
auto containers = config.value(config_key::containers).toArray();
|
||||
for (auto i = 0; i < containers.size(); i++) {
|
||||
auto container = containers.at(i).toObject();
|
||||
auto dockerContainer = ContainerProps::containerFromString(container.value(config_key::container).toString());
|
||||
if (ContainerProps::isAwgContainer(dockerContainer) || dockerContainer == DockerContainer::WireGuard) {
|
||||
auto containerConfig = container.value(ContainerProps::containerTypeToProtocolString(dockerContainer)).toObject();
|
||||
auto protocolConfig = containerConfig.value(config_key::last_config).toString();
|
||||
if (protocolConfig.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject jsonConfig = QJsonDocument::fromJson(protocolConfig.toUtf8()).object();
|
||||
jsonConfig[config_key::mtu] =
|
||||
ContainerProps::isAwgContainer(dockerContainer) ? protocols::awg::defaultMtu : protocols::wireguard::defaultMtu;
|
||||
|
||||
containerConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
||||
|
||||
container[ContainerProps::containerTypeToProtocolString(dockerContainer)] = containerConfig;
|
||||
containers.replace(i, container);
|
||||
config.insert(config_key::containers, containers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
#ifndef IMPORTCONTROLLER_H
|
||||
#define IMPORTCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
enum class ConfigTypes {
|
||||
Amnezia,
|
||||
OpenVpn,
|
||||
WireGuard,
|
||||
Awg,
|
||||
Xray,
|
||||
ShadowSocks,
|
||||
Backup,
|
||||
Invalid
|
||||
};
|
||||
}
|
||||
|
||||
class ImportController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImportController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void importConfig();
|
||||
void clearConfigFileName();
|
||||
bool extractConfigFromFile(const QString &fileName);
|
||||
bool extractConfigFromData(QString data);
|
||||
bool extractConfigFromQr(const QByteArray &data);
|
||||
QString getConfig();
|
||||
QString getConfigFileName();
|
||||
QString getMaliciousWarningText();
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void startDecodingQr();
|
||||
bool parseQrCodeChunk(const QString &code);
|
||||
|
||||
double getQrCodeScanProgressBarValue();
|
||||
QString getQrCodeScanProgressString();
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
static bool decodeQrCode(const QString &code);
|
||||
#endif
|
||||
|
||||
bool isNativeWireGuardConfig();
|
||||
void processNativeWireGuardConfig();
|
||||
|
||||
signals:
|
||||
void importFinished();
|
||||
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
|
||||
|
||||
void qrDecodingFinished();
|
||||
|
||||
void restoreAppConfig(const QByteArray &data);
|
||||
|
||||
private:
|
||||
QJsonObject extractOpenVpnConfig(const QString &data);
|
||||
QJsonObject extractWireGuardConfig(const QString &data);
|
||||
QJsonObject extractXrayConfig(const QString &data, const QString &description = "");
|
||||
|
||||
void checkForMaliciousStrings(const QJsonObject &protocolConfig);
|
||||
|
||||
void processAmneziaConfig(QJsonObject &config);
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void stopDecodingQr();
|
||||
#endif
|
||||
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QJsonObject m_config;
|
||||
QString m_configFileName;
|
||||
ConfigTypes m_configType;
|
||||
QString m_maliciousWarningText;
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
QMap<int, QByteArray> m_qrCodeChunks;
|
||||
bool m_isQrCodeProcessed;
|
||||
int m_totalQrCodeChunksCount;
|
||||
int m_receivedQrCodeChunksCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // IMPORTCONTROLLER_H
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "importUiController.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QMutex>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "systemController.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
ImportUiController* ImportUiController::mInstance = nullptr;
|
||||
static QMutex qrDecodeMutex;
|
||||
#endif
|
||||
|
||||
ImportUiController::ImportUiController(ImportController* importController, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_importController(importController),
|
||||
m_isNativeWireGuardConfig(false)
|
||||
{
|
||||
#if defined Q_OS_ANDROID
|
||||
mInstance = this;
|
||||
#endif
|
||||
|
||||
connect(m_importController, &ImportController::importFinished, this, &ImportUiController::importFinished);
|
||||
connect(m_importController, &ImportController::importErrorOccurred, this, &ImportUiController::importErrorOccurred);
|
||||
connect(m_importController, &ImportController::restoreAppConfig, this, &ImportUiController::restoreAppConfig);
|
||||
}
|
||||
|
||||
bool ImportUiController::extractConfigFromFile(const QString &fileName)
|
||||
{
|
||||
QString data;
|
||||
if (!SystemController::readFile(fileName, data)) {
|
||||
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString configFileName = QFileInfo(QFile(fileName).fileName()).fileName();
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (configFileName.isEmpty()) {
|
||||
configFileName = AndroidController::instance()->getFileName(fileName);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto result = m_importController->extractConfigFromData(data, configFileName);
|
||||
|
||||
if (result.errorCode != ErrorCode::NoError) {
|
||||
emit importErrorOccurred(result.errorCode, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_config = result.config;
|
||||
m_configFileName = result.configFileName;
|
||||
m_maliciousWarningText = result.maliciousWarningText;
|
||||
m_isNativeWireGuardConfig = result.isNativeWireGuardConfig;
|
||||
|
||||
emit importConfigChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImportUiController::extractConfigFromData(QString data)
|
||||
{
|
||||
auto result = m_importController->extractConfigFromData(data);
|
||||
|
||||
if (result.errorCode != ErrorCode::NoError) {
|
||||
emit importErrorOccurred(result.errorCode, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_config = result.config;
|
||||
m_configFileName = result.configFileName;
|
||||
m_maliciousWarningText = result.maliciousWarningText;
|
||||
m_isNativeWireGuardConfig = result.isNativeWireGuardConfig;
|
||||
|
||||
emit importConfigChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImportUiController::extractConfigFromQr(const QByteArray &data)
|
||||
{
|
||||
auto result = m_importController->extractConfigFromQr(data);
|
||||
|
||||
if (result.errorCode != ErrorCode::NoError) {
|
||||
emit importErrorOccurred(result.errorCode, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_config = result.config;
|
||||
m_configFileName = result.configFileName;
|
||||
m_maliciousWarningText = result.maliciousWarningText;
|
||||
m_isNativeWireGuardConfig = result.isNativeWireGuardConfig;
|
||||
|
||||
emit importConfigChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ImportUiController::getConfig()
|
||||
{
|
||||
return QJsonDocument(m_config).toJson(QJsonDocument::Indented);
|
||||
}
|
||||
|
||||
QString ImportUiController::getConfigFileName()
|
||||
{
|
||||
return m_configFileName;
|
||||
}
|
||||
|
||||
QString ImportUiController::getMaliciousWarningText()
|
||||
{
|
||||
return m_maliciousWarningText;
|
||||
}
|
||||
|
||||
bool ImportUiController::isNativeWireGuardConfig()
|
||||
{
|
||||
return m_isNativeWireGuardConfig;
|
||||
}
|
||||
|
||||
void ImportUiController::processNativeWireGuardConfig()
|
||||
{
|
||||
m_config = m_importController->processNativeWireGuardConfig(m_config);
|
||||
emit importConfigChanged();
|
||||
}
|
||||
|
||||
void ImportUiController::importConfig()
|
||||
{
|
||||
m_importController->importConfig(m_config);
|
||||
|
||||
m_config = {};
|
||||
m_configFileName.clear();
|
||||
m_maliciousWarningText.clear();
|
||||
m_isNativeWireGuardConfig = false;
|
||||
|
||||
emit importConfigChanged();
|
||||
}
|
||||
|
||||
void ImportUiController::clearConfigFileName()
|
||||
{
|
||||
m_configFileName.clear();
|
||||
emit importConfigChanged();
|
||||
}
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void ImportUiController::startDecodingQr()
|
||||
{
|
||||
m_importController->startDecodingQr();
|
||||
#if defined Q_OS_ANDROID
|
||||
AndroidController::instance()->startQrReaderActivity();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ImportUiController::stopDecodingQr()
|
||||
{
|
||||
emit qrDecodingFinished();
|
||||
}
|
||||
|
||||
bool ImportUiController::parseQrCodeChunk(const QString &code)
|
||||
{
|
||||
auto parseResult = m_importController->parseQrCodeChunk(code);
|
||||
if (parseResult.success) {
|
||||
m_config = parseResult.importResult.config;
|
||||
m_configFileName = parseResult.importResult.configFileName;
|
||||
m_maliciousWarningText = parseResult.importResult.maliciousWarningText;
|
||||
m_isNativeWireGuardConfig = parseResult.importResult.isNativeWireGuardConfig;
|
||||
emit importConfigChanged();
|
||||
stopDecodingQr();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double ImportUiController::getQrCodeScanProgressBarValue()
|
||||
{
|
||||
const int total = m_importController->qrChunksTotal();
|
||||
if (total == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return (1.0 / total) * m_importController->qrChunksReceived();
|
||||
}
|
||||
|
||||
QString ImportUiController::getQrCodeScanProgressString()
|
||||
{
|
||||
return tr("Scanned %1 of %2.").arg(m_importController->qrChunksReceived()).arg(m_importController->qrChunksTotal());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
bool ImportUiController::decodeQrCode(const QString &code)
|
||||
{
|
||||
QMutexLocker lock(&qrDecodeMutex);
|
||||
|
||||
if (!mInstance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mInstance->m_importController->isQrDecodingActive()) {
|
||||
mInstance->m_importController->startDecodingQr();
|
||||
}
|
||||
return mInstance->parseQrCodeChunk(code);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef IMPORTUICONTROLLER_H
|
||||
#define IMPORTUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/controllers/selfhosted/importController.h"
|
||||
|
||||
class ImportUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString config READ getConfig NOTIFY importConfigChanged)
|
||||
Q_PROPERTY(QString configFileName READ getConfigFileName NOTIFY importConfigChanged)
|
||||
Q_PROPERTY(QString maliciousWarningText READ getMaliciousWarningText NOTIFY importConfigChanged)
|
||||
Q_PROPERTY(bool isNativeWireGuardConfig READ isNativeWireGuardConfig NOTIFY importConfigChanged)
|
||||
|
||||
public:
|
||||
explicit ImportUiController(ImportController* importController, QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void importConfig();
|
||||
void clearConfigFileName();
|
||||
bool extractConfigFromFile(const QString &fileName);
|
||||
bool extractConfigFromData(QString data);
|
||||
bool extractConfigFromQr(const QByteArray &data);
|
||||
QString getConfig();
|
||||
QString getConfigFileName();
|
||||
QString getMaliciousWarningText();
|
||||
bool isNativeWireGuardConfig();
|
||||
void processNativeWireGuardConfig();
|
||||
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void startDecodingQr();
|
||||
bool parseQrCodeChunk(const QString &code);
|
||||
|
||||
double getQrCodeScanProgressBarValue();
|
||||
QString getQrCodeScanProgressString();
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
static bool decodeQrCode(const QString &code);
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void importFinished();
|
||||
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
|
||||
void qrDecodingFinished();
|
||||
void restoreAppConfig(const QByteArray &data);
|
||||
void importConfigChanged();
|
||||
|
||||
private:
|
||||
#if defined Q_OS_ANDROID || defined Q_OS_IOS
|
||||
void stopDecodingQr();
|
||||
#endif
|
||||
|
||||
ImportController* m_importController;
|
||||
|
||||
QJsonObject m_config;
|
||||
QString m_configFileName;
|
||||
QString m_maliciousWarningText;
|
||||
bool m_isNativeWireGuardConfig;
|
||||
|
||||
#if defined Q_OS_ANDROID
|
||||
static ImportUiController* mInstance;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // IMPORTUICONTROLLER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,120 +0,0 @@
|
||||
#ifndef INSTALLCONTROLLER_H
|
||||
#define INSTALLCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
#include "core/defs.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#include "ui/models/containers_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,
|
||||
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 setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData);
|
||||
void setShouldCreateServer(bool shouldCreateServer);
|
||||
|
||||
void scanServerForInstalledContainers();
|
||||
|
||||
void updateContainer(QJsonObject config);
|
||||
|
||||
void removeProcessedServer();
|
||||
void rebootProcessedServer();
|
||||
void removeAllContainers();
|
||||
void removeProcessedContainer();
|
||||
|
||||
void removeApiConfig(const int serverIndex);
|
||||
|
||||
void clearCachedProfile(QSharedPointer<ServerController> serverController = nullptr);
|
||||
|
||||
QRegularExpression ipAddressPortRegExp();
|
||||
QRegularExpression ipAddressRegExp();
|
||||
|
||||
void mountSftpDrive(const QString &port, const QString &password, const QString &username);
|
||||
|
||||
bool checkSshConnection(QSharedPointer<ServerController> serverController = nullptr);
|
||||
|
||||
void setEncryptedPassphrase(QString passphrase);
|
||||
|
||||
void addEmptyServer();
|
||||
|
||||
void validateConfig();
|
||||
|
||||
signals:
|
||||
void configValidated(bool isValid);
|
||||
void installContainerFinished(const QString &finishMessage, bool isServiceInstall);
|
||||
void installServerFinished(const QString &finishMessage);
|
||||
|
||||
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 removeProcessedContainerFinished(const QString &finishedMessage);
|
||||
|
||||
void installationErrorOccurred(ErrorCode errorCode);
|
||||
void wrongInstallationUser(const QString &message);
|
||||
|
||||
void serverAlreadyExists(int serverIndex);
|
||||
|
||||
void passphraseRequestStarted();
|
||||
void passphraseRequestFinished();
|
||||
|
||||
void serverIsBusy(const bool isBusy);
|
||||
void cancelInstallation();
|
||||
|
||||
void currentContainerUpdated();
|
||||
|
||||
void cachedProfileCleared(const QString &message);
|
||||
void apiConfigRemoved(const QString &message);
|
||||
|
||||
void noInstalledContainers();
|
||||
|
||||
void profileCleared(const QJsonObject &config);
|
||||
|
||||
private:
|
||||
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
|
||||
const ServerCredentials &serverCredentials, const QSharedPointer<ServerController> &serverController,
|
||||
QString &finishMessage);
|
||||
void installContainer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
|
||||
const ServerCredentials &serverCredentials, const QSharedPointer<ServerController> &serverController,
|
||||
QString &finishMessage);
|
||||
bool isServerAlreadyExists();
|
||||
|
||||
ErrorCode getAlreadyInstalledContainers(const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController,
|
||||
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_processedServerCredentials;
|
||||
|
||||
bool m_shouldCreateServer;
|
||||
|
||||
QString m_privateKeyPassphrase;
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
QList<QSharedPointer<QProcess>> m_sftpMountProcesses;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // INSTALLCONTROLLER_H
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "ipSplitTunnelingUiController.h"
|
||||
|
||||
#include "systemController.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
|
||||
IpSplitTunnelingUiController::IpSplitTunnelingUiController(IpSplitTunnelingController* ipSplitTunnelingController,
|
||||
IpSplitTunnelingModel* ipSplitTunnelingModel, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_ipSplitTunnelingController(ipSplitTunnelingController),
|
||||
m_ipSplitTunnelingModel(ipSplitTunnelingModel)
|
||||
{
|
||||
m_ipSplitTunnelingModel->updateModel(m_ipSplitTunnelingController->getCurrentSites());
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::addSite(QString hostname)
|
||||
{
|
||||
if (m_ipSplitTunnelingController->addSite(hostname)) {
|
||||
emit finished(tr("New site added: %1").arg(hostname));
|
||||
}
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::removeSite(int index)
|
||||
{
|
||||
auto modelIndex = m_ipSplitTunnelingModel->index(index);
|
||||
auto hostname = m_ipSplitTunnelingModel->data(modelIndex, IpSplitTunnelingModel::Roles::UrlRole).toString();
|
||||
if (m_ipSplitTunnelingController->removeSite(hostname)) {
|
||||
emit finished(tr("Site removed: %1").arg(hostname));
|
||||
}
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::removeSites()
|
||||
{
|
||||
m_ipSplitTunnelingController->removeSites();
|
||||
emit finished(tr("Site list cleared!"));
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::importSites(const QString &fileName, bool replaceExisting)
|
||||
{
|
||||
QByteArray jsonData;
|
||||
if (!SystemController::readFile(fileName, jsonData)) {
|
||||
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
QString errorMessage;
|
||||
if (m_ipSplitTunnelingController->importSitesFromJson(jsonData, replaceExisting, errorMessage)) {
|
||||
emit finished(tr("Import completed"));
|
||||
} else {
|
||||
emit errorOccurred(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::exportSites(const QString &fileName)
|
||||
{
|
||||
QByteArray jsonData = m_ipSplitTunnelingController->exportSitesToJson();
|
||||
SystemController::saveFile(fileName, QString::fromUtf8(jsonData));
|
||||
emit finished(tr("Export completed"));
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::toggleSplitTunneling(bool enabled)
|
||||
{
|
||||
m_ipSplitTunnelingController->toggleSplitTunneling(enabled);
|
||||
emit isSplitTunnelingEnabledChanged();
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::setRouteMode(int routeMode)
|
||||
{
|
||||
m_ipSplitTunnelingController->setRouteMode(static_cast<amnezia::RouteMode>(routeMode));
|
||||
emit routeModeChanged();
|
||||
}
|
||||
|
||||
int IpSplitTunnelingUiController::getRouteMode() const
|
||||
{
|
||||
return static_cast<int>(m_ipSplitTunnelingController->getRouteMode());
|
||||
}
|
||||
|
||||
bool IpSplitTunnelingUiController::isSplitTunnelingEnabled() const
|
||||
{
|
||||
return m_ipSplitTunnelingController->isSplitTunnelingEnabled();
|
||||
}
|
||||
|
||||
void IpSplitTunnelingUiController::updateModel()
|
||||
{
|
||||
m_ipSplitTunnelingModel->updateModel(m_ipSplitTunnelingController->getCurrentSites());
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef IPSPLITTUNNELINGUICONTROLLER_H
|
||||
#define IPSPLITTUNNELINGUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/controllers/ipSplitTunnelingController.h"
|
||||
#include "ui/models/ipSplitTunnelingModel.h"
|
||||
|
||||
class IpSplitTunnelingUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int routeMode READ getRouteMode WRITE setRouteMode NOTIFY routeModeChanged)
|
||||
Q_PROPERTY(bool isSplitTunnelingEnabled READ isSplitTunnelingEnabled NOTIFY isSplitTunnelingEnabledChanged)
|
||||
|
||||
public:
|
||||
explicit IpSplitTunnelingUiController(IpSplitTunnelingController* ipSplitTunnelingController,
|
||||
IpSplitTunnelingModel* ipSplitTunnelingModel, QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addSite(QString hostname);
|
||||
void removeSite(int index);
|
||||
void removeSites();
|
||||
void importSites(const QString &fileName, bool replaceExisting);
|
||||
void exportSites(const QString &fileName);
|
||||
void toggleSplitTunneling(bool enabled);
|
||||
void setRouteMode(int routeMode);
|
||||
|
||||
int getRouteMode() const;
|
||||
bool isSplitTunnelingEnabled() const;
|
||||
|
||||
void updateModel();
|
||||
|
||||
signals:
|
||||
void routeModeChanged();
|
||||
void isSplitTunnelingEnabledChanged();
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
IpSplitTunnelingController* m_ipSplitTunnelingController;
|
||||
IpSplitTunnelingModel* m_ipSplitTunnelingModel;
|
||||
};
|
||||
|
||||
#endif // IPSPLITTUNNELINGUICONTROLLER_H
|
||||
@@ -0,0 +1,125 @@
|
||||
#include "languageUiController.h"
|
||||
|
||||
LanguageUiController::LanguageUiController(SettingsController* settingsController,
|
||||
LanguageModel* languageModel,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_settingsController(settingsController),
|
||||
m_languageModel(languageModel)
|
||||
{
|
||||
}
|
||||
|
||||
void LanguageUiController::onAppLanguageChanged(const QLocale &locale)
|
||||
{
|
||||
emit updateTranslations(locale);
|
||||
emit translationsUpdated();
|
||||
}
|
||||
|
||||
void LanguageUiController::changeLanguage(const LanguageSettings::AvailableLanguageEnum language)
|
||||
{
|
||||
QLocale locale = languageEnumToLocale(language);
|
||||
m_settingsController->setAppLanguage(locale);
|
||||
}
|
||||
|
||||
int LanguageUiController::getCurrentLanguageIndex() const
|
||||
{
|
||||
auto locale = m_settingsController->getAppLanguage();
|
||||
switch (locale.language()) {
|
||||
case QLocale::English: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
|
||||
case QLocale::Russian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Russian); break;
|
||||
case QLocale::Chinese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::China_cn); break;
|
||||
case QLocale::Ukrainian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Ukrainian); break;
|
||||
case QLocale::Persian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Persian); break;
|
||||
case QLocale::Arabic: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Arabic); break;
|
||||
case QLocale::Burmese: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Burmese); break;
|
||||
case QLocale::Urdu: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Urdu); break;
|
||||
case QLocale::Hindi: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Hindi); break;
|
||||
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
|
||||
}
|
||||
}
|
||||
|
||||
int LanguageUiController::getLineHeightAppend() const
|
||||
{
|
||||
auto locale = m_settingsController->getAppLanguage();
|
||||
switch (locale.language()) {
|
||||
case QLocale::Burmese: return 10; break;
|
||||
default: return 0; break;
|
||||
}
|
||||
}
|
||||
|
||||
QString LanguageUiController::getCurrentLanguageName() const
|
||||
{
|
||||
int index = getCurrentLanguageIndex();
|
||||
return getLocalLanguageName(static_cast<LanguageSettings::AvailableLanguageEnum>(index));
|
||||
}
|
||||
|
||||
LanguageSettings::AvailableLanguageEnum LanguageUiController::getSystemLanguageEnum() const
|
||||
{
|
||||
QLocale locale = QLocale::system();
|
||||
switch (locale.language()) {
|
||||
case QLocale::Russian: return LanguageSettings::AvailableLanguageEnum::Russian;
|
||||
case QLocale::Chinese: return LanguageSettings::AvailableLanguageEnum::China_cn;
|
||||
case QLocale::Ukrainian: return LanguageSettings::AvailableLanguageEnum::Ukrainian;
|
||||
case QLocale::Persian: return LanguageSettings::AvailableLanguageEnum::Persian;
|
||||
case QLocale::Arabic: return LanguageSettings::AvailableLanguageEnum::Arabic;
|
||||
case QLocale::Burmese: return LanguageSettings::AvailableLanguageEnum::Burmese;
|
||||
case QLocale::Urdu: return LanguageSettings::AvailableLanguageEnum::Urdu;
|
||||
case QLocale::Hindi: return LanguageSettings::AvailableLanguageEnum::Hindi;
|
||||
case QLocale::English: return LanguageSettings::AvailableLanguageEnum::English;
|
||||
default: return LanguageSettings::AvailableLanguageEnum::English;
|
||||
}
|
||||
}
|
||||
|
||||
QString LanguageUiController::getCurrentSiteUrl(const QString &path) const
|
||||
{
|
||||
auto locale = m_settingsController->getAppLanguage();
|
||||
if (locale.language() == QLocale::Russian) {
|
||||
return "https://storage.googleapis.com/amnezia/amnezia.org" + (path.isEmpty() ? "" : (QString("?m-path=/%1").arg(path)));
|
||||
}
|
||||
return QString("https://amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path)));
|
||||
}
|
||||
|
||||
QString LanguageUiController::getCurrentDocsUrl(const QString &path) const
|
||||
{
|
||||
auto locale = m_settingsController->getAppLanguage();
|
||||
if (locale.language() == QLocale::Russian) {
|
||||
return "https://storage.googleapis.com/amnezia/docs" + (path.isEmpty() ? "" : (QString("?m-path=/%1").arg(path)));
|
||||
}
|
||||
return QString("https://docs.amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path)));
|
||||
}
|
||||
|
||||
QString LanguageUiController::getLocalLanguageName(const LanguageSettings::AvailableLanguageEnum language) const
|
||||
{
|
||||
QString strLanguage("");
|
||||
switch (language) {
|
||||
case LanguageSettings::AvailableLanguageEnum::English: strLanguage = "English"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian: strLanguage = "Русский"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Ukrainian: strLanguage = "Українська"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::China_cn: strLanguage = "\347\256\200\344\275\223\344\270\255\346\226\207"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Persian: strLanguage = "فارسی"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Arabic: strLanguage = "العربية"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Burmese: strLanguage = "မြန်မာဘာသာ"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Urdu: strLanguage = "اُرْدُوْ"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Hindi: strLanguage = "हिन्दी"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return strLanguage;
|
||||
}
|
||||
|
||||
QLocale LanguageUiController::languageEnumToLocale(const LanguageSettings::AvailableLanguageEnum language) const
|
||||
{
|
||||
switch (language) {
|
||||
case LanguageSettings::AvailableLanguageEnum::English: return QLocale::English;
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian: return QLocale::Russian;
|
||||
case LanguageSettings::AvailableLanguageEnum::China_cn: return QLocale::Chinese;
|
||||
case LanguageSettings::AvailableLanguageEnum::Ukrainian: return QLocale::Ukrainian;
|
||||
case LanguageSettings::AvailableLanguageEnum::Persian: return QLocale::Persian;
|
||||
case LanguageSettings::AvailableLanguageEnum::Arabic: return QLocale::Arabic;
|
||||
case LanguageSettings::AvailableLanguageEnum::Burmese: return QLocale::Burmese;
|
||||
case LanguageSettings::AvailableLanguageEnum::Urdu: return QLocale::Urdu;
|
||||
case LanguageSettings::AvailableLanguageEnum::Hindi: return QLocale::Hindi;
|
||||
default: return QLocale::English;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef LANGUAGEUICONTROLLER_H
|
||||
#define LANGUAGEUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLocale>
|
||||
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "ui/models/languageModel.h"
|
||||
|
||||
class LanguageUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString currentLanguageName READ getCurrentLanguageName NOTIFY translationsUpdated)
|
||||
Q_PROPERTY(int currentLanguageIndex READ getCurrentLanguageIndex NOTIFY translationsUpdated)
|
||||
Q_PROPERTY(int lineHeightAppend READ getLineHeightAppend NOTIFY translationsUpdated)
|
||||
|
||||
public:
|
||||
explicit LanguageUiController(SettingsController* settingsController,
|
||||
LanguageModel* languageModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void changeLanguage(const LanguageSettings::AvailableLanguageEnum language);
|
||||
void onAppLanguageChanged(const QLocale &locale);
|
||||
int getCurrentLanguageIndex() const;
|
||||
int getLineHeightAppend() const;
|
||||
QString getCurrentLanguageName() const;
|
||||
QString getCurrentSiteUrl(const QString &path = "") const;
|
||||
QString getCurrentDocsUrl(const QString &path = "") const;
|
||||
LanguageSettings::AvailableLanguageEnum getSystemLanguageEnum() const;
|
||||
|
||||
signals:
|
||||
void updateTranslations(const QLocale &locale);
|
||||
void translationsUpdated();
|
||||
|
||||
private:
|
||||
QString getLocalLanguageName(const LanguageSettings::AvailableLanguageEnum language) const;
|
||||
QLocale languageEnumToLocale(const LanguageSettings::AvailableLanguageEnum language) const;
|
||||
|
||||
SettingsController* m_settingsController;
|
||||
LanguageModel* m_languageModel;
|
||||
};
|
||||
|
||||
#endif // LANGUAGEUICONTROLLER_H
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#include "focusController.h"
|
||||
#include "utils/qmlUtils.h"
|
||||
#include "ui/utils/qmlUtils.h"
|
||||
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickWindow>
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef FOCUSCONTROLLER_H
|
||||
#define FOCUSCONTROLLER_H
|
||||
|
||||
#include "ui/controllers/listViewFocusController.h"
|
||||
#include "ui/controllers/qml/listViewFocusController.h"
|
||||
|
||||
#include <QQmlApplicationEngine>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#include "listViewFocusController.h"
|
||||
#include "utils/qmlUtils.h"
|
||||
#include "ui/utils/qmlUtils.h"
|
||||
|
||||
#include <QQuickWindow>
|
||||
|
||||
+95
-13
@@ -1,6 +1,7 @@
|
||||
#include "pageController.h"
|
||||
#include "utils/converter.h"
|
||||
#include "core/errorstrings.h"
|
||||
|
||||
#include "ui/utils/converter.h"
|
||||
#include "core/utils/errorStrings.h"
|
||||
#if defined(MACOS_NE)
|
||||
#include "platforms/ios/ios_controller.h"
|
||||
#endif
|
||||
@@ -15,16 +16,29 @@
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
#if defined Q_OS_MAC
|
||||
#include "ui/macos_util.h"
|
||||
#include "ui/utils/macosUtil.h"
|
||||
#endif
|
||||
|
||||
PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
|
||||
PageController::PageController(ServersController* serversController,
|
||||
SettingsController* settingsController,
|
||||
QObject *parent)
|
||||
: QObject(parent), m_serversController(serversController), m_settingsController(settingsController)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
auto initialPageNavigationBarColor = getInitialPageNavigationBarColor();
|
||||
AndroidController::instance()->setNavigationBarColor(initialPageNavigationBarColor);
|
||||
|
||||
connect(AndroidController::instance(), &AndroidController::imeInsetsChanged, this, [this](int heightDp) {
|
||||
m_imeHeight = heightDp;
|
||||
emit imeHeightChanged(heightDp);
|
||||
emit safeAreaBottomMarginChanged();
|
||||
});
|
||||
connect(AndroidController::instance(), &AndroidController::systemBarsInsetsChanged, this, [this](int navBarHeightDp, int statusBarHeightDp) {
|
||||
m_cachedNavigationBarHeight = navBarHeightDp;
|
||||
m_cachedStatusBarHeight = statusBarHeightDp;
|
||||
emit safeAreaBottomMarginChanged();
|
||||
emit safeAreaTopMarginChanged();
|
||||
});
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_MACX
|
||||
@@ -43,10 +57,9 @@ PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
|
||||
|
||||
bool PageController::isStartPageVisible()
|
||||
{
|
||||
if (m_serversModel->getServersCount()) {
|
||||
if (m_serversModel->getDefaultServerIndex() < 0) {
|
||||
auto defaultServerIndex = m_serversModel->index(0);
|
||||
m_serversModel->setData(defaultServerIndex, true, ServersModel::Roles::IsDefaultRole);
|
||||
if (m_serversController->getServersCount()) {
|
||||
if (m_serversController->getDefaultServerIndex() < 0) {
|
||||
m_serversController->setDefaultServerIndex(0);
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
@@ -63,7 +76,6 @@ QString PageController::getPagePath(PageLoader::PageEnum page)
|
||||
|
||||
void PageController::closeWindow()
|
||||
{
|
||||
// On mobile platforms, quit app on close; on desktop, just hide window
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
qApp->quit();
|
||||
#else
|
||||
@@ -97,7 +109,7 @@ void PageController::keyPressEvent(Qt::Key key)
|
||||
|
||||
unsigned int PageController::getInitialPageNavigationBarColor()
|
||||
{
|
||||
if (m_serversModel->getServersCount()) {
|
||||
if (m_serversController->getServersCount()) {
|
||||
return 0xFF1C1D21;
|
||||
} else {
|
||||
return 0xFF0E0E11;
|
||||
@@ -113,7 +125,7 @@ void PageController::updateNavigationBarColor(const int color)
|
||||
|
||||
void PageController::showOnStartup()
|
||||
{
|
||||
if (!m_settings->isStartMinimized()) {
|
||||
if (!m_settingsController->isStartMinimizedEnabled()) {
|
||||
emit raiseMainWindow();
|
||||
} else {
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
@@ -165,6 +177,76 @@ int PageController::decrementDrawerDepth()
|
||||
}
|
||||
}
|
||||
|
||||
bool PageController::isEdgeToEdgeEnabled()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (!m_edgeToEdgeCached) {
|
||||
m_cachedEdgeToEdgeEnabled = AndroidController::instance()->isEdgeToEdgeEnabled();
|
||||
m_edgeToEdgeCached = true;
|
||||
}
|
||||
return m_cachedEdgeToEdgeEnabled;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int PageController::getStatusBarHeight()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (m_cachedStatusBarHeight < 0) {
|
||||
m_cachedStatusBarHeight = AndroidController::instance()->getStatusBarHeight();
|
||||
}
|
||||
return m_cachedStatusBarHeight;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int PageController::getNavigationBarHeight()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (m_cachedNavigationBarHeight < 0) {
|
||||
m_cachedNavigationBarHeight = AndroidController::instance()->getNavigationBarHeight();
|
||||
}
|
||||
return m_cachedNavigationBarHeight;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int PageController::getSafeAreaTopMargin()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (isEdgeToEdgeEnabled()) {
|
||||
int height = getStatusBarHeight();
|
||||
int result = height > 0 ? height : 40;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PageController::getSafeAreaBottomMargin()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (isEdgeToEdgeEnabled()) {
|
||||
if (m_imeHeight > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int height = getNavigationBarHeight();
|
||||
int result = height > 0 ? height : 56;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PageController::getImeHeight()
|
||||
{
|
||||
return m_imeHeight;
|
||||
}
|
||||
|
||||
void PageController::onShowErrorMessage(ErrorCode errorCode)
|
||||
{
|
||||
const auto fullErrorMessage = errorString(errorCode);
|
||||
+31
-9
@@ -4,8 +4,11 @@
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "core/defs.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
|
||||
namespace PageLoader
|
||||
{
|
||||
@@ -62,8 +65,6 @@ namespace PageLoader
|
||||
PageSetupWizardApiFreeInfo,
|
||||
|
||||
PageProtocolOpenVpnSettings,
|
||||
PageProtocolShadowSocksSettings,
|
||||
PageProtocolCloakSettings,
|
||||
PageProtocolXraySettings,
|
||||
PageProtocolWireGuardSettings,
|
||||
PageProtocolAwgSettings,
|
||||
@@ -93,9 +94,14 @@ class PageController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageController(const QSharedPointer<ServersModel> &serversModel, const std::shared_ptr<Settings> &settings,
|
||||
explicit PageController(ServersController* serversController,
|
||||
SettingsController* settingsController,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(int safeAreaTopMargin READ getSafeAreaTopMargin NOTIFY safeAreaTopMarginChanged)
|
||||
Q_PROPERTY(int safeAreaBottomMargin READ getSafeAreaBottomMargin NOTIFY safeAreaBottomMarginChanged)
|
||||
Q_PROPERTY(int imeHeight READ getImeHeight NOTIFY imeHeightChanged)
|
||||
|
||||
public slots:
|
||||
bool isStartPageVisible();
|
||||
QString getPagePath(PageLoader::PageEnum page);
|
||||
@@ -119,6 +125,13 @@ public slots:
|
||||
int incrementDrawerDepth();
|
||||
int decrementDrawerDepth();
|
||||
|
||||
bool isEdgeToEdgeEnabled();
|
||||
int getStatusBarHeight();
|
||||
int getNavigationBarHeight();
|
||||
int getSafeAreaTopMargin();
|
||||
int getSafeAreaBottomMargin();
|
||||
int getImeHeight();
|
||||
|
||||
private slots:
|
||||
void onShowErrorMessage(amnezia::ErrorCode errorCode);
|
||||
|
||||
@@ -154,14 +167,23 @@ signals:
|
||||
void escapePressed();
|
||||
void closeTopDrawer();
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
void imeHeightChanged(int height);
|
||||
void safeAreaTopMarginChanged();
|
||||
void safeAreaBottomMarginChanged();
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
private:
|
||||
ServersController* m_serversController;
|
||||
SettingsController* m_settingsController;
|
||||
|
||||
bool m_isTriggeredByConnectButton;
|
||||
|
||||
int m_drawerDepth = 0;
|
||||
|
||||
mutable int m_cachedStatusBarHeight = -1;
|
||||
mutable int m_cachedNavigationBarHeight = -1;
|
||||
mutable bool m_cachedEdgeToEdgeEnabled = false;
|
||||
mutable bool m_edgeToEdgeCached = false;
|
||||
int m_imeHeight = 0;
|
||||
};
|
||||
|
||||
#endif // PAGECONTROLLER_H
|
||||
#endif
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "exportUiController.h"
|
||||
|
||||
#include "../systemController.h"
|
||||
|
||||
ExportUiController::ExportUiController(ExportController* exportController, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_exportController(exportController)
|
||||
{
|
||||
}
|
||||
|
||||
void ExportUiController::generateFullAccessConfig(int serverIndex)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
auto result = m_exportController->generateFullAccessConfig(serverIndex);
|
||||
applyExportResult(result);
|
||||
}
|
||||
|
||||
void ExportUiController::generateConnectionConfig(int serverIndex, int containerIndex, const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
auto result = m_exportController->generateConnectionConfig(serverIndex, containerIndex, clientName);
|
||||
applyExportResult(result);
|
||||
}
|
||||
|
||||
void ExportUiController::generateOpenVpnConfig(int serverIndex, const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
auto result = m_exportController->generateOpenVpnConfig(serverIndex, clientName);
|
||||
applyExportResult(result);
|
||||
}
|
||||
|
||||
void ExportUiController::generateWireGuardConfig(int serverIndex, const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
auto result = m_exportController->generateWireGuardConfig(serverIndex, clientName);
|
||||
applyExportResult(result);
|
||||
}
|
||||
|
||||
void ExportUiController::generateAwgConfig(int serverIndex, int containerIndex, const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
auto result = m_exportController->generateAwgConfig(serverIndex, containerIndex, clientName);
|
||||
applyExportResult(result);
|
||||
}
|
||||
|
||||
|
||||
void ExportUiController::generateXrayConfig(int serverIndex, const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
auto result = m_exportController->generateXrayConfig(serverIndex, clientName);
|
||||
applyExportResult(result);
|
||||
}
|
||||
|
||||
QString ExportUiController::getConfig()
|
||||
{
|
||||
return m_config;
|
||||
}
|
||||
|
||||
QString ExportUiController::getNativeConfigString()
|
||||
{
|
||||
return m_nativeConfigString;
|
||||
}
|
||||
|
||||
QList<QString> ExportUiController::getQrCodes()
|
||||
{
|
||||
return m_qrCodes;
|
||||
}
|
||||
|
||||
void ExportUiController::exportConfig(const QString &fileName)
|
||||
{
|
||||
SystemController::saveFile(fileName, m_config);
|
||||
}
|
||||
|
||||
void ExportUiController::updateClientManagementModel(int serverIndex, int containerIndex)
|
||||
{
|
||||
m_exportController->updateClientManagementModel(serverIndex, containerIndex);
|
||||
}
|
||||
|
||||
void ExportUiController::revokeConfig(int row, int serverIndex, int containerIndex)
|
||||
{
|
||||
m_exportController->revokeConfig(row, serverIndex, containerIndex);
|
||||
emit revokeConfigFinished();
|
||||
}
|
||||
|
||||
void ExportUiController::renameClient(int row, const QString &clientName, int serverIndex, int containerIndex)
|
||||
{
|
||||
m_exportController->renameClient(row, clientName, serverIndex, containerIndex);
|
||||
}
|
||||
|
||||
int ExportUiController::getQrCodesCount()
|
||||
{
|
||||
return m_qrCodes.size();
|
||||
}
|
||||
|
||||
void ExportUiController::clearPreviousConfig()
|
||||
{
|
||||
m_config.clear();
|
||||
m_nativeConfigString.clear();
|
||||
m_qrCodes.clear();
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportUiController::applyExportResult(const ExportController::ExportResult &result)
|
||||
{
|
||||
if (result.errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(result.errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
m_config = result.config;
|
||||
m_nativeConfigString = result.nativeConfigString;
|
||||
m_qrCodes = result.qrCodes;
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef EXPORTUICONTROLLER_H
|
||||
#define EXPORTUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/controllers/selfhosted/exportController.h"
|
||||
|
||||
class ExportUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExportUiController(ExportController* exportController, QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QList<QString> 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(int serverIndex);
|
||||
void generateConnectionConfig(int serverIndex, int containerIndex, const QString &clientName);
|
||||
void generateOpenVpnConfig(int serverIndex, const QString &clientName);
|
||||
void generateWireGuardConfig(int serverIndex, const QString &clientName);
|
||||
void generateAwgConfig(int serverIndex, int containerIndex, const QString &clientName);
|
||||
void generateXrayConfig(int serverIndex, const QString &clientName);
|
||||
|
||||
QString getConfig();
|
||||
QString getNativeConfigString();
|
||||
QList<QString> getQrCodes();
|
||||
|
||||
void exportConfig(const QString &fileName);
|
||||
|
||||
void updateClientManagementModel(int serverIndex, int containerIndex);
|
||||
void revokeConfig(int row, int serverIndex, int containerIndex);
|
||||
void renameClient(int row, const QString &clientName, int serverIndex, int containerIndex);
|
||||
|
||||
signals:
|
||||
void generateConfig(int type);
|
||||
void revokeConfigFinished();
|
||||
void exportErrorOccurred(const QString &errorMessage);
|
||||
void exportErrorOccurred(ErrorCode errorCode);
|
||||
|
||||
void exportConfigChanged();
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
int getQrCodesCount();
|
||||
void clearPreviousConfig();
|
||||
void applyExportResult(const ExportController::ExportResult &result);
|
||||
|
||||
ExportController* m_exportController;
|
||||
|
||||
QString m_config;
|
||||
QString m_nativeConfigString;
|
||||
QList<QString> m_qrCodes;
|
||||
};
|
||||
|
||||
#endif // EXPORTUICONTROLLER_H
|
||||
+493
@@ -0,0 +1,493 @@
|
||||
#include "installUiController.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QEventLoop>
|
||||
#include <QJsonObject>
|
||||
#include <QRandomGenerator>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "core/utils/api/apiUtils.h"
|
||||
#include "core/controllers/selfhosted/installController.h"
|
||||
#include "core/utils/selfhosted/sshSession.h"
|
||||
#include "core/utils/networkUtilities.h"
|
||||
#include "logger.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/protocols/protocolUtils.h"
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include "ui/models/protocols/awgConfigModel.h"
|
||||
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||
#include "ui/models/protocols/openvpnConfigModel.h"
|
||||
#include "ui/models/protocols/xrayConfigModel.h"
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include "ui/models/protocols/ikev2ConfigModel.h"
|
||||
#endif
|
||||
#include "ui/models/services/sftpConfigModel.h"
|
||||
#include "ui/models/services/socks5ProxyConfigModel.h"
|
||||
#include "ui/models/services/torConfigModel.h"
|
||||
#include "core/utils/utilities.h"
|
||||
#include "core/models/serverConfig.h"
|
||||
#include "core/models/containerConfig.h"
|
||||
#include "core/models/protocols/awgProtocolConfig.h"
|
||||
#include "core/models/protocols/wireGuardProtocolConfig.h"
|
||||
#include "core/models/protocols/openVpnProtocolConfig.h"
|
||||
#include "core/models/protocols/xrayProtocolConfig.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
Logger logger("InstallUiController");
|
||||
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serverCountryName[] = "server_country_name";
|
||||
constexpr char availableCountries[] = "available_countries";
|
||||
|
||||
constexpr char apiConfig[] = "api_config";
|
||||
constexpr char authData[] = "auth_data";
|
||||
}
|
||||
}
|
||||
|
||||
InstallUiController::InstallUiController(InstallController *installController,
|
||||
ServersController *serversController,
|
||||
SettingsController *settingsController,
|
||||
ProtocolsModel *protocolsModel,
|
||||
UsersController *usersController,
|
||||
AwgConfigModel *awgConfigModel,
|
||||
WireGuardConfigModel *wireGuardConfigModel,
|
||||
OpenVpnConfigModel *openVpnConfigModel,
|
||||
XrayConfigModel *xrayConfigModel,
|
||||
TorConfigModel *torConfigModel,
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Ikev2ConfigModel *ikev2ConfigModel,
|
||||
#endif
|
||||
SftpConfigModel *sftpConfigModel,
|
||||
Socks5ProxyConfigModel *socks5ConfigModel,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_installController(installController),
|
||||
m_serversController(serversController),
|
||||
m_settingsController(settingsController),
|
||||
m_protocolModel(protocolsModel),
|
||||
m_usersController(usersController),
|
||||
m_awgConfigModel(awgConfigModel),
|
||||
m_wireGuardConfigModel(wireGuardConfigModel),
|
||||
m_openVpnConfigModel(openVpnConfigModel),
|
||||
m_xrayConfigModel(xrayConfigModel),
|
||||
m_torConfigModel(torConfigModel),
|
||||
#ifdef Q_OS_WINDOWS
|
||||
m_ikev2ConfigModel(ikev2ConfigModel),
|
||||
#endif
|
||||
m_sftpConfigModel(sftpConfigModel),
|
||||
m_socks5ConfigModel(socks5ConfigModel)
|
||||
{
|
||||
connect(m_installController, &InstallController::configValidated, this, &InstallUiController::configValidated);
|
||||
connect(m_installController, &InstallController::validationErrorOccurred, this, [this](ErrorCode errorCode) {
|
||||
if (errorCode == ErrorCode::NoInstalledContainersError) {
|
||||
emit noInstalledContainers();
|
||||
} else {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InstallUiController::~InstallUiController()
|
||||
{
|
||||
}
|
||||
|
||||
void InstallUiController::install(DockerContainer container, int port, TransportProto transportProto, int serverIndex)
|
||||
{
|
||||
const bool isNewServer = serverIndex < 0;
|
||||
|
||||
ServerCredentials serverCredentials;
|
||||
if (isNewServer) {
|
||||
serverCredentials = m_processedServerCredentials;
|
||||
} else {
|
||||
serverCredentials = m_serversController->getServerCredentials(serverIndex);
|
||||
m_processedServerCredentials = ServerCredentials();
|
||||
}
|
||||
|
||||
QMap<DockerContainer, QJsonObject> preparedContainers;
|
||||
QString finishMessage;
|
||||
ErrorCode errorCode;
|
||||
|
||||
if (isNewServer) {
|
||||
int existingServerIndex = -1;
|
||||
if (m_installController->isServerAlreadyExists(serverCredentials, existingServerIndex)) {
|
||||
emit serverAlreadyExists(existingServerIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasContainerInstalled = false;
|
||||
errorCode = m_installController->installServer(serverCredentials, container, port, transportProto, wasContainerInstalled);
|
||||
if (errorCode) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
int serverIndex = m_serversController->getServersCount() - 1;
|
||||
ServerConfig serverConfig = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containers = serverConfig.containers();
|
||||
int containersCount = containers.size();
|
||||
|
||||
if (wasContainerInstalled) {
|
||||
finishMessage = tr("%1 installed successfully. ").arg(ContainerUtils::containerHumanNames().value(container));
|
||||
} else {
|
||||
finishMessage = tr("%1 is already installed on the server. ").arg(ContainerUtils::containerHumanNames().value(container));
|
||||
}
|
||||
|
||||
if (containersCount > 1) {
|
||||
finishMessage += tr("\nAdded containers that were already installed on the server");
|
||||
}
|
||||
|
||||
emit installServerFinished(finishMessage);
|
||||
} else {
|
||||
ServerConfig serverConfig = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containers = serverConfig.containers();
|
||||
int containersCount = containers.size();
|
||||
|
||||
bool wasContainerInstalled = false;
|
||||
errorCode = m_installController->installContainer(serverIndex, container, port, transportProto,
|
||||
wasContainerInstalled);
|
||||
if (errorCode) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
ServerConfig newServerConfig = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> newContainers = newServerConfig.containers();
|
||||
int newContainersCount = newContainers.size();
|
||||
|
||||
bool hasNewContainers = (newContainersCount - containersCount) > (wasContainerInstalled ? 1 : 0);
|
||||
|
||||
if (wasContainerInstalled) {
|
||||
finishMessage = tr("%1 installed successfully. ").arg(ContainerUtils::containerHumanNames().value(container));
|
||||
} else {
|
||||
finishMessage = tr("%1 is already installed on the server. ").arg(ContainerUtils::containerHumanNames().value(container));
|
||||
}
|
||||
|
||||
if (hasNewContainers) {
|
||||
finishMessage += tr("\nAlready installed containers were found on the server. "
|
||||
"All installed containers have been added to the application");
|
||||
}
|
||||
|
||||
emit installContainerFinished(finishMessage, ContainerUtils::containerService(container) == ServiceType::Other);
|
||||
}
|
||||
}
|
||||
|
||||
void InstallUiController::scanServerForInstalledContainers(int serverIndex)
|
||||
{
|
||||
ServerConfig serverBefore = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containersBefore = serverBefore.containers();
|
||||
int containersCountBefore = containersBefore.size();
|
||||
|
||||
ErrorCode errorCode = m_installController->scanServerForInstalledContainers(serverIndex);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
ServerConfig serverAfter = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containersAfter = serverAfter.containers();
|
||||
int containersCountAfter = containersAfter.size();
|
||||
|
||||
bool isInstalledContainerAdded = containersCountAfter > containersCountBefore;
|
||||
emit scanServerFinished(isInstalledContainerAdded);
|
||||
return;
|
||||
}
|
||||
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
void InstallUiController::updateContainer(int serverIndex, int containerIndex, int protocolIndex)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
|
||||
Proto protocolType = static_cast<Proto>(protocolIndex);
|
||||
|
||||
ContainerConfig containerConfig;
|
||||
containerConfig.container = container;
|
||||
|
||||
switch (protocolType) {
|
||||
case Proto::Awg: {
|
||||
containerConfig.protocolConfig = m_awgConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::WireGuard: {
|
||||
containerConfig.protocolConfig = m_wireGuardConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::OpenVpn: {
|
||||
containerConfig.protocolConfig = m_openVpnConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::Xray:
|
||||
case Proto::SSXray: {
|
||||
containerConfig.protocolConfig = m_xrayConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::TorWebSite: {
|
||||
containerConfig.protocolConfig = m_torConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::Sftp: {
|
||||
containerConfig.protocolConfig = m_sftpConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
case Proto::Socks5Proxy: {
|
||||
containerConfig.protocolConfig = m_socks5ConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
case Proto::Ikev2: {
|
||||
containerConfig.protocolConfig = m_ikev2ConfigModel->getProtocolConfig();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return;
|
||||
}
|
||||
ContainerConfig oldContainerConfig = m_serversController->getContainerConfig(serverIndex, container);
|
||||
|
||||
ErrorCode errorCode = m_installController->updateContainer(serverIndex, container, oldContainerConfig, containerConfig);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
ContainerConfig updatedConfig = m_serversController->getContainerConfig(serverIndex, container);
|
||||
m_protocolModel->updateModel(updatedConfig);
|
||||
|
||||
auto defaultContainer = m_serversController->getServerConfig(serverIndex).defaultContainer();
|
||||
if ((serverIndex == m_serversController->getDefaultServerIndex()) && (container == defaultContainer)) {
|
||||
emit currentContainerUpdated();
|
||||
} else {
|
||||
emit updateContainerFinished(tr("Settings updated successfully"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
void InstallUiController::rebootServer(int serverIndex)
|
||||
{
|
||||
QString serverName = m_serversController->getServerConfig(serverIndex).displayName();
|
||||
|
||||
const auto errorCode = m_installController->rebootServer(serverIndex);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
emit rebootServerFinished(tr("Server '%1' was rebooted").arg(serverName));
|
||||
} else {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
void InstallUiController::removeServer(int serverIndex)
|
||||
{
|
||||
QString serverName = m_serversController->getServerConfig(serverIndex).displayName();
|
||||
|
||||
m_serversController->removeServer(serverIndex);
|
||||
emit removeServerFinished(tr("Server '%1' was removed").arg(serverName));
|
||||
}
|
||||
|
||||
void InstallUiController::removeAllContainers(int serverIndex)
|
||||
{
|
||||
QString serverName = m_serversController->getServerConfig(serverIndex).displayName();
|
||||
|
||||
ErrorCode errorCode = m_installController->removeAllContainers(serverIndex);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
emit removeAllContainersFinished(tr("All containers from server '%1' have been removed").arg(serverName));
|
||||
return;
|
||||
}
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
void InstallUiController::removeContainer(int serverIndex, int containerIndex)
|
||||
{
|
||||
QString serverName = m_serversController->getServerConfig(serverIndex).displayName();
|
||||
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
QString containerName = ContainerUtils::containerHumanNames().value(container);
|
||||
|
||||
ErrorCode errorCode = m_installController->removeContainer(serverIndex, container);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
|
||||
emit removeContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName, serverName));
|
||||
return;
|
||||
}
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
|
||||
void InstallUiController::clearCachedProfile(int serverIndex, int containerIndex)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
if (ContainerUtils::containerService(container) == ServiceType::Other) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_installController->clearCachedProfile(serverIndex, container);
|
||||
|
||||
emit cachedProfileCleared(tr("%1 cached profile cleared").arg(ContainerUtils::containerHumanNames().value(container)));
|
||||
ContainerConfig updatedConfig = m_serversController->getContainerConfig(serverIndex, container);
|
||||
m_protocolModel->updateModel(updatedConfig);
|
||||
}
|
||||
|
||||
QRegularExpression InstallUiController::ipAddressRegExp()
|
||||
{
|
||||
return NetworkUtilities::ipAddressRegExp();
|
||||
}
|
||||
|
||||
void InstallUiController::clearProcessedServerCredentials()
|
||||
{
|
||||
m_processedServerCredentials = ServerCredentials();
|
||||
}
|
||||
|
||||
void InstallUiController::setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData)
|
||||
{
|
||||
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_processedServerCredentials.userName = userName;
|
||||
m_processedServerCredentials.secretData = secretData;
|
||||
}
|
||||
|
||||
void InstallUiController::mountSftpDrive(int serverIndex, const QString &port, const QString &password, const QString &username)
|
||||
{
|
||||
ServerCredentials serverCredentials = m_serversController->getServerCredentials(serverIndex);
|
||||
ErrorCode errorCode = m_installController->mountSftpDrive(serverCredentials, port, password, username);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallUiController::checkSshConnection()
|
||||
{
|
||||
m_privateKeyPassphrase = "";
|
||||
|
||||
auto passphraseCallback = [this]() {
|
||||
emit passphraseRequestStarted();
|
||||
QEventLoop loop;
|
||||
QObject::connect(this, &InstallUiController::passphraseRequestFinished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
return m_privateKeyPassphrase;
|
||||
};
|
||||
|
||||
QString output;
|
||||
ErrorCode errorCode = m_installController->checkSshConnection(m_processedServerCredentials, output, passphraseCallback);
|
||||
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit installationErrorOccurred(errorCode);
|
||||
return false;
|
||||
} else {
|
||||
if (output.contains(tr("Please login as the user"))) {
|
||||
output.replace("\n", "");
|
||||
emit wrongInstallationUser(output);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstallUiController::setEncryptedPassphrase(QString passphrase)
|
||||
{
|
||||
m_privateKeyPassphrase = passphrase;
|
||||
emit passphraseRequestFinished();
|
||||
}
|
||||
|
||||
void InstallUiController::addEmptyServer()
|
||||
{
|
||||
SelfHostedServerConfig serverConfig;
|
||||
serverConfig.hostName = m_processedServerCredentials.hostName;
|
||||
serverConfig.userName = m_processedServerCredentials.userName;
|
||||
serverConfig.password = m_processedServerCredentials.secretData;
|
||||
serverConfig.port = m_processedServerCredentials.port;
|
||||
serverConfig.description = m_settingsController->nextAvailableServerName();
|
||||
serverConfig.defaultContainer = DockerContainer::None;
|
||||
|
||||
m_serversController->addServer(ServerConfig(serverConfig));
|
||||
emit installServerFinished(tr("Server added successfully"));
|
||||
}
|
||||
|
||||
void InstallUiController::validateConfig()
|
||||
{
|
||||
int serverIndex = m_serversController->getDefaultServerIndex();
|
||||
m_installController->validateConfig(serverIndex);
|
||||
}
|
||||
|
||||
void InstallUiController::updateProtocols(int serverIndex, int containerIndex)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
ContainerConfig containerConfig = m_serversController->getContainerConfig(serverIndex, container);
|
||||
containerConfig.container = container;
|
||||
m_protocolModel->updateModel(containerConfig);
|
||||
}
|
||||
|
||||
void InstallUiController::openServerSettings(int serverIndex, int containerIndex, int protocolIndex)
|
||||
{
|
||||
updateProtocolConfigModel(serverIndex, containerIndex, protocolIndex);
|
||||
}
|
||||
|
||||
void InstallUiController::openClientSettings(int serverIndex, int containerIndex, int protocolIndex)
|
||||
{
|
||||
updateProtocolConfigModel(serverIndex, containerIndex, protocolIndex);
|
||||
}
|
||||
|
||||
int InstallUiController::defaultPort(int protocolIndex)
|
||||
{
|
||||
Proto proto = static_cast<Proto>(protocolIndex);
|
||||
return ProtocolUtils::defaultPort(proto);
|
||||
}
|
||||
|
||||
int InstallUiController::getPortForInstall(int protocolIndex)
|
||||
{
|
||||
Proto proto = static_cast<Proto>(protocolIndex);
|
||||
return ProtocolUtils::getPortForInstall(proto);
|
||||
}
|
||||
|
||||
int InstallUiController::defaultTransportProto(int protocolIndex)
|
||||
{
|
||||
Proto proto = static_cast<Proto>(protocolIndex);
|
||||
return static_cast<int>(ProtocolUtils::defaultTransportProto(proto));
|
||||
}
|
||||
|
||||
bool InstallUiController::defaultPortChangeable(int protocolIndex)
|
||||
{
|
||||
Proto proto = static_cast<Proto>(protocolIndex);
|
||||
return ProtocolUtils::defaultPortChangeable(proto);
|
||||
}
|
||||
|
||||
bool InstallUiController::defaultTransportProtoChangeable(int protocolIndex)
|
||||
{
|
||||
Proto proto = static_cast<Proto>(protocolIndex);
|
||||
return ProtocolUtils::defaultTransportProtoChangeable(proto);
|
||||
}
|
||||
|
||||
void InstallUiController::updateProtocolConfigModel(int serverIndex, int containerIndex, int protocolIndex)
|
||||
{
|
||||
DockerContainer container = static_cast<DockerContainer>(containerIndex);
|
||||
ContainerConfig containerConfig = m_serversController->getContainerConfig(serverIndex, container);
|
||||
containerConfig.container = container;
|
||||
Proto protocolType = static_cast<Proto>(protocolIndex);
|
||||
|
||||
auto updateIfPresent = [&](auto* model, auto* config) {
|
||||
if (model && config) model->updateModel(container, *config);
|
||||
};
|
||||
|
||||
switch (protocolType) {
|
||||
case Proto::Awg: updateIfPresent(m_awgConfigModel, containerConfig.getAwgProtocolConfig()); break;
|
||||
case Proto::WireGuard: updateIfPresent(m_wireGuardConfigModel, containerConfig.getWireGuardProtocolConfig()); break;
|
||||
case Proto::OpenVpn: updateIfPresent(m_openVpnConfigModel, containerConfig.getOpenVpnProtocolConfig()); break;
|
||||
case Proto::Xray: updateIfPresent(m_xrayConfigModel, containerConfig.getXrayProtocolConfig()); break;
|
||||
case Proto::TorWebSite: updateIfPresent(m_torConfigModel, containerConfig.getTorProtocolConfig()); break;
|
||||
case Proto::Sftp: updateIfPresent(m_sftpConfigModel, containerConfig.getSftpProtocolConfig()); break;
|
||||
case Proto::Socks5Proxy: updateIfPresent(m_socks5ConfigModel, containerConfig.getSocks5ProxyProtocolConfig()); break;
|
||||
#ifdef Q_OS_WINDOWS
|
||||
case Proto::Ikev2: updateIfPresent(m_ikev2ConfigModel, containerConfig.getIkev2ProtocolConfig()); break;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
#ifndef INSTALLUICONTROLLER_H
|
||||
#define INSTALLUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "core/controllers/selfhosted/usersController.h"
|
||||
#include "core/controllers/selfhosted/installController.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "core/models/containerConfig.h"
|
||||
#include "ui/models/protocolsModel.h"
|
||||
#include "ui/models/protocols/awgConfigModel.h"
|
||||
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||
#include "ui/models/protocols/openvpnConfigModel.h"
|
||||
#include "ui/models/protocols/xrayConfigModel.h"
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include "ui/models/protocols/ikev2ConfigModel.h"
|
||||
#endif
|
||||
#include "ui/models/services/sftpConfigModel.h"
|
||||
#include "ui/models/services/socks5ProxyConfigModel.h"
|
||||
#include "ui/models/services/torConfigModel.h"
|
||||
#include "core/models/protocols/sftpProtocolConfig.h"
|
||||
#include "core/models/protocols/socks5ProxyProtocolConfig.h"
|
||||
|
||||
class InstallUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InstallUiController(InstallController* installController,
|
||||
ServersController* serversController,
|
||||
SettingsController* settingsController,
|
||||
ProtocolsModel* protocolsModel,
|
||||
UsersController* usersController,
|
||||
AwgConfigModel* awgConfigModel,
|
||||
WireGuardConfigModel* wireGuardConfigModel,
|
||||
OpenVpnConfigModel* openVpnConfigModel,
|
||||
XrayConfigModel* xrayConfigModel,
|
||||
TorConfigModel* torConfigModel,
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Ikev2ConfigModel* ikev2ConfigModel,
|
||||
#endif
|
||||
SftpConfigModel* sftpConfigModel,
|
||||
Socks5ProxyConfigModel* socks5ConfigModel,
|
||||
QObject *parent = nullptr);
|
||||
~InstallUiController();
|
||||
|
||||
public slots:
|
||||
void install(DockerContainer container, int port, TransportProto transportProto, int serverIndex);
|
||||
void setProcessedServerCredentials(const QString &hostName, const QString &userName, const QString &secretData);
|
||||
void clearProcessedServerCredentials();
|
||||
|
||||
void scanServerForInstalledContainers(int serverIndex);
|
||||
|
||||
void updateContainer(int serverIndex, int containerIndex, int protocolIndex);
|
||||
|
||||
void removeServer(int serverIndex);
|
||||
void rebootServer(int serverIndex);
|
||||
void removeAllContainers(int serverIndex);
|
||||
void removeContainer(int serverIndex, int containerIndex);
|
||||
|
||||
void clearCachedProfile(int serverIndex, int containerIndex);
|
||||
|
||||
QRegularExpression ipAddressRegExp();
|
||||
|
||||
void mountSftpDrive(int serverIndex, const QString &port, const QString &password, const QString &username);
|
||||
|
||||
bool checkSshConnection();
|
||||
|
||||
void setEncryptedPassphrase(QString passphrase);
|
||||
|
||||
void addEmptyServer();
|
||||
|
||||
void validateConfig();
|
||||
|
||||
Q_INVOKABLE void updateProtocols(int serverIndex, int containerIndex);
|
||||
|
||||
void openServerSettings(int serverIndex, int containerIndex, int protocolIndex);
|
||||
void openClientSettings(int serverIndex, int containerIndex, int protocolIndex);
|
||||
|
||||
int defaultPort(int protocolIndex);
|
||||
int getPortForInstall(int protocolIndex);
|
||||
int defaultTransportProto(int protocolIndex);
|
||||
bool defaultPortChangeable(int protocolIndex);
|
||||
bool defaultTransportProtoChangeable(int protocolIndex);
|
||||
|
||||
signals:
|
||||
void installContainerFinished(const QString &finishMessage, bool isServiceInstall);
|
||||
void installServerFinished(const QString &finishMessage);
|
||||
|
||||
void updateContainerFinished(const QString &message);
|
||||
|
||||
void scanServerFinished(bool isInstalledContainerFound);
|
||||
|
||||
void rebootServerFinished(const QString &finishedMessage);
|
||||
void removeServerFinished(const QString &finishedMessage);
|
||||
void removeAllContainersFinished(const QString &finishedMessage);
|
||||
void removeContainerFinished(const QString &finishedMessage);
|
||||
|
||||
void installationErrorOccurred(ErrorCode errorCode);
|
||||
void wrongInstallationUser(const QString &message);
|
||||
|
||||
void serverAlreadyExists(int serverIndex);
|
||||
|
||||
void passphraseRequestStarted();
|
||||
void passphraseRequestFinished();
|
||||
|
||||
void serverIsBusy(const bool isBusy);
|
||||
void cancelInstallation();
|
||||
|
||||
void currentContainerUpdated();
|
||||
|
||||
void cachedProfileCleared(const QString &message);
|
||||
void apiConfigRemoved(const QString &message);
|
||||
|
||||
void noInstalledContainers();
|
||||
void configValidated(bool isValid);
|
||||
|
||||
private:
|
||||
|
||||
InstallController* m_installController;
|
||||
ServersController* m_serversController;
|
||||
SettingsController* m_settingsController;
|
||||
ProtocolsModel* m_protocolModel;
|
||||
UsersController* m_usersController;
|
||||
|
||||
AwgConfigModel* m_awgConfigModel;
|
||||
WireGuardConfigModel* m_wireGuardConfigModel;
|
||||
OpenVpnConfigModel* m_openVpnConfigModel;
|
||||
XrayConfigModel* m_xrayConfigModel;
|
||||
TorConfigModel* m_torConfigModel;
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Ikev2ConfigModel* m_ikev2ConfigModel;
|
||||
#endif
|
||||
SftpConfigModel* m_sftpConfigModel;
|
||||
Socks5ProxyConfigModel* m_socks5ConfigModel;
|
||||
|
||||
ServerCredentials m_processedServerCredentials;
|
||||
|
||||
QString m_privateKeyPassphrase;
|
||||
|
||||
void updateProtocolConfigModel(int serverIndex, int containerIndex, int protocolIndex);
|
||||
};
|
||||
|
||||
#endif // INSTALLUICONTROLLER_H
|
||||
@@ -0,0 +1,491 @@
|
||||
#include "serversUiController.h"
|
||||
|
||||
#include "core/utils/api/apiEnums.h"
|
||||
#include "core/utils/constants/apiKeys.h"
|
||||
#include "core/utils/constants/apiConstants.h"
|
||||
#include "core/utils/api/apiUtils.h"
|
||||
#include "core/utils/containerEnum.h"
|
||||
#include "core/utils/containers/containerUtils.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/utils/protocolEnum.h"
|
||||
#include "core/protocols/protocolUtils.h"
|
||||
#include "core/utils/constants/configKeys.h"
|
||||
#include "core/utils/constants/protocolConstants.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include "core/models/serverConfig.h"
|
||||
#include "core/models/protocolConfig.h"
|
||||
#include "core/models/containerConfig.h"
|
||||
#include "core/models/protocols/awgProtocolConfig.h"
|
||||
|
||||
using namespace amnezia;
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
{
|
||||
constexpr char apiConfig[] = "api_config";
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
constexpr char serverCountryName[] = "server_country_name";
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
}
|
||||
}
|
||||
|
||||
ServersUiController::ServersUiController(ServersController* serversController,
|
||||
SettingsController* settingsController,
|
||||
ServersModel* serversModel,
|
||||
ContainersModel* containersModel,
|
||||
ContainersModel* defaultServerContainersModel,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_serversController(serversController),
|
||||
m_settingsController(settingsController),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_defaultServerContainersModel(defaultServerContainersModel)
|
||||
{
|
||||
}
|
||||
|
||||
void ServersUiController::removeServer(int index)
|
||||
{
|
||||
m_serversController->removeServer(index);
|
||||
updateModel();
|
||||
}
|
||||
|
||||
void ServersUiController::editServerName(int index, const QString &name)
|
||||
{
|
||||
ServerConfig serverConfig = m_serversController->getServerConfig(index);
|
||||
|
||||
if (serverConfig.isApiV1()) {
|
||||
ApiV1ServerConfig* apiV1 = serverConfig.as<ApiV1ServerConfig>();
|
||||
if (apiV1) {
|
||||
apiV1->name = name;
|
||||
}
|
||||
} else if (serverConfig.isApiV2()) {
|
||||
ApiV2ServerConfig* apiV2 = serverConfig.as<ApiV2ServerConfig>();
|
||||
if (apiV2) {
|
||||
apiV2->name = name;
|
||||
apiV2->nameOverriddenByUser = true;
|
||||
}
|
||||
} else {
|
||||
serverConfig.visit([&name](auto& arg) {
|
||||
arg.description = name;
|
||||
});
|
||||
}
|
||||
|
||||
m_serversController->editServer(index, serverConfig);
|
||||
updateModel();
|
||||
}
|
||||
|
||||
void ServersUiController::setDefaultServerIndex(int index)
|
||||
{
|
||||
m_serversController->setDefaultServerIndex(index);
|
||||
updateModel();
|
||||
emit defaultServerIndexChanged(index);
|
||||
}
|
||||
|
||||
void ServersUiController::setDefaultContainer(int serverIndex, int containerIndex)
|
||||
{
|
||||
auto container = static_cast<DockerContainer>(containerIndex);
|
||||
m_serversController->setDefaultContainer(serverIndex, container);
|
||||
updateModel();
|
||||
}
|
||||
|
||||
void ServersUiController::toggleAmneziaDns(bool enabled)
|
||||
{
|
||||
m_settingsController->toggleAmneziaDns(enabled);
|
||||
updateModel();
|
||||
}
|
||||
|
||||
void ServersUiController::onDefaultServerChanged(int index)
|
||||
{
|
||||
setProcessedServerIndex(index);
|
||||
updateModel();
|
||||
updateDefaultServerContainersModel();
|
||||
emit defaultServerIndexChanged(index);
|
||||
}
|
||||
|
||||
void ServersUiController::updateModel()
|
||||
{
|
||||
int defaultIndex = m_serversController->getDefaultServerIndex();
|
||||
bool wasEmpty = !hasServersFromGatewayApi();
|
||||
int serversCount = m_serversController->getServersCount();
|
||||
|
||||
if (m_processedServerIndex >= serversCount) {
|
||||
setProcessedServerIndex(defaultIndex);
|
||||
} else if (m_processedServerIndex >= 0) {
|
||||
setProcessedServerIndex(m_processedServerIndex);
|
||||
}
|
||||
|
||||
m_serversModel->updateModel(m_serversController->getServers(), defaultIndex, m_settingsController->isAmneziaDnsEnabled());
|
||||
|
||||
|
||||
updateContainersModel();
|
||||
updateDefaultServerContainersModel();
|
||||
|
||||
bool isEmpty = !hasServersFromGatewayApi();
|
||||
if (wasEmpty != isEmpty) {
|
||||
emit hasServersFromGatewayApiChanged();
|
||||
}
|
||||
|
||||
emit defaultServerIndexChanged(defaultIndex);
|
||||
}
|
||||
|
||||
int ServersUiController::getDefaultServerIndex() const
|
||||
{
|
||||
return m_serversController->getDefaultServerIndex();
|
||||
}
|
||||
|
||||
QString ServersUiController::getDefaultServerName() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
return m_serversController->getServerConfig(defaultIndex).displayName();
|
||||
}
|
||||
|
||||
QString ServersUiController::getDefaultServerDefaultContainerName() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
const ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
return ContainerUtils::containerHumanNames().value(server.defaultContainer());
|
||||
}
|
||||
|
||||
QString ServersUiController::getDefaultServerDescriptionCollapsed() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
const ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
QString description = getDefaultServerDescription(server, defaultIndex);
|
||||
|
||||
if (server.isApiConfig()) {
|
||||
return description;
|
||||
}
|
||||
|
||||
DockerContainer container = server.defaultContainer();
|
||||
QString containerName = ContainerUtils::containerHumanNames().value(container);
|
||||
QString protocolVersion;
|
||||
QString hostName = server.hostName();
|
||||
|
||||
if (ContainerUtils::isAwgContainer(container)) {
|
||||
ContainerConfig containerConfig = server.containerConfig(container);
|
||||
if (auto* awgProtocolConfig = containerConfig.getAwgProtocolConfig()) {
|
||||
QString version = awgProtocolConfig->serverConfig.protocolVersion;
|
||||
if (version == protocols::awg::awgV2) {
|
||||
protocolVersion = QObject::tr(" (version 2)");
|
||||
} else if (version == protocols::awg::awgV1_5) {
|
||||
protocolVersion = QObject::tr(" (version 1.5)");
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Awg && !awgProtocolConfig->serverConfig.isThirdPartyConfig) {
|
||||
containerName = "AmneziaWG Legacy";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return description + containerName + protocolVersion + " | " + hostName;
|
||||
}
|
||||
|
||||
QString ServersUiController::getDefaultServerImagePathCollapsed() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
const ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
|
||||
if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
if (!apiV2) return QString();
|
||||
const QString countryCode = apiV2->apiConfig.serverCountryCode;
|
||||
if (countryCode.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString ServersUiController::getDefaultServerDescriptionExpanded() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
const ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
QString description = getDefaultServerDescription(server, defaultIndex);
|
||||
|
||||
if (server.isApiConfig()) {
|
||||
return description;
|
||||
}
|
||||
|
||||
return description + server.hostName();
|
||||
}
|
||||
|
||||
bool ServersUiController::isDefaultServerDefaultContainerHasSplitTunneling() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
const ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
DockerContainer defaultContainer = server.defaultContainer();
|
||||
|
||||
ContainerConfig containerConfig = server.containerConfig(defaultContainer);
|
||||
|
||||
if (defaultContainer == DockerContainer::Awg || defaultContainer == DockerContainer::WireGuard) {
|
||||
auto hasSplitTunnelingFromAllowedIps = [](const QStringList& allowedIps, const QString& nativeConfig) -> bool {
|
||||
bool hasSplitTunneling = !allowedIps.isEmpty() && !allowedIps.contains("0.0.0.0/0");
|
||||
if (!hasSplitTunneling && !nativeConfig.isEmpty()) {
|
||||
hasSplitTunneling = nativeConfig.contains("AllowedIPs")
|
||||
&& !nativeConfig.contains("AllowedIPs = 0.0.0.0/0, ::/0");
|
||||
}
|
||||
return hasSplitTunneling;
|
||||
};
|
||||
|
||||
if (defaultContainer == DockerContainer::Awg) {
|
||||
if (const auto* awgConfig = containerConfig.getAwgProtocolConfig()) {
|
||||
if (awgConfig->hasClientConfig()) {
|
||||
return hasSplitTunnelingFromAllowedIps(
|
||||
awgConfig->clientConfig->allowedIps,
|
||||
awgConfig->clientConfig->nativeConfig
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (defaultContainer == DockerContainer::WireGuard) {
|
||||
if (const auto* wgConfig = containerConfig.getWireGuardProtocolConfig()) {
|
||||
if (wgConfig->hasClientConfig()) {
|
||||
return hasSplitTunnelingFromAllowedIps(
|
||||
wgConfig->clientConfig->allowedIps,
|
||||
wgConfig->clientConfig->nativeConfig
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (defaultContainer == DockerContainer::OpenVpn) {
|
||||
if (const auto* ovpnConfig = containerConfig.getOpenVpnProtocolConfig()) {
|
||||
if (ovpnConfig->hasClientConfig()) {
|
||||
return !ovpnConfig->clientConfig->nativeConfig.isEmpty()
|
||||
&& !ovpnConfig->clientConfig->nativeConfig.contains("redirect-gateway");
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServersUiController::isDefaultServerFromApi() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
const ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
const int configVersion = server.configVersion();
|
||||
return configVersion == apiDefs::ConfigSource::Telegram
|
||||
|| configVersion == apiDefs::ConfigSource::AmneziaGateway;
|
||||
}
|
||||
|
||||
int ServersUiController::getProcessedServerIndex() const
|
||||
{
|
||||
return m_processedServerIndex;
|
||||
}
|
||||
|
||||
int ServersUiController::getProcessedContainerIndex() const
|
||||
{
|
||||
return m_processedContainerIndex;
|
||||
}
|
||||
|
||||
void ServersUiController::setProcessedContainerIndex(int index)
|
||||
{
|
||||
if (m_processedContainerIndex != index) {
|
||||
m_processedContainerIndex = index;
|
||||
m_containersModel->setProcessedContainerIndex(index);
|
||||
emit processedContainerIndexChanged(m_processedContainerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void ServersUiController::setProcessedServerIndex(int index)
|
||||
{
|
||||
if (index >= m_serversController->getServersCount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_processedServerIndex != index) {
|
||||
m_processedServerIndex = index;
|
||||
m_serversModel->setProcessedServerIndex(index);
|
||||
|
||||
if (index >= 0) {
|
||||
updateContainersModel();
|
||||
|
||||
ServerConfig server = m_serversController->getServerConfig(index);
|
||||
setProcessedContainerIndex(static_cast<int>(server.defaultContainer()));
|
||||
|
||||
if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
if (apiV2 && !apiV2->apiConfig.availableCountries.isEmpty()) {
|
||||
emit updateApiCountryModel();
|
||||
}
|
||||
emit updateApiServicesModel();
|
||||
}
|
||||
}
|
||||
|
||||
emit processedServerIndexChanged(m_processedServerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bool ServersUiController::processedServerIsPremium() const
|
||||
{
|
||||
ServerConfig server = m_serversController->getServerConfig(m_processedServerIndex);
|
||||
if (server.isApiV1()) {
|
||||
const ApiV1ServerConfig* apiV1 = server.as<ApiV1ServerConfig>();
|
||||
return apiV1 ? apiV1->isPremium() : false;
|
||||
} else if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
return apiV2 ? (apiV2->isPremium() || apiV2->isExternalPremium()) : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const ServerCredentials ServersUiController::getProcessedServerCredentials() const
|
||||
{
|
||||
return m_serversController->getServerCredentials(m_processedServerIndex);
|
||||
}
|
||||
|
||||
bool ServersUiController::isDefaultServerCurrentlyProcessed() const
|
||||
{
|
||||
return m_serversController->getDefaultServerIndex() == m_processedServerIndex;
|
||||
}
|
||||
|
||||
bool ServersUiController::isProcessedServerHasWriteAccess() const
|
||||
{
|
||||
ServerCredentials credentials = m_serversController->getServerCredentials(m_processedServerIndex);
|
||||
return (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
QString ServersUiController::getDefaultServerDescription(const ServerConfig& server, int index) const
|
||||
{
|
||||
QString description;
|
||||
|
||||
if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
if (!apiV2) return QString();
|
||||
if (!apiV2->apiConfig.serverCountryCode.isEmpty()) {
|
||||
return apiV2->apiConfig.serverCountryName;
|
||||
}
|
||||
return apiV2->description;
|
||||
} else if (server.isApiV1()) {
|
||||
const ApiV1ServerConfig* apiV1 = server.as<ApiV1ServerConfig>();
|
||||
return apiV1 ? apiV1->description : QString();
|
||||
} else {
|
||||
ServerCredentials credentials = m_serversController->getServerCredentials(index);
|
||||
if (!credentials.userName.isEmpty() && !credentials.secretData.isEmpty()) {
|
||||
bool isAmneziaDnsEnabled = m_settingsController->isAmneziaDnsEnabled();
|
||||
if (isAmneziaDnsEnabled && isAmneziaDnsContainerInstalled(index)) {
|
||||
description += "Amnezia DNS | ";
|
||||
}
|
||||
} else {
|
||||
if (server.dns1() == protocols::dns::amneziaDnsIp) {
|
||||
description += "Amnezia DNS | ";
|
||||
}
|
||||
}
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
bool ServersUiController::isAmneziaDnsContainerInstalled(int serverIndex) const
|
||||
{
|
||||
const ServerConfig server = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containers = server.containers();
|
||||
|
||||
return containers.contains(DockerContainer::Dns);
|
||||
}
|
||||
|
||||
bool ServersUiController::hasServersFromGatewayApi() const
|
||||
{
|
||||
QVector<ServerConfig> servers = m_serversController->getServers();
|
||||
for (const ServerConfig &server : servers) {
|
||||
if (server.isApiV2()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServersUiController::isAdVisible() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
if (defaultIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
if (!apiV2) return false;
|
||||
return apiV2->apiConfig.serviceInfo.isAdVisible;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString ServersUiController::adHeader() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
if (defaultIndex < 0) {
|
||||
return QString();
|
||||
}
|
||||
ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
if (!apiV2) return QString();
|
||||
return apiV2->apiConfig.serviceInfo.adHeader;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString ServersUiController::adDescription() const
|
||||
{
|
||||
int defaultIndex = getDefaultServerIndex();
|
||||
if (defaultIndex < 0) {
|
||||
return QString();
|
||||
}
|
||||
ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
if (server.isApiV2()) {
|
||||
const ApiV2ServerConfig* apiV2 = server.as<ApiV2ServerConfig>();
|
||||
if (!apiV2) return QString();
|
||||
return apiV2->apiConfig.serviceInfo.adDescription;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void ServersUiController::updateContainersModel()
|
||||
{
|
||||
if (m_processedServerIndex < 0 || m_processedServerIndex >= m_serversController->getServersCount()) {
|
||||
return;
|
||||
}
|
||||
ServerConfig server = m_serversController->getServerConfig(m_processedServerIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containers = server.containers();
|
||||
m_containersModel->updateModel(containers);
|
||||
}
|
||||
|
||||
void ServersUiController::updateDefaultServerContainersModel()
|
||||
{
|
||||
int defaultIndex = m_serversController->getDefaultServerIndex();
|
||||
if (defaultIndex < 0 || defaultIndex >= m_serversController->getServersCount()) {
|
||||
return;
|
||||
}
|
||||
ServerConfig server = m_serversController->getServerConfig(defaultIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containers = server.containers();
|
||||
m_defaultServerContainersModel->updateModel(containers);
|
||||
}
|
||||
|
||||
QStringList ServersUiController::getAllInstalledServicesName(int serverIndex) const
|
||||
{
|
||||
QStringList servicesName;
|
||||
ServerConfig server = m_serversController->getServerConfig(serverIndex);
|
||||
QMap<DockerContainer, ContainerConfig> containers = server.containers();
|
||||
|
||||
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
||||
DockerContainer container = it.key();
|
||||
if (ContainerUtils::containerService(container) == ServiceType::Other) {
|
||||
if (container == DockerContainer::Dns) {
|
||||
servicesName.append("DNS");
|
||||
} else if (container == DockerContainer::Sftp) {
|
||||
servicesName.append("SFTP");
|
||||
} else if (container == DockerContainer::TorWebSite) {
|
||||
servicesName.append("TOR");
|
||||
} else if (container == DockerContainer::Socks5Proxy) {
|
||||
servicesName.append("SOCKS5");
|
||||
}
|
||||
}
|
||||
}
|
||||
servicesName.sort();
|
||||
return servicesName;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef SERVERSUICONTROLLER_H
|
||||
#define SERVERSUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QSet>
|
||||
#include <QJsonObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include "core/controllers/serversController.h"
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "ui/models/serversModel.h"
|
||||
#include "ui/models/containersModel.h"
|
||||
#include "core/models/serverConfig.h"
|
||||
|
||||
class ServersUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(int defaultIndex READ getDefaultServerIndex NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString defaultServerDefaultContainerName READ getDefaultServerDefaultContainerName NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString defaultServerImagePathCollapsed READ getDefaultServerImagePathCollapsed NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(bool isDefaultServerDefaultContainerHasSplitTunneling READ isDefaultServerDefaultContainerHasSplitTunneling NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
|
||||
|
||||
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
|
||||
Q_PROPERTY(int processedContainerIndex READ getProcessedContainerIndex WRITE setProcessedContainerIndex NOTIFY processedContainerIndexChanged)
|
||||
Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerIndexChanged)
|
||||
|
||||
Q_PROPERTY(bool hasServersFromGatewayApi READ hasServersFromGatewayApi NOTIFY hasServersFromGatewayApiChanged)
|
||||
|
||||
Q_PROPERTY(bool isAdVisible READ isAdVisible NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString adHeader READ adHeader NOTIFY defaultServerIndexChanged)
|
||||
Q_PROPERTY(QString adDescription READ adDescription NOTIFY defaultServerIndexChanged)
|
||||
|
||||
public:
|
||||
explicit ServersUiController(ServersController* serversController,
|
||||
SettingsController* settingsController,
|
||||
ServersModel* serversModel,
|
||||
ContainersModel* containersModel,
|
||||
ContainersModel* defaultServerContainersModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void removeServer(int index);
|
||||
void editServerName(int index, const QString &name);
|
||||
void setDefaultServerIndex(int index);
|
||||
void setDefaultContainer(int serverIndex, int containerIndex);
|
||||
void toggleAmneziaDns(bool enabled);
|
||||
void onDefaultServerChanged(int index);
|
||||
|
||||
// Getters for properties
|
||||
int getDefaultServerIndex() const;
|
||||
QString getDefaultServerName() const;
|
||||
QString getDefaultServerDefaultContainerName() const;
|
||||
QString getDefaultServerDescriptionCollapsed() const;
|
||||
QString getDefaultServerImagePathCollapsed() const;
|
||||
QString getDefaultServerDescriptionExpanded() const;
|
||||
bool isDefaultServerDefaultContainerHasSplitTunneling() const;
|
||||
bool isDefaultServerFromApi() const;
|
||||
|
||||
int getProcessedServerIndex() const;
|
||||
void setProcessedServerIndex(int index);
|
||||
int getProcessedContainerIndex() const;
|
||||
void setProcessedContainerIndex(int index);
|
||||
bool processedServerIsPremium() const;
|
||||
|
||||
const ServerCredentials getProcessedServerCredentials() const;
|
||||
bool isDefaultServerCurrentlyProcessed() const;
|
||||
bool isProcessedServerHasWriteAccess() const;
|
||||
|
||||
bool hasServersFromGatewayApi() const;
|
||||
|
||||
bool isAdVisible() const;
|
||||
QString adHeader() const;
|
||||
QString adDescription() const;
|
||||
|
||||
QStringList getAllInstalledServicesName(int serverIndex) const;
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
void defaultServerIndexChanged(int index);
|
||||
void processedServerIndexChanged(int index);
|
||||
void processedContainerIndexChanged(int index);
|
||||
void hasServersFromGatewayApiChanged();
|
||||
void updateApiCountryModel();
|
||||
void updateApiServicesModel();
|
||||
|
||||
public:
|
||||
void updateModel();
|
||||
|
||||
private:
|
||||
QString getDefaultServerDescription(const ServerConfig& server, int index) const;
|
||||
bool isAmneziaDnsContainerInstalled(int serverIndex) const;
|
||||
|
||||
void updateContainersModel();
|
||||
void updateDefaultServerContainersModel();
|
||||
void updateApiModelsForProcessedServer();
|
||||
|
||||
ServersController* m_serversController;
|
||||
SettingsController* m_settingsController;
|
||||
ServersModel* m_serversModel;
|
||||
ContainersModel* m_containersModel;
|
||||
ContainersModel* m_defaultServerContainersModel;
|
||||
|
||||
int m_processedServerIndex = -1;
|
||||
int m_processedContainerIndex = -1;
|
||||
};
|
||||
|
||||
#endif // SERVERSUICONTROLLER_H
|
||||
|
||||
@@ -1,535 +0,0 @@
|
||||
#include "settingsController.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QOperatingSystemVersion>
|
||||
|
||||
#include "logger.h"
|
||||
#include "systemController.h"
|
||||
#include "ui/qautostart.h"
|
||||
#include "amnezia_application.h"
|
||||
#include "version.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
|
||||
SettingsController::SettingsController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<LanguageModel> &languageModel,
|
||||
const QSharedPointer<SitesModel> &sitesModel,
|
||||
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_languageModel(languageModel),
|
||||
m_sitesModel(sitesModel),
|
||||
m_appSplitTunnelingModel(appSplitTunnelingModel),
|
||||
m_settings(settings)
|
||||
{
|
||||
m_appVersion = QString("%1 (%2, %3)").arg(QString(APP_VERSION), __DATE__, GIT_COMMIT_HASH);
|
||||
checkIfNeedDisableLogs();
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsController::onNotificationStateChanged);
|
||||
connect(AndroidController::instance(), &AndroidController::imeInsetsChanged, this, [this](int heightDp) {
|
||||
m_imeHeight = heightDp;
|
||||
emit imeHeightChanged(heightDp);
|
||||
emit safeAreaBottomMarginChanged();
|
||||
});
|
||||
connect(AndroidController::instance(), &AndroidController::systemBarsInsetsChanged, this, [this](int navBarHeightDp, int statusBarHeightDp) {
|
||||
m_cachedNavigationBarHeight = navBarHeightDp;
|
||||
m_cachedStatusBarHeight = statusBarHeightDp;
|
||||
emit safeAreaBottomMarginChanged();
|
||||
emit safeAreaTopMarginChanged();
|
||||
});
|
||||
connect(AndroidController::instance(), &AndroidController::activityPaused, this, &SettingsController::activityPaused);
|
||||
connect(AndroidController::instance(), &AndroidController::activityResumed, this, &SettingsController::activityResumed);
|
||||
#endif
|
||||
|
||||
m_isDevModeEnabled = m_settings->isDevGatewayEnv();
|
||||
toggleDevGatewayEnv(m_isDevModeEnabled);
|
||||
}
|
||||
|
||||
QString getPlatformName()
|
||||
{
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
return "Windows";
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
return "Android";
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return "Linux";
|
||||
#elif defined(Q_OS_MACX)
|
||||
return "MacOS";
|
||||
#elif defined(Q_OS_IOS)
|
||||
return "iOS";
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsController::toggleAmneziaDns(bool enable)
|
||||
{
|
||||
m_settings->setUseAmneziaDns(enable);
|
||||
emit amneziaDnsToggled(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isAmneziaDnsEnabled()
|
||||
{
|
||||
return m_settings->useAmneziaDns();
|
||||
}
|
||||
|
||||
QString SettingsController::getPrimaryDns()
|
||||
{
|
||||
return m_settings->primaryDns();
|
||||
}
|
||||
|
||||
void SettingsController::setPrimaryDns(const QString &dns)
|
||||
{
|
||||
m_settings->setPrimaryDns(dns);
|
||||
emit primaryDnsChanged();
|
||||
}
|
||||
|
||||
QString SettingsController::getSecondaryDns()
|
||||
{
|
||||
return m_settings->secondaryDns();
|
||||
}
|
||||
|
||||
void SettingsController::setSecondaryDns(const QString &dns)
|
||||
{
|
||||
return m_settings->setSecondaryDns(dns);
|
||||
emit secondaryDnsChanged();
|
||||
}
|
||||
|
||||
bool SettingsController::isLoggingEnabled()
|
||||
{
|
||||
return m_settings->isSaveLogs();
|
||||
}
|
||||
|
||||
void SettingsController::toggleLogging(bool enable)
|
||||
{
|
||||
m_settings->setSaveLogs(enable);
|
||||
#if defined(Q_OS_IOS)
|
||||
AmneziaVPN::toggleLogging(enable);
|
||||
#endif
|
||||
if (enable == true) {
|
||||
qInfo().noquote() << QString("Logging has enabled on %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
}
|
||||
emit loggingStateChanged();
|
||||
}
|
||||
|
||||
void SettingsController::openLogsFolder()
|
||||
{
|
||||
Logger::openLogsFolder(false);
|
||||
}
|
||||
|
||||
void SettingsController::openServiceLogsFolder()
|
||||
{
|
||||
Logger::openLogsFolder(true);
|
||||
}
|
||||
|
||||
void SettingsController::exportLogsFile(const QString &fileName)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->exportLogsFile(fileName);
|
||||
#else
|
||||
SystemController::saveFile(fileName, Logger::getLogFile());
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsController::exportServiceLogsFile(const QString &fileName)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->exportLogsFile(fileName);
|
||||
#else
|
||||
SystemController::saveFile(fileName, Logger::getServiceLogFile());
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsController::clearLogs()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->clearLogs();
|
||||
#else
|
||||
Logger::clearLogs(false);
|
||||
Logger::clearServiceLogs();
|
||||
#endif
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
}
|
||||
|
||||
void SettingsController::backupAppConfig(const QString &fileName)
|
||||
{
|
||||
QByteArray data = m_settings->backupAppConfig();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
QJsonObject config = doc.object();
|
||||
|
||||
config["AppPlatform"] = getPlatformName();
|
||||
config["Conf/autoStart"] = Autostart::isAutostart();
|
||||
config["Conf/killSwitchEnabled"] = isKillSwitchEnabled();
|
||||
config["Conf/strictKillSwitchEnabled"] = isStrictKillSwitchEnabled();
|
||||
config["Conf/useAmneziaDns"] = isAmneziaDnsEnabled();
|
||||
|
||||
SystemController::saveFile(fileName, QJsonDocument(config).toJson());
|
||||
}
|
||||
|
||||
void SettingsController::restoreAppConfig(const QString &fileName)
|
||||
{
|
||||
QByteArray data;
|
||||
if (!SystemController::readFile(fileName, data)) {
|
||||
emit changeSettingsErrorOccurred(tr("Can't open file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
restoreAppConfigFromData(data);
|
||||
}
|
||||
|
||||
void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
||||
{
|
||||
bool ok = m_settings->restoreAppConfig(data);
|
||||
if (ok) {
|
||||
QJsonObject newConfigData = QJsonDocument::fromJson(data).object();
|
||||
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_MACX)
|
||||
bool autoStart = false;
|
||||
if (newConfigData.contains("Conf/autoStart")) {
|
||||
autoStart = newConfigData["Conf/autoStart"].toBool();
|
||||
}
|
||||
toggleAutoStart(autoStart);
|
||||
#endif
|
||||
|
||||
m_serversModel->resetModel();
|
||||
m_languageModel->changeLanguage(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
|
||||
int appSplitTunnelingRouteMode = newConfigData.value("Conf/appsRouteMode").toInt();
|
||||
bool appSplittunnelingEnabled =
|
||||
newConfigData.value("Conf/appsSplitTunnelingEnabled").toVariant().toString().toLower() == "true";
|
||||
m_appSplitTunnelingModel->setRouteMode(appSplitTunnelingRouteMode);
|
||||
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
m_appSplitTunnelingModel->setRouteMode(static_cast<int>(Settings::AppsRouteMode::VpnAllExceptApps));
|
||||
#endif
|
||||
|
||||
if (newConfigData.contains("AppPlatform")) { //if backup is from a new version
|
||||
if (newConfigData.value("AppPlatform").toString() != getPlatformName()) {
|
||||
m_appSplitTunnelingModel->clearAppsList();
|
||||
}
|
||||
}
|
||||
|
||||
m_appSplitTunnelingModel->toggleSplitTunneling(appSplittunnelingEnabled);
|
||||
#endif
|
||||
|
||||
int siteSplitTunnelingRouteMode = newConfigData.value("Conf/routeMode").toInt();
|
||||
bool siteSplittunnelingEnabled =
|
||||
newConfigData.value("Conf/sitesSplitTunnelingEnabled").toVariant().toString().toLower() == "true";
|
||||
m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode);
|
||||
m_sitesModel->toggleSplitTunneling(siteSplittunnelingEnabled);
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
m_settings->setAutoConnect(false);
|
||||
m_settings->setStartMinimized(false);
|
||||
m_settings->setKillSwitchEnabled(false);
|
||||
m_settings->setStrictKillSwitchEnabled(false);
|
||||
#endif
|
||||
|
||||
bool amneziaDnsEnabled = newConfigData.contains("Conf/useAmneziaDns")
|
||||
? newConfigData.value("Conf/useAmneziaDns").toBool()
|
||||
: m_settings->useAmneziaDns();
|
||||
emit amneziaDnsToggled(amneziaDnsEnabled);
|
||||
|
||||
emit restoreBackupFinished();
|
||||
} else {
|
||||
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
||||
}
|
||||
}
|
||||
|
||||
QString SettingsController::getAppVersion()
|
||||
{
|
||||
return m_appVersion;
|
||||
}
|
||||
|
||||
void SettingsController::clearSettings()
|
||||
{
|
||||
m_settings->clearSettings();
|
||||
m_serversModel->resetModel();
|
||||
m_languageModel->changeLanguage(m_languageModel->getSystemLanguageEnum());
|
||||
|
||||
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
||||
m_sitesModel->toggleSplitTunneling(false);
|
||||
|
||||
m_appSplitTunnelingModel->setRouteMode(Settings::AppsRouteMode::VpnAllExceptApps);
|
||||
m_appSplitTunnelingModel->toggleSplitTunneling(false);
|
||||
|
||||
toggleAutoStart(false);
|
||||
|
||||
emit changeSettingsFinished(tr("All settings have been reset to default values"));
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
AmneziaVPN::clearSettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SettingsController::isAutoConnectEnabled()
|
||||
{
|
||||
return m_settings->isAutoConnect();
|
||||
}
|
||||
|
||||
void SettingsController::toggleAutoConnect(bool enable)
|
||||
{
|
||||
m_settings->setAutoConnect(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isAutoStartEnabled()
|
||||
{
|
||||
return Autostart::isAutostart();
|
||||
}
|
||||
|
||||
void SettingsController::toggleAutoStart(bool enable)
|
||||
{
|
||||
Autostart::setAutostart(enable);
|
||||
if (!enable) {
|
||||
toggleStartMinimized(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsController::isStartMinimizedEnabled()
|
||||
{
|
||||
return m_settings->isStartMinimized();
|
||||
}
|
||||
|
||||
void SettingsController::toggleStartMinimized(bool enable)
|
||||
{
|
||||
m_settings->setStartMinimized(enable);
|
||||
emit startMinimizedChanged();
|
||||
}
|
||||
|
||||
bool SettingsController::isNewsNotificationsEnabled()
|
||||
{
|
||||
return m_settings->isNewsNotifications();
|
||||
}
|
||||
void SettingsController::toggleNewsNotificationsEnabled(bool enable)
|
||||
{
|
||||
m_settings->setNewsNotifications(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isScreenshotsEnabled()
|
||||
{
|
||||
return m_settings->isScreenshotsEnabled();
|
||||
}
|
||||
|
||||
void SettingsController::toggleScreenshotsEnabled(bool enable)
|
||||
{
|
||||
m_settings->setScreenshotsEnabled(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isCameraPresent()
|
||||
{
|
||||
#if defined Q_OS_IOS
|
||||
return true;
|
||||
#elif defined Q_OS_ANDROID
|
||||
return AndroidController::instance()->isCameraPresent();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsController::checkIfNeedDisableLogs()
|
||||
{
|
||||
if (m_settings->isSaveLogs()) {
|
||||
m_loggingDisableDate = m_settings->getLogEnableDate().addDays(14);
|
||||
if (m_loggingDisableDate <= QDateTime::currentDateTime()) {
|
||||
toggleLogging(false);
|
||||
clearLogs();
|
||||
emit loggingDisableByWatcher();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsController::isKillSwitchEnabled()
|
||||
{
|
||||
return m_settings->isKillSwitchEnabled();
|
||||
}
|
||||
|
||||
void SettingsController::toggleKillSwitch(bool enable)
|
||||
{
|
||||
m_settings->setKillSwitchEnabled(enable);
|
||||
emit killSwitchEnabledChanged();
|
||||
if (enable == false) {
|
||||
emit strictKillSwitchEnabledChanged(false);
|
||||
} else {
|
||||
emit strictKillSwitchEnabledChanged(isStrictKillSwitchEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsController::isStrictKillSwitchEnabled()
|
||||
{
|
||||
return m_settings->isStrictKillSwitchEnabled();
|
||||
}
|
||||
|
||||
void SettingsController::toggleStrictKillSwitch(bool enable)
|
||||
{
|
||||
m_settings->setStrictKillSwitchEnabled(enable);
|
||||
emit strictKillSwitchEnabledChanged(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isNotificationPermissionGranted()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return AndroidController::instance()->isNotificationPermissionGranted();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsController::requestNotificationPermission()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->requestNotificationPermission();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString SettingsController::getInstallationUuid()
|
||||
{
|
||||
return m_settings->getInstallationUuid(false);
|
||||
}
|
||||
|
||||
void SettingsController::enableDevMode()
|
||||
{
|
||||
m_isDevModeEnabled = true;
|
||||
emit devModeEnabled();
|
||||
}
|
||||
|
||||
bool SettingsController::isDevModeEnabled()
|
||||
{
|
||||
return m_isDevModeEnabled;
|
||||
}
|
||||
|
||||
void SettingsController::resetGatewayEndpoint()
|
||||
{
|
||||
m_settings->resetGatewayEndpoint();
|
||||
emit gatewayEndpointChanged(m_settings->getGatewayEndpoint());
|
||||
}
|
||||
|
||||
void SettingsController::setGatewayEndpoint(const QString &endpoint)
|
||||
{
|
||||
m_settings->setGatewayEndpoint(endpoint);
|
||||
emit gatewayEndpointChanged(endpoint);
|
||||
}
|
||||
|
||||
QString SettingsController::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()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return AndroidController::instance()->isOnTv();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SettingsController::isEdgeToEdgeEnabled()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (!m_edgeToEdgeCached) {
|
||||
m_cachedEdgeToEdgeEnabled = AndroidController::instance()->isEdgeToEdgeEnabled();
|
||||
m_edgeToEdgeCached = true;
|
||||
}
|
||||
return m_cachedEdgeToEdgeEnabled;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SettingsController::getStatusBarHeight()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (m_cachedStatusBarHeight < 0) {
|
||||
m_cachedStatusBarHeight = AndroidController::instance()->getStatusBarHeight();
|
||||
}
|
||||
return m_cachedStatusBarHeight;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SettingsController::getNavigationBarHeight()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (m_cachedNavigationBarHeight < 0) {
|
||||
m_cachedNavigationBarHeight = AndroidController::instance()->getNavigationBarHeight();
|
||||
}
|
||||
return m_cachedNavigationBarHeight;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SettingsController::getSafeAreaTopMargin()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (isEdgeToEdgeEnabled()) {
|
||||
int height = getStatusBarHeight();
|
||||
int result = height > 0 ? height : 40; // fallback to 40 if system returns 0
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SettingsController::getSafeAreaBottomMargin()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (isEdgeToEdgeEnabled()) {
|
||||
if (m_imeHeight > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int height = getNavigationBarHeight();
|
||||
int result = height > 0 ? height : 56; // fallback to 56 if system returns 0
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SettingsController::getImeHeight()
|
||||
{
|
||||
return m_imeHeight;
|
||||
}
|
||||
|
||||
bool SettingsController::isHomeAdLabelVisible()
|
||||
{
|
||||
return m_settings->isHomeAdLabelVisible();
|
||||
}
|
||||
|
||||
void SettingsController::disableHomeAdLabel()
|
||||
{
|
||||
m_settings->disableHomeAdLabel();
|
||||
emit isHomeAdLabelVisibleChanged(false);
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
#include "settingsUiController.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStandardPaths>
|
||||
#include <QOperatingSystemVersion>
|
||||
#include <QFile>
|
||||
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
#include "logger.h"
|
||||
#include "systemController.h"
|
||||
#include "amneziaApplication.h"
|
||||
#include "version.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/android_controller.h"
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
|
||||
SettingsUiController::SettingsUiController(SettingsController* settingsController,
|
||||
ServersController* serversController,
|
||||
LanguageUiController* languageUiController,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_settingsController(settingsController),
|
||||
m_serversController(serversController),
|
||||
m_languageUiController(languageUiController)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
connect(AndroidController::instance(), &AndroidController::notificationStateChanged, this, &SettingsUiController::onNotificationStateChanged);
|
||||
connect(AndroidController::instance(), &AndroidController::activityPaused, this, &SettingsUiController::activityPaused);
|
||||
connect(AndroidController::instance(), &AndroidController::activityResumed, this, &SettingsUiController::activityResumed);
|
||||
#endif
|
||||
|
||||
m_settingsController->checkIfNeedDisableLogs();
|
||||
if (m_settingsController->isDevGatewayEnv()) {
|
||||
m_settingsController->enableDevMode();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleAmneziaDns(bool enable)
|
||||
{
|
||||
m_settingsController->toggleAmneziaDns(enable);
|
||||
emit amneziaDnsToggled(enable);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isAmneziaDnsEnabled()
|
||||
{
|
||||
return m_settingsController->isAmneziaDnsEnabled();
|
||||
}
|
||||
|
||||
QString SettingsUiController::getPrimaryDns()
|
||||
{
|
||||
return m_settingsController->getPrimaryDns();
|
||||
}
|
||||
|
||||
void SettingsUiController::setPrimaryDns(const QString &dns)
|
||||
{
|
||||
m_settingsController->setPrimaryDns(dns);
|
||||
emit primaryDnsChanged();
|
||||
}
|
||||
|
||||
QString SettingsUiController::getSecondaryDns()
|
||||
{
|
||||
return m_settingsController->getSecondaryDns();
|
||||
}
|
||||
|
||||
void SettingsUiController::setSecondaryDns(const QString &dns)
|
||||
{
|
||||
m_settingsController->setSecondaryDns(dns);
|
||||
emit secondaryDnsChanged();
|
||||
}
|
||||
|
||||
bool SettingsUiController::isLoggingEnabled()
|
||||
{
|
||||
return m_settingsController->isLoggingEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleLogging(bool enable)
|
||||
{
|
||||
m_settingsController->toggleLogging(enable);
|
||||
#if defined(Q_OS_IOS)
|
||||
AmneziaVPN::toggleLogging(enable);
|
||||
#endif
|
||||
if (enable == true) {
|
||||
qInfo().noquote() << QString("Logging has enabled on %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
}
|
||||
emit loggingStateChanged();
|
||||
}
|
||||
|
||||
void SettingsUiController::openLogsFolder()
|
||||
{
|
||||
Logger::openLogsFolder(false);
|
||||
}
|
||||
|
||||
void SettingsUiController::openServiceLogsFolder()
|
||||
{
|
||||
Logger::openLogsFolder(true);
|
||||
}
|
||||
|
||||
void SettingsUiController::exportLogsFile(const QString &fileName)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->exportLogsFile(fileName);
|
||||
#else
|
||||
SystemController::saveFile(fileName, Logger::getLogFile());
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsUiController::exportServiceLogsFile(const QString &fileName)
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->exportLogsFile(fileName);
|
||||
#else
|
||||
SystemController::saveFile(fileName, Logger::getServiceLogFile());
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsUiController::clearLogs()
|
||||
{
|
||||
m_settingsController->clearLogs();
|
||||
|
||||
qInfo().noquote() << QString("Started %1 version %2 %3").arg(APPLICATION_NAME, APP_VERSION, GIT_COMMIT_HASH);
|
||||
qInfo().noquote() << QString("%1 (%2)").arg(QSysInfo::prettyProductName(), QSysInfo::currentCpuArchitecture());
|
||||
qInfo().noquote() << QString("SSL backend: %1").arg(QSslSocket::sslLibraryVersionString());
|
||||
}
|
||||
|
||||
void SettingsUiController::backupAppConfig(const QString &fileName)
|
||||
{
|
||||
QByteArray data = m_settingsController->backupAppConfig();
|
||||
SystemController::saveFile(fileName, data);
|
||||
}
|
||||
|
||||
void SettingsUiController::restoreAppConfig(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
emit errorOccurred(ErrorCode::OpenError);
|
||||
return;
|
||||
}
|
||||
|
||||
restoreAppConfigFromData(file.readAll());
|
||||
}
|
||||
|
||||
void SettingsUiController::restoreAppConfigFromData(const QByteArray &data)
|
||||
{
|
||||
ErrorCode errorCode = m_settingsController->restoreAppConfigFromData(data);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
emit appLanguageChanged(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageUiController->getCurrentLanguageIndex()));
|
||||
|
||||
bool amneziaDnsEnabled = m_settingsController->isAmneziaDnsEnabled();
|
||||
emit amneziaDnsToggled(amneziaDnsEnabled);
|
||||
|
||||
emit restoreBackupFinished();
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
QString SettingsUiController::getAppVersion()
|
||||
{
|
||||
return m_settingsController->getAppVersion();
|
||||
}
|
||||
|
||||
void SettingsUiController::clearSettings()
|
||||
{
|
||||
m_settingsController->clearSettings();
|
||||
emit resetLanguageToSystem();
|
||||
|
||||
emit changeSettingsFinished(tr("All settings have been reset to default values"));
|
||||
|
||||
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
||||
AmneziaVPN::clearSettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SettingsUiController::isAutoConnectEnabled()
|
||||
{
|
||||
return m_settingsController->isAutoConnectEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleAutoConnect(bool enable)
|
||||
{
|
||||
m_settingsController->toggleAutoConnect(enable);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isAutoStartEnabled()
|
||||
{
|
||||
return m_settingsController->isAutoStartEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleAutoStart(bool enable)
|
||||
{
|
||||
m_settingsController->toggleAutoStart(enable);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isStartMinimizedEnabled()
|
||||
{
|
||||
return m_settingsController->isStartMinimizedEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleStartMinimized(bool enable)
|
||||
{
|
||||
m_settingsController->toggleStartMinimized(enable);
|
||||
emit startMinimizedChanged();
|
||||
}
|
||||
|
||||
bool SettingsUiController::isScreenshotsEnabled()
|
||||
{
|
||||
return m_settingsController->isScreenshotsEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleScreenshotsEnabled(bool enable)
|
||||
{
|
||||
m_settingsController->toggleScreenshotsEnabled(enable);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isNewsNotificationsEnabled()
|
||||
{
|
||||
return m_settingsController->isNewsNotificationsEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleNewsNotificationsEnabled(bool enable)
|
||||
{
|
||||
m_settingsController->toggleNewsNotificationsEnabled(enable);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isCameraPresent()
|
||||
{
|
||||
#if defined Q_OS_IOS
|
||||
return true;
|
||||
#elif defined Q_OS_ANDROID
|
||||
return AndroidController::instance()->isCameraPresent();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SettingsUiController::isKillSwitchEnabled()
|
||||
{
|
||||
return m_settingsController->isKillSwitchEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleKillSwitch(bool enable)
|
||||
{
|
||||
m_settingsController->toggleKillSwitch(enable);
|
||||
emit killSwitchEnabledChanged();
|
||||
if (enable == false) {
|
||||
emit strictKillSwitchEnabledChanged(false);
|
||||
} else {
|
||||
emit strictKillSwitchEnabledChanged(isStrictKillSwitchEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsUiController::isStrictKillSwitchEnabled()
|
||||
{
|
||||
return m_settingsController->isStrictKillSwitchEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleStrictKillSwitch(bool enable)
|
||||
{
|
||||
m_settingsController->toggleStrictKillSwitch(enable);
|
||||
emit strictKillSwitchEnabledChanged(enable);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isNotificationPermissionGranted()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return AndroidController::instance()->isNotificationPermissionGranted();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsUiController::requestNotificationPermission()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
AndroidController::instance()->requestNotificationPermission();
|
||||
#endif
|
||||
}
|
||||
|
||||
QString SettingsUiController::getInstallationUuid()
|
||||
{
|
||||
return m_settingsController->getInstallationUuid();
|
||||
}
|
||||
|
||||
void SettingsUiController::enableDevMode()
|
||||
{
|
||||
m_settingsController->enableDevMode();
|
||||
emit devModeEnabled();
|
||||
}
|
||||
|
||||
bool SettingsUiController::isDevModeEnabled()
|
||||
{
|
||||
return m_settingsController->isDevModeEnabled();
|
||||
}
|
||||
|
||||
void SettingsUiController::resetGatewayEndpoint()
|
||||
{
|
||||
m_settingsController->resetGatewayEndpoint();
|
||||
emit gatewayEndpointChanged(m_settingsController->getGatewayEndpoint());
|
||||
}
|
||||
|
||||
void SettingsUiController::setGatewayEndpoint(const QString &endpoint)
|
||||
{
|
||||
m_settingsController->setGatewayEndpoint(endpoint);
|
||||
emit gatewayEndpointChanged(endpoint);
|
||||
}
|
||||
|
||||
QString SettingsUiController::getGatewayEndpoint()
|
||||
{
|
||||
return m_settingsController->getGatewayEndpoint();
|
||||
}
|
||||
|
||||
bool SettingsUiController::isDevGatewayEnv()
|
||||
{
|
||||
return m_settingsController->isDevGatewayEnv();
|
||||
}
|
||||
|
||||
void SettingsUiController::toggleDevGatewayEnv(bool enabled)
|
||||
{
|
||||
m_settingsController->toggleDevGatewayEnv(enabled);
|
||||
emit gatewayEndpointChanged(m_settingsController->getGatewayEndpoint());
|
||||
emit devGatewayEnvChanged(enabled);
|
||||
}
|
||||
|
||||
bool SettingsUiController::isOnTv()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return AndroidController::instance()->isOnTv();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SettingsUiController::isHomeAdLabelVisible()
|
||||
{
|
||||
return m_settingsController->isHomeAdLabelVisible();
|
||||
}
|
||||
|
||||
void SettingsUiController::disableHomeAdLabel()
|
||||
{
|
||||
m_settingsController->disableHomeAdLabel();
|
||||
emit isHomeAdLabelVisibleChanged(false);
|
||||
}
|
||||
+21
-50
@@ -1,24 +1,24 @@
|
||||
#ifndef SETTINGSCONTROLLER_H
|
||||
#define SETTINGSCONTROLLER_H
|
||||
#ifndef SETTINGSUICONTROLLER_H
|
||||
#define SETTINGSUICONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "core/controllers/settingsController.h"
|
||||
#include "core/controllers/serversController.h"
|
||||
#include "ui/controllers/languageUiController.h"
|
||||
#include "ui/models/languageModel.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
#include "ui/models/sites_model.h"
|
||||
#include "ui/models/appSplitTunnelingModel.h"
|
||||
#include "core/utils/errorCodes.h"
|
||||
#include "core/utils/routeModes.h"
|
||||
#include "core/utils/commonStructs.h"
|
||||
|
||||
class SettingsController : public QObject
|
||||
class SettingsUiController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SettingsController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<LanguageModel> &languageModel,
|
||||
const QSharedPointer<SitesModel> &sitesModel,
|
||||
const QSharedPointer<AppSplitTunnelingModel> &appSplitTunnelingModel,
|
||||
const std::shared_ptr<Settings> &settings, QObject *parent = nullptr);
|
||||
explicit SettingsUiController(SettingsController* settingsController,
|
||||
ServersController* serversController,
|
||||
LanguageUiController* languageUiController,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QString primaryDns READ getPrimaryDns WRITE setPrimaryDns NOTIFY primaryDnsChanged)
|
||||
Q_PROPERTY(QString secondaryDns READ getSecondaryDns WRITE setSecondaryDns NOTIFY secondaryDnsChanged)
|
||||
@@ -33,9 +33,6 @@ public:
|
||||
|
||||
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
|
||||
Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged)
|
||||
Q_PROPERTY(int safeAreaTopMargin READ getSafeAreaTopMargin NOTIFY safeAreaTopMarginChanged)
|
||||
Q_PROPERTY(int safeAreaBottomMargin READ getSafeAreaBottomMargin NOTIFY safeAreaBottomMarginChanged)
|
||||
Q_PROPERTY(int imeHeight READ getImeHeight NOTIFY imeHeightChanged)
|
||||
|
||||
public slots:
|
||||
void toggleAmneziaDns(bool enable);
|
||||
@@ -102,12 +99,6 @@ public slots:
|
||||
void toggleDevGatewayEnv(bool enabled);
|
||||
|
||||
bool isOnTv();
|
||||
bool isEdgeToEdgeEnabled();
|
||||
int getStatusBarHeight();
|
||||
int getNavigationBarHeight();
|
||||
int getSafeAreaTopMargin();
|
||||
int getSafeAreaBottomMargin();
|
||||
int getImeHeight();
|
||||
|
||||
bool isHomeAdLabelVisible();
|
||||
void disableHomeAdLabel();
|
||||
@@ -121,7 +112,7 @@ signals:
|
||||
|
||||
void restoreBackupFinished();
|
||||
void changeSettingsFinished(const QString &finishedMessage);
|
||||
void changeSettingsErrorOccurred(const QString &errorMessage);
|
||||
void errorOccurred(ErrorCode errorCode);
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
@@ -131,15 +122,14 @@ signals:
|
||||
|
||||
void loggingDisableByWatcher();
|
||||
|
||||
void appLanguageChanged(const LanguageSettings::AvailableLanguageEnum language);
|
||||
void resetLanguageToSystem();
|
||||
|
||||
void onNotificationStateChanged();
|
||||
|
||||
void devModeEnabled();
|
||||
void gatewayEndpointChanged(const QString &endpoint);
|
||||
void devGatewayEnvChanged(bool enabled);
|
||||
|
||||
void imeHeightChanged(int height);
|
||||
void safeAreaTopMarginChanged();
|
||||
void safeAreaBottomMarginChanged();
|
||||
|
||||
void activityPaused();
|
||||
void activityResumed();
|
||||
@@ -148,28 +138,9 @@ signals:
|
||||
void startMinimizedChanged();
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
QSharedPointer<LanguageModel> m_languageModel;
|
||||
QSharedPointer<SitesModel> m_sitesModel;
|
||||
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
|
||||
|
||||
mutable int m_cachedStatusBarHeight = -1;
|
||||
mutable int m_cachedNavigationBarHeight = -1;
|
||||
mutable bool m_cachedEdgeToEdgeEnabled = false;
|
||||
mutable bool m_edgeToEdgeCached = false;
|
||||
int m_imeHeight = 0;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QString m_appVersion;
|
||||
|
||||
QString getPlatform();
|
||||
|
||||
QDateTime m_loggingDisableDate;
|
||||
|
||||
bool m_isDevModeEnabled = false;
|
||||
|
||||
void checkIfNeedDisableLogs();
|
||||
SettingsController* m_settingsController;
|
||||
ServersController* m_serversController;
|
||||
LanguageUiController* m_languageUiController;
|
||||
};
|
||||
|
||||
#endif // SETTINGSCONTROLLER_H
|
||||
#endif
|
||||
@@ -1,134 +0,0 @@
|
||||
#include "sitesController.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QHostInfo>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "systemController.h"
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
SitesController::SitesController(const std::shared_ptr<Settings> &settings, const QSharedPointer<SitesModel> &sitesModel, QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_sitesModel(sitesModel)
|
||||
{
|
||||
}
|
||||
|
||||
void SitesController::addSite(QString hostname)
|
||||
{
|
||||
if (hostname.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hostname.contains(".")) {
|
||||
emit errorOccurred(tr("Hostname not look like ip adress or domain name"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
|
||||
// get domain name if it present
|
||||
hostname.replace("https://", "");
|
||||
hostname.replace("http://", "");
|
||||
hostname.replace("ftp://", "");
|
||||
|
||||
hostname = hostname.split("/", Qt::SkipEmptyParts).first();
|
||||
}
|
||||
|
||||
const auto &resolveCallback = [this](const QHostInfo &hostInfo) {
|
||||
const QList<QHostAddress> &addresses = hostInfo.addresses();
|
||||
for (const QHostAddress &addr : hostInfo.addresses()) {
|
||||
if (addr.protocol() == QAbstractSocket::NetworkLayerProtocol::IPv4Protocol) {
|
||||
m_sitesModel->addSite(hostInfo.hostName(), addr.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
|
||||
m_sitesModel->addSite(hostname, "");
|
||||
} else {
|
||||
m_sitesModel->addSite(hostname, "");
|
||||
QHostInfo::lookupHost(hostname, this, resolveCallback);
|
||||
}
|
||||
|
||||
emit finished(tr("New site added: %1").arg(hostname));
|
||||
}
|
||||
|
||||
void SitesController::removeSite(int index)
|
||||
{
|
||||
auto modelIndex = m_sitesModel->index(index);
|
||||
auto hostname = m_sitesModel->data(modelIndex, SitesModel::Roles::UrlRole).toString();
|
||||
m_sitesModel->removeSite(modelIndex);
|
||||
|
||||
emit finished(tr("Site removed: %1").arg(hostname));
|
||||
}
|
||||
|
||||
void SitesController::removeSites()
|
||||
{
|
||||
m_sitesModel->removeSites();
|
||||
|
||||
emit finished(tr("Site list cleared!"));
|
||||
}
|
||||
|
||||
void SitesController::importSites(const QString &fileName, bool replaceExisting)
|
||||
{
|
||||
QByteArray jsonData;
|
||||
if (!SystemController::readFile(fileName, jsonData)) {
|
||||
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
|
||||
if (jsonDocument.isNull()) {
|
||||
emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!jsonDocument.isArray()) {
|
||||
emit errorOccurred(tr("The JSON data is not an array in file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
auto jsonArray = jsonDocument.array();
|
||||
QMap<QString, QString> sites;
|
||||
QStringList ips;
|
||||
|
||||
for (auto jsonValue : jsonArray) {
|
||||
auto jsonObject = jsonValue.toObject();
|
||||
auto hostname = jsonObject.value("hostname").toString("");
|
||||
auto ip = jsonObject.value("ip").toString("");
|
||||
|
||||
if (!hostname.contains(".") && !NetworkUtilities::ipAddressWithSubnetRegExp().exactMatch(hostname)) {
|
||||
qDebug() << hostname << " not look like ip adress or domain name";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ip.isEmpty()) {
|
||||
ips.append(hostname);
|
||||
} else {
|
||||
ips.append(ip);
|
||||
}
|
||||
sites.insert(hostname, ip);
|
||||
}
|
||||
|
||||
m_sitesModel->addSites(sites, replaceExisting);
|
||||
|
||||
emit finished(tr("Import completed"));
|
||||
}
|
||||
|
||||
void SitesController::exportSites(const QString &fileName)
|
||||
{
|
||||
auto sites = m_sitesModel->getCurrentSites();
|
||||
|
||||
QJsonArray jsonArray;
|
||||
|
||||
for (const auto &site : sites) {
|
||||
QJsonObject jsonObject { { "hostname", site.first }, { "ip", site.second } };
|
||||
jsonArray.append(jsonObject);
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument(jsonArray);
|
||||
QByteArray jsonData = jsonDocument.toJson();
|
||||
|
||||
SystemController::saveFile(fileName, jsonData);
|
||||
|
||||
emit finished(tr("Export completed"));
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef SITESCONTROLLER_H
|
||||
#define SITESCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "settings.h"
|
||||
#include "ui/models/sites_model.h"
|
||||
#include "vpnconnection.h"
|
||||
|
||||
class SitesController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SitesController(const std::shared_ptr<Settings> &settings, const QSharedPointer<SitesModel> &sitesModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addSite(QString hostname);
|
||||
void removeSite(int index);
|
||||
|
||||
void removeSites();
|
||||
void importSites(const QString &fileName, bool replaceExisting);
|
||||
void exportSites(const QString &fileName);
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
QSharedPointer<SitesModel> m_sitesModel;
|
||||
};
|
||||
|
||||
#endif // SITESCONTROLLER_H
|
||||
@@ -19,8 +19,8 @@
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
SystemController::SystemController(const std::shared_ptr<Settings> &settings, QObject *parent)
|
||||
: QObject(parent), m_settings(settings)
|
||||
SystemController::SystemController(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -38,8 +38,9 @@ void SystemController::saveFile(const QString &fileName, const QString &data)
|
||||
QFile file(fileName);
|
||||
#endif
|
||||
|
||||
// todo check if save successful
|
||||
file.open(QIODevice::WriteOnly);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
return;
|
||||
}
|
||||
file.write(data.toUtf8());
|
||||
file.close();
|
||||
|
||||
|
||||
@@ -3,13 +3,11 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
class SystemController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SystemController(const std::shared_ptr<Settings> &setting, QObject *parent = nullptr);
|
||||
explicit SystemController(QObject *parent = nullptr);
|
||||
|
||||
static void saveFile(const QString &fileName, const QString &data);
|
||||
static bool readFile(const QString &fileName, QByteArray &data);
|
||||
@@ -28,8 +26,6 @@ signals:
|
||||
void fileDialogClosed(const bool isAccepted);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
|
||||
QObject *m_qmlRoot;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user