Compare commits

..

3 Commits

Author SHA1 Message Date
Mitternacht822 8fab9b244e fixed some warning in exportcontroller.cpp 2025-05-05 17:09:15 +04:00
Mitternacht822 9fdcb9cf39 fixed issue with not updating server config for xray on windows platform 2025-05-05 17:08:26 +04:00
Mitternacht822 6745cb0c49 added the ability to change port after installing xray 2025-04-30 17:35:24 +04:00
128 changed files with 1667 additions and 3502 deletions
+1 -81
View File
@@ -20,8 +20,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Install Qt'
@@ -92,8 +90,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Get sources'
@@ -160,8 +156,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Setup xcode'
@@ -249,7 +243,7 @@ jobs:
# ------------------------------------------------------
Build-MacOS-old:
Build-MacOS:
runs-on: macos-latest
env:
@@ -261,78 +255,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.4.0'
- name: 'Install Qt'
uses: jurplel/install-qt-action@v3
with:
version: ${{ env.QT_VERSION }}
host: 'mac'
target: 'desktop'
arch: 'clang_64'
modules: 'qtremoteobjects qt5compat qtshadertools'
dir: ${{ runner.temp }}
setup-python: 'true'
set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
run: |
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
- name: 'Get sources'
uses: actions/checkout@v4
with:
submodules: 'true'
fetch-depth: 10
- name: 'Setup ccache'
uses: hendrikmuhs/ccache-action@v1.2
- name: 'Build project'
run: |
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
bash deploy/build_macos.sh
- name: 'Upload installer artifact'
uses: actions/upload-artifact@v4
with:
name: AmneziaVPN_MacOS_old_installer
path: AmneziaVPN.dmg
retention-days: 7
- name: 'Upload unpacked artifact'
uses: actions/upload-artifact@v4
with:
name: AmneziaVPN_MacOS_old_unpacked
path: deploy/build/client/AmneziaVPN.app
retention-days: 7
# ------------------------------------------------------
Build-MacOS:
runs-on: macos-latest
env:
QT_VERSION: 6.8.0
QIF_VERSION: 4.8.1
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Setup xcode'
@@ -402,8 +324,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Install desktop Qt'
-2
View File
@@ -20,8 +20,6 @@ jobs:
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
FREE_V2_ENDPOINT: ${{ secrets.FREE_V2_ENDPOINT }}
PREM_V1_ENDPOINT: ${{ secrets.PREM_V1_ENDPOINT }}
steps:
- name: 'Install desktop Qt'
+1 -5
View File
@@ -133,8 +133,4 @@ client/3rd/ShadowSocks/ss_ios.xcconfig
out/
# CMake files
CMakeFiles/
ios-ne-build.sh
macos-ne-build.sh
macos-signed-build.sh
CMakeFiles/
+2 -2
View File
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.8.7.2
project(${PROJECT} VERSION 4.8.6.0
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,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 2086)
set(APP_ANDROID_VERSION_CODE 2083)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
-3
View File
@@ -31,9 +31,6 @@ add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
add_definitions(-DFREE_V2_ENDPOINT="$ENV{FREE_V2_ENDPOINT}")
add_definitions(-DPREM_V1_ENDPOINT="$ENV{PREM_V1_ENDPOINT}")
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
set(PACKAGES ${PACKAGES} Widgets)
endif()
@@ -13,10 +13,10 @@
#include <QApplication>
#endif
#include "core/networkUtilities.h"
#include "containers/containers_defs.h"
#include "core/controllers/serverController.h"
#include "core/scripts_registry.h"
#include "core/server_defs.h"
#include "settings.h"
#include "utilities.h"
@@ -24,7 +24,6 @@
#include <openssl/rsa.h>
#include <openssl/x509.h>
OpenVpnConfigurator::OpenVpnConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController,
QObject *parent)
: ConfiguratorBase(settings, serverController, parent)
@@ -120,14 +119,20 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
if (!m_settings->isSitesSplitTunnelingEnabled()) {
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
#endif
config.append("block-ipv6\n");
} else if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
// no redirect-gateway
// no redirect-gateway
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
config.append("\nredirect-gateway ipv6 !ipv4 bypass-dhcp\n");
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
#endif
config.append("block-ipv6\n");
}
@@ -164,6 +169,7 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
// Prevent ipv6 leak
config.append("ifconfig-ipv6 fd15:53b6:dead::2/64 fd15:53b6:dead::1\n");
config.append("block-ipv6\n");
// remove block-outside-dns for all exported configs
+84 -69
View File
@@ -140,83 +140,98 @@ QMap<DockerContainer, QString> ContainerProps::containerDetailedDescriptions()
{
return {
{ DockerContainer::OpenVpn,
QObject::tr("OpenVPN is one of the most popular and reliable VPN protocols. "
"It uses SSL/TLS encryption, supports a wide variety of devices and operating systems, "
"and is continuously improved by the community due to its open-source nature. "
"It provides a good balance between speed and security but is easily recognized by DPI systems, "
"making it susceptible to blocking.\n"
"\nFeatures:\n"
"* Available on all AmneziaVPN platforms\n"
"* Normal battery consumption on mobile devices\n"
"* Flexible customization for various devices and OS\n"
"* Operates over both TCP and UDP protocols") },
QObject::tr(
"OpenVPN stands as one of the most popular and time-tested VPN protocols available.\n"
"It employs its unique security protocol, "
"leveraging the strength of SSL/TLS for encryption and key exchange. "
"Furthermore, OpenVPN's support for a multitude of authentication methods makes it versatile and adaptable, "
"catering to a wide range of devices and operating systems. "
"Due to its open-source nature, OpenVPN benefits from extensive scrutiny by the global community, "
"which continually reinforces its security. "
"With a strong balance of performance, security, and compatibility, "
"OpenVPN remains a top choice for privacy-conscious individuals and businesses alike.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Normal power consumption on mobile devices\n"
"* Flexible customisation to suit user needs to work with different operating systems and devices\n"
"* Recognised by DPI systems and therefore susceptible to blocking\n"
"* Can operate over both TCP and UDP network protocols.") },
{ DockerContainer::ShadowSocks,
QObject::tr("Shadowsocks is based on the SOCKS5 protocol and encrypts connections using AEAD cipher. "
"Although designed to be discreet, it doesn't mimic a standard HTTPS connection and can be detected by some DPI systems. "
"Due to limited support in Amnezia, we recommend using the AmneziaWG protocol.\n"
"\nFeatures:\n"
"* Available in AmneziaVPN only on desktop platforms\n"
"* Customizable encryption protocol\n"
QObject::tr("Shadowsocks, inspired by the SOCKS5 protocol, safeguards the connection using the AEAD cipher. "
"Although Shadowsocks is designed to be discreet and challenging to identify, it isn't identical to a standard HTTPS connection."
"However, certain traffic analysis systems might still detect a Shadowsocks connection. "
"Due to limited support in Amnezia, it's recommended to use AmneziaWG protocol.\n\n"
"* Available in the AmneziaVPN only on desktop platforms\n"
"* Configurable encryption protocol\n"
"* Detectable by some DPI systems\n"
"* Operates over TCP protocol\n") },
"* Works over TCP network protocol.") },
{ DockerContainer::Cloak,
QObject::tr("This combination includes the OpenVPN protocol and the Cloak plugin, specifically designed to protect against blocking.\n"
"\nOpenVPN securely encrypts all internet traffic between your device and the server.\n"
"\nThe Cloak plugin further protects the connection from DPI detection. "
"It modifies traffic metadata to disguise VPN traffic as regular web traffic and prevents detection through active probing. "
"If an incoming connection fails authentication, Cloak serves a fake website, making your VPN invisible to traffic analysis systems.\n"
"\nIn regions with heavy internet censorship, we strongly recommend using OpenVPN with Cloak from your first connection.\n"
"\nFeatures:\n"
"* Available on all AmneziaVPN platforms\n"
QObject::tr("This is a combination of the OpenVPN protocol and the Cloak plugin designed specifically for "
"protecting against detection.\n\n"
"OpenVPN provides a secure VPN connection by encrypting all internet traffic between the client "
"and the server.\n\n"
"Cloak protects OpenVPN from detection. \n\n"
"Cloak can modify packet metadata so that it completely masks VPN traffic as normal web traffic, "
"and also protects the VPN from detection by Active Probing. This makes it very resistant to "
"being detected\n\n"
"Immediately after receiving the first data packet, Cloak authenticates the incoming connection. "
"If authentication fails, the plugin masks the server as a fake website and your VPN becomes "
"invisible to analysis systems.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* High power consumption on mobile devices\n"
"* Flexible configuration options\n"
"* Undetectable by DPI systems\n"
"* Operates over TCP protocol on port 443") },
"* Flexible settings\n"
"* Not recognised by detection systems\n"
"* Works over TCP network protocol, 443 port.\n") },
{ DockerContainer::WireGuard,
QObject::tr("WireGuard is a modern, streamlined VPN protocol offering stable connectivity and excellent performance across all devices. "
"It uses fixed encryption settings, delivering lower latency and higher data transfer speeds compared to OpenVPN. "
"However, WireGuard is easily identifiable by DPI systems due to its distinctive packet signatures, making it susceptible to blocking.\n"
"\nFeatures:\n"
"* Available on all AmneziaVPN platforms\n"
"* Low power consumption on mobile devices\n"
"* Minimal configuration required\n"
"* Easily detected by DPI systems (susceptible to blocking)\n"
"* Operates over UDP protocol") },
QObject::tr("A relatively new popular VPN protocol with a simplified architecture.\n"
"WireGuard provides stable VPN connection and high performance on all devices. It uses hard-coded encryption "
"settings. WireGuard compared to OpenVPN has lower latency and better data transfer throughput.\n"
"WireGuard is very susceptible to detection and blocking due to its distinct packet signatures. "
"Unlike some other VPN protocols that employ obfuscation techniques, "
"the consistent signature patterns of WireGuard packets can be more easily identified and "
"thus blocked by advanced Deep Packet Inspection (DPI) systems and other network monitoring tools.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Low power consumption\n"
"* Minimum number of settings\n"
"* Easily recognised by DPI analysis systems, susceptible to blocking\n"
"* Works over UDP network protocol.") },
{ DockerContainer::Awg,
QObject::tr("AmneziaWG is a modern VPN protocol based on WireGuard, "
"combining simplified architecture with high performance across all devices. "
"It addresses WireGuard's main vulnerability (easy detection by DPI systems) through advanced obfuscation techniques, "
"making VPN traffic indistinguishable from regular internet traffic.\n"
"\nAmneziaWG is an excellent choice for those seeking a fast, stealthy VPN connection.\n"
"\nFeatures:\n"
"* Available on all AmneziaVPN platforms\n"
"* Low battery consumption on mobile devices\n"
"* Minimal settings required\n"
"* Undetectable by traffic analysis systems (DPI)\n"
"* Operates over UDP protocol") },
QObject::tr("A modern iteration of the popular VPN protocol, "
"AmneziaWG builds upon the foundation set by WireGuard, "
"retaining its simplified architecture and high-performance capabilities across devices.\n"
"While WireGuard is known for its efficiency, "
"it had issues with being easily detected due to its distinct packet signatures. "
"AmneziaWG solves this problem by using better obfuscation methods, "
"making its traffic blend in with regular internet traffic.\n"
"This means that AmneziaWG keeps the fast performance of the original "
"while adding an extra layer of stealth, "
"making it a great choice for those wanting a fast and discreet VPN connection.\n\n"
"* Available in the AmneziaVPN across all platforms\n"
"* Low power consumption\n"
"* Minimum number of settings\n"
"* Not recognised by traffic analysis systems\n"
"* Works over UDP network protocol.") },
{ DockerContainer::Xray,
QObject::tr("REALITY is an innovative protocol developed by the creators of XRay, designed specifically to combat high levels of internet censorship. "
"REALITY identifies censorship systems during the TLS handshake, "
"redirecting suspicious traffic seamlessly to legitimate websites like google.com while providing genuine TLS certificates. "
"This allows VPN traffic to blend indistinguishably with regular web traffic without special configuration."
"\nUnlike older protocols such as VMess, VLESS, and XTLS-Vision, REALITY incorporates an advanced built-in \"friend-or-foe\" detection mechanism, "
"effectively protecting against DPI and other traffic analysis methods.\n"
"\nFeatures:\n"
"* Resistant to active probing and DPI detection\n"
"* No special configuration required to disguise traffic\n"
"* Highly effective in heavily censored regions\n"
"* Minimal battery consumption on devices\n"
"* Operates over TCP protocol") },
QObject::tr("The REALITY protocol, a pioneering development by the creators of XRay, "
"is designed to provide the highest level of protection against detection through its innovative approach to security and privacy.\n"
"It uniquely identifies attackers during the TLS handshake phase, seamlessly operating as a proxy for legitimate clients while diverting attackers to genuine websites, "
"thus presenting an authentic TLS certificate and data. \n"
"This advanced capability differentiates REALITY from similar technologies by its ability to disguise web traffic as coming from random, "
"legitimate sites without the need for specific configurations. \n"
"Unlike older protocols such as VMess, VLESS, and the XTLS-Vision transport, "
"REALITY's innovative \"friend or foe\" recognition at the TLS handshake enhances security. "
"This makes REALITY a robust solution for maintaining internet freedom.")
},
{ DockerContainer::Ipsec,
QObject::tr("IKEv2, combined with IPSec encryption, is a modern and reliable VPN protocol. "
"It reconnects quickly when switching networks or devices, making it ideal for dynamic network environments. "
"While it provides good security and speed, it's easily recognized by DPI systems and susceptible to blocking.\n"
"\nFeatures:\n"
"* Available in AmneziaVPN only on Windows\n"
"* Low battery consumption on mobile devices\n"
"* Minimal configuration required\n"
"* Detectable by DPI analysis systems(easily blocked)\n"
"* Operates over UDP protocol(ports 500 and 4500)") },
QObject::tr("IKEv2, paired with the IPSec encryption layer, stands as a modern and stable VPN protocol.\n"
"One of its distinguishing features is its ability to swiftly switch between networks and devices, "
"making it particularly adaptive in dynamic network environments. \n"
"While it offers a blend of security, stability, and speed, "
"it's essential to note that IKEv2 can be easily detected and is susceptible to blocking.\n\n"
"* Available in the AmneziaVPN only on Windows\n"
"* Low power consumption, on mobile devices\n"
"* Minimal configuration\n"
"* Recognised by DPI analysis systems\n"
"* Works over UDP network protocol, ports 500 and 4500.") },
{ DockerContainer::TorWebSite, QObject::tr("Website in Tor network") },
{ DockerContainer::Dns, QObject::tr("DNS Service") },
-12
View File
@@ -22,20 +22,12 @@ namespace apiDefs
namespace key
{
constexpr QLatin1String configVersion("config_version");
constexpr QLatin1String apiEndpoint("api_endpoint");
constexpr QLatin1String apiKey("api_key");
constexpr QLatin1String description("description");
constexpr QLatin1String name("name");
constexpr QLatin1String protocol("protocol");
constexpr QLatin1String apiConfig("api_config");
constexpr QLatin1String stackType("stack_type");
constexpr QLatin1String serviceType("service_type");
constexpr QLatin1String cliVersion("cli_version");
constexpr QLatin1String vpnKey("vpn_key");
constexpr QLatin1String config("config");
constexpr QLatin1String configs("configs");
constexpr QLatin1String installationUuid("installation_uuid");
constexpr QLatin1String workerLastUpdated("worker_last_updated");
@@ -59,10 +51,6 @@ namespace apiDefs
constexpr QLatin1String website("website");
constexpr QLatin1String websiteName("website_name");
constexpr QLatin1String telegram("telegram");
constexpr QLatin1String id("id");
constexpr QLatin1String orderId("order_id");
constexpr QLatin1String migrationCode("migration_code");
}
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
+3 -70
View File
@@ -3,24 +3,6 @@
#include <QDateTime>
#include <QJsonObject>
namespace
{
const QByteArray AMNEZIA_CONFIG_SIGNATURE = QByteArray::fromHex("000000ff");
QString escapeUnicode(const QString &input)
{
QString output;
for (QChar c : input) {
if (c.unicode() < 0x20 || c.unicode() > 0x7E) {
output += QString("\\u%1").arg(QString::number(c.unicode(), 16).rightJustified(4, '0'));
} else {
output += c;
}
}
return output;
}
}
bool apiUtils::isSubscriptionExpired(const QString &subscriptionEndDate)
{
QDateTime now = QDateTime::currentDateTime();
@@ -41,21 +23,13 @@ bool apiUtils::isServerFromApi(const QJsonObject &serverConfigObject)
apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObject)
{
auto configVersion = serverConfigObject.value(apiDefs::key::configVersion).toInt();
switch (configVersion) {
case apiDefs::ConfigSource::Telegram: {
constexpr QLatin1String freeV2Endpoint(FREE_V2_ENDPOINT);
constexpr QLatin1String premiumV1Endpoint(PREM_V1_ENDPOINT);
auto apiEndpoint = serverConfigObject.value(apiDefs::key::apiEndpoint).toString();
if (apiEndpoint.contains(premiumV1Endpoint)) {
return apiDefs::ConfigType::AmneziaPremiumV1;
} else if (apiEndpoint.contains(freeV2Endpoint)) {
return apiDefs::ConfigType::AmneziaFreeV2;
}
};
case apiDefs::ConfigSource::AmneziaGateway: {
constexpr QLatin1String stackPremium("prem");
constexpr QLatin1String stackFree("free");
constexpr QLatin1String servicePremium("amnezia-premium");
constexpr QLatin1String serviceFree("amnezia-free");
constexpr QLatin1String serviceExternalPremium("external-premium");
@@ -96,9 +70,6 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
qDebug() << reply->error();
return amnezia::ErrorCode::ApiConfigTimeoutError;
} else if (reply->error() == QNetworkReply::NetworkError::OperationNotImplementedError) {
qDebug() << reply->error();
return amnezia::ErrorCode::ApiUpdateRequestError;
} else {
QString err = reply->errorString();
int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -124,41 +95,3 @@ bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
apiDefs::ConfigType::ExternalPremium };
return premiumTypes.contains(getConfigType(serverConfigObject));
}
QString apiUtils::getPremiumV1VpnKey(const QJsonObject &serverConfigObject)
{
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV1) {
return {};
}
QList<QPair<QString, QVariant>> orderedFields;
orderedFields.append(qMakePair(apiDefs::key::name, serverConfigObject[apiDefs::key::name].toString()));
orderedFields.append(qMakePair(apiDefs::key::description, serverConfigObject[apiDefs::key::description].toString()));
orderedFields.append(qMakePair(apiDefs::key::configVersion, serverConfigObject[apiDefs::key::configVersion].toDouble()));
orderedFields.append(qMakePair(apiDefs::key::protocol, serverConfigObject[apiDefs::key::protocol].toString()));
orderedFields.append(qMakePair(apiDefs::key::apiEndpoint, serverConfigObject[apiDefs::key::apiEndpoint].toString()));
orderedFields.append(qMakePair(apiDefs::key::apiKey, serverConfigObject[apiDefs::key::apiKey].toString()));
QString vpnKeyStr = "{";
for (int i = 0; i < orderedFields.size(); ++i) {
const auto &pair = orderedFields[i];
if (pair.second.typeId() == QMetaType::Type::QString) {
vpnKeyStr += "\"" + pair.first + "\": \"" + pair.second.toString() + "\"";
} else if (pair.second.typeId() == QMetaType::Type::Double || pair.second.typeId() == QMetaType::Type::Int) {
vpnKeyStr += "\"" + pair.first + "\": " + QString::number(pair.second.toDouble(), 'f', 1);
}
if (i < orderedFields.size() - 1) {
vpnKeyStr += ", ";
}
}
vpnKeyStr += "}";
QByteArray vpnKeyCompressed = escapeUnicode(vpnKeyStr).toUtf8();
vpnKeyCompressed = qCompress(vpnKeyCompressed, 6);
vpnKeyCompressed = vpnKeyCompressed.mid(4);
QByteArray signedData = AMNEZIA_CONFIG_SIGNATURE + vpnKeyCompressed;
return QString("vpn://%1").arg(QString(signedData.toBase64(QByteArray::Base64UrlEncoding)));
}
-2
View File
@@ -19,8 +19,6 @@ namespace apiUtils
apiDefs::ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
amnezia::ErrorCode checkNetworkReplyErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply);
QString getPremiumV1VpnKey(const QJsonObject &serverConfigObject);
}
#endif // APIUTILS_H
@@ -48,9 +48,6 @@ void CoreController::initModels()
m_sitesModel.reset(new SitesModel(m_settings, this));
m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
m_allowedDnsModel.reset(new AllowedDnsModel(m_settings, this));
m_engine->rootContext()->setContextProperty("AllowedDnsModel", m_allowedDnsModel.get());
m_appSplitTunnelingModel.reset(new AppSplitTunnelingModel(m_settings, this));
m_engine->rootContext()->setContextProperty("AppSplitTunnelingModel", m_appSplitTunnelingModel.get());
@@ -133,9 +130,6 @@ void CoreController::initControllers()
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
m_allowedDnsController.reset(new AllowedDnsController(m_settings, m_allowedDnsModel));
m_engine->rootContext()->setContextProperty("AllowedDnsController", m_allowedDnsController.get());
m_appSplitTunnelingController.reset(new AppSplitTunnelingController(m_settings, m_appSplitTunnelingModel));
m_engine->rootContext()->setContextProperty("AppSplitTunnelingController", m_appSplitTunnelingController.get());
@@ -148,9 +142,6 @@ void CoreController::initControllers()
m_apiConfigsController.reset(new ApiConfigsController(m_serversModel, m_apiServicesModel, m_settings));
m_engine->rootContext()->setContextProperty("ApiConfigsController", m_apiConfigsController.get());
m_apiPremV1MigrationController.reset(new ApiPremV1MigrationController(m_serversModel, m_settings, this));
m_engine->rootContext()->setContextProperty("ApiPremV1MigrationController", m_apiPremV1MigrationController.get());
}
void CoreController::initAndroidController()
@@ -223,9 +214,6 @@ void CoreController::initSignalHandlers()
initAutoConnectHandler();
initAmneziaDnsToggledHandler();
initPrepareConfigHandler();
initImportPremiumV2VpnKeyHandler();
initShowMigrationDrawerHandler();
initStrictKillSwitchHandler();
}
void CoreController::initNotificationHandler()
@@ -368,31 +356,6 @@ void CoreController::initPrepareConfigHandler()
});
}
void CoreController::initImportPremiumV2VpnKeyHandler()
{
connect(m_apiPremV1MigrationController.get(), &ApiPremV1MigrationController::importPremiumV2VpnKey, this, [this](const QString &vpnKey) {
m_importController->extractConfigFromData(vpnKey);
m_importController->importConfig();
emit m_apiPremV1MigrationController->migrationFinished();
});
}
void CoreController::initShowMigrationDrawerHandler()
{
QTimer::singleShot(1000, this, [this]() {
if (m_apiPremV1MigrationController->isPremV1MigrationReminderActive() && m_apiPremV1MigrationController->hasConfigsToMigration()) {
m_apiPremV1MigrationController->showMigrationDrawer();
}
});
}
void CoreController::initStrictKillSwitchHandler()
{
connect(m_settingsController.get(), &SettingsController::strictKillSwitchEnabledChanged, m_vpnConnection.get(),
&VpnConnection::onKillSwitchModeChanged);
}
QSharedPointer<PageController> CoreController::pageController() const
{
return m_pageController;
-9
View File
@@ -7,9 +7,7 @@
#include "ui/controllers/api/apiConfigsController.h"
#include "ui/controllers/api/apiSettingsController.h"
#include "ui/controllers/api/apiPremV1MigrationController.h"
#include "ui/controllers/appSplitTunnelingController.h"
#include "ui/controllers/allowedDnsController.h"
#include "ui/controllers/connectionController.h"
#include "ui/controllers/exportController.h"
#include "ui/controllers/focusController.h"
@@ -20,7 +18,6 @@
#include "ui/controllers/sitesController.h"
#include "ui/controllers/systemController.h"
#include "ui/models/allowed_dns_model.h"
#include "ui/models/containers_model.h"
#include "ui/models/languageModel.h"
#include "ui/models/protocols/cloakConfigModel.h"
@@ -83,9 +80,6 @@ private:
void initAutoConnectHandler();
void initAmneziaDnsToggledHandler();
void initPrepareConfigHandler();
void initImportPremiumV2VpnKeyHandler();
void initShowMigrationDrawerHandler();
void initStrictKillSwitchHandler();
QQmlApplicationEngine *m_engine {}; // TODO use parent child system here?
std::shared_ptr<Settings> m_settings;
@@ -108,11 +102,9 @@ private:
QScopedPointer<SitesController> m_sitesController;
QScopedPointer<SystemController> m_systemController;
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
QScopedPointer<AllowedDnsController> m_allowedDnsController;
QScopedPointer<ApiSettingsController> m_apiSettingsController;
QScopedPointer<ApiConfigsController> m_apiConfigsController;
QScopedPointer<ApiPremV1MigrationController> m_apiPremV1MigrationController;
QSharedPointer<ContainersModel> m_containersModel;
QSharedPointer<ContainersModel> m_defaultServerContainersModel;
@@ -120,7 +112,6 @@ private:
QSharedPointer<LanguageModel> m_languageModel;
QSharedPointer<ProtocolsModel> m_protocolsModel;
QSharedPointer<SitesModel> m_sitesModel;
QSharedPointer<AllowedDnsModel> m_allowedDnsModel;
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
QSharedPointer<ClientManagementModel> m_clientManagementModel;
+2 -44
View File
@@ -7,20 +7,14 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QUrl>
#include "QBlockCipher.h"
#include "QRsa.h"
#include "amnezia_application.h"
#include "core/api/apiUtils.h"
#include "core/networkUtilities.h"
#include "utilities.h"
#ifdef AMNEZIA_DESKTOP
#include "core/ipcclient.h"
#endif
namespace
{
namespace configKey
@@ -36,17 +30,10 @@ namespace
constexpr QLatin1String errorResponsePattern1("No active configuration found for");
constexpr QLatin1String errorResponsePattern2("No non-revoked public key found for");
constexpr QLatin1String errorResponsePattern3("Account not found.");
constexpr QLatin1String updateRequestResponsePattern("client version update is required");
}
GatewayController::GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
const bool isStrictKillSwitchEnabled, QObject *parent)
: QObject(parent),
m_gatewayEndpoint(gatewayEndpoint),
m_isDevEnvironment(isDevEnvironment),
m_requestTimeoutMsecs(requestTimeoutMsecs),
m_isStrictKillSwitchEnabled(isStrictKillSwitchEnabled)
GatewayController::GatewayController(const QString &gatewayEndpoint, bool isDevEnvironment, int requestTimeoutMsecs, QObject *parent)
: QObject(parent), m_gatewayEndpoint(gatewayEndpoint), m_isDevEnvironment(isDevEnvironment), m_requestTimeoutMsecs(requestTimeoutMsecs)
{
}
@@ -63,17 +50,6 @@ ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBo
request.setUrl(QString(endpoint).arg(m_gatewayEndpoint));
// bypass killSwitch exceptions for API-gateway
#ifdef AMNEZIA_DESKTOP
if (m_isStrictKillSwitchEnabled) {
QString host = QUrl(request.url()).host();
QString ip = NetworkUtilities::getIPAddress(host);
if (!ip.isEmpty()) {
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList { ip });
}
}
#endif
QNetworkReply *reply;
reply = amnApp->networkManager()->get(request);
@@ -125,17 +101,6 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api
request.setUrl(endpoint.arg(m_gatewayEndpoint));
// bypass killSwitch exceptions for API-gateway
#ifdef AMNEZIA_DESKTOP
if (m_isStrictKillSwitchEnabled) {
QString host = QUrl(request.url()).host();
QString ip = NetworkUtilities::getIPAddress(host);
if (!ip.isEmpty()) {
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList { ip });
}
}
#endif
QSimpleCrypto::QBlockCipher blockCipher;
QByteArray key = blockCipher.generatePrivateSalt(32);
QByteArray iv = blockCipher.generatePrivateSalt(32);
@@ -313,13 +278,6 @@ bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray
qDebug() << reply->error();
return true;
}
} else if (reply->error() == QNetworkReply::NetworkError::OperationNotImplementedError) {
if (responseBody.contains(updateRequestResponsePattern)) {
return false;
} else {
qDebug() << reply->error();
return true;
}
} else if (reply->error() != QNetworkReply::NetworkError::NoError) {
qDebug() << reply->error();
return true;
+1 -3
View File
@@ -15,8 +15,7 @@ class GatewayController : public QObject
Q_OBJECT
public:
explicit GatewayController(const QString &gatewayEndpoint, const bool isDevEnvironment, const int requestTimeoutMsecs,
const bool isStrictKillSwitchEnabled, QObject *parent = nullptr);
explicit GatewayController(const QString &gatewayEndpoint, bool isDevEnvironment, int requestTimeoutMsecs, QObject *parent = nullptr);
amnezia::ErrorCode get(const QString &endpoint, QByteArray &responseBody);
amnezia::ErrorCode post(const QString &endpoint, const QJsonObject apiPayload, QByteArray &responseBody);
@@ -31,7 +30,6 @@ private:
int m_requestTimeoutMsecs;
QString m_gatewayEndpoint;
bool m_isDevEnvironment = false;
bool m_isStrictKillSwitchEnabled = false;
};
#endif // GATEWAYCONTROLLER_H
-2
View File
@@ -117,8 +117,6 @@ namespace amnezia
ApiServicesMissingError = 1107,
ApiConfigLimitError = 1108,
ApiNotFoundError = 1109,
ApiMigrationError = 1110,
ApiUpdateRequestError = 1111,
// QFile errors
OpenError = 1200,
-2
View File
@@ -74,8 +74,6 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiServicesMissingError): errorMessage = QObject::tr("Missing list of available services"); break;
case (ErrorCode::ApiConfigLimitError): errorMessage = QObject::tr("The limit of allowed configurations per subscription has been exceeded"); break;
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;
// QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
-12
View File
@@ -12,7 +12,6 @@
#include <winsock.h>
#include <QNetworkInterface>
#include "qendian.h"
#include <QSettings>
#endif
#ifdef Q_OS_LINUX
#include <arpa/inet.h>
@@ -186,17 +185,6 @@ int NetworkUtilities::AdapterIndexTo(const QHostAddress& dst) {
return 0;
}
bool NetworkUtilities::checkIpv6Enabled() {
#ifdef Q_OS_WIN
QSettings RegHLM("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters",
QSettings::NativeFormat);
int ret = RegHLM.value("DisabledComponents", 0).toInt();
qDebug() << "Check for Windows disabled IPv6 return " << ret;
return (ret != 255);
#endif
return true;
}
#ifdef Q_OS_WIN
DWORD GetAdaptersAddressesWrapper(const ULONG Family,
const ULONG Flags,
+1 -1
View File
@@ -16,7 +16,6 @@ public:
static QString getStringBetween(const QString &s, const QString &a, const QString &b);
static bool checkIPv4Format(const QString &ip);
static bool checkIpSubnetFormat(const QString &ip);
static bool checkIpv6Enabled();
static QString getGatewayAndIface();
// Returns the Interface Index that could Route to dst
static int AdapterIndexTo(const QHostAddress& dst);
@@ -30,6 +29,7 @@ public:
static QString netMaskFromIpWithSubnet(const QString ip);
static QString ipAddressFromIpWithSubnet(const QString ip);
static QStringList summarizeRoutes(const QStringList &ips, const QString cidr);
};
+2 -4
View File
@@ -149,7 +149,8 @@ bool Daemon::activate(const InterfaceConfig& config) {
// set routing
for (const IPAddress& ip : config.m_allowedIPAddressRanges) {
if (!wgutils()->updateRoutePrefix(ip)) {
logger.debug() << "Routing configuration failed for" << ip.toString();
logger.debug() << "Routing configuration failed for"
<< logger.sensitive(ip.toString());
return false;
}
}
@@ -370,9 +371,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
return false;
}
if (!parseStringList(obj, "allowedDnsServers", config.m_allowedDnsServers)) {
return false;
}
config.m_killSwitchEnabled = QVariant(obj.value("killSwitchOption").toString()).toBool();
-7
View File
@@ -48,13 +48,6 @@ QJsonObject InterfaceConfig::toJson() const {
}
json.insert("excludedAddresses", jsExcludedAddresses);
QJsonArray jsAllowedDnsServers;
for (const QString& i : m_allowedDnsServers) {
jsAllowedDnsServers.append(QJsonValue(i));
}
json.insert("allowedDnsServers", jsAllowedDnsServers);
QJsonArray disabledApps;
for (const QString& i : m_vpnDisabledApps) {
disabledApps.append(QJsonValue(i));
-1
View File
@@ -38,7 +38,6 @@ class InterfaceConfig {
QList<IPAddress> m_allowedIPAddressRanges;
QStringList m_excludedAddresses;
QStringList m_vpnDisabledApps;
QStringList m_allowedDnsServers;
bool m_killSwitchEnabled;
#if defined(MZ_ANDROID) || defined(MZ_IOS)
QString m_installationId;
-3
View File
@@ -123,7 +123,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
int appSplitTunnelType = rawConfig.value(amnezia::config_key::appSplitTunnelType).toInt();
QJsonArray splitTunnelApps = rawConfig.value(amnezia::config_key::splitTunnelApps).toArray();
QJsonArray allowedDns = rawConfig.value(amnezia::config_key::allowedDnsServers).toArray();
QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject();
@@ -227,8 +226,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
json.insert("vpnDisabledApps", splitTunnelApps);
json.insert("allowedDnsServers", allowedDns);
json.insert(amnezia::config_key::killSwitchOption, rawConfig.value(amnezia::config_key::killSwitchOption));
if (protocolName == amnezia::config_key::awg) {
@@ -31,9 +31,7 @@ IPUtilsLinux::~IPUtilsLinux() {
}
bool IPUtilsLinux::addInterfaceIPs(const InterfaceConfig& config) {
bool ret = addIP4AddressToDevice(config);
addIP6AddressToDevice(config);
return ret;
return addIP4AddressToDevice(config) && addIP6AddressToDevice(config);
}
bool IPUtilsLinux::setMTUAndUp(const InterfaceConfig& config) {
@@ -97,7 +95,7 @@ bool IPUtilsLinux::addIP4AddressToDevice(const InterfaceConfig& config) {
// Set ifr to interface
int ret = ioctl(sockfd, SIOCSIFADDR, &ifr);
if (ret) {
logger.error() << "Failed to set IPv4: " << deviceAddr
logger.error() << "Failed to set IPv4: " << logger.sensitive(deviceAddr)
<< "error:" << strerror(errno);
return false;
}
@@ -138,7 +136,7 @@ bool IPUtilsLinux::addIP6AddressToDevice(const InterfaceConfig& config) {
// Set ifr6 to the interface
ret = ioctl(sockfd, SIOCSIFADDR, &ifr6);
if (ret && (errno != EEXIST)) {
logger.error() << "Failed to set IPv6: " << deviceAddr
logger.error() << "Failed to set IPv6: " << logger.sensitive(deviceAddr)
<< "error:" << strerror(errno);
return false;
}
@@ -455,6 +455,9 @@ void LinuxFirewall::updateDNSServers(const QStringList& servers)
void LinuxFirewall::updateAllowNets(const QStringList& servers)
{
static QStringList existingServers {};
existingServers = servers;
execute(QStringLiteral("iptables -F %1.110.allowNets").arg(kAnchorName));
for (const QString& rule : getAllowRule(servers))
execute(QStringLiteral("iptables -A %1.110.allowNets %2").arg(kAnchorName, rule));
@@ -17,8 +17,6 @@
#include "leakdetector.h"
#include "logger.h"
#include "killswitch.h"
constexpr const int WG_TUN_PROC_TIMEOUT = 5000;
constexpr const char* WG_RUNTIME_DIR = "/var/run/amneziawg";
@@ -184,7 +182,7 @@ bool WireguardUtilsLinux::deleteInterface() {
QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name"));
// double-check + ensure our firewall is installed and enabled
KillSwitch::instance()->disableKillSwitch();
LinuxFirewall::uninstall();
return true;
}
@@ -122,7 +122,7 @@ bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) {
// Set ifr to interface
int ret = ioctl(sockfd, SIOCAIFADDR, &ifr);
if (ret) {
logger.error() << "Failed to set IPv4: " << deviceAddr
logger.error() << "Failed to set IPv4: " << logger.sensitive(deviceAddr)
<< "error:" << strerror(errno);
return false;
}
@@ -162,7 +162,7 @@ bool IPUtilsMacos::addIP6AddressToDevice(const InterfaceConfig& config) {
// Set ifr to interface
int ret = ioctl(sockfd, SIOCAIFADDR_IN6, &ifr6);
if (ret) {
logger.error() << "Failed to set IPv6: " << deviceAddr
logger.error() << "Failed to set IPv6: " << logger.sensitive(deviceAddr)
<< "error:" << strerror(errno);
return false;
}
@@ -144,7 +144,7 @@ void MacosRouteMonitor::handleRtmDelete(const struct rt_msghdr* rtm,
for (const IPAddress& prefix : m_exclusionRoutes) {
if (prefix.address().protocol() == protocol) {
logger.debug() << "Removing exclusion route to"
<< prefix.toString();
<< logger.sensitive(prefix.toString());
rtmSendRoute(RTM_DELETE, prefix, rtm->rtm_index, nullptr);
}
}
@@ -259,7 +259,7 @@ void MacosRouteMonitor::handleRtmUpdate(const struct rt_msghdr* rtm,
for (const IPAddress& prefix : m_exclusionRoutes) {
if (prefix.address().protocol() == protocol) {
logger.debug() << "Updating exclusion route to"
<< prefix.toString();
<< logger.sensitive(prefix.toString());
rtmSendRoute(rtm_type, prefix, ifindex, addrlist[1].constData());
}
}
@@ -510,7 +510,8 @@ bool MacosRouteMonitor::deleteRoute(const IPAddress& prefix, int flags) {
}
bool MacosRouteMonitor::addExclusionRoute(const IPAddress& prefix) {
logger.debug() << "Adding exclusion route for" << prefix.toString();
logger.debug() << "Adding exclusion route for"
<< logger.sensitive(prefix.toString());
if (m_exclusionRoutes.contains(prefix)) {
logger.warning() << "Exclusion route already exists";
@@ -535,7 +536,8 @@ bool MacosRouteMonitor::addExclusionRoute(const IPAddress& prefix) {
}
bool MacosRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) {
logger.debug() << "Deleting exclusion route for" << prefix.toString();
logger.debug() << "Deleting exclusion route for"
<< logger.sensitive(prefix.toString());
m_exclusionRoutes.removeAll(prefix);
if (prefix.address().protocol() == QAbstractSocket::IPv4Protocol) {
@@ -16,8 +16,6 @@
#include "leakdetector.h"
#include "logger.h"
#include "killswitch.h"
constexpr const int WG_TUN_PROC_TIMEOUT = 5000;
constexpr const char* WG_RUNTIME_DIR = "/var/run/amneziawg";
@@ -182,7 +180,7 @@ bool WireguardUtilsMacos::deleteInterface() {
QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name"));
// double-check + ensure our firewall is installed and enabled
KillSwitch::instance()->disableKillSwitch();
MacOSFirewall::uninstall();
return true;
}
@@ -29,8 +29,6 @@
#include "logger.h"
#include "platforms/windows/windowsutils.h"
#include "killswitch.h"
#define IPV6_ADDRESS_SIZE 16
// ID for the Firewall Sublayer
@@ -182,29 +180,16 @@ bool WindowsFirewall::enableInterface(int vpnAdapterIndex) {
} \
}
logger.info() << "Enabling Killswitch Using Adapter:" << vpnAdapterIndex;
if (vpnAdapterIndex < 0)
{
IPAddress allv4("0.0.0.0/0");
if (!blockTrafficTo(allv4, MED_WEIGHT,
"Block Internet", "killswitch")) {
return false;
}
IPAddress allv6("::/0");
if (!blockTrafficTo(allv6, MED_WEIGHT,
"Block Internet", "killswitch")) {
return false;
}
} else
logger.info() << "Enabling firewall Using Adapter:" << vpnAdapterIndex;
FW_OK(allowTrafficOfAdapter(vpnAdapterIndex, MED_WEIGHT,
"Allow usage of VPN Adapter"));
"Allow usage of VPN Adapter"));
FW_OK(allowDHCPTraffic(MED_WEIGHT, "Allow DHCP Traffic"));
FW_OK(allowHyperVTraffic(MAX_WEIGHT, "Allow Hyper-V Traffic"));
FW_OK(allowHyperVTraffic(MED_WEIGHT, "Allow Hyper-V Traffic"));
FW_OK(allowTrafficForAppOnAll(getCurrentPath(), MAX_WEIGHT,
"Allow all for AmneziaVPN.exe"));
FW_OK(blockTrafficOnPort(53, MED_WEIGHT, "Block all DNS"));
FW_OK(allowLoopbackTraffic(MED_WEIGHT,
"Allow Loopback traffic on device %1"));
FW_OK(
allowLoopbackTraffic(MED_WEIGHT, "Allow Loopback traffic on device %1"));
logger.debug() << "Killswitch on! Rules:" << m_activeRules.length();
return true;
@@ -241,37 +226,6 @@ bool WindowsFirewall::enableLanBypass(const QList<IPAddress>& ranges) {
return true;
}
// Allow unprotected traffic sent to the following address ranges.
bool WindowsFirewall::allowTrafficRange(const QStringList& ranges) {
// Start the firewall transaction
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
if (result != ERROR_SUCCESS) {
disableKillSwitch();
return false;
}
auto cleanup = qScopeGuard([&] {
FwpmTransactionAbort0(m_sessionHandle);
disableKillSwitch();
});
for (const QString& addr : ranges) {
logger.debug() << "Allow killswitch exclude: " << addr;
if (!allowTrafficTo(QHostAddress(addr), HIGH_WEIGHT, "Allow killswitch bypass traffic")) {
return false;
}
}
result = FwpmTransactionCommit0(m_sessionHandle);
if (result != ERROR_SUCCESS) {
logger.error() << "FwpmTransactionCommit0 failed with error:" << result;
return false;
}
cleanup.dismiss();
return true;
}
bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
// Start the firewall transaction
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
@@ -308,20 +262,12 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
}
}
for (const QString& dns : config.m_allowedDnsServers) {
logger.debug() << "Allow DNS: " << dns;
if (!allowTrafficTo(QHostAddress(dns), 53, HIGH_WEIGHT,
"Allow DNS-Server", config.m_serverPublicKey)) {
return false;
}
}
if (!config.m_excludedAddresses.empty()) {
for (const QString& i : config.m_excludedAddresses) {
logger.debug() << "excludedAddresses range: " << i;
if (!allowTrafficTo(i, HIGH_WEIGHT,
"Allow Ecxlude route", config.m_serverPublicKey)) {
"Allow Ecxlude route", config.m_serverPublicKey)) {
return false;
}
}
@@ -367,41 +313,37 @@ bool WindowsFirewall::disablePeerTraffic(const QString& pubkey) {
}
bool WindowsFirewall::disableKillSwitch() {
return KillSwitch::instance()->disableKillSwitch();
}
bool WindowsFirewall::allowAllTraffic() {
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
auto cleanup = qScopeGuard([&] {
if (result != ERROR_SUCCESS) {
FwpmTransactionAbort0(m_sessionHandle);
}
});
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
auto cleanup = qScopeGuard([&] {
if (result != ERROR_SUCCESS) {
logger.error() << "FwpmTransactionBegin0 failed. Return value:.\n"
<< result;
return false;
FwpmTransactionAbort0(m_sessionHandle);
}
});
if (result != ERROR_SUCCESS) {
logger.error() << "FwpmTransactionBegin0 failed. Return value:.\n"
<< result;
return false;
}
for (const auto& filterID : m_peerRules.values()) {
FwpmFilterDeleteById0(m_sessionHandle, filterID);
}
for (const auto& filterID : m_peerRules.values()) {
FwpmFilterDeleteById0(m_sessionHandle, filterID);
}
for (const auto& filterID : qAsConst(m_activeRules)) {
FwpmFilterDeleteById0(m_sessionHandle, filterID);
}
for (const auto& filterID : qAsConst(m_activeRules)) {
FwpmFilterDeleteById0(m_sessionHandle, filterID);
}
// Commit!
result = FwpmTransactionCommit0(m_sessionHandle);
if (result != ERROR_SUCCESS) {
logger.error() << "FwpmTransactionCommit0 failed. Return value:.\n"
<< result;
return false;
}
m_peerRules.clear();
m_activeRules.clear();
logger.debug() << "Firewall Disabled!";
return true;
// Commit!
result = FwpmTransactionCommit0(m_sessionHandle);
if (result != ERROR_SUCCESS) {
logger.error() << "FwpmTransactionCommit0 failed. Return value:.\n"
<< result;
return false;
}
m_peerRules.clear();
m_activeRules.clear();
logger.debug() << "Firewall Disabled!";
return true;
}
bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
@@ -43,8 +43,6 @@ class WindowsFirewall final : public QObject {
bool enablePeerTraffic(const InterfaceConfig& config);
bool disablePeerTraffic(const QString& pubkey);
bool disableKillSwitch();
bool allowAllTraffic();
bool allowTrafficRange(const QStringList& ranges);
private:
static bool initSublayer();
@@ -303,7 +303,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) {
data->Age++;
continue;
}
logger.debug() << "Capturing route to" << prefix.toString();
logger.debug() << "Capturing route to"
<< logger.sensitive(prefix.toString());
// Clone the route and direct it into the VPN tunnel.
data = new MIB_IPFORWARD_ROW2;
@@ -353,7 +354,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) {
continue;
}
logger.debug() << "Removing route capture for" << i.key().toString();
logger.debug() << "Removing route capture for"
<< logger.sensitive(i.key().toString());
// Otherwise, this route is no longer in use.
DWORD result = DeleteIpForwardEntry2(data);
@@ -366,7 +368,8 @@ void WindowsRouteMonitor::updateCapturedRoutes(int family, void* ptable) {
}
bool WindowsRouteMonitor::addExclusionRoute(const IPAddress& prefix) {
logger.debug() << "Adding exclusion route for" << prefix.toString();
logger.debug() << "Adding exclusion route for"
<< logger.sensitive(prefix.toString());
// Silently ignore non-routeable addresses.
QHostAddress addr = prefix.address();
@@ -434,7 +437,7 @@ bool WindowsRouteMonitor::addExclusionRoute(const IPAddress& prefix) {
bool WindowsRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) {
logger.debug() << "Deleting exclusion route for"
<< prefix.address().toString();
<< logger.sensitive(prefix.address().toString());
MIB_IPFORWARD_ROW2* data = m_exclusionRoutes.take(prefix);
if (data == nullptr) {
@@ -444,7 +447,7 @@ bool WindowsRouteMonitor::deleteExclusionRoute(const IPAddress& prefix) {
DWORD result = DeleteIpForwardEntry2(data);
if ((result != ERROR_NOT_FOUND) && (result != NO_ERROR)) {
logger.error() << "Failed to delete route to"
<< prefix.toString()
<< logger.sensitive(prefix.toString())
<< "result:" << result;
}
@@ -462,7 +465,7 @@ void WindowsRouteMonitor::flushRouteTable(
DWORD result = DeleteIpForwardEntry2(data);
if ((result != ERROR_NOT_FOUND) && (result != NO_ERROR)) {
logger.error() << "Failed to delete route to"
<< i.key().toString()
<< logger.sensitive(i.key().toString())
<< "result:" << result;
}
delete data;
@@ -14,6 +14,8 @@
#include "leakdetector.h"
#include "logger.h"
#include "platforms/windows/windowscommons.h"
#include "windowsdaemon.h"
#include "windowsfirewall.h"
#pragma comment(lib, "iphlpapi.lib")
@@ -267,13 +269,6 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) {
if (result == ERROR_OBJECT_ALREADY_EXISTS) {
return true;
}
// Case for ipv6 route with disabled ipv6
if (prefix.address().protocol() == QAbstractSocket::IPv6Protocol
&& result == ERROR_NOT_FOUND) {
return true;
}
if (result != NO_ERROR) {
logger.error() << "Failed to create route to"
<< prefix.toString()
-5
View File
@@ -171,11 +171,6 @@ ErrorCode OpenVpnProtocol::start()
return lastError();
}
#ifdef AMNEZIA_DESKTOP
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList(NetworkUtilities::getIPAddress(
m_configData.value(amnezia::config_key::hostName).toString())));
#endif
// Detect default gateway
#ifdef Q_OS_MAC
QProcess p;
-2
View File
@@ -95,8 +95,6 @@ namespace amnezia
constexpr char splitTunnelApps[] = "splitTunnelApps";
constexpr char appSplitTunnelType[] = "appSplitTunnelType";
constexpr char allowedDnsServers[] = "allowedDnsServers";
constexpr char killSwitchOption[] = "killSwitchOption";
constexpr char crc[] = "crc";
+1 -9
View File
@@ -129,7 +129,6 @@
<file>ui/qml/Components/SettingsContainersListView.qml</file>
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
<file>ui/qml/Components/TransportProtoSelector.qml</file>
<file>ui/qml/Components/AddSitePanel.qml</file>
<file>ui/qml/Config/GlobalConfig.qml</file>
<file>ui/qml/Config/qmldir</file>
<file>ui/qml/Controls2/BackButtonType.qml</file>
@@ -144,9 +143,7 @@
<file>ui/qml/Controls2/DropDownType.qml</file>
<file>ui/qml/Controls2/FlickableType.qml</file>
<file>ui/qml/Controls2/Header2Type.qml</file>
<file>ui/qml/Controls2/BaseHeaderType.qml</file>
<file>ui/qml/Controls2/HeaderTypeWithButton.qml</file>
<file>ui/qml/Controls2/HeaderTypeWithSwitcher.qml</file>
<file>ui/qml/Controls2/HeaderType.qml</file>
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
<file>ui/qml/Controls2/ImageButtonType.qml</file>
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
@@ -202,8 +199,6 @@
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
<file>ui/qml/Pages2/PageSettingsKillSwitch.qml</file>
<file>ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml</file>
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
@@ -236,9 +231,6 @@
<file>ui/qml/Pages2/PageSettingsApiNativeConfigs.qml</file>
<file>ui/qml/Pages2/PageSettingsApiDevices.qml</file>
<file>images/controls/monitor.svg</file>
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
</qresource>
<qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file>
+2 -2
View File
@@ -1,7 +1,7 @@
#include "secure_qsettings.h"
#include "../client/3rd/QSimpleCrypto/src/include/QAead.h"
#include "../client/3rd/QSimpleCrypto/src/include/QBlockCipher.h"
#include "QAead.h"
#include "QBlockCipher.h"
#include "utilities.h"
#include <QDataStream>
#include <QDebug>
+1 -1
View File
@@ -6,7 +6,7 @@
#include <QObject>
#include <QSettings>
#include "../client/3rd/qtkeychain/qtkeychain/keychain.h"
#include "keychain.h"
class SecureQSettings : public QObject
{
-30
View File
@@ -443,16 +443,6 @@ void Settings::setKillSwitchEnabled(bool enabled)
setValue("Conf/killSwitchEnabled", enabled);
}
bool Settings::isStrictKillSwitchEnabled() const
{
return value("Conf/strictKillSwitchEnabled", false).toBool();
}
void Settings::setStrictKillSwitchEnabled(bool enabled)
{
setValue("Conf/strictKillSwitchEnabled", enabled);
}
QString Settings::getInstallationUuid(const bool needCreate)
{
auto uuid = value("Conf/installationUuid", "").toString();
@@ -558,23 +548,3 @@ void Settings::disableHomeAdLabel()
{
setValue("Conf/homeAdLabelVisible", false);
}
bool Settings::isPremV1MigrationReminderActive()
{
return value("Conf/premV1MigrationReminderActive", true).toBool();
}
void Settings::disablePremV1MigrationReminder()
{
setValue("Conf/premV1MigrationReminderActive", false);
}
QStringList Settings::allowedDnsServers() const
{
return value("Conf/allowedDnsServers").toStringList();
}
void Settings::setAllowedDnsServers(const QStringList &servers)
{
setValue("Conf/allowedDnsServers", servers);
}
-10
View File
@@ -213,10 +213,6 @@ public:
bool isKillSwitchEnabled() const;
void setKillSwitchEnabled(bool enabled);
bool isStrictKillSwitchEnabled() const;
void setStrictKillSwitchEnabled(bool enabled);
QString getInstallationUuid(const bool needCreate);
void resetGatewayEndpoint();
@@ -229,12 +225,6 @@ public:
bool isHomeAdLabelVisible();
void disableHomeAdLabel();
bool isPremV1MigrationReminderActive();
void disablePremV1MigrationReminder();
QStringList allowedDnsServers() const;
void setAllowedDnsServers(const QStringList &servers);
signals:
void saveLogsChanged(bool enabled);
void screenshotsEnabledChanged(bool enabled);
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
TextArea {
id: root
width: parent.width
topPadding: 16
leftPadding: 16
color: "#D7D8DB"
selectionColor: "#412102"
selectedTextColor: "#D7D8DB"
placeholderTextColor: "#878B91"
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
wrapMode: Text.Wrap
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: contextMenu.open()
}
ContextMenuType {
id: contextMenu
textObj: textField
}
}
@@ -1,101 +0,0 @@
#include "allowedDnsController.h"
#include <QFile>
#include <QStandardPaths>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include "systemController.h"
#include "core/networkUtilities.h"
#include "core/defs.h"
AllowedDnsController::AllowedDnsController(const std::shared_ptr<Settings> &settings,
const QSharedPointer<AllowedDnsModel> &allowedDnsModel,
QObject *parent)
: QObject(parent), m_settings(settings), m_allowedDnsModel(allowedDnsModel)
{
}
void AllowedDnsController::addDns(QString ip)
{
if (ip.isEmpty()) {
return;
}
if (!NetworkUtilities::ipAddressRegExp().match(ip).hasMatch()) {
emit errorOccurred(tr("The address does not look like a valid IP address"));
return;
}
if (m_allowedDnsModel->addDns(ip)) {
emit finished(tr("New DNS server added: %1").arg(ip));
} else {
emit errorOccurred(tr("DNS server already exists: %1").arg(ip));
}
}
void AllowedDnsController::removeDns(int index)
{
auto modelIndex = m_allowedDnsModel->index(index);
auto ip = m_allowedDnsModel->data(modelIndex, AllowedDnsModel::Roles::IpRole).toString();
m_allowedDnsModel->removeDns(modelIndex);
emit finished(tr("DNS server removed: %1").arg(ip));
}
void AllowedDnsController::importDns(const QString &fileName, bool replaceExisting)
{
QByteArray jsonData;
if (!SystemController::readFile(fileName, jsonData)) {
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
return;
}
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
if (jsonDocument.isNull()) {
emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
return;
}
if (!jsonDocument.isArray()) {
emit errorOccurred(tr("The JSON data is not an array in file: %1").arg(fileName));
return;
}
auto jsonArray = jsonDocument.array();
QStringList dnsServers;
for (auto jsonValue : jsonArray) {
auto ip = jsonValue.toString();
if (!NetworkUtilities::ipAddressRegExp().match(ip).hasMatch()) {
qDebug() << ip << " is not a valid IP address";
continue;
}
dnsServers.append(ip);
}
m_allowedDnsModel->addDnsList(dnsServers, replaceExisting);
emit finished(tr("Import completed"));
}
void AllowedDnsController::exportDns(const QString &fileName)
{
auto dnsServers = m_allowedDnsModel->getCurrentDnsServers();
QJsonArray jsonArray;
for (const auto &ip : dnsServers) {
jsonArray.append(ip);
}
QJsonDocument jsonDocument(jsonArray);
QByteArray jsonData = jsonDocument.toJson();
SystemController::saveFile(fileName, jsonData);
emit finished(tr("Export completed"));
}
@@ -1,35 +0,0 @@
#ifndef ALLOWEDDNSCONTROLLER_H
#define ALLOWEDDNSCONTROLLER_H
#include <QObject>
#include "settings.h"
#include "ui/models/allowed_dns_model.h"
class AllowedDnsController : public QObject
{
Q_OBJECT
public:
explicit AllowedDnsController(const std::shared_ptr<Settings> &settings,
const QSharedPointer<AllowedDnsModel> &allowedDnsModel,
QObject *parent = nullptr);
public slots:
void addDns(QString ip);
void removeDns(int index);
void importDns(const QString &fileName, bool replaceExisting);
void exportDns(const QString &fileName);
signals:
void errorOccurred(const QString &errorMessage);
void finished(const QString &message);
void saveFile(const QString &fileName, const QString &data);
private:
std::shared_ptr<Settings> m_settings;
QSharedPointer<AllowedDnsModel> m_allowedDnsModel;
};
#endif // ALLOWEDDNSCONTROLLER_H
@@ -63,8 +63,7 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
return false;
}
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
@@ -77,7 +76,6 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
apiPayload[configKey::serverCountryCode] = serverCountryCode;
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/native_config"), apiPayload, responseBody);
@@ -96,8 +94,7 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
@@ -110,7 +107,6 @@ bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
apiPayload[configKey::serverCountryCode] = serverCountryCode;
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_native_config"), apiPayload, responseBody);
@@ -144,8 +140,7 @@ void ApiConfigsController::copyVpnKeyToClipboard()
bool ApiConfigsController::fillAvailableServices()
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
QJsonObject apiPayload;
apiPayload[configKey::osVersion] = QSysInfo::productType();
@@ -176,8 +171,7 @@ bool ApiConfigsController::importServiceFromGateway()
return false;
}
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto installationUuid = m_settings->getInstallationUuid(true);
auto userCountryCode = m_apiServicesModel->getCountryCode();
@@ -190,7 +184,6 @@ bool ApiConfigsController::importServiceFromGateway()
apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::uuid] = installationUuid;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
@@ -218,8 +211,7 @@ bool ApiConfigsController::importServiceFromGateway()
bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
bool reloadServiceConfig)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
@@ -236,7 +228,6 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::uuid] = installationUuid;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
if (!newCountryCode.isEmpty()) {
apiPayload[configKey::serverCountryCode] = newCountryCode;
@@ -283,8 +274,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
QThread::msleep(10);
#endif
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
auto installationUuid = m_settings->getInstallationUuid(true);
@@ -314,8 +304,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
bool ApiConfigsController::deactivateDevice()
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverIndex = m_serversModel->getProcessedServerIndex();
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
@@ -334,7 +323,6 @@ bool ApiConfigsController::deactivateDevice()
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[configKey::uuid] = m_settings->getInstallationUuid(true);
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
@@ -351,8 +339,7 @@ bool ApiConfigsController::deactivateDevice()
bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverIndex = m_serversModel->getProcessedServerIndex();
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
@@ -371,7 +358,6 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[configKey::uuid] = uuid;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
@@ -1,133 +0,0 @@
#include "apiPremV1MigrationController.h"
#include <QEventLoop>
#include <QTimer>
#include "core/api/apiDefs.h"
#include "core/api/apiUtils.h"
#include "core/controllers/gatewayController.h"
ApiPremV1MigrationController::ApiPremV1MigrationController(const QSharedPointer<ServersModel> &serversModel,
const std::shared_ptr<Settings> &settings, QObject *parent)
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
{
}
bool ApiPremV1MigrationController::hasConfigsToMigration()
{
QJsonArray vpnKeys;
auto serversCount = m_serversModel->getServersCount();
for (size_t i = 0; i < serversCount; i++) {
auto serverConfigObject = m_serversModel->getServerConfig(i);
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV1) {
continue;
}
QString vpnKey = apiUtils::getPremiumV1VpnKey(serverConfigObject);
vpnKeys.append(vpnKey);
}
if (!vpnKeys.isEmpty()) {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload["configs"] = vpnKeys;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/is-active-subscription"), apiPayload, responseBody);
auto migrationsStatus = QJsonDocument::fromJson(responseBody).object();
for (const auto &migrationStatus : migrationsStatus) {
if (migrationStatus == "not_found") {
return true;
}
}
}
return false;
}
void ApiPremV1MigrationController::getSubscriptionList(const QString &email)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload[apiDefs::key::email] = email;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/subscription-list"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) {
m_email = email;
m_subscriptionsModel = QJsonDocument::fromJson(responseBody).array();
if (m_subscriptionsModel.isEmpty()) {
emit noSubscriptionToMigrate();
return;
}
emit subscriptionsModelChanged();
} else {
emit errorOccurred(ErrorCode::ApiMigrationError);
}
}
QJsonArray ApiPremV1MigrationController::getSubscriptionModel()
{
return m_subscriptionsModel;
}
void ApiPremV1MigrationController::sendMigrationCode(const int subscriptionIndex)
{
QEventLoop wait;
QTimer::singleShot(1000, &wait, &QEventLoop::quit);
wait.exec();
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload[apiDefs::key::email] = m_email;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/migration-code"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) {
m_subscriptionIndex = subscriptionIndex;
emit otpSuccessfullySent();
} else {
emit errorOccurred(ErrorCode::ApiMigrationError);
}
}
void ApiPremV1MigrationController::migrate(const QString &migrationCode)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload;
apiPayload[apiDefs::key::email] = m_email;
apiPayload[apiDefs::key::orderId] = m_subscriptionsModel.at(m_subscriptionIndex).toObject().value(apiDefs::key::id).toString();
apiPayload[apiDefs::key::migrationCode] = migrationCode;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/prem-v1/migrate"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) {
auto responseObject = QJsonDocument::fromJson(responseBody).object();
QString premiumV2VpnKey = responseObject.value(apiDefs::key::config).toString();
emit importPremiumV2VpnKey(premiumV2VpnKey);
} else {
emit errorOccurred(ErrorCode::ApiMigrationError);
}
}
bool ApiPremV1MigrationController::isPremV1MigrationReminderActive()
{
return m_settings->isPremV1MigrationReminderActive();
}
void ApiPremV1MigrationController::disablePremV1MigrationReminder()
{
m_settings->disablePremV1MigrationReminder();
}
@@ -1,50 +0,0 @@
#ifndef APIPREMV1MIGRATIONCONTROLLER_H
#define APIPREMV1MIGRATIONCONTROLLER_H
#include <QObject>
#include "ui/models/servers_model.h"
class ApiPremV1MigrationController : public QObject
{
Q_OBJECT
public:
ApiPremV1MigrationController(const QSharedPointer<ServersModel> &serversModel, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
Q_PROPERTY(QJsonArray subscriptionsModel READ getSubscriptionModel NOTIFY subscriptionsModelChanged)
public slots:
bool hasConfigsToMigration();
void getSubscriptionList(const QString &email);
QJsonArray getSubscriptionModel();
void sendMigrationCode(const int subscriptionIndex);
void migrate(const QString &migrationCode);
bool isPremV1MigrationReminderActive();
void disablePremV1MigrationReminder();
signals:
void subscriptionsModelChanged();
void otpSuccessfullySent();
void importPremiumV2VpnKey(const QString &vpnKey);
void errorOccurred(ErrorCode errorCode);
void showMigrationDrawer();
void migrationFinished();
void noSubscriptionToMigrate();
private:
QSharedPointer<ServersModel> m_serversModel;
std::shared_ptr<Settings> m_settings;
QJsonArray m_subscriptionsModel;
int m_subscriptionIndex;
QString m_email;
};
#endif // APIPREMV1MIGRATIONCONTROLLER_H
@@ -5,7 +5,6 @@
#include "core/api/apiUtils.h"
#include "core/controllers/gatewayController.h"
#include "version.h"
namespace
{
@@ -49,8 +48,7 @@ bool ApiSettingsController::getAccountInfo(bool reload)
wait.exec();
}
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), requestTimeoutMsecs);
auto processedIndex = m_serversModel->getProcessedServerIndex();
auto serverConfig = m_serversModel->getServerConfig(processedIndex);
@@ -61,14 +59,15 @@ bool ApiSettingsController::getAccountInfo(bool reload)
apiPayload[configKey::userCountryCode] = apiConfig.value(configKey::userCountryCode).toString();
apiPayload[configKey::serviceType] = apiConfig.value(configKey::serviceType).toString();
apiPayload[configKey::authData] = authData;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
if (apiUtils::isPremiumServer(serverConfig)) {
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
}
QJsonObject accountInfo = QJsonDocument::fromJson(responseBody).object();
+9 -9
View File
@@ -665,27 +665,27 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
const QRegularExpression regExp { "(\\w+-\\w+|\\w+)" };
const size_t dangerousTagsMaxCount = 3;
// https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/script-options.rst
QStringList dangerousTags {
"up", "tls-verify", "ipchange", "client-connect", "route-up", "route-pre-down", "client-disconnect", "down", "learn-address", "auth-user-pass-verify"
};
QStringList maliciousStrings;
QStringList lines = protocolConfigJson.split('\n', Qt::SkipEmptyParts);
for (const QString &rawLine : lines) {
QString line = rawLine.trimmed();
QString command = line.section(' ', 0, 0, QString::SectionSkipEmpty);
if (dangerousTags.contains(command, Qt::CaseInsensitive)) {
maliciousStrings << rawLine;
QStringList lines = protocolConfigJson.replace("\r", "").split("\n");
for (const QString &l : lines) {
QRegularExpressionMatch match = regExp.match(l);
if (dangerousTags.contains(match.captured(0))) {
maliciousStrings << l;
}
}
m_maliciousWarningText = tr("This configuration contains an OpenVPN setup. OpenVPN configurations can include malicious "
"scripts, so only add it if you fully trust the provider of this config. ");
if (!maliciousStrings.isEmpty()) {
if (maliciousStrings.size() >= dangerousTagsMaxCount) {
m_maliciousWarningText.push_back(tr("<br>In the imported configuration, potentially dangerous lines were found:"));
for (const auto &string : maliciousStrings) {
m_maliciousWarningText.push_back(QString("<br><i>%1</i>").arg(string));
+1 -67
View File
@@ -363,8 +363,7 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
QJsonObject config;
Proto mainProto = ContainerProps::defaultProtocol(container);
const auto &protocols = ContainerProps::protocolsForContainer(container);
for (const auto &protocol : protocols) {
for (auto protocol : ContainerProps::protocolsForContainer(container)) {
QJsonObject containerConfig;
if (protocol == mainProto) {
containerConfig.insert(config_key::port, port);
@@ -388,7 +387,6 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
}
}
containerConfig[config_key::subnet_address] = serverConfigMap.value("Address").remove("/24");
containerConfig[config_key::junkPacketCount] = serverConfigMap.value(config_key::junkPacketCount);
containerConfig[config_key::junkPacketMinSize] = serverConfigMap.value(config_key::junkPacketMinSize);
containerConfig[config_key::junkPacketMaxSize] = serverConfigMap.value(config_key::junkPacketMaxSize);
@@ -400,25 +398,6 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
serverConfigMap.value(config_key::underloadPacketMagicHeader);
containerConfig[config_key::transportPacketMagicHeader] =
serverConfigMap.value(config_key::transportPacketMagicHeader);
} else if (protocol == Proto::WireGuard) {
QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
protocols::wireguard::serverConfigPath, errorCode);
QMap<QString, QString> serverConfigMap;
auto serverConfigLines = serverConfig.split("\n");
for (auto &line : serverConfigLines) {
auto trimmedLine = line.trimmed();
if (trimmedLine.startsWith("[") && trimmedLine.endsWith("]")) {
continue;
} else {
QStringList parts = trimmedLine.split(" = ");
if (parts.count() == 2) {
serverConfigMap.insert(parts[0].trimmed(), parts[1].trimmed());
}
}
}
containerConfig[config_key::subnet_address] = serverConfigMap.value("Address").remove("/24");
} else if (protocol == Proto::Sftp) {
stdOut.clear();
script = QString("sudo docker inspect --format '{{.Config.Cmd}}' %1").arg(name);
@@ -453,51 +432,6 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
containerConfig.insert(config_key::userName, userName);
containerConfig.insert(config_key::password, password);
}
} else if (protocol == Proto::Xray) {
QString currentConfig = serverController->getTextFileFromContainer(
container, credentials, amnezia::protocols::xray::serverConfigPath, errorCode);
QJsonDocument doc = QJsonDocument::fromJson(currentConfig.toUtf8());
qDebug() << doc;
if (doc.isNull() || !doc.isObject()) {
logger.error() << "Failed to parse server config JSON";
errorCode = ErrorCode::InternalError;
return errorCode;
}
QJsonObject serverConfig = doc.object();
if (!serverConfig.contains("inbounds")) {
logger.error() << "Server config missing 'inbounds' field";
errorCode = ErrorCode::InternalError;
return errorCode;
}
QJsonArray inbounds = serverConfig["inbounds"].toArray();
if (inbounds.isEmpty()) {
logger.error() << "Server config has empty 'inbounds' array";
errorCode = ErrorCode::InternalError;
return errorCode;
}
QJsonObject inbound = inbounds[0].toObject();
if (!inbound.contains("streamSettings")) {
logger.error() << "Inbound missing 'streamSettings' field";
errorCode = ErrorCode::InternalError;
return errorCode;
}
QJsonObject streamSettings = inbound["streamSettings"].toObject();
QJsonObject realitySettings = streamSettings["realitySettings"].toObject();
if (!realitySettings.contains("serverNames")) {
logger.error() << "Settings missing 'clients' field";
errorCode = ErrorCode::InternalError;
return errorCode;
}
QString siteName = realitySettings["serverNames"][0].toString();
qDebug() << siteName;
containerConfig.insert(config_key::site, siteName);
}
config.insert(config_key::container, ContainerProps::containerToString(container));
+1 -3
View File
@@ -31,15 +31,13 @@ namespace PageLoader
PageSettingsLogging,
PageSettingsSplitTunneling,
PageSettingsAppSplitTunneling,
PageSettingsKillSwitch,
PageSettingsApiServerInfo,
PageSettingsApiAvailableCountries,
PageSettingsApiSupport,
PageSettingsApiInstructions,
PageSettingsApiNativeConfigs,
PageSettingsApiDevices,
PageSettingsKillSwitchExceptions,
PageServiceSftpSettings,
PageServiceTorWebsiteSettings,
PageServiceDnsSettings,
@@ -245,23 +245,6 @@ bool SettingsController::isKillSwitchEnabled()
void SettingsController::toggleKillSwitch(bool enable)
{
m_settings->setKillSwitchEnabled(enable);
emit killSwitchEnabledChanged();
if (enable == false) {
emit strictKillSwitchEnabledChanged(false);
} else {
emit strictKillSwitchEnabledChanged(isStrictKillSwitchEnabled());
}
}
bool SettingsController::isStrictKillSwitchEnabled()
{
return m_settings->isStrictKillSwitchEnabled();
}
void SettingsController::toggleStrictKillSwitch(bool enable)
{
m_settings->setStrictKillSwitchEnabled(enable);
emit strictKillSwitchEnabledChanged(enable);
}
bool SettingsController::isNotificationPermissionGranted()
@@ -24,8 +24,6 @@ public:
Q_PROPERTY(QString secondaryDns READ getSecondaryDns WRITE setSecondaryDns NOTIFY secondaryDnsChanged)
Q_PROPERTY(bool isLoggingEnabled READ isLoggingEnabled WRITE toggleLogging NOTIFY loggingStateChanged)
Q_PROPERTY(bool isNotificationPermissionGranted READ isNotificationPermissionGranted NOTIFY onNotificationStateChanged)
Q_PROPERTY(bool isKillSwitchEnabled READ isKillSwitchEnabled WRITE toggleKillSwitch NOTIFY killSwitchEnabledChanged)
Q_PROPERTY(bool strictKillSwitchEnabled READ isStrictKillSwitchEnabled WRITE toggleStrictKillSwitch NOTIFY strictKillSwitchEnabledChanged)
Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled)
Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged)
@@ -77,9 +75,6 @@ public slots:
bool isKillSwitchEnabled();
void toggleKillSwitch(bool enable);
bool isStrictKillSwitchEnabled();
void toggleStrictKillSwitch(bool enable);
bool isNotificationPermissionGranted();
void requestNotificationPermission();
@@ -103,8 +98,6 @@ signals:
void primaryDnsChanged();
void secondaryDnsChanged();
void loggingStateChanged();
void killSwitchEnabledChanged();
void strictKillSwitchEnabledChanged(bool enabled);
void restoreBackupFinished();
void changeSettingsFinished(const QString &finishedMessage);
-86
View File
@@ -1,86 +0,0 @@
#include "allowed_dns_model.h"
AllowedDnsModel::AllowedDnsModel(std::shared_ptr<Settings> settings, QObject *parent)
: QAbstractListModel(parent), m_settings(settings)
{
fillDnsServers();
}
int AllowedDnsModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_dnsServers.size();
}
QVariant AllowedDnsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
return QVariant();
switch (role) {
case IpRole:
return m_dnsServers.at(index.row());
default:
return QVariant();
}
}
bool AllowedDnsModel::addDns(const QString &ip)
{
if (m_dnsServers.contains(ip)) {
return false;
}
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_dnsServers.append(ip);
m_settings->setAllowedDnsServers(m_dnsServers);
endInsertRows();
return true;
}
void AllowedDnsModel::addDnsList(const QStringList &dnsServers, bool replaceExisting)
{
beginResetModel();
if (replaceExisting) {
m_dnsServers.clear();
}
for (const QString &ip : dnsServers) {
if (!m_dnsServers.contains(ip)) {
m_dnsServers.append(ip);
}
}
m_settings->setAllowedDnsServers(m_dnsServers);
endResetModel();
}
void AllowedDnsModel::removeDns(QModelIndex index)
{
if (!index.isValid() || index.row() >= m_dnsServers.size()) {
return;
}
beginRemoveRows(QModelIndex(), index.row(), index.row());
m_dnsServers.removeAt(index.row());
m_settings->setAllowedDnsServers(m_dnsServers);
endRemoveRows();
}
QStringList AllowedDnsModel::getCurrentDnsServers()
{
return m_dnsServers;
}
QHash<int, QByteArray> AllowedDnsModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[IpRole] = "ip";
return roles;
}
void AllowedDnsModel::fillDnsServers()
{
m_dnsServers = m_settings->allowedDnsServers();
}
-37
View File
@@ -1,37 +0,0 @@
#ifndef ALLOWEDDNSMODEL_H
#define ALLOWEDDNSMODEL_H
#include <QAbstractListModel>
#include "settings.h"
class AllowedDnsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
IpRole = Qt::UserRole + 1
};
explicit AllowedDnsModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
public slots:
bool addDns(const QString &ip);
void addDnsList(const QStringList &dnsServers, bool replaceExisting);
void removeDns(QModelIndex index);
QStringList getCurrentDnsServers();
protected:
QHash<int, QByteArray> roleNames() const override;
private:
void fillDnsServers();
std::shared_ptr<Settings> m_settings;
QStringList m_dnsServers;
};
#endif // ALLOWEDDNSMODEL_H
+2 -2
View File
@@ -69,7 +69,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
"Access all websites and online resources. Speeds up to %1 Mbps.")
.arg(speed);
} else if (serviceType == serviceType::amneziaFree) {
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.");
QString description = tr("AmneziaFree provides free unlimited access to a basic set of web sites, such as Facebook, Instagram, Twitter (X), Discord, Telegram, and others. 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>");
@@ -82,7 +82,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
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.");
return tr("AmneziaFree provides free unlimited access to a basic set of web sites, such as Facebook, Instagram, Twitter (X), Discord, Telegram, and others. YouTube is not included in the free plan.");
}
}
case IsServiceAvailableRole: {
-19
View File
@@ -348,25 +348,6 @@ void ServersModel::removeServer()
endResetModel();
}
void ServersModel::removeServer(const int serverIndex)
{
beginResetModel();
m_settings->removeServer(serverIndex);
m_servers = m_settings->serversArray();
if (m_settings->defaultServerIndex() == serverIndex) {
setDefaultServerIndex(0);
} else if (m_settings->defaultServerIndex() > serverIndex) {
setDefaultServerIndex(m_settings->defaultServerIndex() - 1);
}
if (m_settings->serversCount() == 0) {
setDefaultServerIndex(-1);
}
setProcessedServerIndex(m_defaultServerIndex);
endResetModel();
}
QHash<int, QByteArray> ServersModel::roleNames() const
{
QHash<int, QByteArray> roles;
-1
View File
@@ -90,7 +90,6 @@ public slots:
void addServer(const QJsonObject &server);
void editServer(const QJsonObject &server, const int serverIndex);
void removeServer();
void removeServer(const int serverIndex);
QJsonObject getServerConfig(const int serverIndex);
-73
View File
@@ -1,73 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
Item {
id: root
property bool enabled: true
property string placeholderText: ""
property alias textField: searchField.textField
signal addClicked(string text)
signal moreClicked()
implicitWidth: 360
implicitHeight: 96
Rectangle {
id: background
anchors.fill: parent
color: "#0E0F12"
opacity: 0.85
z: -1
}
RowLayout {
id: addSiteButton
enabled: root.enabled
spacing: 2
anchors {
fill: parent
topMargin: 16
leftMargin: 16
rightMargin: 16
bottomMargin: 24
}
TextFieldWithHeaderType {
id: searchField
Layout.fillWidth: true
rightButtonClickedOnEnter: true
textField.placeholderText: root.placeholderText
buttonImageSource: "qrc:/images/controls/plus.svg"
clickedFunc: function() {
root.addClicked(textField.text)
textField.text = ""
}
}
ImageButtonType {
id: addSiteButtonImage
implicitWidth: 56
implicitHeight: 56
image: "qrc:/images/controls/more-vertical.svg"
imageColor: AmneziaStyle.color.paleGray
onClicked: root.moreClicked()
Keys.onReturnPressed: addSiteButtonImage.clicked()
Keys.onEnterPressed: addSiteButtonImage.clicked()
}
}
}
@@ -1,194 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtCore
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
DrawerType2 {
id: root
expandedHeight: parent.height * 0.9
Connections {
target: ApiPremV1MigrationController
function onErrorOccurred(error, goToPageHome) {
PageController.showErrorMessage(error)
root.closeTriggered()
}
}
expandedStateContent: Item {
implicitHeight: root.expandedHeight
ListViewType {
id: listView
anchors.fill: parent
model: 1 // fake model to force the ListView to be created without a model
snapMode: ListView.NoSnap
header: ColumnLayout {
width: listView.width
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Switch to the new Amnezia Premium subscription")
}
}
delegate: ColumnLayout {
width: listView.width
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
horizontalAlignment: Text.AlignLeft
textFormat: Text.RichText
text: {
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>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>"
str += qsTr("Old keys will be deactivated after switching.")
}
}
TextFieldWithHeaderType {
id: emailLabel
Layout.fillWidth: true
borderColor: AmneziaStyle.color.mutedGray
headerTextColor: AmneziaStyle.color.paleGray
headerText: qsTr("Email")
textField.placeholderText: qsTr("mail@example.com")
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
}
Connections {
target: ApiPremV1MigrationController
function onNoSubscriptionToMigrate() {
emailLabel.errorText = qsTr("No old format subscriptions for a given email")
}
}
}
CaptionTextType {
Layout.fillWidth: true
Layout.topMargin: 16
color: AmneziaStyle.color.mutedGray
text: qsTr("Enter the email you used for your current subscription")
}
ApiPremV1SubListDrawer {
id: apiPremV1SubListDrawer
parent: root
anchors.fill: parent
}
OtpCodeDrawer {
id: otpCodeDrawer
parent: root
anchors.fill: parent
}
BasicButtonType {
id: yesButton
Layout.fillWidth: true
Layout.topMargin: 32
text: qsTr("Continue")
clickedFunc: function() {
PageController.showBusyIndicator(true)
ApiPremV1MigrationController.getSubscriptionList(emailLabel.textField.text)
PageController.showBusyIndicator(false)
}
}
BasicButtonType {
id: noButton
Layout.fillWidth: true
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
text: qsTr("Remind me later")
clickedFunc: function() {
root.closeTriggered()
}
}
BasicButtonType {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: 32
Layout.bottomMargin: 32
implicitHeight: 32
defaultColor: "transparent"
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
textColor: AmneziaStyle.color.vibrantRed
text: qsTr("Don't remind me again")
clickedFunc: function() {
var headerText = qsTr("No more reminders? You can always switch to the new format in the server settings")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
ApiPremV1MigrationController.disablePremV1MigrationReminder()
root.closeTriggered()
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
}
}
}
}
@@ -1,89 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
id: root
Connections {
target: ApiPremV1MigrationController
function onSubscriptionsModelChanged() {
if (ApiPremV1MigrationController.subscriptionsModel.length > 1) {
root.openTriggered()
} else {
sendMigrationCode(0)
}
}
}
function sendMigrationCode(index) {
PageController.showBusyIndicator(true)
ApiPremV1MigrationController.sendMigrationCode(index)
root.closeTriggered()
PageController.showBusyIndicator(false)
}
expandedHeight: parent.height * 0.9
expandedStateContent: Item {
implicitHeight: root.expandedHeight
ListViewType {
id: listView
anchors.fill: parent
model: ApiPremV1MigrationController.subscriptionsModel
header: ColumnLayout {
width: listView.width
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Choose Subscription")
}
}
delegate: Item {
implicitWidth: listView.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
id: server
Layout.fillWidth: true
text: qsTr("Order ID: ") + modelData.id
descriptionText: qsTr("Purchase Date: ") + Qt.formatDateTime(new Date(modelData.created_at), "dd.MM.yyyy hh:mm")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
sendMigrationCode(index)
}
}
DividerType {}
}
}
}
}
}
@@ -18,8 +18,7 @@ ListView {
property var selectedText
width: rootWidth
anchors.top: parent.top
anchors.bottom: parent.bottom
height: contentItem.height
clip: true
snapMode: ListView.SnapToItem
@@ -1,77 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Style 1.0
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
DrawerType2 {
id: root
Connections {
target: ApiPremV1MigrationController
function onOtpSuccessfullySent() {
root.openTriggered()
}
}
expandedHeight: parent.height * 0.6
expandedStateContent: Item {
implicitHeight: root.expandedHeight
ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
Header2Type {
id: header
Layout.fillWidth: true
Layout.topMargin: 20
headerText: qsTr("OTP code was sent to your email")
}
TextFieldWithHeaderType {
id: otpFiled
borderColor: AmneziaStyle.color.mutedGray
headerTextColor: AmneziaStyle.color.paleGray
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("OTP Code")
textField.maximumLength: 30
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Continue")
clickedFunc: function() {
PageController.showBusyIndicator(true)
ApiPremV1MigrationController.migrate(otpFiled.textField.text)
PageController.showBusyIndicator(false)
root.closeTriggered()
}
}
}
}
}
+8 -12
View File
@@ -1,5 +1,3 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@@ -41,7 +39,7 @@ DrawerType2 {
Layout.rightMargin: 16
Layout.leftMargin: 16
text: root.headerText
text: headerText
}
ParagraphTextType {
@@ -50,7 +48,7 @@ DrawerType2 {
Layout.rightMargin: 16
Layout.leftMargin: 16
text: root.descriptionText
text: descriptionText
}
BasicButtonType {
@@ -60,11 +58,11 @@ DrawerType2 {
Layout.rightMargin: 16
Layout.leftMargin: 16
text: root.yesButtonText
text: yesButtonText
clickedFunc: function() {
if (root.yesButtonFunction && typeof root.yesButtonFunction === "function") {
root.yesButtonFunction()
if (yesButtonFunction && typeof yesButtonFunction === "function") {
yesButtonFunction()
}
}
}
@@ -82,13 +80,11 @@ DrawerType2 {
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
visible: root.noButtonText !== ""
text: root.noButtonText
text: noButtonText
clickedFunc: function() {
if (root.noButtonFunction && typeof root.noButtonFunction === "function") {
root.noButtonFunction()
if (noButtonFunction && typeof noButtonFunction === "function") {
noButtonFunction()
}
}
}
@@ -1,45 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Style 1.0
import "TextTypes"
Item {
id: root
property string headerText
property int headerTextMaximumLineCount: 2
property int headerTextElide: Qt.ElideRight
property string descriptionText
property alias headerRow: headerRow
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
ColumnLayout {
id: content
anchors.fill: parent
RowLayout {
id: headerRow
Header1TextType {
id: header
Layout.fillWidth: true
text: root.headerText
maximumLineCount: root.headerTextMaximumLineCount
elide: root.headerTextElide
}
}
ParagraphTextType {
id: description
Layout.topMargin: 16
Layout.fillWidth: true
text: root.descriptionText
color: AmneziaStyle.color.mutedGray
visible: root.descriptionText !== ""
}
}
}
-1
View File
@@ -239,7 +239,6 @@ Item {
sourceComponent: root.listView
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
+86
View File
@@ -0,0 +1,86 @@
import QtQuick
import QtQuick.Layouts
import Style 1.0
import "TextTypes"
Item {
id: root
property string actionButtonImage
property var actionButtonFunction
property alias actionButton: headerActionButton
property string headerText
property int headerTextMaximumLineCount: 2
property int headerTextElide: Qt.ElideRight
property string descriptionText
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
ColumnLayout {
id: content
anchors.fill: parent
RowLayout {
Header1TextType {
id: header
Layout.fillWidth: true
text: root.headerText
maximumLineCount: root.headerTextMaximumLineCount
elide: root.headerTextElide
}
ImageButtonType {
id: headerActionButton
implicitWidth: 40
implicitHeight: 40
Layout.alignment: Qt.AlignRight
image: root.actionButtonImage
imageColor: AmneziaStyle.color.paleGray
visible: image ? true : false
onClicked: {
if (actionButtonFunction && typeof actionButtonFunction === "function") {
actionButtonFunction()
}
}
}
}
ParagraphTextType {
id: description
Layout.topMargin: 16
Layout.fillWidth: true
text: root.descriptionText
color: AmneziaStyle.color.mutedGray
visible: root.descriptionText !== ""
}
}
Keys.onEnterPressed: {
if (actionButtonFunction && typeof actionButtonFunction === "function") {
actionButtonFunction()
}
}
Keys.onReturnPressed: {
if (actionButtonFunction && typeof actionButtonFunction === "function") {
actionButtonFunction()
}
}
}
@@ -1,44 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Style 1.0
BaseHeaderType {
id: root
property string actionButtonImage
property var actionButtonFunction
property alias actionButton: headerActionButton
Component.onCompleted: {
headerRow.children.push(headerActionButton)
}
ImageButtonType {
id: headerActionButton
implicitWidth: 40
implicitHeight: 40
Layout.alignment: Qt.AlignRight
image: root.actionButtonImage
imageColor: AmneziaStyle.color.paleGray
visible: image ? true : false
onClicked: {
if (actionButtonFunction && typeof actionButtonFunction === "function") {
actionButtonFunction()
}
}
}
Keys.onEnterPressed: {
if (actionButtonFunction && typeof actionButtonFunction === "function") {
actionButtonFunction()
}
}
Keys.onReturnPressed: {
if (actionButtonFunction && typeof actionButtonFunction === "function") {
actionButtonFunction()
}
}
}
@@ -1,28 +0,0 @@
import QtQuick
import QtQuick.Layouts
import Style 1.0
BaseHeaderType {
id: root
property var switcherFunction
property bool showSwitcher: false
property alias switcher: headerSwitcher
Component.onCompleted: {
headerRow.children.push(headerSwitcher)
}
SwitcherType {
id: headerSwitcher
Layout.alignment: Qt.AlignRight
visible: root.showSwitcher
onToggled: {
if (switcherFunction && typeof switcherFunction === "function") {
switcherFunction(checked)
}
}
}
}
@@ -20,11 +20,7 @@ RadioButton {
property string selectedColor: AmneziaStyle.color.transparent
property string textColor: AmneziaStyle.color.paleGray
property string textDisabledColor: AmneziaStyle.color.mutedGray
property string selectedTextColor: AmneziaStyle.color.goldenApricot
property string selectedTextDisabledColor: AmneziaStyle.color.burntOrange
property string descriptionColor: AmneziaStyle.color.mutedGray
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
property string borderFocusedColor: AmneziaStyle.color.paleGray
property int borderFocusedWidth: 1
@@ -34,12 +30,6 @@ RadioButton {
property bool isFocusable: true
property string radioButtonInnerCirclePressedSource: "qrc:/images/controls/radio-button-inner-circle-pressed.png"
property string radioButtonInnerCircleSource: "qrc:/images/controls/radio-button-inner-circle.png"
property string radioButtonPressedSource: "qrc:/images/controls/radio-button-pressed.svg"
property string radioButtonDefaultSource: "qrc:/images/controls/radio-button.svg"
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
@@ -104,15 +94,14 @@ RadioButton {
if (showImage) {
return imageSource
} else if (root.pressed) {
return root.radioButtonInnerCirclePressedSource
return "qrc:/images/controls/radio-button-inner-circle-pressed.png"
} else if (root.checked) {
return root.radioButtonInnerCircleSource
return "qrc:/images/controls/radio-button-inner-circle.png"
}
return ""
}
opacity: root.enabled ? 1.0 : 0.3
anchors.centerIn: parent
width: 24
@@ -124,13 +113,12 @@ RadioButton {
if (showImage) {
return ""
} else if (root.pressed || root.checked) {
return root.radioButtonPressedSource
return "qrc:/images/controls/radio-button-pressed.svg"
} else {
return root.radioButtonDefaultSource
return "qrc:/images/controls/radio-button.svg"
}
}
opacity: root.enabled ? 1.0 : 0.3
anchors.centerIn: parent
width: 24
@@ -160,11 +148,10 @@ RadioButton {
elide: root.textElide
color: {
if (root.enabled) {
return root.checked ? selectedTextColor : textColor
} else {
return root.checked ? selectedTextDisabledColor : textDisabledColor
if (root.checked) {
return selectedTextColor
}
return textColor
}
Layout.fillWidth: true
@@ -177,7 +164,7 @@ RadioButton {
CaptionTextType {
id: description
color: root.enabled ? root.descriptionColor : root.descriptionDisabledColor
color: AmneziaStyle.color.mutedGray
text: root.descriptionText
visible: root.descriptionText !== ""
@@ -190,7 +177,6 @@ RadioButton {
MouseArea {
anchors.fill: root
cursorShape: Qt.PointingHandCursor
preventStealing: false
enabled: false
}
}
+1 -1
View File
@@ -56,7 +56,7 @@ PageType {
anchors.rightMargin: 16
anchors.leftMargin: 16
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 20
+1 -1
View File
@@ -39,7 +39,7 @@ PageType {
header: ColumnLayout {
width: listView.width
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
-30
View File
@@ -33,31 +33,6 @@ PageType {
}
}
Connections {
target: ApiPremV1MigrationController
function onMigrationFinished() {
apiPremV1MigrationDrawer.closeTriggered()
var headerText = qsTr("You've successfully switched to the new Amnezia Premium subscription!")
var descriptionText = qsTr("Old keys will no longer work. Please use your new subscription key to connect. \nThank you for staying with us!")
var yesButtonText = qsTr("Continue")
var noButtonText = ""
var yesButtonFunction = function() {
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
function onShowMigrationDrawer() {
apiPremV1MigrationDrawer.openTriggered()
}
}
Item {
objectName: "homeColumnItem"
@@ -454,9 +429,4 @@ PageType {
}
}
}
ApiPremV1MigrationDrawer {
id: apiPremV1MigrationDrawer
anchors.fill: parent
}
}
@@ -91,7 +91,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("AmneziaWG settings")
@@ -91,7 +91,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("AmneziaWG settings")
@@ -76,7 +76,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("Cloak settings")
@@ -75,7 +75,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("OpenVPN settings")
+1 -1
View File
@@ -32,7 +32,7 @@ PageType {
id: backButton
}
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
@@ -78,7 +78,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("Shadowsocks settings")
@@ -85,7 +85,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("WG settings")
@@ -77,7 +77,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("WG settings")
}
@@ -75,7 +75,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("XRay settings")
}
@@ -93,9 +93,9 @@ PageType {
var tmpText = textField.text
tmpText = tmpText.toLocaleLowerCase()
if (tmpText.startsWith("https://")) {
var indexHttps = tmpText.indexOf("https://")
if (indexHttps === 0) {
tmpText = textField.text.substring(8)
site = tmpText
} else {
site = textField.text
}
@@ -43,7 +43,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
@@ -85,7 +85,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
@@ -77,7 +77,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
@@ -217,7 +217,7 @@ PageType {
}
}
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("SOCKS5 settings")
@@ -54,7 +54,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
+1 -1
View File
@@ -29,7 +29,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
Layout.topMargin: 24
@@ -69,7 +69,7 @@ PageType {
Layout.topMargin: 20
}
HeaderTypeWithButton {
HeaderType {
id: headerContent
objectName: "headerContent"
@@ -135,6 +135,12 @@ PageType {
}
}
MouseArea {
anchors.fill: containerRadioButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
Keys.onEnterPressed: {
if (checkable) {
checked = true
@@ -35,7 +35,7 @@ PageType {
id: backButton
}
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
@@ -77,7 +77,7 @@ PageType {
}
var headerText = qsTr("Are you sure you want to unlink this device?")
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing \"Reload API config\" in subscription settings on device.")
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
@@ -91,7 +91,7 @@ PageType {
id: backButton
}
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
@@ -38,7 +38,7 @@ PageType {
id: backButton
}
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
@@ -93,7 +93,7 @@ PageType {
Layout.topMargin: 20
}
HeaderTypeWithButton {
HeaderType {
id: headerContent
objectName: "headerContent"
@@ -333,7 +333,7 @@ PageType {
clickedFunc: function() {
var headerText = qsTr("Are you sure you want to unlink this device?")
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing \"Reload API config\" in subscription settings on device.")
var descriptionText = qsTr("This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
@@ -71,7 +71,7 @@ PageType {
id: backButton
}
BaseHeaderType {
HeaderType {
id: header
Layout.fillWidth: true
@@ -88,7 +88,6 @@ PageType {
LabelWithButtonType {
Layout.fillWidth: true
visible: link !== ""
text: title
descriptionText: description
rightImageSource: "qrc:/images/controls/external-link.svg"
@@ -79,22 +79,29 @@ PageType {
id: backButton
}
HeaderTypeWithSwitcher {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
RowLayout {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
headerText: qsTr("App split tunneling")
headerText: qsTr("App split tunneling")
enabled: root.pageEnabled
showSwitcher: true
switcher {
checked: AppSplitTunnelingModel.isTunnelingEnabled
enabled: root.pageEnabled
}
switcherFunction: function(checked) {
AppSplitTunnelingModel.toggleSplitTunneling(checked)
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
SwitcherType {
id: switcher
Layout.fillWidth: true
Layout.rightMargin: 16
enabled: root.pageEnabled
checked: AppSplitTunnelingModel.isTunnelingEnabled
onToggled: {
AppSplitTunnelingModel.toggleSplitTunneling(checked)
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
}
}
}
@@ -38,7 +38,7 @@ PageType {
spacing: 0
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
+1 -1
View File
@@ -60,7 +60,7 @@ PageType {
spacing: 16
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("Back up your configuration")
@@ -36,7 +36,7 @@ PageType {
anchors.left: parent.left
anchors.right: parent.right
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
@@ -94,7 +94,9 @@ PageType {
}
}
DividerType {}
DividerType {
visible: root.isAppSplitTinnelingEnabled
}
LabelWithButtonType {
id: splitTunnelingButton2
@@ -117,20 +119,29 @@ PageType {
visible: root.isAppSplitTinnelingEnabled
}
LabelWithButtonType {
id: killSwitchButton
SwitcherType {
id: killSwitchSwitcher
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.margins: 16
text: qsTr("KillSwitch")
descriptionText: qsTr("Blocks network connections without VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.")
parentFlickable: fl
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
checked: SettingsController.isKillSwitchEnabled()
checkable: !ConnectionController.isConnected
onCheckedChanged: {
if (checked !== SettingsController.isKillSwitchEnabled()) {
SettingsController.toggleKillSwitch(checked)
}
}
onClicked: {
if (!checkable) {
PageController.showNotificationMessage(qsTr("Cannot change KillSwitch settings during active connection"))
}
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ PageType {
spacing: 16
BaseHeaderType {
HeaderType {
Layout.fillWidth: true
headerText: qsTr("DNS servers")
@@ -1,126 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import PageEnum 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Config"
PageType {
id: root
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
}
FlickableType {
id: fl
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout {
id: content
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
HeaderTypeWithSwitcher {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("KillSwitch")
descriptionText: qsTr("Enable to ensure network traffic goes through a secure VPN tunnel, preventing accidental exposure of your IP and DNS queries if the connection drops")
showSwitcher: true
switcher {
checked: SettingsController.isKillSwitchEnabled
enabled: !ConnectionController.isConnected
}
switcherFunction: function(checked) {
if (!ConnectionController.isConnected) {
SettingsController.isKillSwitchEnabled = checked
} else {
PageController.showNotificationMessage(qsTr("KillSwitch settings cannot be changed during an active connection"))
switcher.checked = SettingsController.isKillSwitchEnabled
}
}
}
VerticalRadioButton {
id: softKillSwitch
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
checked: !SettingsController.strictKillSwitchEnabled
text: qsTr("Soft KillSwitch")
descriptionText: qsTr("Internet access is blocked if the VPN disconnects unexpectedly")
onClicked: function() {
SettingsController.strictKillSwitchEnabled = false
}
}
DividerType {}
VerticalRadioButton {
id: strictKillSwitch
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: false
enabled: false //SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
checked: SettingsController.strictKillSwitchEnabled
text: qsTr("Strict KillSwitch")
descriptionText: qsTr("Internet connection is blocked even when VPN is turned off manually or hasn't started")
onClicked: function() {
var headerText = qsTr("Just a little heads-up")
var descriptionText = qsTr("If the VPN disconnects or drops while Strict KillSwitch is enabled, internet access will be blocked. To restore access, reconnect VPN or disable/change the KillSwitch.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
SettingsController.strictKillSwitchEnabled = true
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {
visible: false
}
LabelWithButtonType {
Layout.topMargin: 32
Layout.fillWidth: true
enabled: true
text: qsTr("DNS Exceptions")
descriptionText: qsTr("DNS servers listed here will remain accessible when KillSwitch is active.")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsKillSwitchExceptions)
}
}
}
}
}
@@ -1,302 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import QtCore
import SortFilterProxyModel 0.2
import PageEnum 1.0
import ProtocolEnum 1.0
import ContainerProps 1.0
import Style 1.0
import "./"
import "../Controls2"
import "../Controls2/TextTypes"
import "../Config"
import "../Components"
PageType {
id: root
property bool pageEnabled: true
ColumnLayout {
id: header
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
BackButtonType {
id: backButton
}
BaseHeaderType {
enabled: root.pageEnabled
Layout.fillWidth: true
Layout.leftMargin: 16
headerText: qsTr("DNS Exceptions")
descriptionText: qsTr("DNS servers listed here will remain accessible when KillSwitch is active")
}
}
ListView {
id: listView
anchors.top: header.bottom
anchors.topMargin: 16
anchors.bottom: parent.bottom
width: parent.width
enabled: root.pageEnabled
property bool isFocusable: true
cacheBuffer: 200
displayMarginBeginning: 40
displayMarginEnd: 40
ScrollBar.vertical: ScrollBarType { }
footer: Item {
width: listView.width
height: addSitePanel.height
}
footerPositioning: ListView.InlineFooter
model: SortFilterProxyModel {
id: dnsFilterModel
sourceModel: AllowedDnsModel
filters: [
RegExpFilter {
roleName: "ip"
pattern: ".*" + addSitePanel.textField.text + ".*"
caseSensitivity: Qt.CaseInsensitive
}
]
}
clip: true
reuseItems: true
delegate: ColumnLayout {
id: delegateContent
width: listView.width
LabelWithButtonType {
id: site
Layout.fillWidth: true
text: ip
rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
var headerText = qsTr("Delete ") + ip + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
AllowedDnsController.removeDns(dnsFilterModel.mapToSource(index))
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
site.rightButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {}
}
}
AddSitePanel {
id: addSitePanel
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
enabled: root.pageEnabled
placeholderText: qsTr("IPv4 address")
onAddClicked: function(text) {
PageController.showBusyIndicator(true)
AllowedDnsController.addDns(text)
PageController.showBusyIndicator(false)
}
onMoreClicked: {
moreActionsDrawer.openTriggered()
}
}
DrawerType2 {
id: moreActionsDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.4375
expandedStateContent: ColumnLayout {
id: moreActionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import / Export addresses")
}
LabelWithButtonType {
id: importSitesButton
Layout.fillWidth: true
text: qsTr("Import")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() {
importSitesDrawer.openTriggered()
}
}
DividerType {}
LabelWithButtonType {
id: exportSitesButton
Layout.fillWidth: true
text: qsTr("Save address list")
clickedFunction: function() {
var fileName = ""
if (GC.isMobile()) {
fileName = "amnezia_killswitch_exceptions.json"
} else {
fileName = SystemController.getFileName(qsTr("Save addresses"),
qsTr("Address files (*.json)"),
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_killswitch_exceptions",
true,
".json")
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
AllowedDnsController.exportDns(fileName)
moreActionsDrawer.closeTriggered()
PageController.showBusyIndicator(false)
}
}
}
DividerType {}
}
}
DrawerType2 {
id: importSitesDrawer
anchors.fill: parent
expandedHeight: parent.height * 0.4375
expandedStateContent: Item {
implicitHeight: importSitesDrawer.expandedHeight
BackButtonType {
id: importSitesDrawerBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
importSitesDrawer.closeTriggered()
}
}
FlickableType {
anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: importSitesDrawerContent.height
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type {
Layout.fillWidth: true
Layout.margins: 16
headerText: qsTr("Import address list")
}
LabelWithButtonType {
id: importSitesButton2
Layout.fillWidth: true
text: qsTr("Replace address list")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open address file"),
qsTr("Address files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
}
}
DividerType {}
LabelWithButtonType {
id: importSitesButton3
Layout.fillWidth: true
text: qsTr("Add imported addresses to existing ones")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open address file"),
qsTr("Address files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
AllowedDnsController.importDns(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.closeTriggered()
moreActionsDrawer.closeTriggered()
}
DividerType {}
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More