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:
parent
3f257af7a9
commit
a42beb86c0
19 changed files with 771 additions and 102 deletions
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
75
client/ui/models/clientManagementModel.cpp
Normal file
75
client/ui/models/clientManagementModel.cpp
Normal 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;
|
||||
}
|
42
client/ui/models/clientManagementModel.h
Normal file
42
client/ui/models/clientManagementModel.h
Normal 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
|
|
@ -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() {
|
||||
|
|
43
client/ui/pages_logic/ClientInfoLogic.cpp
Normal file
43
client/ui/pages_logic/ClientInfoLogic.cpp
Normal 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()
|
||||
{
|
||||
|
||||
}
|
32
client/ui/pages_logic/ClientInfoLogic.h
Normal file
32
client/ui/pages_logic/ClientInfoLogic.h
Normal 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
|
44
client/ui/pages_logic/ClientManagementLogic.cpp
Normal file
44
client/ui/pages_logic/ClientManagementLogic.cpp
Normal 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);
|
||||
}
|
28
client/ui/pages_logic/ClientManagementLogic.h
Normal file
28
client/ui/pages_logic/ClientManagementLogic.h
Normal 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
|
15
client/ui/qml/Pages/ClientInfo/PageClientInfoBase.qml
Normal file
15
client/ui/qml/Pages/ClientInfo/PageClientInfoBase.qml
Normal 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
|
||||
}
|
103
client/ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml
Normal file
103
client/ui/qml/Pages/ClientInfo/PageClientInfoOpenVPN.qml
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
client/ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml
Normal file
11
client/ui/qml/Pages/ClientInfo/PageClientInfoWireGuard.qml
Normal file
|
@ -0,0 +1,11 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import ProtocolEnum 1.0
|
||||
import "../"
|
||||
import "../../Controls"
|
||||
import "../../Config"
|
||||
|
||||
PageClientInfoBase {
|
||||
|
||||
}
|
121
client/ui/qml/Pages/PageClientManagement.qml
Normal file
121
client/ui/qml/Pages/PageClientManagement.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
38
docs/openvpnRevokeClientCertificate.plantuml
Normal file
38
docs/openvpnRevokeClientCertificate.plantuml
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue