Merge branch 'dev' into refactoring/android

This commit is contained in:
albexk
2023-12-20 20:47:19 +03:00
69 changed files with 5605 additions and 753 deletions
+129
View File
@@ -0,0 +1,129 @@
#include "apiController.h"
#include <QEventLoop>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "configurators/openvpn_configurator.h"
namespace
{
namespace configKey
{
constexpr char cloak[] = "cloak";
constexpr char apiEdnpoint[] = "api_endpoint";
constexpr char accessToken[] = "api_key";
constexpr char certificate[] = "certificate";
constexpr char publicKey[] = "public_key";
constexpr char protocol[] = "protocol";
}
}
ApiController::ApiController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_containersModel(containersModel)
{
}
QString ApiController::genPublicKey(const QString &protocol)
{
if (protocol == configKey::cloak) {
return ".";
}
return QString();
}
QString ApiController::genCertificateRequest(const QString &protocol)
{
if (protocol == configKey::cloak) {
m_certRequest = OpenVpnConfigurator::createCertRequest();
return m_certRequest.request;
}
return QString();
}
void ApiController::processCloudConfig(const QString &protocol, QString &config)
{
if (protocol == configKey::cloak) {
config.replace("<key>", "<key>\n");
config.replace("$OPENVPN_PRIV_KEY", m_certRequest.privKey);
return;
}
return;
}
bool ApiController::updateServerConfigFromApi()
{
auto serverConfig = m_serversModel->getDefaultServerConfig();
auto containerConfig = serverConfig.value(config_key::containers).toArray();
if (serverConfig.value(config_key::configVersion).toInt() && containerConfig.isEmpty()) {
QNetworkAccessManager manager;
QNetworkRequest request;
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization",
"Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
request.setUrl(endpoint.replace("https", "http")); // todo remove
QString protocol = serverConfig.value(configKey::protocol).toString();
QJsonObject obj;
obj[configKey::publicKey] = genPublicKey(protocol);
obj[configKey::certificate] = genCertificateRequest(protocol);
QByteArray requestBody = QJsonDocument(obj).toJson();
qDebug() << requestBody;
QScopedPointer<QNetworkReply> reply;
reply.reset(manager.post(request, requestBody));
QEventLoop wait;
QObject::connect(reply.get(), &QNetworkReply::finished, &wait, &QEventLoop::quit);
wait.exec();
if (reply->error() == QNetworkReply::NoError) {
QString contents = QString::fromUtf8(reply->readAll());
auto data = QJsonDocument::fromJson(contents.toUtf8()).object().value(config_key::config).toString();
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(),
QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QString configStr = ba;
processCloudConfig(protocol, configStr);
QJsonObject cloudConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig.insert("cloudConfig", cloudConfig);
serverConfig.insert(config_key::dns1, cloudConfig.value(config_key::dns1));
serverConfig.insert(config_key::dns2, cloudConfig.value(config_key::dns2));
serverConfig.insert(config_key::containers, cloudConfig.value(config_key::containers));
serverConfig.insert(config_key::hostName, cloudConfig.value(config_key::hostName));
auto defaultContainer = cloudConfig.value(config_key::defaultContainer).toString();
serverConfig.insert(config_key::defaultContainer, defaultContainer);
m_serversModel->editServer(serverConfig);
emit m_serversModel->defaultContainerChanged(ContainerProps::containerFromString(defaultContainer));
} else {
QString err = reply->errorString();
qDebug() << QString::fromUtf8(reply->readAll()); //todo remove debug output
qDebug() << reply->error();
qDebug() << err;
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
emit errorOccurred(tr("Error when retrieving configuration from cloud server"));
return false;
}
}
return true;
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef APICONTROLLER_H
#define APICONTROLLER_H
#include <QObject>
#include "configurators/openvpn_configurator.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
class ApiController : public QObject
{
Q_OBJECT
public:
explicit ApiController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, QObject *parent = nullptr);
public slots:
bool updateServerConfigFromApi();
signals:
void errorOccurred(const QString &errorMessage);
private:
QString genPublicKey(const QString &protocol);
QString genCertificateRequest(const QString &protocol);
void processCloudConfig(const QString &protocol, QString &config);
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
OpenVpnConfigurator::ConnectionData m_certRequest;
};
#endif // APICONTROLLER_H
@@ -26,13 +26,10 @@ ConnectionController::ConnectionController(const QSharedPointer<ServersModel> &s
void ConnectionController::openConnection()
{
int serverIndex = m_serversModel->getDefaultServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = m_containersModel->getDefaultContainer();
QModelIndex containerModelIndex = m_containersModel->index(container);
const QJsonObject &containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
const QJsonObject &containerConfig = m_containersModel->getContainerConfig(container);
if (container == DockerContainer::None) {
emit connectionErrorOccurred(tr("VPN Protocols is not installed.\n Please install VPN container at first"));
@@ -40,6 +37,7 @@ void ConnectionController::openConnection()
}
qApp->processEvents();
emit connectToVpn(serverIndex, credentials, container, containerConfig);
}
@@ -110,6 +108,8 @@ void ConnectionController::onCurrentContainerUpdated()
if (m_isConnected || m_isConnectionInProgress) {
emit reconnectWithUpdatedContainer(tr("Settings updated successfully, Reconnnection..."));
openConnection();
} else {
emit reconnectWithUpdatedContainer(tr("Settings updated successfully"));
}
}
+146 -25
View File
@@ -8,7 +8,9 @@
#include <QImage>
#include <QStandardPaths>
#include "configurators/cloak_configurator.h"
#include "configurators/openvpn_configurator.h"
#include "configurators/shadowsocks_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "core/errorstrings.h"
#include "systemController.h"
@@ -19,11 +21,13 @@
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent)
: QObject(parent),
m_serversModel(serversModel),
m_containersModel(containersModel),
m_clientManagementModel(clientManagementModel),
m_settings(settings),
m_configurator(configurator)
{
@@ -75,35 +79,40 @@ void ExportController::generateFullAccessConfigAndroid()
}
#endif
void ExportController::generateConnectionConfig()
void ExportController::generateConnectionConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol);
QString vpnConfig =
m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, &errorCode);
QString clientId;
QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol,
clientId, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
protocolConfig.insert(config_key::last_config, vpnConfig);
containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfig);
if (protocol == Proto::OpenVpn || protocol == Proto::Awg || protocol == Proto::WireGuard) {
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
}
}
QJsonObject config = m_settings->server(serverIndex);
QJsonObject config = m_settings->server(serverIndex); // todo change to servers_model
if (!errorCode) {
config.remove(config_key::userName);
config.remove(config_key::password);
@@ -126,23 +135,21 @@ void ExportController::generateConnectionConfig()
emit exportConfigChanged();
}
void ExportController::generateOpenVpnConfig()
void ExportController::generateOpenVpnConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config =
m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &errorCode);
QString clientId;
QString config = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig,
clientId, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
@@ -155,26 +162,32 @@ void ExportController::generateOpenVpnConfig()
m_config.append(line + "\n");
}
m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8());
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged();
}
void ExportController::generateWireGuardConfig()
void ExportController::generateWireGuardConfig(const QString &clientName)
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
QString clientId;
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig,
&errorCode);
clientId, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
@@ -187,6 +200,84 @@ void ExportController::generateWireGuardConfig()
m_config.append(line + "\n");
}
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
emit exportConfigChanged();
}
void ExportController::generateShadowSocksConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->shadowSocksConfigurator->genShadowSocksConfig(credentials, container,
containerConfig, &errorCode);
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::ShadowSocks, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
m_nativeConfigString =
QString("%1:%2@%3:%4")
.arg(configJson.value("method").toString(), configJson.value("password").toString(),
configJson.value("server").toString(), configJson.value("server_port").toString());
m_nativeConfigString = "ss://" + m_nativeConfigString.toUtf8().toBase64();
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_nativeConfigString.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
emit exportConfigChanged();
}
void ExportController::generateCloakConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = m_serversModel->getServerCredentials(serverIndex);
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QJsonObject containerConfig = m_containersModel->getContainerConfig(container);
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config =
m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Cloak, config);
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
configJson.remove(config_key::transport_proto);
configJson.insert("ProxyMethod", "shadowsocks");
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n");
for (const QString &line : lines) {
m_config.append(line + "\n");
}
emit exportConfigChanged();
}
@@ -195,6 +286,11 @@ QString ExportController::getConfig()
return m_config;
}
QString ExportController::getNativeConfigString()
{
return m_nativeConfigString;
}
QList<QString> ExportController::getQrCodes()
{
return m_qrCodes;
@@ -205,6 +301,30 @@ void ExportController::exportConfig(const QString &fileName)
SystemController::saveFile(fileName, m_config);
}
void ExportController::updateClientManagementModel(const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->updateModel(container, credentials);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
}
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
}
void ExportController::renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials)
{
ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials);
if (errorCode != ErrorCode::NoError) {
emit exportErrorOccurred(errorString(errorCode));
}
}
QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &data)
{
double k = 850;
@@ -219,7 +339,7 @@ QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &dat
QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW);
QString svg = QString::fromStdString(toSvgString(qr, 0));
QString svg = QString::fromStdString(toSvgString(qr, 1));
chunks.append(svgToBase64(svg));
}
@@ -239,5 +359,6 @@ int ExportController::getQrCodesCount()
void ExportController::clearPreviousConfig()
{
m_config.clear();
m_nativeConfigString.clear();
m_qrCodes.clear();
}
+15 -3
View File
@@ -6,6 +6,7 @@
#include "configurators/vpn_configurator.h"
#include "ui/models/containers_model.h"
#include "ui/models/servers_model.h"
#include "ui/models/clientManagementModel.h"
#ifdef Q_OS_ANDROID
#include "platforms/android/authResultReceiver.h"
#endif
@@ -16,27 +17,36 @@ class ExportController : public QObject
public:
explicit ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel,
const QSharedPointer<ClientManagementModel> &clientManagementModel,
const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, 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();
#if defined(Q_OS_ANDROID)
void generateFullAccessConfigAndroid();
#endif
void generateConnectionConfig();
void generateOpenVpnConfig();
void generateWireGuardConfig();
void generateConnectionConfig(const QString &clientName);
void generateOpenVpnConfig(const QString &clientName);
void generateWireGuardConfig(const QString &clientName);
void generateShadowSocksConfig();
void generateCloakConfig();
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 exportErrorOccurred(const QString &errorMessage);
@@ -55,10 +65,12 @@ private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator;
QString m_config;
QString m_nativeConfigString;
QList<QString> m_qrCodes;
#ifdef Q_OS_ANDROID
+6 -2
View File
@@ -123,7 +123,9 @@ void ImportController::importConfig()
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)) {
if (credentials.isValid()
|| m_config.contains(config_key::containers)
|| m_config.contains(config_key::configVersion)) { // todo
m_serversModel->addServer(m_config);
emit importFinished();
@@ -147,7 +149,9 @@ QJsonObject ImportController::extractAmneziaConfig(QString &data)
ba = ba_uncompressed;
}
return QJsonDocument::fromJson(ba).object();
QJsonObject config = QJsonDocument::fromJson(ba).object();
return config;
}
QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
+14 -19
View File
@@ -8,7 +8,7 @@
#include <QRandomGenerator>
#include "core/errorstrings.h"
#include "core/servercontroller.h"
#include "core/controllers/serverController.h"
#include "utilities.h"
namespace
@@ -130,6 +130,7 @@ void InstallController::installServer(DockerContainer container, QJsonObject &co
{
ServerController serverController(m_settings);
connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy);
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode =
@@ -181,6 +182,7 @@ void InstallController::installContainer(DockerContainer container, QJsonObject
ServerController serverController(m_settings);
connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy);
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
QMap<DockerContainer, QJsonObject> installedContainers;
ErrorCode errorCode = serverController.getAlreadyInstalledContainers(serverCredentials, installedContainers);
@@ -199,12 +201,9 @@ void InstallController::installContainer(DockerContainer container, QJsonObject
if (errorCode == ErrorCode::NoError) {
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
auto modelIndex = m_containersModel->index(iterator.key());
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(modelIndex, ContainersModel::Roles::ConfigRole));
QJsonObject containerConfig = m_containersModel->getContainerConfig(iterator.key());
if (containerConfig.isEmpty()) {
m_containersModel->setData(m_containersModel->index(iterator.key()), iterator.value(),
ContainersModel::Roles::ConfigRole);
m_serversModel->addContainerConfig(iterator.key(), iterator.value());
if (container != iterator.key()) { // skip the newly installed container
isInstalledContainerAddedToGui = true;
}
@@ -252,12 +251,9 @@ void InstallController::scanServerForInstalledContainers()
bool isInstalledContainerAddedToGui = false;
for (auto iterator = installedContainers.begin(); iterator != installedContainers.end(); iterator++) {
auto modelIndex = m_containersModel->index(iterator.key());
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(modelIndex, ContainersModel::Roles::ConfigRole));
QJsonObject containerConfig = m_containersModel->getContainerConfig(iterator.key());
if (containerConfig.isEmpty()) {
m_containersModel->setData(m_containersModel->index(iterator.key()), iterator.value(),
ContainersModel::Roles::ConfigRole);
m_serversModel->addContainerConfig(iterator.key(), iterator.value());
isInstalledContainerAddedToGui = true;
}
}
@@ -276,16 +272,15 @@ void InstallController::updateContainer(QJsonObject config)
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
const DockerContainer container = ContainerProps::containerFromString(config.value(config_key::container).toString());
auto modelIndex = m_containersModel->index(container);
QJsonObject oldContainerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(modelIndex, ContainersModel::Roles::ConfigRole));
QJsonObject oldContainerConfig = m_containersModel->getContainerConfig(container);
ServerController serverController(m_settings);
connect(&serverController, &ServerController::serverIsBusy, this, &InstallController::serverIsBusy);
connect(this, &InstallController::cancelInstallation, &serverController, &ServerController::cancelInstallation);
auto errorCode = serverController.updateContainer(serverCredentials, container, oldContainerConfig, config);
if (errorCode == ErrorCode::NoError) {
m_containersModel->setData(modelIndex, config, ContainersModel::Roles::ConfigRole);
m_serversModel->updateContainerConfig(container, config);
m_protocolModel->updateModel(config);
if ((serverIndex == m_serversModel->getDefaultServerIndex())
@@ -315,7 +310,7 @@ void InstallController::removeAllContainers()
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
ErrorCode errorCode = m_containersModel->removeAllContainers();
ErrorCode errorCode = m_serversModel->removeAllContainers();
if (errorCode == ErrorCode::NoError) {
emit removeAllContainersFinished(tr("All containers from server '%1' have been removed").arg(serverName));
return;
@@ -329,12 +324,12 @@ void InstallController::removeCurrentlyProcessedContainer()
QString serverName = m_serversModel->data(serverIndex, ServersModel::Roles::NameRole).toString();
int container = m_containersModel->getCurrentlyProcessedContainerIndex();
QString containerName = m_containersModel->data(container, ContainersModel::Roles::NameRole).toString();
QString containerName = m_containersModel->getCurrentlyProcessedContainerName();
ErrorCode errorCode = m_containersModel->removeCurrentlyProcessedContainer();
ErrorCode errorCode = m_serversModel->removeContainer(container);
if (errorCode == ErrorCode::NoError) {
emit removeCurrentlyProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName).arg(serverName));
emit removeCurrentlyProcessedContainerFinished(tr("%1 has been removed from the server '%2'").arg(containerName, serverName));
return;
}
emit installationErrorOccurred(errorString(errorCode));
@@ -65,6 +65,7 @@ signals:
void passphraseRequestFinished();
void serverIsBusy(const bool isBusy);
void cancelInstallation();
void currentContainerUpdated();
+3 -1
View File
@@ -51,7 +51,9 @@ namespace PageLoader
PageProtocolWireGuardSettings,
PageProtocolAwgSettings,
PageProtocolIKev2Settings,
PageProtocolRaw
PageProtocolRaw,
PageShareFullAccess
};
Q_ENUM_NS(PageEnum)
+2 -1
View File
@@ -42,6 +42,7 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
void SettingsController::toggleAmneziaDns(bool enable)
{
m_settings->setUseAmneziaDns(enable);
emit amneziaDnsToggled(enable);
}
bool SettingsController::isAmneziaDnsEnabled()
@@ -138,7 +139,7 @@ void SettingsController::clearSettings()
void SettingsController::clearCachedProfiles()
{
m_containersModel->clearCachedProfiles();
m_serversModel->clearCachedProfiles();
emit changeSettingsFinished(tr("Cached profiles cleared"));
}
@@ -70,6 +70,8 @@ signals:
void importBackupFromOutside(QString filePath);
void amneziaDnsToggled(bool enable);
private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel;
+332 -63
View File
@@ -1,104 +1,373 @@
#include "clientManagementModel.h"
#include <QJsonDocument>
#include <QJsonObject>
ClientManagementModel::ClientManagementModel(QObject *parent) : QAbstractListModel(parent)
{
#include "core/controllers/serverController.h"
#include "logger.h"
}
void ClientManagementModel::clearData()
namespace
{
beginResetModel();
m_content.clear();
endResetModel();
}
Logger logger("ClientManagementModel");
void ClientManagementModel::setContent(const QVector<QVariant> &data)
{
beginResetModel();
m_content = data;
endResetModel();
}
QJsonObject ClientManagementModel::getContent(amnezia::Proto protocol)
{
QJsonObject clientsTable;
for (const auto &item : m_content) {
if (protocol == amnezia::Proto::OpenVpn) {
clientsTable[item.toJsonObject()["openvpnCertId"].toString()] = item.toJsonObject();
} else if (protocol == amnezia::Proto::WireGuard) {
clientsTable[item.toJsonObject()["wireguardPublicKey"].toString()] = item.toJsonObject();
}
namespace configKey {
constexpr char clientId[] = "clientId";
constexpr char clientName[] = "clientName";
constexpr char container[] = "container";
constexpr char userData[] = "userData";
}
return clientsTable;
}
ClientManagementModel::ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
{
}
int ClientManagementModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return static_cast<int>(m_content.size());
return static_cast<int>(m_clientsTable.size());
}
QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0
|| index.row() >= static_cast<int>(m_content.size())) {
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_clientsTable.size())) {
return QVariant();
}
if (role == NameRole) {
return m_content[index.row()].toJsonObject()["clientName"].toString();
} else if (role == OpenVpnCertIdRole) {
return m_content[index.row()].toJsonObject()["openvpnCertId"].toString();
} else if (role == OpenVpnCertDataRole) {
return m_content[index.row()].toJsonObject()["openvpnCertData"].toString();
} else if (role == WireGuardPublicKey) {
return m_content[index.row()].toJsonObject()["wireguardPublicKey"].toString();
auto client = m_clientsTable.at(index.row()).toObject();
auto userData = client.value(configKey::userData).toObject();
switch (role) {
case ClientNameRole: return userData.value(configKey::clientName).toString();
}
return QVariant();
}
void ClientManagementModel::setData(const QModelIndex &index, QVariant data, int role)
ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials)
{
if (!index.isValid() || index.row() < 0
|| index.row() >= static_cast<int>(m_content.size())) {
return;
beginResetModel();
m_clientsTable = QJsonArray();
ServerController serverController(m_settings);
ErrorCode error = ErrorCode::NoError;
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
const QByteArray clientsTableString =
serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the clientsTable file from the server";
endResetModel();
return error;
}
auto client = m_content[index.row()].toJsonObject();
if (role == NameRole) {
client["clientName"] = data.toString();
} else if (role == OpenVpnCertIdRole) {
client["openvpnCertId"] = data.toString();
} else if (role == OpenVpnCertDataRole) {
client["openvpnCertData"] = data.toString();
} else if (role == WireGuardPublicKey) {
client["wireguardPublicKey"] = data.toString();
} else {
return;
}
if (m_content[index.row()] != client) {
m_content[index.row()] = client;
emit dataChanged(index, index);
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
if (m_clientsTable.isEmpty()) {
int count = 0;
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
error = getOpenVpnClients(serverController, container, credentials, count);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
error = getWireGuardClients(serverController, container, credentials, count);
}
if (error != ErrorCode::NoError) {
endResetModel();
return error;
}
const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson();
if (clientsTableString != newClientsTableString) {
error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString,
clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
}
}
endResetModel();
return error;
}
bool ClientManagementModel::removeRows(int row)
ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count)
{
ErrorCode error = ErrorCode::NoError;
QString stdOut;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
stdOut += data + "\n";
return ErrorCode::NoError;
};
const QString getOpenVpnClientsList =
"sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'";
QString script = serverController.replaceVars(getOpenVpnClientsList,
serverController.genVarsForScript(credentials, container));
error = serverController.runScript(credentials, script, cbReadStdOut);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to retrieve the list of issued certificates on the server";
return error;
}
if (!stdOut.isEmpty()) {
QStringList certsIds = stdOut.split("\n", Qt::SkipEmptyParts);
certsIds.removeAll("AmneziaReq.crt");
for (auto &openvpnCertId : certsIds) {
openvpnCertId.replace(".crt", "");
if (!isClientExists(openvpnCertId)) {
QJsonObject client;
client[configKey::clientId] = openvpnCertId;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
count++;
}
}
}
return error;
}
ErrorCode ClientManagementModel::getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count)
{
ErrorCode error = ErrorCode::NoError;
const QString wireGuardConfigFile =
QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString =
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server";
return error;
}
auto configLines = wireguardConfigString.split("\n", Qt::SkipEmptyParts);
QStringList wireguardKeys;
for (const auto &line : configLines) {
auto configPair = line.split(" = ", Qt::SkipEmptyParts);
if (configPair.front() == "PublicKey") {
wireguardKeys.push_back(configPair.back());
}
}
for (auto &wireguardKey : wireguardKeys) {
if (!isClientExists(wireguardKey)) {
QJsonObject client;
client[configKey::clientId] = wireguardKey;
QJsonObject userData;
userData[configKey::clientName] = QString("Client %1").arg(count);
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
count++;
}
}
return error;
}
bool ClientManagementModel::isClientExists(const QString &clientId)
{
for (const QJsonValue &value : qAsConst(m_clientsTable)) {
if (value.isObject()) {
QJsonObject obj = value.toObject();
if (obj.contains(configKey::clientId) && obj[configKey::clientId].toString() == clientId) {
return true;
}
}
}
return false;
}
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName,
const DockerContainer container, ServerCredentials credentials)
{
ErrorCode error;
error = updateModel(container, credentials);
if (error != ErrorCode::NoError) {
return error;
}
for (int i = 0; i < m_clientsTable.size(); i++) {
if (m_clientsTable.at(i).toObject().value(configKey::clientId) == clientId) {
return renameClient(i, clientName, container, credentials);
}
}
beginResetModel();
QJsonObject client;
client[configKey::clientId] = clientId;
QJsonObject userData;
userData[configKey::clientName] = clientName;
client[configKey::userData] = userData;
m_clientsTable.push_back(client);
endResetModel();
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
ServerController serverController(m_settings);
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
return error;
}
ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName, const DockerContainer container,
ServerCredentials credentials)
{
auto client = m_clientsTable.at(row).toObject();
auto userData = client[configKey::userData].toObject();
userData[configKey::clientName] = clientName;
client[configKey::userData] = userData;
m_clientsTable.replace(row, client);
emit dataChanged(index(row, 0), index(row, 0));
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
ServerController serverController(m_settings);
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
ErrorCode error =
serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
}
return error;
}
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container,
ServerCredentials credentials)
{
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|| container == DockerContainer::Cloak) {
return revokeOpenVpn(row, container, credentials);
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
return revokeWireGuard(row, container, credentials);
}
return ErrorCode::NoError;
}
ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container,
ServerCredentials credentials)
{
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
const QString getOpenVpnCertData = QString("sudo docker exec -i $CONTAINER_NAME bash -c '"
"cd /opt/amnezia/openvpn ;\\"
"easyrsa revoke %1 ;\\"
"easyrsa gen-crl ;\\"
"cp pki/crl.pem .'")
.arg(clientId);
ServerController serverController(m_settings);
const QString script =
serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
ErrorCode error = serverController.runScript(credentials, script);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to revoke the certificate";
return error;
}
beginRemoveRows(QModelIndex(), row, row);
m_content.removeAt(row);
m_clientsTable.removeAt(row);
endRemoveRows();
return true;
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
return error;
}
return ErrorCode::NoError;
}
ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container,
ServerCredentials credentials)
{
ErrorCode error;
ServerController serverController(m_settings);
const QString wireGuardConfigFile =
QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
const QString wireguardConfigString =
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the wg conf file from the server";
return error;
}
auto client = m_clientsTable.at(row).toObject();
QString clientId = client.value(configKey::clientId).toString();
auto configSections = wireguardConfigString.split("[", Qt::SkipEmptyParts);
for (auto &section : configSections) {
if (section.contains(clientId)) {
configSections.removeOne(section);
break;
}
}
QString newWireGuardConfig = configSections.join("[");
newWireGuardConfig.insert(0, "[");
error = serverController.uploadTextFileToContainer(container, credentials, newWireGuardConfig, wireGuardConfigFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the wg conf file to the server";
return error;
}
beginRemoveRows(QModelIndex(), row, row);
m_clientsTable.removeAt(row);
endRemoveRows();
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
const QString clientsTableFile =
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to upload the clientsTable file to the server";
return error;
}
const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'";
error = serverController.runScript(
credentials,
serverController.replaceVars(script.arg(wireGuardConfigFile),
serverController.genVarsForScript(credentials, container)));
if (error != ErrorCode::NoError) {
logger.error() << "Failed to execute the command 'wg syncconf' on the server";
return error;
}
return ErrorCode::NoError;
}
QHash<int, QByteArray> ClientManagementModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "clientName";
roles[OpenVpnCertIdRole] = "openvpnCertId";
roles[OpenVpnCertDataRole] = "openvpnCertData";
roles[WireGuardPublicKey] = "wireguardPublicKey";
roles[ClientNameRole] = "clientName";
return roles;
}
+25 -13
View File
@@ -2,36 +2,48 @@
#define CLIENTMANAGEMENTMODEL_H
#include <QAbstractListModel>
#include <QJsonArray>
#include "protocols/protocols_defs.h"
#include "core/controllers/serverController.h"
#include "settings.h"
class ClientManagementModel : public QAbstractListModel
{
Q_OBJECT
public:
enum ClientRoles {
NameRole = Qt::UserRole + 1,
OpenVpnCertIdRole,
OpenVpnCertDataRole,
WireGuardPublicKey,
enum Roles {
ClientNameRole = Qt::UserRole + 1,
};
ClientManagementModel(QObject *parent = nullptr);
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
void clearData();
void setContent(const QVector<QVariant> &data);
QJsonObject getContent(amnezia::Proto protocol);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void setData(const QModelIndex &index, QVariant data, int role = Qt::DisplayRole);
bool removeRows(int row);
public slots:
ErrorCode updateModel(DockerContainer container, ServerCredentials credentials);
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
ServerCredentials credentials);
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container,
ServerCredentials credentials);
ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials);
protected:
QHash<int, QByteArray> roleNames() const override;
private:
QVector<QVariant> m_content;
bool isClientExists(const QString &clientId);
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, ServerCredentials credentials);
ErrorCode revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials);
ErrorCode getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count);
ErrorCode getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count);
QJsonArray m_clientsTable;
std::shared_ptr<Settings> m_settings;
};
#endif // CLIENTMANAGEMENTMODEL_H
+17 -140
View File
@@ -1,9 +1,9 @@
#include "containers_model.h"
#include "core/servercontroller.h"
#include <QJsonArray>
ContainersModel::ContainersModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
ContainersModel::ContainersModel(QObject *parent)
: QAbstractListModel(parent)
{
}
@@ -13,37 +13,6 @@ int ContainersModel::rowCount(const QModelIndex &parent) const
return ContainerProps::allContainers().size();
}
bool ContainersModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) {
return false;
}
DockerContainer container = ContainerProps::allContainers().at(index.row());
switch (role) {
case ConfigRole: {
m_settings->setContainerConfig(m_currentlyProcessedServerIndex, container, value.toJsonObject());
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
if (m_defaultContainerIndex != DockerContainer::None) {
break;
} else if (ContainerProps::containerService(container) == ServiceType::Other) {
break;
}
}
case IsDefaultRole: { //todo remove
m_settings->setDefaultContainer(m_currentlyProcessedServerIndex, container);
m_defaultContainerIndex = container;
emit defaultContainerChanged();
}
default: break;
}
emit containersModelUpdated();
emit dataChanged(index, index);
return true;
}
QVariant ContainersModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) {
@@ -84,37 +53,32 @@ QVariant ContainersModel::data(const int index, int role) const
return data(modelIndex, role);
}
void ContainersModel::setCurrentlyProcessedServerIndex(const int index)
void ContainersModel::updateModel(QJsonArray &containers)
{
beginResetModel();
m_currentlyProcessedServerIndex = index;
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
m_defaultContainerIndex = m_settings->defaultContainer(m_currentlyProcessedServerIndex);
m_containers.clear();
for (const QJsonValue &val : containers) {
m_containers.insert(ContainerProps::containerFromString(val.toObject().value(config_key::container).toString()),
val.toObject());
}
endResetModel();
emit defaultContainerChanged();
}
void ContainersModel::setCurrentlyProcessedContainerIndex(int index)
void ContainersModel::setDefaultContainer(const int containerIndex)
{
m_currentlyProcessedContainerIndex = index;
m_defaultContainerIndex = static_cast<DockerContainer>(containerIndex);
emit dataChanged(index(containerIndex, 0), index(containerIndex, 0));
}
DockerContainer ContainersModel::getDefaultContainer()
{
return m_defaultContainerIndex;
}
QString ContainersModel::getDefaultContainerName()
void ContainersModel::setCurrentlyProcessedContainerIndex(int index)
{
return ContainerProps::containerHumanNames().value(m_defaultContainerIndex);
}
void ContainersModel::setDefaultContainer(int index)
{
auto container = static_cast<DockerContainer>(index);
m_settings->setDefaultContainer(m_currentlyProcessedServerIndex, container);
m_defaultContainerIndex = container;
emit defaultContainerChanged();
m_currentlyProcessedContainerIndex = index;
}
int ContainersModel::getCurrentlyProcessedContainerIndex()
@@ -127,91 +91,9 @@ QString ContainersModel::getCurrentlyProcessedContainerName()
return ContainerProps::containerHumanNames().value(static_cast<DockerContainer>(m_currentlyProcessedContainerIndex));
}
QJsonObject ContainersModel::getCurrentlyProcessedContainerConfig()
QJsonObject ContainersModel::getContainerConfig(const int containerIndex)
{
return qvariant_cast<QJsonObject>(data(index(m_currentlyProcessedContainerIndex), ConfigRole));
}
QStringList ContainersModel::getAllInstalledServicesName(const int serverIndex)
{
QStringList servicesName;
const auto &containers = m_settings->containers(serverIndex);
for (const DockerContainer &container : containers.keys()) {
if (ContainerProps::containerService(container) == ServiceType::Other && m_containers.contains(container)) {
if (container == DockerContainer::Dns) {
servicesName.append("DNS");
} else if (container == DockerContainer::Sftp) {
servicesName.append("SFTP");
} else if (container == DockerContainer::TorWebSite) {
servicesName.append("TOR");
}
}
}
servicesName.sort();
return servicesName;
}
ErrorCode ContainersModel::removeAllContainers()
{
ServerController serverController(m_settings);
ErrorCode errorCode =
serverController.removeAllContainers(m_settings->serverCredentials(m_currentlyProcessedServerIndex));
if (errorCode == ErrorCode::NoError) {
beginResetModel();
m_settings->setContainers(m_currentlyProcessedServerIndex, {});
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
setData(index(DockerContainer::None, 0), true, IsDefaultRole);
endResetModel();
}
return errorCode;
}
ErrorCode ContainersModel::removeCurrentlyProcessedContainer()
{
ServerController serverController(m_settings);
auto credentials = m_settings->serverCredentials(m_currentlyProcessedServerIndex);
auto dockerContainer = static_cast<DockerContainer>(m_currentlyProcessedContainerIndex);
ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer);
if (errorCode == ErrorCode::NoError) {
beginResetModel();
m_settings->removeContainerConfig(m_currentlyProcessedServerIndex, dockerContainer);
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
if (m_defaultContainerIndex == m_currentlyProcessedContainerIndex) {
if (m_containers.isEmpty()) {
setData(index(DockerContainer::None, 0), true, IsDefaultRole);
} else {
setData(index(m_containers.begin().key(), 0), true, IsDefaultRole);
}
}
endResetModel();
}
return errorCode;
}
void ContainersModel::clearCachedProfiles()
{
const auto &containers = m_settings->containers(m_currentlyProcessedServerIndex);
for (DockerContainer container : containers.keys()) {
m_settings->clearLastConnectionConfig(m_currentlyProcessedServerIndex, container);
}
}
bool ContainersModel::isAmneziaDnsContainerInstalled()
{
return m_containers.contains(DockerContainer::Dns);
}
bool ContainersModel::isAmneziaDnsContainerInstalled(const int serverIndex)
{
QMap<DockerContainer, QJsonObject> containers = m_settings->containers(serverIndex);
return containers.contains(DockerContainer::Dns);
return qvariant_cast<QJsonObject>(data(index(containerIndex), ConfigRole));
}
bool ContainersModel::isAnyContainerInstalled()
@@ -228,11 +110,6 @@ bool ContainersModel::isAnyContainerInstalled()
return false;
}
void ContainersModel::updateContainersConfig()
{
m_containers = m_settings->containers(m_currentlyProcessedServerIndex);
}
QHash<int, QByteArray> ContainersModel::roleNames() const
{
QHash<int, QByteArray> roles;
+6 -23
View File
@@ -7,13 +7,12 @@
#include <vector>
#include "containers/containers_defs.h"
#include "settings.h"
class ContainersModel : public QAbstractListModel
{
Q_OBJECT
public:
ContainersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
ContainersModel(QObject *parent = nullptr);
enum Roles {
NameRole = Qt::UserRole + 1,
@@ -37,37 +36,24 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant data(const int index, int role) const;
Q_PROPERTY(QString defaultContainerName READ getDefaultContainerName NOTIFY defaultContainerChanged)
public slots:
void updateModel(QJsonArray &containers);
DockerContainer getDefaultContainer();
QString getDefaultContainerName();
void setDefaultContainer(int index);
void setDefaultContainer(const int containerIndex);
void setCurrentlyProcessedServerIndex(const int index);
void setCurrentlyProcessedContainerIndex(int index);
void setCurrentlyProcessedContainerIndex(int containerIndex);
int getCurrentlyProcessedContainerIndex();
QString getCurrentlyProcessedContainerName();
QJsonObject getCurrentlyProcessedContainerConfig();
QStringList getAllInstalledServicesName(const int serverIndex);
ErrorCode removeAllContainers();
ErrorCode removeCurrentlyProcessedContainer();
void clearCachedProfiles();
bool isAmneziaDnsContainerInstalled();
bool isAmneziaDnsContainerInstalled(const int serverIndex);
QJsonObject getContainerConfig(const int containerIndex);
bool isAnyContainerInstalled();
void updateContainersConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
@@ -78,11 +64,8 @@ signals:
private:
QMap<DockerContainer, QJsonObject> m_containers;
int m_currentlyProcessedServerIndex;
int m_currentlyProcessedContainerIndex;
DockerContainer m_defaultContainerIndex;
std::shared_ptr<Settings> m_settings;
};
#endif // CONTAINERS_MODEL_H
+3
View File
@@ -44,6 +44,7 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
case LanguageSettings::AvailableLanguageEnum::English: strLanguage = "English"; break;
case LanguageSettings::AvailableLanguageEnum::Russian: 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;
default:
break;
}
@@ -57,6 +58,7 @@ void LanguageModel::changeLanguage(const LanguageSettings::AvailableLanguageEnum
case LanguageSettings::AvailableLanguageEnum::English: emit updateTranslations(QLocale::English); break;
case LanguageSettings::AvailableLanguageEnum::Russian: emit updateTranslations(QLocale::Russian); break;
case LanguageSettings::AvailableLanguageEnum::China_cn: emit updateTranslations(QLocale::Chinese); break;
case LanguageSettings::AvailableLanguageEnum::Persian: emit updateTranslations(QLocale::Persian); break;
default: emit updateTranslations(QLocale::English); break;
}
}
@@ -68,6 +70,7 @@ int LanguageModel::getCurrentLanguageIndex()
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::Persian: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::Persian); break;
default: return static_cast<int>(LanguageSettings::AvailableLanguageEnum::English); break;
}
}
+2 -1
View File
@@ -12,7 +12,8 @@ namespace LanguageSettings
enum class AvailableLanguageEnum {
English,
Russian,
China_cn
China_cn,
Persian
};
Q_ENUM_NS(AvailableLanguageEnum)
+303 -10
View File
@@ -1,5 +1,7 @@
#include "servers_model.h"
#include "core/controllers/serverController.h"
ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
: m_settings(settings), QAbstractListModel(parent)
{
@@ -8,6 +10,11 @@ ServersModel::ServersModel(std::shared_ptr<Settings> settings, QObject *parent)
m_currentlyProcessedServerIndex = m_defaultServerIndex;
connect(this, &ServersModel::defaultServerIndexChanged, this, &ServersModel::defaultServerNameChanged);
connect(this, &ServersModel::defaultContainerChanged, this, &ServersModel::defaultServerDescriptionChanged);
connect(this, &ServersModel::defaultServerIndexChanged, this, [this](const int serverIndex) {
auto defaultContainer = ContainerProps::containerFromString(m_servers.at(serverIndex).toObject().value(config_key::defaultContainer).toString());
emit ServersModel::defaultContainerChanged(defaultContainer);
});
}
int ServersModel::rowCount(const QModelIndex &parent) const
@@ -50,14 +57,23 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
}
const QJsonObject server = m_servers.at(index.row()).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt();
switch (role) {
case NameRole: {
auto description = server.value(config_key::description).toString();
if (description.isEmpty()) {
if (configVersion) {
return server.value(config_key::name).toString();
}
auto name = server.value(config_key::description).toString();
if (name.isEmpty()) {
return server.value(config_key::hostName).toString();
}
return description;
return name;
}
case ServerDescriptionRole: {
if (configVersion) {
return server.value(config_key::description).toString();
}
return server.value(config_key::hostName).toString();
}
case HostNameRole: return server.value(config_key::hostName).toString();
case CredentialsRole: return QVariant::fromValue(serverCredentials(index.row()));
@@ -72,6 +88,9 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const
QString primaryDns = server.value(config_key::dns1).toString();
return primaryDns == protocols::dns::amneziaDnsIp;
}
case DefaultContainerRole: {
return ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
}
}
return QVariant();
@@ -114,6 +133,53 @@ const QString ServersModel::getDefaultServerHostName()
return qvariant_cast<QString>(data(m_defaultServerIndex, HostNameRole));
}
QString ServersModel::getDefaultServerDescription(const QJsonObject &server)
{
const auto configVersion = server.value(config_key::configVersion).toInt();
QString description;
if (configVersion) {
return server.value(config_key::description).toString();
} else if (isDefaultServerHasWriteAccess()) {
if (m_isAmneziaDnsEnabled
&& isAmneziaDnsContainerInstalled(m_defaultServerIndex)) {
description += "Amnezia DNS | ";
}
} else {
if (isDefaultServerConfigContainsAmneziaDns()) {
description += "Amnezia DNS | ";
}
}
return description;
}
const QString ServersModel::getDefaultServerDescriptionCollapsed()
{
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getDefaultServerDescription(server);
if (configVersion) {
return description;
}
auto container = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
return description += ContainerProps::containerHumanNames().value(container) + " | " + server.value(config_key::hostName).toString();
}
const QString ServersModel::getDefaultServerDescriptionExpanded()
{
const QJsonObject server = m_servers.at(m_defaultServerIndex).toObject();
const auto configVersion = server.value(config_key::configVersion).toInt();
auto description = getDefaultServerDescription(server);
if (configVersion) {
return description;
}
return description += server.value(config_key::hostName).toString();
}
const int ServersModel::getServersCount()
{
return m_servers.count();
@@ -132,6 +198,7 @@ bool ServersModel::hasServerWithWriteAccess()
void ServersModel::setCurrentlyProcessedServerIndex(const int index)
{
m_currentlyProcessedServerIndex = index;
updateContainersModel();
emit currentlyProcessedServerIndexChanged(m_currentlyProcessedServerIndex);
}
@@ -145,6 +212,16 @@ QString ServersModel::getCurrentlyProcessedServerHostName()
return qvariant_cast<QString>(data(m_currentlyProcessedServerIndex, HostNameRole));
}
const ServerCredentials ServersModel::getCurrentlyProcessedServerCredentials()
{
return serverCredentials(m_currentlyProcessedServerIndex);
}
const ServerCredentials ServersModel::getServerCredentials(const int index)
{
return serverCredentials(index);
}
bool ServersModel::isDefaultServerCurrentlyProcessed()
{
return m_defaultServerIndex == m_currentlyProcessedServerIndex;
@@ -168,6 +245,15 @@ void ServersModel::addServer(const QJsonObject &server)
endResetModel();
}
void ServersModel::editServer(const QJsonObject &server)
{
beginResetModel();
m_settings->editServer(m_currentlyProcessedServerIndex, server);
m_servers = m_settings->serversArray();
endResetModel();
updateContainersModel();
}
void ServersModel::removeServer()
{
beginResetModel();
@@ -193,23 +279,27 @@ bool ServersModel::isDefaultServerConfigContainsAmneziaDns()
return primaryDns == protocols::dns::amneziaDnsIp;
}
void ServersModel::updateContainersConfig()
{
auto server = m_settings->server(m_currentlyProcessedServerIndex);
m_servers.replace(m_currentlyProcessedServerIndex, server);
}
QHash<int, QByteArray> ServersModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "serverName";
roles[NameRole] = "name";
roles[ServerDescriptionRole] = "serverDescription";
roles[HostNameRole] = "hostName";
roles[CredentialsRole] = "credentials";
roles[CredentialsLoginRole] = "credentialsLogin";
roles[IsDefaultRole] = "isDefault";
roles[IsCurrentlyProcessedRole] = "isCurrentlyProcessed";
roles[HasWriteAccessRole] = "hasWriteAccess";
roles[ContainsAmneziaDnsRole] = "containsAmneziaDns";
roles[DefaultContainerRole] = "defaultContainer";
return roles;
}
@@ -225,3 +315,206 @@ ServerCredentials ServersModel::serverCredentials(int index) const
return credentials;
}
void ServersModel::updateContainersModel()
{
auto containers = m_servers.at(m_currentlyProcessedServerIndex).toObject().value(config_key::containers).toArray();
emit containersUpdated(containers);
}
QJsonObject ServersModel::getDefaultServerConfig()
{
return m_servers.at(m_defaultServerIndex).toObject();
}
void ServersModel::reloadContainerConfig()
{
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto container = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
auto containers = server.value(config_key::containers).toArray();
auto config = m_settings->containerConfig(m_currentlyProcessedServerIndex, container);
for (auto i = 0; i < containers.size(); i++) {
auto c = ContainerProps::containerFromString(containers.at(i).toObject().value(config_key::container).toString());
if (c == container) {
containers.replace(i, config);
break;
}
}
server.insert(config_key::containers, containers);
editServer(server);
}
void ServersModel::updateContainerConfig(const int containerIndex, const QJsonObject config)
{
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
for (auto i = 0; i < containers.size(); i++) {
auto c = ContainerProps::containerFromString(containers.at(i).toObject().value(config_key::container).toString());
if (c == container) {
containers.replace(i, config);
break;
}
}
server.insert(config_key::containers, containers);
auto defaultContainer = server.value(config_key::defaultContainer).toString();
if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
}
editServer(server);
}
void ServersModel::addContainerConfig(const int containerIndex, const QJsonObject config)
{
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
containers.push_back(config);
server.insert(config_key::containers, containers);
bool isDefaultContainerChanged = false;
auto defaultContainer = server.value(config_key::defaultContainer).toString();
if ((ContainerProps::containerFromString(defaultContainer) == DockerContainer::None || ContainerProps::containerService(container) != ServiceType::Other)) {
server.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
isDefaultContainerChanged = true;
}
editServer(server);
if (isDefaultContainerChanged) {
emit defaultContainerChanged(container);
}
}
void ServersModel::setDefaultContainer(const int containerIndex)
{
auto container = static_cast<DockerContainer>(containerIndex);
QJsonObject s = m_servers.at(m_currentlyProcessedServerIndex).toObject();
s.insert(config_key::defaultContainer, ContainerProps::containerToString(container));
editServer(s); //check
emit defaultContainerChanged(container);
}
DockerContainer ServersModel::getDefaultContainer()
{
return qvariant_cast<DockerContainer>(data(m_currentlyProcessedServerIndex, DefaultContainerRole));
}
const QString ServersModel::getDefaultContainerName()
{
auto defaultContainer = getDefaultContainer();
return ContainerProps::containerHumanNames().value(defaultContainer);
}
ErrorCode ServersModel::removeAllContainers()
{
ServerController serverController(m_settings);
ErrorCode errorCode =
serverController.removeAllContainers(m_settings->serverCredentials(m_currentlyProcessedServerIndex));
if (errorCode == ErrorCode::NoError) {
QJsonObject s = m_servers.at(m_currentlyProcessedServerIndex).toObject();
s.insert(config_key::containers, {});
s.insert(config_key::defaultContainer, ContainerProps::containerToString(DockerContainer::None));
editServer(s);
emit defaultContainerChanged(DockerContainer::None);
}
return errorCode;
}
ErrorCode ServersModel::removeContainer(const int containerIndex)
{
ServerController serverController(m_settings);
auto credentials = m_settings->serverCredentials(m_currentlyProcessedServerIndex);
auto dockerContainer = static_cast<DockerContainer>(containerIndex);
ErrorCode errorCode = serverController.removeContainer(credentials, dockerContainer);
if (errorCode == ErrorCode::NoError) {
QJsonObject server = m_servers.at(m_currentlyProcessedServerIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
for (auto it = containers.begin(); it != containers.end(); it++) {
if (it->toObject().value(config_key::container).toString() == ContainerProps::containerToString(dockerContainer)) {
containers.erase(it);
break;
}
}
server.insert(config_key::containers, containers);
auto defaultContainer = ContainerProps::containerFromString(server.value(config_key::defaultContainer).toString());
if (defaultContainer == containerIndex) {
if (containers.empty()) {
defaultContainer = DockerContainer::None;
} else {
defaultContainer = ContainerProps::containerFromString(containers.begin()->toObject().value(config_key::container).toString());
}
server.insert(config_key::defaultContainer, ContainerProps::containerToString(defaultContainer));
}
editServer(server);
emit defaultContainerChanged(defaultContainer);
}
return errorCode;
}
void ServersModel::clearCachedProfiles()
{
const auto &containers = m_settings->containers(m_currentlyProcessedServerIndex);
for (DockerContainer container : containers.keys()) {
m_settings->clearLastConnectionConfig(m_currentlyProcessedServerIndex, container);
}
m_servers.replace(m_currentlyProcessedServerIndex, m_settings->server(m_currentlyProcessedServerIndex));
updateContainersModel();
}
bool ServersModel::isAmneziaDnsContainerInstalled(const int serverIndex)
{
QJsonObject server = m_servers.at(serverIndex).toObject();
auto containers = server.value(config_key::containers).toArray();
for (auto it = containers.begin(); it != containers.end(); it++) {
if (it->toObject().value(config_key::container).toString() == ContainerProps::containerToString(DockerContainer::Dns)) {
return true;
}
}
return false;
}
QStringList ServersModel::getAllInstalledServicesName(const int serverIndex)
{
QStringList servicesName;
QJsonObject server = m_servers.at(serverIndex).toObject();
const auto containers = server.value(config_key::containers).toArray();
for (auto it = containers.begin(); it != containers.end(); it++) {
auto container = ContainerProps::containerFromString(it->toObject().value(config_key::container).toString());
if (ContainerProps::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");
}
}
}
servicesName.sort();
return servicesName;
}
void ServersModel::toggleAmneziaDns(bool enabled)
{
m_isAmneziaDnsEnabled = enabled;
emit defaultServerDescriptionChanged();
}
+46 -2
View File
@@ -11,13 +11,21 @@ class ServersModel : public QAbstractListModel
public:
enum Roles {
NameRole = Qt::UserRole + 1,
ServerDescriptionRole,
HostNameRole,
CredentialsRole,
CredentialsLoginRole,
IsDefaultRole,
IsCurrentlyProcessedRole,
HasWriteAccessRole,
ContainsAmneziaDnsRole
ContainsAmneziaDnsRole,
DefaultContainerRole
};
ServersModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
@@ -33,6 +41,10 @@ public:
Q_PROPERTY(int defaultIndex READ getDefaultServerIndex WRITE setDefaultServerIndex NOTIFY defaultServerIndexChanged)
Q_PROPERTY(QString defaultServerName READ getDefaultServerName NOTIFY defaultServerNameChanged)
Q_PROPERTY(QString defaultServerHostName READ getDefaultServerHostName NOTIFY defaultServerIndexChanged)
Q_PROPERTY(QString defaultContainerName READ getDefaultContainerName NOTIFY defaultContainerChanged)
Q_PROPERTY(QString defaultServerDescriptionCollapsed READ getDefaultServerDescriptionCollapsed NOTIFY defaultServerDescriptionChanged)
Q_PROPERTY(QString defaultServerDescriptionExpanded READ getDefaultServerDescriptionExpanded NOTIFY defaultServerDescriptionChanged)
Q_PROPERTY(int currentlyProcessedIndex READ getCurrentlyProcessedServerIndex WRITE setCurrentlyProcessedServerIndex
NOTIFY currentlyProcessedServerIndexChanged)
@@ -41,6 +53,8 @@ public slots:
const int getDefaultServerIndex();
const QString getDefaultServerName();
const QString getDefaultServerHostName();
const QString getDefaultServerDescriptionCollapsed();
const QString getDefaultServerDescriptionExpanded();
bool isDefaultServerCurrentlyProcessed();
bool isCurrentlyProcessedServerHasWriteAccess();
@@ -53,13 +67,34 @@ public slots:
int getCurrentlyProcessedServerIndex();
QString getCurrentlyProcessedServerHostName();
const ServerCredentials getCurrentlyProcessedServerCredentials();
const ServerCredentials getServerCredentials(const int index);
void addServer(const QJsonObject &server);
void editServer(const QJsonObject &server);
void removeServer();
bool isDefaultServerConfigContainsAmneziaDns();
bool isAmneziaDnsContainerInstalled(const int serverIndex);
void updateContainersConfig();
QJsonObject getDefaultServerConfig();
void reloadContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config);
void addContainerConfig(const int containerIndex, const QJsonObject config);
void clearCachedProfiles();
ErrorCode removeContainer(const int containerIndex);
ErrorCode removeAllContainers();
void setDefaultContainer(const int containerIndex);
DockerContainer getDefaultContainer();
const QString getDefaultContainerName();
QStringList getAllInstalledServicesName(const int serverIndex);
void toggleAmneziaDns(bool enabled);
protected:
QHash<int, QByteArray> roleNames() const override;
@@ -68,9 +103,16 @@ signals:
void currentlyProcessedServerIndexChanged(const int index);
void defaultServerIndexChanged(const int index);
void defaultServerNameChanged();
void defaultServerDescriptionChanged();
void containersUpdated(QJsonArray &containers);
void defaultContainerChanged(const int containerIndex);
private:
ServerCredentials serverCredentials(int index) const;
void updateContainersModel();
QString getDefaultServerDescription(const QJsonObject &server);
QJsonArray m_servers;
@@ -78,6 +120,8 @@ private:
int m_defaultServerIndex;
int m_currentlyProcessedServerIndex;
bool m_isAmneziaDnsEnabled = m_settings->useAmneziaDns();
};
#endif // SERVERSMODEL_H
@@ -138,6 +138,10 @@ Button {
}
onClicked: {
if (!ApiController.updateServerConfigFromApi()) {
return
}
if (!ContainersModel.isAnyContainerInstalled()) {
PageController.setTriggeredBtConnectButton(true)
@@ -60,9 +60,8 @@ ListView {
}
if (checked) {
isDefault = true
ServersModel.setDefaultContainer(proxyContainersModel.mapToSource(index))
menuContent.currentIndex = index
containersDropDown.menuVisible = false
} else {
if (!isSupported && isInstalled) {
@@ -112,6 +112,30 @@ DrawerType {
}
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 8
visible: nativeConfigString.text !== ""
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
borderWidth: 1
text: qsTr("Copy config string")
imageSource: "qrc:/images/controls/copy.svg"
onClicked: {
nativeConfigString.selectAll()
nativeConfigString.copy()
nativeConfigString.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 24
@@ -170,6 +194,12 @@ DrawerType {
}
TextField {
id: nativeConfigString
visible: false
text: ExportController.nativeConfigString
}
TextArea {
id: configText
Layout.fillWidth: true
@@ -213,7 +243,6 @@ DrawerType {
Image {
anchors.fill: parent
anchors.margins: 2
smooth: false
source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""
+1
View File
@@ -87,6 +87,7 @@ Switch {
id: content
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
ListItemTitleType {
Layout.fillWidth: true
+6 -43
View File
@@ -22,10 +22,6 @@ PageType {
property string borderColor: "#2C2D30"
property string defaultServerName: ServersModel.defaultServerName
property string defaultServerHostName: ServersModel.defaultServerHostName
property string defaultContainerName: ContainersModel.defaultContainerName
Connections {
target: PageController
@@ -40,41 +36,6 @@ PageType {
}
}
Connections {
target: ServersModel
function onDefaultServerIndexChanged() {
updateDescriptions()
}
}
Connections {
target: ContainersModel
function onDefaultContainerChanged() {
updateDescriptions()
}
}
function updateDescriptions() {
var description = ""
if (ServersModel.isDefaultServerHasWriteAccess()) {
if (SettingsController.isAmneziaDnsEnabled()
&& ContainersModel.isAmneziaDnsContainerInstalled(ServersModel.getDefaultServerIndex())) {
description += "Amnezia DNS | "
}
} else {
if (ServersModel.isDefaultServerConfigContainsAmneziaDns()) {
description += "Amnezia DNS | "
}
}
collapsedServerMenuDescription.text = description + root.defaultContainerName + " | " + root.defaultServerHostName
expandedServersMenuDescription.text = description + root.defaultServerHostName
}
Component.onCompleted: updateDescriptions()
MouseArea {
anchors.fill: parent
enabled: buttonContent.state === "expanded"
@@ -267,7 +228,7 @@ PageType {
maximumLineCount: 2
elide: Qt.ElideRight
text: root.defaultServerName
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
Behavior on opacity {
@@ -304,6 +265,7 @@ PageType {
Layout.bottomMargin: 44
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
visible: buttonContent.collapsedVisibility
text: ServersModel.defaultServerDescriptionCollapsed
}
ColumnLayout {
@@ -319,7 +281,7 @@ PageType {
Layout.leftMargin: 16
Layout.rightMargin: 16
text: root.defaultServerName
text: ServersModel.defaultServerName
horizontalAlignment: Qt.AlignHCenter
maximumLineCount: 2
elide: Qt.ElideRight
@@ -331,6 +293,7 @@ PageType {
Layout.fillWidth: true
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: ServersModel.defaultServerDescriptionExpanded
}
RowLayout {
@@ -349,7 +312,7 @@ PageType {
rootButtonTextTopMargin: 8
rootButtonTextBottomMargin: 8
text: root.defaultContainerName
text: ServersModel.defaultContainerName
textColor: "#0E0E11"
headerText: qsTr("VPN protocol")
headerBackButtonImage: "qrc:/images/controls/arrow-left.svg"
@@ -468,7 +431,7 @@ PageType {
var description = ""
if (hasWriteAccess) {
if (SettingsController.isAmneziaDnsEnabled()
&& ContainersModel.isAmneziaDnsContainerInstalled(index)) {
&& ServersModel.isAmneziaDnsContainerInstalled(index)) {
description += "Amnezia DNS | "
}
} else {
@@ -312,9 +312,8 @@ PageType {
onClicked: {
forceActiveFocus()
PageController.showBusyIndicator(true)
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
PageController.showBusyIndicator(false)
}
}
}
@@ -4,6 +4,8 @@ import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
@@ -160,9 +162,8 @@ PageType {
onClicked: {
forceActiveFocus()
PageController.showBusyIndicator(true)
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(CloakConfigModel.getConfig())
PageController.showBusyIndicator(false)
}
}
}
@@ -390,9 +390,8 @@ PageType {
onClicked: {
forceActiveFocus()
PageController.showBusyIndicator(true)
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
PageController.showBusyIndicator(false)
}
}
}
@@ -4,6 +4,8 @@ import QtQuick.Layouts
import SortFilterProxyModel 0.2
import PageEnum 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
@@ -138,9 +140,8 @@ PageType {
onClicked: {
forceActiveFocus()
PageController.showBusyIndicator(true)
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
PageController.showBusyIndicator(false)
}
}
}
@@ -66,8 +66,8 @@ PageType {
text: qsTr("Website address")
descriptionText: {
var config = ContainersModel.getCurrentlyProcessedContainerConfig()
var containerIndex = ContainersModel.getCurrentlyProcessedContainerIndex()
var config = ContainersModel.getContainerConfig(containerIndex)
return config[ContainerProps.containerTypeToString(containerIndex)]["site"]
}
@@ -77,7 +77,7 @@ PageType {
text: name
descriptionText: {
var servicesNameString = ""
var servicesName = ContainersModel.getAllInstalledServicesName(index)
var servicesName = ServersModel.getAllInstalledServicesName(index)
for (var i = 0; i < servicesName.length; i++) {
servicesNameString += servicesName[i] + " · "
}
@@ -54,7 +54,7 @@ PageType {
regularExpression: InstallController.ipAddressPortRegExp()
}
onTextFieldTextChanged: {
onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
}
}
@@ -81,6 +81,10 @@ PageType {
clickedFunc: function() {
hidePassword = !hidePassword
}
onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
}
}
BasicButtonType {
@@ -90,6 +94,7 @@ PageType {
text: qsTr("Continue")
onClicked: function() {
forceActiveFocus()
if (!isCredentialsFilled()) {
return
}
@@ -112,8 +117,7 @@ PageType {
Layout.fillWidth: true
Layout.topMargin: 12
text: qsTr("All data you enter will remain strictly confidential
and will not be shared or disclosed to the Amnezia or any third parties")
text: qsTr("All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties")
}
}
}
@@ -19,13 +19,14 @@ PageType {
property bool isTimerRunning: true
property string progressBarText: qsTr("Usually it takes no more than 5 minutes")
property bool isCancelButtonVisible: false
Connections {
target: InstallController
function onInstallContainerFinished(finishedMessage, isServiceInstall) {
if (!ConnectionController.isConnected && !isServiceInstall) {
ContainersModel.setDefaultContainer(ContainersModel.getCurrentlyProcessedContainerIndex())
ServersModel.setDefaultContainer(ContainersModel.getCurrentlyProcessedContainerIndex())
}
PageController.closePage() // close installing page
@@ -61,11 +62,13 @@ PageType {
function onServerIsBusy(isBusy) {
if (isBusy) {
root.isCancelButtonVisible = true
root.progressBarText = qsTr("Amnezia has detected that your server is currently ") +
qsTr("busy installing other software. Amnezia installation ") +
qsTr("will pause until the server finishes installing other software")
root.isTimerRunning = false
} else {
root.isCancelButtonVisible = false
root.progressBarText = qsTr("Usually it takes no more than 5 minutes")
root.isTimerRunning = true
}
@@ -150,6 +153,22 @@ PageType {
text: root.progressBarText
}
BasicButtonType {
id: cancelIntallationButton
Layout.fillWidth: true
Layout.topMargin: 24
visible: root.isCancelButtonVisible
text: qsTr("Cancel installation")
onClicked: {
InstallController.cancelInstallation()
PageController.showBusyIndicator(true)
}
}
}
}
}
@@ -60,6 +60,7 @@ PageType {
target: InstallController
function onInstallationErrorOccurred(errorMessage) {
PageController.showBusyIndicator(false)
PageController.showErrorMessage(errorMessage)
var currentPageName = stackView.currentItem.objectName
@@ -24,7 +24,7 @@ PageType {
}
function onImportFinished() {
if (ConnectionController.isConnected) {
if (!ConnectionController.isConnected) {
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
}
+353 -51
View File
@@ -18,15 +18,29 @@ PageType {
enum ConfigType {
AmneziaConnection,
AmneziaFullAccess,
OpenVpn,
WireGuard
WireGuard,
ShadowSocks,
Cloak
}
signal revokeConfig(int index)
onRevokeConfig: function(index) {
PageController.showBusyIndicator(true)
ExportController.revokeConfig(index,
ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
PageController.showNotificationMessage(qsTr("Config revoked"))
}
Connections {
target: ExportController
function onGenerateConfig(type) {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open()
@@ -34,28 +48,34 @@ PageType {
PageController.showBusyIndicator(true)
switch (type) {
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(); break;
case PageShare.ConfigType.AmneziaFullAccess: {
if (Qt.platform.os === "android") {
ExportController.generateFullAccessConfigAndroid();
} else {
ExportController.generateFullAccessConfig();
}
break;
}
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(clientNameTextField.textFieldText); break;
case PageShare.ConfigType.OpenVpn: {
ExportController.generateOpenVpnConfig();
ExportController.generateOpenVpnConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config")
shareConnectionDrawer.configExtension = ".ovpn"
shareConnectionDrawer.configFileName = "amnezia_for_openvpn"
break;
break
}
case PageShare.ConfigType.WireGuard: {
ExportController.generateWireGuardConfig();
ExportController.generateWireGuardConfig(clientNameTextField.textFieldText)
shareConnectionDrawer.configCaption = qsTr("Save WireGuard config")
shareConnectionDrawer.configExtension = ".conf"
shareConnectionDrawer.configFileName = "amnezia_for_wireguard"
break;
break
}
case PageShare.ConfigType.ShadowSocks: {
ExportController.generateShadowSocksConfig()
shareConnectionDrawer.configCaption = qsTr("Save ShadowSocks config")
shareConnectionDrawer.configExtension = ".json"
shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks"
break
}
case PageShare.ConfigType.Cloak: {
ExportController.generateCloakConfig()
shareConnectionDrawer.configCaption = qsTr("Save Cloak config")
shareConnectionDrawer.configExtension = ".json"
shareConnectionDrawer.configFileName = "amnezia_for_cloak"
break
}
}
@@ -73,8 +93,7 @@ PageType {
}
}
property string fullConfigServerSelectorText
property string connectionServerSelectorText
property bool isSearchBarVisible: false
property bool showContent: false
property bool shareButtonEnabled: true
property list<QtObject> connectionTypesModel: [
@@ -96,6 +115,16 @@ PageType {
property string name: qsTr("WireGuard native format")
property var type: PageShare.ConfigType.WireGuard
}
QtObject {
id: shadowSocksConnectionFormat
property string name: qsTr("ShadowSocks native format")
property var type: PageShare.ConfigType.ShadowSocks
}
QtObject {
id: cloakConnectionFormat
property string name: qsTr("Cloak native format")
property var type: PageShare.ConfigType.Cloak
}
FlickableType {
anchors.top: parent.top
@@ -119,6 +148,51 @@ PageType {
Layout.topMargin: 24
headerText: qsTr("Share VPN Access")
actionButtonImage: "qrc:/images/controls/more-vertical.svg"
actionButtonFunction: function() {
shareFullAccessDrawer.open()
}
DrawerType {
id: shareFullAccessDrawer
width: root.width
height: root.height * 0.45
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
spacing: 0
Header2Type {
Layout.fillWidth: true
Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Share full access to the server and VPN")
descriptionText: qsTr("Use for your own devices, or share with those you trust to manage the server.")
}
LabelWithButtonType {
Layout.fillWidth: true
text: qsTr("Share")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageShareFullAccess)
shareFullAccessDrawer.close()
}
}
}
}
}
Rectangle {
@@ -147,20 +221,21 @@ PageType {
onClicked: {
accessTypeSelector.currentIndex = 0
serverSelector.text = root.connectionServerSelectorText
}
}
HorizontalRadioButton {
checked: root.currentIndex === 1
checked: accessTypeSelector.currentIndex === 1
implicitWidth: (root.width - 32) / 2
text: qsTr("Full access")
text: qsTr("Users")
onClicked: {
accessTypeSelector.currentIndex = 1
serverSelector.text = root.fullConfigServerSelectorText
root.shareButtonEnabled = true
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
}
}
}
@@ -171,16 +246,30 @@ PageType {
Layout.topMargin: 24
Layout.bottomMargin: 24
text: accessTypeSelector.currentIndex === 0 ? qsTr("Share VPN access without the ability to manage the server") :
qsTr("Share access to server management. The user with whom you share full access to the server will be able to add and remove any protocols and services to the server, as well as change settings.")
visible: accessTypeSelector.currentIndex === 0
text: qsTr("Share VPN access without the ability to manage the server")
color: "#878B91"
}
TextFieldWithHeaderType {
id: clientNameTextField
Layout.fillWidth: true
Layout.topMargin: 16
visible: accessTypeSelector.currentIndex === 0
headerText: qsTr("User name")
textFieldText: "New client"
checkEmptyText: true
}
DropDownType {
id: serverSelector
signal severSelectorIndexChanged
property int currentIndex: 0
property int currentIndex: -1
Layout.fillWidth: true
Layout.topMargin: 16
@@ -207,8 +296,6 @@ PageType {
]
}
currentIndex: 0
clickedFunction: function() {
handler()
@@ -217,22 +304,17 @@ PageType {
serverSelector.severSelectorIndexChanged()
}
if (accessTypeSelector.currentIndex !== 0) {
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
}
serverSelector.menuVisible = false
}
Component.onCompleted: {
handler()
serverSelector.severSelectorIndexChanged()
serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ?
proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0
serverSelectorListView.triggerCurrentItem()
}
function handler() {
serverSelector.text = selectedText
root.fullConfigServerSelectorText = selectedText
root.connectionServerSelectorText = selectedText
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex)
}
}
@@ -241,8 +323,6 @@ PageType {
DropDownType {
id: protocolSelector
visible: accessTypeSelector.currentIndex === 0
Layout.fillWidth: true
Layout.topMargin: 16
@@ -280,17 +360,11 @@ PageType {
protocolSelector.menuVisible = false
}
Component.onCompleted: {
if (accessTypeSelector.currentIndex === 0) {
handler()
}
}
Connections {
target: serverSelector
function onSeverSelectorIndexChanged() {
protocolSelectorListView.currentIndex = 0
protocolSelectorListView.currentIndex = proxyContainersModel.mapFromSource(ServersModel.getDefaultContainer())
protocolSelectorListView.triggerCurrentItem()
}
}
@@ -304,13 +378,17 @@ PageType {
}
protocolSelector.text = selectedText
root.connectionServerSelectorText = serverSelector.text
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex))
fillConnectionTypeModel()
if (accessTypeSelector.currentIndex === 1) {
PageController.showBusyIndicator(true)
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
}
}
function fillConnectionTypeModel() {
@@ -322,6 +400,13 @@ PageType {
root.connectionTypesModel.push(openVpnConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-wireguard")) {
root.connectionTypesModel.push(wireGuardConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
root.connectionTypesModel.push(shadowSocksConnectionFormat)
} else if (index === ContainerProps.containerFromString("amnezia-openvpn-cloak")) {
root.connectionTypesModel.push(openVpnConnectionFormat)
root.connectionTypesModel.push(shadowSocksConnectionFormat)
root.connectionTypesModel.push(cloakConnectionFormat)
}
}
}
@@ -378,18 +463,235 @@ PageType {
Layout.topMargin: 40
enabled: shareButtonEnabled
visible: accessTypeSelector.currentIndex === 0
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
onClicked: {
if (accessTypeSelector.currentIndex === 0) {
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
} else {
ExportController.generateConfig(PageShare.ConfigType.AmneziaFullAccess)
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
}
}
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 16
visible: accessTypeSelector.currentIndex === 1 && !root.isSearchBarVisible
headerText: qsTr("Users")
actionButtonImage: "qrc:/images/controls/search.svg"
actionButtonFunction: function() {
root.isSearchBarVisible = true
}
}
RowLayout {
Layout.topMargin: 24
Layout.bottomMargin: 16
visible: accessTypeSelector.currentIndex === 1 && root.isSearchBarVisible
TextFieldWithHeaderType {
id: searchTextField
Layout.fillWidth: true
textFieldPlaceholderText: qsTr("Search")
}
ImageButtonType {
image: "qrc:/images/controls/close.svg"
imageColor: "#D7D8DB"
onClicked: function() {
root.isSearchBarVisible = false
searchTextField.textFieldText = ""
}
}
}
ListView {
id: clientsListView
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
visible: accessTypeSelector.currentIndex === 1
model: SortFilterProxyModel {
id: proxyClientManagementModel
sourceModel: ClientManagementModel
filters: RegExpFilter {
roleName: "clientName"
pattern: ".*" + searchTextField.textFieldText + ".*"
caseSensitivity: Qt.CaseInsensitive
}
}
clip: true
interactive: false
delegate: Item {
implicitWidth: clientsListView.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: -16
anchors.leftMargin: -16
LabelWithButtonType {
Layout.fillWidth: true
text: clientName
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
clientInfoDrawer.open()
}
}
DividerType {}
DrawerType {
id: clientInfoDrawer
width: root.width
height: root.height * 0.5
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 8
Header2Type {
Layout.fillWidth: true
Layout.bottomMargin: 24
headerText: clientName
descriptionText: serverSelector.text
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 24
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
borderWidth: 1
text: qsTr("Rename")
onClicked: function() {
clientNameEditDrawer.open()
}
DrawerType {
id: clientNameEditDrawer
width: root.width
height: root.height * 0.35
onVisibleChanged: {
if (clientNameEditDrawer.visible) {
clientNameEditor.textField.forceActiveFocus()
}
}
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
anchors.leftMargin: 16
anchors.rightMargin: 16
TextFieldWithHeaderType {
id: clientNameEditor
Layout.fillWidth: true
headerText: qsTr("Client name")
textFieldText: clientName
textField.maximumLength: 30
}
BasicButtonType {
Layout.fillWidth: true
text: qsTr("Save")
onClicked: {
if (clientNameEditor.textFieldText !== clientName) {
PageController.showBusyIndicator(true)
ExportController.renameClient(index,
clientNameEditor.textFieldText,
ContainersModel.getCurrentlyProcessedContainerIndex(),
ServersModel.getCurrentlyProcessedServerCredentials())
PageController.showBusyIndicator(false)
clientNameEditDrawer.close()
}
}
}
}
}
}
BasicButtonType {
Layout.fillWidth: true
defaultColor: "transparent"
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
pressedColor: Qt.rgba(1, 1, 1, 0.12)
disabledColor: "#878B91"
textColor: "#D7D8DB"
borderWidth: 1
text: qsTr("Revoke")
onClicked: function() {
questionDrawer.headerText = qsTr("Revoke the config for a user - ") + clientName + "?"
questionDrawer.descriptionText = qsTr("The user will no longer be able to connect to your server.")
questionDrawer.yesButtonText = qsTr("Continue")
questionDrawer.noButtonText = qsTr("Cancel")
questionDrawer.yesButtonFunction = function() {
questionDrawer.close()
clientInfoDrawer.close()
root.revokeConfig(index)
}
questionDrawer.noButtonFunction = function() {
questionDrawer.close()
}
questionDrawer.open()
}
}
}
}
}
}
}
QuestionDrawer {
id: questionDrawer
}
}
}
MouseArea {
anchors.fill: parent
onPressed: function(mouse) {
forceActiveFocus()
mouse.accepted = false
}
}
}
@@ -0,0 +1,155 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import SortFilterProxyModel 0.2
import PageEnum 1.0
import ContainerProps 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Components"
PageType {
id: root
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
}
FlickableType {
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 0
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 24
headerText: qsTr("Full access to the server and VPN")
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") +
qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ")
color: "#878B91"
}
DropDownType {
id: serverSelector
signal severSelectorIndexChanged
property int currentIndex: 0
Layout.fillWidth: true
Layout.topMargin: 16
drawerHeight: 0.4375
descriptionText: qsTr("Server")
headerText: qsTr("Server")
listView: ListViewWithRadioButtonType {
id: serverSelectorListView
rootWidth: root.width
imageSource: "qrc:/images/controls/check.svg"
model: SortFilterProxyModel {
id: proxyServersModel
sourceModel: ServersModel
filters: [
ValueFilter {
roleName: "hasWriteAccess"
value: true
}
]
}
currentIndex: 0
clickedFunction: function() {
handler()
if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) {
serverSelector.currentIndex = serverSelectorListView.currentIndex
}
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
serverSelector.menuVisible = false
}
Component.onCompleted: {
handler()
}
function handler() {
serverSelector.text = selectedText
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex)
}
}
}
BasicButtonType {
Layout.fillWidth: true
Layout.topMargin: 40
text: qsTr("Share")
imageSource: "qrc:/images/controls/share-2.svg"
onClicked: function() {
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
shareConnectionDrawer.needCloseButton = false
shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true)
if (Qt.platform.os === "android") {
ExportController.generateFullAccessConfigAndroid();
} else {
ExportController.generateFullAccessConfig();
}
PageController.showBusyIndicator(false)
shareConnectionDrawer.needCloseButton = true
PageController.showTopCloseButton(true)
shareConnectionDrawer.contentVisible = true
}
}
ShareConnectionDrawer {
id: shareConnectionDrawer
}
}
}
}
+3
View File
@@ -82,6 +82,7 @@ PageType {
target: InstallController
function onInstallationErrorOccurred(errorMessage) {
PageController.showBusyIndicator(false)
PageController.showErrorMessage(errorMessage)
var needCloseCurrentPage = false
@@ -99,6 +100,7 @@ PageType {
function onUpdateContainerFinished(message) {
PageController.showNotificationMessage(message)
PageController.closePage()
}
}
@@ -107,6 +109,7 @@ PageType {
function onReconnectWithUpdatedContainer(message) {
PageController.showNotificationMessage(message)
PageController.closePage()
}
}