diff --git a/client/core/servercontroller.cpp b/client/core/servercontroller.cpp index c7336b62..ca00f91d 100644 --- a/client/core/servercontroller.cpp +++ b/client/core/servercontroller.cpp @@ -796,6 +796,59 @@ SshConnection *ServerController::connectToHost(const SshConnectionParameters &ss return client; } +ErrorCode ServerController::getClientsList(const ServerCredentials &credentials, DockerContainer container, Proto mainProtocol, QJsonObject &clietns) +{ + QString stdOut; + auto cbReadStdOut = [&](const QString &data, QSharedPointer proc) { + stdOut += data + "\n"; + }; + + ErrorCode error = ErrorCode::NoError; + if (mainProtocol == Proto::OpenVpn) { + error = runScript(credentials, + replaceVars(QString("sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'"), + genVarsForScript(credentials, container)), cbReadStdOut); + // TODO error processing + if (!stdOut.isEmpty()) { + QStringList clietnsNames = stdOut.split("\n", Qt::SkipEmptyParts); + clietnsNames.removeAll("AmneziaReq.crt"); + + QByteArray clientsTableString = getTextFileFromContainer(container, credentials, "opt/amnezia/openvpn/clientsTable"); + QJsonObject clientsTable = QJsonDocument::fromJson(clientsTableString).object(); + for (auto &clietnId : clietnsNames) { + clietnId.replace(".crt", ""); + if (!clientsTable.contains(clietnId)) { + stdOut.clear(); + error = runScript(credentials, + replaceVars(QString("sudo docker exec -i $CONTAINER_NAME bash -c 'cat /opt/amnezia/openvpn/pki/issued/%1.crt'").arg(clietnId), + genVarsForScript(credentials, container)), cbReadStdOut); + // TODO error processing + QJsonObject client; + client["name"] = ""; + client["certificate"] = stdOut; + clientsTable[clietnId] = client; + } + } + QByteArray newClientsTableString = QJsonDocument(clientsTable).toJson(); + if (clientsTableString != newClientsTableString) { + error = uploadTextFileToContainer(container, credentials, newClientsTableString, "opt/amnezia/openvpn/clientsTable"); + } + // TODO error processing + clietns = clientsTable; + } + } else if (mainProtocol == Proto::WireGuard) { + + } + + return error; +} + +ErrorCode ServerController::setClientsList(const ServerCredentials &credentials, DockerContainer container, Proto mainProtocol, QJsonObject &clietns) +{ + auto error = uploadTextFileToContainer(container, credentials, QJsonDocument(clietns).toJson(), "opt/amnezia/openvpn/clientsTable"); + return error; +} + void ServerController::disconnectFromHost(const ServerCredentials &credentials) { SshConnection *client = acquireConnection(sshParams(credentials)); diff --git a/client/core/servercontroller.h b/client/core/servercontroller.h index 091eaa52..11d0dee9 100644 --- a/client/core/servercontroller.h +++ b/client/core/servercontroller.h @@ -73,6 +73,9 @@ public: QString checkSshConnection(const ServerCredentials &credentials, ErrorCode *errorCode = nullptr); QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams); + ErrorCode getClientsList(const ServerCredentials &credentials, DockerContainer container, Proto mainProtocol, QJsonObject &clietns); + ErrorCode setClientsList(const ServerCredentials &credentials, DockerContainer container, Proto mainProtocol, QJsonObject &clietns); + private: ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container); diff --git a/client/resources.qrc b/client/resources.qrc index a7e67e39..130857a7 100644 --- a/client/resources.qrc +++ b/client/resources.qrc @@ -160,5 +160,9 @@ ui/qml/Pages/PageQrDecoderIos.qml server_scripts/website_tor/Dockerfile ui/qml/Pages/PageViewConfig.qml + ui/qml/Pages/PageClientManagement.qml + ui/qml/Pages/ClientInfo/PageClientInfoBase.qml + ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml + ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp new file mode 100644 index 00000000..c3724387 --- /dev/null +++ b/client/ui/models/clientManagementModel.cpp @@ -0,0 +1,75 @@ +#include "clientManagementModel.h" + +ClientManagementModel::ClientManagementModel(std::shared_ptr settings, QObject *parent) : + m_settings(settings), + QAbstractListModel(parent) +{ + +} + +void ClientManagementModel::clearData() +{ + beginResetModel(); + m_content.clear(); + endResetModel(); +} + +void ClientManagementModel::setContent(const QVector &data) +{ + beginResetModel(); + m_content = data; + endResetModel(); +} + +int ClientManagementModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return static_cast(m_content.size()); +} + +QVariant ClientManagementModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 + || index.row() >= static_cast(m_content.size())) { + return QVariant(); + } + + if (role == NameRole) { + return m_content[index.row()].name; + } + if (role == CertIdRole) { + return m_content[index.row()].certId; + } + if (role == CertDataRole) { + return m_content[index.row()].certData; + } + return QVariant(); +} + +void ClientManagementModel::setData(const QModelIndex &index, QVariant data, int role) +{ + if (!index.isValid() || index.row() < 0 + || index.row() >= static_cast(m_content.size())) { + return; + } + + if (role == NameRole) { + m_content[index.row()].name = data.toString(); + } + if (role == CertIdRole) { + m_content[index.row()].certId = data.toString(); + } + if (role == CertDataRole) { + m_content[index.row()].certData = data.toString(); + } + emit dataChanged(index, index); +} + +QHash ClientManagementModel::roleNames() const +{ + QHash roles; + roles[NameRole] = "clientName"; + roles[CertIdRole] = "certId"; + roles[CertDataRole] = "certData"; + return roles; +} diff --git a/client/ui/models/clientManagementModel.h b/client/ui/models/clientManagementModel.h new file mode 100644 index 00000000..6f9cfbc7 --- /dev/null +++ b/client/ui/models/clientManagementModel.h @@ -0,0 +1,42 @@ +#ifndef CLIENTMANAGEMENTMODEL_H +#define CLIENTMANAGEMENTMODEL_H + +#include + +#include "settings.h" + +class ClientManagementModel : public QAbstractListModel +{ + Q_OBJECT + +public: + enum ClientRoles { + NameRole = Qt::UserRole + 1, + CertIdRole, + CertDataRole + }; + + struct ClientInfo + { + QString name; + QString certId; + QString certData; + }; + + ClientManagementModel(std::shared_ptr settings, QObject *parent = nullptr); + + void clearData(); + void setContent(const QVector &data); + 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); + +protected: + QHash roleNames() const override; + +private: + std::shared_ptr m_settings; //TODO remove this? + QVector m_content; +}; + +#endif // CLIENTMANAGEMENTMODEL_H diff --git a/client/ui/pages.h b/client/ui/pages.h index 69f417fa..ca1d1fa9 100644 --- a/client/ui/pages.h +++ b/client/ui/pages.h @@ -12,7 +12,8 @@ public: enum Type { Basic, Proto, - ShareProto + ShareProto, + ClientInfo }; Q_ENUM(Type) }; @@ -24,7 +25,7 @@ enum class Page {Start = 0, NewServer, NewServerProtocols, Vpn, Wizard, WizardLow, WizardMedium, WizardHigh, WizardVpnMode, ServerConfiguringProgress, GeneralSettings, AppSettings, NetworkSettings, ServerSettings, ServerContainers, ServersList, ShareConnection, Sites, - ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About, ViewConfig}; + ProtocolSettings, ProtocolShare, QrDecoder, QrDecoderIos, About, ViewConfig, ClientManagement, ClientInfo}; Q_ENUM_NS(Page) static void declareQmlPageEnum() { diff --git a/client/ui/pages_logic/ClientInfoLogic.cpp b/client/ui/pages_logic/ClientInfoLogic.cpp new file mode 100644 index 00000000..4a401022 --- /dev/null +++ b/client/ui/pages_logic/ClientInfoLogic.cpp @@ -0,0 +1,43 @@ +#include "ClientInfoLogic.h" + +#include "core/servercontroller.h" +#include "ui/models/clientManagementModel.h" +#include "ui/uilogic.h" + +ClientInfoLogic::ClientInfoLogic(UiLogic *logic, QObject *parent): + PageLogicBase(logic, parent) +{ + +} + +void ClientInfoLogic::setCurrentClientId(int index) +{ + m_currentClientIndex = index; +} + +void ClientInfoLogic::onUpdatePage() +{ + DockerContainer selectedContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex); + QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer); + set_labelCurrentVpnProtocolText(tr("Service: ") + selectedContainerName); + + auto model = qobject_cast(uiLogic()->clientManagementModel()); + auto modelIndex = model->index(m_currentClientIndex); + set_lineEditNameAliasText(model->data(modelIndex, ClientManagementModel::ClientRoles::NameRole).toString()); + set_labelCertId(model->data(modelIndex, ClientManagementModel::ClientRoles::CertIdRole).toString()); + set_textAreaCertificate(model->data(modelIndex, ClientManagementModel::ClientRoles::CertDataRole).toString()); +} + +void ClientInfoLogic::onLineEditNameAliasEditingFinished() +{ + auto model = qobject_cast(uiLogic()->clientManagementModel()); + auto modelIndex = model->index(m_currentClientIndex); + model->setData(modelIndex, m_lineEditNameAliasText, ClientManagementModel::ClientRoles::NameRole); + + m_serverController->setClientsList(); +} + +void ClientInfoLogic::onRevokeCertificateClicked() +{ + +} diff --git a/client/ui/pages_logic/ClientInfoLogic.h b/client/ui/pages_logic/ClientInfoLogic.h new file mode 100644 index 00000000..4d2f7e97 --- /dev/null +++ b/client/ui/pages_logic/ClientInfoLogic.h @@ -0,0 +1,32 @@ +#ifndef CLIENTINFOLOGIC_H +#define CLIENTINFOLOGIC_H + +#include "PageLogicBase.h" + +class UiLogic; + +class ClientInfoLogic : public PageLogicBase +{ + Q_OBJECT + + AUTO_PROPERTY(QString, lineEditNameAliasText) + AUTO_PROPERTY(QString, labelCertId) + AUTO_PROPERTY(QString, textAreaCertificate) + AUTO_PROPERTY(QString, labelCurrentVpnProtocolText) + +public: + ClientInfoLogic(UiLogic *uiLogic, QObject *parent = nullptr); + ~ClientInfoLogic() = default; + + void setCurrentClientId(int index); + +public slots: + void onUpdatePage() override; + void onLineEditNameAliasEditingFinished(); + void onRevokeCertificateClicked(); + +private: + int m_currentClientIndex; +}; + +#endif // CLIENTINFOLOGIC_H diff --git a/client/ui/pages_logic/ClientManagementLogic.cpp b/client/ui/pages_logic/ClientManagementLogic.cpp new file mode 100644 index 00000000..96073823 --- /dev/null +++ b/client/ui/pages_logic/ClientManagementLogic.cpp @@ -0,0 +1,44 @@ +#include "ClientManagementLogic.h" + +#include "core/servercontroller.h" +#include "ui/pages_logic/ClientInfoLogic.h" +#include "ui/models/clientManagementModel.h" +#include "ui/uilogic.h" + +ClientManagementLogic::ClientManagementLogic(UiLogic *logic, QObject *parent): + PageLogicBase(logic, parent) +{ + +} + +void ClientManagementLogic::onUpdatePage() +{ + DockerContainer selectedContainer = m_settings->defaultContainer(uiLogic()->selectedServerIndex); + QString selectedContainerName = ContainerProps::containerHumanNames().value(selectedContainer); + set_labelCurrentVpnProtocolText(tr("Service: ") + selectedContainerName); + + QJsonObject clients; + + auto protocols = ContainerProps::protocolsForContainer(selectedContainer); + if (!protocols.empty()) { + m_currentMainProtocol = protocols.front(); + + ErrorCode e = m_serverController->getClientsList(m_settings->serverCredentials(uiLogic()->selectedServerIndex), + selectedContainer, m_currentMainProtocol, clients); + } + QVector clientsArray; + for (auto &clientId : clients.keys()) { + ClientManagementModel::ClientInfo clientInfo; + clientInfo.certId = clientId; + clientInfo.name = clients[clientId].toObject()["name"].toString(); + clientInfo.certData = clients[clientId].toObject()["certificate"].toString(); + clientsArray.push_back(clientInfo); + } + qobject_cast(uiLogic()->clientManagementModel())->setContent(clientsArray); +} + +void ClientManagementLogic::onClientItemClicked(int index) +{ + uiLogic()->pageLogic()->setCurrentClientId(index); + emit uiLogic()->goToClientInfoPage(m_currentMainProtocol); +} diff --git a/client/ui/pages_logic/ClientManagementLogic.h b/client/ui/pages_logic/ClientManagementLogic.h new file mode 100644 index 00000000..3ba17503 --- /dev/null +++ b/client/ui/pages_logic/ClientManagementLogic.h @@ -0,0 +1,28 @@ +#ifndef CLIENTMANAGMENTLOGIC_H +#define CLIENTMANAGMENTLOGIC_H + +#include "PageLogicBase.h" + +#include "protocols/protocols_defs.h" + +class UiLogic; + +class ClientManagementLogic : public PageLogicBase +{ + Q_OBJECT + + AUTO_PROPERTY(QString, labelCurrentVpnProtocolText) + +public: + ClientManagementLogic(UiLogic *uiLogic, QObject *parent = nullptr); + ~ClientManagementLogic() = default; + +public slots: + void onUpdatePage() override; + void onClientItemClicked(int index); + +private: + amnezia::Proto m_currentMainProtocol; +}; + +#endif // CLIENTMANAGMENTLOGIC_H diff --git a/client/ui/qml/Pages/ClientInfo/PageClientInfoBase.qml b/client/ui/qml/Pages/ClientInfo/PageClientInfoBase.qml new file mode 100644 index 00000000..7fde5bab --- /dev/null +++ b/client/ui/qml/Pages/ClientInfo/PageClientInfoBase.qml @@ -0,0 +1,15 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import PageEnum 1.0 +import ProtocolEnum 1.0 +import "../" +import "../../Controls" +import "../../Config" + +PageBase { + id: root + property var protocol: ProtocolEnum.Any + page: PageEnum.ClientInfo + logic: ClientInfoLogic +} diff --git a/client/ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml b/client/ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml new file mode 100644 index 00000000..aab4cc49 --- /dev/null +++ b/client/ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml @@ -0,0 +1,103 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import ProtocolEnum 1.0 +import "../" +import "../../Controls" +import "../../Config" + +PageClientInfoBase { + id: root + protocol: ProtocolEnum.OpenVpn + + BackButton { + id: back + } + + Caption { + id: caption + text: qsTr("Client Info") + } + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + LabelType { + Layout.fillWidth: true + font.pixelSize: 20 + horizontalAlignment: Text.AlignHCenter + text: ClientInfoLogic.labelCurrentVpnProtocolText + } + + LabelType { + height: 21 + text: qsTr("Client name") + } + + TextFieldType { + Layout.fillWidth: true + Layout.preferredHeight: 31 + text: ClientInfoLogic.lineEditNameAliasText + onEditingFinished: { + ClientInfoLogic.lineEditNameAliasText = text + ClientInfoLogic.onLineEditNameAliasEditingFinished() + } + } + + LabelType { + Layout.topMargin: 20 + height: 21 + text: qsTr("Certificate id") + } + + LabelType { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + text: ClientInfoLogic.labelCertId + } + + LabelType { + Layout.topMargin: 20 + height: 21 + text: qsTr("Certificate") + } + + TextAreaType { + Layout.preferredHeight: 200 + Layout.fillWidth: true + + textArea.readOnly: true + textArea.wrapMode: TextEdit.WrapAnywhere + textArea.verticalAlignment: Text.AlignTop + textArea.text: ClientInfoLogic.textAreaCertificate + } + + BlueButtonType { + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Revoke Certificate") + onClicked: { + ClientInfoLogic.onRevokeCertificateClicked() + } + } + } + } +} diff --git a/client/ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml b/client/ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml new file mode 100644 index 00000000..088ca3ec --- /dev/null +++ b/client/ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml @@ -0,0 +1,11 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import ProtocolEnum 1.0 +import "../" +import "../../Controls" +import "../../Config" + +PageClientInfoBase { + +} diff --git a/client/ui/qml/Pages/PageClientManagement.qml b/client/ui/qml/Pages/PageClientManagement.qml new file mode 100644 index 00000000..cb75bb81 --- /dev/null +++ b/client/ui/qml/Pages/PageClientManagement.qml @@ -0,0 +1,121 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Shapes 1.4 +import PageEnum 1.0 +import "./" +import "../Controls" +import "../Config" + +PageBase { + id: root + page: PageEnum.ClientManagement + logic: ClientManagementLogic + + BackButton { + id: back + } + + Caption { + id: caption + text: qsTr("Clients Management") + } + + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: root.bottom + anchors.bottomMargin: 20 + + contentHeight: content.height + clip: true + + Column { + id: content + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + LabelType { + anchors.left: parent.left + font.pixelSize: 20 + horizontalAlignment: Text.AlignHCenter + text: ServerSettingsLogic.labelCurrentVpnProtocolText + } + + ListView { + id: lv_clients + width: parent.width + implicitHeight: contentHeight + 20 + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 10 + anchors.rightMargin: 10 + topMargin: 10 + spacing: 10 + clip: true + model: UiLogic.clientManagementModel + highlightRangeMode: ListView.ApplyRange + highlightMoveVelocity: -1 + delegate: Item { + implicitWidth: lv_clients.width + implicitHeight: 60 + + MouseArea { + id: ms + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + ClientManagementLogic.onClientItemClicked(index) + } + } + + Rectangle { + anchors.fill: parent + gradient: ms.containsMouse ? gradient_containsMouse : gradient_notContainsMouse + LinearGradient { + id: gradient_notContainsMouse + x1: 0 ; y1:0 + x2: 0 ; y2: height + stops: [ + GradientStop { position: 0.0; color: "#FAFBFE" }, + GradientStop { position: 1.0; color: "#ECEEFF" } + ] + } + LinearGradient { + id: gradient_containsMouse + x1: 0 ; y1:0 + x2: 0 ; y2: height + stops: [ + GradientStop { position: 0.0; color: "#FAFBFE" }, + GradientStop { position: 1.0; color: "#DCDEDF" } + ] + } + } + + Text { + x: 10 + y: 10 + font.family: "Lato" + font.styleName: "normal" + color: "#181922" + verticalAlignment: Text.AlignVCenter + wrapMode: Text.Wrap + text: clientName + } + + LabelType { + x: 20 + y: 40 +// width: 141 + height: 16 + text: certId + } + } + } + } + } +} diff --git a/client/ui/qml/Pages/PageServerSettings.qml b/client/ui/qml/Pages/PageServerSettings.qml index 2be04d5a..adc6bf86 100644 --- a/client/ui/qml/Pages/PageServerSettings.qml +++ b/client/ui/qml/Pages/PageServerSettings.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Controls +import QtQuick.Layouts import PageEnum 1.0 import "./" import "../Controls" @@ -15,114 +16,135 @@ PageBase { BackButton { id: back } + Caption { + id: caption text: qsTr("Server settings") anchors.horizontalCenter: parent.horizontalCenter } - LabelType { - anchors.horizontalCenter: parent.horizontalCenter - y: 150 - width: 341 - height: 31 - font.pixelSize: 20 - horizontalAlignment: Text.AlignHCenter - text: ServerSettingsLogic.labelCurrentVpnProtocolText - } -// LabelType { -// anchors.horizontalCenter: parent.horizontalCenter -// y: 120 -// width: 341 -// height: 31 -// font.pixelSize: 20 -// horizontalAlignment: Text.AlignHCenter -// text: ServerSettingsLogic.labelServerText -// } - TextFieldType { - anchors.horizontalCenter: parent.horizontalCenter - y: 120 - width: 341 - height: 31 - font.pixelSize: 20 - horizontalAlignment: Text.AlignHCenter - text: ServerSettingsLogic.labelServerText - readOnly: true - background: Item {} - } - LabelType { - anchors.horizontalCenter: parent.horizontalCenter - y: 530 - width: 301 - height: 41 - text: ServerSettingsLogic.labelWaitInfoText - visible: ServerSettingsLogic.labelWaitInfoVisible - } - TextFieldType { - anchors.horizontalCenter: parent.horizontalCenter - y: 80 - width: 251 - height: 31 - text: ServerSettingsLogic.lineEditDescriptionText - onEditingFinished: { - ServerSettingsLogic.lineEditDescriptionText = text - ServerSettingsLogic.onLineEditDescriptionEditingFinished() - } - } - BlueButtonType { - anchors.horizontalCenter: parent.horizontalCenter - y: 410 - width: parent.width - 40 - height: 40 - text: ServerSettingsLogic.pushButtonClearText - visible: ServerSettingsLogic.pushButtonClearVisible - onClicked: { - ServerSettingsLogic.onPushButtonClearServer() - } - } - BlueButtonType { - anchors.horizontalCenter: parent.horizontalCenter - y: 350 - width: parent.width - 40 - height: 40 - text: ServerSettingsLogic.pushButtonClearClientCacheText - visible: ServerSettingsLogic.pushButtonClearClientCacheVisible - onClicked: { - ServerSettingsLogic.onPushButtonClearClientCacheClicked() - } - } - BlueButtonType { - anchors.horizontalCenter: parent.horizontalCenter - y: 470 - width: parent.width - 40 - height: 40 - text: qsTr("Forget this server") - onClicked: { - ServerSettingsLogic.onPushButtonForgetServer() - } - } - BlueButtonType { - anchors.horizontalCenter: parent.horizontalCenter - y: 210 - width: parent.width - 40 - height: 40 - text: qsTr("Protocols and Services") - onClicked: { - UiLogic.goToPage(PageEnum.ServerContainers) - } - } - BlueButtonType { - anchors.horizontalCenter: parent.horizontalCenter - y: 260 - width: parent.width - 40 - height: 40 - text: qsTr("Share Server (FULL ACCESS)") - visible: ServerSettingsLogic.pushButtonShareFullVisible - onClicked: { - ServerSettingsLogic.onPushButtonShareFullClicked() + Flickable { + id: fl + width: root.width + anchors.top: caption.bottom + anchors.topMargin: 20 + anchors.bottom: logo.top + anchors.bottomMargin: 20 + anchors.left: root.left + anchors.leftMargin: 30 + anchors.right: root.right + anchors.rightMargin: 30 + + contentHeight: content.height + clip: true + + ColumnLayout { + id: content + enabled: logic.pageEnabled + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + + TextFieldType { + Layout.alignment: Qt.AlignHCenter + Layout.preferredWidth: 251 + Layout.preferredHeight: 31 + text: ServerSettingsLogic.lineEditDescriptionText + onEditingFinished: { + ServerSettingsLogic.lineEditDescriptionText = text + ServerSettingsLogic.onLineEditDescriptionEditingFinished() + } + } + + TextFieldType { + Layout.fillWidth: true + font.pixelSize: 20 + horizontalAlignment: Text.AlignHCenter + text: ServerSettingsLogic.labelServerText + readOnly: true + background: Item {} + } + + LabelType { + Layout.fillWidth: true + font.pixelSize: 20 + horizontalAlignment: Text.AlignHCenter + text: ServerSettingsLogic.labelCurrentVpnProtocolText + } + + BlueButtonType { + Layout.topMargin: 15 + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Protocols and Services") + onClicked: { + UiLogic.goToPage(PageEnum.ServerContainers) + } + } + + BlueButtonType { + Layout.topMargin: 10 + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Share Server (FULL ACCESS)") + visible: ServerSettingsLogic.pushButtonShareFullVisible + onClicked: { + ServerSettingsLogic.onPushButtonShareFullClicked() + } + } + + BlueButtonType { + Layout.topMargin: 10 + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Clients Management") + onClicked: { + UiLogic.goToPage(PageEnum.ClientManagement) + } + } + + BlueButtonType { + Layout.topMargin: 30 + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: ServerSettingsLogic.pushButtonClearClientCacheText + visible: ServerSettingsLogic.pushButtonClearClientCacheVisible + onClicked: { + ServerSettingsLogic.onPushButtonClearClientCacheClicked() + } + } + + BlueButtonType { + Layout.topMargin: 10 + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: ServerSettingsLogic.pushButtonClearText + visible: ServerSettingsLogic.pushButtonClearVisible + onClicked: { + ServerSettingsLogic.onPushButtonClearServer() + } + } + + BlueButtonType { + Layout.topMargin: 10 + Layout.fillWidth: true + Layout.preferredHeight: 41 + text: qsTr("Forget this server") + onClicked: { + ServerSettingsLogic.onPushButtonForgetServer() + } + } + + LabelType { + Layout.fillWidth: true + text: ServerSettingsLogic.labelWaitInfoText + visible: ServerSettingsLogic.labelWaitInfoVisible + } } } Logo { + id: logo anchors.bottom: parent.bottom } } diff --git a/client/ui/qml/main.qml b/client/ui/qml/main.qml index 1e190d02..ddc8d78d 100644 --- a/client/ui/qml/main.qml +++ b/client/ui/qml/main.qml @@ -13,12 +13,14 @@ import "Controls" import "Pages" import "Pages/Protocols" import "Pages/Share" +import "Pages/ClientInfo" import "Config" Window { property var pages: ({}) property var protocolPages: ({}) property var sharePages: ({}) + property var clientInfoPages: ({}) id: root visible: true @@ -39,6 +41,7 @@ Window { if (type === PageType.Basic) p_obj = pages[page] else if (type === PageType.Proto) p_obj = protocolPages[page] else if (type === PageType.ShareProto) p_obj = sharePages[page] + else if (type === PageType.ClientInfo) p_obj = clientInfoPages[page] else return //console.debug("QML gotoPage " + type + " " + page + " " + p_obj) @@ -175,6 +178,19 @@ Window { } } + FolderListModel { + id: folderModelClientInfo + folder: "qrc:/ui/qml/Pages/ClientInfo/" + nameFilters: ["*.qml"] + showDirs: false + + onStatusChanged: if (status == FolderListModel.Ready) { + for (var i=0; i settings, std::shared_ptrmoveToThread(&m_vpnConnectionThread); m_vpnConnectionThread.start(); @@ -676,4 +679,6 @@ void UiLogic::registerPagesLogic() registerPageLogic(); registerPageLogic(); registerPageLogic(); + registerPageLogic(); + registerPageLogic(); } diff --git a/client/ui/uilogic.h b/client/ui/uilogic.h index 82f2d6ea..b049fbde 100644 --- a/client/ui/uilogic.h +++ b/client/ui/uilogic.h @@ -18,6 +18,7 @@ #include "models/containers_model.h" #include "models/protocols_model.h" +#include "models/clientManagementModel.h" #include "notificationhandler.h" @@ -42,6 +43,8 @@ class StartPageLogic; class ViewConfigLogic; class VpnLogic; class WizardLogic; +class ClientManagementLogic; +class ClientInfoLogic; class PageProtocolLogicBase; class OpenVpnLogic; @@ -64,6 +67,7 @@ class UiLogic : public QObject READONLY_PROPERTY(QObject *, containersModel) READONLY_PROPERTY(QObject *, protocolsModel) + READONLY_PROPERTY(QObject *, clientManagementModel) public: explicit UiLogic(std::shared_ptr settings, std::shared_ptr configurator, @@ -87,6 +91,8 @@ public: friend class ViewConfigLogic; friend class VpnLogic; friend class WizardLogic; + friend class ClientManagementLogic; + friend class ClientInfoLogic; friend class PageProtocolLogicBase; friend class OpenVpnLogic; @@ -120,6 +126,7 @@ signals: void goToPage(PageEnumNS::Page page, bool reset = true, bool slide = true); void goToProtocolPage(Proto protocol, bool reset = true, bool slide = true); void goToShareProtocolPage(Proto protocol, bool reset = true, bool slide = true); + void goToClientInfoPage(Proto protocol, bool reset = true, bool slide = true); void closePage(); void setStartPage(PageEnumNS::Page page, bool slide = true); diff --git a/docs/openvpnRevokeClientCertificate.plantuml b/docs/openvpnRevokeClientCertificate.plantuml new file mode 100644 index 00000000..f453ae71 --- /dev/null +++ b/docs/openvpnRevokeClientCertificate.plantuml @@ -0,0 +1,38 @@ +@startuml openvpnRevokeClientCertificate +actor Admin as adm +participant "Amnezia Client" as cli +participant "Amnezia Container" as cont +participant "OpenVpn Service" as ovpn + +adm -> cli: revoke the selected client certificate +cli -> cli: start progress bar +cli -> cont: execute script "revoke openvpn client" + +cont -> cont: easyrsa revoke clientName +note right + clientName is the clientId field + of the ConnectionData structure +end note + +cont -> cont: easyrsa gen-crl +cont -> cont: cp crl.pem +cont -> ovpn: restart openvpn service +note right + In the OpenVpn config + there should be a line "crl-verify crl.pem". + After that, the service will ignore + the certificates contained in the crl.pem file +end note + + +group#lightgreen #lightgreen if [successful case] + ovpn --> cont: restart result + cont --> cli: display that the selected certificate has been revoked +else #pink some kind of failure + cont --> cli: display an error depending on when it occurred +end + +cli -> cli: stop progress bar +cli --> adm: return control to the user + +@enduml \ No newline at end of file