mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-21 02:15:51 +03:00
Compare commits
20 Commits
feature/ki
...
checking-L
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd6a47f9d9 | ||
|
|
39ab6dca1e | ||
|
|
52216043bb | ||
|
|
ded3995169 | ||
|
|
8156ac7757 | ||
|
|
d61e2bc8f6 | ||
|
|
9e1298550f | ||
|
|
805bc5fb61 | ||
|
|
3241782098 | ||
|
|
b19009b669 | ||
|
|
26218b22ee | ||
|
|
3eeeb5094e | ||
|
|
f309a358c3 | ||
|
|
be0ec37738 | ||
|
|
179c6093ce | ||
|
|
10933ce466 | ||
|
|
cd9cdd24ec | ||
|
|
144ed3c988 | ||
|
|
e046b6df04 | ||
|
|
548959752c |
4
.github/workflows/deploy.yml
vendored
4
.github/workflows/deploy.yml
vendored
@@ -10,7 +10,7 @@ env:
|
||||
|
||||
jobs:
|
||||
Build-Linux-Ubuntu:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.6.2
|
||||
@@ -190,7 +190,7 @@ jobs:
|
||||
- name: 'Install go'
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.24'
|
||||
go-version: '1.22.1'
|
||||
cache: false
|
||||
|
||||
- name: 'Setup gomobile'
|
||||
|
||||
61
.github/workflows/tag-upload.yml
vendored
61
.github/workflows/tag-upload.yml
vendored
@@ -1,41 +1,64 @@
|
||||
name: 'Upload a new version'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
RELEASE_VERSION:
|
||||
description: 'Release version (e.g. 1.2.3.4)'
|
||||
required: true
|
||||
type: string
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
Upload-S3:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
name: upload
|
||||
steps:
|
||||
- name: Checkout
|
||||
- name: Checkout CMakeLists.txt
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.RELEASE_VERSION }}
|
||||
ref: ${{ github.ref_name }}
|
||||
sparse-checkout: |
|
||||
CMakeLists.txt
|
||||
deploy/deploy_s3.sh
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Verify git tag
|
||||
run: |
|
||||
TAG_NAME=${{ inputs.RELEASE_VERSION }}
|
||||
GIT_TAG=${{ github.ref_name }}
|
||||
CMAKE_TAG=$(grep 'project.*VERSION' CMakeLists.txt | sed -E 's/.* ([0-9]+.[0-9]+.[0-9]+.[0-9]+)$/\1/')
|
||||
if [[ "$TAG_NAME" == "$CMAKE_TAG" ]]; then
|
||||
echo "Git tag ($TAG_NAME) matches CMakeLists.txt version ($CMAKE_TAG)."
|
||||
|
||||
if [[ "$GIT_TAG" == "$CMAKE_TAG" ]]; then
|
||||
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are the same. Continuing..."
|
||||
else
|
||||
echo "::error::Mismatch: Git tag ($TAG_NAME) != CMakeLists.txt version ($CMAKE_TAG). Exiting with error..."
|
||||
echo "Git tag ($GIT_TAG) and version in CMakeLists.txt ($CMAKE_TAG) are not the same! Cancelling..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Rclone
|
||||
uses: AnimMouse/setup-rclone@v1
|
||||
- name: Download artifacts from the "${{ github.ref_name }}" tag
|
||||
uses: robinraju/release-downloader@v1.8
|
||||
with:
|
||||
rclone_config: ${{ secrets.RCLONE_CONFIG }}
|
||||
tag: ${{ github.ref_name }}
|
||||
fileName: "AmneziaVPN_(Linux_|)${{ github.ref_name }}*"
|
||||
out-file-path: ${{ github.ref_name }}
|
||||
|
||||
- name: Send dist to S3
|
||||
run: bash deploy/deploy_s3.sh ${{ inputs.RELEASE_VERSION }}
|
||||
- name: Upload beta version
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: contains(github.event.base_ref, 'dev')
|
||||
with:
|
||||
args: --include "AmneziaVPN*" --delete
|
||||
env:
|
||||
AWS_S3_BUCKET: updates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
|
||||
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
|
||||
SOURCE_DIR: ${{ github.ref_name }}
|
||||
DEST_DIR: beta/${{ github.ref_name }}
|
||||
|
||||
- name: Upload stable version
|
||||
uses: jakejarvis/s3-sync-action@master
|
||||
if: contains(github.event.base_ref, 'master')
|
||||
with:
|
||||
args: --include "AmneziaVPN*" --delete
|
||||
env:
|
||||
AWS_S3_BUCKET: updates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_SECRET_ACCESS_KEY }}
|
||||
AWS_S3_ENDPOINT: https://${{ vars.CF_ACCOUNT_ID }}.r2.cloudflarestorage.com
|
||||
SOURCE_DIR: ${{ github.ref_name }}
|
||||
DEST_DIR: stable/${{ github.ref_name }}
|
||||
|
||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
|
||||
project(${PROJECT} VERSION 4.8.6.0
|
||||
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 2083)
|
||||
set(APP_ANDROID_VERSION_CODE 2082)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
|
||||
@@ -35,6 +35,10 @@ WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings,
|
||||
|
||||
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
|
||||
m_defaultPort = m_isAwg ? protocols::wireguard::defaultPort : protocols::awg::defaultPort;
|
||||
|
||||
m_interfaceName = m_isAwg ? protocols::awg::interfaceName : protocols::wireguard::interfaceName;
|
||||
m_wgBinaryName = m_isAwg ? protocols::awg::wgBinaryName : protocols::wireguard::wgBinaryName;
|
||||
m_wgQuickBinaryName = m_isAwg ? protocols::awg::wgQuickBinaryName : protocols::wireguard::wgQuickBinaryName;
|
||||
}
|
||||
|
||||
WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
|
||||
@@ -103,6 +107,20 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
|
||||
return connData;
|
||||
}
|
||||
|
||||
if (container == DockerContainer::Awg) {
|
||||
if (m_serverController->isNewAwgContainer(credentials)) {
|
||||
m_serverConfigPath = amnezia::protocols::awg::serverConfigPath;
|
||||
m_interfaceName = protocols::awg::interfaceName;
|
||||
m_wgBinaryName = protocols::awg::wgBinaryName;
|
||||
m_wgQuickBinaryName = protocols::awg::wgQuickBinaryName;
|
||||
} else {
|
||||
m_serverConfigPath = "/opt/amnezia/awg/wg0.conf";
|
||||
m_interfaceName = protocols::wireguard::interfaceName;
|
||||
m_wgBinaryName = protocols::wireguard::wgBinaryName;
|
||||
m_wgQuickBinaryName = protocols::wireguard::wgQuickBinaryName;
|
||||
}
|
||||
}
|
||||
|
||||
QString getIpsScript = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
@@ -168,8 +186,8 @@ 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 '%4 syncconf %2 <(%3 strip %1)'")
|
||||
.arg(m_serverConfigPath, m_interfaceName, m_wgQuickBinaryName, m_wgBinaryName);
|
||||
|
||||
errorCode = m_serverController->runScript(
|
||||
credentials,
|
||||
|
||||
@@ -49,6 +49,9 @@ private:
|
||||
amnezia::ProtocolScriptType m_configTemplate;
|
||||
QString m_protocolName;
|
||||
QString m_defaultPort;
|
||||
QString m_interfaceName;
|
||||
QString m_wgBinaryName;
|
||||
QString m_wgQuickBinaryName;
|
||||
};
|
||||
|
||||
#endif // WIREGUARD_CONFIGURATOR_H
|
||||
|
||||
@@ -10,8 +10,7 @@ namespace apiDefs
|
||||
AmneziaFreeV3,
|
||||
AmneziaPremiumV1,
|
||||
AmneziaPremiumV2,
|
||||
SelfHosted,
|
||||
ExternalPremium
|
||||
SelfHosted
|
||||
};
|
||||
|
||||
enum ConfigSource {
|
||||
@@ -44,13 +43,6 @@ namespace apiDefs
|
||||
constexpr QLatin1String maxDeviceCount("max_device_count");
|
||||
constexpr QLatin1String subscriptionEndDate("subscription_end_date");
|
||||
constexpr QLatin1String issuedConfigs("issued_configs");
|
||||
|
||||
constexpr QLatin1String supportInfo("support_info");
|
||||
constexpr QLatin1String email("email");
|
||||
constexpr QLatin1String billingEmail("billing_email");
|
||||
constexpr QLatin1String website("website");
|
||||
constexpr QLatin1String websiteName("website_name");
|
||||
constexpr QLatin1String telegram("telegram");
|
||||
}
|
||||
|
||||
const int requestTimeoutMsecs = 12 * 1000; // 12 secs
|
||||
|
||||
@@ -32,17 +32,15 @@ apiDefs::ConfigType apiUtils::getConfigType(const QJsonObject &serverConfigObjec
|
||||
|
||||
constexpr QLatin1String servicePremium("amnezia-premium");
|
||||
constexpr QLatin1String serviceFree("amnezia-free");
|
||||
constexpr QLatin1String serviceExternalPremium("external-premium");
|
||||
|
||||
auto apiConfigObject = serverConfigObject.value(apiDefs::key::apiConfig).toObject();
|
||||
auto stackType = apiConfigObject.value(apiDefs::key::stackType).toString();
|
||||
auto serviceType = apiConfigObject.value(apiDefs::key::serviceType).toString();
|
||||
|
||||
if (serviceType == servicePremium) {
|
||||
if (serviceType == servicePremium || stackType == stackPremium) {
|
||||
return apiDefs::ConfigType::AmneziaPremiumV2;
|
||||
} else if (serviceType == serviceFree) {
|
||||
} else if (serviceType == serviceFree || stackType == stackFree) {
|
||||
return apiDefs::ConfigType::AmneziaFreeV3;
|
||||
} else if (serviceType == serviceExternalPremium) {
|
||||
return apiDefs::ConfigType::ExternalPremium;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
@@ -68,7 +66,6 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
|
||||
return amnezia::ErrorCode::NoError;
|
||||
} else if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
|
||||
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) {
|
||||
qDebug() << reply->error();
|
||||
return amnezia::ErrorCode::ApiConfigTimeoutError;
|
||||
} else {
|
||||
QString err = reply->errorString();
|
||||
@@ -88,10 +85,3 @@ amnezia::ErrorCode apiUtils::checkNetworkReplyErrors(const QList<QSslError> &ssl
|
||||
qDebug() << "something went wrong";
|
||||
return amnezia::ErrorCode::InternalError;
|
||||
}
|
||||
|
||||
bool apiUtils::isPremiumServer(const QJsonObject &serverConfigObject)
|
||||
{
|
||||
static const QSet<apiDefs::ConfigType> premiumTypes = { apiDefs::ConfigType::AmneziaPremiumV1, apiDefs::ConfigType::AmneziaPremiumV2,
|
||||
apiDefs::ConfigType::ExternalPremium };
|
||||
return premiumTypes.contains(getConfigType(serverConfigObject));
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace apiUtils
|
||||
|
||||
bool isSubscriptionExpired(const QString &subscriptionEndDate);
|
||||
|
||||
bool isPremiumServer(const QJsonObject &serverConfigObject);
|
||||
|
||||
apiDefs::ConfigType getConfigType(const QJsonObject &serverConfigObject);
|
||||
apiDefs::ConfigSource getConfigSource(const QJsonObject &serverConfigObject);
|
||||
|
||||
|
||||
@@ -48,9 +48,6 @@ void CoreController::initModels()
|
||||
m_sitesModel.reset(new SitesModel(m_settings, this));
|
||||
m_engine->rootContext()->setContextProperty("SitesModel", m_sitesModel.get());
|
||||
|
||||
m_allowedDnsModel.reset(new AllowedDnsModel(m_settings, this));
|
||||
m_engine->rootContext()->setContextProperty("AllowedDnsModel", m_allowedDnsModel.get());
|
||||
|
||||
m_appSplitTunnelingModel.reset(new AppSplitTunnelingModel(m_settings, this));
|
||||
m_engine->rootContext()->setContextProperty("AppSplitTunnelingModel", m_appSplitTunnelingModel.get());
|
||||
|
||||
@@ -133,9 +130,6 @@ void CoreController::initControllers()
|
||||
m_sitesController.reset(new SitesController(m_settings, m_vpnConnection, m_sitesModel));
|
||||
m_engine->rootContext()->setContextProperty("SitesController", m_sitesController.get());
|
||||
|
||||
m_allowedDnsController.reset(new AllowedDnsController(m_settings, m_allowedDnsModel));
|
||||
m_engine->rootContext()->setContextProperty("AllowedDnsController", m_allowedDnsController.get());
|
||||
|
||||
m_appSplitTunnelingController.reset(new AppSplitTunnelingController(m_settings, m_appSplitTunnelingModel));
|
||||
m_engine->rootContext()->setContextProperty("AppSplitTunnelingController", m_appSplitTunnelingController.get());
|
||||
|
||||
@@ -220,7 +214,6 @@ void CoreController::initSignalHandlers()
|
||||
initAutoConnectHandler();
|
||||
initAmneziaDnsToggledHandler();
|
||||
initPrepareConfigHandler();
|
||||
initStrictKillSwitchHandler();
|
||||
}
|
||||
|
||||
void CoreController::initNotificationHandler()
|
||||
@@ -363,12 +356,6 @@ void CoreController::initPrepareConfigHandler()
|
||||
});
|
||||
}
|
||||
|
||||
void CoreController::initStrictKillSwitchHandler()
|
||||
{
|
||||
connect(m_settingsController.get(), &SettingsController::strictKillSwitchEnabledChanged,
|
||||
m_vpnConnection.get(), &VpnConnection::onKillSwitchModeChanged);
|
||||
}
|
||||
|
||||
QSharedPointer<PageController> CoreController::pageController() const
|
||||
{
|
||||
return m_pageController;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "ui/controllers/api/apiConfigsController.h"
|
||||
#include "ui/controllers/api/apiSettingsController.h"
|
||||
#include "ui/controllers/appSplitTunnelingController.h"
|
||||
#include "ui/controllers/allowedDnsController.h"
|
||||
#include "ui/controllers/connectionController.h"
|
||||
#include "ui/controllers/exportController.h"
|
||||
#include "ui/controllers/focusController.h"
|
||||
@@ -19,7 +18,6 @@
|
||||
#include "ui/controllers/sitesController.h"
|
||||
#include "ui/controllers/systemController.h"
|
||||
|
||||
#include "ui/models/allowed_dns_model.h"
|
||||
#include "ui/models/containers_model.h"
|
||||
#include "ui/models/languageModel.h"
|
||||
#include "ui/models/protocols/cloakConfigModel.h"
|
||||
@@ -82,7 +80,6 @@ private:
|
||||
void initAutoConnectHandler();
|
||||
void initAmneziaDnsToggledHandler();
|
||||
void initPrepareConfigHandler();
|
||||
void initStrictKillSwitchHandler();
|
||||
|
||||
QQmlApplicationEngine *m_engine {}; // TODO use parent child system here?
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
@@ -105,7 +102,6 @@ private:
|
||||
QScopedPointer<SitesController> m_sitesController;
|
||||
QScopedPointer<SystemController> m_systemController;
|
||||
QScopedPointer<AppSplitTunnelingController> m_appSplitTunnelingController;
|
||||
QScopedPointer<AllowedDnsController> m_allowedDnsController;
|
||||
|
||||
QScopedPointer<ApiSettingsController> m_apiSettingsController;
|
||||
QScopedPointer<ApiConfigsController> m_apiConfigsController;
|
||||
@@ -116,7 +112,6 @@ private:
|
||||
QSharedPointer<LanguageModel> m_languageModel;
|
||||
QSharedPointer<ProtocolsModel> m_protocolsModel;
|
||||
QSharedPointer<SitesModel> m_sitesModel;
|
||||
QSharedPointer<AllowedDnsModel> m_allowedDnsModel;
|
||||
QSharedPointer<AppSplitTunnelingModel> m_appSplitTunnelingModel;
|
||||
QSharedPointer<ClientManagementModel> m_clientManagementModel;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrl>
|
||||
|
||||
#include "QBlockCipher.h"
|
||||
#include "QRsa.h"
|
||||
@@ -15,11 +14,6 @@
|
||||
#include "amnezia_application.h"
|
||||
#include "core/api/apiUtils.h"
|
||||
#include "utilities.h"
|
||||
#include "core/networkUtilities.h"
|
||||
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
#include "core/ipcclient.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -56,17 +50,6 @@ ErrorCode GatewayController::get(const QString &endpoint, QByteArray &responseBo
|
||||
|
||||
request.setUrl(QString(endpoint).arg(m_gatewayEndpoint));
|
||||
|
||||
// bypass killSwitch exceptions for API-gateway
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
{
|
||||
QString host = QUrl(request.url()).host();
|
||||
QString ip = NetworkUtilities::getIPAddress(host);
|
||||
if (!ip.isEmpty()) {
|
||||
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList{ip});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QNetworkReply *reply;
|
||||
reply = amnApp->networkManager()->get(request);
|
||||
|
||||
@@ -118,17 +101,6 @@ ErrorCode GatewayController::post(const QString &endpoint, const QJsonObject api
|
||||
|
||||
request.setUrl(endpoint.arg(m_gatewayEndpoint));
|
||||
|
||||
// bypass killSwitch exceptions for API-gateway
|
||||
#ifdef AMNEZIA_DESKTOP
|
||||
{
|
||||
QString host = QUrl(request.url()).host();
|
||||
QString ip = NetworkUtilities::getIPAddress(host);
|
||||
if (!ip.isEmpty()) {
|
||||
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList{ip});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QSimpleCrypto::QBlockCipher blockCipher;
|
||||
QByteArray key = blockCipher.generatePrivateSalt(32);
|
||||
QByteArray iv = blockCipher.generatePrivateSalt(32);
|
||||
@@ -279,9 +251,6 @@ QStringList GatewayController::getProxyUrls()
|
||||
}
|
||||
return endpoints;
|
||||
} else {
|
||||
apiUtils::checkNetworkReplyErrors(sslErrors, reply);
|
||||
qDebug() << "go to the next storage endpoint";
|
||||
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
@@ -292,29 +261,26 @@ bool GatewayController::shouldBypassProxy(QNetworkReply *reply, const QByteArray
|
||||
const QByteArray &iv, const QByteArray &salt)
|
||||
{
|
||||
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
|
||||
qDebug() << "timeout occurred";
|
||||
qDebug() << reply->error();
|
||||
qDebug() << "Timeout occurred";
|
||||
return true;
|
||||
} else if (responseBody.contains("html")) {
|
||||
qDebug() << "the response contains an html tag";
|
||||
qDebug() << "The response contains an html tag";
|
||||
return true;
|
||||
} else if (reply->error() == QNetworkReply::NetworkError::ContentNotFoundError) {
|
||||
if (responseBody.contains(errorResponsePattern1) || responseBody.contains(errorResponsePattern2)
|
||||
|| responseBody.contains(errorResponsePattern3)) {
|
||||
return false;
|
||||
} else {
|
||||
qDebug() << reply->error();
|
||||
return true;
|
||||
}
|
||||
} else if (reply->error() != QNetworkReply::NetworkError::NoError) {
|
||||
qDebug() << reply->error();
|
||||
return true;
|
||||
} else if (checkEncryption) {
|
||||
try {
|
||||
QSimpleCrypto::QBlockCipher blockCipher;
|
||||
static_cast<void>(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
|
||||
} catch (...) {
|
||||
qDebug() << "failed to decrypt the data";
|
||||
qDebug() << "Failed to decrypt the data";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -335,7 +301,7 @@ void GatewayController::bypassProxy(const QString &endpoint, QNetworkReply *repl
|
||||
QByteArray responseBody;
|
||||
|
||||
for (const QString &proxyUrl : proxyUrls) {
|
||||
qDebug() << "go to the next proxy endpoint";
|
||||
qDebug() << "Go to the next endpoint";
|
||||
reply->deleteLater(); // delete the previous reply
|
||||
reply = requestFunction(endpoint.arg(proxyUrl));
|
||||
|
||||
|
||||
@@ -407,6 +407,18 @@ ErrorCode ServerController::installDockerWorker(const ServerCredentials &credent
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
|
||||
qDebug().noquote() << "ServerController::installDockerWorker" << stdOut;
|
||||
if (container == DockerContainer::Awg) {
|
||||
QRegularExpression regex(R"(Linux\s+(\d+)\.(\d+)[^\d]*)");
|
||||
QRegularExpressionMatch match = regex.match(stdOut);
|
||||
if (match.hasMatch()) {
|
||||
int majorVersion = match.captured(1).toInt();
|
||||
int minorVersion = match.captured(2).toInt();
|
||||
|
||||
if (majorVersion < 4 || (majorVersion == 4 && minorVersion < 14)) {
|
||||
return ErrorCode::ServerLinuxKernelTooOld;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stdOut.contains("lock"))
|
||||
return ErrorCode::ServerPacketManagerError;
|
||||
if (stdOut.contains("command not found"))
|
||||
@@ -843,3 +855,24 @@ ErrorCode ServerController::getDecryptedPrivateKey(const ServerCredentials &cred
|
||||
auto error = m_sshClient.getDecryptedPrivateKey(credentials, decryptedPrivateKey, callback);
|
||||
return error;
|
||||
}
|
||||
|
||||
bool ServerController::isNewAwgContainer(const ServerCredentials &credentials)
|
||||
{
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
auto cbReadStdErr = [&](const QString &data, libssh::Client &) {
|
||||
stdOut += data + "\n";
|
||||
return ErrorCode::NoError;
|
||||
};
|
||||
|
||||
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'type awg'");
|
||||
|
||||
runScript(credentials, replaceVars(script, genVarsForScript(credentials, DockerContainer::Awg)), cbReadStdOut, cbReadStdErr);
|
||||
|
||||
return stdOut.contains("/usr/bin/awg");
|
||||
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
ErrorCode getDecryptedPrivateKey(const ServerCredentials &credentials, QString &decryptedPrivateKey,
|
||||
const std::function<QString()> &callback);
|
||||
|
||||
bool isNewAwgContainer(const ServerCredentials &credentials);
|
||||
|
||||
private:
|
||||
ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
|
||||
ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace amnezia
|
||||
ServerUserDirectoryNotAccessible = 208,
|
||||
ServerUserNotAllowedInSudoers = 209,
|
||||
ServerUserPasswordRequired = 210,
|
||||
ServerLinuxKernelTooOld = 211,
|
||||
|
||||
// Ssh connection errors
|
||||
SshRequestDeniedError = 300,
|
||||
|
||||
@@ -26,6 +26,7 @@ QString errorString(ErrorCode code) {
|
||||
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;
|
||||
case(ErrorCode::ServerLinuxKernelTooOld): errorMessage = QObject::tr("Server error: Linux kernel is too old"); break;
|
||||
|
||||
// Libssh errors
|
||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||
|
||||
@@ -371,9 +371,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||
if (!parseStringList(obj, "vpnDisabledApps", config.m_vpnDisabledApps)) {
|
||||
return false;
|
||||
}
|
||||
if (!parseStringList(obj, "allowedDnsServers", config.m_allowedDnsServers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.m_killSwitchEnabled = QVariant(obj.value("killSwitchOption").toString()).toBool();
|
||||
|
||||
|
||||
@@ -48,13 +48,6 @@ QJsonObject InterfaceConfig::toJson() const {
|
||||
}
|
||||
json.insert("excludedAddresses", jsExcludedAddresses);
|
||||
|
||||
|
||||
QJsonArray jsAllowedDnsServers;
|
||||
for (const QString& i : m_allowedDnsServers) {
|
||||
jsAllowedDnsServers.append(QJsonValue(i));
|
||||
}
|
||||
json.insert("allowedDnsServers", jsAllowedDnsServers);
|
||||
|
||||
QJsonArray disabledApps;
|
||||
for (const QString& i : m_vpnDisabledApps) {
|
||||
disabledApps.append(QJsonValue(i));
|
||||
|
||||
@@ -37,7 +37,6 @@ class InterfaceConfig {
|
||||
QList<IPAddress> m_allowedIPAddressRanges;
|
||||
QStringList m_excludedAddresses;
|
||||
QStringList m_vpnDisabledApps;
|
||||
QStringList m_allowedDnsServers;
|
||||
bool m_killSwitchEnabled;
|
||||
#if defined(MZ_ANDROID) || defined(MZ_IOS)
|
||||
QString m_installationId;
|
||||
|
||||
@@ -123,7 +123,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
|
||||
int appSplitTunnelType = rawConfig.value(amnezia::config_key::appSplitTunnelType).toInt();
|
||||
QJsonArray splitTunnelApps = rawConfig.value(amnezia::config_key::splitTunnelApps).toArray();
|
||||
QJsonArray allowedDns = rawConfig.value(amnezia::config_key::allowedDnsServers).toArray();
|
||||
|
||||
QJsonObject wgConfig = rawConfig.value(protocolName + "_config_data").toObject();
|
||||
|
||||
@@ -227,8 +226,6 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
|
||||
json.insert("vpnDisabledApps", splitTunnelApps);
|
||||
|
||||
json.insert("allowedDnsServers", allowedDns);
|
||||
|
||||
json.insert(amnezia::config_key::killSwitchOption, rawConfig.value(amnezia::config_key::killSwitchOption));
|
||||
|
||||
if (protocolName == amnezia::config_key::awg) {
|
||||
|
||||
@@ -455,6 +455,9 @@ void LinuxFirewall::updateDNSServers(const QStringList& servers)
|
||||
|
||||
void LinuxFirewall::updateAllowNets(const QStringList& servers)
|
||||
{
|
||||
static QStringList existingServers {};
|
||||
|
||||
existingServers = servers;
|
||||
execute(QStringLiteral("iptables -F %1.110.allowNets").arg(kAnchorName));
|
||||
for (const QString& rule : getAllowRule(servers))
|
||||
execute(QStringLiteral("iptables -A %1.110.allowNets %2").arg(kAnchorName, rule));
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include "leakdetector.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include "killswitch.h"
|
||||
|
||||
constexpr const int WG_TUN_PROC_TIMEOUT = 5000;
|
||||
constexpr const char* WG_RUNTIME_DIR = "/var/run/amneziawg";
|
||||
|
||||
@@ -184,7 +182,7 @@ bool WireguardUtilsLinux::deleteInterface() {
|
||||
QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name"));
|
||||
|
||||
// double-check + ensure our firewall is installed and enabled
|
||||
KillSwitch::instance()->disableKillSwitch();
|
||||
LinuxFirewall::uninstall();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "leakdetector.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include "killswitch.h"
|
||||
|
||||
constexpr const int WG_TUN_PROC_TIMEOUT = 5000;
|
||||
constexpr const char* WG_RUNTIME_DIR = "/var/run/amneziawg";
|
||||
|
||||
@@ -182,7 +180,7 @@ bool WireguardUtilsMacos::deleteInterface() {
|
||||
QFile::remove(wgRuntimeDir.filePath(QString(WG_INTERFACE) + ".name"));
|
||||
|
||||
// double-check + ensure our firewall is installed and enabled
|
||||
KillSwitch::instance()->disableKillSwitch();
|
||||
MacOSFirewall::uninstall();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include "logger.h"
|
||||
#include "platforms/windows/windowsutils.h"
|
||||
|
||||
#include "killswitch.h"
|
||||
|
||||
#define IPV6_ADDRESS_SIZE 16
|
||||
|
||||
// ID for the Firewall Sublayer
|
||||
@@ -182,29 +180,16 @@ bool WindowsFirewall::enableInterface(int vpnAdapterIndex) {
|
||||
} \
|
||||
}
|
||||
|
||||
logger.info() << "Enabling Killswitch Using Adapter:" << vpnAdapterIndex;
|
||||
if (vpnAdapterIndex < 0)
|
||||
{
|
||||
IPAddress allv4("0.0.0.0/0");
|
||||
if (!blockTrafficTo(allv4, MED_WEIGHT,
|
||||
"Block Internet", "killswitch")) {
|
||||
return false;
|
||||
}
|
||||
IPAddress allv6("::/0");
|
||||
if (!blockTrafficTo(allv6, MED_WEIGHT,
|
||||
"Block Internet", "killswitch")) {
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
logger.info() << "Enabling firewall Using Adapter:" << vpnAdapterIndex;
|
||||
FW_OK(allowTrafficOfAdapter(vpnAdapterIndex, MED_WEIGHT,
|
||||
"Allow usage of VPN Adapter"));
|
||||
"Allow usage of VPN Adapter"));
|
||||
FW_OK(allowDHCPTraffic(MED_WEIGHT, "Allow DHCP Traffic"));
|
||||
FW_OK(allowHyperVTraffic(MAX_WEIGHT, "Allow Hyper-V Traffic"));
|
||||
FW_OK(allowHyperVTraffic(MED_WEIGHT, "Allow Hyper-V Traffic"));
|
||||
FW_OK(allowTrafficForAppOnAll(getCurrentPath(), MAX_WEIGHT,
|
||||
"Allow all for AmneziaVPN.exe"));
|
||||
FW_OK(blockTrafficOnPort(53, MED_WEIGHT, "Block all DNS"));
|
||||
FW_OK(allowLoopbackTraffic(MED_WEIGHT,
|
||||
"Allow Loopback traffic on device %1"));
|
||||
FW_OK(
|
||||
allowLoopbackTraffic(MED_WEIGHT, "Allow Loopback traffic on device %1"));
|
||||
|
||||
logger.debug() << "Killswitch on! Rules:" << m_activeRules.length();
|
||||
return true;
|
||||
@@ -241,37 +226,6 @@ bool WindowsFirewall::enableLanBypass(const QList<IPAddress>& ranges) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow unprotected traffic sent to the following address ranges.
|
||||
bool WindowsFirewall::allowTrafficRange(const QStringList& ranges) {
|
||||
// Start the firewall transaction
|
||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
disableKillSwitch();
|
||||
return false;
|
||||
}
|
||||
auto cleanup = qScopeGuard([&] {
|
||||
FwpmTransactionAbort0(m_sessionHandle);
|
||||
disableKillSwitch();
|
||||
});
|
||||
|
||||
for (const QString& addr : ranges) {
|
||||
logger.debug() << "Allow killswitch exclude: " << addr;
|
||||
if (!allowTrafficTo(QHostAddress(addr), LOW_WEIGHT + 1, "Allow killswitch bypass traffic")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = FwpmTransactionCommit0(m_sessionHandle);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
logger.error() << "FwpmTransactionCommit0 failed with error:" << result;
|
||||
return false;
|
||||
}
|
||||
|
||||
cleanup.dismiss();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
||||
// Start the firewall transaction
|
||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||
@@ -308,20 +262,12 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString& dns : config.m_allowedDnsServers) {
|
||||
logger.debug() << "Allow DNS: " << dns;
|
||||
if (!allowTrafficTo(QHostAddress(dns), 53, HIGH_WEIGHT,
|
||||
"Allow DNS-Server", config.m_serverPublicKey)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.m_excludedAddresses.empty()) {
|
||||
for (const QString& i : config.m_excludedAddresses) {
|
||||
logger.debug() << "excludedAddresses range: " << i;
|
||||
|
||||
if (!allowTrafficTo(i, HIGH_WEIGHT,
|
||||
"Allow Ecxlude route", config.m_serverPublicKey)) {
|
||||
"Allow Ecxlude route", config.m_serverPublicKey)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -367,41 +313,37 @@ bool WindowsFirewall::disablePeerTraffic(const QString& pubkey) {
|
||||
}
|
||||
|
||||
bool WindowsFirewall::disableKillSwitch() {
|
||||
return KillSwitch::instance()->disableKillSwitch();
|
||||
}
|
||||
|
||||
bool WindowsFirewall::allowAllTraffic() {
|
||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||
auto cleanup = qScopeGuard([&] {
|
||||
if (result != ERROR_SUCCESS) {
|
||||
FwpmTransactionAbort0(m_sessionHandle);
|
||||
}
|
||||
});
|
||||
auto result = FwpmTransactionBegin(m_sessionHandle, NULL);
|
||||
auto cleanup = qScopeGuard([&] {
|
||||
if (result != ERROR_SUCCESS) {
|
||||
logger.error() << "FwpmTransactionBegin0 failed. Return value:.\n"
|
||||
<< result;
|
||||
return false;
|
||||
FwpmTransactionAbort0(m_sessionHandle);
|
||||
}
|
||||
});
|
||||
if (result != ERROR_SUCCESS) {
|
||||
logger.error() << "FwpmTransactionBegin0 failed. Return value:.\n"
|
||||
<< result;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& filterID : m_peerRules.values()) {
|
||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||
}
|
||||
for (const auto& filterID : m_peerRules.values()) {
|
||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||
}
|
||||
|
||||
for (const auto& filterID : qAsConst(m_activeRules)) {
|
||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||
}
|
||||
for (const auto& filterID : qAsConst(m_activeRules)) {
|
||||
FwpmFilterDeleteById0(m_sessionHandle, filterID);
|
||||
}
|
||||
|
||||
// Commit!
|
||||
result = FwpmTransactionCommit0(m_sessionHandle);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
logger.error() << "FwpmTransactionCommit0 failed. Return value:.\n"
|
||||
<< result;
|
||||
return false;
|
||||
}
|
||||
m_peerRules.clear();
|
||||
m_activeRules.clear();
|
||||
logger.debug() << "Firewall Disabled!";
|
||||
return true;
|
||||
// Commit!
|
||||
result = FwpmTransactionCommit0(m_sessionHandle);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
logger.error() << "FwpmTransactionCommit0 failed. Return value:.\n"
|
||||
<< result;
|
||||
return false;
|
||||
}
|
||||
m_peerRules.clear();
|
||||
m_activeRules.clear();
|
||||
logger.debug() << "Firewall Disabled!";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsFirewall::allowTrafficForAppOnAll(const QString& exePath,
|
||||
|
||||
@@ -43,8 +43,6 @@ class WindowsFirewall final : public QObject {
|
||||
bool enablePeerTraffic(const InterfaceConfig& config);
|
||||
bool disablePeerTraffic(const QString& pubkey);
|
||||
bool disableKillSwitch();
|
||||
bool allowAllTraffic();
|
||||
bool allowTrafficRange(const QStringList& ranges);
|
||||
|
||||
private:
|
||||
static bool initSublayer();
|
||||
|
||||
@@ -171,11 +171,6 @@ ErrorCode OpenVpnProtocol::start()
|
||||
return lastError();
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
|
||||
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList(NetworkUtilities::getIPAddress(
|
||||
m_configData.value(amnezia::config_key::hostName).toString())));
|
||||
#endif
|
||||
|
||||
// Detect default gateway
|
||||
#ifdef Q_OS_MAC
|
||||
QProcess p;
|
||||
|
||||
@@ -95,8 +95,6 @@ namespace amnezia
|
||||
constexpr char splitTunnelApps[] = "splitTunnelApps";
|
||||
constexpr char appSplitTunnelType[] = "appSplitTunnelType";
|
||||
|
||||
constexpr char allowedDnsServers[] = "allowedDnsServers";
|
||||
|
||||
constexpr char killSwitchOption[] = "killSwitchOption";
|
||||
|
||||
constexpr char crc[] = "crc";
|
||||
@@ -188,6 +186,9 @@ namespace amnezia
|
||||
constexpr char serverPublicKeyPath[] = "/opt/amnezia/wireguard/wireguard_server_public_key.key";
|
||||
constexpr char serverPskKeyPath[] = "/opt/amnezia/wireguard/wireguard_psk.key";
|
||||
|
||||
constexpr char interfaceName[] = "wg0";
|
||||
constexpr char wgBinaryName[] = "wg";
|
||||
constexpr char wgQuickBinaryName[] = "wg-quick";
|
||||
}
|
||||
|
||||
namespace sftp
|
||||
@@ -205,7 +206,7 @@ namespace amnezia
|
||||
constexpr char defaultMtu[] = "1376";
|
||||
#endif
|
||||
|
||||
constexpr char serverConfigPath[] = "/opt/amnezia/awg/wg0.conf";
|
||||
constexpr char serverConfigPath[] = "/opt/amnezia/awg/awg0.conf";
|
||||
constexpr char serverPublicKeyPath[] = "/opt/amnezia/awg/wireguard_server_public_key.key";
|
||||
constexpr char serverPskKeyPath[] = "/opt/amnezia/awg/wireguard_psk.key";
|
||||
|
||||
@@ -218,6 +219,10 @@ namespace amnezia
|
||||
constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
|
||||
constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
|
||||
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
|
||||
|
||||
constexpr char interfaceName[] = "awg0";
|
||||
constexpr char wgBinaryName[] = "awg";
|
||||
constexpr char wgQuickBinaryName[] = "awg-quick";
|
||||
}
|
||||
|
||||
namespace socks5Proxy
|
||||
|
||||
@@ -129,7 +129,6 @@
|
||||
<file>ui/qml/Components/SettingsContainersListView.qml</file>
|
||||
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
|
||||
<file>ui/qml/Components/TransportProtoSelector.qml</file>
|
||||
<file>ui/qml/Components/AddSitePanel.qml</file>
|
||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||
<file>ui/qml/Config/qmldir</file>
|
||||
<file>ui/qml/Controls2/BackButtonType.qml</file>
|
||||
@@ -144,9 +143,7 @@
|
||||
<file>ui/qml/Controls2/DropDownType.qml</file>
|
||||
<file>ui/qml/Controls2/FlickableType.qml</file>
|
||||
<file>ui/qml/Controls2/Header2Type.qml</file>
|
||||
<file>ui/qml/Controls2/BaseHeaderType.qml</file>
|
||||
<file>ui/qml/Controls2/HeaderTypeWithButton.qml</file>
|
||||
<file>ui/qml/Controls2/HeaderTypeWithSwitcher.qml</file>
|
||||
<file>ui/qml/Controls2/HeaderType.qml</file>
|
||||
<file>ui/qml/Controls2/HorizontalRadioButton.qml</file>
|
||||
<file>ui/qml/Controls2/ImageButtonType.qml</file>
|
||||
<file>ui/qml/Controls2/LabelWithButtonType.qml</file>
|
||||
@@ -202,8 +199,6 @@
|
||||
<file>ui/qml/Pages2/PageSettingsBackup.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsConnection.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsDns.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsKillSwitch.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsKillSwitchExceptions.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsLogging.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerData.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsServerInfo.qml</file>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "secure_qsettings.h"
|
||||
|
||||
#include "../client/3rd/QSimpleCrypto/src/include/QAead.h"
|
||||
#include "../client/3rd/QSimpleCrypto/src/include/QBlockCipher.h"
|
||||
#include "QAead.h"
|
||||
#include "QBlockCipher.h"
|
||||
#include "utilities.h"
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
|
||||
#include "../client/3rd/qtkeychain/qtkeychain/keychain.h"
|
||||
#include "keychain.h"
|
||||
|
||||
class SecureQSettings : public QObject
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM amneziavpn/amnezia-wg:latest
|
||||
FROM amneziavpn/amneziawg-go:latest
|
||||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
mkdir -p /opt/amnezia/awg
|
||||
cd /opt/amnezia/awg
|
||||
WIREGUARD_SERVER_PRIVATE_KEY=$(wg genkey)
|
||||
WIREGUARD_SERVER_PRIVATE_KEY=$(awg genkey)
|
||||
echo $WIREGUARD_SERVER_PRIVATE_KEY > /opt/amnezia/awg/wireguard_server_private_key.key
|
||||
|
||||
WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | wg pubkey)
|
||||
WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | awg pubkey)
|
||||
echo $WIREGUARD_SERVER_PUBLIC_KEY > /opt/amnezia/awg/wireguard_server_public_key.key
|
||||
|
||||
WIREGUARD_PSK=$(wg genpsk)
|
||||
WIREGUARD_PSK=$(awg genpsk)
|
||||
echo $WIREGUARD_PSK > /opt/amnezia/awg/wireguard_psk.key
|
||||
|
||||
cat > /opt/amnezia/awg/wg0.conf <<EOF
|
||||
cat > /opt/amnezia/awg/awg0.conf <<EOF
|
||||
[Interface]
|
||||
PrivateKey = $WIREGUARD_SERVER_PRIVATE_KEY
|
||||
Address = $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR
|
||||
|
||||
@@ -6,19 +6,19 @@ echo "Container startup"
|
||||
#ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up
|
||||
|
||||
# kill daemons in case of restart
|
||||
wg-quick down /opt/amnezia/awg/wg0.conf
|
||||
awg-quick down /opt/amnezia/awg/awg0.conf
|
||||
|
||||
# start daemons if configured
|
||||
if [ -f /opt/amnezia/awg/wg0.conf ]; then (wg-quick up /opt/amnezia/awg/wg0.conf); fi
|
||||
if [ -f /opt/amnezia/awg/awg0.conf ]; then (awg-quick up /opt/amnezia/awg/awg0.conf); fi
|
||||
|
||||
# Allow traffic on the TUN interface.
|
||||
iptables -A INPUT -i wg0 -j ACCEPT
|
||||
iptables -A FORWARD -i wg0 -j ACCEPT
|
||||
iptables -A OUTPUT -o wg0 -j ACCEPT
|
||||
iptables -A INPUT -i awg0 -j ACCEPT
|
||||
iptables -A FORWARD -i awg0 -j ACCEPT
|
||||
iptables -A OUTPUT -o awg0 -j ACCEPT
|
||||
|
||||
# Allow forwarding traffic only from the VPN.
|
||||
iptables -A FORWARD -i wg0 -o eth0 -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i wg0 -o eth1 -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i awg0 -o eth0 -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
|
||||
iptables -A FORWARD -i awg0 -o eth1 -s $AWG_SUBNET_IP/$WIREGUARD_SUBNET_CIDR -j ACCEPT
|
||||
|
||||
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||
|
||||
|
||||
@@ -20,4 +20,5 @@ if [ "$(systemctl is-active docker)" != "active" ]; then \
|
||||
sleep 5; sudo systemctl start docker; sleep 5;\
|
||||
fi;\
|
||||
if ! command -v sudo > /dev/null 2>&1; then echo "Failed to install sudo, command not found"; exit 1; fi;\
|
||||
docker --version
|
||||
docker --version;\
|
||||
uname -sr
|
||||
|
||||
@@ -443,16 +443,6 @@ void Settings::setKillSwitchEnabled(bool enabled)
|
||||
setValue("Conf/killSwitchEnabled", enabled);
|
||||
}
|
||||
|
||||
bool Settings::isStrictKillSwitchEnabled() const
|
||||
{
|
||||
return value("Conf/strictKillSwitchEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setStrictKillSwitchEnabled(bool enabled)
|
||||
{
|
||||
setValue("Conf/strictKillSwitchEnabled", enabled);
|
||||
}
|
||||
|
||||
QString Settings::getInstallationUuid(const bool needCreate)
|
||||
{
|
||||
auto uuid = value("Conf/installationUuid", "").toString();
|
||||
@@ -558,13 +548,3 @@ void Settings::disableHomeAdLabel()
|
||||
{
|
||||
setValue("Conf/homeAdLabelVisible", false);
|
||||
}
|
||||
|
||||
QStringList Settings::allowedDnsServers() const
|
||||
{
|
||||
return value("Conf/allowedDnsServers").toStringList();
|
||||
}
|
||||
|
||||
void Settings::setAllowedDnsServers(const QStringList &servers)
|
||||
{
|
||||
setValue("Conf/allowedDnsServers", servers);
|
||||
}
|
||||
|
||||
@@ -213,10 +213,6 @@ public:
|
||||
|
||||
bool isKillSwitchEnabled() const;
|
||||
void setKillSwitchEnabled(bool enabled);
|
||||
|
||||
bool isStrictKillSwitchEnabled() const;
|
||||
void setStrictKillSwitchEnabled(bool enabled);
|
||||
|
||||
QString getInstallationUuid(const bool needCreate);
|
||||
|
||||
void resetGatewayEndpoint();
|
||||
@@ -229,9 +225,6 @@ public:
|
||||
bool isHomeAdLabelVisible();
|
||||
void disableHomeAdLabel();
|
||||
|
||||
QStringList allowedDnsServers() const;
|
||||
void setAllowedDnsServers(const QStringList &servers);
|
||||
|
||||
signals:
|
||||
void saveLogsChanged(bool enabled);
|
||||
void screenshotsEnabledChanged(bool enabled);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,10 @@
|
||||
<TS version="2.1" language="ru_RU">
|
||||
<context>
|
||||
<name>AdLabel</name>
|
||||
<message>
|
||||
<source>Amnezia Premium - for access to any website</source>
|
||||
<translation type="vanished">Amnezia Premium - для доступа к любым сайтам</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Components/AdLabel.qml" line="57"/>
|
||||
<source>Amnezia Premium - for access to all websites and online resources</source>
|
||||
<translation>Amnezia Premium - доступ ко всем сайтам и онлайн ресурсам</translation>
|
||||
<source>Amnezia Premium - for access to any website</source>
|
||||
<translation>Amnezia Premium - для доступа к любым сайтам</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -60,12 +56,12 @@
|
||||
<translation>%1 успешно установлен.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="257"/>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="258"/>
|
||||
<source>API config reloaded</source>
|
||||
<translation>Конфигурация API перезагружена</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="261"/>
|
||||
<location filename="../ui/controllers/api/apiConfigsController.cpp" line="262"/>
|
||||
<source>Successfully changed the country of connection to %1</source>
|
||||
<translation>Страна подключения изменена на %1</translation>
|
||||
</message>
|
||||
@@ -94,8 +90,9 @@
|
||||
<translation type="vanished">Amnezia Free - это бесплатный VPN для обхода блокировок в странах с высоким уровнем интернет-цензуры</translation>
|
||||
</message>
|
||||
<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="vanished">Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Скорость до %1 Мбит/с. Безлимитный трафик.</translation>
|
||||
<translation>Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Скорость до %1 Мбит/с. Безлимитный трафик.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="72"/>
|
||||
@@ -103,19 +100,10 @@
|
||||
<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>AmneziaFree предоставляет бесплатный неограниченный доступ к базовому набору сайтов и приложений, таким как Facebook, Instagram, Twitter (X), Discord, Telegram и другим. YouTube не включен в бесплатный тариф.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<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="vanished">Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Работает для любых сайтов без ограничений.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="68"/>
|
||||
<source>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.</source>
|
||||
<translation>Amnezia Premium - это классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Доступ ко всем сайтам и онлайн ресурсам. Скорость - до %1 Мбит/с.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="82"/>
|
||||
<source>Amnezia Premium is classic VPN for for seamless work, downloading large files, and watching videos. Access all websites and online resources.</source>
|
||||
<translation>Amnezia Premium - это классический VPN для комфортной работы, загрузки больших файлов и просмотра видео. Доступ ко всем сайтам и онлайн ресурсам.</translation>
|
||||
<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>Amnezia Premium — VPN для комфортной работы, скачивания больших файлов и просмотра видео в высоком разрешении. Работает для любых сайтов без ограничений.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/models/api/apiServicesModel.cpp" line="97"/>
|
||||
@@ -352,23 +340,14 @@ Can't be disabled for current server</source>
|
||||
<translation type="vanished">Неверный файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/importController.cpp" line="650"/>
|
||||
<location filename="../ui/controllers/importController.cpp" line="651"/>
|
||||
<source>Scanned %1 of %2.</source>
|
||||
<translation>Отсканировано %1 из %2.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/importController.cpp" line="685"/>
|
||||
<source>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. </source>
|
||||
<translation>Эта конфигурация содержит настройки OpenVPN. Конфигурации OpenVPN могут содержать вредоносные скрипты, поэтому добавляйте их только в том случае, если полностью доверяете источнику этого файла. </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/importController.cpp" line="689"/>
|
||||
<source><br>In the imported configuration, potentially dangerous lines were found:</source>
|
||||
<translation><br>В импортированной конфигурации обнаружены потенциально опасные строки:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/importController.cpp" line="686"/>
|
||||
<source>In the imported configuration, potentially dangerous lines were found:</source>
|
||||
<translation type="vanished">В импортированной конфигурации были обнаружены потенциально опасные строки:</translation>
|
||||
<translation>В импортированной конфигурации были обнаружены потенциально опасные строки:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -538,12 +517,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="68"/>
|
||||
<source>Gateway endpoint</source>
|
||||
<translation>Gateway endpoint</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageDevMenu.qml" line="97"/>
|
||||
<source>Dev gateway environment</source>
|
||||
<translation>Dev gateway environment</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -673,47 +652,47 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="146"/>
|
||||
<source>Jc - Junk packet count</source>
|
||||
<translation>Jc - Junk packet count</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="168"/>
|
||||
<source>Jmin - Junk packet minimum size</source>
|
||||
<translation>Jmin - Junk packet minimum size</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="186"/>
|
||||
<source>Jmax - Junk packet maximum size</source>
|
||||
<translation>Jmax - Junk packet maximum size</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="204"/>
|
||||
<source>S1 - Init packet junk size</source>
|
||||
<translation>S1 - Init packet junk size</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="228"/>
|
||||
<source>S2 - Response packet junk size</source>
|
||||
<translation>S2 - Response packet junk size</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="252"/>
|
||||
<source>H1 - Init packet magic header</source>
|
||||
<translation>H1 - Init packet magic header</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="270"/>
|
||||
<source>H2 - Response packet magic header</source>
|
||||
<translation>H2 - Response packet magic header</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="288"/>
|
||||
<source>H4 - Transport packet magic header</source>
|
||||
<translation>H4 - Transport packet magic header</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="306"/>
|
||||
<source>H3 - Underload packet magic header</source>
|
||||
<translation>H3 - Underload packet magic header</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageProtocolAwgSettings.qml" line="354"/>
|
||||
@@ -1482,7 +1461,7 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettings.qml" line="123"/>
|
||||
<source>Dev console</source>
|
||||
<translation>Dev console</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettings.qml" line="142"/>
|
||||
@@ -1609,13 +1588,9 @@ Already installed containers were found on the server. All installed containers
|
||||
</context>
|
||||
<context>
|
||||
<name>PageSettingsApiDevices</name>
|
||||
<message>
|
||||
<source>Active devices</source>
|
||||
<translation type="vanished">Активные устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiDevices.qml" line="45"/>
|
||||
<source>Active Devices</source>
|
||||
<source>Active devices</source>
|
||||
<translation>Активные устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -1766,14 +1741,10 @@ Already installed containers were found on the server. All installed containers
|
||||
<source>Save AmneziaVPN config</source>
|
||||
<translation>Сохранить конфигурацию AmneziaVPN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Configuration files</source>
|
||||
<translation type="vanished">Файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="48"/>
|
||||
<source>Configuration Files</source>
|
||||
<translation>Файлы конфигурации</translation>
|
||||
<source>Configuration files</source>
|
||||
<translation>Файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiNativeConfigs.qml" line="49"/>
|
||||
@@ -1861,8 +1832,9 @@ Already installed containers were found on the server. All installed containers
|
||||
<translation type="vanished">Период работы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="37"/>
|
||||
<source>Valid until</source>
|
||||
<translation type="vanished">Действует до</translation>
|
||||
<translation>Действует до</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Speed</source>
|
||||
@@ -1873,12 +1845,14 @@ Already installed containers were found on the server. All installed containers
|
||||
<translation type="vanished">Скопировано</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="29"/>
|
||||
<source>Subscription status</source>
|
||||
<translation type="vanished">Статус подписки</translation>
|
||||
<translation>Статус подписки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="45"/>
|
||||
<source>Active connections</source>
|
||||
<translation type="vanished">Активные соединения</translation>
|
||||
<translation>Активные соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="171"/>
|
||||
@@ -1886,8 +1860,9 @@ Already installed containers were found on the server. All installed containers
|
||||
<translation>Сетевые адреса одного или нескольких серверов были обновлены. Пожалуйста, удалите старые конфигурацию и загрузите новые файлы</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="186"/>
|
||||
<source>Subscription key</source>
|
||||
<translation type="vanished">Ключ для подключения</translation>
|
||||
<translation>Ключ для подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="190"/>
|
||||
@@ -1895,8 +1870,9 @@ Already installed containers were found on the server. All installed containers
|
||||
<translation>Ключ подписки Amnezia Premium</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="194"/>
|
||||
<source>Save VPN key to file</source>
|
||||
<translation type="vanished">Сохранить VPN-ключ в файле</translation>
|
||||
<translation>Сохранить VPN-ключ в файле</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="195"/>
|
||||
@@ -1904,51 +1880,18 @@ Already installed containers were found on the server. All installed containers
|
||||
<translation>Скопировать VPN ключ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="216"/>
|
||||
<source>Configuration files</source>
|
||||
<translation type="vanished">Файл конфигурации</translation>
|
||||
<translation>Файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="218"/>
|
||||
<source>Manage configuration files</source>
|
||||
<translation>Управление файлами конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Active devices</source>
|
||||
<translation type="vanished">Активные устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="29"/>
|
||||
<source>Subscription Status</source>
|
||||
<translation>Статус подписки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="37"/>
|
||||
<source>Valid Until</source>
|
||||
<translation>Действительна до</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="45"/>
|
||||
<source>Active Connections</source>
|
||||
<translation>Активные соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="186"/>
|
||||
<source>Subscription Key</source>
|
||||
<translation>Ключ для подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="194"/>
|
||||
<source>Save VPN key as a file</source>
|
||||
<translation>Сохранить VPN-ключ в файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="216"/>
|
||||
<source>Configuration Files</source>
|
||||
<translation>Файлы конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiServerInfo.qml" line="236"/>
|
||||
<source>Active Devices</source>
|
||||
<source>Active devices</source>
|
||||
<translation>Активные устройства</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -2038,13 +1981,9 @@ Already installed containers were found on the server. All installed containers
|
||||
<source>Telegram</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Email Support</source>
|
||||
<translation type="vanished">Email</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsApiSupport.qml" line="30"/>
|
||||
<source>Email</source>
|
||||
<source>Email Support</source>
|
||||
<translation>Email</translation>
|
||||
</message>
|
||||
<message>
|
||||
@@ -2393,12 +2332,8 @@ Already installed containers were found on the server. All installed containers
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="143"/>
|
||||
<source>Cannot change KillSwitch settings during active connection</source>
|
||||
<translation>Невозможно изменить настройки KillSwitch во время активного подключения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cannot change killSwitch settings during active connection</source>
|
||||
<translation type="vanished">Невозможно изменить настройки аварийного выключателя во время активного соединения</translation>
|
||||
<translation>Невозможно изменить настройки аварийного выключателя во время активного соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsConnection.qml" line="86"/>
|
||||
@@ -2561,12 +2496,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="175"/>
|
||||
<source>Client logs</source>
|
||||
<translation>Логи приложения</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="176"/>
|
||||
<source>AmneziaVPN logs</source>
|
||||
<translation>AmneziaVPN logs</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="142"/>
|
||||
@@ -2581,12 +2516,12 @@ Already installed containers were found on the server. All installed containers
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="204"/>
|
||||
<source>Service logs</source>
|
||||
<translation>Логи службы</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="205"/>
|
||||
<source>AmneziaVPN-service logs</source>
|
||||
<translation>AmneziaVPN-service logs</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSettingsLogging.qml" line="78"/>
|
||||
@@ -3071,7 +3006,7 @@ It's okay as long as it's from someone you trust.</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="109"/>
|
||||
<source>Support tag</source>
|
||||
<translation>Support tag</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageSetupWizardConfigSource.qml" line="120"/>
|
||||
@@ -3659,7 +3594,7 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<message>
|
||||
<location filename="../ui/qml/Pages2/PageShare.qml" line="726"/>
|
||||
<source>Allowed IPs: %1</source>
|
||||
<translation>Разрешенные подсети: %1</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Creation date: </source>
|
||||
@@ -4111,58 +4046,38 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<source>Server error: Package manager error</source>
|
||||
<translation>Ошибка сервера: Ошибка менеджера пакетов</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="25"/>
|
||||
<source>The sudo package is not pre-installed on the server</source>
|
||||
<translation>Пакет sudo не установлен на сервере по умолчанию</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="26"/>
|
||||
<source>The server user's home directory is not accessible</source>
|
||||
<translation>Домашний каталог пользователя сервера недоступен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="27"/>
|
||||
<source>Action not allowed in sudoers</source>
|
||||
<translation>Действие не разрешено в sudoers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="28"/>
|
||||
<source>The user's password is required</source>
|
||||
<translation>Требуется пароль пользователя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="31"/>
|
||||
<source>SSH request was denied</source>
|
||||
<translation>SSH-запрос был отклонён</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="32"/>
|
||||
<location filename="../core/errorstrings.cpp" line="28"/>
|
||||
<source>SSH request was interrupted</source>
|
||||
<translation>SSH-запрос был прерван</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="33"/>
|
||||
<location filename="../core/errorstrings.cpp" line="29"/>
|
||||
<source>SSH internal error</source>
|
||||
<translation>Внутренняя ошибка SSH</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="34"/>
|
||||
<location filename="../core/errorstrings.cpp" line="30"/>
|
||||
<source>Invalid private key or invalid passphrase entered</source>
|
||||
<translation>Введен неверный закрытый ключ или неверная парольная фраза</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="35"/>
|
||||
<location filename="../core/errorstrings.cpp" line="31"/>
|
||||
<source>The selected private key format is not supported, use openssh ED25519 key types or PEM key types</source>
|
||||
<translation>Выбранный формат закрытого ключа не поддерживается, используйте типы ключей openssh ED25519 или PEM</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="36"/>
|
||||
<location filename="../core/errorstrings.cpp" line="32"/>
|
||||
<source>Timeout connecting to server</source>
|
||||
<translation>Тайм-аут подключения к серверу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="39"/>
|
||||
<location filename="../core/errorstrings.cpp" line="35"/>
|
||||
<source>SCP error: Generic failure</source>
|
||||
<translation>Ошибка SCP: общий сбой</translation>
|
||||
</message>
|
||||
@@ -4219,23 +4134,23 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<translation type="vanished">Sftp error: No media was in remote drive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="57"/>
|
||||
<location filename="../core/errorstrings.cpp" line="53"/>
|
||||
<source>The config does not contain any containers and credentials for connecting to the server</source>
|
||||
<translation>Конфигурация не содержит каких-либо контейнеров и учетных данных для подключения к серверу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="65"/>
|
||||
<location filename="../core/errorstrings.cpp" line="74"/>
|
||||
<location filename="../core/errorstrings.cpp" line="61"/>
|
||||
<location filename="../core/errorstrings.cpp" line="70"/>
|
||||
<source>Error when retrieving configuration from API</source>
|
||||
<translation>Ошибка при получении конфигурации из API</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="66"/>
|
||||
<location filename="../core/errorstrings.cpp" line="62"/>
|
||||
<source>This config has already been added to the application</source>
|
||||
<translation>Данная конфигурация уже была добавлена в приложение</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="89"/>
|
||||
<location filename="../core/errorstrings.cpp" line="85"/>
|
||||
<source>ErrorCode: %1. </source>
|
||||
<translation>Код ошибки: %1. </translation>
|
||||
</message>
|
||||
@@ -4244,139 +4159,139 @@ and will not be shared or disclosed to the Amnezia or any third parties</source>
|
||||
<translation type="vanished">Failed to save config to disk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="42"/>
|
||||
<location filename="../core/errorstrings.cpp" line="38"/>
|
||||
<source>OpenVPN config missing</source>
|
||||
<translation>Отсутствует конфигурация OpenVPN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="43"/>
|
||||
<location filename="../core/errorstrings.cpp" line="39"/>
|
||||
<source>OpenVPN management server error</source>
|
||||
<translation>Серверная ошибка управлением OpenVPN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="46"/>
|
||||
<location filename="../core/errorstrings.cpp" line="42"/>
|
||||
<source>OpenVPN executable missing</source>
|
||||
<translation>Отсутствует исполняемый файл OpenVPN</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="47"/>
|
||||
<location filename="../core/errorstrings.cpp" line="43"/>
|
||||
<source>Shadowsocks (ss-local) executable missing</source>
|
||||
<translation>Отсутствует исполняемый файл Shadowsocks (ss-local)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="48"/>
|
||||
<location filename="../core/errorstrings.cpp" line="44"/>
|
||||
<source>Cloak (ck-client) executable missing</source>
|
||||
<translation>Отсутствует исполняемый файл Cloak (ck-client)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="49"/>
|
||||
<location filename="../core/errorstrings.cpp" line="45"/>
|
||||
<source>Amnezia helper service error</source>
|
||||
<translation>Ошибка вспомогательной службы Amnezia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="50"/>
|
||||
<location filename="../core/errorstrings.cpp" line="46"/>
|
||||
<source>OpenSSL failed</source>
|
||||
<translation>Ошибка OpenSSL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="53"/>
|
||||
<location filename="../core/errorstrings.cpp" line="49"/>
|
||||
<source>Can't connect: another VPN connection is active</source>
|
||||
<translation>Невозможно подключиться: активно другое VPN-соединение</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="54"/>
|
||||
<location filename="../core/errorstrings.cpp" line="50"/>
|
||||
<source>Can't setup OpenVPN TAP network adapter</source>
|
||||
<translation>Невозможно настроить сетевой адаптер OpenVPN TAP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="55"/>
|
||||
<location filename="../core/errorstrings.cpp" line="51"/>
|
||||
<source>VPN pool error: no available addresses</source>
|
||||
<translation>Ошибка пула VPN: нет доступных адресов</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="58"/>
|
||||
<location filename="../core/errorstrings.cpp" line="54"/>
|
||||
<source>Unable to open config file</source>
|
||||
<translation>Не удалось открыть файл конфигурации</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="59"/>
|
||||
<location filename="../core/errorstrings.cpp" line="55"/>
|
||||
<source>VPN Protocols is not installed.
|
||||
Please install VPN container at first</source>
|
||||
<translation>VPN-протоколы не установлены.
|
||||
Пожалуйста, установите протокол</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="62"/>
|
||||
<location filename="../core/errorstrings.cpp" line="58"/>
|
||||
<source>VPN connection error</source>
|
||||
<translation>Ошибка VPN-соединения</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="67"/>
|
||||
<location filename="../core/errorstrings.cpp" line="63"/>
|
||||
<source>In the response from the server, an empty config was received</source>
|
||||
<translation>В ответе от сервера была получена пустая конфигурация</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="68"/>
|
||||
<location filename="../core/errorstrings.cpp" line="64"/>
|
||||
<source>SSL error occurred</source>
|
||||
<translation>Произошла ошибка SSL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="69"/>
|
||||
<location filename="../core/errorstrings.cpp" line="65"/>
|
||||
<source>Server response timeout on api request</source>
|
||||
<translation>Тайм-аут ответа сервера на запрос API</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="70"/>
|
||||
<location filename="../core/errorstrings.cpp" line="66"/>
|
||||
<source>Missing AGW public key</source>
|
||||
<translation>Отсутствует публичный ключ AGW</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="71"/>
|
||||
<location filename="../core/errorstrings.cpp" line="67"/>
|
||||
<source>Failed to decrypt response payload</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="72"/>
|
||||
<location filename="../core/errorstrings.cpp" line="68"/>
|
||||
<source>Missing list of available services</source>
|
||||
<translation>Отсутствует список доступных сервисов</translation>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="73"/>
|
||||
<location filename="../core/errorstrings.cpp" line="69"/>
|
||||
<source>The limit of allowed configurations per subscription has been exceeded</source>
|
||||
<translation>Превышен лимит разрешенных конфигураций для одной подписки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="77"/>
|
||||
<location filename="../core/errorstrings.cpp" line="73"/>
|
||||
<source>QFile error: The file could not be opened</source>
|
||||
<translation>Ошибка QFile: не удалось открыть файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="78"/>
|
||||
<location filename="../core/errorstrings.cpp" line="74"/>
|
||||
<source>QFile error: An error occurred when reading from the file</source>
|
||||
<translation>Ошибка QFile: произошла ошибка при чтении из файла</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="79"/>
|
||||
<location filename="../core/errorstrings.cpp" line="75"/>
|
||||
<source>QFile error: The file could not be accessed</source>
|
||||
<translation>Ошибка QFile: не удалось получить доступ к файлу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="80"/>
|
||||
<location filename="../core/errorstrings.cpp" line="76"/>
|
||||
<source>QFile error: An unspecified error occurred</source>
|
||||
<translation>Ошибка QFile: произошла неизвестная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="81"/>
|
||||
<location filename="../core/errorstrings.cpp" line="77"/>
|
||||
<source>QFile error: A fatal error occurred</source>
|
||||
<translation>Ошибка QFile: произошла фатальная ошибка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="82"/>
|
||||
<location filename="../core/errorstrings.cpp" line="78"/>
|
||||
<source>QFile error: The operation was aborted</source>
|
||||
<translation>Ошибка QFile: операция была прервана</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../core/errorstrings.cpp" line="86"/>
|
||||
<location filename="../core/errorstrings.cpp" line="82"/>
|
||||
<source>Internal error</source>
|
||||
<translation>Внутренняя ошибка</translation>
|
||||
</message>
|
||||
@@ -5138,37 +5053,37 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||
<translation>Имя хоста не похоже на IP-адрес или доменное имя</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="66"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="67"/>
|
||||
<source>New site added: %1</source>
|
||||
<translation>Добавлен новый сайт: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="78"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="80"/>
|
||||
<source>Site removed: %1</source>
|
||||
<translation>Сайт удален: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="85"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="87"/>
|
||||
<source>Can't open file: %1</source>
|
||||
<translation>Невозможно открыть файл: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="91"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="93"/>
|
||||
<source>Failed to parse JSON data from file: %1</source>
|
||||
<translation>Не удалось разобрать JSON-данные из файла: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="96"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="98"/>
|
||||
<source>The JSON data is not an array in file: %1</source>
|
||||
<translation>JSON-данные не являются массивом в файле: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="126"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="129"/>
|
||||
<source>Import completed</source>
|
||||
<translation>Импорт завершен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="145"/>
|
||||
<location filename="../ui/controllers/sitesController.cpp" line="148"/>
|
||||
<source>Export completed</source>
|
||||
<translation>Экспорт завершен</translation>
|
||||
</message>
|
||||
@@ -5217,7 +5132,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
|
||||
<context>
|
||||
<name>VpnConnection</name>
|
||||
<message>
|
||||
<location filename="../vpnconnection.cpp" line="421"/>
|
||||
<location filename="../vpnconnection.cpp" line="415"/>
|
||||
<source>Mbps</source>
|
||||
<translation>Мбит/с</translation>
|
||||
</message>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,101 +0,0 @@
|
||||
#include "allowedDnsController.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QStandardPaths>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "systemController.h"
|
||||
#include "core/networkUtilities.h"
|
||||
#include "core/defs.h"
|
||||
|
||||
AllowedDnsController::AllowedDnsController(const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<AllowedDnsModel> &allowedDnsModel,
|
||||
QObject *parent)
|
||||
: QObject(parent), m_settings(settings), m_allowedDnsModel(allowedDnsModel)
|
||||
{
|
||||
}
|
||||
|
||||
void AllowedDnsController::addDns(QString ip)
|
||||
{
|
||||
if (ip.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetworkUtilities::ipAddressRegExp().match(ip).hasMatch()) {
|
||||
emit errorOccurred(tr("The address does not look like a valid IP address"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_allowedDnsModel->addDns(ip)) {
|
||||
emit finished(tr("New DNS server added: %1").arg(ip));
|
||||
} else {
|
||||
emit errorOccurred(tr("DNS server already exists: %1").arg(ip));
|
||||
}
|
||||
}
|
||||
|
||||
void AllowedDnsController::removeDns(int index)
|
||||
{
|
||||
auto modelIndex = m_allowedDnsModel->index(index);
|
||||
auto ip = m_allowedDnsModel->data(modelIndex, AllowedDnsModel::Roles::IpRole).toString();
|
||||
m_allowedDnsModel->removeDns(modelIndex);
|
||||
|
||||
emit finished(tr("DNS server removed: %1").arg(ip));
|
||||
}
|
||||
|
||||
void AllowedDnsController::importDns(const QString &fileName, bool replaceExisting)
|
||||
{
|
||||
QByteArray jsonData;
|
||||
if (!SystemController::readFile(fileName, jsonData)) {
|
||||
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
|
||||
if (jsonDocument.isNull()) {
|
||||
emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!jsonDocument.isArray()) {
|
||||
emit errorOccurred(tr("The JSON data is not an array in file: %1").arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
auto jsonArray = jsonDocument.array();
|
||||
QStringList dnsServers;
|
||||
|
||||
for (auto jsonValue : jsonArray) {
|
||||
auto ip = jsonValue.toString();
|
||||
|
||||
if (!NetworkUtilities::ipAddressRegExp().match(ip).hasMatch()) {
|
||||
qDebug() << ip << " is not a valid IP address";
|
||||
continue;
|
||||
}
|
||||
|
||||
dnsServers.append(ip);
|
||||
}
|
||||
|
||||
m_allowedDnsModel->addDnsList(dnsServers, replaceExisting);
|
||||
|
||||
emit finished(tr("Import completed"));
|
||||
}
|
||||
|
||||
void AllowedDnsController::exportDns(const QString &fileName)
|
||||
{
|
||||
auto dnsServers = m_allowedDnsModel->getCurrentDnsServers();
|
||||
|
||||
QJsonArray jsonArray;
|
||||
|
||||
for (const auto &ip : dnsServers) {
|
||||
jsonArray.append(ip);
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument(jsonArray);
|
||||
QByteArray jsonData = jsonDocument.toJson();
|
||||
|
||||
SystemController::saveFile(fileName, jsonData);
|
||||
|
||||
emit finished(tr("Export completed"));
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef ALLOWEDDNSCONTROLLER_H
|
||||
#define ALLOWEDDNSCONTROLLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "settings.h"
|
||||
#include "ui/models/allowed_dns_model.h"
|
||||
|
||||
class AllowedDnsController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AllowedDnsController(const std::shared_ptr<Settings> &settings,
|
||||
const QSharedPointer<AllowedDnsModel> &allowedDnsModel,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void addDns(QString ip);
|
||||
void removeDns(int index);
|
||||
|
||||
void importDns(const QString &fileName, bool replaceExisting);
|
||||
void exportDns(const QString &fileName);
|
||||
|
||||
signals:
|
||||
void errorOccurred(const QString &errorMessage);
|
||||
void finished(const QString &message);
|
||||
|
||||
void saveFile(const QString &fileName, const QString &data);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
QSharedPointer<AllowedDnsModel> m_allowedDnsModel;
|
||||
};
|
||||
|
||||
#endif // ALLOWEDDNSCONTROLLER_H
|
||||
@@ -310,7 +310,7 @@ bool ApiConfigsController::deactivateDevice()
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
if (!apiUtils::isPremiumServer(serverConfigObject)) {
|
||||
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
if (!apiUtils::isPremiumServer(serverConfigObject)) {
|
||||
if (apiUtils::getConfigType(serverConfigObject) != apiDefs::ConfigType::AmneziaPremiumV2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ bool ApiSettingsController::getAccountInfo(bool reload)
|
||||
|
||||
QByteArray responseBody;
|
||||
|
||||
if (apiUtils::isPremiumServer(serverConfig)) {
|
||||
if (apiUtils::getConfigType(serverConfig) == apiDefs::ConfigType::AmneziaPremiumV2) {
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace
|
||||
} else if ((config.contains(xrayConfigPatternInbound)) && (config.contains(xrayConfigPatternOutbound))) {
|
||||
return ConfigTypes::Xray;
|
||||
} else if (config.contains(openVpnConfigPatternCli)
|
||||
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
||||
&& (config.contains(openVpnConfigPatternDriver1) || config.contains(openVpnConfigPatternDriver2))) {
|
||||
return ConfigTypes::OpenVpn;
|
||||
}
|
||||
return ConfigTypes::Invalid;
|
||||
@@ -94,8 +94,6 @@ bool ImportController::extractConfigFromFile(const QString &fileName)
|
||||
|
||||
bool ImportController::extractConfigFromData(QString data)
|
||||
{
|
||||
m_maliciousWarningText.clear();
|
||||
|
||||
QString config = data;
|
||||
QString prefix;
|
||||
QString errormsg;
|
||||
@@ -660,7 +658,6 @@ 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,11 +679,8 @@ 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.push_back(tr("<br>In the imported configuration, potentially dangerous lines were found:"));
|
||||
m_maliciousWarningText = tr("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));
|
||||
}
|
||||
|
||||
@@ -370,8 +370,17 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
containerConfig.insert(config_key::transport_proto, transportProto);
|
||||
|
||||
if (protocol == Proto::Awg) {
|
||||
QString serverConfigPath;
|
||||
if (container == DockerContainer::Awg) {
|
||||
if (serverController->isNewAwgContainer(credentials)) {
|
||||
serverConfigPath = amnezia::protocols::awg::serverConfigPath;
|
||||
} else {
|
||||
serverConfigPath = "/opt/amnezia/awg/wg0.conf";
|
||||
}
|
||||
}
|
||||
|
||||
QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||
protocols::awg::serverConfigPath, errorCode);
|
||||
serverConfigPath, errorCode);
|
||||
|
||||
QMap<QString, QString> serverConfigMap;
|
||||
auto serverConfigLines = serverConfig.split("\n");
|
||||
|
||||
@@ -31,15 +31,13 @@ namespace PageLoader
|
||||
PageSettingsLogging,
|
||||
PageSettingsSplitTunneling,
|
||||
PageSettingsAppSplitTunneling,
|
||||
PageSettingsKillSwitch,
|
||||
PageSettingsApiServerInfo,
|
||||
PageSettingsApiAvailableCountries,
|
||||
PageSettingsApiSupport,
|
||||
PageSettingsApiInstructions,
|
||||
PageSettingsApiNativeConfigs,
|
||||
PageSettingsApiDevices,
|
||||
PageSettingsKillSwitchExceptions,
|
||||
|
||||
|
||||
PageServiceSftpSettings,
|
||||
PageServiceTorWebsiteSettings,
|
||||
PageServiceDnsSettings,
|
||||
|
||||
@@ -245,23 +245,6 @@ bool SettingsController::isKillSwitchEnabled()
|
||||
void SettingsController::toggleKillSwitch(bool enable)
|
||||
{
|
||||
m_settings->setKillSwitchEnabled(enable);
|
||||
emit killSwitchEnabledChanged();
|
||||
if (enable == false) {
|
||||
emit strictKillSwitchEnabledChanged(false);
|
||||
} else {
|
||||
emit strictKillSwitchEnabledChanged(isStrictKillSwitchEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsController::isStrictKillSwitchEnabled()
|
||||
{
|
||||
return m_settings->isStrictKillSwitchEnabled();
|
||||
}
|
||||
|
||||
void SettingsController::toggleStrictKillSwitch(bool enable)
|
||||
{
|
||||
m_settings->setStrictKillSwitchEnabled(enable);
|
||||
emit strictKillSwitchEnabledChanged(enable);
|
||||
}
|
||||
|
||||
bool SettingsController::isNotificationPermissionGranted()
|
||||
|
||||
@@ -24,8 +24,6 @@ public:
|
||||
Q_PROPERTY(QString secondaryDns READ getSecondaryDns WRITE setSecondaryDns NOTIFY secondaryDnsChanged)
|
||||
Q_PROPERTY(bool isLoggingEnabled READ isLoggingEnabled WRITE toggleLogging NOTIFY loggingStateChanged)
|
||||
Q_PROPERTY(bool isNotificationPermissionGranted READ isNotificationPermissionGranted NOTIFY onNotificationStateChanged)
|
||||
Q_PROPERTY(bool isKillSwitchEnabled READ isKillSwitchEnabled WRITE toggleKillSwitch NOTIFY killSwitchEnabledChanged)
|
||||
Q_PROPERTY(bool strictKillSwitchEnabled READ isStrictKillSwitchEnabled WRITE toggleStrictKillSwitch NOTIFY strictKillSwitchEnabledChanged)
|
||||
|
||||
Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled)
|
||||
Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged)
|
||||
@@ -77,9 +75,6 @@ public slots:
|
||||
bool isKillSwitchEnabled();
|
||||
void toggleKillSwitch(bool enable);
|
||||
|
||||
bool isStrictKillSwitchEnabled();
|
||||
void toggleStrictKillSwitch(bool enable);
|
||||
|
||||
bool isNotificationPermissionGranted();
|
||||
void requestNotificationPermission();
|
||||
|
||||
@@ -103,8 +98,6 @@ signals:
|
||||
void primaryDnsChanged();
|
||||
void secondaryDnsChanged();
|
||||
void loggingStateChanged();
|
||||
void killSwitchEnabledChanged();
|
||||
void strictKillSwitchEnabledChanged(bool enabled);
|
||||
|
||||
void restoreBackupFinished();
|
||||
void changeSettingsFinished(const QString &finishedMessage);
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#include "allowed_dns_model.h"
|
||||
|
||||
AllowedDnsModel::AllowedDnsModel(std::shared_ptr<Settings> settings, QObject *parent)
|
||||
: QAbstractListModel(parent), m_settings(settings)
|
||||
{
|
||||
fillDnsServers();
|
||||
}
|
||||
|
||||
int AllowedDnsModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_dnsServers.size();
|
||||
}
|
||||
|
||||
QVariant AllowedDnsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= static_cast<int>(rowCount()))
|
||||
return QVariant();
|
||||
|
||||
switch (role) {
|
||||
case IpRole:
|
||||
return m_dnsServers.at(index.row());
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool AllowedDnsModel::addDns(const QString &ip)
|
||||
{
|
||||
if (m_dnsServers.contains(ip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), rowCount(), rowCount());
|
||||
m_dnsServers.append(ip);
|
||||
m_settings->setAllowedDnsServers(m_dnsServers);
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AllowedDnsModel::addDnsList(const QStringList &dnsServers, bool replaceExisting)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
if (replaceExisting) {
|
||||
m_dnsServers.clear();
|
||||
}
|
||||
|
||||
for (const QString &ip : dnsServers) {
|
||||
if (!m_dnsServers.contains(ip)) {
|
||||
m_dnsServers.append(ip);
|
||||
}
|
||||
}
|
||||
|
||||
m_settings->setAllowedDnsServers(m_dnsServers);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void AllowedDnsModel::removeDns(QModelIndex index)
|
||||
{
|
||||
if (!index.isValid() || index.row() >= m_dnsServers.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
beginRemoveRows(QModelIndex(), index.row(), index.row());
|
||||
m_dnsServers.removeAt(index.row());
|
||||
m_settings->setAllowedDnsServers(m_dnsServers);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
QStringList AllowedDnsModel::getCurrentDnsServers()
|
||||
{
|
||||
return m_dnsServers;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> AllowedDnsModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[IpRole] = "ip";
|
||||
return roles;
|
||||
}
|
||||
|
||||
void AllowedDnsModel::fillDnsServers()
|
||||
{
|
||||
m_dnsServers = m_settings->allowedDnsServers();
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef ALLOWEDDNSMODEL_H
|
||||
#define ALLOWEDDNSMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include "settings.h"
|
||||
|
||||
class AllowedDnsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Roles {
|
||||
IpRole = Qt::UserRole + 1
|
||||
};
|
||||
|
||||
explicit AllowedDnsModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
public slots:
|
||||
bool addDns(const QString &ip);
|
||||
void addDnsList(const QStringList &dnsServers, bool replaceExisting);
|
||||
void removeDns(QModelIndex index);
|
||||
QStringList getCurrentDnsServers();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
private:
|
||||
void fillDnsServers();
|
||||
|
||||
std::shared_ptr<Settings> m_settings;
|
||||
QStringList m_dnsServers;
|
||||
};
|
||||
|
||||
#endif // ALLOWEDDNSMODEL_H
|
||||
@@ -48,19 +48,15 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
case ServiceDescriptionRole: {
|
||||
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) {
|
||||
return tr("Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online "
|
||||
"resources. "
|
||||
return tr("Classic VPN for seamless work, downloading large files, and watching videos. Access all websites and online resources. "
|
||||
"Speeds up to 200 Mbps");
|
||||
} else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
|
||||
return tr("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.");
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
case IsComponentVisibleRole: {
|
||||
return m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2
|
||||
|| m_accountInfoData.configType == apiDefs::ConfigType::ExternalPremium;
|
||||
return m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2;
|
||||
}
|
||||
case HasExpiredWorkerRole: {
|
||||
for (int i = 0; i < m_issuedConfigsInfo.size(); i++) {
|
||||
@@ -97,8 +93,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons
|
||||
|
||||
m_accountInfoData = accountInfoData;
|
||||
|
||||
m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -127,27 +121,12 @@ QJsonArray ApiAccountInfoModel::getIssuedConfigsInfo()
|
||||
|
||||
QString ApiAccountInfoModel::getTelegramBotLink()
|
||||
{
|
||||
return m_supportInfo.value(apiDefs::key::telegram).toString();
|
||||
}
|
||||
|
||||
QString ApiAccountInfoModel::getEmailLink()
|
||||
{
|
||||
return m_supportInfo.value(apiDefs::key::email).toString();
|
||||
}
|
||||
|
||||
QString ApiAccountInfoModel::getBillingEmailLink()
|
||||
{
|
||||
return m_supportInfo.value(apiDefs::key::billingEmail).toString();
|
||||
}
|
||||
|
||||
QString ApiAccountInfoModel::getSiteLink()
|
||||
{
|
||||
return m_supportInfo.value(apiDefs::key::websiteName).toString();
|
||||
}
|
||||
|
||||
QString ApiAccountInfoModel::getFullSiteLink()
|
||||
{
|
||||
return m_supportInfo.value(apiDefs::key::website).toString();
|
||||
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
|
||||
return tr("amnezia_free_support_bot");
|
||||
} else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) {
|
||||
return tr("amnezia_premium_support_bot");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
|
||||
|
||||
@@ -33,12 +33,7 @@ public slots:
|
||||
|
||||
QJsonArray getAvailableCountries();
|
||||
QJsonArray getIssuedConfigsInfo();
|
||||
|
||||
QString getTelegramBotLink();
|
||||
QString getEmailLink();
|
||||
QString getBillingEmailLink();
|
||||
QString getSiteLink();
|
||||
QString getFullSiteLink();
|
||||
|
||||
protected:
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
@@ -56,7 +51,6 @@ private:
|
||||
AccountInfoData m_accountInfoData;
|
||||
QJsonArray m_availableCountries;
|
||||
QJsonArray m_issuedConfigsInfo;
|
||||
QJsonObject m_supportInfo;
|
||||
};
|
||||
|
||||
#endif // APIACCOUNTINFOMODEL_H
|
||||
|
||||
@@ -209,7 +209,8 @@ ErrorCode ClientManagementModel::getWireGuardClients(const DockerContainer conta
|
||||
{
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
|
||||
const QString wireGuardConfigFile = QString("opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
|
||||
const QString wireGuardConfigFile =
|
||||
DockerContainer::WireGuard ? amnezia::protocols::wireguard::serverConfigPath : amnezia::protocols::awg::serverConfigPath;
|
||||
const QString wireguardConfigString = serverController->getTextFileFromContainer(container, credentials, wireGuardConfigFile, error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to get the wg conf file from the server";
|
||||
@@ -736,8 +737,17 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
|
||||
{
|
||||
ErrorCode error = ErrorCode::NoError;
|
||||
|
||||
const QString wireGuardConfigFile =
|
||||
QString("/opt/amnezia/%1/wg0.conf").arg(container == DockerContainer::WireGuard ? "wireguard" : "awg");
|
||||
QString wireGuardConfigFile;
|
||||
if (container == DockerContainer::Awg) {
|
||||
if (serverController->isNewAwgContainer(credentials)) {
|
||||
wireGuardConfigFile = amnezia::protocols::awg::serverConfigPath;
|
||||
} else {
|
||||
wireGuardConfigFile = "/opt/amnezia/awg/wg0.conf";
|
||||
}
|
||||
} else {
|
||||
wireGuardConfigFile = amnezia::protocols::wireguard::serverConfigPath;
|
||||
}
|
||||
|
||||
const QString wireguardConfigString = serverController->getTextFileFromContainer(container, credentials, wireGuardConfigFile, error);
|
||||
if (error != ErrorCode::NoError) {
|
||||
logger.error() << "Failed to get the wg conf file from the server";
|
||||
@@ -780,7 +790,11 @@ ErrorCode ClientManagementModel::revokeWireGuard(const int row, const DockerCont
|
||||
return error;
|
||||
}
|
||||
|
||||
const QString script = "sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'";
|
||||
QString interfaceName = DockerContainer::WireGuard ? protocols::wireguard::interfaceName : protocols::awg::interfaceName;
|
||||
QString wgBinaryName = DockerContainer::WireGuard ? protocols::wireguard::wgBinaryName : protocols::awg::wgBinaryName;
|
||||
QString wgQuickBinaryName = DockerContainer::WireGuard ? protocols::wireguard::wgQuickBinaryName : protocols::awg::wgQuickBinaryName;
|
||||
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c '%4 syncconf %2 <(%3 strip %1)'")
|
||||
.arg(wireGuardConfigFile, interfaceName, wgQuickBinaryName, wgBinaryName);
|
||||
error = serverController->runScript(
|
||||
credentials,
|
||||
serverController->replaceVars(script.arg(wireGuardConfigFile), serverController->genVarsForScript(credentials, container)));
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#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) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +50,8 @@ 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;
|
||||
@@ -101,12 +104,11 @@ QString LanguageModel::getCurrentLanguageName()
|
||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
||||
}
|
||||
|
||||
QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
||||
QString LanguageModel::getCurrentSiteUrl()
|
||||
{
|
||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||
switch (language) {
|
||||
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)));
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian: return "https://storage.googleapis.com/amnezia/amnezia.org";
|
||||
default: return "https://amnezia.org";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public slots:
|
||||
int getCurrentLanguageIndex();
|
||||
int getLineHeightAppend();
|
||||
QString getCurrentLanguageName();
|
||||
QString getCurrentSiteUrl(const QString &path = "");
|
||||
QString getCurrentSiteUrl();
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool enabled: true
|
||||
property string placeholderText: ""
|
||||
property alias textField: searchField.textField
|
||||
|
||||
signal addClicked(string text)
|
||||
signal moreClicked()
|
||||
|
||||
implicitWidth: 360
|
||||
implicitHeight: 96
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
color: "#0E0F12"
|
||||
opacity: 0.85
|
||||
z: -1
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: addSiteButton
|
||||
|
||||
enabled: root.enabled
|
||||
spacing: 2
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
topMargin: 16
|
||||
leftMargin: 16
|
||||
rightMargin: 16
|
||||
bottomMargin: 24
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: searchField
|
||||
|
||||
Layout.fillWidth: true
|
||||
rightButtonClickedOnEnter: true
|
||||
|
||||
textField.placeholderText: root.placeholderText
|
||||
buttonImageSource: "qrc:/images/controls/plus.svg"
|
||||
|
||||
clickedFunc: function() {
|
||||
root.addClicked(textField.text)
|
||||
textField.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: addSiteButtonImage
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
|
||||
image: "qrc:/images/controls/more-vertical.svg"
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
onClicked: root.moreClicked()
|
||||
|
||||
Keys.onReturnPressed: addSiteButtonImage.clicked()
|
||||
Keys.onEnterPressed: addSiteButtonImage.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property int headerTextMaximumLineCount: 2
|
||||
property int headerTextElide: Qt.ElideRight
|
||||
property string descriptionText
|
||||
property alias headerRow: headerRow
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
|
||||
Header1TextType {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
text: root.headerText
|
||||
maximumLineCount: root.headerTextMaximumLineCount
|
||||
elide: root.headerTextElide
|
||||
}
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
id: description
|
||||
Layout.topMargin: 16
|
||||
Layout.fillWidth: true
|
||||
text: root.descriptionText
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
86
client/ui/qml/Controls2/HeaderType.qml
Normal file
86
client/ui/qml/Controls2/HeaderType.qml
Normal file
@@ -0,0 +1,86 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string actionButtonImage
|
||||
property var actionButtonFunction
|
||||
|
||||
property alias actionButton: headerActionButton
|
||||
|
||||
property string headerText
|
||||
property int headerTextMaximumLineCount: 2
|
||||
property int headerTextElide: Qt.ElideRight
|
||||
|
||||
property string descriptionText
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
Header1TextType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.headerText
|
||||
maximumLineCount: root.headerTextMaximumLineCount
|
||||
elide: root.headerTextElide
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: headerActionButton
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
image: root.actionButtonImage
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
visible: image ? true : false
|
||||
|
||||
onClicked: {
|
||||
if (actionButtonFunction && typeof actionButtonFunction === "function") {
|
||||
actionButtonFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
id: description
|
||||
|
||||
Layout.topMargin: 16
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.descriptionText
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (actionButtonFunction && typeof actionButtonFunction === "function") {
|
||||
actionButtonFunction()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (actionButtonFunction && typeof actionButtonFunction === "function") {
|
||||
actionButtonFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
BaseHeaderType {
|
||||
id: root
|
||||
|
||||
property string actionButtonImage
|
||||
property var actionButtonFunction
|
||||
property alias actionButton: headerActionButton
|
||||
|
||||
Component.onCompleted: {
|
||||
headerRow.children.push(headerActionButton)
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: headerActionButton
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
Layout.alignment: Qt.AlignRight
|
||||
image: root.actionButtonImage
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
visible: image ? true : false
|
||||
|
||||
onClicked: {
|
||||
if (actionButtonFunction && typeof actionButtonFunction === "function") {
|
||||
actionButtonFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (actionButtonFunction && typeof actionButtonFunction === "function") {
|
||||
actionButtonFunction()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (actionButtonFunction && typeof actionButtonFunction === "function") {
|
||||
actionButtonFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
BaseHeaderType {
|
||||
id: root
|
||||
|
||||
property var switcherFunction
|
||||
property bool showSwitcher: false
|
||||
property alias switcher: headerSwitcher
|
||||
|
||||
Component.onCompleted: {
|
||||
headerRow.children.push(headerSwitcher)
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: headerSwitcher
|
||||
Layout.alignment: Qt.AlignRight
|
||||
visible: root.showSwitcher
|
||||
|
||||
onToggled: {
|
||||
if (switcherFunction && typeof switcherFunction === "function") {
|
||||
switcherFunction(checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,7 @@ RadioButton {
|
||||
property string selectedColor: AmneziaStyle.color.transparent
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
property string selectedTextColor: AmneziaStyle.color.goldenApricot
|
||||
property string selectedTextDisabledColor: AmneziaStyle.color.burntOrange
|
||||
property string descriptionColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
@@ -34,12 +30,6 @@ RadioButton {
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
|
||||
property string radioButtonInnerCirclePressedSource: "qrc:/images/controls/radio-button-inner-circle-pressed.png"
|
||||
property string radioButtonInnerCircleSource: "qrc:/images/controls/radio-button-inner-circle.png"
|
||||
property string radioButtonPressedSource: "qrc:/images/controls/radio-button-pressed.svg"
|
||||
property string radioButtonDefaultSource: "qrc:/images/controls/radio-button.svg"
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
@@ -104,15 +94,14 @@ RadioButton {
|
||||
if (showImage) {
|
||||
return imageSource
|
||||
} else if (root.pressed) {
|
||||
return root.radioButtonInnerCirclePressedSource
|
||||
return "qrc:/images/controls/radio-button-inner-circle-pressed.png"
|
||||
} else if (root.checked) {
|
||||
return root.radioButtonInnerCircleSource
|
||||
return "qrc:/images/controls/radio-button-inner-circle.png"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
opacity: root.enabled ? 1.0 : 0.3
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: 24
|
||||
@@ -124,13 +113,12 @@ RadioButton {
|
||||
if (showImage) {
|
||||
return ""
|
||||
} else if (root.pressed || root.checked) {
|
||||
return root.radioButtonPressedSource
|
||||
return "qrc:/images/controls/radio-button-pressed.svg"
|
||||
} else {
|
||||
return root.radioButtonDefaultSource
|
||||
return "qrc:/images/controls/radio-button.svg"
|
||||
}
|
||||
}
|
||||
|
||||
opacity: root.enabled ? 1.0 : 0.3
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: 24
|
||||
@@ -160,11 +148,10 @@ RadioButton {
|
||||
elide: root.textElide
|
||||
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
return root.checked ? selectedTextColor : textColor
|
||||
} else {
|
||||
return root.checked ? selectedTextDisabledColor : textDisabledColor
|
||||
if (root.checked) {
|
||||
return selectedTextColor
|
||||
}
|
||||
return textColor
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
@@ -177,7 +164,7 @@ RadioButton {
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
color: root.enabled ? root.descriptionColor : root.descriptionDisabledColor
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
text: root.descriptionText
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
|
||||
@@ -56,7 +56,7 @@ PageType {
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ PageType {
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -91,7 +91,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
|
||||
@@ -91,7 +91,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
|
||||
@@ -76,7 +76,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Cloak settings")
|
||||
|
||||
@@ -75,7 +75,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("OpenVPN settings")
|
||||
|
||||
@@ -32,7 +32,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -78,7 +78,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Shadowsocks settings")
|
||||
|
||||
@@ -85,7 +85,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("WG settings")
|
||||
|
||||
@@ -77,7 +77,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("WG settings")
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
headerText: qsTr("XRay settings")
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -85,7 +85,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -77,7 +77,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
@@ -217,7 +217,7 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("SOCKS5 settings")
|
||||
|
||||
@@ -54,7 +54,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -29,7 +29,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
@@ -252,7 +252,7 @@ PageType {
|
||||
text: qsTr("Privacy Policy")
|
||||
|
||||
clickedFunc: function() {
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl("policy"))
|
||||
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl() + "/policy")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ PageType {
|
||||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderTypeWithButton {
|
||||
HeaderType {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -91,7 +91,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -38,7 +38,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -93,7 +93,7 @@ PageType {
|
||||
Layout.topMargin: 20
|
||||
}
|
||||
|
||||
HeaderTypeWithButton {
|
||||
HeaderType {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
|
||||
@@ -28,24 +28,24 @@ PageType {
|
||||
id: techSupport
|
||||
|
||||
readonly property string title: qsTr("Email")
|
||||
readonly property string description: ApiAccountInfoModel.getEmailLink()
|
||||
readonly property string link: "mailto:" + ApiAccountInfoModel.getEmailLink()
|
||||
readonly property string description: qsTr("support@amnezia.org")
|
||||
readonly property string link: "mailto:support@amnezia.org"
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: paymentSupport
|
||||
|
||||
readonly property string title: qsTr("Email Billing & Orders")
|
||||
readonly property string description: ApiAccountInfoModel.getBillingEmailLink()
|
||||
readonly property string link: "mailto:" + ApiAccountInfoModel.getBillingEmailLink()
|
||||
readonly property string description: qsTr("help@vpnpay.io")
|
||||
readonly property string link: "mailto:help@vpnpay.io"
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: site
|
||||
|
||||
readonly property string title: qsTr("Website")
|
||||
readonly property string description: ApiAccountInfoModel.getSiteLink()
|
||||
readonly property string link: ApiAccountInfoModel.getFullSiteLink()
|
||||
readonly property string description: qsTr("amnezia.org")
|
||||
readonly property string link: LanguageModel.getCurrentSiteUrl()
|
||||
}
|
||||
|
||||
property list<QtObject> supportModel: [
|
||||
@@ -71,7 +71,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -79,22 +79,29 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
HeaderTypeWithSwitcher {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
RowLayout {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("App split tunneling")
|
||||
headerText: qsTr("App split tunneling")
|
||||
|
||||
enabled: root.pageEnabled
|
||||
showSwitcher: true
|
||||
switcher {
|
||||
checked: AppSplitTunnelingModel.isTunnelingEnabled
|
||||
enabled: root.pageEnabled
|
||||
}
|
||||
switcherFunction: function(checked) {
|
||||
AppSplitTunnelingModel.toggleSplitTunneling(checked)
|
||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||
|
||||
SwitcherType {
|
||||
id: switcher
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
checked: AppSplitTunnelingModel.isTunnelingEnabled
|
||||
onToggled: {
|
||||
AppSplitTunnelingModel.toggleSplitTunneling(checked)
|
||||
selector.text = root.routeModesModel[getRouteModesModelIndex()].name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ PageType {
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -60,7 +60,7 @@ PageType {
|
||||
|
||||
spacing: 16
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Back up your configuration")
|
||||
|
||||
@@ -36,7 +36,7 @@ PageType {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
@@ -94,7 +94,9 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
DividerType {
|
||||
visible: root.isAppSplitTinnelingEnabled
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: splitTunnelingButton2
|
||||
@@ -117,20 +119,29 @@ PageType {
|
||||
visible: root.isAppSplitTinnelingEnabled
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: killSwitchButton
|
||||
SwitcherType {
|
||||
id: killSwitchSwitcher
|
||||
visible: !GC.isMobile()
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
text: qsTr("KillSwitch")
|
||||
descriptionText: qsTr("Blocks network connections without VPN")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
descriptionText: qsTr("Disables your internet if your encrypted VPN connection drops out for any reason.")
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsKillSwitch)
|
||||
checked: SettingsController.isKillSwitchEnabled()
|
||||
checkable: !ConnectionController.isConnected
|
||||
onCheckedChanged: {
|
||||
if (checked !== SettingsController.isKillSwitchEnabled()) {
|
||||
SettingsController.toggleKillSwitch(checked)
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
if (!checkable) {
|
||||
PageController.showNotificationMessage(qsTr("Cannot change KillSwitch settings during active connection"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ PageType {
|
||||
|
||||
spacing: 16
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("DNS servers")
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Config"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.height
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
HeaderTypeWithSwitcher {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("KillSwitch")
|
||||
descriptionText: qsTr("Enable to ensure network traffic goes through a secure VPN tunnel, preventing accidental exposure of your IP and DNS queries if the connection drops")
|
||||
|
||||
showSwitcher: true
|
||||
switcher {
|
||||
checked: SettingsController.isKillSwitchEnabled
|
||||
enabled: !ConnectionController.isConnected
|
||||
}
|
||||
switcherFunction: function(checked) {
|
||||
if (!ConnectionController.isConnected) {
|
||||
SettingsController.isKillSwitchEnabled = checked
|
||||
} else {
|
||||
PageController.showNotificationMessage(qsTr("Cannot change killSwitch settings during active connection"))
|
||||
switcher.checked = SettingsController.isKillSwitchEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerticalRadioButton {
|
||||
id: softKillSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
checked: !SettingsController.strictKillSwitchEnabled
|
||||
|
||||
text: qsTr("Soft KillSwitch")
|
||||
descriptionText: qsTr("Internet connection is blocked if VPN connection drops accidentally")
|
||||
|
||||
onClicked: function() {
|
||||
SettingsController.strictKillSwitchEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
VerticalRadioButton {
|
||||
id: strictKillSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
|
||||
checked: SettingsController.strictKillSwitchEnabled
|
||||
|
||||
text: qsTr("Strict KillSwitch")
|
||||
descriptionText: qsTr("Internet connection is blocked even if VPN was turned off manually or not started")
|
||||
|
||||
onClicked: function() {
|
||||
var headerText = qsTr("Just a little heads-up")
|
||||
var descriptionText = qsTr("If you disconnect from VPN or the VPN connection drops while the Strict Kill Switch is turned on, your internet access will be disabled. To restore it, connect to VPN, change the Kill Switch mode or turn the Kill Switch off.")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
SettingsController.strictKillSwitchEnabled = true
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
Layout.topMargin: 32
|
||||
Layout.fillWidth: true
|
||||
|
||||
enabled: true
|
||||
text: qsTr("DNS Exceptions")
|
||||
descriptionText: qsTr("DNS servers from the list will remain accessible when Kill Switch is triggered")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsKillSwitchExceptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import QtCore
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ProtocolEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
property bool pageEnabled: true
|
||||
|
||||
ColumnLayout {
|
||||
id: header
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
enabled: root.pageEnabled
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
|
||||
headerText: qsTr("DNS Exceptions")
|
||||
descriptionText: qsTr("DNS servers from the list will remain accessible when Kill Switch is triggered")
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: header.bottom
|
||||
anchors.topMargin: 16
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
width: parent.width
|
||||
|
||||
enabled: root.pageEnabled
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
cacheBuffer: 200
|
||||
displayMarginBeginning: 40
|
||||
displayMarginEnd: 40
|
||||
|
||||
ScrollBar.vertical: ScrollBarType { }
|
||||
|
||||
footer: Item {
|
||||
width: listView.width
|
||||
height: addSitePanel.height
|
||||
}
|
||||
|
||||
footerPositioning: ListView.InlineFooter
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: dnsFilterModel
|
||||
sourceModel: AllowedDnsModel
|
||||
filters: [
|
||||
RegExpFilter {
|
||||
roleName: "ip"
|
||||
pattern: ".*" + addSitePanel.textField.text + ".*"
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
clip: true
|
||||
|
||||
reuseItems: true
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: delegateContent
|
||||
|
||||
width: listView.width
|
||||
|
||||
LabelWithButtonType {
|
||||
id: site
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: ip
|
||||
rightImageSource: "qrc:/images/controls/trash.svg"
|
||||
rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
clickedFunction: function() {
|
||||
var headerText = qsTr("Delete ") + ip + "?"
|
||||
var yesButtonText = qsTr("Continue")
|
||||
var noButtonText = qsTr("Cancel")
|
||||
|
||||
var yesButtonFunction = function() {
|
||||
AllowedDnsController.removeDns(dnsFilterModel.mapToSource(index))
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
site.rightButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
|
||||
AddSitePanel {
|
||||
id: addSitePanel
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
enabled: root.pageEnabled
|
||||
placeholderText: qsTr("IPv4 address")
|
||||
|
||||
onAddClicked: function(text) {
|
||||
PageController.showBusyIndicator(true)
|
||||
AllowedDnsController.addDns(text)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
|
||||
onMoreClicked: {
|
||||
moreActionsDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: moreActionsDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: moreActionsDrawerContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
headerText: qsTr("Import / Export addresses")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: importSitesButton
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Import")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
importSitesDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: exportSitesButton
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Save address list")
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = "amnezia_killswitch_exceptions.json"
|
||||
} else {
|
||||
fileName = SystemController.getFileName(qsTr("Save addresses"),
|
||||
qsTr("Address files (*.json)"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/amnezia_killswitch_exceptions",
|
||||
true,
|
||||
".json")
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
AllowedDnsController.exportDns(fileName)
|
||||
moreActionsDrawer.closeTriggered()
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: importSitesDrawer
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.4375
|
||||
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: importSitesDrawer.expandedHeight
|
||||
|
||||
BackButtonType {
|
||||
id: importSitesDrawerBackButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() {
|
||||
importSitesDrawer.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
anchors.top: importSitesDrawerBackButton.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
contentHeight: importSitesDrawerContent.height
|
||||
|
||||
ColumnLayout {
|
||||
id: importSitesDrawerContent
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 16
|
||||
|
||||
headerText: qsTr("Import address list")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: importSitesButton2
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Replace address list")
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = SystemController.getFileName(qsTr("Open address file"),
|
||||
qsTr("Address files (*.json)"))
|
||||
if (fileName !== "") {
|
||||
importSitesDrawerContent.importSites(fileName, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: importSitesButton3
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Add imported addresses to existing ones")
|
||||
|
||||
clickedFunction: function() {
|
||||
var fileName = SystemController.getFileName(qsTr("Open address file"),
|
||||
qsTr("Address files (*.json)"))
|
||||
if (fileName !== "") {
|
||||
importSitesDrawerContent.importSites(fileName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function importSites(fileName, replaceExistingSites) {
|
||||
PageController.showBusyIndicator(true)
|
||||
AllowedDnsController.importDns(fileName, replaceExistingSites)
|
||||
PageController.showBusyIndicator(false)
|
||||
importSitesDrawer.closeTriggered()
|
||||
moreActionsDrawer.closeTriggered()
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ PageType {
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -71,7 +71,7 @@ PageType {
|
||||
objectName: "backButton"
|
||||
}
|
||||
|
||||
HeaderTypeWithButton {
|
||||
HeaderType {
|
||||
id: headerContent
|
||||
objectName: "headerContent"
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -31,7 +31,7 @@ PageType {
|
||||
id: backButton
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
HeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user