Merge branch 'dev' of github.com:amnezia-vpn/amnezia-client into HEAD
This commit is contained in:
commit
0f4bb78712
36 changed files with 1260 additions and 239 deletions
27
.github/workflows/deploy.yml
vendored
27
.github/workflows/deploy.yml
vendored
|
@ -1,7 +1,12 @@
|
|||
name: 'Deploy workflow'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
on: [push]
|
||||
env:
|
||||
QT_MIRROR: https://mirrors.ocf.berkeley.edu/qt/ # https://download.qt.io/static/mirrorlist/
|
||||
|
||||
jobs:
|
||||
Build-Linux-Ubuntu:
|
||||
|
@ -25,7 +30,7 @@ jobs:
|
|||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v3
|
||||
|
@ -89,7 +94,7 @@ jobs:
|
|||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Setup mvsc'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
|
@ -119,15 +124,14 @@ jobs:
|
|||
|
||||
# ------------------------------------------------------
|
||||
|
||||
Build-IOS:
|
||||
name: 'Build-IOS'
|
||||
Build-iOS:
|
||||
name: 'Build-iOS'
|
||||
runs-on: macos-12
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.5.2
|
||||
|
||||
steps:
|
||||
# Just select XCode
|
||||
- name: 'Setup xcode'
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
|
@ -143,6 +147,7 @@ jobs:
|
|||
arch: 'clang_64'
|
||||
dir: ${{ runner.temp }}
|
||||
set-env: 'true'
|
||||
extra: '--base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install iOS Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
|
@ -154,7 +159,7 @@ jobs:
|
|||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install go'
|
||||
uses: actions/setup-go@v3
|
||||
|
@ -174,7 +179,7 @@ jobs:
|
|||
- name: 'Setup ccache'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: Install dependencies
|
||||
- name: 'Install dependencies'
|
||||
run: pip install jsonschema jinja2
|
||||
|
||||
- name: 'Build project'
|
||||
|
@ -232,7 +237,7 @@ jobs:
|
|||
setup-python: 'true'
|
||||
tools: 'tools_ifw'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v3
|
||||
|
@ -296,7 +301,7 @@ jobs:
|
|||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install android Qt'
|
||||
uses: jurplel/install-qt-action@v3
|
||||
|
@ -309,7 +314,7 @@ jobs:
|
|||
dir: ${{ runner.temp }}
|
||||
setup-python: 'true'
|
||||
set-env: 'true'
|
||||
extra: '--external 7z'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Grant execute permission for qt-cmake'
|
||||
shell: bash
|
||||
|
|
64
.github/workflows/tag-upload.yml
vendored
Normal file
64
.github/workflows/tag-upload.yml
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
name: 'Upload a new version'
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
name: upload
|
||||
steps:
|
||||
- name: Checkout CMakeLists.txt
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref_name }}
|
||||
sparse-checkout: |
|
||||
CMakeLists.txt
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Verify git tag
|
||||
run: |
|
||||
GIT_TAG=${{ github.ref_name }}
|
||||
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
|
||||
|
||||
if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
|
||||
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
|
||||
else
|
||||
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download artifacts from the "${{ github.ref_name }}" tag
|
||||
uses: robinraju/release-downloader@v1.8
|
||||
with:
|
||||
tag: ${{ github.ref_name }}
|
||||
fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
|
||||
out-file-path: ${{ github.ref_name }}
|
||||
|
||||
- name: Upload beta version
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: contains(github.event.base_ref, 'dev')
|
||||
with:
|
||||
args: --include "AmneziaVPN*" --delete
|
||||
env:
|
||||
AWS_S3_BUCKET: updates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
|
||||
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
|
||||
SOURCE_DIR: ${{ github.ref_name }}
|
||||
DEST_DIR: beta/${{ github.ref_name }}
|
||||
|
||||
- name: Upload stable version
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: contains(github.event.base_ref, 'master')
|
||||
with:
|
||||
args: --include "AmneziaVPN*" --delete
|
||||
env:
|
||||
AWS_S3_BUCKET: updates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
|
||||
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
|
||||
SOURCE_DIR: ${{ github.ref_name }}
|
||||
DEST_DIR: stable/${{ github.ref_name }}
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
|||
|
||||
set(PROJECT AmneziaVPN)
|
||||
|
||||
project(${PROJECT} VERSION 4.1.0.0
|
||||
project(${PROJECT} VERSION 4.1.0.1
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
HOMEPAGE_URL "https://amnezia.org/"
|
||||
)
|
||||
|
|
|
@ -279,7 +279,7 @@ void AmneziaApplication::initModels()
|
|||
{
|
||||
m_containersModel.reset(new ContainersModel(m_settings, this));
|
||||
m_engine->rootContext()->setContextProperty("ContainersModel", m_containersModel.get());
|
||||
connect(m_vpnConnection.get(), &VpnConnection::newVpnConfigurationCreated, m_containersModel.get(),
|
||||
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, m_containersModel.get(),
|
||||
&ContainersModel::updateContainersConfig);
|
||||
|
||||
m_serversModel.reset(new ServersModel(m_settings, this));
|
||||
|
@ -324,6 +324,11 @@ void AmneziaApplication::initModels()
|
|||
|
||||
m_sftpConfigModel.reset(new SftpConfigModel(this));
|
||||
m_engine->rootContext()->setContextProperty("SftpConfigModel", m_sftpConfigModel.get());
|
||||
|
||||
m_clientManagementModel.reset(new ClientManagementModel(m_settings, this));
|
||||
m_engine->rootContext()->setContextProperty("ClientManagementModel", m_clientManagementModel.get());
|
||||
connect(m_configurator.get(), &VpnConfigurator::newVpnConfigCreated, m_clientManagementModel.get(),
|
||||
&ClientManagementModel::appendClient);
|
||||
}
|
||||
|
||||
void AmneziaApplication::initControllers()
|
||||
|
@ -349,12 +354,12 @@ void AmneziaApplication::initControllers()
|
|||
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
||||
|
||||
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_settings, m_configurator));
|
||||
m_exportController.reset(new ExportController(m_serversModel, m_containersModel, m_clientManagementModel, m_settings, m_configurator));
|
||||
m_engine->rootContext()->setContextProperty("ExportController", m_exportController.get());
|
||||
|
||||
m_settingsController.reset(new SettingsController(m_serversModel, m_containersModel, m_languageModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("SettingsController", m_settingsController.get());
|
||||
if (m_settingsController->isAutoStartEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
|
||||
if (m_settingsController->isAutoConnectEnabled() && m_serversModel->getDefaultServerIndex() >= 0) {
|
||||
QTimer::singleShot(1000, this, [this]() { m_connectionController->openConnection(); });
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "ui/models/servers_model.h"
|
||||
#include "ui/models/services/sftpConfigModel.h"
|
||||
#include "ui/models/sites_model.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
|
||||
#define amnApp (static_cast<AmneziaApplication *>(QCoreApplication::instance()))
|
||||
|
||||
|
@ -95,6 +96,7 @@ private:
|
|||
QSharedPointer<LanguageModel> m_languageModel;
|
||||
QSharedPointer<ProtocolsModel> m_protocolsModel;
|
||||
QSharedPointer<SitesModel> m_sitesModel;
|
||||
QSharedPointer<ClientManagementModel> m_clientManagementModel;
|
||||
|
||||
QScopedPointer<OpenVpnConfigModel> m_openVpnConfigModel;
|
||||
QScopedPointer<ShadowSocksConfigModel> m_shadowSocksConfigModel;
|
||||
|
|
|
@ -10,11 +10,10 @@ AwgConfigurator::AwgConfigurator(std::shared_ptr<Settings> settings, QObject *pa
|
|||
{
|
||||
}
|
||||
|
||||
QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials,
|
||||
DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
QString AwgConfigurator::genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
|
||||
{
|
||||
QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||
QString config = WireguardConfigurator::genWireguardConfig(credentials, container, containerConfig, clientId, errorCode);
|
||||
|
||||
QJsonObject jsonConfig = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||
QString awgConfig = jsonConfig.value(config_key::config).toString();
|
||||
|
|
|
@ -12,7 +12,7 @@ public:
|
|||
AwgConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
|
||||
QString genAwgConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
|
||||
};
|
||||
|
||||
#endif // AWGCONFIGURATOR_H
|
||||
|
|
|
@ -83,7 +83,7 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
}
|
||||
|
||||
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
|
||||
{
|
||||
ServerController serverController(m_settings);
|
||||
QString config =
|
||||
|
@ -113,6 +113,8 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
|
|||
QJsonObject jConfig;
|
||||
jConfig[config_key::config] = config;
|
||||
|
||||
clientId = connData.clientId;
|
||||
|
||||
return QJsonDocument(jConfig).toJson();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
};
|
||||
|
||||
QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
|
||||
|
||||
QString processConfigWithLocalSettings(QString jsonConfig);
|
||||
QString processConfigWithExportSettings(QString jsonConfig);
|
||||
|
|
|
@ -28,11 +28,11 @@ VpnConfigurator::VpnConfigurator(std::shared_ptr<Settings> settings, QObject *pa
|
|||
}
|
||||
|
||||
QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode)
|
||||
const QJsonObject &containerConfig, Proto proto, QString &clientId, ErrorCode *errorCode)
|
||||
{
|
||||
switch (proto) {
|
||||
case Proto::OpenVpn:
|
||||
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, errorCode);
|
||||
return openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, clientId, errorCode);
|
||||
|
||||
case Proto::ShadowSocks:
|
||||
return shadowSocksConfigurator->genShadowSocksConfig(credentials, container, containerConfig, errorCode);
|
||||
|
@ -40,10 +40,10 @@ QString VpnConfigurator::genVpnProtocolConfig(const ServerCredentials &credentia
|
|||
case Proto::Cloak: return cloakConfigurator->genCloakConfig(credentials, container, containerConfig, errorCode);
|
||||
|
||||
case Proto::WireGuard:
|
||||
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, errorCode);
|
||||
return wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig, clientId, errorCode);
|
||||
|
||||
case Proto::Awg:
|
||||
return awgConfigurator->genAwgConfig(credentials, container, containerConfig, errorCode);
|
||||
return awgConfigurator->genAwgConfig(credentials, container, containerConfig, clientId, errorCode);
|
||||
|
||||
case Proto::Ikev2: return ikev2Configurator->genIkev2Config(credentials, container, containerConfig, errorCode);
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "configurator_base.h"
|
||||
#include "core/defs.h"
|
||||
|
||||
|
||||
class OpenVpnConfigurator;
|
||||
class ShadowSocksConfigurator;
|
||||
class CloakConfigurator;
|
||||
|
@ -16,14 +15,15 @@ class SshConfigurator;
|
|||
class AwgConfigurator;
|
||||
|
||||
// Retrieve connection settings from server
|
||||
class VpnConfigurator : ConfiguratorBase
|
||||
class VpnConfigurator : public ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit VpnConfigurator(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
|
||||
QString genVpnProtocolConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, Proto proto, ErrorCode *errorCode = nullptr);
|
||||
const QJsonObject &containerConfig, Proto proto, QString &clientId,
|
||||
ErrorCode *errorCode = nullptr);
|
||||
|
||||
QPair<QString, QString> getDnsForConfig(int serverIndex);
|
||||
QString &processConfigWithDnsSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
@ -32,8 +32,8 @@ public:
|
|||
QString &processConfigWithExportSettings(int serverIndex, DockerContainer container, Proto proto, QString &config);
|
||||
|
||||
// workaround for containers which is not support normal configuration
|
||||
void updateContainerConfigAfterInstallation(DockerContainer container,
|
||||
QJsonObject &containerConfig, const QString &stdOut);
|
||||
void updateContainerConfigAfterInstallation(DockerContainer container, QJsonObject &containerConfig,
|
||||
const QString &stdOut);
|
||||
|
||||
std::shared_ptr<OpenVpnConfigurator> openVpnConfigurator;
|
||||
std::shared_ptr<ShadowSocksConfigurator> shadowSocksConfigurator;
|
||||
|
@ -42,6 +42,10 @@ public:
|
|||
std::shared_ptr<Ikev2Configurator> ikev2Configurator;
|
||||
std::shared_ptr<SshConfigurator> sshConfigurator;
|
||||
std::shared_ptr<AwgConfigurator> awgConfigurator;
|
||||
|
||||
signals:
|
||||
void newVpnConfigCreated(const QString &clientId, const QString &clientName, const DockerContainer container,
|
||||
ServerCredentials credentials);
|
||||
};
|
||||
|
||||
#endif // VPN_CONFIGURATOR_H
|
||||
|
|
|
@ -177,7 +177,7 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
|||
}
|
||||
|
||||
QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode)
|
||||
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode)
|
||||
{
|
||||
ServerController serverController(m_settings);
|
||||
QString scriptData = amnezia::scriptData(m_configTemplate, container);
|
||||
|
@ -205,6 +205,8 @@ QString WireguardConfigurator::genWireguardConfig(const ServerCredentials &crede
|
|||
jConfig[config_key::psk_key] = connData.pskKey;
|
||||
jConfig[config_key::server_pub_key] = connData.serverPubKey;
|
||||
|
||||
clientId = connData.clientPubKey;
|
||||
|
||||
return QJsonDocument(jConfig).toJson();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
};
|
||||
|
||||
QString genWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
|
||||
const QJsonObject &containerConfig, QString &clientId, ErrorCode *errorCode = nullptr);
|
||||
|
||||
QString processConfigWithLocalSettings(QString config);
|
||||
QString processConfigWithExportSettings(QString config);
|
||||
|
|
|
@ -36,7 +36,7 @@ enum ErrorCode
|
|||
ServerPacketManagerError,
|
||||
|
||||
// Ssh connection errors
|
||||
SshRequsetDeniedError, SshInterruptedError, SshInternalError,
|
||||
SshRequestDeniedError, SshInterruptedError, SshInternalError,
|
||||
SshPrivateKeyError, SshPrivateKeyFormatError, SshTimeoutError,
|
||||
|
||||
// Ssh sftp errors
|
||||
|
@ -47,7 +47,6 @@ enum ErrorCode
|
|||
SshSftpNoMediaError,
|
||||
|
||||
// Local errors
|
||||
FailedToSaveConfigData,
|
||||
OpenVpnConfigMissing,
|
||||
OpenVpnManagementServerError,
|
||||
ConfigMissing,
|
||||
|
@ -67,7 +66,6 @@ enum ErrorCode
|
|||
|
||||
// 3rd party utils errors
|
||||
OpenSslFailed,
|
||||
OpenVpnExecutableCrashed,
|
||||
ShadowSocksExecutableCrashed,
|
||||
CloakExecutableCrashed,
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ QString errorString(ErrorCode code){
|
|||
case(ServerUserNotInSudo): return QObject::tr("The user does not have permission to use sudo");
|
||||
|
||||
// Libssh errors
|
||||
case(SshRequsetDeniedError): return QObject::tr("Ssh request was denied");
|
||||
case(SshRequestDeniedError): return QObject::tr("Ssh request was denied");
|
||||
case(SshInterruptedError): return QObject::tr("Ssh request was interrupted");
|
||||
case(SshInternalError): return QObject::tr("Ssh internal error");
|
||||
case(SshPrivateKeyError): return QObject::tr("Invalid private key or invalid passphrase entered");
|
||||
|
@ -42,7 +42,6 @@ QString errorString(ErrorCode code){
|
|||
case(SshSftpNoMediaError): return QObject::tr("Sftp error: No media was in remote drive");
|
||||
|
||||
// Local errors
|
||||
case (FailedToSaveConfigData): return QObject::tr("Failed to save config to disk");
|
||||
case (OpenVpnConfigMissing): return QObject::tr("OpenVPN config missing");
|
||||
case (OpenVpnManagementServerError): return QObject::tr("OpenVPN management server error");
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ namespace libssh {
|
|||
|
||||
switch (errorCode) {
|
||||
case(SSH_NO_ERROR): return ErrorCode::NoError;
|
||||
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequsetDeniedError;
|
||||
case(SSH_REQUEST_DENIED): return ErrorCode::SshRequestDeniedError;
|
||||
case(SSH_EINTR): return ErrorCode::SshInterruptedError;
|
||||
case(SSH_FATAL): return ErrorCode::SshInternalError;
|
||||
default: return ErrorCode::SshInternalError;
|
||||
|
|
6
client/images/controls/close.svg
Normal file
6
client/images/controls/close.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="x, ×, close">
|
||||
<path id="Vector" d="M18 6L6 18" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="Vector_2" d="M6 6L18 18" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 374 B |
6
client/images/controls/search.svg
Normal file
6
client/images/controls/search.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="search">
|
||||
<path id="Vector" d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="Vector_2" d="M21.0004 20.9984L16.6504 16.6484" stroke="#D7D8DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 483 B |
|
@ -222,5 +222,8 @@
|
|||
<file>server_scripts/awg/configure_container.sh</file>
|
||||
<file>server_scripts/awg/run_container.sh</file>
|
||||
<file>server_scripts/awg/Dockerfile</file>
|
||||
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
||||
<file>images/controls/close.svg</file>
|
||||
<file>images/controls/search.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); docker_pkg="docker.io"; dist="debian";\
|
||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); docker_pkg="docker"; dist="fedora";\
|
||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); docker_pkg="docker"; dist="centos";\
|
||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
|
||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
|
||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
|
||||
else echo "Packet manager not found"; exit 1; fi;\
|
||||
echo "Dist: $dist, Packet manager: $pm, Docker pkg: $docker_pkg";\
|
||||
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\
|
||||
if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi;\
|
||||
if ! command -v sudo > /dev/null 2>&1; then $pm update -yq; $pm install -yq sudo; fi;\
|
||||
if ! command -v fuser > /dev/null 2>&1; then sudo $pm install -yq psmisc; fi;\
|
||||
if ! command -v lsof > /dev/null 2>&1; then sudo $pm install -yq lsof; fi;\
|
||||
if ! command -v docker > /dev/null 2>&1; then sudo $pm update -yq; sudo $pm install -yq $docker_pkg;\
|
||||
if ! command -v sudo > /dev/null 2>&1; then $pm $check_pkgs; $pm $silent_inst sudo; fi;\
|
||||
if ! command -v fuser > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst psmisc; fi;\
|
||||
if ! command -v lsof > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst lsof; fi;\
|
||||
if ! command -v docker > /dev/null 2>&1; then sudo $pm $check_pkgs; sudo $pm $silent_inst $docker_pkg;\
|
||||
if [ "$dist" = "fedora" ] || [ "$dist" = "centos" ] || [ "$dist" = "debian" ]; then sudo systemctl enable docker && sudo systemctl start docker; fi;\
|
||||
fi;\
|
||||
if [ "$dist" = "debian" ]; then \
|
||||
docker_service=$(systemctl list-units --full --all | grep docker.service | grep -v inactive | grep -v dead | grep -v failed);\
|
||||
if [ -z "$docker_service" ]; then sudo $pm update -yq; sudo $pm install -yq curl $docker_pkg; fi;\
|
||||
if [ -z "$docker_service" ]; then sudo $pm $check_pkgs; sudo $pm $silent_inst curl $docker_pkg; fi;\
|
||||
sleep 3 && sudo systemctl start docker && sleep 3;\
|
||||
fi;\
|
||||
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install Docker";exit 1;fi;\
|
||||
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install Docker"; exit 1; fi;\
|
||||
docker --version
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#include <QImage>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "configurators/cloak_configurator.h"
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
#include "configurators/shadowsocks_configurator.h"
|
||||
#include "configurators/wireguard_configurator.h"
|
||||
#include "core/errorstrings.h"
|
||||
#include "systemController.h"
|
||||
|
@ -19,11 +21,13 @@
|
|||
|
||||
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
const std::shared_ptr<Settings> &settings,
|
||||
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_serversModel(serversModel),
|
||||
m_containersModel(containersModel),
|
||||
m_clientManagementModel(clientManagementModel),
|
||||
m_settings(settings),
|
||||
m_configurator(configurator)
|
||||
{
|
||||
|
@ -75,13 +79,12 @@ void ExportController::generateFullAccessConfigAndroid()
|
|||
}
|
||||
#endif
|
||||
|
||||
void ExportController::generateConnectionConfig()
|
||||
void ExportController::generateConnectionConfig(const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
||||
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
|
||||
ServerCredentials credentials =
|
||||
qvariant_cast<ServerCredentials>(m_serversModel->data(serverIndex, ServersModel::Roles::CredentialsRole));
|
||||
ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials();
|
||||
|
||||
DockerContainer container = static_cast<DockerContainer>(m_containersModel->getCurrentlyProcessedContainerIndex());
|
||||
QModelIndex containerModelIndex = m_containersModel->index(container);
|
||||
|
@ -93,17 +96,25 @@ void ExportController::generateConnectionConfig()
|
|||
for (Proto protocol : ContainerProps::protocolsForContainer(container)) {
|
||||
QJsonObject protocolConfig = m_settings->protocolConfig(serverIndex, container, protocol);
|
||||
|
||||
QString vpnConfig =
|
||||
m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol, &errorCode);
|
||||
QString clientId;
|
||||
QString vpnConfig = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, protocol,
|
||||
clientId, &errorCode);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
protocolConfig.insert(config_key::last_config, vpnConfig);
|
||||
containerConfig.insert(ProtocolProps::protoToString(protocol), protocolConfig);
|
||||
if (protocol == Proto::OpenVpn || protocol == Proto::Awg || protocol == Proto::WireGuard) {
|
||||
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject config = m_settings->server(serverIndex);
|
||||
QJsonObject config = m_settings->server(serverIndex); // todo change to servers_model
|
||||
if (!errorCode) {
|
||||
config.remove(config_key::userName);
|
||||
config.remove(config_key::password);
|
||||
|
@ -126,7 +137,127 @@ void ExportController::generateConnectionConfig()
|
|||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateOpenVpnConfig()
|
||||
void ExportController::generateOpenVpnConfig(const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
||||
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
|
||||
ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials();
|
||||
|
||||
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 clientId;
|
||||
QString config = m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig,
|
||||
clientId, &errorCode);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, 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_config.append(line + "\n");
|
||||
}
|
||||
|
||||
m_qrCodes = generateQrCodeImageSeries(m_config.toUtf8());
|
||||
|
||||
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateWireGuardConfig(const QString &clientName)
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
||||
int serverIndex = m_serversModel->getCurrentlyProcessedServerIndex();
|
||||
ServerCredentials credentials = m_serversModel->getCurrentlyProcessedServerCredentials();
|
||||
|
||||
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));
|
||||
|
||||
QString clientId;
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
QString config = m_configurator->wireguardConfigurator->genWireguardConfig(credentials, container, containerConfig,
|
||||
clientId, &errorCode);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::WireGuard, 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_config.append(line + "\n");
|
||||
}
|
||||
|
||||
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_config.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
|
||||
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
|
||||
|
||||
errorCode = m_clientManagementModel->appendClient(clientId, clientName, container, credentials);
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateShadowSocksConfig()
|
||||
{
|
||||
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->shadowSocksConfigurator->genShadowSocksConfig(credentials, container,
|
||||
containerConfig, &errorCode);
|
||||
|
||||
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::ShadowSocks, config);
|
||||
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||
|
||||
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n");
|
||||
for (const QString &line : lines) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
||||
m_nativeConfigString =
|
||||
QString("%1:%2@%3:%4")
|
||||
.arg(configJson.value("method").toString(), configJson.value("password").toString(),
|
||||
configJson.value("server").toString(), configJson.value("server_port").toString());
|
||||
|
||||
m_nativeConfigString = "ss://" + m_nativeConfigString.toUtf8().toBase64();
|
||||
|
||||
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(m_nativeConfigString.toUtf8(), qrcodegen::QrCode::Ecc::LOW);
|
||||
m_qrCodes << svgToBase64(QString::fromStdString(toSvgString(qr, 1)));
|
||||
|
||||
emit exportConfigChanged();
|
||||
}
|
||||
|
||||
void ExportController::generateCloakConfig()
|
||||
{
|
||||
clearPreviousConfig();
|
||||
|
||||
|
@ -142,47 +273,19 @@ void ExportController::generateOpenVpnConfig()
|
|||
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
QString config =
|
||||
m_configurator->openVpnConfigurator->genOpenVpnConfig(credentials, container, containerConfig, &errorCode);
|
||||
m_configurator->cloakConfigurator->genCloakConfig(credentials, container, containerConfig, &errorCode);
|
||||
|
||||
if (errorCode) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
return;
|
||||
}
|
||||
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::OpenVpn, config);
|
||||
config = m_configurator->processConfigWithExportSettings(serverIndex, container, Proto::Cloak, config);
|
||||
QJsonObject configJson = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||
|
||||
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_config.append(line + "\n");
|
||||
}
|
||||
configJson.remove(config_key::transport_proto);
|
||||
configJson.insert("ProxyMethod", "shadowsocks");
|
||||
|
||||
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);
|
||||
|
||||
auto configJson = QJsonDocument::fromJson(config.toUtf8()).object();
|
||||
QStringList lines = configJson.value(config_key::config).toString().replace("\r", "").split("\n");
|
||||
QStringList lines = QString(QJsonDocument(configJson).toJson()).replace("\r", "").split("\n");
|
||||
for (const QString &line : lines) {
|
||||
m_config.append(line + "\n");
|
||||
}
|
||||
|
@ -195,6 +298,11 @@ QString ExportController::getConfig()
|
|||
return m_config;
|
||||
}
|
||||
|
||||
QString ExportController::getNativeConfigString()
|
||||
{
|
||||
return m_nativeConfigString;
|
||||
}
|
||||
|
||||
QList<QString> ExportController::getQrCodes()
|
||||
{
|
||||
return m_qrCodes;
|
||||
|
@ -205,6 +313,30 @@ void ExportController::exportConfig(const QString &fileName)
|
|||
SystemController::saveFile(fileName, m_config);
|
||||
}
|
||||
|
||||
void ExportController::updateClientManagementModel(const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
ErrorCode errorCode = m_clientManagementModel->updateModel(container, credentials);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
}
|
||||
}
|
||||
|
||||
void ExportController::revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
ErrorCode errorCode = m_clientManagementModel->revokeClient(row, container, credentials);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
}
|
||||
}
|
||||
|
||||
void ExportController::renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
ErrorCode errorCode = m_clientManagementModel->renameClient(row, clientName, container, credentials);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorString(errorCode));
|
||||
}
|
||||
}
|
||||
|
||||
QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &data)
|
||||
{
|
||||
double k = 850;
|
||||
|
@ -219,7 +351,7 @@ QList<QString> ExportController::generateQrCodeImageSeries(const QByteArray &dat
|
|||
QByteArray ba = chunk.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
|
||||
|
||||
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(ba, qrcodegen::QrCode::Ecc::LOW);
|
||||
QString svg = QString::fromStdString(toSvgString(qr, 0));
|
||||
QString svg = QString::fromStdString(toSvgString(qr, 1));
|
||||
chunks.append(svgToBase64(svg));
|
||||
}
|
||||
|
||||
|
@ -239,5 +371,6 @@ int ExportController::getQrCodesCount()
|
|||
void ExportController::clearPreviousConfig()
|
||||
{
|
||||
m_config.clear();
|
||||
m_nativeConfigString.clear();
|
||||
m_qrCodes.clear();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "configurators/vpn_configurator.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/servers_model.h"
|
||||
#include "ui/models/clientManagementModel.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "platforms/android/authResultReceiver.h"
|
||||
#endif
|
||||
|
@ -16,27 +17,36 @@ class ExportController : public QObject
|
|||
public:
|
||||
explicit ExportController(const QSharedPointer<ServersModel> &serversModel,
|
||||
const QSharedPointer<ContainersModel> &containersModel,
|
||||
const QSharedPointer<ClientManagementModel> &clientManagementModel,
|
||||
const std::shared_ptr<Settings> &settings,
|
||||
const std::shared_ptr<VpnConfigurator> &configurator, QObject *parent = nullptr);
|
||||
|
||||
Q_PROPERTY(QList<QString> qrCodes READ getQrCodes NOTIFY exportConfigChanged)
|
||||
Q_PROPERTY(int qrCodesCount READ getQrCodesCount NOTIFY exportConfigChanged)
|
||||
Q_PROPERTY(QString config READ getConfig NOTIFY exportConfigChanged)
|
||||
Q_PROPERTY(QString nativeConfigString READ getNativeConfigString NOTIFY exportConfigChanged)
|
||||
|
||||
public slots:
|
||||
void generateFullAccessConfig();
|
||||
#if defined(Q_OS_ANDROID)
|
||||
void generateFullAccessConfigAndroid();
|
||||
#endif
|
||||
void generateConnectionConfig();
|
||||
void generateOpenVpnConfig();
|
||||
void generateWireGuardConfig();
|
||||
void generateConnectionConfig(const QString &clientName);
|
||||
void generateOpenVpnConfig(const QString &clientName);
|
||||
void generateWireGuardConfig(const QString &clientName);
|
||||
void generateShadowSocksConfig();
|
||||
void generateCloakConfig();
|
||||
|
||||
QString getConfig();
|
||||
QString getNativeConfigString();
|
||||
QList<QString> getQrCodes();
|
||||
|
||||
void exportConfig(const QString &fileName);
|
||||
|
||||
void updateClientManagementModel(const DockerContainer container, ServerCredentials credentials);
|
||||
void revokeConfig(const int row, const DockerContainer container, ServerCredentials credentials);
|
||||
void renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials);
|
||||
|
||||
signals:
|
||||
void generateConfig(int type);
|
||||
void exportErrorOccurred(const QString &errorMessage);
|
||||
|
@ -55,10 +65,12 @@ private:
|
|||
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
QSharedPointer<ContainersModel> m_containersModel;
|
||||
QSharedPointer<ClientManagementModel> m_clientManagementModel;
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
std::shared_ptr<VpnConfigurator> m_configurator;
|
||||
|
||||
QString m_config;
|
||||
QString m_nativeConfigString;
|
||||
QList<QString> m_qrCodes;
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
|
|
|
@ -51,7 +51,9 @@ namespace PageLoader
|
|||
PageProtocolWireGuardSettings,
|
||||
PageProtocolAwgSettings,
|
||||
PageProtocolIKev2Settings,
|
||||
PageProtocolRaw
|
||||
PageProtocolRaw,
|
||||
|
||||
PageShareFullAccess
|
||||
};
|
||||
Q_ENUM_NS(PageEnum)
|
||||
|
||||
|
|
|
@ -1,104 +1,373 @@
|
|||
#include "clientManagementModel.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
ClientManagementModel::ClientManagementModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
#include "core/servercontroller.h"
|
||||
#include "logger.h"
|
||||
|
||||
}
|
||||
|
||||
void ClientManagementModel::clearData()
|
||||
namespace
|
||||
{
|
||||
beginResetModel();
|
||||
m_content.clear();
|
||||
endResetModel();
|
||||
}
|
||||
Logger logger("ClientManagementModel");
|
||||
|
||||
void ClientManagementModel::setContent(const QVector<QVariant> &data)
|
||||
{
|
||||
beginResetModel();
|
||||
m_content = data;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QJsonObject ClientManagementModel::getContent(amnezia::Proto protocol)
|
||||
{
|
||||
QJsonObject clientsTable;
|
||||
for (const auto &item : m_content) {
|
||||
if (protocol == amnezia::Proto::OpenVpn) {
|
||||
clientsTable[item.toJsonObject()["openvpnCertId"].toString()] = item.toJsonObject();
|
||||
} else if (protocol == amnezia::Proto::WireGuard) {
|
||||
clientsTable[item.toJsonObject()["wireguardPublicKey"].toString()] = item.toJsonObject();
|
||||
}
|
||||
namespace configKey {
|
||||
constexpr char clientId[] = "clientId";
|
||||
constexpr char clientName[] = "clientName";
|
||||
constexpr char container[] = "container";
|
||||
constexpr char userData[] = "userData";
|
||||
}
|
||||
return clientsTable;
|
||||
}
|
||||
|
||||
ClientManagementModel::ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent)
|
||||
: m_settings(settings), QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int ClientManagementModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return static_cast<int>(m_content.size());
|
||||
return static_cast<int>(m_clientsTable.size());
|
||||
}
|
||||
|
||||
QVariant ClientManagementModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0
|
||||
|| index.row() >= static_cast<int>(m_content.size())) {
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(m_clientsTable.size())) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role == NameRole) {
|
||||
return m_content[index.row()].toJsonObject()["clientName"].toString();
|
||||
} else if (role == OpenVpnCertIdRole) {
|
||||
return m_content[index.row()].toJsonObject()["openvpnCertId"].toString();
|
||||
} else if (role == OpenVpnCertDataRole) {
|
||||
return m_content[index.row()].toJsonObject()["openvpnCertData"].toString();
|
||||
} else if (role == WireGuardPublicKey) {
|
||||
return m_content[index.row()].toJsonObject()["wireguardPublicKey"].toString();
|
||||
auto client = m_clientsTable.at(index.row()).toObject();
|
||||
auto userData = client.value(configKey::userData).toObject();
|
||||
|
||||
switch (role) {
|
||||
case ClientNameRole: return userData.value(configKey::clientName).toString();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void ClientManagementModel::setData(const QModelIndex &index, QVariant data, int role)
|
||||
ErrorCode ClientManagementModel::updateModel(DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0
|
||||
|| index.row() >= static_cast<int>(m_content.size())) {
|
||||
return;
|
||||
beginResetModel();
|
||||
m_clientsTable = QJsonArray();
|
||||
|
||||
ServerController serverController(m_settings);
|
||||
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
|
||||
const QString clientsTableFile =
|
||||
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
|
||||
const QByteArray clientsTableString =
|
||||
serverController.getTextFileFromContainer(container, credentials, clientsTableFile, &error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to get the clientsTable file from the server";
|
||||
endResetModel();
|
||||
return error;
|
||||
}
|
||||
|
||||
auto client = m_content[index.row()].toJsonObject();
|
||||
if (role == NameRole) {
|
||||
client["clientName"] = data.toString();
|
||||
} else if (role == OpenVpnCertIdRole) {
|
||||
client["openvpnCertId"] = data.toString();
|
||||
} else if (role == OpenVpnCertDataRole) {
|
||||
client["openvpnCertData"] = data.toString();
|
||||
} else if (role == WireGuardPublicKey) {
|
||||
client["wireguardPublicKey"] = data.toString();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (m_content[index.row()] != client) {
|
||||
m_content[index.row()] = client;
|
||||
emit dataChanged(index, index);
|
||||
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
|
||||
|
||||
if (m_clientsTable.isEmpty()) {
|
||||
int count = 0;
|
||||
|
||||
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|
||||
|| container == DockerContainer::Cloak) {
|
||||
error = getOpenVpnClients(serverController, container, credentials, count);
|
||||
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
||||
error = getWireGuardClients(serverController, container, credentials, count);
|
||||
}
|
||||
if (error != ErrorCode::NoError) {
|
||||
endResetModel();
|
||||
return error;
|
||||
}
|
||||
|
||||
const QByteArray newClientsTableString = QJsonDocument(m_clientsTable).toJson();
|
||||
if (clientsTableString != newClientsTableString) {
|
||||
error = serverController.uploadTextFileToContainer(container, credentials, newClientsTableString,
|
||||
clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
return error;
|
||||
}
|
||||
|
||||
bool ClientManagementModel::removeRows(int row)
|
||||
ErrorCode ClientManagementModel::getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count)
|
||||
{
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
const QString getOpenVpnClientsList =
|
||||
"sudo docker exec -i $CONTAINER_NAME bash -c 'ls /opt/amnezia/openvpn/pki/issued'";
|
||||
QString script = serverController.replaceVars(getOpenVpnClientsList,
|
||||
serverController.genVarsForScript(credentials, container));
|
||||
error = serverController.runScript(credentials, script, cbReadStdOut);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to retrieve the list of issued certificates on the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
if (!stdOut.isEmpty()) {
|
||||
QStringList certsIds = stdOut.split("\n", Qt::SkipEmptyParts);
|
||||
certsIds.removeAll("AmneziaReq.crt");
|
||||
|
||||
for (auto &openvpnCertId : certsIds) {
|
||||
openvpnCertId.replace(".crt", "");
|
||||
if (!isClientExists(openvpnCertId)) {
|
||||
QJsonObject client;
|
||||
client[configKey::clientId] = openvpnCertId;
|
||||
|
||||
QJsonObject userData;
|
||||
userData[configKey::clientName] = QString("Client %1").arg(count);
|
||||
client[configKey::userData] = userData;
|
||||
|
||||
m_clientsTable.push_back(client);
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count)
|
||||
{
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
|
||||
const QString wireGuardConfigFile =
|
||||
QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
|
||||
const QString wireguardConfigString =
|
||||
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to get the wg conf file from the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
auto configLines = wireguardConfigString.split("\n", Qt::SkipEmptyParts);
|
||||
QStringList wireguardKeys;
|
||||
for (const auto &line : configLines) {
|
||||
auto configPair = line.split(" = ", Qt::SkipEmptyParts);
|
||||
if (configPair.front() == "PublicKey") {
|
||||
wireguardKeys.push_back(configPair.back());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &wireguardKey : wireguardKeys) {
|
||||
if (!isClientExists(wireguardKey)) {
|
||||
QJsonObject client;
|
||||
client[configKey::clientId] = wireguardKey;
|
||||
|
||||
QJsonObject userData;
|
||||
userData[configKey::clientName] = QString("Client %1").arg(count);
|
||||
client[configKey::userData] = userData;
|
||||
|
||||
m_clientsTable.push_back(client);
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
bool ClientManagementModel::isClientExists(const QString &clientId)
|
||||
{
|
||||
for (const QJsonValue &value : qAsConst(m_clientsTable)) {
|
||||
if (value.isObject()) {
|
||||
QJsonObject obj = value.toObject();
|
||||
if (obj.contains(configKey::clientId) && obj[configKey::clientId].toString() == clientId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QString &clientName,
|
||||
const DockerContainer container, ServerCredentials credentials)
|
||||
{
|
||||
ErrorCode error;
|
||||
|
||||
error = updateModel(container, credentials);
|
||||
if (error != ErrorCode::NoError) {
|
||||
return error;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_clientsTable.size(); i++) {
|
||||
if (m_clientsTable.at(i).toObject().value(configKey::clientId) == clientId) {
|
||||
return renameClient(i, clientName, container, credentials);
|
||||
}
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
QJsonObject client;
|
||||
client[configKey::clientId] = clientId;
|
||||
|
||||
QJsonObject userData;
|
||||
userData[configKey::clientName] = clientName;
|
||||
client[configKey::userData] = userData;
|
||||
m_clientsTable.push_back(client);
|
||||
endResetModel();
|
||||
|
||||
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
|
||||
|
||||
ServerController serverController(m_settings);
|
||||
const QString clientsTableFile =
|
||||
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
|
||||
|
||||
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName, const DockerContainer container,
|
||||
ServerCredentials credentials)
|
||||
{
|
||||
auto client = m_clientsTable.at(row).toObject();
|
||||
auto userData = client[configKey::userData].toObject();
|
||||
userData[configKey::clientName] = clientName;
|
||||
client[configKey::userData] = userData;
|
||||
|
||||
m_clientsTable.replace(row, client);
|
||||
emit dataChanged(index(row, 0), index(row, 0));
|
||||
|
||||
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
|
||||
|
||||
ServerController serverController(m_settings);
|
||||
const QString clientsTableFile =
|
||||
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
|
||||
|
||||
ErrorCode error =
|
||||
serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container,
|
||||
ServerCredentials credentials)
|
||||
{
|
||||
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocks
|
||||
|| container == DockerContainer::Cloak) {
|
||||
return revokeOpenVpn(row, container, credentials);
|
||||
} else if (container == DockerContainer::WireGuard || container == DockerContainer::Awg) {
|
||||
return revokeWireGuard(row, container, credentials);
|
||||
}
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::revokeOpenVpn(const int row, const DockerContainer container,
|
||||
ServerCredentials credentials)
|
||||
{
|
||||
auto client = m_clientsTable.at(row).toObject();
|
||||
QString clientId = client.value(configKey::clientId).toString();
|
||||
|
||||
const QString getOpenVpnCertData = QString("sudo docker exec -i $CONTAINER_NAME bash -c '"
|
||||
"cd /opt/amnezia/openvpn ;\\"
|
||||
"easyrsa revoke %1 ;\\"
|
||||
"easyrsa gen-crl ;\\"
|
||||
"cp pki/crl.pem .'")
|
||||
.arg(clientId);
|
||||
|
||||
ServerController serverController(m_settings);
|
||||
const QString script =
|
||||
serverController.replaceVars(getOpenVpnCertData, serverController.genVarsForScript(credentials, container));
|
||||
ErrorCode error = serverController.runScript(credentials, script);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to revoke the certificate";
|
||||
return error;
|
||||
}
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_content.removeAt(row);
|
||||
m_clientsTable.removeAt(row);
|
||||
endRemoveRows();
|
||||
return true;
|
||||
|
||||
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
|
||||
|
||||
const QString clientsTableFile =
|
||||
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
|
||||
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerContainer container,
|
||||
ServerCredentials credentials)
|
||||
{
|
||||
ErrorCode error;
|
||||
ServerController serverController(m_settings);
|
||||
|
||||
const QString wireGuardConfigFile =
|
||||
QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
|
||||
const QString wireguardConfigString =
|
||||
serverController.getTextFileFromContainer(container, credentials, wireGuardConfigFile, &error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to get the wg conf file from the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
auto client = m_clientsTable.at(row).toObject();
|
||||
QString clientId = client.value(configKey::clientId).toString();
|
||||
|
||||
auto configSections = wireguardConfigString.split("[", Qt::SkipEmptyParts);
|
||||
for (auto §ion : configSections) {
|
||||
if (section.contains(clientId)) {
|
||||
configSections.removeOne(section);
|
||||
break;
|
||||
}
|
||||
}
|
||||
QString newWireGuardConfig = configSections.join("[");
|
||||
newWireGuardConfig.insert(0, "[");
|
||||
error = serverController.uploadTextFileToContainer(container, credentials, newWireGuardConfig, wireGuardConfigFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the wg conf file to the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
m_clientsTable.removeAt(row);
|
||||
endRemoveRows();
|
||||
|
||||
const QByteArray clientsTableString = QJsonDocument(m_clientsTable).toJson();
|
||||
|
||||
const QString clientsTableFile =
|
||||
QString("/opt/amnezia/%1/clientsTable").arg(ContainerProps::containerTypeToString(container));
|
||||
error = serverController.uploadTextFileToContainer(container, credentials, clientsTableString, clientsTableFile);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to upload the clientsTable file to the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'";
|
||||
error = serverController.runScript(
|
||||
credentials,
|
||||
serverController.replaceVars(script.arg(wireGuardConfigFile),
|
||||
serverController.genVarsForScript(credentials, container)));
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to execute the command 'wg syncconf' on the server";
|
||||
return error;
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ClientManagementModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[NameRole] = "clientName";
|
||||
roles[OpenVpnCertIdRole] = "openvpnCertId";
|
||||
roles[OpenVpnCertDataRole] = "openvpnCertData";
|
||||
roles[WireGuardPublicKey] = "wireguardPublicKey";
|
||||
roles[ClientNameRole] = "clientName";
|
||||
return roles;
|
||||
}
|
||||
|
|
|
@ -2,36 +2,48 @@
|
|||
#define CLIENTMANAGEMENTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "protocols/protocols_defs.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include "settings.h"
|
||||
|
||||
class ClientManagementModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ClientRoles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
OpenVpnCertIdRole,
|
||||
OpenVpnCertDataRole,
|
||||
WireGuardPublicKey,
|
||||
enum Roles {
|
||||
ClientNameRole = Qt::UserRole + 1,
|
||||
};
|
||||
|
||||
ClientManagementModel(QObject *parent = nullptr);
|
||||
ClientManagementModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
|
||||
void clearData();
|
||||
void setContent(const QVector<QVariant> &data);
|
||||
QJsonObject getContent(amnezia::Proto protocol);
|
||||
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);
|
||||
bool removeRows(int row);
|
||||
|
||||
public slots:
|
||||
ErrorCode updateModel(DockerContainer container, ServerCredentials credentials);
|
||||
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
|
||||
ServerCredentials credentials);
|
||||
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container,
|
||||
ServerCredentials credentials);
|
||||
ErrorCode revokeClient(const int index, const DockerContainer container, ServerCredentials credentials);
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
QVector<QVariant> m_content;
|
||||
bool isClientExists(const QString &clientId);
|
||||
|
||||
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, ServerCredentials credentials);
|
||||
ErrorCode revokeWireGuard(const int row, const DockerContainer container, ServerCredentials credentials);
|
||||
|
||||
ErrorCode getOpenVpnClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count);
|
||||
ErrorCode getWireGuardClients(ServerController &serverController, DockerContainer container, ServerCredentials credentials, int &count);
|
||||
|
||||
QJsonArray m_clientsTable;
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
};
|
||||
|
||||
#endif // CLIENTMANAGEMENTMODEL_H
|
||||
|
|
|
@ -145,6 +145,11 @@ QString ServersModel::getCurrentlyProcessedServerHostName()
|
|||
return qvariant_cast<QString>(data(m_currentlyProcessedServerIndex, HostNameRole));
|
||||
}
|
||||
|
||||
const ServerCredentials ServersModel::getCurrentlyProcessedServerCredentials()
|
||||
{
|
||||
return serverCredentials(m_currentlyProcessedServerIndex);
|
||||
}
|
||||
|
||||
bool ServersModel::isDefaultServerCurrentlyProcessed()
|
||||
{
|
||||
return m_defaultServerIndex == m_currentlyProcessedServerIndex;
|
||||
|
|
|
@ -53,6 +53,7 @@ public slots:
|
|||
int getCurrentlyProcessedServerIndex();
|
||||
|
||||
QString getCurrentlyProcessedServerHostName();
|
||||
const ServerCredentials getCurrentlyProcessedServerCredentials();
|
||||
|
||||
void addServer(const QJsonObject &server);
|
||||
void editServer(const QJsonObject &server);
|
||||
|
|
|
@ -112,6 +112,30 @@ DrawerType {
|
|||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
|
||||
visible: nativeConfigString.text !== ""
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
||||
disabledColor: "#878B91"
|
||||
textColor: "#D7D8DB"
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Copy config string")
|
||||
imageSource: "qrc:/images/controls/copy.svg"
|
||||
|
||||
onClicked: {
|
||||
nativeConfigString.selectAll()
|
||||
nativeConfigString.copy()
|
||||
nativeConfigString.select(0, 0)
|
||||
PageController.showNotificationMessage(qsTr("Copied"))
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
@ -170,6 +194,12 @@ DrawerType {
|
|||
}
|
||||
|
||||
TextField {
|
||||
id: nativeConfigString
|
||||
visible: false
|
||||
text: ExportController.nativeConfigString
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: configText
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
@ -213,7 +243,6 @@ DrawerType {
|
|||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
smooth: false
|
||||
|
||||
source: ExportController.qrCodesCount ? ExportController.qrCodes[0] : ""
|
||||
|
|
|
@ -87,6 +87,7 @@ Switch {
|
|||
id: content
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
|
|
|
@ -54,7 +54,7 @@ PageType {
|
|||
regularExpression: InstallController.ipAddressPortRegExp()
|
||||
}
|
||||
|
||||
onTextFieldTextChanged: {
|
||||
onFocusChanged: {
|
||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,10 @@ PageType {
|
|||
clickedFunc: function() {
|
||||
hidePassword = !hidePassword
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
textField.text = textField.text.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
|
@ -90,6 +94,7 @@ PageType {
|
|||
text: qsTr("Continue")
|
||||
|
||||
onClicked: function() {
|
||||
forceActiveFocus()
|
||||
if (!isCredentialsFilled()) {
|
||||
return
|
||||
}
|
||||
|
@ -112,8 +117,7 @@ PageType {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: 12
|
||||
|
||||
text: qsTr("All data you enter will remain strictly confidential
|
||||
and will not be shared or disclosed to the Amnezia or any third parties")
|
||||
text: qsTr("All data you enter will remain strictly confidential and will not be shared or disclosed to the Amnezia or any third parties")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ PageType {
|
|||
}
|
||||
|
||||
function onImportFinished() {
|
||||
if (ConnectionController.isConnected) {
|
||||
if (!ConnectionController.isConnected) {
|
||||
ServersModel.setDefaultServerIndex(ServersModel.getServersCount() - 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,15 +18,28 @@ PageType {
|
|||
|
||||
enum ConfigType {
|
||||
AmneziaConnection,
|
||||
AmneziaFullAccess,
|
||||
OpenVpn,
|
||||
WireGuard
|
||||
WireGuard,
|
||||
ShadowSocks,
|
||||
Cloak
|
||||
}
|
||||
|
||||
signal revokeConfig(int index)
|
||||
onRevokeConfig: function(index) {
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.revokeConfig(index,
|
||||
ContainersModel.getCurrentlyProcessedContainerIndex(),
|
||||
ServersModel.getCurrentlyProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ExportController
|
||||
|
||||
function onGenerateConfig(type) {
|
||||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
|
||||
shareConnectionDrawer.needCloseButton = false
|
||||
|
||||
shareConnectionDrawer.open()
|
||||
|
@ -34,28 +47,34 @@ PageType {
|
|||
PageController.showBusyIndicator(true)
|
||||
|
||||
switch (type) {
|
||||
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(); break;
|
||||
case PageShare.ConfigType.AmneziaFullAccess: {
|
||||
if (Qt.platform.os === "android") {
|
||||
ExportController.generateFullAccessConfigAndroid();
|
||||
} else {
|
||||
ExportController.generateFullAccessConfig();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PageShare.ConfigType.AmneziaConnection: ExportController.generateConnectionConfig(clientNameTextField.textFieldText); break;
|
||||
case PageShare.ConfigType.OpenVpn: {
|
||||
ExportController.generateOpenVpnConfig();
|
||||
ExportController.generateOpenVpnConfig(clientNameTextField.textFieldText)
|
||||
shareConnectionDrawer.configCaption = qsTr("Save OpenVPN config")
|
||||
shareConnectionDrawer.configExtension = ".ovpn"
|
||||
shareConnectionDrawer.configFileName = "amnezia_for_openvpn"
|
||||
break;
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.WireGuard: {
|
||||
ExportController.generateWireGuardConfig();
|
||||
ExportController.generateWireGuardConfig(clientNameTextField.textFieldText)
|
||||
shareConnectionDrawer.configCaption = qsTr("Save WireGuard config")
|
||||
shareConnectionDrawer.configExtension = ".conf"
|
||||
shareConnectionDrawer.configFileName = "amnezia_for_wireguard"
|
||||
break;
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.ShadowSocks: {
|
||||
ExportController.generateShadowSocksConfig()
|
||||
shareConnectionDrawer.configCaption = qsTr("Save ShadowSocks config")
|
||||
shareConnectionDrawer.configExtension = ".json"
|
||||
shareConnectionDrawer.configFileName = "amnezia_for_shadowsocks"
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.Cloak: {
|
||||
ExportController.generateCloakConfig()
|
||||
shareConnectionDrawer.configCaption = qsTr("Save Cloak config")
|
||||
shareConnectionDrawer.configExtension = ".json"
|
||||
shareConnectionDrawer.configFileName = "amnezia_for_cloak"
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,8 +92,7 @@ PageType {
|
|||
}
|
||||
}
|
||||
|
||||
property string fullConfigServerSelectorText
|
||||
property string connectionServerSelectorText
|
||||
property bool isSearchBarVisible: false
|
||||
property bool showContent: false
|
||||
property bool shareButtonEnabled: true
|
||||
property list<QtObject> connectionTypesModel: [
|
||||
|
@ -96,6 +114,16 @@ PageType {
|
|||
property string name: qsTr("WireGuard native format")
|
||||
property var type: PageShare.ConfigType.WireGuard
|
||||
}
|
||||
QtObject {
|
||||
id: shadowSocksConnectionFormat
|
||||
property string name: qsTr("ShadowSocks native format")
|
||||
property var type: PageShare.ConfigType.ShadowSocks
|
||||
}
|
||||
QtObject {
|
||||
id: cloakConnectionFormat
|
||||
property string name: qsTr("Cloak native format")
|
||||
property var type: PageShare.ConfigType.Cloak
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
anchors.top: parent.top
|
||||
|
@ -119,6 +147,51 @@ PageType {
|
|||
Layout.topMargin: 24
|
||||
|
||||
headerText: qsTr("Share VPN Access")
|
||||
|
||||
actionButtonImage: "qrc:/images/controls/more-vertical.svg"
|
||||
actionButtonFunction: function() {
|
||||
shareFullAccessDrawer.open()
|
||||
}
|
||||
|
||||
DrawerType {
|
||||
id: shareFullAccessDrawer
|
||||
|
||||
width: root.width
|
||||
height: root.height * 0.45
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
spacing: 0
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Share full access to the server and VPN")
|
||||
descriptionText: qsTr("Use for your own devices, or share with those you trust to manage the server.")
|
||||
}
|
||||
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Share")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageShareFullAccess)
|
||||
shareFullAccessDrawer.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@ -147,20 +220,21 @@ PageType {
|
|||
|
||||
onClicked: {
|
||||
accessTypeSelector.currentIndex = 0
|
||||
serverSelector.text = root.connectionServerSelectorText
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalRadioButton {
|
||||
checked: root.currentIndex === 1
|
||||
checked: accessTypeSelector.currentIndex === 1
|
||||
|
||||
implicitWidth: (root.width - 32) / 2
|
||||
text: qsTr("Full access")
|
||||
text: qsTr("Users")
|
||||
|
||||
onClicked: {
|
||||
accessTypeSelector.currentIndex = 1
|
||||
serverSelector.text = root.fullConfigServerSelectorText
|
||||
root.shareButtonEnabled = true
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
|
||||
ServersModel.getCurrentlyProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,16 +245,30 @@ PageType {
|
|||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
text: accessTypeSelector.currentIndex === 0 ? qsTr("Share VPN access without the ability to manage the server") :
|
||||
qsTr("Share access to server management. The user with whom you share full access to the server will be able to add and remove any protocols and services to the server, as well as change settings.")
|
||||
visible: accessTypeSelector.currentIndex === 0
|
||||
|
||||
text: qsTr("Share VPN access without the ability to manage the server")
|
||||
color: "#878B91"
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: clientNameTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: accessTypeSelector.currentIndex === 0
|
||||
|
||||
headerText: qsTr("User name")
|
||||
textFieldText: "New client"
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: serverSelector
|
||||
|
||||
signal severSelectorIndexChanged
|
||||
property int currentIndex: 0
|
||||
property int currentIndex: -1
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
@ -207,8 +295,6 @@ PageType {
|
|||
]
|
||||
}
|
||||
|
||||
currentIndex: 0
|
||||
|
||||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
|
@ -217,22 +303,17 @@ PageType {
|
|||
serverSelector.severSelectorIndexChanged()
|
||||
}
|
||||
|
||||
if (accessTypeSelector.currentIndex !== 0) {
|
||||
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
}
|
||||
serverSelector.menuVisible = false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
handler()
|
||||
serverSelector.severSelectorIndexChanged()
|
||||
serverSelectorListView.currentIndex = ServersModel.isDefaultServerHasWriteAccess() ?
|
||||
proxyServersModel.mapFromSource(ServersModel.defaultIndex) : 0
|
||||
serverSelectorListView.triggerCurrentItem()
|
||||
}
|
||||
|
||||
function handler() {
|
||||
serverSelector.text = selectedText
|
||||
root.fullConfigServerSelectorText = selectedText
|
||||
root.connectionServerSelectorText = selectedText
|
||||
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex)
|
||||
}
|
||||
}
|
||||
|
@ -241,8 +322,6 @@ PageType {
|
|||
DropDownType {
|
||||
id: protocolSelector
|
||||
|
||||
visible: accessTypeSelector.currentIndex === 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
|
@ -275,22 +354,18 @@ PageType {
|
|||
currentIndex: 0
|
||||
|
||||
clickedFunction: function() {
|
||||
protocolSelectorListView.currentItem.y
|
||||
|
||||
handler()
|
||||
|
||||
protocolSelector.menuVisible = false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (accessTypeSelector.currentIndex === 0) {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: serverSelector
|
||||
|
||||
function onSeverSelectorIndexChanged() {
|
||||
protocolSelectorListView.currentIndex = 0
|
||||
protocolSelectorListView.currentIndex = proxyContainersModel.mapFromSource(ContainersModel.getDefaultContainer())
|
||||
protocolSelectorListView.triggerCurrentItem()
|
||||
}
|
||||
}
|
||||
|
@ -304,13 +379,17 @@ PageType {
|
|||
}
|
||||
|
||||
protocolSelector.text = selectedText
|
||||
root.connectionServerSelectorText = serverSelector.text
|
||||
|
||||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
ContainersModel.setCurrentlyProcessedContainerIndex(proxyContainersModel.mapToSource(currentIndex))
|
||||
|
||||
fillConnectionTypeModel()
|
||||
|
||||
if (accessTypeSelector.currentIndex === 1) {
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.updateClientManagementModel(ContainersModel.getCurrentlyProcessedContainerIndex(),
|
||||
ServersModel.getCurrentlyProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
|
||||
function fillConnectionTypeModel() {
|
||||
|
@ -322,6 +401,13 @@ PageType {
|
|||
root.connectionTypesModel.push(openVpnConnectionFormat)
|
||||
} else if (index === ContainerProps.containerFromString("amnezia-wireguard")) {
|
||||
root.connectionTypesModel.push(wireGuardConnectionFormat)
|
||||
} else if (index === ContainerProps.containerFromString("amnezia-shadowsocks")) {
|
||||
root.connectionTypesModel.push(openVpnConnectionFormat)
|
||||
root.connectionTypesModel.push(shadowSocksConnectionFormat)
|
||||
} else if (index === ContainerProps.containerFromString("amnezia-openvpn-cloak")) {
|
||||
root.connectionTypesModel.push(openVpnConnectionFormat)
|
||||
root.connectionTypesModel.push(shadowSocksConnectionFormat)
|
||||
root.connectionTypesModel.push(cloakConnectionFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -378,18 +464,235 @@ PageType {
|
|||
Layout.topMargin: 40
|
||||
|
||||
enabled: shareButtonEnabled
|
||||
visible: accessTypeSelector.currentIndex === 0
|
||||
|
||||
text: qsTr("Share")
|
||||
imageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
onClicked: {
|
||||
if (accessTypeSelector.currentIndex === 0) {
|
||||
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
|
||||
} else {
|
||||
ExportController.generateConfig(PageShare.ConfigType.AmneziaFullAccess)
|
||||
ExportController.generateConfig(root.connectionTypesModel[exportTypeSelector.currentIndex].type)
|
||||
}
|
||||
}
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: accessTypeSelector.currentIndex === 1 && !root.isSearchBarVisible
|
||||
|
||||
headerText: qsTr("Users")
|
||||
actionButtonImage: "qrc:/images/controls/search.svg"
|
||||
actionButtonFunction: function() {
|
||||
root.isSearchBarVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 16
|
||||
visible: accessTypeSelector.currentIndex === 1 && root.isSearchBarVisible
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: searchTextField
|
||||
Layout.fillWidth: true
|
||||
|
||||
textFieldPlaceholderText: qsTr("Search")
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
image: "qrc:/images/controls/close.svg"
|
||||
imageColor: "#D7D8DB"
|
||||
|
||||
onClicked: function() {
|
||||
root.isSearchBarVisible = false
|
||||
searchTextField.textFieldText = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: clientsListView
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
visible: accessTypeSelector.currentIndex === 1
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyClientManagementModel
|
||||
sourceModel: ClientManagementModel
|
||||
filters: RegExpFilter {
|
||||
roleName: "clientName"
|
||||
pattern: ".*" + searchTextField.textFieldText + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: clientsListView.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.rightMargin: -16
|
||||
anchors.leftMargin: -16
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: clientName
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
clientInfoDrawer.open()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
DrawerType {
|
||||
id: clientInfoDrawer
|
||||
|
||||
width: root.width
|
||||
height: root.height * 0.5
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
spacing: 8
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
headerText: clientName
|
||||
descriptionText: serverSelector.text
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
||||
disabledColor: "#878B91"
|
||||
textColor: "#D7D8DB"
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Rename")
|
||||
|
||||
onClicked: function() {
|
||||
clientNameEditDrawer.open()
|
||||
}
|
||||
|
||||
DrawerType {
|
||||
id: clientNameEditDrawer
|
||||
|
||||
width: root.width
|
||||
height: root.height * 0.35
|
||||
|
||||
onVisibleChanged: {
|
||||
if (clientNameEditDrawer.visible) {
|
||||
clientNameEditor.textField.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: clientNameEditor
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("Client name")
|
||||
textFieldText: clientName
|
||||
textField.maximumLength: 30
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
onClicked: {
|
||||
if (clientNameEditor.textFieldText !== clientName) {
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.renameClient(index,
|
||||
clientNameEditor.textFieldText,
|
||||
ContainersModel.getCurrentlyProcessedContainerIndex(),
|
||||
ServersModel.getCurrentlyProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
clientNameEditDrawer.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
defaultColor: "transparent"
|
||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
||||
disabledColor: "#878B91"
|
||||
textColor: "#D7D8DB"
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Revoke")
|
||||
|
||||
onClicked: function() {
|
||||
questionDrawer.headerText = qsTr("Revoke the config for a user - ") + clientName + "?"
|
||||
questionDrawer.descriptionText = qsTr("The user will no longer be able to connect to your server.")
|
||||
questionDrawer.yesButtonText = qsTr("Continue")
|
||||
questionDrawer.noButtonText = qsTr("Cancel")
|
||||
|
||||
questionDrawer.yesButtonFunction = function() {
|
||||
questionDrawer.close()
|
||||
clientInfoDrawer.close()
|
||||
root.revokeConfig(index)
|
||||
}
|
||||
questionDrawer.noButtonFunction = function() {
|
||||
questionDrawer.close()
|
||||
}
|
||||
questionDrawer.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QuestionDrawer {
|
||||
id: questionDrawer
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: function(mouse) {
|
||||
forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
155
client/ui/qml/Pages2/PageShareFullAccess.qml
Normal file
155
client/ui/qml/Pages2/PageShareFullAccess.qml
Normal file
|
@ -0,0 +1,155 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
spacing: 0
|
||||
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
headerText: qsTr("Full access to the server and VPN")
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
text: qsTr("We recommend that you use full access to the server only for your own additional devices.\n") +
|
||||
qsTr("If you share full access with other people, they can remove and add protocols and services to the server, which will cause the VPN to work incorrectly for all users. ")
|
||||
color: "#878B91"
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: serverSelector
|
||||
|
||||
signal severSelectorIndexChanged
|
||||
property int currentIndex: 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
drawerHeight: 0.4375
|
||||
|
||||
descriptionText: qsTr("Server")
|
||||
headerText: qsTr("Server")
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: serverSelectorListView
|
||||
|
||||
rootWidth: root.width
|
||||
imageSource: "qrc:/images/controls/check.svg"
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyServersModel
|
||||
sourceModel: ServersModel
|
||||
filters: [
|
||||
ValueFilter {
|
||||
roleName: "hasWriteAccess"
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
currentIndex: 0
|
||||
|
||||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) {
|
||||
serverSelector.currentIndex = serverSelectorListView.currentIndex
|
||||
}
|
||||
|
||||
shareConnectionDrawer.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
serverSelector.menuVisible = false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
handler()
|
||||
}
|
||||
|
||||
function handler() {
|
||||
serverSelector.text = selectedText
|
||||
ServersModel.currentlyProcessedIndex = proxyServersModel.mapToSource(currentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
|
||||
text: qsTr("Share")
|
||||
imageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
onClicked: function() {
|
||||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
|
||||
shareConnectionDrawer.needCloseButton = false
|
||||
|
||||
shareConnectionDrawer.open()
|
||||
shareConnectionDrawer.contentVisible = false
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
if (Qt.platform.os === "android") {
|
||||
ExportController.generateFullAccessConfigAndroid();
|
||||
} else {
|
||||
ExportController.generateFullAccessConfig();
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
shareConnectionDrawer.needCloseButton = true
|
||||
PageController.showTopCloseButton(true)
|
||||
|
||||
shareConnectionDrawer.contentVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
ShareConnectionDrawer {
|
||||
id: shareConnectionDrawer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -227,12 +227,15 @@ QString VpnConnection::createVpnConfigurationForProto(int serverIndex, const Ser
|
|||
configData = lastVpnConfig.value(proto);
|
||||
configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData);
|
||||
} else {
|
||||
configData = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, proto, errorCode);
|
||||
QString clientId;
|
||||
configData = m_configurator->genVpnProtocolConfig(credentials, container, containerConfig, proto, clientId, errorCode);
|
||||
|
||||
if (errorCode && *errorCode) {
|
||||
return "";
|
||||
}
|
||||
|
||||
emit m_configurator->newVpnConfigCreated(clientId, "unnamed client", container, credentials);
|
||||
|
||||
QString configDataBeforeLocalProcessing = configData;
|
||||
|
||||
configData = m_configurator->processConfigWithLocalSettings(serverIndex, container, proto, configData);
|
||||
|
@ -321,7 +324,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
|||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
m_vpnConfiguration = createVpnConfiguration(serverIndex, credentials, container, containerConfig, &e);
|
||||
emit newVpnConfigurationCreated();
|
||||
|
||||
if (e) {
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
return;
|
||||
|
@ -375,7 +378,8 @@ void VpnConnection::appendSplitTunnelingConfig()
|
|||
|
||||
// Allow traffic to Amezia DNS
|
||||
if (routeMode == Settings::VpnOnlyForwardSites){
|
||||
sitesJsonArray.append(amnezia::protocols::dns::amneziaDnsIp);
|
||||
sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns1).toString());
|
||||
sitesJsonArray.append(m_vpnConfiguration.value(config_key::dns2).toString());
|
||||
}
|
||||
|
||||
m_vpnConfiguration.insert(config_key::splitTunnelType, routeMode);
|
||||
|
|
|
@ -79,8 +79,6 @@ signals:
|
|||
|
||||
void serviceIsNotReady();
|
||||
|
||||
void newVpnConfigurationCreated();
|
||||
|
||||
protected slots:
|
||||
void onBytesChanged(quint64 receivedBytes, quint64 sentBytes);
|
||||
void onConnectionStateChanged(Vpn::ConnectionState state);
|
||||
|
|
|
@ -76,9 +76,7 @@ function raiseInstallerWindow()
|
|||
function appProcessIsRunning()
|
||||
{
|
||||
if (runningOnWindows()) {
|
||||
var cmdArgs = ["/FI", "WINDOWTITLE eq " + appName()];
|
||||
var result = installer.execute("tasklist", cmdArgs);
|
||||
|
||||
var result = installer.execute("tasklist");
|
||||
if ( Number(result[1]) === 0 ) {
|
||||
if (result[0].indexOf(appExecutableFileName()) !== -1) {
|
||||
return true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue