added config export in native format openvpn and wireguard

This commit is contained in:
vladimir.kuznetsov 2023-07-05 10:15:38 +09:00
parent 43261f8469
commit a97417fd38
5 changed files with 137 additions and 39 deletions

View file

@ -9,6 +9,8 @@
#include <QImage> #include <QImage>
#include <QStandardPaths> #include <QStandardPaths>
#include "configurators/openvpn_configurator.h"
#include "configurators/wireguard_configurator.h"
#include "qrcodegen.hpp" #include "qrcodegen.hpp"
#include "core/errorstrings.h" #include "core/errorstrings.h"
@ -27,14 +29,17 @@ ExportController::ExportController(const QSharedPointer<ServersModel> &serversMo
void ExportController::generateFullAccessConfig() void ExportController::generateFullAccessConfig()
{ {
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
QJsonObject config = m_settings->server(serverIndex); QJsonObject config = m_settings->server(serverIndex);
QByteArray compressedConfig = QJsonDocument(config).toJson(); QByteArray compressedConfig = QJsonDocument(config).toJson();
compressedConfig = qCompress(compressedConfig, 8); compressedConfig = qCompress(compressedConfig, 8);
m_amneziaCode = QString("vpn://%1") m_rawConfig = QString("vpn://%1")
.arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding .arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding
| QByteArray::OmitTrailingEquals))); | QByteArray::OmitTrailingEquals)));
m_formattedConfig = m_rawConfig;
m_qrCodes = generateQrCodeImageSeries(compressedConfig); m_qrCodes = generateQrCodeImageSeries(compressedConfig);
emit exportConfigChanged(); emit exportConfigChanged();
@ -42,6 +47,8 @@ void ExportController::generateFullAccessConfig()
void ExportController::generateConnectionConfig() void ExportController::generateConnectionConfig()
{ {
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex(); int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials = ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole)); qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
@ -81,17 +88,86 @@ void ExportController::generateConnectionConfig()
QByteArray compressedConfig = QJsonDocument(config).toJson(); QByteArray compressedConfig = QJsonDocument(config).toJson();
compressedConfig = qCompress(compressedConfig, 8); compressedConfig = qCompress(compressedConfig, 8);
m_amneziaCode = QString("vpn://%1") m_rawConfig = QString("vpn://%1")
.arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding .arg(QString(compressedConfig.toBase64(QByteArray::Base64UrlEncoding
| QByteArray::OmitTrailingEquals))); | QByteArray::OmitTrailingEquals)));
m_formattedConfig = m_rawConfig;
m_qrCodes = generateQrCodeImageSeries(compressedConfig); m_qrCodes = generateQrCodeImageSeries(compressedConfig);
emit exportConfigChanged(); emit exportConfigChanged();
} }
QString ExportController::getAmneziaCode() void ExportController::generateOpenVpnConfig()
{ {
return m_amneziaCode; clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config =
m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, config);
m_rawConfig = config;
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_formattedConfig.append(line + "\n");
}
emit exportConfigChanged();
}
void ExportController::generateWireGuardConfig()
{
clearPreviousConfig();
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
ServerCredentials credentials =
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
QModelIndex containerModelIndex = m_containersModel->index(container);
QJsonObject containerConfig =
qvariant_cast<QJsonObject>(m_containersModel->data(containerModelIndex, ContainersModel::Roles::ConfigRole));
containerConfig.insert(config_key::container, ContainerProps::containerToString(container));
ErrorCode errorCode = ErrorCode::NoError;
QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig,
&errorCode);
if (errorCode) {
emit exportErrorOccurred(errorString(errorCode));
return;
}
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, config);
m_rawConfig = config;
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
for (const QString &line : lines) {
m_formattedConfig.append(line + "\n");
}
emit exportConfigChanged();
}
QString ExportController::getFormattedConfig()
{
return m_formattedConfig;
} }
QList<QString> ExportController::getQrCodes() QList<QString> ExportController::getQrCodes()
@ -117,7 +193,7 @@ void ExportController::saveFile()
QFile save(fileName.toLocalFile()); QFile save(fileName.toLocalFile());
save.open(QIODevice::WriteOnly); save.open(QIODevice::WriteOnly);
save.write(m_amneziaCode.toUtf8()); save.write(m_rawConfig.toUtf8());
save.close(); save.close();
QFileInfo fi(fileName.toLocalFile()); QFileInfo fi(fileName.toLocalFile());
@ -154,3 +230,10 @@ int ExportController::getQrCodesCount()
{ {
return m_qrCodes.size(); return m_qrCodes.size();
} }
void ExportController::clearPreviousConfig()
{
m_rawConfig.clear();
m_formattedConfig.clear();
m_qrCodes.clear();
}

View file

