mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-21 02:01:03 +07:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 38082f9940 | |||
| 9d571a4c71 | |||
| f283858490 | |||
| 76fe203767 | |||
| b9a47f2f50 | |||
| 27cb17c640 | |||
| ef8fb89eb3 | |||
| 71691fa01e | |||
| 62d9bcaf7f | |||
| 5ef8254cba | |||
| f767171c06 | |||
| eff460b227 | |||
| 319043818a | |||
| f1b045f8a8 | |||
| e730521576 | |||
| 517930dd22 | |||
| 26994c21b1 | |||
| 681eb5aa86 | |||
| 4b86425992 | |||
| 9b41ed66bb | |||
| 8bb4fa3f35 | |||
| 050066132b | |||
| 2a6e6a1e24 | |||
| 92689d084c | |||
| 00f314039d | |||
| fcb75e837d | |||
| 9fbea76b74 | |||
| b3ff120bcf | |||
| e792117be1 | |||
| 9dea98f020 | |||
| c4701d4e7a | |||
| 48903ca3a1 | |||
| 0c9fd4aef4 | |||
| b2af2e46ac | |||
| efc76a0683 | |||
| c4a553c166 | |||
| 69a00b0252 | |||
| 4257c08b43 | |||
| c9e5b92f79 | |||
| 99818c2ad8 | |||
| 99e3afabad | |||
| d3339a7f3a |
@@ -190,7 +190,7 @@ jobs:
|
||||
- name: 'Install go'
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22.1'
|
||||
go-version: '1.24'
|
||||
cache: false
|
||||
|
||||
- name: 'Setup gomobile'
|
||||
|
||||
+2
-2
@@ -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.5.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 2080)
|
||||
set(APP_ANDROID_VERSION_CODE 2082)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
|
||||
+10
-10
@@ -6,11 +6,11 @@
|
||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
||||
|
||||
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
|
||||
[AmneziaVPN](https://amnezia.org) — это open sourse VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
||||
[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
||||
|
||||
[](https://amnezia.org)
|
||||
|
||||
### [Сайт](https://amnezia.org) | [Зеркало на сайт](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
||||
### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
||||
|
||||
> [!TIP]
|
||||
> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org).
|
||||
@@ -30,7 +30,7 @@
|
||||
- Классические VPN-протоколы: OpenVPN, WireGuard и IKEv2.
|
||||
- Протоколы с маскировкой трафика (обфускацией): OpenVPN с плагином [Cloak](https://github.com/cbeuw/Cloak), Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
|
||||
- Поддержка Split Tunneling — добавляйте любые сайты или приложения в список, чтобы включить VPN только для них.
|
||||
- Поддерживает платформы: Windows, MacOS, Linux, Android, iOS.
|
||||
- Поддерживает платформы: Windows, macOS, Linux, Android, iOS.
|
||||
- Поддержка конфигурации протокола AmneziaWG на [бета-прошивке Keenetic](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
|
||||
|
||||
## Ссылки
|
||||
@@ -38,10 +38,10 @@
|
||||
- [https://amnezia.org](https://amnezia.org) - Веб-сайт проекта | [Альтернативная ссылка (зеркало)](https://storage.googleapis.com/kldscp/amnezia.org)
|
||||
- [https://docs.amnezia.org](https://docs.amnezia.org) - Документация
|
||||
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
|
||||
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Канал поддржки в Telegram (Английский)
|
||||
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Канал поддржки в Telegram (Фарси)
|
||||
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Канал поддржки в Telegram (Мьянма)
|
||||
- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Канал поддржки в Telegram (Русский)
|
||||
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Канал поддержки в Telegram (Английский)
|
||||
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Канал поддержки в Telegram (Фарси)
|
||||
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Канал поддержки в Telegram (Мьянма)
|
||||
- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Канал поддержки в Telegram (Русский)
|
||||
- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium | [Зеркало](https://storage.googleapis.com/kldscp/vpnpay.io/ru/amnezia-premium\)
|
||||
|
||||
## Технологии
|
||||
@@ -80,8 +80,8 @@ git submodule update --init --recursive
|
||||
Проверьте папку deploy для скриптов сборки.
|
||||
|
||||
### Как собрать iOS-приложение из исходного кода на MacOS
|
||||
1. Убедитесь, что у вас установлен XCode версии 14 или выше.
|
||||
2. Для генерации проекта XCode используется QT. Требуется версия QT 6.6.2. Установите QT для MacOS здесь или через QT Online Installer. Необходимые модули:
|
||||
1. Убедитесь, что у вас установлен Xcode версии 14 или выше.
|
||||
2. Для генерации проекта Xcode используется QT. Требуется версия QT 6.6.2. Установите QT для MacOS здесь или через QT Online Installer. Необходимые модули:
|
||||
- MacOS
|
||||
- iOS
|
||||
- Модуль совместимости с Qt 5
|
||||
@@ -117,7 +117,7 @@ $QT_IOS_BIN/qt-cmake . -B build-ios -GXcode -DQT_HOST_PATH=$QT_MACOS_ROOT_DIR
|
||||
export PATH=$(PATH):/path/to/GOPATH/bin
|
||||
```
|
||||
|
||||
6. Откройте проект в XCode. Теперь вы можете тестировать, архивировать или публиковать приложение.
|
||||
6. Откройте проект в Xcode. Теперь вы можете тестировать, архивировать или публиковать приложение.
|
||||
|
||||
Если сборка завершится с ошибкой:
|
||||
```
|
||||
|
||||
+1
-1
Submodule client/3rd-prebuilt updated: e555c78bcf...efad1a5b5c
@@ -31,10 +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}")
|
||||
|
||||
if(IOS)
|
||||
set(PACKAGES ${PACKAGES} Multimedia)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
set(PACKAGES ${PACKAGES} Widgets)
|
||||
endif()
|
||||
@@ -48,10 +44,6 @@ set(LIBS ${LIBS}
|
||||
Qt6::Core5Compat Qt6::Concurrent
|
||||
)
|
||||
|
||||
if(IOS)
|
||||
set(LIBS ${LIBS} Qt6::Multimedia)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
set(LIBS ${LIBS} Qt6::Widgets)
|
||||
endif()
|
||||
|
||||
@@ -36,7 +36,6 @@ set(HEADERS ${HEADERS}
|
||||
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.h
|
||||
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.h
|
||||
${CLIENT_ROOT_DIR}/mozilla/controllerimpl.h
|
||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
|
||||
)
|
||||
|
||||
if(NOT IOS)
|
||||
@@ -86,7 +85,6 @@ set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/mozilla/models/server.cpp
|
||||
${CLIENT_ROOT_DIR}/mozilla/shared/ipaddress.cpp
|
||||
${CLIENT_ROOT_DIR}/mozilla/shared/leakdetector.cpp
|
||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
||||
)
|
||||
|
||||
if(NOT IOS)
|
||||
@@ -175,11 +173,13 @@ if(WIN32 OR (APPLE AND NOT IOS) OR (LINUX AND NOT ANDROID))
|
||||
${CLIENT_ROOT_DIR}/protocols/wireguardprotocol.h
|
||||
${CLIENT_ROOT_DIR}/protocols/xrayprotocol.h
|
||||
${CLIENT_ROOT_DIR}/protocols/awgprotocol.h
|
||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.h
|
||||
)
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
${CLIENT_ROOT_DIR}/core/ipcclient.cpp
|
||||
${CLIENT_ROOT_DIR}/core/privileged_process.cpp
|
||||
${CLIENT_ROOT_DIR}/mozilla/localsocketcontroller.cpp
|
||||
${CLIENT_ROOT_DIR}/ui/systemtray_notificationhandler.cpp
|
||||
${CLIENT_ROOT_DIR}/protocols/openvpnprotocol.cpp
|
||||
${CLIENT_ROOT_DIR}/protocols/openvpnovercloakprotocol.cpp
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QTemporaryDir>
|
||||
#include <QTemporaryFile>
|
||||
@@ -19,13 +20,17 @@
|
||||
#include "settings.h"
|
||||
#include "utilities.h"
|
||||
|
||||
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController,
|
||||
bool isAwg, QObject *parent)
|
||||
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings,
|
||||
const QSharedPointer<ServerController> &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<QHostAddress> WireguardConfigurator::getIpsFromConf(const QString &input)
|
||||
{
|
||||
QRegularExpression regex("AllowedIPs = (\\d+\\.\\d+\\.\\d+\\.\\d+)");
|
||||
QRegularExpressionMatchIterator matchIterator = regex.globalMatch(input);
|
||||
|
||||
QList<QHostAddress> 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<quint8>(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<QString, QString> &dns, const bool isApiConfig,
|
||||
QString &protocolConfigString)
|
||||
QString WireguardConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns,
|
||||
const bool isApiConfig, QString &protocolConfigString)
|
||||
{
|
||||
processConfigWithDnsSettings(dns, protocolConfigString);
|
||||
|
||||
return protocolConfigString;
|
||||
}
|
||||
|
||||
QString WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||
QString &protocolConfigString)
|
||||
QString WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns,
|
||||
const bool isApiConfig, QString &protocolConfigString)
|
||||
{
|
||||
processConfigWithDnsSettings(dns, protocolConfigString);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef WIREGUARD_CONFIGURATOR_H
|
||||
#define WIREGUARD_CONFIGURATOR_H
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
@@ -12,8 +13,8 @@ class WireguardConfigurator : public ConfiguratorBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
WireguardConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, bool isAwg,
|
||||
QObject *parent = nullptr);
|
||||
WireguardConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &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<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString);
|
||||
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString);
|
||||
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||
QString &protocolConfigString);
|
||||
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
|
||||
QString &protocolConfigString);
|
||||
|
||||
static ConnectionData genClientKeys();
|
||||
|
||||
private:
|
||||
QList<QHostAddress> getIpsFromConf(const QString &input);
|
||||
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
|
||||
const QJsonObject &containerConfig, ErrorCode &errorCode);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "coreController.h"
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QTranslator>
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
@@ -238,7 +239,23 @@ void CoreController::updateTranslator(const QLocale &locale)
|
||||
QCoreApplication::removeTranslator(m_translator.get());
|
||||
}
|
||||
|
||||
QString strFileName = QString(":/translations/amneziavpn") + QLatin1String("_") + locale.name() + ".qm";
|
||||
QStringList availableTranslations;
|
||||
QDirIterator it(":/translations", QStringList("amneziavpn_*.qm"), QDir::Files);
|
||||
while (it.hasNext()) {
|
||||
availableTranslations << it.next();
|
||||
}
|
||||
|
||||
// This code allow to load translation for the language only, without country code
|
||||
const QString lang = locale.name().split("_").first();
|
||||
const QString translationFilePrefix = QString(":/translations/amneziavpn_") + lang;
|
||||
QString strFileName = QString(":/translations/amneziavpn_%1.qm").arg(locale.name());
|
||||
for (const QString &translation : availableTranslations) {
|
||||
if (translation.contains(translationFilePrefix)) {
|
||||
strFileName = translation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_translator->load(strFileName)) {
|
||||
if (QCoreApplication::installTranslator(m_translator.get())) {
|
||||
m_settings->setAppLanguage(locale);
|
||||
|
||||
@@ -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<QSslError> 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<void>(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -757,10 +757,6 @@ ErrorCode ServerController::isServerPortBusy(const ServerCredentials &credential
|
||||
|
||||
ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, DockerContainer container)
|
||||
{
|
||||
if (credentials.userName == "root") {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
@@ -774,8 +770,16 @@ ErrorCode ServerController::isUserInSudo(const ServerCredentials &credentials, D
|
||||
const QString scriptData = amnezia::scriptData(SharedScriptType::check_user_in_sudo);
|
||||
ErrorCode error = runScript(credentials, replaceVars(scriptData, genVarsForScript(credentials)), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
if (!stdOut.contains("sudo"))
|
||||
if (credentials.userName != "root" && stdOut.contains("sudo:") && !stdOut.contains("uname:") && stdOut.contains("not found"))
|
||||
return ErrorCode::ServerSudoPackageIsNotPreinstalled;
|
||||
if (credentials.userName != "root" && !stdOut.contains("sudo") && !stdOut.contains("wheel"))
|
||||
return ErrorCode::ServerUserNotInSudo;
|
||||
if (stdOut.contains("can't cd to") || stdOut.contains("Permission denied") || stdOut.contains("No such file or directory"))
|
||||
return ErrorCode::ServerUserDirectoryNotAccessible;
|
||||
if (stdOut.contains("sudoers") || stdOut.contains("is not allowed to run sudo on"))
|
||||
return ErrorCode::ServerUserNotAllowedInSudoers;
|
||||
if (stdOut.contains("password is required"))
|
||||
return ErrorCode::ServerUserPasswordRequired;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@ namespace amnezia
|
||||
ServerCancelInstallation = 204,
|
||||
ServerUserNotInSudo = 205,
|
||||
ServerPacketManagerError = 206,
|
||||
ServerSudoPackageIsNotPreinstalled = 207,
|
||||
ServerUserDirectoryNotAccessible = 208,
|
||||
ServerUserNotAllowedInSudoers = 209,
|
||||
ServerUserPasswordRequired = 210,
|
||||
|
||||
// Ssh connection errors
|
||||
SshRequestDeniedError = 300,
|
||||
|
||||
@@ -20,8 +20,12 @@ QString errorString(ErrorCode code) {
|
||||
case(ErrorCode::ServerContainerMissingError): errorMessage = QObject::tr("Server error: Docker container missing"); break;
|
||||
case(ErrorCode::ServerDockerFailedError): errorMessage = QObject::tr("Server error: Docker failed"); break;
|
||||
case(ErrorCode::ServerCancelInstallation): errorMessage = QObject::tr("Installation canceled by user"); break;
|
||||
case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user does not have permission to use sudo"); break;
|
||||
case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Packet manager error"); break;
|
||||
case(ErrorCode::ServerUserNotInSudo): errorMessage = QObject::tr("The user is not a member of the sudo group"); break;
|
||||
case(ErrorCode::ServerPacketManagerError): errorMessage = QObject::tr("Server error: Package manager error"); break;
|
||||
case(ErrorCode::ServerSudoPackageIsNotPreinstalled): errorMessage = QObject::tr("The sudo package is not pre-installed on the server"); break;
|
||||
case(ErrorCode::ServerUserDirectoryNotAccessible): errorMessage = QObject::tr("The server user's home directory is not accessible"); break;
|
||||
case(ErrorCode::ServerUserNotAllowedInSudoers): errorMessage = QObject::tr("Action not allowed in sudoers"); break;
|
||||
case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
|
||||
|
||||
// Libssh errors
|
||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||
|
||||
@@ -18,6 +18,12 @@ bool IpcClient::isSocketConnected() const
|
||||
return m_isSocketConnected;
|
||||
}
|
||||
|
||||
void IpcClient::close()
|
||||
{
|
||||
if (m_localSocket)
|
||||
m_localSocket->close();
|
||||
}
|
||||
|
||||
IpcClient *IpcClient::Instance()
|
||||
{
|
||||
return m_instance;
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
|
||||
|
||||
bool isSocketConnected() const;
|
||||
void close();
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
@@ -14,10 +14,8 @@
|
||||
#include <QJsonValue>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "ipaddress.h"
|
||||
#include "leakdetector.h"
|
||||
#include "logger.h"
|
||||
#include "models/server.h"
|
||||
#include "daemon/daemonerrors.h"
|
||||
|
||||
#include "protocols/protocols_defs.h"
|
||||
@@ -38,7 +36,7 @@ LocalSocketController::LocalSocketController() {
|
||||
m_socket = new QLocalSocket(this);
|
||||
connect(m_socket, &QLocalSocket::connected, this,
|
||||
&LocalSocketController::daemonConnected);
|
||||
connect(m_socket, &QLocalSocket::disconnected, this,
|
||||
connect(m_socket, &QLocalSocket::disconnected, this,
|
||||
[&] { errorOccurred(QLocalSocket::PeerClosedError); });
|
||||
connect(m_socket, &QLocalSocket::errorOccurred, this,
|
||||
&LocalSocketController::errorOccurred);
|
||||
@@ -115,7 +113,6 @@ void LocalSocketController::daemonConnected() {
|
||||
}
|
||||
|
||||
void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
|
||||
QString protocolName = rawConfig.value("protocol").toString();
|
||||
|
||||
int splitTunnelType = rawConfig.value("splitTunnelType").toInt();
|
||||
@@ -131,13 +128,17 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
// json.insert("hopindex", QJsonValue((double)hop.m_hopindex));
|
||||
json.insert("privateKey", wgConfig.value(amnezia::config_key::client_priv_key));
|
||||
json.insert("deviceIpv4Address", wgConfig.value(amnezia::config_key::client_ip));
|
||||
m_deviceIpv4 = wgConfig.value(amnezia::config_key::client_ip).toString();
|
||||
|
||||
// set up IPv6 unique-local-address, ULA, with "fd00::/8" prefix, not globally routable.
|
||||
// this will be default IPv6 gateway, OS recognizes that IPv6 link is local and switches to IPv4.
|
||||
// Otherwise some OSes (Linux) try IPv6 forever and hang.
|
||||
// this will be default IPv6 gateway, OS recognizes that IPv6 link
|
||||
// is local and switches to IPv4.
|
||||
// Otherwise some OSes (Linux) try IPv6 forever and hang.
|
||||
// https://en.wikipedia.org/wiki/Unique_local_address (RFC 4193)
|
||||
// https://man7.org/linux/man-pages/man5/gai.conf.5.html
|
||||
json.insert("deviceIpv6Address", "fd58:baa6:dead::1"); // simply "dead::1" is globally-routable, don't use it
|
||||
|
||||
// simply "dead::1" is globally-routable, don't use it
|
||||
json.insert("deviceIpv6Address", "fd58:baa6:dead::1");
|
||||
|
||||
json.insert("serverPublicKey", wgConfig.value(amnezia::config_key::server_pub_key));
|
||||
json.insert("serverPskKey", wgConfig.value(amnezia::config_key::psk_key));
|
||||
@@ -212,7 +213,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
|
||||
json.insert("allowedIPAddressRanges", jsAllowedIPAddesses);
|
||||
|
||||
|
||||
QJsonArray jsExcludedAddresses;
|
||||
jsExcludedAddresses.append(wgConfig.value(amnezia::config_key::hostName));
|
||||
if (splitTunnelType == 2) {
|
||||
@@ -406,6 +406,7 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||
}
|
||||
|
||||
if (type == "status") {
|
||||
|
||||
QJsonValue serverIpv4Gateway = obj.value("serverIpv4Gateway");
|
||||
if (!serverIpv4Gateway.isString()) {
|
||||
logger.error() << "Unexpected serverIpv4Gateway value";
|
||||
@@ -450,6 +451,11 @@ void LocalSocketController::parseCommand(const QByteArray& command) {
|
||||
|
||||
logger.debug() << "Handshake completed with:"
|
||||
<< pubkey.toString();
|
||||
|
||||
checkStatus();
|
||||
|
||||
emit statusUpdated("", m_deviceIpv4, 0, 0);
|
||||
|
||||
emit connected(pubkey.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "controllerimpl.h"
|
||||
|
||||
|
||||
class QJsonObject;
|
||||
|
||||
class LocalSocketController final : public ControllerImpl {
|
||||
@@ -58,6 +59,7 @@ class LocalSocketController final : public ControllerImpl {
|
||||
|
||||
QByteArray m_buffer;
|
||||
|
||||
QString m_deviceIpv4;
|
||||
std::function<void(const QString&)> m_logCallback = nullptr;
|
||||
|
||||
QTimer m_initializingTimer;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "logger.h"
|
||||
//#include "mozillavpn.h"
|
||||
#include "networkwatcherimpl.h"
|
||||
#include "platforms/dummy/dummynetworkwatcher.h"
|
||||
//#include "settingsholder.h"
|
||||
|
||||
#ifdef MZ_WINDOWS
|
||||
@@ -51,7 +50,7 @@ NetworkWatcher::NetworkWatcher() { MZ_COUNT_CTOR(NetworkWatcher); }
|
||||
NetworkWatcher::~NetworkWatcher() { MZ_COUNT_DTOR(NetworkWatcher); }
|
||||
|
||||
void NetworkWatcher::initialize() {
|
||||
logger.debug() << "Initialize";
|
||||
logger.debug() << "Initialize NetworkWatcher";
|
||||
|
||||
#if defined(MZ_WINDOWS)
|
||||
m_impl = new WindowsNetworkWatcher(this);
|
||||
@@ -69,14 +68,17 @@ void NetworkWatcher::initialize() {
|
||||
m_impl = new DummyNetworkWatcher(this);
|
||||
#endif
|
||||
|
||||
|
||||
connect(m_impl, &NetworkWatcherImpl::unsecuredNetwork, this,
|
||||
&NetworkWatcher::unsecuredNetwork);
|
||||
connect(m_impl, &NetworkWatcherImpl::networkChanged, this,
|
||||
&NetworkWatcher::networkChange);
|
||||
|
||||
connect(m_impl, &NetworkWatcherImpl::sleepMode, this,
|
||||
&NetworkWatcher::onSleepMode);
|
||||
m_impl->initialize();
|
||||
|
||||
|
||||
|
||||
// TODO: IMPL FOR AMNEZIA
|
||||
#if 0
|
||||
SettingsHolder* settingsHolder = SettingsHolder::instance();
|
||||
@@ -117,11 +119,16 @@ void NetworkWatcher::settingsChanged() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkWatcher::onSleepMode()
|
||||
{
|
||||
logger.debug() << "Resumed from sleep mode";
|
||||
emit sleepMode();
|
||||
}
|
||||
|
||||
void NetworkWatcher::unsecuredNetwork(const QString& networkName,
|
||||
const QString& networkId) {
|
||||
logger.debug() << "Unsecured network:" << logger.sensitive(networkName)
|
||||
<< "id:" << logger.sensitive(networkId);
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
if (!m_reportUnsecuredNetwork) {
|
||||
logger.debug() << "Disabled. Ignoring unsecured network";
|
||||
|
||||
@@ -29,10 +29,13 @@ public:
|
||||
// false to restore.
|
||||
void simulateDisconnection(bool simulatedDisconnection);
|
||||
|
||||
void onSleepMode();
|
||||
|
||||
QNetworkInformation::Reachability getReachability();
|
||||
|
||||
signals:
|
||||
void networkChange();
|
||||
void sleepMode();
|
||||
|
||||
private:
|
||||
void settingsChanged();
|
||||
|
||||
@@ -41,6 +41,8 @@ signals:
|
||||
// TODO: Only windows-networkwatcher has this, the other plattforms should
|
||||
// too.
|
||||
void networkChanged(QString newBSSID);
|
||||
void sleepMode();
|
||||
|
||||
|
||||
private:
|
||||
bool m_active = false;
|
||||
|
||||
@@ -41,6 +41,7 @@ void PingHelper::start(const QString& serverIpv4Gateway,
|
||||
|
||||
m_gateway = QHostAddress(serverIpv4Gateway);
|
||||
m_source = QHostAddress(deviceIpv4Address.section('/', 0, 0));
|
||||
|
||||
m_pingSender = PingSenderFactory::create(m_source, this);
|
||||
|
||||
// Some platforms require root access to send and receive ICMP pings. If
|
||||
@@ -53,8 +54,10 @@ void PingHelper::start(const QString& serverIpv4Gateway,
|
||||
|
||||
connect(m_pingSender, &PingSender::recvPing, this, &PingHelper::pingReceived,
|
||||
Qt::QueuedConnection);
|
||||
connect(m_pingSender, &PingSender::criticalPingError, this,
|
||||
[]() { logger.info() << "Encountered Unrecoverable ping error"; });
|
||||
connect(m_pingSender, &PingSender::criticalPingError, this, [this]() {
|
||||
logger.info() << "Encountered Unrecoverable ping error";
|
||||
emit connectionLose();
|
||||
});
|
||||
|
||||
// Reset the ping statistics
|
||||
m_sequence = 0;
|
||||
|
||||
@@ -33,6 +33,8 @@ class PingHelper final : public QObject {
|
||||
|
||||
signals:
|
||||
void pingSentAndReceived(qint64 msec);
|
||||
void connectionLose();
|
||||
|
||||
|
||||
private:
|
||||
void nextPing();
|
||||
|
||||
@@ -5,27 +5,26 @@
|
||||
#include "pingsenderfactory.h"
|
||||
|
||||
#if defined(MZ_LINUX) || defined(MZ_ANDROID)
|
||||
//# include "platforms/linux/linuxpingsender.h"
|
||||
# include "platforms/linux/linuxpingsender.h"
|
||||
#elif defined(MZ_MACOS) || defined(MZ_IOS)
|
||||
# include "platforms/macos/macospingsender.h"
|
||||
# include "platforms/macos/macospingsender.h"
|
||||
#elif defined(MZ_WINDOWS)
|
||||
# include "platforms/windows/windowspingsender.h"
|
||||
#elif defined(MZ_DUMMY) || defined(UNIT_TEST)
|
||||
# include "platforms/dummy/dummypingsender.h"
|
||||
# include "platforms/windows/windowspingsender.h"
|
||||
#elif defined(MZ_WASM) || defined(UNIT_TEST)
|
||||
# include "platforms/dummy/dummypingsender.h"
|
||||
#else
|
||||
# error "Unsupported platform"
|
||||
# error "Unsupported platform"
|
||||
#endif
|
||||
|
||||
PingSender* PingSenderFactory::create(const QHostAddress& source,
|
||||
QObject* parent) {
|
||||
#if defined(MZ_LINUX) || defined(MZ_ANDROID)
|
||||
return nullptr;
|
||||
// return new LinuxPingSender(source, parent);
|
||||
return new LinuxPingSender(source, parent);
|
||||
#elif defined(MZ_MACOS) || defined(MZ_IOS)
|
||||
return new MacOSPingSender(source, parent);
|
||||
return new MacOSPingSender(source, parent);
|
||||
#elif defined(MZ_WINDOWS)
|
||||
return new WindowsPingSender(source, parent);
|
||||
return new WindowsPingSender(source, parent);
|
||||
#else
|
||||
return new DummyPingSender(source, parent);
|
||||
return new DummyPingSender(source, parent);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@ class QHostAddress;
|
||||
class QObject;
|
||||
|
||||
class PingSenderFactory final {
|
||||
public:
|
||||
PingSenderFactory() = delete;
|
||||
static PingSender* create(const QHostAddress& source, QObject* parent);
|
||||
public:
|
||||
PingSenderFactory() = delete;
|
||||
static PingSender* create(const QHostAddress& source, QObject* parent);
|
||||
};
|
||||
|
||||
|
||||
#endif // PINGSENDERFACTORY_H
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ void LinuxNetworkWatcher::initialize() {
|
||||
connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this,
|
||||
&LinuxNetworkWatcher::unsecuredNetwork);
|
||||
|
||||
connect(m_worker, &LinuxNetworkWatcherWorker::sleepMode, this,
|
||||
&NetworkWatcherImpl::sleepMode);
|
||||
|
||||
// Let's wait a few seconds to allow the UI to be fully loaded and shown.
|
||||
// This is not strictly needed, but it's better for user experience because
|
||||
// it makes the UI faster to appear, plus it gives a bit of delay between the
|
||||
|
||||
@@ -33,7 +33,21 @@
|
||||
#define NM_802_11_AP_SEC_WEAK_CRYPTO \
|
||||
(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104)
|
||||
|
||||
|
||||
enum NMState {
|
||||
NM_STATE_UNKNOWN = 0,
|
||||
NM_STATE_ASLEEP = 10,
|
||||
NM_STATE_DISCONNECTED = 20,
|
||||
NM_STATE_DISCONNECTING = 30,
|
||||
NM_STATE_CONNECTING = 40,
|
||||
NM_STATE_CONNECTED_LOCAL = 50,
|
||||
NM_STATE_CONNECTED_SITE = 60,
|
||||
NM_STATE_CONNECTED_GLOBAL = 70
|
||||
};
|
||||
|
||||
|
||||
constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager";
|
||||
constexpr const char* DBUS_NETWORKMANAGER_PATH = "/org/freedesktop/NetworkManager";
|
||||
|
||||
namespace {
|
||||
Logger logger("LinuxNetworkWatcherWorker");
|
||||
@@ -73,7 +87,7 @@ void LinuxNetworkWatcherWorker::initialize() {
|
||||
// documentation:
|
||||
// https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html
|
||||
|
||||
QDBusInterface nm(DBUS_NETWORKMANAGER, "/org/freedesktop/NetworkManager",
|
||||
QDBusInterface nm(DBUS_NETWORKMANAGER, DBUS_NETWORKMANAGER_PATH,
|
||||
DBUS_NETWORKMANAGER, QDBusConnection::systemBus());
|
||||
if (!nm.isValid()) {
|
||||
logger.error()
|
||||
@@ -108,6 +122,12 @@ void LinuxNetworkWatcherWorker::initialize() {
|
||||
SLOT(propertyChanged(QString, QVariantMap, QStringList)));
|
||||
}
|
||||
|
||||
QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER,
|
||||
DBUS_NETWORKMANAGER_PATH,
|
||||
DBUS_NETWORKMANAGER,
|
||||
"StateChanged",
|
||||
this, SLOT(NMStateChanged(quint32)));
|
||||
|
||||
if (m_devicePaths.isEmpty()) {
|
||||
logger.warning() << "No wifi devices found";
|
||||
return;
|
||||
@@ -173,5 +193,16 @@ void LinuxNetworkWatcherWorker::checkDevices() {
|
||||
emit unsecuredNetwork(ssid, bssid);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state)
|
||||
{
|
||||
if (state == NM_STATE_ASLEEP) {
|
||||
emit sleepMode();
|
||||
}
|
||||
|
||||
logger.debug() << "NMStateChanged " << state;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
|
||||
|
||||
signals:
|
||||
void unsecuredNetwork(const QString& networkName, const QString& networkId);
|
||||
void sleepMode();
|
||||
|
||||
public slots:
|
||||
void initialize();
|
||||
@@ -30,6 +31,7 @@ class LinuxNetworkWatcherWorker final : public QObject {
|
||||
private slots:
|
||||
void propertyChanged(QString interface, QVariantMap properties,
|
||||
QStringList list);
|
||||
void NMStateChanged(quint32 state);
|
||||
|
||||
private:
|
||||
// We collect the list of DBus wifi network device paths during the
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "linuxpingsender.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <linux/filter.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <QSocketNotifier>
|
||||
#include <QtEndian>
|
||||
|
||||
#include "leakdetector.h"
|
||||
#include "logger.h"
|
||||
#include "qhostaddress.h"
|
||||
|
||||
namespace {
|
||||
Logger logger("LinuxPingSender");
|
||||
}
|
||||
|
||||
int LinuxPingSender::createSocket() {
|
||||
// Try creating an ICMP socket. This would be the ideal choice, but it can
|
||||
// fail depending on the kernel config (see: sys.net.ipv4.ping_group_range)
|
||||
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
|
||||
if (m_socket >= 0) {
|
||||
m_ident = 0;
|
||||
return m_socket;
|
||||
}
|
||||
if ((errno != EPERM) && (errno != EACCES)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// As a fallback, create a raw socket, which requires root permissions
|
||||
// or CAP_NET_RAW to be granted to the VPN client.
|
||||
m_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
if (m_socket < 0) {
|
||||
return -1;
|
||||
}
|
||||
m_ident = getpid() & 0xffff;
|
||||
|
||||
// Attach a BPF filter to discard everything but replies to our echo.
|
||||
struct sock_filter bpf_prog[] = {
|
||||
BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. */
|
||||
BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, m_ident, 1, 0), /* Ours? */
|
||||
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected identifier. Reject. */
|
||||
BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
|
||||
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
|
||||
BPF_STMT(BPF_RET | BPF_K, 0), /* Unexpected type. Reject. */
|
||||
BPF_STMT(BPF_RET | BPF_K, ~0U), /* Packet passes the filter. */
|
||||
};
|
||||
struct sock_fprog filter = {
|
||||
.len = sizeof(bpf_prog) / sizeof(struct sock_filter),
|
||||
.filter = bpf_prog,
|
||||
};
|
||||
setsockopt(m_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
|
||||
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
LinuxPingSender::LinuxPingSender(const QHostAddress& source, QObject* parent)
|
||||
: PingSender(parent) {
|
||||
MZ_COUNT_CTOR(LinuxPingSender);
|
||||
|
||||
logger.debug() << "LinuxPingSender(" + logger.sensitive(source.toString()) +
|
||||
") created";
|
||||
|
||||
m_socket = createSocket();
|
||||
if (m_socket < 0) {
|
||||
logger.error() << "Socket creation error: " << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
quint32 ipv4addr = INADDR_ANY;
|
||||
if (!source.isNull()) {
|
||||
ipv4addr = source.toIPv4Address();
|
||||
}
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof addr);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4addr);
|
||||
|
||||
if (bind(m_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||
close(m_socket);
|
||||
m_socket = -1;
|
||||
logger.error() << "bind error:" << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
m_notifier = new QSocketNotifier(m_socket, QSocketNotifier::Read, this);
|
||||
if (m_ident) {
|
||||
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||
&LinuxPingSender::rawSocketReady);
|
||||
} else {
|
||||
connect(m_notifier, &QSocketNotifier::activated, this,
|
||||
&LinuxPingSender::icmpSocketReady);
|
||||
}
|
||||
}
|
||||
|
||||
LinuxPingSender::~LinuxPingSender() {
|
||||
MZ_COUNT_DTOR(LinuxPingSender);
|
||||
if (m_socket >= 0) {
|
||||
close(m_socket);
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPingSender::sendPing(const QHostAddress& dest, quint16 sequence) {
|
||||
quint32 ipv4dest = dest.toIPv4Address();
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = qToBigEndian<quint32>(ipv4dest);
|
||||
|
||||
struct icmphdr packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
packet.type = ICMP_ECHO;
|
||||
packet.un.echo.id = htons(m_ident);
|
||||
packet.un.echo.sequence = htons(sequence);
|
||||
packet.checksum = inetChecksum(&packet, sizeof(packet));
|
||||
|
||||
int rc = sendto(m_socket, &packet, sizeof(packet), 0, (struct sockaddr*)&addr,
|
||||
sizeof(addr));
|
||||
if (rc < 0) {
|
||||
logger.error() << "failed to send:" << strerror(errno);
|
||||
if (errno == ENETUNREACH) {
|
||||
emit criticalPingError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPingSender::icmpSocketReady() {
|
||||
socklen_t slen = 0;
|
||||
unsigned char data[2048];
|
||||
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
|
||||
if (rc <= 0) {
|
||||
logger.error() << "recvfrom failed:" << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
struct icmphdr packet;
|
||||
if (rc >= (int)sizeof(packet)) {
|
||||
memcpy(&packet, data, sizeof(packet));
|
||||
if (packet.type == ICMP_ECHOREPLY) {
|
||||
emit recvPing(htons(packet.un.echo.sequence));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxPingSender::rawSocketReady() {
|
||||
socklen_t slen = 0;
|
||||
unsigned char data[2048];
|
||||
int rc = recvfrom(m_socket, data, sizeof(data), MSG_DONTWAIT, NULL, &slen);
|
||||
if (rc <= 0) {
|
||||
logger.error() << "recvfrom failed:" << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the IP header
|
||||
const struct iphdr* ip = (struct iphdr*)data;
|
||||
int iphdrlen = ip->ihl * 4;
|
||||
if (rc < iphdrlen || iphdrlen < (int)sizeof(struct iphdr)) {
|
||||
logger.error() << "malformed IP packet:" << strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the ICMP packet
|
||||
struct icmphdr packet;
|
||||
if (inetChecksum(data + iphdrlen, rc - iphdrlen) != 0) {
|
||||
logger.warning() << "invalid checksum";
|
||||
return;
|
||||
}
|
||||
if (rc >= (iphdrlen + (int)sizeof(packet))) {
|
||||
memcpy(&packet, data + iphdrlen, sizeof(packet));
|
||||
quint16 id = htons(m_ident);
|
||||
if ((packet.type == ICMP_ECHOREPLY) && (packet.un.echo.id == id)) {
|
||||
emit recvPing(htons(packet.un.echo.sequence));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef LINUXPINGSENDER_H
|
||||
#define LINUXPINGSENDER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../client/mozilla/pingsender.h"
|
||||
|
||||
class QSocketNotifier;
|
||||
|
||||
class LinuxPingSender final : public PingSender {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(LinuxPingSender)
|
||||
|
||||
public:
|
||||
LinuxPingSender(const QHostAddress& source, QObject* parent = nullptr);
|
||||
~LinuxPingSender();
|
||||
|
||||
bool isValid() override { return (m_socket >= 0); };
|
||||
|
||||
void sendPing(const QHostAddress& dest, quint16 sequence) override;
|
||||
|
||||
private:
|
||||
int createSocket();
|
||||
|
||||
private slots:
|
||||
void rawSocketReady();
|
||||
void icmpSocketReady();
|
||||
|
||||
private:
|
||||
QSocketNotifier* m_notifier = nullptr;
|
||||
int m_socket = -1;
|
||||
quint16 m_ident = 0;
|
||||
};
|
||||
|
||||
#endif // LINUXPINGSENDER_H
|
||||
@@ -10,8 +10,28 @@
|
||||
#include "../ios/iosnetworkwatcher.h"
|
||||
#include "networkwatcherimpl.h"
|
||||
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include <IOKit/IOMessage.h>
|
||||
|
||||
|
||||
class QString;
|
||||
|
||||
// Inspired by https://ladydebug.com/blog/2020/05/21/programmatically-capture-energy-saver-event-on-mac/
|
||||
class PowerNotificationsListener
|
||||
{
|
||||
public:
|
||||
void registerForNotifications();
|
||||
|
||||
private:
|
||||
static void sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument);
|
||||
|
||||
private:
|
||||
IONotificationPortRef notifyPortRef = nullptr; // notification port allocated by IORegisterForSystemPower
|
||||
io_object_t notifierObj = IO_OBJECT_NULL; // notifier object, used to deregister later
|
||||
io_connect_t rootPowerDomain = IO_OBJECT_NULL; // a reference to the Root Power Domain IOService
|
||||
};
|
||||
|
||||
|
||||
class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
||||
public:
|
||||
MacOSNetworkWatcher(QObject* parent);
|
||||
@@ -25,6 +45,7 @@ class MacOSNetworkWatcher final : public IOSNetworkWatcher {
|
||||
|
||||
private:
|
||||
void* m_delegate = nullptr;
|
||||
PowerNotificationsListener m_powerlistener;
|
||||
};
|
||||
|
||||
#endif // MACOSNETWORKWATCHER_H
|
||||
|
||||
@@ -38,6 +38,93 @@ Logger logger("MacOSNetworkWatcher");
|
||||
|
||||
@end
|
||||
|
||||
void PowerNotificationsListener::registerForNotifications()
|
||||
{
|
||||
rootPowerDomain = IORegisterForSystemPower(this, ¬ifyPortRef, sleepWakeupCallBack, ¬ifierObj);
|
||||
if (rootPowerDomain == IO_OBJECT_NULL) {
|
||||
logger.debug() << "Failed to register for system power notifications!";
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug() << "IORegisterForSystemPower OK! Root port:" << rootPowerDomain;
|
||||
|
||||
// add the notification port to the application runloop
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
static void PowerNotificationsListener::sleepWakeupCallBack(void *refParam, io_service_t service, natural_t messageType, void *messageArgument)
|
||||
{
|
||||
Q_UNUSED(service)
|
||||
|
||||
auto listener = static_cast<PowerNotificationsListener *>(refParam);
|
||||
|
||||
switch (messageType) {
|
||||
case kIOMessageCanSystemSleep:
|
||||
/* Idle sleep is about to kick in. This message will not be sent for forced sleep.
|
||||
* Applications have a chance to prevent sleep by calling IOCancelPowerChange.
|
||||
* Most applications should not prevent idle sleep. Power Management waits up to
|
||||
* 30 seconds for you to either allow or deny idle sleep. If you don’t acknowledge
|
||||
* this power change by calling either IOAllowPowerChange or IOCancelPowerChange,
|
||||
* the system will wait 30 seconds then go to sleep.
|
||||
*/
|
||||
|
||||
logger.debug() << "System power message: can system sleep?";
|
||||
|
||||
// Uncomment to cancel idle sleep
|
||||
// IOCancelPowerChange(thiz->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||
|
||||
// Allow idle sleep
|
||||
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||
break;
|
||||
|
||||
case kIOMessageSystemWillNotSleep:
|
||||
/* Announces that the system has retracted a previous attempt to sleep; it
|
||||
* follows `kIOMessageCanSystemSleep`.
|
||||
*/
|
||||
logger.debug() << "System power message: system will NOT sleep.";
|
||||
break;
|
||||
|
||||
case kIOMessageSystemWillSleep:
|
||||
/* The system WILL go to sleep. If you do not call IOAllowPowerChange or
|
||||
* IOCancelPowerChange to acknowledge this message, sleep will be delayed by
|
||||
* 30 seconds.
|
||||
*
|
||||
* NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
|
||||
* however the system WILL still go to sleep.
|
||||
*/
|
||||
|
||||
logger.debug() << "System power message: system WILL sleep.";
|
||||
|
||||
IOAllowPowerChange(listener->rootPowerDomain, reinterpret_cast<long>(messageArgument));
|
||||
break;
|
||||
|
||||
case kIOMessageSystemWillPowerOn:
|
||||
/* Announces that the system is beginning to power the device tree; most devices
|
||||
* are still unavailable at this point.
|
||||
*/
|
||||
/* From the documentation:
|
||||
*
|
||||
* - kIOMessageSystemWillPowerOn is delivered at early wakeup time, before most hardware
|
||||
* has been powered on. Be aware that any attempts to access disk, network, the display,
|
||||
* etc. may result in errors or blocking your process until those resources become
|
||||
* available.
|
||||
*
|
||||
* So we do NOT log this event.
|
||||
*/
|
||||
break;
|
||||
|
||||
case kIOMessageSystemHasPoweredOn:
|
||||
/* Announces that the system and its devices have woken up. */
|
||||
logger.debug() << "System power message: system has powered on.";
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.debug() << "System power message: other event: " << messageType;
|
||||
/* Not a system sleep and wake notification. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MacOSNetworkWatcher::MacOSNetworkWatcher(QObject* parent) : IOSNetworkWatcher(parent) {
|
||||
MZ_COUNT_CTOR(MacOSNetworkWatcher);
|
||||
}
|
||||
@@ -66,6 +153,8 @@ void MacOSNetworkWatcher::start() {
|
||||
logger.debug() << "Delegate already registered";
|
||||
return;
|
||||
}
|
||||
|
||||
m_powerlistener.registerForNotifications();
|
||||
|
||||
CWWiFiClient* client = CWWiFiClient.sharedWiFiClient;
|
||||
if (!client) {
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "logger.h"
|
||||
#include "platforms/windows/daemon/windowsfirewall.h"
|
||||
#include "platforms/windows/daemon/windowssplittunnel.h"
|
||||
#include "platforms/windows/windowscommons.h"
|
||||
#include "windowsfirewall.h"
|
||||
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
@@ -32,9 +32,28 @@ WindowsNetworkWatcher::~WindowsNetworkWatcher() {
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT WindowsNetworkWatcher::PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
auto obj = reinterpret_cast<WindowsNetworkWatcher*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
if (!obj){
|
||||
logger.debug() << "obj not casted";
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
switch (uMsg) {
|
||||
case WM_POWERBROADCAST:
|
||||
if (wParam == PBT_APMRESUMESUSPEND) {
|
||||
emit obj->sleepMode();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WindowsNetworkWatcher::initialize() {
|
||||
logger.debug() << "initialize";
|
||||
|
||||
|
||||
DWORD negotiatedVersion;
|
||||
if (WlanOpenHandle(2, nullptr, &negotiatedVersion, &m_wlanHandle) !=
|
||||
ERROR_SUCCESS) {
|
||||
@@ -51,6 +70,25 @@ void WindowsNetworkWatcher::initialize() {
|
||||
return;
|
||||
}
|
||||
|
||||
const wchar_t* className = L"PowerMonitorClass";
|
||||
WNDCLASS wc = { 0 };
|
||||
wc.lpfnWndProc = &WindowsNetworkWatcher::PowerWndProcCallback;
|
||||
wc.hInstance = GetModuleHandle(NULL);
|
||||
wc.lpszClassName = className;
|
||||
wc.cbWndExtra = sizeof(WindowsNetworkWatcher*);
|
||||
|
||||
if (!RegisterClass(&wc)) {
|
||||
logger.debug() << "Failed to register window class in createPowerMonitorWindow.";
|
||||
return;
|
||||
}
|
||||
|
||||
HWND hwnd = CreateWindowEx(0, className, L"Power Monitor", 0, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), static_cast<LPVOID>(this));
|
||||
if (!hwnd) {
|
||||
logger.debug() << "Failed to create window in createPowerMonitorWindow.";
|
||||
return;
|
||||
}
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
|
||||
|
||||
logger.debug() << "callback registered";
|
||||
}
|
||||
|
||||
@@ -137,4 +175,4 @@ void WindowsNetworkWatcher::processWlan(PWLAN_NOTIFICATION_DATA data) {
|
||||
logger.debug() << "Unsecure network:" << logger.sensitive(ssid)
|
||||
<< "id:" << logger.sensitive(bssid);
|
||||
emit unsecuredNetwork(ssid, bssid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ class WindowsNetworkWatcher final : public NetworkWatcherImpl {
|
||||
|
||||
private:
|
||||
static void wlanCallback(PWLAN_NOTIFICATION_DATA data, PVOID context);
|
||||
static LRESULT PowerWndProcCallback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
void processWlan(PWLAN_NOTIFICATION_DATA data);
|
||||
|
||||
|
||||
@@ -179,6 +179,7 @@ void WindowsPingSender::pingEventReady() {
|
||||
return;
|
||||
}
|
||||
QString errmsg = WindowsUtils::getErrorMessage();
|
||||
emit criticalPingError();
|
||||
logger.error() << "No ping reply. Code: " << error
|
||||
<< " Message: " << errmsg;
|
||||
return;
|
||||
|
||||
@@ -103,6 +103,11 @@ QString VpnProtocol::vpnGateway() const
|
||||
return m_vpnGateway;
|
||||
}
|
||||
|
||||
QString VpnProtocol::vpnLocalAddress() const
|
||||
{
|
||||
return m_vpnLocalAddress;
|
||||
}
|
||||
|
||||
VpnProtocol *VpnProtocol::factory(DockerContainer container, const QJsonObject &configuration)
|
||||
{
|
||||
switch (container) {
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
|
||||
QString routeGateway() const;
|
||||
QString vpnGateway() const;
|
||||
QString vpnLocalAddress() const;
|
||||
|
||||
static VpnProtocol* factory(amnezia::DockerContainer container, const QJsonObject &configuration);
|
||||
|
||||
|
||||
@@ -17,6 +17,13 @@ WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *
|
||||
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
||||
});
|
||||
connect(m_impl.get(), &ControllerImpl::statusUpdated, this,
|
||||
[this](const QString& serverIpv4Gateway,
|
||||
const QString& deviceIpv4Address, uint64_t txBytes,
|
||||
uint64_t rxBytes) {
|
||||
m_vpnLocalAddress = deviceIpv4Address;
|
||||
});
|
||||
|
||||
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
||||
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
||||
m_impl->initialize(nullptr, nullptr);
|
||||
|
||||
@@ -1,2 +1,13 @@
|
||||
CUR_USER=$(whoami);\
|
||||
groups $CUR_USER
|
||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
|
||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
|
||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
|
||||
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
|
||||
else pm="uname"; opt="-a";\
|
||||
fi;\
|
||||
CUR_USER=$(whoami 2>/dev/null || echo $HOME | sed 's/.*\///');\
|
||||
echo $LANG | grep -qE '^(en_US.UTF-8|C.UTF-8|C)$' || export LC_ALL=C;\
|
||||
sudo -K;\
|
||||
cd ~;\
|
||||
if [ "$CUR_USER" = "root" ] || ( groups "$CUR_USER" | grep -E '\<(sudo|wheel)\>' ); then \
|
||||
sudo -nu $CUR_USER $pm $opt > /dev/null; sudo -n $pm $opt > /dev/null;\
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CUR_USER=$(whoami);\
|
||||
CUR_USER=$(whoami 2>/dev/null || echo $HOME | sed 's/.*\///');\
|
||||
sudo mkdir -p $DOCKERFILE_FOLDER;\
|
||||
sudo chown $CUR_USER $DOCKERFILE_FOLDER;\
|
||||
if ! sudo docker network ls | grep -q amnezia-dns-net; then sudo docker network create \
|
||||
|
||||
@@ -3334,8 +3334,8 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>ليس لدي المستخدم الصلحيات لأستخدام sudo</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>المستخدم ليس عضوًا في مجموعة sudo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
@@ -3399,7 +3399,7 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>خطأ في الخادم: خطأ في مدير الحزم</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
||||
@@ -3468,8 +3468,8 @@ It's okay as long as it's from someone you trust.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>The user does not have permission to use sudo</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>کاربر عضو گروه sudo نیست</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
@@ -3590,8 +3590,8 @@ It's okay as long as it's from someone you trust.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<translation>Server error: Packet manager error</translation>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>خطای سرور: خطای مدیر بسته</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="34"/>
|
||||
|
||||
@@ -3434,13 +3434,13 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>उपयोगकर्ता के पास sudo का उपयोग करने की अनुमति नहीं है</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>उपयोगकर्ता sudo समूह का सदस्य नहीं है</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<translation>सर्वर त्रुटि: पैकेट प्रबंधक त्रुटि</translation>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>सर्वर त्रुटि: पैकेज प्रबंधक त्रुटि</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
|
||||
@@ -3330,8 +3330,8 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>ဤအသုံးပြုသူသည် sudo ကိုအသုံးပြုရန်ခွင့်ပြုချက်မရှိပါ</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>ဤအသုံးပြုသူသည် sudo အုပ်စု၏အဖွဲ့ဝင်မဟုတ်ပါ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
@@ -3395,8 +3395,8 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<translation>ဆာဗာ မှားယွင်းမှု: Packet Manager မှားယွင်းမှု</translation>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>ဆာဗာ အမှား- Package manager အမှား</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="34"/>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../ui/qml/Components/AdLabel.qml" line="57"/>
|
||||
<source>Amnezia Premium - for access to any website</source>
|
||||
<translation>Amnezia Premium - для доступа к любым сайтам </translation>
|
||||
<translation>Amnezia Premium - для доступа к любым сайтам</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -15,37 +15,37 @@
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="31"/>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="34"/>
|
||||
<source>Active</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Активна</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="34"/>
|
||||
<source>Inactive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Не активна</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="47"/>
|
||||
<source>%1 out of %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 из %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="51"/>
|
||||
<source>Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online resources. Speeds up to 200 Mbps</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Доступ ко всем сайтам и онлайн-ресурсам. Скорость — до 200 Мбит/с</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="54"/>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Бесплатный неограниченный доступ к базовому набору сайтов и приложений, таким как Facebook, Instagram, Twitter (X), Discord, Telegram и другим. YouTube не включен в бесплатный тариф.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="125"/>
|
||||
<source>amnezia_free_support_bot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiAccountInfoModel.cpp" line="127"/>
|
||||
<source>amnezia_premium_support_bot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -53,17 +53,17 @@
|
||||
<message>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="203"/>
|
||||
<source>%1 installed successfully.</source>
|
||||
<translation type="unfinished">%1 успешно установлен.</translation>
|
||||
<translation>%1 успешно установлен.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="258"/>
|
||||
<source>API config reloaded</source>
|
||||
<translation type="unfinished">Конфигурация API перезагружена</translation>
|
||||
<translation>Конфигурация API перезагружена</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="262"/>
|
||||
<source>Successfully changed the country of connection to %1</source>
|
||||
<translation type="unfinished">Изменение страны подключения на %1</translation>
|
||||
<translation>Страна подключения изменена на %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -92,18 +92,18 @@
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="68"/>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Скорость до %1 Мбит/с. Безлимитный трафик.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="72"/>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="85"/>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>AmneziaFree предоставляет бесплатный неограниченный доступ к базовому набору сайтов и приложений, таким как Facebook, Instagram, Twitter (X), Discord, Telegram и другим. YouTube не включен в бесплатный тариф.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="82"/>
|
||||
<source>Amnezia Premium is VPN for comfortable work, downloading large files and watching videos in 8K resolution. Works for any sites with no restrictions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Работает для любых сайтов без ограничений.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="97"/>
|
||||
@@ -562,12 +562,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="97"/>
|
||||
<source>AmneziaWG settings</source>
|
||||
<translation type="unfinished">Настройки AmneziaWG</translation>
|
||||
<translation>Настройки AmneziaWG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="105"/>
|
||||
<source>MTU</source>
|
||||
<translation type="unfinished">MTU</translation>
|
||||
<translation>MTU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="181"/>
|
||||
@@ -577,7 +577,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="191"/>
|
||||
<source>Port</source>
|
||||
<translation type="unfinished">Порт</translation>
|
||||
<translation>Порт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="278"/>
|
||||
@@ -592,7 +592,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="289"/>
|
||||
<source>Only the settings for this device will be changed</source>
|
||||
<translation>Будут изменены настройки только для этого устройства.</translation>
|
||||
<translation>Будут изменены настройки только для этого устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgClientSettings.qml" line="290"/>
|
||||
@@ -1036,12 +1036,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="91"/>
|
||||
<source>WG settings</source>
|
||||
<translation type="unfinished">Настройки WG</translation>
|
||||
<translation>Настройки WG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="99"/>
|
||||
<source>MTU</source>
|
||||
<translation type="unfinished">MTU</translation>
|
||||
<translation>MTU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="116"/>
|
||||
@@ -1051,12 +1051,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="126"/>
|
||||
<source>Port</source>
|
||||
<translation type="unfinished">Порт</translation>
|
||||
<translation>Порт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="149"/>
|
||||
<source>Save</source>
|
||||
<translation type="unfinished">Сохранить</translation>
|
||||
<translation>Сохранить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolWireGuardClientSettings.qml" line="153"/>
|
||||
@@ -1508,7 +1508,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="46"/>
|
||||
<source>support@amnezia.org</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>support@amnezia.org</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mail</source>
|
||||
@@ -1526,7 +1526,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="50"/>
|
||||
<source>mailto:support@amnezia.org</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="57"/>
|
||||
@@ -1536,7 +1536,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="58"/>
|
||||
<source>Discover the source code</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Посмотреть исходный код</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="61"/>
|
||||
@@ -1551,7 +1551,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsAbout.qml" line="69"/>
|
||||
<source>Visit official website</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Посетить официальный сайт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>https://amnezia.org</source>
|
||||
@@ -1578,12 +1578,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="84"/>
|
||||
<source>Location for connection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Страны для подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiAvailableCountries.qml" line="123"/>
|
||||
<source>Unable change server location while there is an active connection</source>
|
||||
<translation type="unfinished">Невозможно изменить локацию во время активного соединения</translation>
|
||||
<translation>Невозможно изменить локацию во время активного соединения</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1591,57 +1591,57 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="45"/>
|
||||
<source>Active devices</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Активные устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="46"/>
|
||||
<source>Manage currently connected devices</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Управление подключенными устройствами</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="55"/>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Вы можете найти support tag во вкладке «Поддержка» или, в более ранних версиях приложения, нажав «+» на нижней панели, а затем три точки вверху страницы.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="69"/>
|
||||
<source> (current device)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation> (текущее устройство)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="70"/>
|
||||
<source>Support tag: </source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Support tag: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="70"/>
|
||||
<source>Last updated: </source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Последнее обновление: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="75"/>
|
||||
<source>Cannot unlink device during active connection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Невозможно отвязать устройство во время активного соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="79"/>
|
||||
<source>Are you sure you want to unlink this device?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Вы уверены, что хотите отвязать это устройство?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="80"/>
|
||||
<source>This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Это устройство будет отвязано от вашей подписки. Вы можете подключить его снова в любой момент, нажав кнопку "Подключиться".</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="81"/>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Продолжить</translation>
|
||||
<translation>Продолжить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="82"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Отменить</translation>
|
||||
<translation>Отменить</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1649,82 +1649,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="22"/>
|
||||
<source>Windows</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="23"/>
|
||||
<source>https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#windows</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="29"/>
|
||||
<source>macOS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="30"/>
|
||||
<source>https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#macos</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="36"/>
|
||||
<source>Android</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="37"/>
|
||||
<source>https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#android</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="43"/>
|
||||
<source>AndroidTV</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="44"/>
|
||||
<source>https://docs.amnezia.org/ru/documentation/instructions/android_tv_connect/</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="50"/>
|
||||
<source>iOS</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="51"/>
|
||||
<source>https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#ios</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="57"/>
|
||||
<source>Linux</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="58"/>
|
||||
<source>https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#linux</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="64"/>
|
||||
<source>Routers</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="65"/>
|
||||
<source>https://docs.amnezia.org/documentation/instructions/connect-amnezia-premium#routers</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="101"/>
|
||||
<source>How to connect on another device</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Как подключить другие устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiInstructions.qml" line="102"/>
|
||||
<source>Setup guides on the Amnezia website</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Инструкции по настройке</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1739,82 +1739,82 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="23"/>
|
||||
<source>Save AmneziaVPN config</source>
|
||||
<translation type="unfinished">Сохранить конфигурацию AmneziaVPN</translation>
|
||||
<translation>Сохранить конфигурацию AmneziaVPN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="48"/>
|
||||
<source>Configuration files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="49"/>
|
||||
<source>For router setup or the AmneziaWG app</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Для настройки роутера или приложения AmneziaWG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="61"/>
|
||||
<source>The configuration needs to be reissued</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Необходимо заново скачать конфигурацию и добавить ее в приложение</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="126"/>
|
||||
<source> configuration file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation> файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="132"/>
|
||||
<source>Generate a new configuration file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Создать новый файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="133"/>
|
||||
<source>The previously created one will stop working</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ранее созданный файл перестанет работать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="144"/>
|
||||
<source>Revoke the current configuration file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Отозвать текущий файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="177"/>
|
||||
<source>Config file saved</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Файл конфигурации сохранен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="191"/>
|
||||
<source>The config has been revoked</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Конфигурация была отозвана</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="198"/>
|
||||
<source>Generate a new %1 configuration file?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Создать новый %1 файл конфигурации?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="200"/>
|
||||
<source>Revoke the current %1 configuration file?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Отозвать текущий %1 файл конфигурации?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="203"/>
|
||||
<source>Your previous configuration file will no longer work, and it will not be possible to connect using it</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ваш предыдущий файл конфигурации не будет работать, и вы больше не сможете использовать его для подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="204"/>
|
||||
<source>Download</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Скачать</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="204"/>
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished">Продолжить</translation>
|
||||
<translation>Продолжить</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="205"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Отменить</translation>
|
||||
<translation>Отменить</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1834,7 +1834,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="37"/>
|
||||
<source>Valid until</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Действует до</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed</source>
|
||||
@@ -1847,67 +1847,67 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="29"/>
|
||||
<source>Subscription status</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Статус подписки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="45"/>
|
||||
<source>Active connections</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Активные соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="171"/>
|
||||
<source>Configurations have been updated for some countries. Download and install the updated configuration files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="186"/>
|
||||
<source>Subscription key</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ключ для подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="190"/>
|
||||
<source>Amnezia Premium subscription key</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ключ подписки Amnezia Premium</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="194"/>
|
||||
<source>Save VPN key to file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Сохранить VPN-ключ в файле</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="195"/>
|
||||
<source>Copy VPN key</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Скопировать VPN ключ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="216"/>
|
||||
<source>Configuration files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="218"/>
|
||||
<source>Manage configuration files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Управление файлами конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="236"/>
|
||||
<source>Active devices</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Активные устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="238"/>
|
||||
<source>Manage currently connected devices</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Управление подключенными устройствами</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="255"/>
|
||||
<source>Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Поддержка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="270"/>
|
||||
<source>How to connect on another device</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Как подключить другие устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="295"/>
|
||||
@@ -1941,22 +1941,22 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="332"/>
|
||||
<source>Unlink this device</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Отвязать это устройство</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="335"/>
|
||||
<source>Are you sure you want to unlink this device?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Вы уверены, что хотите отвязать это устройство?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="336"/>
|
||||
<source>This will unlink the device from your subscription. You can reconnect it anytime by pressing Connect.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Это устройство будет отвязано от вашей подписки. Вы можете подключить его снова в любой момент, нажав кнопку Подключиться.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="342"/>
|
||||
<source>Cannot unlink device during active connection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Невозможно отвязать устройство во время активного соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="370"/>
|
||||
@@ -1979,57 +1979,57 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="22"/>
|
||||
<source>Telegram</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="30"/>
|
||||
<source>Email Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Email</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="31"/>
|
||||
<source>support@amnezia.org</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="38"/>
|
||||
<source>Email Billing & Orders</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>По вопросам оплаты</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="39"/>
|
||||
<source>help@vpnpay.io</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="46"/>
|
||||
<source>Website</source>
|
||||
<translation type="unfinished">Веб-сайт</translation>
|
||||
<translation>Сайт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="47"/>
|
||||
<source>amnezia.org</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>amnezia.org</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="81"/>
|
||||
<source>Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Поддержка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="82"/>
|
||||
<source>Our technical support specialists are available to assist you at any time</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Наши специалисты технической поддержки всегда готовы помочь вам.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="109"/>
|
||||
<source>Support tag</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="119"/>
|
||||
<source>Copied</source>
|
||||
<translation type="unfinished">Скопировано</translation>
|
||||
<translation>Скопировано</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2730,27 +2730,27 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="98"/>
|
||||
<source> connection settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation> настройки подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="110"/>
|
||||
<source>Click the "connect" button to create a connection configuration</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Нажмите кнопку «Подключиться», чтобы создать конфигурацию</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="130"/>
|
||||
<source> server settings</source>
|
||||
<translation type="unfinished"> настройки сервера</translation>
|
||||
<translation> настройки сервера</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="172"/>
|
||||
<source>Clear profile</source>
|
||||
<translation type="unfinished">Очистить профиль</translation>
|
||||
<translation>Очистить профиль</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="176"/>
|
||||
<source>The connection configuration will be deleted for this device only</source>
|
||||
<translation type="unfinished">Конфигурация подключения будет удалена только для этого устройства</translation>
|
||||
<translation>Конфигурация подключения будет удалена только на этом устройстве</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsServerProtocol.qml" line="182"/>
|
||||
@@ -3201,17 +3201,17 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardEasy.qml" line="68"/>
|
||||
<source>Choose Installation Type</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Выберите тип установки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardEasy.qml" line="142"/>
|
||||
<source>Manual</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ручная</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardEasy.qml" line="143"/>
|
||||
<source>Choose a VPN protocol</source>
|
||||
<translation>Выберите VPN-протокол</translation>
|
||||
<translation>Выбрать VPN-протокол</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardEasy.qml" line="200"/>
|
||||
@@ -3711,7 +3711,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="134"/>
|
||||
<source>Access error!</source>
|
||||
<translation type="unfinished">Ошибка доступа!</translation>
|
||||
<translation>Ошибка доступа!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShareFullAccess.qml" line="140"/>
|
||||
@@ -4009,7 +4009,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="15"/>
|
||||
<source>The selected protocol is not supported on the current platform</source>
|
||||
<translation type="unfinished">Выбранный протокол не поддерживается на данном устройстве</translation>
|
||||
<translation>Выбранный протокол не поддерживается на данном устройстве</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="18"/>
|
||||
@@ -4038,13 +4038,13 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>У пользователя нет прав на использование sudo</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>Пользователь не входит в группу sudo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="24"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<translation>Ошибка сервера: ошибка менеджера пакетов</translation>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>Ошибка сервера: Ошибка менеджера пакетов</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="27"/>
|
||||
@@ -4217,7 +4217,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<location filename="../core/errorstrings.cpp" line="55"/>
|
||||
<source>VPN Protocols is not installed.
|
||||
Please install VPN container at first</source>
|
||||
<translation type="unfinished">VPN-протоколы не установлены.
|
||||
<translation>VPN-протоколы не установлены.
|
||||
Пожалуйста, установите протокол</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -4248,7 +4248,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="67"/>
|
||||
<source>Failed to decrypt response payload</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="68"/>
|
||||
@@ -4258,7 +4258,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="69"/>
|
||||
<source>The limit of allowed configurations per subscription has been exceeded</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Превышен лимит разрешенных конфигураций для одной подписки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="73"/>
|
||||
@@ -4435,27 +4435,27 @@ While it offers a blend of security, stability, and speed, it's essential t
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="113"/>
|
||||
<source>Shadowsocks masks VPN traffic, making it resemble normal web traffic, but it may still be detected by certain analysis systems.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Shadowsocks маскирует VPN-трафик, делая его похожим на обычный веб-трафик, но он все равно может быть обнаружен некоторыми системами анализа.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="115"/>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>OpenVPN over Cloak — OpenVPN с маскировкой под веб-трафик , а также с защитой от обнаружения и систем анализа трафика. Он очень устойчив к обнаружению, но имеет низкую скорость работы в сравнении с другими похожими протоколами.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="118"/>
|
||||
<source>WireGuard - popular VPN protocol with high performance, high speed and low power consumption.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>WireGuard — популярный VPN-протокол с высокой производительностью, высокой скоростью и низким энергопотреблением.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="121"/>
|
||||
<source>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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>AmneziaWG — специальный протокол от Amnezia, основанный на WireGuard. Он обеспечивает высокую скорость соединения и гарантирует стабильную работу даже в самых сложных условиях.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="124"/>
|
||||
<source>XRay with REALITY masks VPN traffic as web traffic and protects against active probing. It is highly resistant to detection and offers high speed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>XRay с REALITY маскирует VPN-трафик под веб-трафик. Обладает высокой устойчивостью к обнаружению и обеспечивает высокую скорость соединения.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="143"/>
|
||||
@@ -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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>OpenVPN является одним из самых популярных и проверенных временем VPN-протоколов. Он использует собственный протокол безопасности, и криптографические протоколы SSL/TLS для шифрования и обмена ключами. Более того, поддержка множества методов аутентификации делает OpenVPN универсальным, адаптируемым и подходящим для широкого спектра устройств и операционных систем. Благодаря своему открытому коду, OpenVPN подвергается тщательной проверке со стороны мирового сообщества, что постоянно укрепляет его безопасность. Имея отличный баланс между производительностью, безопасностью и совместимостью OpenVPN остается лучшим выбором для людей и компаний, заботящихся о конфиденциальности, однако OpenVPN легко распознается современными системами анализа трафика.
|
||||
Доступен в AmneziaVPN на всех платформах
|
||||
Нормальное энергопотребление на мобильных устройствах
|
||||
Гибкая настройка полезная при работе с различными операционными системами и устройствами
|
||||
Распознается системами DPI и, следовательно, уязвим к блокировкам
|
||||
Может работать как по TCP, так и по UDP протоколу.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="168"/>
|
||||
@@ -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.
|
||||
</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Это связка протокола OpenVPN и плагина Cloak, созданная специально для защиты от обнаружения.
|
||||
|
||||
OpenVPN обеспечивает безопасное VPN-соединение, шифруя весь интернет-трафик между клиентом и сервером.
|
||||
|
||||
Плагин Cloak защищает OpenVPN от обнаружения.
|
||||
|
||||
Cloak может изменять метаданные пакета, чтобы полностью замаскировать VPN-трафик под обычный веб-трафик, а также защищает VPN от обнаружения с помощью метода Active Probing. Это делает его очень устойчивым к обнаружению.
|
||||
|
||||
Сразу после получения первого пакета данных Cloak аутентифицирует входящее соединение, если аутентификация не удалась, плагин маскирует сервер под настоящий веб-сайт, и ваш VPN становится невидимым для систем анализа. Имеет низкую скорость работы в сравнении с другими похожими протоколами.
|
||||
|
||||
* Доступно в AmneziaVPN на всех платформах.
|
||||
* Высокое энергопотребление на мобильных устройствах
|
||||
* Гибкие настройки
|
||||
* Не распознается системами обнаружения.
|
||||
* Работает по сетевому протоколу TCP, порт 443.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="185"/>
|
||||
@@ -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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Популярный VPN-протокол с упрощенной архитектурой.
|
||||
WireGuard обеспечивает стабильное VPN-соединение и высокую производительность на всех устройствах. Он использует закодированные настройки шифрования. WireGuard по сравнению с OpenVPN имеет меньшую задержку и лучшую пропускную способность передачи данных.
|
||||
WireGuard очень чувствителен к обнаружению и блокировке из-за различных сигнатур пакетов. В отличие от некоторых других VPN протоколов, использующих методы запутывания, последовательные шаблоны сигнатур пакетов WireGuard легко идентифицируются системами анализа трафика.
|
||||
|
||||
* Доступно в AmneziaVPN на всех платформах.
|
||||
* Низкое энергопотребление
|
||||
* Минимальное количество настроек
|
||||
* Легко распознается системами анализа DPI, подвержен блокировке.
|
||||
* Работает по сетевому протоколу UDP.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="198"/>
|
||||
@@ -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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>AmneziaWG — это современная версия популярного VPN протокола, основанная на базе WireGuard, сохранившая упрощенную архитектуру и высокопроизводительные возможности на всех устройствах.
|
||||
Хотя WireGuard известен своей эффективностью, обнаружить его довольно легко из-за различных сигнатур пакетов. AmneziaWG решает эту проблему, используя более совершенные методы работы, смешивая свой трафик с обычным интернет-трафиком.
|
||||
Это означает, что AmneziaWG сохраняет высокую производительность оригинала, добавляя при этом дополнительный уровень скрытности, что делает его отличным выбором для тех, кому нужно быстрое и незаметное VPN-соединение.
|
||||
|
||||
* Доступно в AmneziaVPN на всех платформах.
|
||||
* Низкое энергопотребление
|
||||
* Минимальное количество настроек
|
||||
* Не распознается системами анализа трафика.
|
||||
* Работает по сетевому протоколу UDP.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="214"/>
|
||||
@@ -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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Протокол REALITY, современная разработка от создателей XRay. Призван обеспечить высочайший уровень защиты от обнаружения благодаря инновационному подходу к безопасности и конфиденциальности.
|
||||
Он безошибочно идентифицирует злоумышленников на этапе установления связи TLS, беспрепятственно работая в качестве прокси-сервера для оригинального клиента и перенаправляя злоумышленников на подлинные веб-сайты, предоставляя тем самым подлинный сертификат TLS и данные.
|
||||
Эта расширенная возможность отличает REALITY от аналогичных технологий тем, что способна маскироваться под случайный веб-трафик без использования специальных настроек.
|
||||
В отличие от старых протоколов, таких как VMess, VLESS и транспорт XTLS-Vision, REALITY имеет инновационную технологию распознавания «свой-чужой».Это делает REALITY надежным решением для обеспечения доступа к свободному интернету.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WireGuard - New popular VPN protocol with high performance, high speed and low power consumption. Recommended for regions with low levels of censorship.</source>
|
||||
@@ -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.</source>
|
||||
<translation>Shadowsocks создан на основе протокола SOCKS5, защищает соединение с помощью шифра AEAD. Несмотря на то, что протокол Shadowsocks разработан таким образом, чтобы быть незаметным и сложным для идентификации, он не идентичен стандартному HTTPS-соединению. Поэтому некоторые системы анализа трафика всё же могут обнаружить соединение Shadowsocks. В связи с ограниченной поддержкой в Amnezia рекомендуется использовать протокол AmneziaWG.
|
||||
<translation>Shadowsocks создан на основе протокола SOCKS5, защищает соединение с помощью шифра AEAD. Несмотря на то, что протокол Shadowsocks разработан таким образом, чтобы быть незаметным и сложным для идентификации, он не идентичен стандартному HTTPS-соединению, поэтому некоторые системы анализа трафика всё же могут обнаружить соединение Shadowsocks. В связи с ограниченной поддержкой в Amnezia рекомендуется использовать протокол AmneziaWG.
|
||||
|
||||
* Доступен в AmneziaVPN только для ПК и ноутбуков
|
||||
* Настраиваемый протокол шифрования
|
||||
* Распознается некоторыми системами DPI-анализа
|
||||
* Работает по сетевому протоколу TCP</translation>
|
||||
* Работает по сетевому протоколу TCP.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>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
|
||||
<message>
|
||||
<location filename="../ui/qml/Components/RenameServerDrawer.qml" line="30"/>
|
||||
<source>Server name</source>
|
||||
<translation type="unfinished">Имя сервера</translation>
|
||||
<translation>Имя сервера</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Components/RenameServerDrawer.qml" line="41"/>
|
||||
<source>Save</source>
|
||||
<translation type="unfinished">Сохранить</translation>
|
||||
<translation>Сохранить</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -4932,7 +4971,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||
<message>
|
||||
<location filename="../ui/qml/Components/ServersListView.qml" line="86"/>
|
||||
<source>Unable change server while there is an active connection</source>
|
||||
<translation type="unfinished">Невозможно изменить сервер во время активного соединения</translation>
|
||||
<translation>Невозможно изменить сервер во время активного соединения</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -5186,12 +5225,12 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="338"/>
|
||||
<source>Automatic</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Автоматическая</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../containers/containers_defs.cpp" line="346"/>
|
||||
<source>AmneziaWG protocol will be installed. It provides high connection speed and ensures stable operation even in the most challenging network conditions.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Будет установлен протокол AmneziaWG. Он обеспечивает высокую скорость соединения и гарантирует стабильную работу даже в самых сложных условиях.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -3700,13 +3700,13 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>The user does not have permission to use sudo</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>Користувач не входить до групи sudo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>Помилка сервера: Помилка менеджера пакетів</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
|
||||
@@ -3433,8 +3433,8 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>صارف کو sudo استعمال کرنے کی اجازت نہیں ہے</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>صارف sudo گروپ کا رکن نہیں ہے</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
@@ -3498,7 +3498,7 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>سرور خطا: پیکیج منیجر خطا</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
||||
@@ -3675,13 +3675,13 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="22"/>
|
||||
<source>The user does not have permission to use sudo</source>
|
||||
<translation>用户没有root权限</translation>
|
||||
<source>The user is not a member of the sudo group</source>
|
||||
<translation>用户不是 sudo 组的成员</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="23"/>
|
||||
<source>Server error: Packet manager error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>服务器错误:包管理器错误</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace
|
||||
constexpr char cloak[] = "cloak";
|
||||
constexpr char awg[] = "awg";
|
||||
|
||||
constexpr char apiEdnpoint[] = "api_endpoint";
|
||||
constexpr char apiEndpoint[] = "api_endpoint";
|
||||
constexpr char accessToken[] = "api_key";
|
||||
constexpr char certificate[] = "certificate";
|
||||
constexpr char publicKey[] = "public_key";
|
||||
@@ -251,7 +251,6 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||
|
||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||
newServerConfig.insert(configKey::authData, authData);
|
||||
// newServerConfig.insert(
|
||||
|
||||
m_serversModel->editServer(newServerConfig, serverIndex);
|
||||
if (reloadServiceConfig) {
|
||||
@@ -270,54 +269,37 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||
|
||||
bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||
{
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
IosController::Instance()->requestInetAccess();
|
||||
QThread::msleep(10);
|
||||
#endif
|
||||
|
||||
if (serverConfig.value(config_key::configVersion).toInt()) {
|
||||
QNetworkRequest request;
|
||||
request.setTransferTimeout(apiDefs::requestTimeoutMsecs);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", "Api-Key " + serverConfig.value(configKey::accessToken).toString().toUtf8());
|
||||
QString endpoint = serverConfig.value(configKey::apiEdnpoint).toString();
|
||||
request.setUrl(endpoint);
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
|
||||
|
||||
QString protocol = serverConfig.value(configKey::protocol).toString();
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||
QString serviceProtocol = serverConfig.value(configKey::protocol).toString();
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||
|
||||
QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
|
||||
apiPayload[configKey::uuid] = installationUuid;
|
||||
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
|
||||
apiPayload[configKey::uuid] = installationUuid;
|
||||
apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString();
|
||||
apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString();
|
||||
|
||||
QByteArray requestBody = QJsonDocument(apiPayload).toJson();
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
|
||||
|
||||
QNetworkReply *reply = amnApp->networkManager()->post(request, requestBody);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
|
||||
|
||||
QEventLoop wait;
|
||||
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||
|
||||
QList<QSslError> sslErrors;
|
||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||
wait.exec();
|
||||
|
||||
auto errorCode = apiUtils::checkNetworkReplyErrors(sslErrors, reply);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
reply->deleteLater();
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto apiResponseBody = reply->readAll();
|
||||
reply->deleteLater();
|
||||
fillServerConfig(protocol, apiPayloadData, apiResponseBody, serverConfig);
|
||||
m_serversModel->editServer(serverConfig, serverIndex);
|
||||
emit updateServerFromApiFinished();
|
||||
return true;
|
||||
} else {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApiConfigsController::deactivateDevice()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -97,6 +94,8 @@ bool ImportController::extractConfigFromFile(const QString &fileName)
|
||||
|
||||
bool ImportController::extractConfigFromData(QString data)
|
||||
{
|
||||
m_maliciousWarningText.clear();
|
||||
|
||||
QString config = data;
|
||||
QString prefix;
|
||||
QString errormsg;
|
||||
@@ -345,7 +344,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);
|
||||
@@ -661,6 +660,7 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
|
||||
if ((containerName == ContainerProps::containerToString(DockerContainer::OpenVpn))
|
||||
|| (containerName == ContainerProps::containerToString(DockerContainer::Cloak))
|
||||
|| (containerName == ContainerProps::containerToString(DockerContainer::ShadowSocks))) {
|
||||
|
||||
QString protocolConfig =
|
||||
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
|
||||
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
|
||||
@@ -682,8 +682,11 @@ void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
|
||||
}
|
||||
}
|
||||
|
||||
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.size() >= dangerousTagsMaxCount) {
|
||||
m_maliciousWarningText = tr("In the imported configuration, potentially dangerous lines were found:");
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#include "languageModel.h"
|
||||
|
||||
LanguageModel::LanguageModel(std::shared_ptr<Settings> settings, QObject *parent)
|
||||
: m_settings(settings), QAbstractListModel(parent)
|
||||
LanguageModel::LanguageModel(std::shared_ptr<Settings> settings, QObject *parent) : m_settings(settings), QAbstractListModel(parent)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<LanguageSettings::AvailableLanguageEnum>();
|
||||
for (int i = 0; i < metaEnum.keyCount(); i++) {
|
||||
m_availableLanguages.push_back(
|
||||
LanguageModelData {getLocalLanguageName(static_cast<LanguageSettings::AvailableLanguageEnum>(i)),
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
|
||||
m_availableLanguages.push_back(LanguageModelData { getLocalLanguageName(static_cast<LanguageSettings::AvailableLanguageEnum>(i)),
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(i) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +48,7 @@ QString LanguageModel::getLocalLanguageName(const LanguageSettings::AvailableLan
|
||||
case LanguageSettings::AvailableLanguageEnum::Burmese: strLanguage = "မြန်မာဘာသာ"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Urdu: strLanguage = "اُرْدُوْ"; break;
|
||||
case LanguageSettings::AvailableLanguageEnum::Hindi: strLanguage = "हिन्दी"; break;
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return strLanguage;
|
||||
@@ -104,11 +101,12 @@ QString LanguageModel::getCurrentLanguageName()
|
||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
||||
}
|
||||
|
||||
QString LanguageModel::getCurrentSiteUrl()
|
||||
QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
||||
{
|
||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||
switch (language) {
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian: return "https://storage.googleapis.com/amnezia/amnezia.org";
|
||||
default: return "https://amnezia.org";
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian:
|
||||
return "https://storage.googleapis.com/amnezia/amnezia.org" + (path.isEmpty() ? "" : (QString("?m-path=/%1").arg(path)));
|
||||
default: return QString("https://amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public slots:
|
||||
int getCurrentLanguageIndex();
|
||||
int getLineHeightAppend();
|
||||
QString getCurrentLanguageName();
|
||||
QString getCurrentSiteUrl();
|
||||
QString getCurrentSiteUrl(const QString &path = "");
|
||||
|
||||
signals:
|
||||
void updateTranslations(const QLocale &locale);
|
||||
|
||||
@@ -29,7 +29,7 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/premium")
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("premium"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -252,7 +252,7 @@ PageType {
|
||||
text: qsTr("Privacy Policy")
|
||||
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("policy"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ PageType {
|
||||
leftImageSource: "qrc:/images/controls/help-circle.svg"
|
||||
|
||||
onClicked: {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/starter-guide")
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("starter-guide"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ PageType {
|
||||
height: containers.contentItem.height
|
||||
spacing: 16
|
||||
|
||||
currentIndex: 1
|
||||
currentIndex: 0
|
||||
clip: true
|
||||
interactive: false
|
||||
model: proxyContainersModel
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <QHostInfo>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "core/controllers/serverController.h"
|
||||
#include <configurators/cloak_configurator.h>
|
||||
#include <configurators/openvpn_configurator.h>
|
||||
#include <configurators/shadowsocks_configurator.h>
|
||||
@@ -14,7 +13,6 @@
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
#include "core/ipcclient.h"
|
||||
#include "ipc.h"
|
||||
#include <protocols/wireguardprotocol.h>
|
||||
#endif
|
||||
|
||||
@@ -54,7 +52,6 @@ void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes)
|
||||
|
||||
void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
{
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
auto container = m_settings->defaultContainer(m_settings->defaultServerIndex());
|
||||
|
||||
@@ -86,6 +83,10 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
}
|
||||
}
|
||||
|
||||
if (container != DockerContainer::Ipsec) {
|
||||
IpcClient::Interface()->startNetworkCheck(m_vpnProtocol->vpnLocalAddress(), m_vpnProtocol->vpnLocalAddress());
|
||||
}
|
||||
|
||||
} else if (state == Vpn::ConnectionState::Error) {
|
||||
IpcClient::Interface()->flushDns();
|
||||
|
||||
@@ -97,6 +98,8 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
|
||||
} else if (state == Vpn::ConnectionState::Connecting) {
|
||||
|
||||
} else if (state == Vpn::ConnectionState::Disconnected) {
|
||||
auto result = IpcClient::Interface()->stopNetworkCheck();
|
||||
result.waitForFinished(3000);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -219,6 +222,11 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
.arg(serverIndex)
|
||||
.arg(ContainerProps::containerToString(container));
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if (m_IpcClient) {
|
||||
m_IpcClient->close();
|
||||
m_IpcClient = nullptr;
|
||||
}
|
||||
|
||||
if (!m_IpcClient) {
|
||||
m_IpcClient = new IpcClient(this);
|
||||
}
|
||||
@@ -237,6 +245,9 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Connecting);
|
||||
|
||||
m_vpnConfiguration = vpnConfiguration;
|
||||
m_serverIndex = serverIndex;
|
||||
m_serverCredentials = credentials;
|
||||
m_dockerContainer = container;
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
if (m_vpnProtocol) {
|
||||
@@ -275,12 +286,36 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
|
||||
emit connectionStateChanged(Vpn::ConnectionState::Error);
|
||||
}
|
||||
|
||||
void VpnConnection::restartConnection()
|
||||
{
|
||||
this->disconnectFromVpn();
|
||||
#ifdef Q_OS_LINUX
|
||||
QThread::msleep(5000);
|
||||
#endif
|
||||
this->connectToVpn(m_serverIndex, m_serverCredentials, m_dockerContainer, m_vpnConfiguration);
|
||||
}
|
||||
|
||||
void VpnConnection::createProtocolConnections()
|
||||
{
|
||||
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
|
||||
connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(Vpn::ConnectionState)), this,
|
||||
SLOT(onConnectionStateChanged(Vpn::ConnectionState)));
|
||||
connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64)));
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
connect(IpcClient::Interface().data(), &IpcInterfaceReplica::connectionLose,
|
||||
this, [this]() {
|
||||
qDebug() << "Connection Lose";
|
||||
auto result = IpcClient::Interface()->stopNetworkCheck();
|
||||
result.waitForFinished(3000);
|
||||
this->restartConnection();
|
||||
});
|
||||
connect(IpcClient::Interface().data(), &IpcInterfaceReplica::networkChange,
|
||||
this, [this]() {
|
||||
qDebug() << "Network change";
|
||||
this->restartConnection();
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void VpnConnection::appendKillSwitchConfig()
|
||||
|
||||
@@ -51,6 +51,7 @@ public slots:
|
||||
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration);
|
||||
|
||||
void disconnectFromVpn();
|
||||
void restartConnection();
|
||||
|
||||
|
||||
void addRoutes(const QStringList &ips);
|
||||
@@ -77,6 +78,10 @@ private:
|
||||
QJsonObject m_routeMode;
|
||||
QString m_remoteAddress;
|
||||
|
||||
ServerCredentials m_serverCredentials;
|
||||
int m_serverIndex;
|
||||
DockerContainer m_dockerContainer;
|
||||
|
||||
// Only for iOS for now, check counters
|
||||
QTimer m_checkTimer;
|
||||
|
||||
|
||||
@@ -32,5 +32,10 @@ class IpcInterface
|
||||
SLOT( bool enablePeerTraffic( const QJsonObject &configStr) );
|
||||
SLOT( bool enableKillSwitch( const QJsonObject &excludeAddr, int vpnAdapterIndex) );
|
||||
SLOT( bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) );
|
||||
SLOT( bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) );
|
||||
SLOT( bool stopNetworkCheck() );
|
||||
|
||||
SIGNAL( connectionLose() );
|
||||
SIGNAL( networkChange() );
|
||||
};
|
||||
|
||||
|
||||
+14
-1
@@ -25,8 +25,8 @@
|
||||
#endif
|
||||
|
||||
IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent)
|
||||
|
||||
{
|
||||
connect(&m_pingHelper, &PingHelper::connectionLose, this, &IpcServer::connectionLose);
|
||||
}
|
||||
|
||||
int IpcServer::createPrivilegedProcess()
|
||||
@@ -188,6 +188,19 @@ void IpcServer::setLogsEnabled(bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
bool IpcServer::startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address)
|
||||
{
|
||||
m_pingHelper.start(serverIpv4Gateway, deviceIpv4Address);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::stopNetworkCheck()
|
||||
{
|
||||
qDebug() << "stopNetworkCheck";
|
||||
m_pingHelper.stop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QRemoteObjectNode>
|
||||
#include <QJsonObject>
|
||||
#include "../client/daemon/interfaceconfig.h"
|
||||
#include "../client/mozilla/pinghelper.h"
|
||||
|
||||
#include "ipc.h"
|
||||
#include "ipcserverprocess.h"
|
||||
@@ -38,6 +39,8 @@ public:
|
||||
virtual bool enableKillSwitch(const QJsonObject &excludeAddr, int vpnAdapterIndex) override;
|
||||
virtual bool disableKillSwitch() override;
|
||||
virtual bool updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers) override;
|
||||
virtual bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) override;
|
||||
virtual bool stopNetworkCheck() override;
|
||||
|
||||
private:
|
||||
int m_localpid = 0;
|
||||
@@ -57,6 +60,8 @@ private:
|
||||
};
|
||||
|
||||
QMap<int, ProcessDescriptor> m_processes;
|
||||
PingHelper m_pingHelper;
|
||||
|
||||
};
|
||||
|
||||
#endif // IPCSERVER_H
|
||||
|
||||
@@ -56,7 +56,6 @@ set(HEADERS ${HEADERS}
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/controllerimpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/dnspingsender.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/localsocketcontroller.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcher.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcherimpl.h
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pinghelper.h
|
||||
@@ -80,7 +79,6 @@ set(SOURCES ${SOURCES}
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/shared/leakdetector.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/dnspingsender.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/localsocketcontroller.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/networkwatcher.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pinghelper.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/../../client/mozilla/pingsender.cpp
|
||||
@@ -212,6 +210,7 @@ if(LINUX)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcher.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcherworker.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxdependencies.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxpingsender.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/iputilslinux.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/dbustypeslinux.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxdaemon.h
|
||||
@@ -226,6 +225,7 @@ if(LINUX)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcher.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxnetworkwatcherworker.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxdependencies.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/linuxpingsender.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/dnsutilslinux.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/iputilslinux.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../client/platforms/linux/daemon/linuxdaemon.cpp
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
|
||||
#include "ipc.h"
|
||||
#include "localserver.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include "router.h"
|
||||
#include "logger.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -47,6 +45,9 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent),
|
||||
return;
|
||||
}
|
||||
|
||||
m_networkWatcher.initialize();
|
||||
connect(&m_networkWatcher, &NetworkWatcher::sleepMode, &m_ipcServer, &IpcServer::networkChange);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// Signal handling for a proper shutdown.
|
||||
QObject::connect(qApp, &QCoreApplication::aboutToQuit,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "ipcserver.h"
|
||||
|
||||
#include "../../client/daemon/daemonlocalserver.h"
|
||||
|
||||
#include "../../client/mozilla/networkwatcher.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "windows/daemon/windowsdaemon.h"
|
||||
@@ -41,6 +41,8 @@ public:
|
||||
IpcProcessTun2Socks m_tun2socks;
|
||||
QRemoteObjectHost m_serverNode;
|
||||
bool m_isRemotingEnabled = false;
|
||||
|
||||
NetworkWatcher m_networkWatcher;
|
||||
#ifdef Q_OS_LINUX
|
||||
DaemonLocalServer server{qApp};
|
||||
LinuxDaemon daemon;
|
||||
|
||||
Reference in New Issue
Block a user