diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp index 4d372226..2e3b7866 100644 --- a/client/amnezia_application.cpp +++ b/client/amnezia_application.cpp @@ -322,12 +322,15 @@ void AmneziaApplication::initModels() m_clientManagementModel.reset(new ClientManagementModel(m_settings, this)); m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get()); + connect(m_clientManagementModel.get(), &ClientManagementModel::adminConfigRevoked, + m_serversModel.get(), &ServersModel::clearCachedProfile); connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, this, [this](const QString &clientId, const QString &clientName, const DockerContainer container, ServerCredentials credentials) { m_serversModel->reloadContainerConfig(); m_clientManagementModel->appendClient(clientId, clientName, container, credentials); + emit m_configurator->clientModelUpdated(); }); } diff --git a/client/configurators/vpn_configurator.h b/client/configurators/vpn_configurator.h index 61dc2ac6..7164bd8e 100644 --- a/client/configurators/vpn_configurator.h +++ b/client/configurators/vpn_configurator.h @@ -46,6 +46,7 @@ public: signals: void newVpnConfigCreated(const QString &clientId, const QString &clientName, const DockerContainer container, ServerCredentials credentials); + void clientModelUpdated(); }; #endif // VPN_CONFIGURATOR_H diff --git a/client/translations/amneziavpn_ru.ts b/client/translations/amneziavpn_ru.ts index 4f24e540..58171e67 100644 --- a/client/translations/amneziavpn_ru.ts +++ b/client/translations/amneziavpn_ru.ts @@ -92,7 +92,7 @@ Configure your server - Настроить ваш сервер + Настроить свой сервер @@ -174,7 +174,7 @@ Added containers that were already installed on the server - + Добавлены сервисы и протоколы, которые были ранее установлены на сервер @@ -196,7 +196,7 @@ Already installed containers were found on the server. All installed containers All containers from server '%1' have been removed - Все протоклы и сервисы были удалены с сервера '%1' + Все протоколы и сервисы были удалены с сервера '%1' @@ -1012,17 +1012,17 @@ Already installed containers were found on the server. All installed containers Allow application screenshots - + Разрешить скриншоты приложения Auto start - + Автозапуск Launch the application every time the device is starts - + Открывать приложение при запуске устройства @@ -1353,7 +1353,7 @@ Already installed containers were found on the server. All installed containers Clear cached profiles? - Удалить кэш Amnezia с сервера? + Удалить кэш Amnezia? @@ -1680,7 +1680,7 @@ and will not be shared or disclosed to the Amnezia or any third parties All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties - + Все введенные вами данные останутся строго конфиденциальными и не будут переданы или раскрыты Amnezia или третьим лицам @@ -1703,7 +1703,7 @@ and will not be shared or disclosed to the Amnezia or any third parties What is the level of internet control in your region? - Какой уровень контроля интеренета в вашем регионе? + Какой уровень контроля интернета в вашем регионе? @@ -1978,12 +1978,12 @@ and will not be shared or disclosed to the Amnezia or any third parties Save ShadowSocks config - + Сохранить конфигурацию ShadowSocks Save Cloak config - + Сохранить конфигурацию Cloak @@ -1993,12 +1993,12 @@ and will not be shared or disclosed to the Amnezia or any third parties ShadowSocks native format - + ShadowSocks нативный формат Cloak native format - + Cloak нативный формат @@ -2008,23 +2008,23 @@ and will not be shared or disclosed to the Amnezia or any third parties Share full access to the server and VPN - + Поделиться полным доступом к серверу Use for your own devices, or share with those you trust to manage the server. - + Используйте для собственных устройств или передайте управление сервером тем, кому вы доверяете. Users - + Пользователи User name - + Имя пользователя @@ -2059,7 +2059,7 @@ and will not be shared or disclosed to the Amnezia or any third parties The user will no longer be able to connect to your server. - + Пользователь больше не сможет подключаться к вашему серверу @@ -2104,24 +2104,24 @@ and will not be shared or disclosed to the Amnezia or any third parties Full access to the server and VPN - + Полный доступ к серверу и VPN We recommend that you use full access to the server only for your own additional devices. - + Мы рекомендуем использовать полный доступ к серверу только для собственных устройств. 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. - + Если вы поделитесь полным доступом с другими людьми, то они смогут удалять и добавлять протоколы и сервисы на сервер, что приведет к некорректной работе VPN для всех пользователей. Server - + Сервер @@ -2537,7 +2537,7 @@ and will not be shared or disclosed to the Amnezia or any third parties The config does not contain any containers and credentials for connecting to the server - + Конфиг не содержит контейнеров и учетных данных для подключения к серверу Failed to save config to disk @@ -2814,7 +2814,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin Sftp file sharing service - is secure FTP service - Сервис обмена файлами Sftp - безопасный FTP-сервис + Файловое хранилище для безопасного хранения данных @@ -2959,7 +2959,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin Show connection settings - + Показать настройки подключения diff --git a/client/ui/controllers/exportController.cpp b/client/ui/controllers/exportController.cpp index 815a241e..4f3fe7d5 100644 --- a/client/ui/controllers/exportController.cpp +++ b/client/ui/controllers/exportController.cpp @@ -48,6 +48,22 @@ void ExportController::generateFullAccessConfig() int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); QJsonObject config = m_settings->server(serverIndex); + QJsonArray containers = config.value(config_key::containers).toArray(); + for (auto i = 0; i < containers.size(); i++) { + auto containerConfig = containers.at(i).toObject(); + auto containerType = ContainerProps::containerFromString(containerConfig.value(config_key::container).toString()); + + for (auto protocol : ContainerProps::protocolsForContainer(containerType)) { + auto protocolConfig = containerConfig.value(ProtocolProps::protoToString(protocol)).toObject(); + + protocolConfig.remove(config_key::last_config); + containerConfig[ProtocolProps::protoToString(protocol)] = protocolConfig; + } + + containers.replace(i, containerConfig); + } + config[config_key::containers] = containers; + QByteArray compressedConfig = QJsonDocument(config).toJson(); compressedConfig = qCompress(compressedConfig, 8); m_config = QString("vpn://%1") diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp index 8ec31d02..f1576d08 100644 --- a/client/ui/models/clientManagementModel.cpp +++ b/client/ui/models/clientManagementModel.cpp @@ -15,6 +15,7 @@ namespace constexpr char clientName[] = "clientName"; constexpr char container[] = "container"; constexpr char userData[] = "userData"; + constexpr char creationDate[] = "creationDate"; } } @@ -40,11 +41,29 @@ QVariant ClientManagementModel::data(const QModelIndex &index, int role) const switch (role) { case ClientNameRole: return userData.value(configKey::clientName).toString(); + case CreationDateRole: return userData.value(configKey::creationDate).toString(); } return QVariant(); } +void ClientManagementModel::migration(const QByteArray &clientsTableString) +{ + QJsonObject clientsTable = QJsonDocument::fromJson(clientsTableString).object(); + + for (auto &clientId : clientsTable.keys()) { + QJsonObject client; + client[configKey::clientId] = clientId; + + QJsonObject userData; + userData[configKey::clientName] = clientsTable.value(clientId).toObject().value(configKey::clientName); + client[configKey::userData] = userData; + + m_clientsTable.push_back(client); + } + +} + ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials) { beginResetModel(); @@ -54,8 +73,14 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr ErrorCode error = ErrorCode::NoError; - const QString clientsTableFile = - QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container)); + QString clientsTableFile = QString("/opt/amnezia/%1/clientsTable"); + if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks + || container == DockerContainer::Cloak) { + clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(DockerContainer::OpenVpn)); + } else { + clientsTableFile = clientsTableFile.arg(ContainerProps::containerTypeToString(container)); + } + const QByteArray clientsTableString = serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error); if (error != ErrorCode::NoError) { @@ -67,6 +92,8 @@ ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCr m_clientsTable = QJsonDocument::fromJson(clientsTableString).array(); if (m_clientsTable.isEmpty()) { + migration(clientsTableString); + int count = 0; if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks @@ -200,19 +227,20 @@ ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QSt 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); + return renameClient(i, clientName, container, credentials, true); } } - beginResetModel(); + beginInsertRows(QModelIndex(), rowCount(), 1); QJsonObject client; client[configKey::clientId] = clientId; QJsonObject userData; userData[configKey::clientName] = clientName; + userData[configKey::creationDate] = QDateTime::currentDateTime().toString(); client[configKey::userData] = userData; m_clientsTable.push_back(client); - endResetModel(); + endInsertRows(); const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson(); @@ -229,11 +257,14 @@ ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QSt } ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName, const DockerContainer container, - ServerCredentials credentials) + ServerCredentials credentials, bool addTimeStamp) { auto client = m_clientsTable.at(row).toObject(); auto userData = client[configKey::userData].toObject(); userData[configKey::clientName] = clientName; + if (addTimeStamp) { + userData[configKey::creationDate] = QDateTime::currentDateTime().toString(); + } client[configKey::userData] = userData; m_clientsTable.replace(row, client); @@ -257,13 +288,33 @@ ErrorCode ClientManagementModel::renameClient(const int row, const QString &clie ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container, ServerCredentials credentials) { + ErrorCode errorCode = ErrorCode::NoError; + if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) { - return revokeOpenVpn(row, container, credentials); + errorCode = revokeOpenVpn(row, container, credentials); } else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) { - return revokeWireGuard(row, container, credentials); + errorCode = revokeWireGuard(row, container, credentials); } - return ErrorCode::NoError; + + if (errorCode == ErrorCode::NoError) { + auto client = m_clientsTable.at(row).toObject(); + QString clientId = client.value(configKey::clientId).toString(); + + const auto server = m_settings->defaultServer(); + QJsonArray containers = server.value(config_key::containers).toArray(); + for (auto i = 0; i < containers.size(); i++) { + auto containerConfig = containers.at(i).toObject(); + auto containerType = ContainerProps::containerFromString(containerConfig.value(config_key::container).toString()); + auto protocolConfig = containerConfig.value(ContainerProps::containerTypeToString(containerType)).toObject(); + + if (protocolConfig.value(config_key::last_config).toString().contains(clientId)) { + emit adminConfigRevoked(container); + } + } + } + + return errorCode; } ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container, @@ -369,5 +420,6 @@ QHash ClientManagementModel::roleNames() const { QHash roles; roles[ClientNameRole] = "clientName"; + roles[CreationDateRole] = "creationDate"; return roles; } diff --git a/client/ui/models/clientManagementModel.h b/client/ui/models/clientManagementModel.h index 6b6adf68..ba36c26f 100644 --- a/client/ui/models/clientManagementModel.h +++ b/client/ui/models/clientManagementModel.h @@ -14,6 +14,7 @@ class ClientManagementModel : public QAbstractListModel public: enum Roles { ClientNameRole = Qt::UserRole + 1, + CreationDateRole }; ClientManagementModel(std::shared_ptr settings, QObject *parent = nullptr); @@ -26,15 +27,20 @@ public slots: 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); + ServerCredentials credentials, bool addTimeStamp = false); ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials); protected: QHash roleNames() const override; +signals: + void adminConfigRevoked(const DockerContainer container); + private: bool isClientExists(const QString &clientId); + void migration(const QByteArray &clientsTableString); + ErrorCode revokeOpenVpn(const int row, const DockerContainer container, ServerCredentials credentials); ErrorCode revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials); diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index ad927fce..b8bfbbc5 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -479,6 +479,14 @@ void ServersModel::clearCachedProfiles() updateContainersModel(); } +void ServersModel::clearCachedProfile(const DockerContainer container) +{ + 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(); diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h index 901605e2..af88febb 100644 --- a/client/ui/models/servers_model.h +++ b/client/ui/models/servers_model.h @@ -84,6 +84,7 @@ public slots: void addContainerConfig(const int containerIndex, const QJsonObject config); void clearCachedProfiles(); + void clearCachedProfile(const DockerContainer container); ErrorCode removeContainer(const int containerIndex); ErrorCode removeAllContainers(); diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml index 80354330..3a769ebe 100644 --- a/client/ui/qml/Pages2/PageShare.qml +++ b/client/ui/qml/Pages2/PageShare.qml @@ -581,7 +581,7 @@ PageType { Layout.bottomMargin: 24 headerText: clientName - descriptionText: serverSelector.text + descriptionText: qsTr("Creation date: ") + creationDate } BasicButtonType { diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index 6b3dae9b..5d4d5f99 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -250,7 +251,10 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, const Ser m_settings->setProtocolConfig(serverIndex, container, proto, protoObject); } - emit m_configurator->newVpnConfigCreated(clientId, "unnamed client", container, credentials); + QEventLoop wait; + emit m_configurator->newVpnConfigCreated(clientId, QString("Admin [%1]").arg(QSysInfo::prettyProductName()), container, credentials); + QObject::connect(m_configurator.get(), &VpnConfigurator::clientModelUpdated, &wait, &QEventLoop::quit); + wait.exec(); } return configData;