@ -14,24 +14,25 @@ public:
explicit ExportController(const QSharedPointer<ServersModel> &serversModel, explicit ExportController(const QSharedPointer<ServersModel> &serversModel,
const QSharedPointer<ContainersModel> &containersModel, const QSharedPointer<ContainersModel> &containersModel,
const std::shared_ptr<Settings> &settings, const std::shared_ptr<Settings> &settings,
const std::shared_ptr<VpnConfigurator> &configurator, const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent = nullptr);
QObject *parent = nullptr);
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged) Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged)
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged) Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged)
Q_PROPERTY(QString amneziaCode READ getAmneziaCode NOTIFY exportConfigChanged) Q_PROPERTY(QString formattedConfig READ getFormattedConfig NOTIFY exportConfigChanged)
public slots: public slots:
void generateFullAccessConfig(); void generateFullAccessConfig();
void generateConnectionConfig(); void generateConnectionConfig();
void generateOpenVpnConfig();
void generateWireGuardConfig();
QString getAmneziaCode(); QString getFormattedConfig();
QList<QString> getQrCodes(); QList<QString> getQrCodes();
void saveFile(); void saveFile();
signals: signals:
void generateConfig(bool isFullAccess); void generateConfig(int type);
void exportErrorOccurred(QString errorMessage); void exportErrorOccurred(QString errorMessage);
void exportConfigChanged(); void exportConfigChanged();
@ -42,12 +43,15 @@ private:
int getQrCodesCount(); int getQrCodesCount();
void clearPreviousConfig();
QSharedPointer<ServersModel> m_serversModel; QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ContainersModel> m_containersModel; QSharedPointer<ContainersModel> m_containersModel;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
std::shared_ptr<VpnConfigurator> m_configurator; std::shared_ptr<VpnConfigurator> m_configurator;
QString m_amneziaCode; QString m_rawConfig;
QString m_formattedConfig;
QList<QString> m_qrCodes; QList<QString> m_qrCodes;
}; };

View file

@ -55,7 +55,7 @@ Button {
fillColor: "transparent" fillColor: "transparent"
strokeColor: { strokeColor: {
if (ConnectionController.isConnectionInProgress) { if (ConnectionController.isConnectionInProgress) {
return Qt.rgba(251/255, 178/255, 106/255, 1) return "#261E1A"
} else if (ConnectionController.isConnected) { } else if (ConnectionController.isConnected) {
return connectedButtonColor return connectedButtonColor
} else { } else {

View file

@ -137,7 +137,7 @@ DrawerType {
Layout.topMargin: 16 Layout.topMargin: 16
} }
TextField { TextArea {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
@ -147,16 +147,17 @@ DrawerType {
height: 24 height: 24
color: "#D7D8DB" color: "#D7D8DB"
selectionColor: "#412102"
selectedTextColor: "#D7D8DB"
font.pixelSize: 16 font.pixelSize: 16
font.weight: Font.Medium font.weight: Font.Medium
font.family: "PT Root UI VF" font.family: "PT Root UI VF"
text: ExportController.amneziaCode text: ExportController.formattedConfig
wrapMode: Text.Wrap wrapMode: Text.Wrap
readOnly: true
background: Rectangle { background: Rectangle {
color: "transparent" color: "transparent"
} }
@ -186,11 +187,13 @@ DrawerType {
running: ExportController.qrCodesCount > 0 running: ExportController.qrCodesCount > 0
repeat: true repeat: true
onTriggered: { onTriggered: {
index++ if (ExportController.qrCodesCount > 0) {
if (index >= ExportController.qrCodesCount) { index++
index = 0 if (index >= ExportController.qrCodesCount) {
index = 0
}
parent.source = ExportController.qrCodes[index]
} }
parent.source = ExportController.qrCodes[index]
} }
} }
@ -205,6 +208,8 @@ DrawerType {
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 32 Layout.bottomMargin: 32
visible: ExportController.qrCodesCount > 0
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: qsTr("To read the QR code in the Amnezia app, select \"Add Server\" → \"I have connection details\"") text: qsTr("To read the QR code in the Amnezia app, select \"Add Server\" → \"I have connection details\"")
} }

View file

@ -16,18 +16,30 @@ import "../Components"
PageType { PageType {
id: root id: root
enum ConfigType {
AmneziaConnection,
AmenziaFullAccess,
OpenVpn,
WireGuard
}
Connections { Connections {
target: ExportController target: ExportController
function onGenerateConfig(isFullAccess) { function onGenerateConfig(type) {
shareConnectionDrawer.open() shareConnectionDrawer.open()
shareConnectionDrawer.contentVisible = false shareConnectionDrawer.contentVisible = false
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
if (isFullAccess) {
ExportController.generateFullAccessConfig() console.log(type)
} else {
ExportController.generateConnectionConfig() switch (type) {
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(); break;
case PageShare.ConfigType.AmenziaFullAccess: ExportController.generateFullAccessConfig(); break;
case PageShare.ConfigType.OpenVpn: ExportController.generateOpenVpnConfig(); break;
case PageShare.ConfigType.WireGuard: ExportController.generateWireGuardConfig(); break;
} }
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
shareConnectionDrawer.contentVisible = true shareConnectionDrawer.contentVisible = true
} }
@ -46,23 +58,17 @@ PageType {
QtObject { QtObject {
id: amneziaConnectionFormat id: amneziaConnectionFormat
property string name: qsTr("For the AmnesiaVPN app") property string name: qsTr("For the AmnesiaVPN app")
property var func: function() { property var type: PageShare.ConfigType.AmneziaConnection
ExportController.generateConfig(false)
}
} }
QtObject { QtObject {
id: openVpnConnectionFormat id: openVpnConnectionFormat
property string name: qsTr("OpenVpn native format") property string name: qsTr("OpenVpn native format")
property var func: function() { property var type: PageShare.ConfigType.OpenVpn
console.log("Item 3 clicked")
}
} }
QtObject { QtObject {
id: wireGuardConnectionFormat id: wireGuardConnectionFormat
property string name: qsTr("WireGuard native format") property string name: qsTr("WireGuard native format")
property var func: function() { property var type: PageShare.ConfigType.WireGuard
console.log("Item 3 clicked")
}
} }
FlickableType { FlickableType {
@ -334,9 +340,9 @@ PageType {
onClicked: { onClicked: {
if (accessTypeSelector.currentIndex === 0) { if (accessTypeSelector.currentIndex === 0) {
root.connectionTypesModel[accessTypeSelector.currentIndex].func() ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
} else { } else {
ExportController.generateConfig(true) ExportController.generateConfig(PageShare.ConfigType.AmneziaFullAccess)
} }
} }
} }