added client management panel

- added classes for displaying the client management panel
- added class for displaying the client info
- added page to display a list of clients
- added page to display OpenVpn client information
- added diagram with OpenVpn certificate revocation process
This commit is contained in:
vladimir.kuznetsov 2023-01-09 12:38:01 +03:00
parent 3f257af7a9
commit a42beb86c0
19 changed files with 771 additions and 102 deletions

View file

@ -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<QSsh::SshRemoteProcess> 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));

View file

@ -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);

View file

@ -160,5 +160,9 @@
<file>ui/qml/Pages/PageQrDecoderIos.qml</file>
<file>server_scripts/website_tor/Dockerfile</file>
<file>ui/qml/Pages/PageViewConfig.qml</file>
<file>ui/qml/Pages/PageClientManagement.qml</file>
<file>ui/qml/Pages/ClientInfo/PageClientInfoBase.qml</file>
<file>ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml</file>
<file>ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml</file>
</qresource>
</RCC>

View file

@ -0,0 +1,75 @@
#include "clientManagementModel.h"
ClientManagementModel::ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent) :
m_settings(settings),
QAbstractListModel(parent)
{
}
void ClientManagementModel::clearData()
{
beginResetModel();
m_content.clear();
endResetModel();
}
void ClientManagementModel::setContent(const QVector<ClientInfo> &data)
{
beginResetModel();
m_content = data;
endResetModel();
}
int ClientManagementModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return static_cast<int>(m_content.size());
}
QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0
|| index.row() >= static_cast<int>(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<int>(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<int, QByteArray> ClientManagementModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[NameRole] = "clientName";
roles[CertIdRole] = "certId";
roles[CertDataRole] = "certData";
return roles;
}

View file

@ -0,0 +1,42 @@
#ifndef CLIENTMANAGEMENTMODEL_H
#define CLIENTMANAGEMENTMODEL_H
#include <QAbstractListModel>
#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> settings, QObject *parent = nullptr);
void clearData();
void setContent(const QVector<ClientInfo> &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<int, QByteArray> roleNames() const override;
private:
std::shared_ptr<Settings> m_settings; //TODO remove this?
QVector<ClientInfo> m_content;
};
#endif // CLIENTMANAGEMENTMODEL_H

View file

@ -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() {

View file

@ -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<ClientManagementModel*>(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<ClientManagementModel*>(uiLogic()->clientManagementModel());
auto modelIndex = model->index(m_currentClientIndex);
model->setData(modelIndex, m_lineEditNameAliasText, ClientManagementModel::ClientRoles::NameRole);
m_serverController->setClientsList();
}
void ClientInfoLogic::onRevokeCertificateClicked()
{
}

View file

@ -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

View file

@ -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<ClientManagementModel::ClientInfo> 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<ClientManagementModel*>(uiLogic()->clientManagementModel())->setContent(clientsArray);
}
void ClientManagementLogic::onClientItemClicked(int index)
{
uiLogic()->pageLogic<ClientInfoLogic>()->setCurrentClientId(index);
emit uiLogic()->goToClientInfoPage(m_currentMainProtocol);
}

View file

@ -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

View file

@ -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
}

View file

@ -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()
}
}
}
}
}

View file

@ -0,0 +1,11 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ProtocolEnum 1.0
import "../"
import "../../Controls"
import "../../Config"
PageClientInfoBase {
}

View file

@ -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
}
}
}
}
}
}

View file

@ -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
}
}

View file

@ -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<folderModelClientInfo.count; i++) {
createPagesObjects(folderModelClientInfo.get(i, "filePath"), PageType.ClientInfo);
}
}
}
function createPagesObjects(file, type) {
if (file.indexOf("Base") !== -1) return; // skip Base Pages
//console.debug("Creating compenent " + file + " for " + type);
@ -198,6 +214,9 @@ Window {
else if (type === PageType.ShareProto) {
sharePages[obj.protocol] = obj
}
else if (type === PageType.ClientInfo) {
clientInfoPages[obj.protocol] = obj
}
// console.debug("Created compenent " + component.url + " for " + type);
}
@ -227,7 +246,10 @@ Window {
//console.debug("Qml Connections onGoToShareProtocolPage " + protocol);
root.gotoPage(PageType.ShareProto, protocol, reset, slide)
}
function onGoToClientInfoPage(protocol, reset, slide) {
//console.debug("Qml Connections onGoToClientInfoPage " + protocol);
root.gotoPage(PageType.ClientInfo, protocol, reset, slide)
}
function onClosePage() {
root.close_page()

View file

@ -67,6 +67,8 @@
#include "pages_logic/ViewConfigLogic.h"
#include "pages_logic/VpnLogic.h"
#include "pages_logic/WizardLogic.h"
#include "pages_logic/ClientManagementLogic.h"
#include "pages_logic/ClientInfoLogic.h"
#include "pages_logic/protocols/CloakLogic.h"
#include "pages_logic/protocols/OpenVpnLogic.h"
@ -87,6 +89,7 @@ UiLogic::UiLogic(std::shared_ptr<Settings> settings, std::shared_ptr<VpnConfigur
{
m_containersModel = new ContainersModel(settings, this);
m_protocolsModel = new ProtocolsModel(settings, this);
m_clientManagementModel = new ClientManagementModel(settings, this);
m_vpnConnection = new VpnConnection(settings, configurator, serverController);
m_vpnConnection->moveToThread(&m_vpnConnectionThread);
m_vpnConnectionThread.start();
@ -676,4 +679,6 @@ void UiLogic::registerPagesLogic()
registerPageLogic<ViewConfigLogic>();
registerPageLogic<VpnLogic>();
registerPageLogic<WizardLogic>();
registerPageLogic<ClientManagementLogic>();
registerPageLogic<ClientInfoLogic>();
}

View file

@ -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> settings, std::shared_ptr<VpnConfigurator> 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);

View file

@ -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