diff --git a/CMakeLists.txt b/CMakeLists.txt index 506946eb2..80f5e2601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR) set(PROJECT AmneziaVPN) -project(${PROJECT} VERSION 4.8.4.3 +project(${PROJECT} VERSION 4.8.4.4 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 1080) +set(APP_ANDROID_VERSION_CODE 1081) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(MZ_PLATFORM_NAME "linux") diff --git a/client/3rd-prebuilt b/client/3rd-prebuilt index e555c78bc..efad1a5b5 160000 --- a/client/3rd-prebuilt +++ b/client/3rd-prebuilt @@ -1 +1 @@ -Subproject commit e555c78bcf44070d5c88bcca54480732c9164f18 +Subproject commit efad1a5b5cb8e8ab61e49ccdca18c9090a0da8d3 diff --git a/client/configurators/wireguard_configurator.cpp b/client/configurators/wireguard_configurator.cpp index 1bca973d8..696999985 100644 --- a/client/configurators/wireguard_configurator.cpp +++ b/client/configurators/wireguard_configurator.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -19,13 +20,17 @@ #include "settings.h" #include "utilities.h" -WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings, const QSharedPointer &serverController, - bool isAwg, QObject *parent) +WireguardConfigurator::WireguardConfigurator(std::shared_ptr settings, + const QSharedPointer &serverController, bool isAwg, + QObject *parent) : ConfiguratorBase(settings, serverController, parent), m_isAwg(isAwg) { - m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath; - m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath; - m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath; + m_serverConfigPath = + m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath; + m_serverPublicKeyPath = + m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath; + m_serverPskKeyPath = + m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath; m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template : ProtocolScriptType::wireguard_template; m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard; @@ -63,9 +68,31 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys() return connData; } +QList WireguardConfigurator::getIpsFromConf(const QString &input) +{ + QRegularExpression regex("AllowedIPs = (\\d+\\.\\d+\\.\\d+\\.\\d+)"); + QRegularExpressionMatchIterator matchIterator = regex.globalMatch(input); + + QList ips; + + while (matchIterator.hasNext()) { + QRegularExpressionMatch match = matchIterator.next(); + const QString address_string { match.captured(1) }; + const QHostAddress address { address_string }; + if (address.isNull()) { + qWarning() << "Couldn't recognize the ip address: " << address_string; + } else { + ips << address; + } + } + + return ips; +} + WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container, - const QJsonObject &containerConfig, ErrorCode &errorCode) + const QJsonObject &containerConfig, + ErrorCode &errorCode) { WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys(); connData.host = credentials.hostName; @@ -76,65 +103,45 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon return connData; } - // Get list of already created clients (only IP addresses) - QString nextIpNumber; - { - QString script = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath); - QString stdOut; - auto cbReadStdOut = [&](const QString &data, libssh::Client &) { - stdOut += data + "\n"; - return ErrorCode::NoError; - }; + QString getIpsScript = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath); + QString stdOut; + auto cbReadStdOut = [&](const QString &data, libssh::Client &) { + stdOut += data + "\n"; + return ErrorCode::NoError; + }; - errorCode = m_serverController->runContainerScript(credentials, container, script, cbReadStdOut); - if (errorCode != ErrorCode::NoError) { - return connData; - } + errorCode = m_serverController->runContainerScript(credentials, container, getIpsScript, cbReadStdOut); + if (errorCode != ErrorCode::NoError) { + return connData; + } + auto ips = getIpsFromConf(stdOut); - stdOut.replace("AllowedIPs = ", ""); - stdOut.replace("/32", ""); - QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts); - - // remove extra IPs from each line for case when user manually edited the wg0.conf - // and added there more IPs for route his itnernal networks, like: - // ... - // AllowedIPs = 10.8.1.6/32, 192.168.1.0/24, 192.168.2.0/24, ... - // ... - // without this code - next IP would be 1 if last item in 'ips' has format above - QStringList vpnIps; - for (const auto &ip : ips) { - vpnIps.append(ip.split(",", Qt::SkipEmptyParts).first().trimmed()); - } - ips = vpnIps; - - // Calc next IP address - if (ips.isEmpty()) { - nextIpNumber = "2"; + QHostAddress nextIp = [&] { + QHostAddress result; + QHostAddress lastIp; + if (ips.empty()) { + lastIp.setAddress(containerConfig.value(m_protocolName) + .toObject() + .value(config_key::subnet_address) + .toString(protocols::wireguard::defaultSubnetAddress)); } else { - int next = ips.last().split(".").last().toInt() + 1; - if (next > 254) { - errorCode = ErrorCode::AddressPoolError; - return connData; - } - nextIpNumber = QString::number(next); + lastIp = ips.last(); } - } - - QString subnetIp = containerConfig.value(m_protocolName).toObject().value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress); - { - QStringList l = subnetIp.split(".", Qt::SkipEmptyParts); - if (l.isEmpty()) { - errorCode = ErrorCode::AddressPoolError; - return connData; + quint8 lastOctet = static_cast(lastIp.toIPv4Address()); + switch (lastOctet) { + case 254: result.setAddress(lastIp.toIPv4Address() + 3); break; + case 255: result.setAddress(lastIp.toIPv4Address() + 2); break; + default: result.setAddress(lastIp.toIPv4Address() + 1); break; } - l.removeLast(); - l.append(nextIpNumber); - connData.clientIP = l.join("."); - } + return result; + }(); + + connData.clientIP = nextIp.toString(); // Get keys - connData.serverPubKey = m_serverController->getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode); + connData.serverPubKey = + m_serverController->getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode); connData.serverPubKey.replace("\n", ""); if (errorCode != ErrorCode::NoError) { return connData; @@ -161,10 +168,12 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon return connData; } - QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'").arg(m_serverConfigPath); + QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'") + .arg(m_serverConfigPath); errorCode = m_serverController->runScript( - credentials, m_serverController->replaceVars(script, m_serverController->genVarsForScript(credentials, container))); + credentials, + m_serverController->replaceVars(script, m_serverController->genVarsForScript(credentials, container))); return connData; } @@ -173,8 +182,8 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials const QJsonObject &containerConfig, ErrorCode &errorCode) { QString scriptData = amnezia::scriptData(m_configTemplate, container); - QString config = - m_serverController->replaceVars(scriptData, m_serverController->genVarsForScript(credentials, container, containerConfig)); + QString config = m_serverController->replaceVars( + scriptData, m_serverController->genVarsForScript(credentials, container, containerConfig)); ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode); if (errorCode != ErrorCode::NoError) { @@ -208,16 +217,16 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials return QJsonDocument(jConfig).toJson(); } -QString WireguardConfigurator::processConfigWithLocalSettings(const QPair &dns, const bool isApiConfig, - QString &protocolConfigString) +QString WireguardConfigurator::processConfigWithLocalSettings(const QPair &dns, + const bool isApiConfig, QString &protocolConfigString) { processConfigWithDnsSettings(dns, protocolConfigString); return protocolConfigString; } -QString WireguardConfigurator::processConfigWithExportSettings(const QPair &dns, const bool isApiConfig, - QString &protocolConfigString) +QString WireguardConfigurator::processConfigWithExportSettings(const QPair &dns, + const bool isApiConfig, QString &protocolConfigString) { processConfigWithDnsSettings(dns, protocolConfigString); diff --git a/client/configurators/wireguard_configurator.h b/client/configurators/wireguard_configurator.h index 22e8a8beb..a4302e3ed 100644 --- a/client/configurators/wireguard_configurator.h +++ b/client/configurators/wireguard_configurator.h @@ -1,6 +1,7 @@ #ifndef WIREGUARD_CONFIGURATOR_H #define WIREGUARD_CONFIGURATOR_H +#include #include #include @@ -12,8 +13,8 @@ class WireguardConfigurator : public ConfiguratorBase { Q_OBJECT public: - WireguardConfigurator(std::shared_ptr settings, const QSharedPointer &serverController, bool isAwg, - QObject *parent = nullptr); + WireguardConfigurator(std::shared_ptr settings, const QSharedPointer &serverController, + bool isAwg, QObject *parent = nullptr); struct ConnectionData { @@ -26,15 +27,18 @@ public: QString port; }; - QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, - ErrorCode &errorCode); + QString createConfig(const ServerCredentials &credentials, DockerContainer container, + const QJsonObject &containerConfig, ErrorCode &errorCode); - QString processConfigWithLocalSettings(const QPair &dns, const bool isApiConfig, QString &protocolConfigString); - QString processConfigWithExportSettings(const QPair &dns, const bool isApiConfig, QString &protocolConfigString); + QString processConfigWithLocalSettings(const QPair &dns, const bool isApiConfig, + QString &protocolConfigString); + QString processConfigWithExportSettings(const QPair &dns, const bool isApiConfig, + QString &protocolConfigString); static ConnectionData genClientKeys(); private: + QList getIpsFromConf(const QString &input); ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, ErrorCode &errorCode); diff --git a/client/core/controllers/gatewayController.cpp b/client/core/controllers/gatewayController.cpp index ba4a8d366..be42ad4de 100644 --- a/client/core/controllers/gatewayController.cpp +++ b/client/core/controllers/gatewayController.cpp @@ -26,6 +26,10 @@ namespace constexpr char apiPayload[] = "api_payload"; constexpr char keyPayload[] = "key_payload"; } + + constexpr QLatin1String errorResponsePattern1("No active configuration found for"); + constexpr QLatin1String errorResponsePattern2("No non-revoked public key found for"); + constexpr QLatin1String errorResponsePattern3("Account not found."); } GatewayController::GatewayController(const QString &gatewayEndpoint, bool isDevEnvironment, int requestTimeoutMsecs, QObject *parent) @@ -194,16 +198,16 @@ QStringList GatewayController::getProxyUrls() QList sslErrors; QNetworkReply *reply; - QStringList proxyStorageUrl; + QStringList proxyStorageUrls; if (m_isDevEnvironment) { - proxyStorageUrl = QStringList { DEV_S3_ENDPOINT }; + proxyStorageUrls = QString(DEV_S3_ENDPOINT).split(", "); } else { - proxyStorageUrl = QStringList { PROD_S3_ENDPOINT }; + proxyStorageUrls = QString(PROD_S3_ENDPOINT).split(", "); } QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY; - for (const auto &proxyStorageUrl : proxyStorageUrl) { + for (const auto &proxyStorageUrl : proxyStorageUrls) { request.setUrl(proxyStorageUrl); reply = amnApp->networkManager()->get(request); @@ -262,7 +266,16 @@ bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray } else if (responseBody.contains("html")) { qDebug() << "The response contains an html tag"; return true; - } else if (reply->error() == QNetworkReply::NetworkError::NoError && checkEncryption) { + } else if (reply->error() == QNetworkReply::NetworkError::ContentNotFoundError) { + if (responseBody.contains(errorResponsePattern1) || responseBody.contains(errorResponsePattern2) + || responseBody.contains(errorResponsePattern3)) { + return false; + } else { + return true; + } + } else if (reply->error() != QNetworkReply::NetworkError::NoError) { + return true; + } else if (checkEncryption) { try { QSimpleCrypto::QBlockCipher blockCipher; static_cast(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt)); diff --git a/client/core/controllers/serverController.cpp b/client/core/controllers/serverController.cpp index 7219ff7d4..ee639ae98 100644 --- a/client/core/controllers/serverController.cpp +++ b/client/core/controllers/serverController.cpp @@ -709,7 +709,7 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential QString transportProto = containerConfig.value(config_key::transport_proto).toString(defaultTransportProto); // TODO reimplement with netstat - QString script = QString("which lsof &>/dev/null || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port); + QString script = QString("which lsof > /dev/null 2>&1 || true && sudo lsof -i -P -n 2>/dev/null | grep -E ':%1 ").arg(port); for (auto &port : fixedPorts) { script = script.append("|:%1").arg(port); } diff --git a/client/platforms/ios/ScreenProtection.swift b/client/platforms/ios/ScreenProtection.swift index 1355dc13d..200cf0cbb 100644 --- a/client/platforms/ios/ScreenProtection.swift +++ b/client/platforms/ios/ScreenProtection.swift @@ -14,10 +14,15 @@ extension UIApplication { var keyWindows: [UIWindow] { connectedScenes .compactMap { + guard let windowScene = $0 as? UIWindowScene else { return nil } if #available(iOS 15.0, *) { - ($0 as? UIWindowScene)?.keyWindow + guard let keywindow = windowScene.keyWindow else { + windowScene.windows.first?.makeKey() + return windowScene.windows.first + } + return keywindow } else { - ($0 as? UIWindowScene)?.windows.first { $0.isKeyWindow } + return windowScene.windows.first { $0.isKeyWindow } } } } diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts index 1aa62f890..ddf6a2129 100644 --- a/client/translations/amneziavpn_ru_RU.ts +++ b/client/translations/amneziavpn_ru_RU.ts @@ -6,7 +6,7 @@ Amnezia Premium - for access to any website - Amnezia Premium - для доступа к любым сайтам + Amnezia Premium - для доступа к любым сайтам @@ -15,37 +15,37 @@ Active - + Активна Inactive - + Не активна %1 out of %2 - + %1 из %2 Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online resources. Speeds up to 200 Mbps - + Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Доступ ко всем сайтам и онлайн-ресурсам. Скорость — до 200 Мбит/с Free unlimited access to a basic set of websites such as Facebook, Instagram, Twitter (X), Discord, Telegram and more. YouTube is not included in the free plan. - + Бесплатный неограниченный доступ к базовому набору сайтов и приложений, таким как Facebook, Instagram, Twitter (X), Discord, Telegram и другим. YouTube не включен в бесплатный тариф. amnezia_free_support_bot - + amnezia_premium_support_bot - + @@ -53,17 +53,17 @@ %1 installed successfully. - %1 успешно установлен. + %1 успешно установлен. API config reloaded - Конфигурация API перезагружена + Конфигурация API перезагружена Successfully changed the country of connection to %1 - Изменение страны подключения на %1 + Страна подключения изменена на %1 @@ -92,18 +92,18 @@ Amnezia Premium is VPN for comfortable work, downloading large files and watching videos in 8K resolution. Works for any sites with no restrictions. Speed up to %1 MBit/s. Unlimited traffic. - + Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Скорость до %1 Мбит/с. Безлимитный трафик. 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. - + AmneziaFree предоставляет бесплатный неограниченный доступ к базовому набору сайтов и приложений, таким как Facebook, Instagram, Twitter (X), Discord, Telegram и другим. YouTube не включен в бесплатный тариф. Amnezia Premium is VPN for comfortable work, downloading large files and watching videos in 8K resolution. Works for any sites with no restrictions. - + Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Работает для любых сайтов без ограничений. @@ -562,12 +562,12 @@ Already installed containers were found on the server. All installed containers AmneziaWG settings - Настройки AmneziaWG + Настройки AmneziaWG MTU - MTU + MTU @@ -577,7 +577,7 @@ Already installed containers were found on the server. All installed containers Port - Порт + Порт @@ -592,7 +592,7 @@ Already installed containers were found on the server. All installed containers Only the settings for this device will be changed - Будут изменены настройки только для этого устройства. + Будут изменены настройки только для этого устройства @@ -1036,12 +1036,12 @@ Already installed containers were found on the server. All installed containers WG settings - Настройки WG + Настройки WG MTU - MTU + MTU @@ -1051,12 +1051,12 @@ Already installed containers were found on the server. All installed containers Port - Порт + Порт Save - Сохранить + Сохранить @@ -1508,7 +1508,7 @@ Already installed containers were found on the server. All installed containers support@amnezia.org - + support@amnezia.org Mail @@ -1526,7 +1526,7 @@ Already installed containers were found on the server. All installed containers mailto:support@amnezia.org - + @@ -1536,7 +1536,7 @@ Already installed containers were found on the server. All installed containers Discover the source code - + Посмотреть исходный код @@ -1551,7 +1551,7 @@ Already installed containers were found on the server. All installed containers Visit official website - + Посетить официальный сайт https://amnezia.org @@ -1578,12 +1578,12 @@ Already installed containers were found on the server. All installed containers Location for connection - + Страны для подключения Unable change server location while there is an active connection - Невозможно изменить локацию во время активного соединения + Невозможно изменить локацию во время активного соединения @@ -1591,57 +1591,57 @@ Already installed containers were found on the server. All installed containers Active devices - + Активные устройства Manage currently connected devices - + Управление подключенными устройствами You can find the identifier on the Support tab or, for older versions of the app, by tapping '+' and then the three dots at the top of the page. - + Вы можете найти support tag во вкладке «Поддержка» или, в более ранних версиях приложения, нажав «+» на нижней панели, а затем три точки вверху страницы. (current device) - + (текущее устройство) Support tag: - + Support tag: Last updated: - + Последнее обновление: Cannot unlink device during active connection - + Невозможно отвязать устройство во время активного соединения Are you sure you want to unlink this device? - + Вы уверены, что хотите отвязать это устройство? This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect. - + Это устройство будет отвязано от вашей подписки. Вы можете подключить его снова в любой момент, нажав кнопку "Подключиться". Continue - Продолжить + Продолжить Cancel - Отменить + Отменить @@ -1649,82 +1649,82 @@ Already installed containers were found on the server. All installed containers Windows - + https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#windows - + macOS - + https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#macos - + Android - + https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#android - + AndroidTV - + https://docs.amnezia.org/ru/documentation/instructions/android_tv_connect/ - + iOS - + https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#ios - + Linux - + https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#linux - + Routers - + https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#routers - + How to connect on another device - + Как подключить другие устройства Setup guides on the Amnezia website - + Инструкции по настройке @@ -1739,82 +1739,82 @@ Already installed containers were found on the server. All installed containers Save AmneziaVPN config - Сохранить конфигурацию AmneziaVPN + Сохранить конфигурацию AmneziaVPN Configuration files - + Файл конфигурации For router setup or the AmneziaWG app - + Для настройки роутера или приложения AmneziaWG The configuration needs to be reissued - + Необходимо заново скачать конфигурацию и добавить ее в приложение configuration file - + файл конфигурации Generate a new configuration file - + Создать новый файл конфигурации The previously created one will stop working - + Ранее созданный файл перестанет работать Revoke the current configuration file - + Отозвать текущий файл конфигурации Config file saved - + Файл конфигурации сохранен The config has been revoked - + Конфигурация была отозвана Generate a new %1 configuration file? - + Создать новый %1 файл конфигурации? Revoke the current %1 configuration file? - + Отозвать текущий %1 файл конфигурации? Your previous configuration file will no longer work, and it will not be possible to connect using it - + Ваш предыдущий файл конфигурации не будет работать, и вы больше не сможете использовать его для подключения Download - + Скачать Continue - Продолжить + Продолжить Cancel - Отменить + Отменить @@ -1834,7 +1834,7 @@ Already installed containers were found on the server. All installed containers Valid until - + Действует до Speed @@ -1847,67 +1847,67 @@ Already installed containers were found on the server. All installed containers Subscription status - + Статус подписки Active connections - + Активные соединения Configurations have been updated for some countries. Download and install the updated configuration files - + Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы Subscription key - + Ключ для подключения Amnezia Premium subscription key - + Ключ подписки Amnezia Premium Save VPN key to file - + Сохранить VPN-ключ в файле Copy VPN key - + Скопировать VPN ключ Configuration files - + Файл конфигурации Manage configuration files - + Управление файлами конфигурации Active devices - + Активные устройства Manage currently connected devices - + Управление подключенными устройствами Support - + Поддержка How to connect on another device - + Как подключить другие устройства @@ -1941,22 +1941,22 @@ Already installed containers were found on the server. All installed containers Unlink this device - + Отвязать это устройство Are you sure you want to unlink this device? - + Вы уверены, что хотите отвязать это устройство? This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect. - + Это устройство будет отвязано от вашей подписки. Вы можете подключить его снова в любой момент, нажав кнопку Подключиться. Cannot unlink device during active connection - + Невозможно отвязать устройство во время активного соединения @@ -1979,57 +1979,57 @@ Already installed containers were found on the server. All installed containers Telegram - + Email Support - + Email support@amnezia.org - + Email Billing & Orders - + По вопросам оплаты help@vpnpay.io - + Website - Веб-сайт + Сайт amnezia.org - + amnezia.org Support - + Поддержка Our technical support specialists are available to assist you at any time - + Наши специалисты технической поддержки всегда готовы помочь вам. Support tag - + Copied - Скопировано + Скопировано @@ -2730,27 +2730,27 @@ Already installed containers were found on the server. All installed containers connection settings - + настройки подключения Click the "connect" button to create a connection configuration - + Нажмите кнопку «Подключиться», чтобы создать конфигурацию server settings - настройки сервера + настройки сервера Clear profile - Очистить профиль + Очистить профиль The connection configuration will be deleted for this device only - Конфигурация подключения будет удалена только для этого устройства + Конфигурация подключения будет удалена только на этом устройстве @@ -3201,17 +3201,17 @@ and will not be shared or disclosed to the Amnezia or any third parties Choose Installation Type - + Выберите тип установки Manual - + Ручная Choose a VPN protocol - Выберите VPN-протокол + Выбрать VPN-протокол @@ -3711,7 +3711,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Access error! - Ошибка доступа! + Ошибка доступа! @@ -4009,7 +4009,7 @@ and will not be shared or disclosed to the Amnezia or any third parties The selected protocol is not supported on the current platform - Выбранный протокол не поддерживается на данном устройстве + Выбранный протокол не поддерживается на данном устройстве @@ -4217,7 +4217,7 @@ and will not be shared or disclosed to the Amnezia or any third parties VPN Protocols is not installed. Please install VPN container at first - VPN-протоколы не установлены. + VPN-протоколы не установлены. Пожалуйста, установите протокол @@ -4248,7 +4248,7 @@ and will not be shared or disclosed to the Amnezia or any third parties Failed to decrypt response payload - + @@ -4258,7 +4258,7 @@ and will not be shared or disclosed to the Amnezia or any third parties The limit of allowed configurations per subscription has been exceeded - + Превышен лимит разрешенных конфигураций для одной подписки @@ -4435,27 +4435,27 @@ While it offers a blend of security, stability, and speed, it's essential t Shadowsocks masks VPN traffic, making it resemble normal web traffic, but it may still be detected by certain analysis systems. - + Shadowsocks маскирует VPN-трафик, делая его похожим на обычный веб-трафик, но он все равно может быть обнаружен некоторыми системами анализа. OpenVPN over Cloak - OpenVPN with VPN masquerading as web traffic and protection against active-probing detection. It is very resistant to detection, but offers low speed. - + OpenVPN over Cloak — OpenVPN с маскировкой под веб-трафик , а также с защитой от обнаружения и систем анализа трафика. Он очень устойчив к обнаружению, но имеет низкую скорость работы в сравнении с другими похожими протоколами. WireGuard - popular VPN protocol with high performance, high speed and low power consumption. - + WireGuard — популярный VPN-протокол с высокой производительностью, высокой скоростью и низким энергопотреблением. AmneziaWG is a special protocol from Amnezia based on WireGuard. It provides high connection speed and ensures stable operation even in the most challenging network conditions. - + AmneziaWG — специальный протокол от Amnezia, основанный на WireGuard. Он обеспечивает высокую скорость соединения и гарантирует стабильную работу даже в самых сложных условиях. XRay with REALITY masks VPN traffic as web traffic and protects against active probing. It is highly resistant to detection and offers high speed. - + XRay с REALITY маскирует VPN-трафик под веб-трафик. Обладает высокой устойчивостью к обнаружению и обеспечивает высокую скорость соединения. @@ -4467,7 +4467,12 @@ It employs its unique security protocol, leveraging the strength of SSL/TLS for * Flexible customisation to suit user needs to work with different operating systems and devices * Recognised by DPI systems and therefore susceptible to blocking * Can operate over both TCP and UDP network protocols. - + OpenVPN является одним из самых популярных и проверенных временем VPN-протоколов. Он использует собственный протокол безопасности, и криптографические протоколы SSL/TLS для шифрования и обмена ключами. Более того, поддержка множества методов аутентификации делает OpenVPN универсальным, адаптируемым и подходящим для широкого спектра устройств и операционных систем. Благодаря своему открытому коду, OpenVPN подвергается тщательной проверке со стороны мирового сообщества, что постоянно укрепляет его безопасность. Имея отличный баланс между производительностью, безопасностью и совместимостью OpenVPN остается лучшим выбором для людей и компаний, заботящихся о конфиденциальности, однако OpenVPN легко распознается современными системами анализа трафика. +Доступен в AmneziaVPN на всех платформах +Нормальное энергопотребление на мобильных устройствах +Гибкая настройка полезная при работе с различными операционными системами и устройствами +Распознается системами DPI и, следовательно, уязвим к блокировкам +Может работать как по TCP, так и по UDP протоколу. @@ -4487,7 +4492,22 @@ Immediately after receiving the first data packet, Cloak authenticates the incom * Not recognised by detection systems * Works over TCP network protocol, 443 port. - + Это связка протокола OpenVPN и плагина Cloak, созданная специально для защиты от обнаружения. + +OpenVPN обеспечивает безопасное VPN-соединение, шифруя весь интернет-трафик между клиентом и сервером. + +Плагин Cloak защищает OpenVPN от обнаружения. + +Cloak может изменять метаданные пакета, чтобы полностью замаскировать VPN-трафик под обычный веб-трафик, а также защищает VPN от обнаружения с помощью метода Active Probing. Это делает его очень устойчивым к обнаружению. + +Сразу после получения первого пакета данных Cloak аутентифицирует входящее соединение, если аутентификация не удалась, плагин маскирует сервер под настоящий веб-сайт, и ваш VPN становится невидимым для систем анализа. Имеет низкую скорость работы в сравнении с другими похожими протоколами. + +* Доступно в AmneziaVPN на всех платформах. +* Высокое энергопотребление на мобильных устройствах +* Гибкие настройки +* Не распознается системами обнаружения. +* Работает по сетевому протоколу TCP, порт 443. + @@ -4500,7 +4520,15 @@ WireGuard is very susceptible to detection and blocking due to its distinct pack * Minimum number of settings * Easily recognised by DPI analysis systems, susceptible to blocking * Works over UDP network protocol. - + Популярный VPN-протокол с упрощенной архитектурой. +WireGuard обеспечивает стабильное VPN-соединение и высокую производительность на всех устройствах. Он использует закодированные настройки шифрования. WireGuard по сравнению с OpenVPN имеет меньшую задержку и лучшую пропускную способность передачи данных. +WireGuard очень чувствителен к обнаружению и блокировке из-за различных сигнатур пакетов. В отличие от некоторых других VPN протоколов, использующих методы запутывания, последовательные шаблоны сигнатур пакетов WireGuard легко идентифицируются системами анализа трафика. + +* Доступно в AmneziaVPN на всех платформах. +* Низкое энергопотребление +* Минимальное количество настроек +* Легко распознается системами анализа DPI, подвержен блокировке. +* Работает по сетевому протоколу UDP. @@ -4513,7 +4541,15 @@ This means that AmneziaWG keeps the fast performance of the original while addin * Minimum number of settings * Not recognised by traffic analysis systems * Works over UDP network protocol. - + AmneziaWG — это современная версия популярного VPN протокола, основанная на базе WireGuard, сохранившая упрощенную архитектуру и высокопроизводительные возможности на всех устройствах. +Хотя WireGuard известен своей эффективностью, обнаружить его довольно легко из-за различных сигнатур пакетов. AmneziaWG решает эту проблему, используя более совершенные методы работы, смешивая свой трафик с обычным интернет-трафиком. +Это означает, что AmneziaWG сохраняет высокую производительность оригинала, добавляя при этом дополнительный уровень скрытности, что делает его отличным выбором для тех, кому нужно быстрое и незаметное VPN-соединение. + +* Доступно в AmneziaVPN на всех платформах. +* Низкое энергопотребление +* Минимальное количество настроек +* Не распознается системами анализа трафика. +* Работает по сетевому протоколу UDP. @@ -4521,7 +4557,10 @@ This means that AmneziaWG keeps the fast performance of the original while addin 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. 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. 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. - + Протокол REALITY, современная разработка от создателей XRay. Призван обеспечить высочайший уровень защиты от обнаружения благодаря инновационному подходу к безопасности и конфиденциальности. +Он безошибочно идентифицирует злоумышленников на этапе установления связи TLS, беспрепятственно работая в качестве прокси-сервера для оригинального клиента и перенаправляя злоумышленников на подлинные веб-сайты, предоставляя тем самым подлинный сертификат TLS и данные. +Эта расширенная возможность отличает REALITY от аналогичных технологий тем, что способна маскироваться под случайный веб-трафик без использования специальных настроек. +В отличие от старых протоколов, таких как VMess, VLESS и транспорт XTLS-Vision, REALITY имеет инновационную технологию распознавания «свой-чужой».Это делает REALITY надежным решением для обеспечения доступа к свободному интернету. WireGuard - New popular VPN protocol with high performance, high speed and low power consumption. Recommended for regions with low levels of censorship. @@ -4575,12 +4614,12 @@ It employs its unique security protocol, leveraging the strength of SSL/TLS for * Configurable encryption protocol * Detectable by some DPI systems * Works over TCP network protocol. - Shadowsocks создан на основе протокола SOCKS5, защищает соединение с помощью шифра AEAD. Несмотря на то, что протокол Shadowsocks разработан таким образом, чтобы быть незаметным и сложным для идентификации, он не идентичен стандартному HTTPS-соединению. Поэтому некоторые системы анализа трафика всё же могут обнаружить соединение Shadowsocks. В связи с ограниченной поддержкой в Amnezia рекомендуется использовать протокол AmneziaWG. + Shadowsocks создан на основе протокола SOCKS5, защищает соединение с помощью шифра AEAD. Несмотря на то, что протокол Shadowsocks разработан таким образом, чтобы быть незаметным и сложным для идентификации, он не идентичен стандартному HTTPS-соединению, поэтому некоторые системы анализа трафика всё же могут обнаружить соединение Shadowsocks. В связи с ограниченной поддержкой в Amnezia рекомендуется использовать протокол AmneziaWG. * Доступен в AmneziaVPN только для ПК и ноутбуков * Настраиваемый протокол шифрования * Распознается некоторыми системами DPI-анализа -* Работает по сетевому протоколу TCP +* Работает по сетевому протоколу TCP. The REALITY protocol, a pioneering development by the creators of XRay, is specifically designed to counteract the highest levels of internet censorship through its novel approach to evasion. @@ -4911,12 +4950,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin Server name - Имя сервера + Имя сервера Save - Сохранить + Сохранить @@ -4932,7 +4971,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin Unable change server while there is an active connection - Невозможно изменить сервер во время активного соединения + Невозможно изменить сервер во время активного соединения @@ -5186,12 +5225,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin Automatic - + Автоматическая AmneziaWG protocol will be installed. It provides high connection speed and ensures stable operation even in the most challenging network conditions. - + Будет установлен протокол AmneziaWG. Он обеспечивает высокую скорость соединения и гарантирует стабильную работу даже в самых сложных условиях. diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index 1bba0e8a3..4ca12e214 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -27,8 +27,6 @@ namespace ConfigTypes checkConfigFormat(const QString &config) { const QString openVpnConfigPatternCli = "client"; - const QString openVpnConfigPatternProto1 = "proto tcp"; - const QString openVpnConfigPatternProto2 = "proto udp"; const QString openVpnConfigPatternDriver1 = "dev tun"; const QString openVpnConfigPatternDriver2 = "dev tap"; @@ -53,14 +51,13 @@ namespace || (config.contains(amneziaConfigPatternHostName) && config.contains(amneziaConfigPatternUserName) && config.contains(amneziaConfigPatternPassword))) { return ConfigTypes::Amnezia; - } else if (config.contains(openVpnConfigPatternCli) - && (config.contains(openVpnConfigPatternProto1) || config.contains(openVpnConfigPatternProto2)) - && (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) { - return ConfigTypes::OpenVpn; } else if (config.contains(wireguardConfigPatternSectionInterface) && config.contains(wireguardConfigPatternSectionPeer)) { return ConfigTypes::WireGuard; } else if ((config.contains(xrayConfigPatternInbound)) && (config.contains(xrayConfigPatternOutbound))) { return ConfigTypes::Xray; + } else if (config.contains(openVpnConfigPatternCli) + && (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) { + return ConfigTypes::OpenVpn; } return ConfigTypes::Invalid; } @@ -345,7 +342,7 @@ QJsonObject ImportController::extractOpenVpnConfig(const QString &data) arr.push_back(containers); QString hostName; - const static QRegularExpression hostNameRegExp("remote (.*) [0-9]*"); + const static QRegularExpression hostNameRegExp("remote\\s+([^\\s]+)"); QRegularExpressionMatch hostNameMatch = hostNameRegExp.match(data); if (hostNameMatch.hasMatch()) { hostName = hostNameMatch.captured(1); diff --git a/client/ui/controllers/sitesController.cpp b/client/ui/controllers/sitesController.cpp index 24ae035f0..d40be4585 100644 --- a/client/ui/controllers/sitesController.cpp +++ b/client/ui/controllers/sitesController.cpp @@ -44,7 +44,6 @@ void SitesController::addSite(QString hostname) QMetaObject::invokeMethod(m_vpnConnection.get(), "addRoutes", Qt::QueuedConnection, Q_ARG(QStringList, QStringList() << hostname)); } - QMetaObject::invokeMethod(m_vpnConnection.get(), "flushDns", Qt::QueuedConnection); }; const auto &resolveCallback = [this, processSite](const QHostInfo &hostInfo) { @@ -75,7 +74,6 @@ void SitesController::removeSite(int index) QMetaObject::invokeMethod(m_vpnConnection.get(), "deleteRoutes", Qt::QueuedConnection, Q_ARG(QStringList, QStringList() << hostname)); - QMetaObject::invokeMethod(m_vpnConnection.get(), "flushDns", Qt::QueuedConnection); emit finished(tr("Site removed: %1").arg(hostname)); } @@ -124,7 +122,6 @@ void SitesController::importSites(const QString &fileName, bool replaceExisting) m_sitesModel->addSites(sites, replaceExisting); QMetaObject::invokeMethod(m_vpnConnection.get(), "addRoutes", Qt::QueuedConnection, Q_ARG(QStringList, ips)); - QMetaObject::invokeMethod(m_vpnConnection.get(), "flushDns", Qt::QueuedConnection); emit finished(tr("Import completed")); } diff --git a/client/ui/models/api/apiServicesModel.cpp b/client/ui/models/api/apiServicesModel.cpp index f1880e4de..65f17758d 100644 --- a/client/ui/models/api/apiServicesModel.cpp +++ b/client/ui/models/api/apiServicesModel.cpp @@ -65,8 +65,8 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const case CardDescriptionRole: { auto speed = apiServiceData.serviceInfo.speed; if (serviceType == serviceType::amneziaPremium) { - return tr("Amnezia Premium is VPN for comfortable work, downloading large files and watching videos in 8K resolution. " - "Works for any sites with no restrictions. Speed up to %1 MBit/s. Unlimited traffic.") + return tr("Amnezia Premium is classic VPN for seamless work, downloading large files, and watching videos. " + "Access all websites and online resources. Speeds up to %1 Mbps.") .arg(speed); } else if (serviceType == serviceType::amneziaFree) { QString description = 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."); @@ -79,8 +79,8 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const } case ServiceDescriptionRole: { if (serviceType == serviceType::amneziaPremium) { - return tr("Amnezia Premium is VPN for comfortable work, downloading large files and watching videos in 8K resolution. " - "Works for any sites with no restrictions."); + 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("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."); } diff --git a/client/ui/qml/Components/AdLabel.qml b/client/ui/qml/Components/AdLabel.qml index efbe1720c..91e1a42c6 100644 --- a/client/ui/qml/Components/AdLabel.qml +++ b/client/ui/qml/Components/AdLabel.qml @@ -54,7 +54,7 @@ Rectangle { Layout.rightMargin: 10 Layout.leftMargin: 10 - text: qsTr("Amnezia Premium - for access to any website") + text: qsTr("Amnezia Premium - for access to all websites and online resources") color: AmneziaStyle.color.pearlGray lineHeight: 18 diff --git a/client/ui/qml/Pages2/PageSettingsApiDevices.qml b/client/ui/qml/Pages2/PageSettingsApiDevices.qml index 07df07a7d..c6a2f98cc 100644 --- a/client/ui/qml/Pages2/PageSettingsApiDevices.qml +++ b/client/ui/qml/Pages2/PageSettingsApiDevices.qml @@ -42,7 +42,7 @@ PageType { Layout.rightMargin: 16 Layout.leftMargin: 16 - headerText: qsTr("Active devices") + headerText: qsTr("Active Devices") descriptionText: qsTr("Manage currently connected devices") } diff --git a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml index f7acdf768..44b2d2fa8 100644 --- a/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml +++ b/client/ui/qml/Pages2/PageSettingsApiNativeConfigs.qml @@ -45,7 +45,7 @@ PageType { Layout.rightMargin: 16 Layout.leftMargin: 16 - headerText: qsTr("Configuration files") + headerText: qsTr("Configuration Files") descriptionText: qsTr("For router setup or the AmneziaWG app") } } diff --git a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml index c76508629..689502c1c 100644 --- a/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml +++ b/client/ui/qml/Pages2/PageSettingsApiServerInfo.qml @@ -26,7 +26,7 @@ PageType { QtObject { id: statusObject - readonly property string title: qsTr("Subscription status") + readonly property string title: qsTr("Subscription Status") readonly property string contentKey: "subscriptionStatus" readonly property string objectImageSource: "qrc:/images/controls/info.svg" } @@ -34,7 +34,7 @@ PageType { QtObject { id: endDateObject - readonly property string title: qsTr("Valid until") + readonly property string title: qsTr("Valid Until") readonly property string contentKey: "endDate" readonly property string objectImageSource: "qrc:/images/controls/history.svg" } @@ -42,7 +42,7 @@ PageType { QtObject { id: deviceCountObject - readonly property string title: qsTr("Active connections") + readonly property string title: qsTr("Active Connections") readonly property string contentKey: "connectedDevices" readonly property string objectImageSource: "qrc:/images/controls/monitor.svg" } @@ -183,7 +183,7 @@ PageType { visible: false //footer.isVisibleForAmneziaFree - text: qsTr("Subscription key") + text: qsTr("Subscription Key") rightImageSource: "qrc:/images/controls/chevron-right.svg" clickedFunction: function() { @@ -191,7 +191,7 @@ PageType { shareConnectionDrawer.openTriggered() shareConnectionDrawer.isSelfHostedConfig = false; - shareConnectionDrawer.shareButtonText = qsTr("Save VPN key to file") + shareConnectionDrawer.shareButtonText = qsTr("Save VPN key as a file") shareConnectionDrawer.copyButtonText = qsTr("Copy VPN key") @@ -213,7 +213,7 @@ PageType { visible: footer.isVisibleForAmneziaFree - text: qsTr("Configuration files") + text: qsTr("Configuration Files") descriptionText: qsTr("Manage configuration files") rightImageSource: "qrc:/images/controls/chevron-right.svg" @@ -233,7 +233,7 @@ PageType { visible: footer.isVisibleForAmneziaFree - text: qsTr("Active devices") + text: qsTr("Active Devices") descriptionText: qsTr("Manage currently connected devices") rightImageSource: "qrc:/images/controls/chevron-right.svg" diff --git a/client/ui/qml/Pages2/PageSettingsApiSupport.qml b/client/ui/qml/Pages2/PageSettingsApiSupport.qml index 3e4f0149b..2ca131512 100644 --- a/client/ui/qml/Pages2/PageSettingsApiSupport.qml +++ b/client/ui/qml/Pages2/PageSettingsApiSupport.qml @@ -27,7 +27,7 @@ PageType { QtObject { id: techSupport - readonly property string title: qsTr("Email Support") + readonly property string title: qsTr("Email") readonly property string description: qsTr("support@amnezia.org") readonly property string link: "mailto:support@amnezia.org" } diff --git a/client/ui/qml/Pages2/PageSettingsConnection.qml b/client/ui/qml/Pages2/PageSettingsConnection.qml index d3743b969..69671f278 100644 --- a/client/ui/qml/Pages2/PageSettingsConnection.qml +++ b/client/ui/qml/Pages2/PageSettingsConnection.qml @@ -140,7 +140,7 @@ PageType { } onClicked: { if (!checkable) { - PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection")) + PageController.showNotificationMessage(qsTr("Cannot change KillSwitch settings during active connection")) } } }