mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-28 13:07:44 +03:00
Compare commits
30 Commits
cryptpad-s
...
feature/li
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4205bb1d31 | ||
|
|
5570cb94b5 | ||
|
|
45323e67fb | ||
|
|
ae3ed9c741 | ||
|
|
f47e4cb729 | ||
|
|
b5cbcc5f2a | ||
|
|
f18d980bdb | ||
|
|
81cfab3566 | ||
|
|
7f123dabac | ||
|
|
de0b400934 | ||
|
|
dcde24649f | ||
|
|
b717560047 | ||
|
|
afd2542a11 | ||
|
|
1438a21902 | ||
|
|
4147632a62 | ||
|
|
948ab4cf71 | ||
|
|
f54308e4f4 | ||
|
|
052261c2b4 | ||
|
|
3cec0dc2a7 | ||
|
|
ad61ef0b22 | ||
|
|
63c569c3d2 | ||
|
|
30df4c6800 | ||
|
|
a96f9dc18a | ||
|
|
fb63cdf7e9 | ||
|
|
2d3b9c2752 | ||
|
|
09c58cb39e | ||
|
|
654d219e7e | ||
|
|
89d4c18e87 | ||
|
|
b0b185027e | ||
|
|
90912f9231 |
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
set(AMNEZIAVPN_VERSION 4.8.10.0)
|
||||
set(AMNEZIAVPN_VERSION 4.8.9.2)
|
||||
|
||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
@@ -12,7 +12,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(APP_ANDROID_VERSION_CODE 2093)
|
||||
set(APP_ANDROID_VERSION_CODE 2092)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
|
||||
@@ -174,6 +174,15 @@ endif()
|
||||
if(LINUX AND NOT ANDROID)
|
||||
set(LIBS ${LIBS} -static-libstdc++ -static-libgcc -ldl)
|
||||
link_directories(${CMAKE_CURRENT_LIST_DIR}/platforms/linux)
|
||||
|
||||
set(HEADERS ${HEADERS}
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_linux.h
|
||||
)
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/protocols/ikev2_vpn_protocol_linux.cpp
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS AND NOT MACOS_NE) OR (LINUX AND NOT ANDROID))
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
#include <QtQuick/QQuickWindow> // for QQuickWindow
|
||||
#include <QWindow> // for qobject_cast<QWindow*>
|
||||
|
||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv),
|
||||
m_optAutostart({QStringLiteral("a"), QStringLiteral("autostart")}, QStringLiteral("System autostart")),
|
||||
m_optCleanup ({QStringLiteral("c"), QStringLiteral("cleanup")}, QStringLiteral("Cleanup logs"))
|
||||
AmneziaApplication::AmneziaApplication(int &argc, char *argv[]) : AMNEZIA_BASE_CLASS(argc, argv)
|
||||
{
|
||||
setQuitOnLastWindowClosed(false);
|
||||
|
||||
@@ -121,7 +119,7 @@ void AmneziaApplication::init()
|
||||
Logger::setServiceLogsEnabled(enabled);
|
||||
|
||||
#ifdef Q_OS_WIN //TODO
|
||||
if (m_parser.isSet(m_optAutostart))
|
||||
if (m_parser.isSet("a"))
|
||||
m_coreController->pageController()->showOnStartup();
|
||||
else
|
||||
emit m_coreController->pageController()->raiseMainWindow();
|
||||
@@ -189,12 +187,15 @@ bool AmneziaApplication::parseCommands()
|
||||
m_parser.addHelpOption();
|
||||
m_parser.addVersionOption();
|
||||
|
||||
m_parser.addOption(m_optAutostart);
|
||||
m_parser.addOption(m_optCleanup);
|
||||
QCommandLineOption c_autostart { { "a", "autostart" }, "System autostart" };
|
||||
m_parser.addOption(c_autostart);
|
||||
|
||||
QCommandLineOption c_cleanup { { "c", "cleanup" }, "Cleanup logs" };
|
||||
m_parser.addOption(c_cleanup);
|
||||
|
||||
m_parser.process(*this);
|
||||
|
||||
if (m_parser.isSet(m_optCleanup)) {
|
||||
if (m_parser.isSet(c_cleanup)) {
|
||||
Logger::cleanUp();
|
||||
QTimer::singleShot(100, this, [this] { quit(); });
|
||||
exec();
|
||||
|
||||
@@ -56,9 +56,6 @@ private:
|
||||
|
||||
QCommandLineParser m_parser;
|
||||
|
||||
QCommandLineOption m_optAutostart;
|
||||
QCommandLineOption m_optCleanup;
|
||||
|
||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||
QThread m_vpnConnectionThread;
|
||||
|
||||
|
||||
@@ -64,6 +64,26 @@ QString Ikev2Configurator::createConfig(const ServerCredentials &credentials, Do
|
||||
return "";
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
QString config = m_serverController->replaceVars(amnezia::scriptData(ProtocolScriptType::ipsec_template, container),
|
||||
m_serverController->genVarsForScript(credentials, container, containerConfig));
|
||||
|
||||
config.replace("$CLIENT_NAME", connData.clientId);
|
||||
config.replace("$UUID1", QUuid::createUuid().toString());
|
||||
config.replace("$SERVER_ADDR", connData.host);
|
||||
|
||||
QJsonObject jConfig;
|
||||
jConfig[config_key::config] = config;
|
||||
|
||||
jConfig[config_key::hostName] = connData.host;
|
||||
jConfig[config_key::userName] = connData.clientId;
|
||||
jConfig[config_key::cert] = QString(connData.clientCert.toBase64());
|
||||
jConfig[config_key::cacert] = QString(connData.caCert);
|
||||
jConfig[config_key::password] = connData.password;
|
||||
|
||||
return QJsonDocument(jConfig).toJson();
|
||||
#endif
|
||||
|
||||
return genIkev2Config(connData);
|
||||
}
|
||||
|
||||
@@ -73,6 +93,7 @@ QString Ikev2Configurator::genIkev2Config(const ConnectionData &connData)
|
||||
config[config_key::hostName] = connData.host;
|
||||
config[config_key::userName] = connData.clientId;
|
||||
config[config_key::cert] = QString(connData.clientCert.toBase64());
|
||||
config[config_key::cacert] = QString(connData.caCert);
|
||||
config[config_key::password] = connData.password;
|
||||
|
||||
return QJsonDocument(config).toJson();
|
||||
@@ -115,3 +136,22 @@ QString Ikev2Configurator::genStrongSwanConfig(const ConnectionData &connData)
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
QString Ikev2Configurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||
QString &protocolConfigString)
|
||||
{
|
||||
processConfigWithDnsSettings(dns, protocolConfigString);
|
||||
|
||||
QJsonObject json;
|
||||
json[config_key::config] = protocolConfigString;
|
||||
return QJsonDocument(json).toJson();
|
||||
}
|
||||
|
||||
QString Ikev2Configurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||
QString &protocolConfigString)
|
||||
{
|
||||
processConfigWithDnsSettings(dns, protocolConfigString);
|
||||
QJsonObject json;
|
||||
json[config_key::config] = protocolConfigString;
|
||||
return QJsonDocument(json).toJson();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ public:
|
||||
QString genIkev2Config(const ConnectionData &connData);
|
||||
QString genMobileConfig(const ConnectionData &connData);
|
||||
QString genStrongSwanConfig(const ConnectionData &connData);
|
||||
QString genIPSecConfig(const ConnectionData &connData);
|
||||
|
||||
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString);
|
||||
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString);
|
||||
|
||||
ConnectionData prepareIkev2Config(const ServerCredentials &credentials,
|
||||
DockerContainer container, ErrorCode &errorCode);
|
||||
|
||||
@@ -257,7 +257,7 @@ Proto ContainerProps::defaultProtocol(DockerContainer c)
|
||||
|
||||
bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX)
|
||||
return true;
|
||||
|
||||
#elif defined(Q_OS_IOS)
|
||||
@@ -306,13 +306,6 @@ bool ContainerProps::isSupportedByCurrentPlatform(DockerContainer c)
|
||||
case DockerContainer::SSXray: return true;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_LINUX)
|
||||
switch (c) {
|
||||
case DockerContainer::Ipsec: return false;
|
||||
default: return true;
|
||||
}
|
||||
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace
|
||||
|
||||
bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
|
||||
{
|
||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QDateTime endDate = QDateTime::fromString(subscriptionEndDate, Qt::ISODateWithMs);
|
||||
return endDate < now;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ void CoreController::initSignalHandlers()
|
||||
|
||||
void CoreController::initNotificationHandler()
|
||||
{
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#ifndef Q_OS_ANDROID
|
||||
m_notificationHandler.reset(NotificationHandler::create(nullptr));
|
||||
|
||||
connect(m_vpnConnection.get(), &VpnConnection::connectionStateChanged, m_notificationHandler.get(),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <QQmlContext>
|
||||
#include <QThread>
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include "ui/systemtray_notificationhandler.h"
|
||||
#endif
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
#include "ui/models/services/socks5ProxyConfigModel.h"
|
||||
#include "ui/models/sites_model.h"
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include "ui/notificationhandler.h"
|
||||
#endif
|
||||
|
||||
@@ -97,7 +97,7 @@ private:
|
||||
QSharedPointer<VpnConnection> m_vpnConnection;
|
||||
QSharedPointer<QTranslator> m_translator;
|
||||
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
#ifndef Q_OS_ANDROID
|
||||
QScopedPointer<NotificationHandler> m_notificationHandler;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -60,9 +60,8 @@ ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBo
|
||||
QNetworkRequest request;
|
||||
request.setTransferTimeout(m_requestTimeoutMsecs);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader(QString("X-Client-Request-ID").toUtf8(), QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8());
|
||||
|
||||
request.setUrl(QString(endpoint).arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl));
|
||||
request.setUrl(QString(endpoint).arg(m_gatewayEndpoint));
|
||||
|
||||
// bypass killSwitch exceptions for API-gateway
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
@@ -123,9 +122,8 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api
|
||||
QNetworkRequest request;
|
||||
request.setTransferTimeout(m_requestTimeoutMsecs);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader(QString("X-Client-Request-ID").toUtf8(), QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8());
|
||||
|
||||
request.setUrl(endpoint.arg(m_proxyUrl.isEmpty() ? m_gatewayEndpoint : m_proxyUrl));
|
||||
request.setUrl(endpoint.arg(m_gatewayEndpoint));
|
||||
|
||||
// bypass killSwitch exceptions for API-gateway
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
@@ -346,14 +344,11 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl
|
||||
std::mt19937 generator(randomDevice());
|
||||
std::shuffle(proxyUrls.begin(), proxyUrls.end(), generator);
|
||||
|
||||
QEventLoop wait;
|
||||
QList<QSslError> sslErrors;
|
||||
QByteArray responseBody;
|
||||
|
||||
auto bypassFunction = [this](const QString &endpoint, const QString &proxyUrl, QNetworkReply *reply,
|
||||
std::function<QNetworkReply *(const QString &url)> requestFunction,
|
||||
std::function<bool(QNetworkReply * reply, const QList<QSslError> &sslErrors)> replyProcessingFunction) {
|
||||
QEventLoop wait;
|
||||
QList<QSslError> sslErrors;
|
||||
|
||||
for (const QString &proxyUrl : proxyUrls) {
|
||||
qDebug() << "go to the next proxy endpoint";
|
||||
reply->deleteLater(); // delete the previous reply
|
||||
reply = requestFunction(endpoint.arg(proxyUrl));
|
||||
@@ -363,50 +358,6 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl
|
||||
wait.exec();
|
||||
|
||||
if (replyProcessingFunction(reply, sslErrors)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (m_proxyUrl.isEmpty()) {
|
||||
QNetworkRequest request;
|
||||
request.setTransferTimeout(1000);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QEventLoop wait;
|
||||
QList<QSslError> sslErrors;
|
||||
QNetworkReply *reply;
|
||||
|
||||
for (const QString &proxyUrl : proxyUrls) {
|
||||
request.setUrl(proxyUrl + "lmbd-health");
|
||||
reply = amnApp->networkManager()->get(request);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||
wait.exec();
|
||||
|
||||
if (reply->error() == QNetworkReply::NetworkError::NoError) {
|
||||
reply->deleteLater();
|
||||
|
||||
m_proxyUrl = proxyUrl;
|
||||
if (!m_proxyUrl.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_proxyUrl.isEmpty()) {
|
||||
if (bypassFunction(endpoint, m_proxyUrl, reply, requestFunction, replyProcessingFunction)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &proxyUrl : proxyUrls) {
|
||||
if (bypassFunction(endpoint, proxyUrl, reply, requestFunction, replyProcessingFunction)) {
|
||||
m_proxyUrl = proxyUrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ private:
|
||||
QString m_gatewayEndpoint;
|
||||
bool m_isDevEnvironment = false;
|
||||
bool m_isStrictKillSwitchEnabled = false;
|
||||
|
||||
inline static QString m_proxyUrl;
|
||||
};
|
||||
|
||||
#endif // GATEWAYCONTROLLER_H
|
||||
|
||||
@@ -120,7 +120,6 @@ namespace amnezia
|
||||
ApiNotFoundError = 1109,
|
||||
ApiMigrationError = 1110,
|
||||
ApiUpdateRequestError = 1111,
|
||||
ApiSubscriptionExpiredError = 1112,
|
||||
|
||||
// QFile errors
|
||||
OpenError = 1200,
|
||||
|
||||
@@ -77,7 +77,6 @@ QString errorString(ErrorCode code) {
|
||||
case (ErrorCode::ApiNotFoundError): errorMessage = QObject::tr("Error when retrieving configuration from API"); break;
|
||||
case (ErrorCode::ApiMigrationError): errorMessage = QObject::tr("A migration error has occurred. Please contact our technical support"); break;
|
||||
case (ErrorCode::ApiUpdateRequestError): errorMessage = QObject::tr("Please update the application to use this feature"); break;
|
||||
case (ErrorCode::ApiSubscriptionExpiredError): errorMessage = QObject::tr("Your Amnezia Premium subscription has expired.\n Please check your email for renewal instructions.\n If you haven't received an email, please contact our support."); break;
|
||||
|
||||
// QFile errors
|
||||
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
|
||||
|
||||
@@ -50,6 +50,7 @@ QString amnezia::scriptName(ProtocolScriptType type)
|
||||
case ProtocolScriptType::wireguard_template: return QLatin1String("template.conf");
|
||||
case ProtocolScriptType::awg_template: return QLatin1String("template.conf");
|
||||
case ProtocolScriptType::xray_template: return QLatin1String("template.json");
|
||||
case ProtocolScriptType::ipsec_template: return QLatin1String("template.conf");
|
||||
default: return QString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ enum ProtocolScriptType {
|
||||
openvpn_template,
|
||||
wireguard_template,
|
||||
awg_template,
|
||||
xray_template
|
||||
xray_template,
|
||||
ipsec_template
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -101,10 +101,10 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||
out << "MTU = " << m_deviceMTU << "\n";
|
||||
}
|
||||
|
||||
if (!m_primaryDnsServer.isEmpty()) {
|
||||
if (!m_primaryDnsServer.isNull()) {
|
||||
QStringList dnsServers;
|
||||
dnsServers.append(m_primaryDnsServer);
|
||||
if (!m_secondaryDnsServer.isEmpty()) {
|
||||
if (!m_secondaryDnsServer.isNull()) {
|
||||
dnsServers.append(m_secondaryDnsServer);
|
||||
}
|
||||
// If the DNS is not the Gateway, it's a user defined DNS
|
||||
|
||||
185
client/protocols/ikev2_vpn_protocol_linux.cpp
Normal file
185
client/protocols/ikev2_vpn_protocol_linux.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
|
||||
#include <QNetworkInterface>
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
#include "settings.h"
|
||||
#include "logger.h"
|
||||
#include "ikev2_vpn_protocol_linux.h"
|
||||
#include "utilities.h"
|
||||
#include "core/ipcclient.h"
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
|
||||
static Ikev2Protocol* self = nullptr;
|
||||
|
||||
|
||||
Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent) :
|
||||
VpnProtocol(configuration, parent)
|
||||
{
|
||||
qDebug() << "IpsecProtocol::Ikev2Protocol()";
|
||||
self = this;
|
||||
readIkev2Configuration(configuration);
|
||||
m_routeGateway = NetworkUtilities::getGatewayAndIface();
|
||||
m_vpnGateway = "192.168.43.10";
|
||||
m_vpnLocalAddress = "192.168.43.10";
|
||||
m_remoteAddress = NetworkUtilities::getIPAddress(configuration.value(amnezia::config_key::hostName).toString());
|
||||
m_routeMode = static_cast<Settings::RouteMode>(configuration.value(amnezia::config_key::splitTunnelType).toInt());
|
||||
m_configData = configuration;
|
||||
}
|
||||
|
||||
Ikev2Protocol::~Ikev2Protocol()
|
||||
{
|
||||
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||
Ikev2Protocol::stop();
|
||||
}
|
||||
|
||||
void Ikev2Protocol::stop()
|
||||
{
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
Ikev2Protocol::disconnect_vpn();
|
||||
qDebug() << "IpsecProtocol::stop()";
|
||||
}
|
||||
|
||||
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||
{
|
||||
qDebug() << "IpsecProtocol::readIkev2Configuration()";
|
||||
QJsonObject ikev2_data = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||
m_config = QJsonDocument::fromJson(ikev2_data.value(config_key::config).toString().toUtf8()).object();
|
||||
}
|
||||
|
||||
ErrorCode Ikev2Protocol::start()
|
||||
{
|
||||
qDebug() << "IpsecProtocol::start()";
|
||||
STACK_OF(X509) *certstack = sk_X509_new_null();
|
||||
BIO *p12 = BIO_new(BIO_s_mem());
|
||||
|
||||
EVP_PKEY *pkey;
|
||||
X509 *cert;
|
||||
|
||||
BIO_write(p12, QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()),
|
||||
QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8()).size());
|
||||
|
||||
PKCS12 *pkcs12 = d2i_PKCS12_bio(p12, NULL);
|
||||
PKCS12_parse(pkcs12, m_config[config_key::password].toString().toStdString().c_str(), &pkey, &cert, &certstack);
|
||||
BIO *bio = BIO_new(BIO_s_mem());
|
||||
PEM_write_bio_X509(bio, cert);
|
||||
|
||||
BUF_MEM *mem = NULL;
|
||||
BIO_get_mem_ptr(bio, &mem);
|
||||
|
||||
std::string pem(mem->data, mem->length);
|
||||
QString alias(pem.c_str());
|
||||
|
||||
IpcClient::Interface()->writeIPsecUserCert(alias, m_config[config_key::userName].toString());
|
||||
IpcClient::Interface()->writeIPsecConfig(m_config[config_key::config].toString());
|
||||
IpcClient::Interface()->writeIPsecCaCert(m_config[config_key::cacert].toString(), m_config[config_key::userName].toString());
|
||||
IpcClient::Interface()->writeIPsecPrivate(m_config[config_key::cert].toString(), m_config[config_key::userName].toString());
|
||||
IpcClient::Interface()->writeIPsecPrivatePass(m_config[config_key::password].toString(), m_config[config_key::hostName].toString(),
|
||||
m_config[config_key::userName].toString());
|
||||
|
||||
connect_to_vpn("ikev2-vpn");
|
||||
|
||||
if (!IpcClient::Interface()) {
|
||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||
}
|
||||
|
||||
QString connectionStatus;
|
||||
|
||||
auto futureResult = IpcClient::Interface()->getTunnelStatus("ikev2-vpn");
|
||||
futureResult.waitForFinished();
|
||||
|
||||
if (futureResult.returnValue().isEmpty()) {
|
||||
auto futureResult = IpcClient::Interface()->getTunnelStatus("ikev2-vpn");
|
||||
futureResult.waitForFinished();
|
||||
}
|
||||
|
||||
connectionStatus = futureResult.returnValue();
|
||||
|
||||
if (connectionStatus.contains("ESTABLISHED")) {
|
||||
QStringList lines = connectionStatus.split('\n');
|
||||
for (auto iter = lines.begin(); iter!=lines.end(); iter++)
|
||||
{
|
||||
if (iter->contains("0.0.0.0/0")) {
|
||||
QList<QHostAddress> dnsAddr;
|
||||
|
||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
||||
if (!m_configData.value(amnezia::config_key::dns1).toString().
|
||||
contains(amnezia::protocols::dns::amneziaDnsIp)) {
|
||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
||||
}
|
||||
|
||||
m_vpnGateway = iter->split("===", Qt::SkipEmptyParts).first();
|
||||
m_vpnGateway = m_vpnGateway.split(" ").at(2);
|
||||
m_vpnGateway = m_vpnGateway.split("/").first();
|
||||
m_vpnLocalAddress = m_vpnGateway;
|
||||
|
||||
// killSwitch toggle
|
||||
if (QVariant(m_config.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||
m_config.insert("vpnServer", m_remoteAddress);
|
||||
IpcClient::Interface()->enableKillSwitch(m_config, 0);
|
||||
}
|
||||
|
||||
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
|
||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "0.0.0.0/1");
|
||||
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "128.0.0.0/1");
|
||||
IpcClient::Interface()->routeAddList(m_routeGateway, QStringList() << m_remoteAddress);
|
||||
}
|
||||
|
||||
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
|
||||
for (int i = 0; i < netInterfaces.size(); i++) {
|
||||
for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++)
|
||||
{
|
||||
if (netInterfaces.at(i).addressEntries().at(j).ip().toString() == m_vpnGateway)
|
||||
{
|
||||
IpcClient::Interface()->updateResolvers(netInterfaces.at(i).humanReadableName(), dnsAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcClient::Interface()->StopRoutingIpv6();
|
||||
}
|
||||
}
|
||||
setConnectionState(Vpn::ConnectionState::Connected);
|
||||
} else {
|
||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
||||
const QString & serv_addr) {
|
||||
qDebug() << "Ikev2Protocol::create_new_vpn()";
|
||||
return true;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
bool Ikev2Protocol::delete_vpn_connection(const QString &vpn_name) {
|
||||
|
||||
return false;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
bool Ikev2Protocol::connect_to_vpn(const QString &vpn_name) {
|
||||
qDebug() << "IpsecProtocol::connect_to_vpn()";
|
||||
IpcClient::Interface()->startIPsec(vpn_name);
|
||||
QThread::msleep(3000);
|
||||
return true;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
bool Ikev2Protocol::disconnect_vpn() {
|
||||
qDebug() << "IpsecProtocol::disconnect_vpn()";
|
||||
IpcClient::Interface()->stopIPsec("ikev2-vpn");
|
||||
IpcClient::Interface()->disableKillSwitch();
|
||||
IpcClient::Interface()->StartRoutingIpv6();
|
||||
return true;
|
||||
}
|
||||
52
client/protocols/ikev2_vpn_protocol_linux.h
Normal file
52
client/protocols/ikev2_vpn_protocol_linux.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef IKEV2_VPN_PROTOCOL_LINUX_H
|
||||
#define IKEV2_VPN_PROTOCOL_LINUX_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTimer>
|
||||
|
||||
#include "vpnprotocol.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
class Ikev2Protocol : public VpnProtocol
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Ikev2Protocol(const QJsonObject& configuration, QObject* parent = nullptr);
|
||||
virtual ~Ikev2Protocol() override;
|
||||
|
||||
ErrorCode start() override;
|
||||
void stop() override;
|
||||
|
||||
static QString tunnelName() { return "AmneziaVPN IKEv2"; }
|
||||
|
||||
|
||||
private:
|
||||
void readIkev2Configuration(const QJsonObject &configuration);
|
||||
|
||||
private:
|
||||
QJsonObject m_config;
|
||||
QJsonObject m_configData;
|
||||
QString m_remoteAddress;
|
||||
int m_routeMode;
|
||||
|
||||
|
||||
bool create_new_vpn(const QString & vpn_name,
|
||||
const QString & serv_addr);
|
||||
bool delete_vpn_connection(const QString &vpn_name);
|
||||
|
||||
bool connect_to_vpn(const QString & vpn_name);
|
||||
bool disconnect_vpn();
|
||||
};
|
||||
|
||||
|
||||
#endif // IKEV2_VPN_PROTOCOL_LINUX_H
|
||||
@@ -30,6 +30,7 @@ Ikev2Protocol::Ikev2Protocol(const QJsonObject &configuration, QObject* parent)
|
||||
Ikev2Protocol::~Ikev2Protocol()
|
||||
{
|
||||
qDebug() << "IpsecProtocol::~IpsecProtocol()";
|
||||
disconnect_vpn();
|
||||
Ikev2Protocol::stop();
|
||||
}
|
||||
|
||||
@@ -37,7 +38,7 @@ void Ikev2Protocol::stop()
|
||||
{
|
||||
setConnectionState(Vpn::ConnectionState::Disconnecting);
|
||||
{
|
||||
if (!disconnect_vpn()){
|
||||
if (! disconnect_vpn() ){
|
||||
qDebug()<<"We don't disconnect";
|
||||
setConnectionState(Vpn::ConnectionState::Error);
|
||||
}
|
||||
@@ -171,7 +172,8 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
|
||||
|
||||
void Ikev2Protocol::readIkev2Configuration(const QJsonObject &configuration)
|
||||
{
|
||||
m_config = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||
QJsonObject ikev2_data = configuration.value(ProtocolProps::key_proto_config_data(Proto::Ikev2)).toObject();
|
||||
m_config = QJsonDocument::fromJson(ikev2_data.value(config_key::config).toString().toUtf8()).object();
|
||||
}
|
||||
|
||||
ErrorCode Ikev2Protocol::start()
|
||||
@@ -310,9 +312,7 @@ bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
bool Ikev2Protocol::disconnect_vpn(){
|
||||
if ( hRasConn != nullptr ){
|
||||
auto ret = RasHangUp(hRasConn);
|
||||
qDebug() << "RasHangUp " << ret;
|
||||
if (ret != ERROR_SUCCESS)
|
||||
if ( RasHangUp(hRasConn) != ERROR_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
QThread::msleep(3000);
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace amnezia
|
||||
constexpr char description[] = "description";
|
||||
constexpr char name[] = "name";
|
||||
constexpr char cert[] = "cert";
|
||||
constexpr char cacert[] = "cacert";
|
||||
constexpr char config[] = "config";
|
||||
|
||||
constexpr char containers[] = "containers";
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#include "ikev2_vpn_protocol_windows.h"
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include "ikev2_vpn_protocol_linux.h"
|
||||
#endif
|
||||
|
||||
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_connectionState(Vpn::ConnectionState::Unknown),
|
||||
@@ -106,7 +110,7 @@ QString VpnProtocol::vpnGateway() const
|
||||
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
|
||||
{
|
||||
switch (container) {
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
case DockerContainer::Ipsec: return new Ikev2Protocol(configuration);
|
||||
#endif
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_MACX) and !defined MACOS_NE || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<file>server_scripts/ipsec/mobileconfig.plist</file>
|
||||
<file>server_scripts/ipsec/run_container.sh</file>
|
||||
<file>server_scripts/ipsec/start.sh</file>
|
||||
<file>server_scripts/ipsec/template.conf</file>
|
||||
<file>server_scripts/ipsec/strongswan.profile</file>
|
||||
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/Dockerfile</file>
|
||||
|
||||
@@ -242,6 +242,7 @@ conn ikev2-cp
|
||||
dpdtimeout=120
|
||||
dpdaction=clear
|
||||
auto=add
|
||||
authby=rsa-sha1
|
||||
ikev2=insist
|
||||
rekey=no
|
||||
pfs=yes
|
||||
|
||||
28
client/server_scripts/ipsec/template.conf
Normal file
28
client/server_scripts/ipsec/template.conf
Normal file
@@ -0,0 +1,28 @@
|
||||
config setup
|
||||
charondebug="ike 1, knl 1, cfg 0"
|
||||
uniqueids=no
|
||||
|
||||
conn ikev2-vpn
|
||||
auto=add
|
||||
type=tunnel
|
||||
keyexchange=ikev2
|
||||
fragmentation=yes
|
||||
forceencaps=yes
|
||||
dpdaction=clear
|
||||
dpddelay=300s
|
||||
rekey=no
|
||||
leftid=$CLIENT_NAME
|
||||
leftcert=$CLIENT_NAME.crt
|
||||
leftdns=$PRIMARY_DNS,$SECONDARY_DNS
|
||||
leftsendcert=always
|
||||
leftsourceip=%config
|
||||
right=$SERVER_IP_ADDRESS
|
||||
rightsubnet=0.0.0.0/0
|
||||
rightsendcert=never
|
||||
eap_identity=%identity
|
||||
encapsulation=yes
|
||||
pfs=yes
|
||||
ike=aes256-sha256-modp2048,aes256-sha1-modp1024,3des-sha1-modp1024
|
||||
esp=aes256-sha256,aes256-sha1,3des-sha1
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,6 @@ namespace
|
||||
constexpr char uuid[] = "installation_uuid";
|
||||
constexpr char osVersion[] = "os_version";
|
||||
constexpr char appVersion[] = "app_version";
|
||||
constexpr char appLanguage[] = "app_language";
|
||||
|
||||
constexpr char userCountryCode[] = "user_country_code";
|
||||
constexpr char serverCountryCode[] = "server_country_code";
|
||||
@@ -44,9 +43,6 @@ namespace
|
||||
constexpr char authData[] = "auth_data";
|
||||
|
||||
constexpr char config[] = "config";
|
||||
|
||||
constexpr char subscription[] = "subscription";
|
||||
constexpr char endDate[] = "end_date";
|
||||
}
|
||||
|
||||
struct ProtocolData
|
||||
@@ -167,7 +163,7 @@ namespace
|
||||
auto clientProtocolConfig =
|
||||
QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
|
||||
|
||||
// TODO looks like this block can be removed after v1 configs EOL
|
||||
//TODO looks like this block can be removed after v1 configs EOL
|
||||
|
||||
serverProtocolConfig[config_key::junkPacketCount] = clientProtocolConfig.value(config_key::junkPacketCount);
|
||||
serverProtocolConfig[config_key::junkPacketMinSize] = clientProtocolConfig.value(config_key::junkPacketMinSize);
|
||||
@@ -227,19 +223,6 @@ namespace
|
||||
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
bool isSubscriptionExpired(const QJsonObject &apiConfig)
|
||||
{
|
||||
auto subscription = apiConfig.value(configKey::subscription).toObject();
|
||||
if (subscription.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
auto subscriptionEndDate = subscription.value(configKey::endDate).toString();
|
||||
if (apiUtils::isSubscriptionExpired(subscriptionEndDate)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &serversModel,
|
||||
@@ -259,11 +242,6 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
if (isSubscriptionExpired(apiConfigObject)) {
|
||||
emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError);
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
@@ -299,11 +277,6 @@ bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
if (isSubscriptionExpired(apiConfigObject)) {
|
||||
emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError);
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
@@ -349,7 +322,6 @@ bool ApiConfigsController::fillAvailableServices()
|
||||
{
|
||||
QJsonObject apiPayload;
|
||||
apiPayload[configKey::osVersion] = QSysInfo::productType();
|
||||
apiPayload[configKey::appLanguage] = m_settings->getAppLanguage().name().split("_").first();
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody);
|
||||
@@ -424,11 +396,6 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
|
||||
if (isSubscriptionExpired(apiConfig)) {
|
||||
emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError);
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
@@ -462,7 +429,6 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||
|
||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||
newServerConfig.insert(configKey::authData, gatewayRequestData.authData);
|
||||
newServerConfig.insert(config_key::crc, serverConfig.value(config_key::crc));
|
||||
|
||||
if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) {
|
||||
newServerConfig.insert(config_key::name, serverConfig.value(config_key::name));
|
||||
@@ -536,11 +502,6 @@ bool ApiConfigsController::deactivateDevice()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isSubscriptionExpired(apiConfigObject)) {
|
||||
emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError);
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
@@ -575,11 +536,6 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isSubscriptionExpired(apiConfigObject)) {
|
||||
emit errorOccurred(ErrorCode::ApiSubscriptionExpiredError);
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
uuid,
|
||||
|
||||
@@ -297,11 +297,10 @@ void ExportController::revokeConfig(const int row, const DockerContainer contain
|
||||
{
|
||||
QSharedPointer<ServerController> serverController(new ServerController(m_settings));
|
||||
ErrorCode errorCode =
|
||||
m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex(), serverController);
|
||||
m_clientManagementModel->revokeClient(row, container, credentials, m_serversModel->getProcessedServerIndex(), serverController);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit exportErrorOccurred(errorCode);
|
||||
}
|
||||
emit revokeConfigCompleted();
|
||||
}
|
||||
|
||||
void ExportController::renameClient(const int row, const QString &clientName, const DockerContainer container, ServerCredentials credentials)
|
||||
|
||||
@@ -42,7 +42,6 @@ public slots:
|
||||
|
||||
signals:
|
||||
void generateConfig(int type);
|
||||
void revokeConfigCompleted();
|
||||
void exportErrorOccurred(const QString &errorMessage);
|
||||
void exportErrorOccurred(ErrorCode errorCode);
|
||||
|
||||
|
||||
@@ -112,7 +112,6 @@ void ListViewFocusController::previousDelegate()
|
||||
case Section::Default: {
|
||||
if (hasFooter()) {
|
||||
m_currentSection = Section::Footer;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
@@ -128,11 +127,9 @@ void ListViewFocusController::previousDelegate()
|
||||
case Section::Delegate: {
|
||||
if (m_delegateIndex > 0) {
|
||||
setDelegateIndex(m_delegateIndex - 1);
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
} else if (hasHeader()) {
|
||||
m_currentSection = Section::Header;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
@@ -140,7 +137,6 @@ void ListViewFocusController::previousDelegate()
|
||||
case Section::Header: {
|
||||
m_isReturnNeeded = true;
|
||||
m_currentSection = Section::Default;
|
||||
viewAtCurrentIndex();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -279,7 +275,7 @@ bool ListViewFocusController::isFirstFocusItemInListView() const
|
||||
return isFirstFocusItemInDelegate() && (m_delegateIndex == 0) && !hasHeader();
|
||||
}
|
||||
case Section::Header: {
|
||||
return isFirstFocusItemInDelegate();
|
||||
isFirstFocusItemInDelegate();
|
||||
}
|
||||
case Section::Default: {
|
||||
return true;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace PageLoader
|
||||
PageSettingsApiDevices,
|
||||
PageSettingsApiSubscriptionKey,
|
||||
PageSettingsKillSwitchExceptions,
|
||||
|
||||
|
||||
PageServiceSftpSettings,
|
||||
PageServiceTorWebsiteSettings,
|
||||
PageServiceDnsSettings,
|
||||
@@ -125,8 +125,6 @@ signals:
|
||||
void goToPageViewConfig();
|
||||
void goToPageSettingsServerServices();
|
||||
void goToPageSettingsBackup();
|
||||
void goToShareConnectionPage(QString headerText, QString configContentHeaderText, QString configCaption, QString configExtension,
|
||||
QString configFileName);
|
||||
|
||||
void closePage();
|
||||
|
||||
|
||||
@@ -264,9 +264,6 @@ bool SettingsController::isAutoStartEnabled()
|
||||
void SettingsController::toggleAutoStart(bool enable)
|
||||
{
|
||||
Autostart::setAutostart(enable);
|
||||
if (!enable) {
|
||||
toggleStartMinimized(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsController::isStartMinimizedEnabled()
|
||||
@@ -277,7 +274,6 @@ bool SettingsController::isStartMinimizedEnabled()
|
||||
void SettingsController::toggleStartMinimized(bool enable)
|
||||
{
|
||||
m_settings->setStartMinimized(enable);
|
||||
emit startMinimizedChanged();
|
||||
}
|
||||
|
||||
bool SettingsController::isScreenshotsEnabled()
|
||||
|
||||
@@ -32,7 +32,6 @@ public:
|
||||
Q_PROPERTY(bool isDevGatewayEnv READ isDevGatewayEnv WRITE toggleDevGatewayEnv NOTIFY devGatewayEnvChanged)
|
||||
|
||||
Q_PROPERTY(bool isHomeAdLabelVisible READ isHomeAdLabelVisible NOTIFY isHomeAdLabelVisibleChanged)
|
||||
Q_PROPERTY(bool startMinimized READ isStartMinimizedEnabled NOTIFY startMinimizedChanged)
|
||||
|
||||
public slots:
|
||||
void toggleAmneziaDns(bool enable);
|
||||
@@ -126,7 +125,6 @@ signals:
|
||||
void devGatewayEnvChanged(bool enabled);
|
||||
|
||||
void isHomeAdLabelVisibleChanged(bool visible);
|
||||
void startMinimizedChanged();
|
||||
|
||||
private:
|
||||
QSharedPointer<ServersModel> m_serversModel;
|
||||
|
||||
@@ -31,7 +31,7 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
|
||||
return tr("Active");
|
||||
}
|
||||
|
||||
return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("<p><a style=\"color: #EB5757;\">Inactive</a>") : tr("Active");
|
||||
return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("Inactive") : tr("Active");
|
||||
}
|
||||
case EndDateRole: {
|
||||
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
constexpr char serviceType[] = "service_type";
|
||||
constexpr char serviceProtocol[] = "service_protocol";
|
||||
constexpr char serviceDescription[] = "service_description";
|
||||
|
||||
constexpr char name[] = "name";
|
||||
constexpr char price[] = "price";
|
||||
@@ -23,10 +22,6 @@ namespace
|
||||
constexpr char timelimit[] = "timelimit";
|
||||
constexpr char region[] = "region";
|
||||
|
||||
constexpr char description[] = "description";
|
||||
constexpr char cardDescription[] = "card_description";
|
||||
constexpr char features[] = "features";
|
||||
|
||||
constexpr char availableCountries[] = "available_countries";
|
||||
|
||||
constexpr char storeEndpoint[] = "store_endpoint";
|
||||
@@ -70,9 +65,11 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
case CardDescriptionRole: {
|
||||
auto speed = apiServiceData.serviceInfo.speed;
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return apiServiceData.serviceInfo.cardDescription.arg(speed);
|
||||
return tr("Amnezia Premium is classic VPN for seamless work, downloading large files, and watching videos. "
|
||||
"Access all websites and online resources. Speeds up to %1 Mbps.")
|
||||
.arg(speed);
|
||||
} else if (serviceType == serviceType::amneziaFree) {
|
||||
QString description = apiServiceData.serviceInfo.cardDescription;
|
||||
QString description = tr("Amnezia Free provides unlimited, free access to a basic set of websites and apps, including Facebook, Instagram, Twitter (X), Discord, Telegram, and more. YouTube is not included in the free plan.");
|
||||
if (!isServiceAvailable) {
|
||||
description += tr("<p><a style=\"color: #EB5757;\">Not available in your region. If you have VPN enabled, disable it, "
|
||||
"return to the previous screen, and try again.</a>");
|
||||
@@ -81,7 +78,12 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
}
|
||||
case ServiceDescriptionRole: {
|
||||
return apiServiceData.serviceInfo.description;
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return tr("Amnezia Premium is classic VPN for for seamless work, downloading large files, and watching videos. "
|
||||
"Access all websites and online resources.");
|
||||
} else {
|
||||
return tr("Amnezia Free provides unlimited, free access to a basic set of websites and apps, including Facebook, Instagram, Twitter (X), Discord, Telegram, and more. YouTube is not included in the free plan.");
|
||||
}
|
||||
}
|
||||
case IsServiceAvailableRole: {
|
||||
if (serviceType == serviceType::amneziaFree) {
|
||||
@@ -105,7 +107,13 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
return apiServiceData.serviceInfo.region;
|
||||
}
|
||||
case FeaturesRole: {
|
||||
return apiServiceData.serviceInfo.features;
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return tr("");
|
||||
} else {
|
||||
return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. "
|
||||
"Other sites will be opened from your real IP address, "
|
||||
"<a href=\"%1\" style=\"color: #FBB26A;\">more details on the website.</a>");
|
||||
}
|
||||
}
|
||||
case PriceRole: {
|
||||
auto price = apiServiceData.serviceInfo.price;
|
||||
@@ -117,13 +125,6 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
case EndDateRole: {
|
||||
return QDateTime::fromString(apiServiceData.subscription.endDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
|
||||
}
|
||||
case OrderRole: {
|
||||
if (serviceType == serviceType::amneziaPremium) {
|
||||
return 0;
|
||||
} else if (serviceType == serviceType::amneziaFree) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -223,7 +224,6 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
|
||||
roles[FeaturesRole] = "features";
|
||||
roles[PriceRole] = "price";
|
||||
roles[EndDateRole] = "endDate";
|
||||
roles[OrderRole] = "order";
|
||||
|
||||
return roles;
|
||||
}
|
||||
@@ -234,7 +234,6 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs
|
||||
auto serviceType = data.value(configKey::serviceType).toString();
|
||||
auto serviceProtocol = data.value(configKey::serviceProtocol).toString();
|
||||
auto availableCountries = data.value(configKey::availableCountries).toArray();
|
||||
auto serviceDescription = data.value(configKey::serviceDescription).toObject();
|
||||
|
||||
auto subscriptionObject = data.value(configKey::subscription).toObject();
|
||||
|
||||
@@ -245,10 +244,6 @@ ApiServicesModel::ApiServicesData ApiServicesModel::getApiServicesData(const QJs
|
||||
serviceData.serviceInfo.speed = serviceInfo.value(configKey::speed).toString();
|
||||
serviceData.serviceInfo.timeLimit = serviceInfo.value(configKey::timelimit).toString();
|
||||
|
||||
serviceData.serviceInfo.cardDescription = serviceDescription.value(configKey::cardDescription).toString();
|
||||
serviceData.serviceInfo.description = serviceDescription.value(configKey::description).toString();
|
||||
serviceData.serviceInfo.features = serviceDescription.value(configKey::features).toString();
|
||||
|
||||
serviceData.type = serviceType;
|
||||
serviceData.protocol = serviceProtocol;
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ public:
|
||||
RegionRole,
|
||||
FeaturesRole,
|
||||
PriceRole,
|
||||
EndDateRole,
|
||||
OrderRole
|
||||
EndDateRole
|
||||
};
|
||||
|
||||
explicit ApiServicesModel(QObject *parent = nullptr);
|
||||
@@ -59,10 +58,6 @@ private:
|
||||
QString region;
|
||||
QString price;
|
||||
|
||||
QString description;
|
||||
QString features;
|
||||
QString cardDescription;
|
||||
|
||||
QJsonObject object;
|
||||
};
|
||||
|
||||
|
||||
@@ -497,8 +497,7 @@ ErrorCode ClientManagementModel::appendClient(const QString &clientId, const QSt
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName,
|
||||
const DockerContainer container,
|
||||
ErrorCode ClientManagementModel::renameClient(const int row, const QString &clientName, const DockerContainer container,
|
||||
const ServerCredentials &credentials,
|
||||
const QSharedPointer<ServerController> &serverController, bool addTimeStamp)
|
||||
{
|
||||
@@ -530,8 +529,7 @@ ErrorCode ClientManagementModel::renameClient(const int row, const QString &clie
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container,
|
||||
const ServerCredentials &credentials,
|
||||
ErrorCode ClientManagementModel::revokeClient(const int row, const DockerContainer container, const ServerCredentials &credentials,
|
||||
const int serverIndex, const QSharedPointer<ServerController> &serverController)
|
||||
{
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
|
||||
@@ -44,10 +44,10 @@ public slots:
|
||||
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
|
||||
ErrorCode appendClient(const QString &clientId, const QString &clientName, const DockerContainer container,
|
||||
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController);
|
||||
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container,
|
||||
const ServerCredentials &credentials, const QSharedPointer<ServerController> &serverController, bool addTimeStamp = false);
|
||||
ErrorCode revokeClient(const int index, const DockerContainer container, const ServerCredentials &credentials,
|
||||
const int serverIndex, const QSharedPointer<ServerController> &serverController);
|
||||
ErrorCode renameClient(const int row, const QString &userName, const DockerContainer container, const ServerCredentials &credentials,
|
||||
const QSharedPointer<ServerController> &serverController, bool addTimeStamp = false);
|
||||
ErrorCode revokeClient(const int index, const DockerContainer container, const ServerCredentials &credentials, const int serverIndex,
|
||||
const QSharedPointer<ServerController> &serverController);
|
||||
ErrorCode revokeClient(const QJsonObject &containerConfig, const DockerContainer container, const ServerCredentials &credentials,
|
||||
const int serverIndex, const QSharedPointer<ServerController> &serverController);
|
||||
|
||||
@@ -60,8 +60,6 @@ signals:
|
||||
private:
|
||||
bool isClientExists(const QString &clientId);
|
||||
|
||||
int clientIndexById(const QString &clientId);
|
||||
|
||||
void migration(const QByteArray &clientsTableString);
|
||||
|
||||
ErrorCode revokeOpenVpn(const int row, const DockerContainer container, const ServerCredentials &credentials, const int serverIndex,
|
||||
|
||||
@@ -191,14 +191,14 @@ QJsonObject AwgConfigModel::getConfig()
|
||||
jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount];
|
||||
jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize];
|
||||
jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize];
|
||||
jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1].toString().trimmed();
|
||||
jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2].toString().trimmed();
|
||||
jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3].toString().trimmed();
|
||||
jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4].toString().trimmed();
|
||||
jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5].toString().trimmed();
|
||||
jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1].toString().trimmed();
|
||||
jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2].toString().trimmed();
|
||||
jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3].toString().trimmed();
|
||||
jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1];
|
||||
jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2];
|
||||
jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3];
|
||||
jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4];
|
||||
jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5];
|
||||
jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1];
|
||||
jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2];
|
||||
jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3];
|
||||
jsonConfig[config_key::specialHandshakeTimeout] = m_clientProtocolConfig[config_key::specialHandshakeTimeout];
|
||||
|
||||
m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
|
||||
|
||||
@@ -73,7 +73,7 @@ DrawerType2 {
|
||||
var str = qsTr("We'll preserve all remaining days of your current subscription and give you an extra month as a thank you. ")
|
||||
str += qsTr("This new subscription type will be actively developed with more locations and features added regularly. Currently available:")
|
||||
str += "<ul style='margin-left: -16px;'>"
|
||||
str += qsTr("<li>20 locations (with more coming soon)</li>")
|
||||
str += qsTr("<li>13 locations (with more coming soon)</li>")
|
||||
str += qsTr("<li>Easier switching between countries in the app</li>")
|
||||
str += qsTr("<li>Personal dashboard to manage your subscription</li>")
|
||||
str += "</ul>"
|
||||
|
||||
@@ -7,20 +7,17 @@ import Style 1.0
|
||||
import "TextTypes"
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
|
||||
property string imageSource
|
||||
property string leftText
|
||||
property var rightText
|
||||
property bool isRightTextUndefined: rightText === undefined
|
||||
property int rightTextFormat: Text.PlainText
|
||||
|
||||
visible: !isRightTextUndefined
|
||||
|
||||
Image {
|
||||
Layout.preferredHeight: 18
|
||||
Layout.preferredWidth: 18
|
||||
source: root.imageSource
|
||||
source: imageSource
|
||||
}
|
||||
|
||||
ListItemTitleType {
|
||||
@@ -28,15 +25,14 @@ RowLayout {
|
||||
Layout.rightMargin: 10
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
text: root.leftText
|
||||
text: leftText
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
visible: root.rightText !== ""
|
||||
visible: rightText !== ""
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
text: root.isRightTextUndefined ? "" : root.rightText
|
||||
textFormat: root.rightTextFormat
|
||||
text: isRightTextUndefined ? "" : rightText
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ Switch {
|
||||
function handleSwitch(event) {
|
||||
if (!event.isAutoRepeat) {
|
||||
root.checked = !root.checked
|
||||
root.toggled()
|
||||
root.checkedChanged()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ PageType {
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.bottom: saveButton.top
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
@@ -37,7 +37,7 @@ PageType {
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
@@ -17,413 +17,427 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
contentHeight: content.implicitHeight
|
||||
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
Column {
|
||||
id: content
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
ListView {
|
||||
id: listview
|
||||
|
||||
headerText: qsTr("OpenVPN Settings")
|
||||
}
|
||||
}
|
||||
width: parent.width
|
||||
height: listview.contentItem.height
|
||||
|
||||
model: OpenVpnConfigModel
|
||||
clip: true
|
||||
interactive: false
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
model: OpenVpnConfigModel
|
||||
|
||||
spacing: 0
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: vpnAddressSubnetTextField
|
||||
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
|
||||
enabled: listView.enabled
|
||||
ColumnLayout {
|
||||
id: col
|
||||
|
||||
headerText: qsTr("VPN address subnet")
|
||||
textField.text: subnetAddress
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== subnetAddress) {
|
||||
subnetAddress = textField.text
|
||||
}
|
||||
}
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
spacing: 0
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("OpenVPN settings")
|
||||
}
|
||||
|
||||
text: qsTr("Network protocol")
|
||||
}
|
||||
TextFieldWithHeaderType {
|
||||
id: vpnAddressSubnetTextField
|
||||
|
||||
TransportProtoSelector {
|
||||
id: transportProtoSelector
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
|
||||
rootWidth: root.width
|
||||
enabled: delegateItem.isEnabled
|
||||
|
||||
enabled: isTransportProtoEditable
|
||||
headerText: qsTr("VPN address subnet")
|
||||
textField.text: subnetAddress
|
||||
|
||||
currentIndex: {
|
||||
return transportProto === "tcp" ? 1 : 0
|
||||
}
|
||||
parentFlickable: fl
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (transportProto === "tcp" && currentIndex === 0) {
|
||||
transportProto = "udp"
|
||||
} else if (transportProto === "udp" && currentIndex === 1) {
|
||||
transportProto = "tcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== subnetAddress) {
|
||||
subnetAddress = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
|
||||
enabled: listView.enabled
|
||||
text: qsTr("Network protocol")
|
||||
}
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
TransportProtoSelector {
|
||||
id: transportProtoSelector
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
rootWidth: root.width
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== port) {
|
||||
port = textField.text
|
||||
}
|
||||
}
|
||||
enabled: isTransportProtoEditable
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
currentIndex: {
|
||||
return transportProto === "tcp" ? 1 : 0
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: autoNegotiateEncryprionSwitcher
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Auto-negotiate encryption")
|
||||
checked: autoNegotiateEncryprion
|
||||
|
||||
onToggled: function() {
|
||||
if (checked !== autoNegotiateEncryprion) {
|
||||
autoNegotiateEncryprion = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: hashDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||
|
||||
descriptionText: qsTr("Hash")
|
||||
headerText: qsTr("Hash")
|
||||
|
||||
drawerParent: root
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: hashListView
|
||||
|
||||
rootWidth: root.width
|
||||
|
||||
model: ListModel {
|
||||
ListElement { name : qsTr("SHA512") }
|
||||
ListElement { name : qsTr("SHA384") }
|
||||
ListElement { name : qsTr("SHA256") }
|
||||
ListElement { name : qsTr("SHA3-512") }
|
||||
ListElement { name : qsTr("SHA3-384") }
|
||||
ListElement { name : qsTr("SHA3-256") }
|
||||
ListElement { name : qsTr("whirlpool") }
|
||||
ListElement { name : qsTr("BLAKE2b512") }
|
||||
ListElement { name : qsTr("BLAKE2s256") }
|
||||
ListElement { name : qsTr("SHA1") }
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
hashDropDown.text = selectedText
|
||||
hash = hashDropDown.text
|
||||
hashDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
hashDropDown.text = hash
|
||||
|
||||
for (var i = 0; i < hashListView.model.count; i++) {
|
||||
if (hashListView.model.get(i).name === hashDropDown.text) {
|
||||
currentIndex = i
|
||||
onCurrentIndexChanged: {
|
||||
if (transportProto === "tcp" && currentIndex === 0) {
|
||||
transportProto = "udp"
|
||||
} else if (transportProto === "udp" && currentIndex === 1) {
|
||||
transportProto = "tcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DropDownType {
|
||||
id: cipherDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
|
||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
parentFlickable: fl
|
||||
|
||||
descriptionText: qsTr("Cipher")
|
||||
headerText: qsTr("Cipher")
|
||||
enabled: delegateItem.isEnabled
|
||||
|
||||
drawerParent: root
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== port) {
|
||||
port = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
rootWidth: root.width
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
model: ListModel {
|
||||
ListElement { name : qsTr("AES-256-GCM") }
|
||||
ListElement { name : qsTr("AES-192-GCM") }
|
||||
ListElement { name : qsTr("AES-128-GCM") }
|
||||
ListElement { name : qsTr("AES-256-CBC") }
|
||||
ListElement { name : qsTr("AES-192-CBC") }
|
||||
ListElement { name : qsTr("AES-128-CBC") }
|
||||
ListElement { name : qsTr("ChaCha20-Poly1305") }
|
||||
ListElement { name : qsTr("ARIA-256-CBC") }
|
||||
ListElement { name : qsTr("CAMELLIA-256-CBC") }
|
||||
ListElement { name : qsTr("none") }
|
||||
}
|
||||
SwitcherType {
|
||||
id: autoNegotiateEncryprionSwitcher
|
||||
|
||||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
cipherDropDown.closeTriggered()
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
parentFlickable: fl
|
||||
|
||||
Component.onCompleted: {
|
||||
cipherDropDown.text = cipher
|
||||
text: qsTr("Auto-negotiate encryption")
|
||||
checked: autoNegotiateEncryprion
|
||||
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||
currentIndex = i
|
||||
onCheckedChanged: {
|
||||
if (checked !== autoNegotiateEncryprion) {
|
||||
autoNegotiateEncryprion = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contentRect
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
DropDownType {
|
||||
id: hashDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
|
||||
Layout.preferredHeight: checkboxLayout.implicitHeight
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
radius: 16
|
||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||
|
||||
ColumnLayout {
|
||||
id: checkboxLayout
|
||||
descriptionText: qsTr("Hash")
|
||||
headerText: qsTr("Hash")
|
||||
|
||||
anchors.fill: parent
|
||||
drawerParent: root
|
||||
|
||||
CheckBoxType {
|
||||
id: tlsAuthCheckBox
|
||||
Layout.fillWidth: true
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: hashListView
|
||||
|
||||
text: qsTr("TLS auth")
|
||||
checked: tlsAuth
|
||||
rootWidth: root.width
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== tlsAuth) {
|
||||
console.log("tlsAuth changed to: " + checked)
|
||||
tlsAuth = checked
|
||||
model: ListModel {
|
||||
ListElement { name : qsTr("SHA512") }
|
||||
ListElement { name : qsTr("SHA384") }
|
||||
ListElement { name : qsTr("SHA256") }
|
||||
ListElement { name : qsTr("SHA3-512") }
|
||||
ListElement { name : qsTr("SHA3-384") }
|
||||
ListElement { name : qsTr("SHA3-256") }
|
||||
ListElement { name : qsTr("whirlpool") }
|
||||
ListElement { name : qsTr("BLAKE2b512") }
|
||||
ListElement { name : qsTr("BLAKE2s256") }
|
||||
ListElement { name : qsTr("SHA1") }
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
hashDropDown.text = selectedText
|
||||
hash = hashDropDown.text
|
||||
hashDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
hashDropDown.text = hash
|
||||
|
||||
for (var i = 0; i < hashListView.model.count; i++) {
|
||||
if (hashListView.model.get(i).name === hashDropDown.text) {
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
DropDownType {
|
||||
id: cipherDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
CheckBoxType {
|
||||
id: blockDnsCheckBox
|
||||
Layout.fillWidth: true
|
||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||
|
||||
text: qsTr("Block DNS requests outside of VPN")
|
||||
checked: blockDns
|
||||
descriptionText: qsTr("Cipher")
|
||||
headerText: qsTr("Cipher")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== blockDns) {
|
||||
blockDns = checked
|
||||
drawerParent: root
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
|
||||
rootWidth: root.width
|
||||
|
||||
model: ListModel {
|
||||
ListElement { name : qsTr("AES-256-GCM") }
|
||||
ListElement { name : qsTr("AES-192-GCM") }
|
||||
ListElement { name : qsTr("AES-128-GCM") }
|
||||
ListElement { name : qsTr("AES-256-CBC") }
|
||||
ListElement { name : qsTr("AES-192-CBC") }
|
||||
ListElement { name : qsTr("AES-128-CBC") }
|
||||
ListElement { name : qsTr("ChaCha20-Poly1305") }
|
||||
ListElement { name : qsTr("ARIA-256-CBC") }
|
||||
ListElement { name : qsTr("CAMELLIA-256-CBC") }
|
||||
ListElement { name : qsTr("none") }
|
||||
}
|
||||
|
||||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
cipherDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
cipherDropDown.text = cipher
|
||||
|
||||
for (var i = 0; i < cipherListView.model.count; i++) {
|
||||
if (cipherListView.model.get(i).name === cipherDropDown.text) {
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalClientCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
Rectangle {
|
||||
id: contentRect
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.preferredHeight: checkboxLayout.implicitHeight
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
radius: 16
|
||||
|
||||
checked: additionalClientCommands !== ""
|
||||
Connections {
|
||||
target: tlsAuthCheckBox
|
||||
enabled: !GC.isMobile()
|
||||
|
||||
text: qsTr("Additional client configuration commands")
|
||||
function onFocusChanged() {
|
||||
if (tlsAuthCheckBox.activeFocus) {
|
||||
fl.ensureVisible(contentRect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onToggled: function() {
|
||||
if (!checked) {
|
||||
additionalClientCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
id: checkboxLayout
|
||||
|
||||
TextAreaType {
|
||||
id: additionalClientCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
anchors.fill: parent
|
||||
CheckBoxType {
|
||||
id: tlsAuthCheckBox
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: additionalClientCommandsSwitcher.checked
|
||||
text: qsTr("TLS auth")
|
||||
checked: tlsAuth
|
||||
|
||||
textAreaText: additionalClientCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
onCheckedChanged: {
|
||||
if (checked !== tlsAuth) {
|
||||
console.log("tlsAuth changed to: " + checked)
|
||||
tlsAuth = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalClientCommands !== textAreaText) {
|
||||
additionalClientCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
DividerType {}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalServerCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
CheckBoxType {
|
||||
id: blockDnsCheckBox
|
||||
Layout.fillWidth: true
|
||||
|
||||
checked: additionalServerCommands !== ""
|
||||
text: qsTr("Block DNS requests outside of VPN")
|
||||
checked: blockDns
|
||||
|
||||
text: qsTr("Additional server configuration commands")
|
||||
|
||||
onToggled: function() {
|
||||
if (!checked) {
|
||||
additionalServerCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaType {
|
||||
id: additionalServerCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: additionalServerCommandsSwitcher.checked
|
||||
|
||||
textAreaText: additionalServerCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalServerCommands !== textAreaText) {
|
||||
additionalServerCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: vpnAddressSubnetTextField.errorText === "" &&
|
||||
portTextField.errorText === ""
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
onClicked: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
var headerText = qsTr("Save settings?")
|
||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||
return
|
||||
onCheckedChanged: {
|
||||
if (checked !== blockDns) {
|
||||
blockDns = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
saveButton.forceActiveFocus()
|
||||
SwitcherType {
|
||||
id: additionalClientCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
parentFlickable: fl
|
||||
|
||||
checked: additionalClientCommands !== ""
|
||||
|
||||
text: qsTr("Additional client configuration commands")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!checked) {
|
||||
additionalClientCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaType {
|
||||
id: additionalClientCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: additionalClientCommandsSwitcher.checked
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
textAreaText: additionalClientCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalClientCommands !== textAreaText) {
|
||||
additionalClientCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalServerCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
parentFlickable: fl
|
||||
|
||||
checked: additionalServerCommands !== ""
|
||||
|
||||
text: qsTr("Additional server configuration commands")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!checked) {
|
||||
additionalServerCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaType {
|
||||
id: additionalServerCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: additionalServerCommandsSwitcher.checked
|
||||
|
||||
textAreaText: additionalServerCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
parentFlickable: fl
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalServerCommands !== textAreaText) {
|
||||
additionalServerCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
enabled: vpnAddressSubnetTextField.errorText === "" &&
|
||||
portTextField.errorText === ""
|
||||
|
||||
text: qsTr("Save")
|
||||
parentFlickable: fl
|
||||
|
||||
onClicked: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
var headerText = qsTr("Save settings?")
|
||||
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
|
||||
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
|
||||
return
|
||||
}
|
||||
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
saveButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: saveButton.clicked()
|
||||
Keys.onReturnPressed: saveButton.clicked()
|
||||
}
|
||||
}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: saveButton.clicked()
|
||||
Keys.onReturnPressed: saveButton.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: delegateItem.isEnabled
|
||||
|
||||
headerText: qsTr("VPN address subnet")
|
||||
textField.text: subnetAddress
|
||||
|
||||
@@ -85,6 +87,8 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: delegateItem.isEnabled
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
|
||||
@@ -43,6 +43,8 @@ PageType {
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: isVisible
|
||||
|
||||
@@ -66,6 +68,8 @@ PageType {
|
||||
|
||||
visible: GC.isDesktop()
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Close application")
|
||||
leftImageSource: "qrc:/images/controls/x-circle.svg"
|
||||
|
||||
@@ -29,7 +29,6 @@ PageType {
|
||||
readonly property string title: qsTr("Subscription Status")
|
||||
readonly property string contentKey: "subscriptionStatus"
|
||||
readonly property string objectImageSource: "qrc:/images/controls/info.svg"
|
||||
readonly property bool isRichText: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
@@ -38,7 +37,6 @@ PageType {
|
||||
readonly property string title: qsTr("Valid Until")
|
||||
readonly property string contentKey: "endDate"
|
||||
readonly property string objectImageSource: "qrc:/images/controls/history.svg"
|
||||
readonly property bool isRichText: false
|
||||
}
|
||||
|
||||
QtObject {
|
||||
@@ -47,7 +45,6 @@ PageType {
|
||||
readonly property string title: qsTr("Active Connections")
|
||||
readonly property string contentKey: "connectedDevices"
|
||||
readonly property string objectImageSource: "qrc:/images/controls/monitor.svg"
|
||||
readonly property bool isRichText: false
|
||||
}
|
||||
|
||||
property var processedServer
|
||||
@@ -137,7 +134,6 @@ PageType {
|
||||
imageSource: objectImageSource
|
||||
leftText: title
|
||||
rightText: ApiAccountInfoModel.data(contentKey)
|
||||
rightTextFormat: isRichText ? Text.RichText : Text.PlainText
|
||||
|
||||
visible: rightText !== ""
|
||||
}
|
||||
@@ -218,6 +214,9 @@ PageType {
|
||||
ApiConfigsController.prepareVpnKeyExport()
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
// Navigate to PageShareConnection page
|
||||
//PageController.goToPage(PageEnum.PageShareConnection)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,14 @@ PageType {
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
defaultColor: AmneziaStyle.color.paleGray
|
||||
hoveredColor: AmneziaStyle.color.sheerWhite
|
||||
pressedColor: AmneziaStyle.color.translucentWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.black
|
||||
leftImageColor: "black"
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Copy key")
|
||||
leftImageSource: "qrc:/images/controls/copy.svg"
|
||||
|
||||
@@ -119,9 +127,8 @@ PageType {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Math.min(Math.min(root.width - (Layout.leftMargin + Layout.rightMargin), root.height * 0.5), 360)
|
||||
Layout.preferredHeight: Layout.preferredWidth
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
@@ -133,9 +140,6 @@ PageType {
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
smooth: false
|
||||
fillMode: Image.PreserveAspectFit
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
source: ApiConfigsController.qrCodesCount > 0 && ApiConfigsController.qrCodes[0] ? ApiConfigsController.qrCodes[0] : ""
|
||||
}
|
||||
}
|
||||
@@ -190,7 +194,7 @@ PageType {
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
font.family: "PT Root UI VF"
|
||||
text: ApiConfigsController.vpnKey
|
||||
text: ApiConfigsController.vpnKey //|| ""
|
||||
wrapMode: Text.Wrap
|
||||
background: Rectangle { color: AmneziaStyle.color.transparent }
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ PageType {
|
||||
text: qsTr("Allow application screenshots")
|
||||
|
||||
checked: SettingsController.isScreenshotsEnabled()
|
||||
onToggled: function() {
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isScreenshotsEnabled()) {
|
||||
SettingsController.toggleScreenshotsEnabled(checked)
|
||||
}
|
||||
@@ -109,7 +109,7 @@ PageType {
|
||||
descriptionText: qsTr("Launch the application every time the device is starts")
|
||||
|
||||
checked: SettingsController.isAutoStartEnabled()
|
||||
onToggled: function() {
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isAutoStartEnabled()) {
|
||||
SettingsController.toggleAutoStart(checked)
|
||||
}
|
||||
@@ -132,7 +132,7 @@ PageType {
|
||||
descriptionText: qsTr("Connect to VPN on app start")
|
||||
|
||||
checked: SettingsController.isAutoConnectEnabled()
|
||||
onToggled: function() {
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isAutoConnectEnabled()) {
|
||||
SettingsController.toggleAutoConnect(checked)
|
||||
}
|
||||
@@ -157,9 +157,9 @@ PageType {
|
||||
enabled: switcherAutoStart.checked
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
|
||||
checked: SettingsController.startMinimized
|
||||
onToggled: function() {
|
||||
if (checked !== SettingsController.startMinimized) {
|
||||
checked: SettingsController.isStartMinimizedEnabled()
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isStartMinimizedEnabled()) {
|
||||
SettingsController.toggleStartMinimized(checked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ PageType {
|
||||
descriptionText: qsTr("If AmneziaDNS is installed on the server")
|
||||
|
||||
checked: SettingsController.isAmneziaDnsEnabled()
|
||||
onToggled: function() {
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isAmneziaDnsEnabled()) {
|
||||
SettingsController.toggleAmneziaDns(checked)
|
||||
}
|
||||
|
||||
@@ -66,13 +66,6 @@ PageType {
|
||||
|
||||
text: qsTr("If AmneziaDNS is not used or installed")
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
spacing: 16
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: primaryDns
|
||||
@@ -103,6 +96,13 @@ PageType {
|
||||
regularExpression: InstallController.ipAddressRegExp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
spacing: 16
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BasicButtonType {
|
||||
id: restoreDefaultButton
|
||||
@@ -139,6 +139,10 @@ PageType {
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
@@ -64,7 +64,7 @@ PageType {
|
||||
|
||||
checked: SettingsController.isLoggingEnabled
|
||||
|
||||
onToggled: function() {
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isLoggingEnabled) {
|
||||
SettingsController.isLoggingEnabled = checked
|
||||
}
|
||||
@@ -167,8 +167,7 @@ PageType {
|
||||
|
||||
// Show service logs only if this is NOT a macOS build with
|
||||
// Network-Extension (IsMacOsNeBuild is injected from C++ at run-time)
|
||||
// or if this is NOT a mobile build
|
||||
property list<QtObject> logTypes: (IsMacOsNeBuild || GC.isMobile()) ? [
|
||||
property list<QtObject> logTypes: IsMacOsNeBuild ? [
|
||||
clientLogs
|
||||
] : [
|
||||
clientLogs,
|
||||
@@ -215,11 +214,15 @@ PageType {
|
||||
}
|
||||
readonly property var exportLogsHandler: function() {
|
||||
var fileName = ""
|
||||
fileName = SystemController.getFileName(qsTr("Save"),
|
||||
qsTr("Logs files (*.log)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
|
||||
true,
|
||||
".log")
|
||||
if (GC.isMobile()) {
|
||||
fileName = "AmneziaVPN-service.log"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save"),
|
||||
qsTr("Logs files (*.log)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
|
||||
true,
|
||||
".log")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
SettingsController.exportServiceLogsFile(fileName)
|
||||
|
||||
@@ -18,8 +18,6 @@ PageType {
|
||||
|
||||
signal lastItemTabClickedSignal()
|
||||
|
||||
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
Connections {
|
||||
target: InstallController
|
||||
|
||||
@@ -61,13 +59,15 @@ PageType {
|
||||
target: ServersModel
|
||||
|
||||
function onProcessedServerIndexChanged() {
|
||||
root.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
|
||||
listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
|
||||
}
|
||||
}
|
||||
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
model: serverActions
|
||||
@@ -107,7 +107,7 @@ PageType {
|
||||
QtObject {
|
||||
id: check
|
||||
|
||||
property bool isVisible: root.isServerWithWriteAccess
|
||||
property bool isVisible: true
|
||||
readonly property string title: qsTr("Check the server for previously installed Amnezia services")
|
||||
readonly property string description: qsTr("Add them to the application if they were not displayed")
|
||||
readonly property var tColor: AmneziaStyle.color.paleGray
|
||||
@@ -121,7 +121,7 @@ PageType {
|
||||
QtObject {
|
||||
id: reboot
|
||||
|
||||
property bool isVisible: root.isServerWithWriteAccess
|
||||
property bool isVisible: true
|
||||
readonly property string title: qsTr("Reboot server")
|
||||
readonly property string description: ""
|
||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||
@@ -181,7 +181,7 @@ PageType {
|
||||
QtObject {
|
||||
id: clear
|
||||
|
||||
property bool isVisible: root.isServerWithWriteAccess
|
||||
property bool isVisible: true
|
||||
readonly property string title: qsTr("Clear server from Amnezia software")
|
||||
readonly property string description: ""
|
||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||
@@ -240,7 +240,7 @@ PageType {
|
||||
QtObject {
|
||||
id: switch_to_premium
|
||||
|
||||
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
|
||||
property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
|
||||
readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
|
||||
readonly property string description: ""
|
||||
readonly property var tColor: AmneziaStyle.color.vibrantRed
|
||||
|
||||
@@ -66,8 +66,6 @@ PageType {
|
||||
imageSource: imagePath
|
||||
leftText: lText
|
||||
rightText: rText
|
||||
|
||||
visible: isVisible
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
@@ -56,15 +54,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyApiServicesModel
|
||||
|
||||
sourceModel: ApiServicesModel
|
||||
sorters: RoleSorter {
|
||||
roleName: "order"
|
||||
sortOrder: Qt.AscendingOrder
|
||||
}
|
||||
}
|
||||
model: ApiServicesModel
|
||||
|
||||
delegate: ColumnLayout {
|
||||
|
||||
@@ -88,7 +78,7 @@ PageType {
|
||||
|
||||
onClicked: {
|
||||
if (isServiceAvailable) {
|
||||
ApiServicesModel.setServiceIndex(proxyApiServicesModel.mapToSource(index))
|
||||
ApiServicesModel.setServiceIndex(index)
|
||||
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ PageType {
|
||||
|
||||
visible: PageController.isStartPageVisible()
|
||||
checked: SettingsController.isLoggingEnabled
|
||||
onToggled: function() {
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isLoggingEnabled) {
|
||||
SettingsController.isLoggingEnabled = checked
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ PageType {
|
||||
if (!ConnectionController.isConnected && !ContainersModel.isServiceContainer(containerIndex)) {
|
||||
ServersModel.setDefaultContainer(ServersModel.processedIndex, containerIndex)
|
||||
}
|
||||
|
||||
|
||||
PageController.closePage() // close installing page
|
||||
PageController.closePage() // close protocol settings page
|
||||
|
||||
@@ -38,10 +38,6 @@ PageType {
|
||||
PageController.restorePageHomeState(true)
|
||||
}
|
||||
|
||||
if (stackView.currentItem.objectName === PageController.getPagePath(PageEnum.PageSetupWizardProtocols)) {
|
||||
PageController.goToPage(PageEnum.PageHome)
|
||||
}
|
||||
|
||||
PageController.showNotificationMessage(finishedMessage)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,78 +29,56 @@ PageType {
|
||||
Xray
|
||||
}
|
||||
|
||||
signal revokeConfig(int index)
|
||||
onRevokeConfig: function(index) {
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.revokeConfig(index,
|
||||
ContainersModel.getProcessedContainerIndex(),
|
||||
ServersModel.getProcessedServerCredentials())
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Config revoked"))
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ExportController
|
||||
|
||||
function onRevokeConfigCompleted() {
|
||||
PageController.showBusyIndicator(false)
|
||||
PageController.showNotificationMessage(qsTr("Config revoked"))
|
||||
}
|
||||
|
||||
function onGenerateConfig(type) {
|
||||
PageController.showBusyIndicator(true)
|
||||
|
||||
var configCaption
|
||||
var configExtension
|
||||
var configFileName
|
||||
|
||||
switch (type) {
|
||||
case PageShare.ConfigType.AmneziaConnection: {
|
||||
ExportController.generateConnectionConfig(clientNameTextField.textField.text);
|
||||
configCaption = qsTr("Save AmneziaVPN config")
|
||||
configExtension = ".vpn"
|
||||
configFileName = "amnezia_config"
|
||||
break;
|
||||
}
|
||||
case PageShare.ConfigType.OpenVpn: {
|
||||
ExportController.generateOpenVpnConfig(clientNameTextField.textField.text)
|
||||
configCaption = qsTr("Save OpenVPN config")
|
||||
configExtension = ".ovpn"
|
||||
configFileName = "amnezia_for_openvpn"
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.WireGuard: {
|
||||
ExportController.generateWireGuardConfig(clientNameTextField.textField.text)
|
||||
configCaption = qsTr("Save WireGuard config")
|
||||
configExtension = ".conf"
|
||||
configFileName = "amnezia_for_wireguard"
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.Awg: {
|
||||
ExportController.generateAwgConfig(clientNameTextField.textField.text)
|
||||
configCaption = qsTr("Save AmneziaWG config")
|
||||
configExtension = ".conf"
|
||||
configFileName = "amnezia_for_awg"
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.ShadowSocks: {
|
||||
ExportController.generateShadowSocksConfig()
|
||||
configCaption = qsTr("Save Shadowsocks config")
|
||||
configExtension = ".json"
|
||||
configFileName = "amnezia_for_shadowsocks"
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.Cloak: {
|
||||
ExportController.generateCloakConfig()
|
||||
configCaption = qsTr("Save Cloak config")
|
||||
configExtension = ".json"
|
||||
configFileName = "amnezia_for_cloak"
|
||||
break
|
||||
}
|
||||
case PageShare.ConfigType.Xray: {
|
||||
ExportController.generateXrayConfig(clientNameTextField.textField.text)
|
||||
configCaption = qsTr("Save XRay config")
|
||||
configExtension = ".json"
|
||||
configFileName = "amnezia_for_xray"
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
var headerText = qsTr("Connection to ") + serverSelector.text
|
||||
var configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||
PageController.goToShareConnectionPage(headerText, configContentHeaderText, configCaption, configExtension, configFileName)
|
||||
PageController.goToPage(PageEnum.PageShareConnection)
|
||||
}
|
||||
|
||||
function onExportErrorOccurred(error) {
|
||||
@@ -792,7 +770,7 @@ PageType {
|
||||
|
||||
if (clientNameEditor.textField.text !== clientName) {
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.renameClient(proxyClientManagementModel.mapToSource(index),
|
||||
ExportController.renameClient(index,
|
||||
clientNameEditor.textField.text,
|
||||
ContainersModel.getProcessedContainerIndex(),
|
||||
ServersModel.getProcessedServerCredentials())
|
||||
@@ -827,10 +805,7 @@ PageType {
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
clientInfoDrawer.closeTriggered()
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.revokeConfig(proxyClientManagementModel.mapToSource(index),
|
||||
ContainersModel.getProcessedContainerIndex(),
|
||||
ServersModel.getProcessedServerCredentials())
|
||||
root.revokeConfig(index)
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ PageType {
|
||||
id: pageShareConnection
|
||||
|
||||
property string headerText
|
||||
|
||||
Component.onCompleted: {
|
||||
var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server"
|
||||
headerText = qsTr("Connection to ") + serverName
|
||||
configContentHeaderText = qsTr("File with connection settings to ") + serverName
|
||||
}
|
||||
property string configContentHeaderText
|
||||
property string shareButtonText: qsTr("Share")
|
||||
property string copyButtonText: qsTr("Copy")
|
||||
@@ -30,17 +36,17 @@ PageType {
|
||||
property string configCaption: qsTr("Save AmneziaVPN config")
|
||||
property string configFileName: "amnezia_config"
|
||||
|
||||
// onVisibleChanged: {
|
||||
// configExtension = ".vpn"
|
||||
// configCaption = qsTr("Save AmneziaVPN config")
|
||||
// configFileName = "amnezia_config"
|
||||
onVisibleChanged: {
|
||||
configExtension = ".vpn"
|
||||
configCaption = qsTr("Save AmneziaVPN config")
|
||||
configFileName = "amnezia_config"
|
||||
|
||||
// if (visible) {
|
||||
// var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server"
|
||||
// headerText = qsTr("Connection to ") + serverName
|
||||
// configContentHeaderText = qsTr("File with connection settings to ") + serverName
|
||||
// }
|
||||
// }
|
||||
if (visible) {
|
||||
var serverName = ServersModel.getProcessedServerData("name") || ServersModel.getProcessedServerData("hostName") || "Server"
|
||||
headerText = qsTr("Connection to ") + serverName
|
||||
configContentHeaderText = qsTr("File with connection settings to ") + serverName
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
@@ -269,9 +275,8 @@ PageType {
|
||||
|
||||
Rectangle {
|
||||
id: qrCodeContainer
|
||||
Layout.preferredWidth: Math.min(Math.min(listView.width - (Layout.leftMargin + Layout.rightMargin), pageShareConnection.height * 0.5), 360)
|
||||
Layout.preferredHeight: Layout.preferredWidth
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
@@ -281,9 +286,6 @@ PageType {
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
smooth: false
|
||||
fillMode: Image.PreserveAspectFit
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
source: pageShareConnection.isSelfHostedConfig ? (isQrCodeVisible ? ExportController.qrCodes[0] : "") : (isQrCodeVisible ? ApiConfigsController.qrCodes[0] : "")
|
||||
property bool isFocusable: true
|
||||
Keys.onTabPressed: FocusController.nextKeyTabItem()
|
||||
|
||||
@@ -37,9 +37,6 @@ PageType {
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
property string headerText: ""
|
||||
property string configContentHeaderText: ""
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
@@ -107,13 +104,12 @@ PageType {
|
||||
clickedFunction: function() {
|
||||
handler()
|
||||
|
||||
if (serverSelector.currentIndex !== serverSelectorListView.selectedIndex) {
|
||||
serverSelector.currentIndex = serverSelectorListView.selectedIndex
|
||||
serverSelector.severSelectorIndexChanged()
|
||||
if (serverSelector.currentIndex !== serverSelectorListView.currentIndex) {
|
||||
serverSelector.currentIndex = serverSelectorListView.currentIndex
|
||||
}
|
||||
|
||||
listView.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
listView.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
shareConnectionPage.headerText = qsTr("Accessing ") + serverSelector.text
|
||||
shareConnectionPage.configContentHeaderText = qsTr("File with accessing settings to ") + serverSelector.text
|
||||
serverSelector.closeTriggered()
|
||||
}
|
||||
|
||||
@@ -125,7 +121,7 @@ PageType {
|
||||
|
||||
function handler() {
|
||||
serverSelector.text = selectedText
|
||||
ServersModel.processedIndex = proxyServersModel.mapToSource(selectedIndex)
|
||||
ServersModel.processedIndex = proxyServersModel.mapToSource(currentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,9 +156,15 @@ PageType {
|
||||
|
||||
PageController.showBusyIndicator(false)
|
||||
|
||||
PageController.goToShareConnectionPage(listView.headerText, listView.configContentHeaderText, "", ".vpn", "amnezia_config")
|
||||
PageController.goToPage(PageEnum.PageShareConnection)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShareConnectionDrawer {
|
||||
id: shareConnectionDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,19 +44,6 @@ PageType {
|
||||
tabBarStackView.push(pagePath, { "objectName" : pagePath }, StackView.PushTransition)
|
||||
}
|
||||
|
||||
function onGoToShareConnectionPage(headerText, configContentHeaderText, configCaption, configExtension, configFileName) {
|
||||
var pagePath = PageController.getPagePath(PageEnum.PageShareConnection)
|
||||
tabBarStackView.push(pagePath,
|
||||
{ "objectName" : pagePath,
|
||||
"headerText" : headerText,
|
||||
"configContentHeaderText" : configContentHeaderText,
|
||||
"configCaption" : configCaption,
|
||||
"configExtension" : configExtension,
|
||||
"configFileName" : configFileName
|
||||
},
|
||||
StackView.PushTransition)
|
||||
}
|
||||
|
||||
function onDisableControls(disabled) {
|
||||
isControlsDisabled = disabled
|
||||
}
|
||||
|
||||
@@ -83,7 +83,9 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
if (IpcClient::Interface()) {
|
||||
if (state == Vpn::ConnectionState::Connected) {
|
||||
IpcClient::Interface()->resetIpStack();
|
||||
IpcClient::Interface()->flushDns();
|
||||
if (container != DockerContainer::Ipsec) {
|
||||
IpcClient::Interface()->flushDns();
|
||||
}
|
||||
|
||||
if (container != DockerContainer::Awg && container != DockerContainer::WireGuard) {
|
||||
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
|
||||
|
||||
@@ -36,5 +36,17 @@ class IpcInterface
|
||||
SLOT( bool enablePeerTraffic( const QJsonObject &configStr) );
|
||||
SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) );
|
||||
SLOT( bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) );
|
||||
|
||||
SLOT( bool writeIPsecCaCert(QString cacert, QString uuid) );
|
||||
SLOT( bool writeIPsecPrivate(QString privKey, QString uuid) );
|
||||
SLOT( bool writeIPsecConfig(QString config) );
|
||||
SLOT( bool writeIPsecUserCert(QString usercert, QString uuid) );
|
||||
SLOT( bool writeIPsecPrivatePass(QString pass, QString host, QString uuid) );
|
||||
|
||||
SLOT( bool stopIPsec(QString tunnelName) );
|
||||
SLOT( bool startIPsec(QString tunnelName) );
|
||||
|
||||
SLOT( QString getTunnelStatus(QString tunnelName) );
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <QFileInfo>
|
||||
#include <QLocalSocket>
|
||||
#include <QObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "logger.h"
|
||||
#include "router.h"
|
||||
@@ -161,6 +162,7 @@ void IpcServer::StartRoutingIpv6()
|
||||
{
|
||||
Router::StartRoutingIpv6();
|
||||
}
|
||||
|
||||
void IpcServer::StopRoutingIpv6()
|
||||
{
|
||||
Router::StopRoutingIpv6();
|
||||
@@ -204,6 +206,196 @@ bool IpcServer::disableKillSwitch()
|
||||
return KillSwitch::instance()->disableKillSwitch();
|
||||
}
|
||||
|
||||
bool IpcServer::startIPsec(QString tunnelName)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
QProcess processSystemd;
|
||||
QStringList commandsSystemd;
|
||||
commandsSystemd << "systemctl" << "restart" << "ipsec";
|
||||
processSystemd.start("sudo", commandsSystemd);
|
||||
if (!processSystemd.waitForStarted(1000))
|
||||
{
|
||||
qDebug().noquote() << "Could not start ipsec tunnel!\n";
|
||||
return false;
|
||||
}
|
||||
else if (!processSystemd.waitForFinished(2000))
|
||||
{
|
||||
qDebug().noquote() << "Could not start ipsec tunnel\n";
|
||||
return false;
|
||||
}
|
||||
commandsSystemd.clear();
|
||||
|
||||
QThread::msleep(5000);
|
||||
|
||||
QProcess process;
|
||||
QStringList commands;
|
||||
commands << "ipsec" << "up" << QString("%1").arg(tunnelName);
|
||||
process.start("sudo", commands);
|
||||
if (!process.waitForStarted(1000))
|
||||
{
|
||||
qDebug().noquote() << "Could not start ipsec tunnel!\n";
|
||||
return false;
|
||||
}
|
||||
else if (!process.waitForFinished(2000))
|
||||
{
|
||||
qDebug().noquote() << "Could not start ipsec tunnel\n";
|
||||
return false;
|
||||
}
|
||||
commands.clear();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::stopIPsec(QString tunnelName)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
QProcess process;
|
||||
QStringList commands;
|
||||
commands << "ipsec" << "down" << QString("%1").arg(tunnelName);
|
||||
process.start("sudo", commands);
|
||||
if (!process.waitForStarted(1000))
|
||||
{
|
||||
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||
return false;
|
||||
}
|
||||
else if (!process.waitForFinished(2000))
|
||||
{
|
||||
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||
return false;
|
||||
}
|
||||
commands.clear();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::writeIPsecConfig(QString config)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
qDebug() << "IPSEC: IPSec config file";
|
||||
QString configFile = QString("/etc/ipsec.conf");
|
||||
QFile ipSecConfFile(configFile);
|
||||
if (ipSecConfFile.open(QIODevice::WriteOnly)) {
|
||||
ipSecConfFile.write(config.toUtf8());
|
||||
ipSecConfFile.close();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::writeIPsecUserCert(QString usercert, QString uuid)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
qDebug() << "IPSEC: Write user cert " << uuid;
|
||||
QString certName = QString("/etc/ipsec.d/certs/%1.crt").arg(uuid);
|
||||
QFile userCertFile(certName);
|
||||
if (userCertFile.open(QIODevice::WriteOnly)) {
|
||||
userCertFile.write(usercert.toUtf8());
|
||||
userCertFile.close();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::writeIPsecCaCert(QString cacert, QString uuid)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
qDebug() << "IPSEC: Write CA cert user " << uuid;
|
||||
QString certName = QString("/etc/ipsec.d/cacerts/%1.crt").arg(uuid);
|
||||
QFile caCertFile(certName);
|
||||
if (caCertFile.open(QIODevice::WriteOnly)) {
|
||||
caCertFile.write(cacert.toUtf8());
|
||||
caCertFile.close();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::writeIPsecPrivate(QString privKey, QString uuid)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
qDebug() << "IPSEC: User private key " << uuid;
|
||||
QString privateKey = QString("/etc/ipsec.d/private/%1.p12").arg(uuid);
|
||||
QFile pKeyFile(privateKey);
|
||||
if (pKeyFile.open(QIODevice::WriteOnly)) {
|
||||
pKeyFile.write(QByteArray::fromBase64(privKey.toUtf8()));
|
||||
pKeyFile.close();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IpcServer::writeIPsecPrivatePass(QString pass, QString host, QString uuid)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
qDebug() << "IPSEC: User private key " << uuid;
|
||||
const QString secretsFilename = "/etc/ipsec.secrets";
|
||||
QStringList lines;
|
||||
|
||||
{
|
||||
QFile secretsFile(secretsFilename);
|
||||
if (secretsFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream edit(&secretsFile);
|
||||
while (!edit.atEnd()) lines.push_back(edit.readLine());
|
||||
}
|
||||
secretsFile.close();
|
||||
}
|
||||
|
||||
for (auto iter = lines.begin(); iter!=lines.end();)
|
||||
{
|
||||
if (iter->contains(host))
|
||||
{
|
||||
iter = lines.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QFile secretsFile(secretsFilename);
|
||||
if (secretsFile.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
QTextStream edit(&secretsFile);
|
||||
for (int i=0; i<lines.size(); i++) edit << lines[i] << Qt::endl;
|
||||
}
|
||||
QString P12 = QString("%any %1 : P12 %2.p12 \"%3\" \n").arg(host, uuid, pass);
|
||||
secretsFile.write(P12.toUtf8());
|
||||
secretsFile.close();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
QString IpcServer::getTunnelStatus(QString tunnelName)
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
QProcess process;
|
||||
QStringList commands;
|
||||
commands << "ipsec" << "status" << QString("%1").arg(tunnelName);
|
||||
process.start("sudo", commands);
|
||||
if (!process.waitForStarted(1000))
|
||||
{
|
||||
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||
return "";
|
||||
}
|
||||
else if (!process.waitForFinished(2000))
|
||||
{
|
||||
qDebug().noquote() << "Could not stop ipsec tunnel\n";
|
||||
return "";
|
||||
}
|
||||
commands.clear();
|
||||
|
||||
|
||||
QString status = process.readAll();
|
||||
return status;
|
||||
#endif
|
||||
return QString();
|
||||
|
||||
}
|
||||
|
||||
bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
||||
{
|
||||
return KillSwitch::instance()->enablePeerTraffic(configStr);
|
||||
|
||||
@@ -42,6 +42,14 @@ public:
|
||||
virtual bool disableKillSwitch() override;
|
||||
virtual bool refreshKillSwitch( bool enabled ) override;
|
||||
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
||||
virtual bool writeIPsecCaCert(QString cacert, QString uuid) override;
|
||||
virtual bool writeIPsecPrivate(QString privKey, QString uuid) override;
|
||||
virtual bool writeIPsecConfig(QString config) override;
|
||||
virtual bool writeIPsecUserCert(QString usercert, QString uuid) override;
|
||||
virtual bool writeIPsecPrivatePass(QString pass, QString host, QString uuid) override;
|
||||
virtual bool stopIPsec(QString tunnelName) override;
|
||||
virtual bool startIPsec(QString tunnelName) override;
|
||||
virtual QString getTunnelStatus(QString tunnelName) override;
|
||||
|
||||
private:
|
||||
int m_localpid = 0;
|
||||
|
||||
@@ -29,7 +29,7 @@ void IpcProcessTun2Socks::start()
|
||||
QString XrayConStr = "socks5://127.0.0.1:10808";
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QStringList arguments({"-device", "tun://tun2?guid={081A8A84-8D12-4DF5-B8C4-396D5B0053E4}", "-proxy", XrayConStr, "-tun-post-up",
|
||||
QStringList arguments({"-device", "tun://tun2", "-proxy", XrayConStr, "-tun-post-up",
|
||||
QString("cmd /c netsh interface ip set address name=\"tun2\" static %1 255.255.255.255")
|
||||
.arg(amnezia::protocols::xray::defaultLocalAddr)});
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user