Compare commits

..

21 commits

Author SHA1 Message Date
Cyril Anisimov
4a8877c2ed refactor OpenVpnSettings page for correct focus 2025-06-17 09:28:56 +02:00
Cyril Anisimov
09e3f39122 make TextAreaType focusable 2025-06-17 09:28:56 +02:00
Cyril Anisimov
3393b97392 refactor OpenVpnConfigModel 2025-06-17 09:28:56 +02:00
Cyril Anisimov
0bc762ccbf update positioning in ListViewFocusController 2025-06-17 09:28:56 +02:00
Cyril Anisimov
727526b39a add focus to CheckBoxType 2025-06-17 09:28:56 +02:00
Cyril Anisimov
00f49dbc82 fix xray settings layout 2025-06-17 09:28:56 +02:00
Cyril Anisimov
b1627887eb fix selection on EasyWizardSetupPage 2025-06-17 09:28:56 +02:00
Cyril Anisimov
ad32b68d84 fix layout 2025-06-17 09:28:56 +02:00
Cyril Anisimov
117c66cd7d fix margins in server info managment tab 2025-06-17 09:28:56 +02:00
Cyril Anisimov
b8d49abdd1 fix: update server access property assignment and import sites method calls 2025-06-17 09:28:56 +02:00
Cyril Anisimov
0298371a52 fix config string view 2025-06-17 09:28:56 +02:00
Cyril Anisimov
5d133aa1a6 fix config load on Mac 2025-06-17 09:28:56 +02:00
Cyril Anisimov
4b20250051 remove deprecated parentFlickable field 2025-06-17 09:28:56 +02:00
Cyril Anisimov
06544660a4 fix full access share 2025-06-17 09:28:56 +02:00
Cyril Anisimov
671d762a20 fix SettingsContainersListView 2025-06-17 09:28:56 +02:00
Cyril Anisimov
d110c96b5c fix key import 2025-06-17 09:28:56 +02:00
Cyril Anisimov
cf5ecf1f1a fix copy on share config 2025-06-17 09:28:56 +02:00
Cyril Anisimov
111a60d81c fix PageSetupWizardProtocolSettings titles 2025-06-17 09:28:56 +02:00
Cyril Anisimov
8b01638424 fix PageSetupWizardEasy 2025-06-17 09:28:56 +02:00
Cyril Anisimov
65e7237610 Update client/ui/controllers/listViewFocusController.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-17 09:28:56 +02:00
Cyril Anisimov
7d187bf881 replace FlickableType and ListView with
`ListViewType`
2025-06-17 09:28:56 +02:00
120 changed files with 6992 additions and 8329 deletions

View file

@ -255,6 +255,7 @@ jobs:
env: env:
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4 # Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
QT_VERSION: 6.4.3 QT_VERSION: 6.4.3
QIF_VERSION: 4.6
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
@ -282,6 +283,11 @@ jobs:
set-env: 'true' set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}' extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
run: |
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
- name: 'Get sources' - name: 'Get sources'
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -295,13 +301,14 @@ jobs:
- name: 'Build project' - name: 'Build project'
run: | run: |
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin" export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
bash deploy/build_macos.sh bash deploy/build_macos.sh
- name: 'Upload installer artifact' - name: 'Upload installer artifact'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: AmneziaVPN_MacOS_old_installer name: AmneziaVPN_MacOS_old_installer
path: deploy/build/pkg/AmneziaVPN.pkg path: AmneziaVPN.dmg
retention-days: 7 retention-days: 7
- name: 'Upload unpacked artifact' - name: 'Upload unpacked artifact'
@ -318,6 +325,7 @@ jobs:
env: env:
QT_VERSION: 6.8.0 QT_VERSION: 6.8.0
QIF_VERSION: 4.8.1
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }} PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
@ -345,6 +353,11 @@ jobs:
set-env: 'true' set-env: 'true'
extra: '--external 7z --base ${{ env.QT_MIRROR }}' extra: '--external 7z --base ${{ env.QT_MIRROR }}'
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
run: |
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
- name: 'Get sources' - name: 'Get sources'
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -358,13 +371,14 @@ jobs:
- name: 'Build project' - name: 'Build project'
run: | run: |
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin" export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
bash deploy/build_macos.sh bash deploy/build_macos.sh
- name: 'Upload installer artifact' - name: 'Upload installer artifact'
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: AmneziaVPN_MacOS_installer name: AmneziaVPN_MacOS_installer
path: deploy/build/pkg/AmneziaVPN.pkg path: AmneziaVPN.dmg
retention-days: 7 retention-days: 7
- name: 'Upload unpacked artifact' - name: 'Upload unpacked artifact'

1
.gitmodules vendored
View file

@ -7,7 +7,6 @@
[submodule "client/3rd-prebuilt"] [submodule "client/3rd-prebuilt"]
path = client/3rd-prebuilt path = client/3rd-prebuilt
url = https://github.com/amnezia-vpn/3rd-prebuilt url = https://github.com/amnezia-vpn/3rd-prebuilt
branch = feature/special-handshake
[submodule "client/3rd/amneziawg-apple"] [submodule "client/3rd/amneziawg-apple"]
path = client/3rd/amneziawg-apple path = client/3rd/amneziawg-apple
url = https://github.com/amnezia-vpn/amneziawg-apple url = https://github.com/amnezia-vpn/amneziawg-apple

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN) set(PROJECT AmneziaVPN)
project(${PROJECT} VERSION 4.8.8.1 project(${PROJECT} VERSION 4.8.7.2
DESCRIPTION "AmneziaVPN" DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/" HOMEPAGE_URL "https://amnezia.org/"
) )
@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}") set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}) set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
set(APP_ANDROID_VERSION_CODE 2087) set(APP_ANDROID_VERSION_CODE 2086)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux") set(MZ_PLATFORM_NAME "linux")

@ -1 +1 @@
Subproject commit 840b7b070e6ac8b90dda2fac6e98859b23727c0c Subproject commit 0f3748efd7cc04e0c914304b68931f925bed1259

@ -1 +1 @@
Subproject commit 811af0a83b3faeade89a9093a588595666d32066 Subproject commit 76e7db556a6d7e2582f9481df91db188a46c009c

View file

@ -120,21 +120,10 @@ open class Wireguard : Protocol() {
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) } configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
configData.optStringOrNull("S1")?.let { setS1(it.toInt()) } configData.optStringOrNull("S1")?.let { setS1(it.toInt()) }
configData.optStringOrNull("S2")?.let { setS2(it.toInt()) } configData.optStringOrNull("S2")?.let { setS2(it.toInt()) }
configData.optStringOrNull("S3")?.let { setS3(it.toInt()) }
configData.optStringOrNull("S4")?.let { setS4(it.toInt()) }
configData.optStringOrNull("H1")?.let { setH1(it.toLong()) } configData.optStringOrNull("H1")?.let { setH1(it.toLong()) }
configData.optStringOrNull("H2")?.let { setH2(it.toLong()) } configData.optStringOrNull("H2")?.let { setH2(it.toLong()) }
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) } configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) } configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
configData.optStringOrNull("I1")?.let { setI1(it) }
configData.optStringOrNull("I2")?.let { setI2(it) }
configData.optStringOrNull("I3")?.let { setI3(it) }
configData.optStringOrNull("I4")?.let { setI4(it) }
configData.optStringOrNull("I5")?.let { setI5(it) }
configData.optStringOrNull("J1")?.let { setJ1(it) }
configData.optStringOrNull("J2")?.let { setJ2(it) }
configData.optStringOrNull("J3")?.let { setJ3(it) }
configData.optStringOrNull("Itime")?.let { setItime(it.toInt()) }
} }
private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) { private fun start(config: WireguardConfig, vpnBuilder: Builder, protect: (Int) -> Boolean) {

View file

@ -20,21 +20,10 @@ open class WireguardConfig protected constructor(
val jmax: Int?, val jmax: Int?,
val s1: Int?, val s1: Int?,
val s2: Int?, val s2: Int?,
val s3: Int?,
val s4: Int?,
val h1: Long?, val h1: Long?,
val h2: Long?, val h2: Long?,
val h3: Long?, val h3: Long?,
val h4: Long?, val h4: Long?
var i1: String?,
var i2: String?,
var i3: String?,
var i4: String?,
var i5: String?,
var j1: String?,
var j2: String?,
var j3: String?,
var itime: Int?
) : ProtocolConfig(protocolConfigBuilder) { ) : ProtocolConfig(protocolConfigBuilder) {
protected constructor(builder: Builder) : this( protected constructor(builder: Builder) : this(
@ -50,21 +39,10 @@ open class WireguardConfig protected constructor(
builder.jmax, builder.jmax,
builder.s1, builder.s1,
builder.s2, builder.s2,
builder.s3,
builder.s4,
builder.h1, builder.h1,
builder.h2, builder.h2,
builder.h3, builder.h3,
builder.h4, builder.h4
builder.i1,
builder.i2,
builder.i3,
builder.i4,
builder.i5,
builder.j1,
builder.j2,
builder.j3,
builder.itime
) )
fun toWgUserspaceString(): String = with(StringBuilder()) { fun toWgUserspaceString(): String = with(StringBuilder()) {
@ -83,21 +61,10 @@ open class WireguardConfig protected constructor(
appendLine("jmax=$jmax") appendLine("jmax=$jmax")
appendLine("s1=$s1") appendLine("s1=$s1")
appendLine("s2=$s2") appendLine("s2=$s2")
s3?.let { appendLine("s3=$it") }
s4?.let { appendLine("s4=$it") }
appendLine("h1=$h1") appendLine("h1=$h1")
appendLine("h2=$h2") appendLine("h2=$h2")
appendLine("h3=$h3") appendLine("h3=$h3")
appendLine("h4=$h4") appendLine("h4=$h4")
i1?.let { appendLine("i1=$it") }
i2?.let { appendLine("i2=$it") }
i3?.let { appendLine("i3=$it") }
i4?.let { appendLine("i4=$it") }
i5?.let { appendLine("i5=$it") }
j1?.let { appendLine("j1=$it") }
j2?.let { appendLine("j2=$it") }
j3?.let { appendLine("j3=$it") }
itime?.let { appendLine("itime=$it") }
} }
} }
@ -150,21 +117,10 @@ open class WireguardConfig protected constructor(
internal var jmax: Int? = null internal var jmax: Int? = null
internal var s1: Int? = null internal var s1: Int? = null
internal var s2: Int? = null internal var s2: Int? = null
internal var s3: Int? = null
internal var s4: Int? = null
internal var h1: Long? = null internal var h1: Long? = null
internal var h2: Long? = null internal var h2: Long? = null
internal var h3: Long? = null internal var h3: Long? = null
internal var h4: Long? = null internal var h4: Long? = null
internal var i1: String? = null
internal var i2: String? = null
internal var i3: String? = null
internal var i4: String? = null
internal var i5: String? = null
internal var j1: String? = null
internal var j2: String? = null
internal var j3: String? = null
internal var itime: Int? = null
fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint } fun setEndpoint(endpoint: InetEndpoint) = apply { this.endpoint = endpoint }
@ -183,21 +139,10 @@ open class WireguardConfig protected constructor(
fun setJmax(jmax: Int) = apply { this.jmax = jmax } fun setJmax(jmax: Int) = apply { this.jmax = jmax }
fun setS1(s1: Int) = apply { this.s1 = s1 } fun setS1(s1: Int) = apply { this.s1 = s1 }
fun setS2(s2: Int) = apply { this.s2 = s2 } fun setS2(s2: Int) = apply { this.s2 = s2 }
fun setS3(s3: Int) = apply { this.s3 = s3 }
fun setS4(s4: Int) = apply { this.s4 = s4 }
fun setH1(h1: Long) = apply { this.h1 = h1 } fun setH1(h1: Long) = apply { this.h1 = h1 }
fun setH2(h2: Long) = apply { this.h2 = h2 } fun setH2(h2: Long) = apply { this.h2 = h2 }
fun setH3(h3: Long) = apply { this.h3 = h3 } fun setH3(h3: Long) = apply { this.h3 = h3 }
fun setH4(h4: Long) = apply { this.h4 = h4 } fun setH4(h4: Long) = apply { this.h4 = h4 }
fun setI1(i1: String) = apply { this.i1 = i1 }
fun setI2(i2: String) = apply { this.i2 = i2 }
fun setI3(i3: String) = apply { this.i3 = i3 }
fun setI4(i4: String) = apply { this.i4 = i4 }
fun setI5(i5: String) = apply { this.i5 = i5 }
fun setJ1(j1: String) = apply { this.j1 = j1 }
fun setJ2(j2: String) = apply { this.j2 = j2 }
fun setJ3(j3: String) = apply { this.j3 = j3 }
fun setItime(itime: Int) = apply { this.itime = itime }
override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) } override fun build(): WireguardConfig = configBuild().run { WireguardConfig(this@Builder) }
} }

View file

@ -1,5 +1,4 @@
#include "awg_configurator.h" #include "awg_configurator.h"
#include "protocols/protocols_defs.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
@ -40,20 +39,6 @@ QString AwgConfigurator::createConfig(const ServerCredentials &credentials, Dock
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader); jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader); jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader); jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
// jsonConfig[config_key::cookieReplyPacketJunkSize] = configMap.value(config_key::cookieReplyPacketJunkSize);
// jsonConfig[config_key::transportPacketJunkSize] = configMap.value(config_key::transportPacketJunkSize);
// jsonConfig[config_key::specialJunk1] = configMap.value(amnezia::config_key::specialJunk1);
// jsonConfig[config_key::specialJunk2] = configMap.value(amnezia::config_key::specialJunk2);
// jsonConfig[config_key::specialJunk3] = configMap.value(amnezia::config_key::specialJunk3);
// jsonConfig[config_key::specialJunk4] = configMap.value(amnezia::config_key::specialJunk4);
// jsonConfig[config_key::specialJunk5] = configMap.value(amnezia::config_key::specialJunk5);
// jsonConfig[config_key::controlledJunk1] = configMap.value(amnezia::config_key::controlledJunk1);
// jsonConfig[config_key::controlledJunk2] = configMap.value(amnezia::config_key::controlledJunk2);
// jsonConfig[config_key::controlledJunk3] = configMap.value(amnezia::config_key::controlledJunk3);
// jsonConfig[config_key::specialHandshakeTimeout] = configMap.value(amnezia::config_key::specialHandshakeTimeout);
jsonConfig[config_key::mtu] = jsonConfig[config_key::mtu] =
containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu); containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu);

View file

@ -118,12 +118,6 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
QRegularExpression regex("redirect-gateway.*"); QRegularExpression regex("redirect-gateway.*");
config.replace(regex, ""); config.replace(regex, "");
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
config.replace(dnsRegex, "");
}
if (!m_settings->isSitesSplitTunnelingEnabled()) { if (!m_settings->isSitesSplitTunnelingEnabled()) {
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
config.append("block-ipv6\n"); config.append("block-ipv6\n");
@ -167,12 +161,6 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString
QRegularExpression regex("redirect-gateway.*"); QRegularExpression regex("redirect-gateway.*");
config.replace(regex, ""); config.replace(regex, "");
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (dns.first.contains(protocols::dns::amneziaDnsIp)) {
QRegularExpression dnsRegex("dhcp-option DNS " + dns.second);
config.replace(dnsRegex, "");
}
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n"); config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
// Prevent ipv6 leak // Prevent ipv6 leak

View file

@ -32,7 +32,6 @@ namespace apiDefs
constexpr QLatin1String stackType("stack_type"); constexpr QLatin1String stackType("stack_type");
constexpr QLatin1String serviceType("service_type"); constexpr QLatin1String serviceType("service_type");
constexpr QLatin1String cliVersion("cli_version"); constexpr QLatin1String cliVersion("cli_version");
constexpr QLatin1String supportedProtocols("supported_protocols");
constexpr QLatin1String vpnKey("vpn_key"); constexpr QLatin1String vpnKey("vpn_key");
constexpr QLatin1String config("config"); constexpr QLatin1String config("config");

View file

@ -349,7 +349,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)) != newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|| (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort) || (oldProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort)) != newProtoConfig.value(config_key::port).toString(protocols::awg::defaultPort))
|| (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount) || (oldProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount)) != newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
|| (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize) || (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize)
@ -366,13 +366,8 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
!= newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader)) != newProtoConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader))
|| (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader) || (oldProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)
!= newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader)) != newProtoConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader))
|| (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)) || (oldProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)
!= newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)) != newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader)))
// || (oldProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize)
// != newProtoConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize))
// || (oldProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize)
// != newProtoConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize))
return true; return true;
} }
@ -380,7 +375,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress) if ((oldProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)
!= newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress)) != newProtoConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress))
|| (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort) || (oldProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort))) != newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
return true; return true;
} }
@ -465,8 +460,6 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
return ErrorCode::ServerDockerOnCgroupsV2; return ErrorCode::ServerDockerOnCgroupsV2;
if (stdOut.contains("cgroup mountpoint does not exist")) if (stdOut.contains("cgroup mountpoint does not exist"))
return ErrorCode::ServerCgroupMountpoint; return ErrorCode::ServerCgroupMountpoint;
if (stdOut.contains("have reached") && stdOut.contains("pull rate limit"))
return ErrorCode::DockerPullRateLimit;
return error; return error;
} }
@ -646,9 +639,6 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } }); vars.append({ { "$UNDERLOAD_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::underloadPacketMagicHeader).toString() } });
vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } }); vars.append({ { "$TRANSPORT_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::transportPacketMagicHeader).toString() } });
vars.append({ { "$COOKIE_REPLY_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::cookieReplyPacketJunkSize).toString() } });
vars.append({ { "$TRANSPORT_PACKET_JUNK_SIZE", amneziaWireguarConfig.value(config_key::transportPacketJunkSize).toString() } });
// Socks5 proxy vars // Socks5 proxy vars
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } }); vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
auto username = socks5ProxyConfig.value(config_key::userName).toString(); auto username = socks5ProxyConfig.value(config_key::userName).toString();
@ -835,7 +825,7 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
if (stdOut.contains("Packet manager not found")) if (stdOut.contains("Packet manager not found"))
return ErrorCode::ServerPacketManagerError; return ErrorCode::ServerPacketManagerError;
if (stdOut.contains("fuser not installed") || stdOut.contains("cat not installed")) if (stdOut.contains("fuser not installed"))
return ErrorCode::NoError; return ErrorCode::NoError;
if (stdOut.isEmpty()) { if (stdOut.isEmpty()) {

View file

@ -60,7 +60,6 @@ namespace amnezia
ServerUserPasswordRequired = 210, ServerUserPasswordRequired = 210,
ServerDockerOnCgroupsV2 = 211, ServerDockerOnCgroupsV2 = 211,
ServerCgroupMountpoint = 212, ServerCgroupMountpoint = 212,
DockerPullRateLimit = 213,
// Ssh connection errors // Ssh connection errors
SshRequestDeniedError = 300, SshRequestDeniedError = 300,

View file

@ -28,7 +28,6 @@ QString errorString(ErrorCode code) {
case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break; case(ErrorCode::ServerUserPasswordRequired): errorMessage = QObject::tr("The user's password is required"); break;
case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break; case(ErrorCode::ServerDockerOnCgroupsV2): errorMessage = QObject::tr("Docker error: runc doesn't work on cgroups v2"); break;
case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break; case(ErrorCode::ServerCgroupMountpoint): errorMessage = QObject::tr("Server error: cgroup mountpoint does not exist"); break;
case(ErrorCode::DockerPullRateLimit): errorMessage = QObject::tr("Docker error: The pull rate limit has been reached"); break;
// Libssh errors // Libssh errors
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break; case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;

View file

@ -169,14 +169,11 @@ bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
if ((config.m_hopType == InterfaceConfig::MultiHopExit) || if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
(config.m_hopType == InterfaceConfig::SingleHop)) { (config.m_hopType == InterfaceConfig::SingleHop)) {
QList<QHostAddress> resolvers; QList<QHostAddress> resolvers;
resolvers.append(QHostAddress(config.m_primaryDnsServer)); resolvers.append(QHostAddress(config.m_dnsServer));
if (!config.m_secondaryDnsServer.isEmpty()) {
resolvers.append(QHostAddress(config.m_secondaryDnsServer));
}
// If the DNS is not the Gateway, it's a user defined DNS // If the DNS is not the Gateway, it's a user defined DNS
// thus, not add any other :) // thus, not add any other :)
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) { if (config.m_dnsServer == config.m_serverIpv4Gateway) {
resolvers.append(QHostAddress(config.m_serverIpv6Gateway)); resolvers.append(QHostAddress(config.m_serverIpv6Gateway));
} }
@ -282,26 +279,15 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString(); config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString();
config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString(); config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString();
if (!obj.contains("primaryDnsServer")) { if (!obj.contains("dnsServer")) {
config.m_primaryDnsServer = QString(); config.m_dnsServer = QString();
} else { } else {
QJsonValue value = obj.value("primaryDnsServer"); QJsonValue value = obj.value("dnsServer");
if (!value.isString()) { if (!value.isString()) {
logger.error() << "dnsServer is not a string"; logger.error() << "dnsServer is not a string";
return false; return false;
} }
config.m_primaryDnsServer = value.toString(); config.m_dnsServer = value.toString();
}
if (!obj.contains("secondaryDnsServer")) {
config.m_secondaryDnsServer = QString();
} else {
QJsonValue value = obj.value("secondaryDnsServer");
if (!value.isString()) {
logger.error() << "dnsServer is not a string";
return false;
}
config.m_secondaryDnsServer = value.toString();
} }
if (!obj.contains("hopType")) { if (!obj.contains("hopType")) {
@ -405,13 +391,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
if (!obj.value("S2").isNull()) { if (!obj.value("S2").isNull()) {
config.m_responsePacketJunkSize = obj.value("S2").toString(); config.m_responsePacketJunkSize = obj.value("S2").toString();
} }
if (!obj.value("S3").isNull()) {
config.m_cookieReplyPacketJunkSize = obj.value("S3").toString();
}
if (!obj.value("S4").isNull()) {
config.m_transportPacketJunkSize = obj.value("S4").toString();
}
if (!obj.value("H1").isNull()) { if (!obj.value("H1").isNull()) {
config.m_initPacketMagicHeader = obj.value("H1").toString(); config.m_initPacketMagicHeader = obj.value("H1").toString();
} }
@ -425,34 +404,6 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
config.m_transportPacketMagicHeader = obj.value("H4").toString(); config.m_transportPacketMagicHeader = obj.value("H4").toString();
} }
if (!obj.value("I1").isNull()) {
config.m_specialJunk["I1"] = obj.value("I1").toString();
}
if (!obj.value("I2").isNull()) {
config.m_specialJunk["I2"] = obj.value("I2").toString();
}
if (!obj.value("I3").isNull()) {
config.m_specialJunk["I3"] = obj.value("I3").toString();
}
if (!obj.value("I4").isNull()) {
config.m_specialJunk["I4"] = obj.value("I4").toString();
}
if (!obj.value("I5").isNull()) {
config.m_specialJunk["I5"] = obj.value("I5").toString();
}
if (!obj.value("J1").isNull()) {
config.m_controlledJunk["J1"] = obj.value("J1").toString();
}
if (!obj.value("J2").isNull()) {
config.m_controlledJunk["J2"] = obj.value("J2").toString();
}
if (!obj.value("J3").isNull()) {
config.m_controlledJunk["J3"] = obj.value("J3").toString();
}
if (!obj.value("Itime").isNull()) {
config.m_specialHandshakeTimeout = obj.value("Itime").toString();
}
return true; return true;
} }

View file

@ -28,8 +28,7 @@ QJsonObject InterfaceConfig::toJson() const {
(m_hopType == InterfaceConfig::SingleHop)) { (m_hopType == InterfaceConfig::SingleHop)) {
json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway)); json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway));
json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway)); json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway));
json.insert("primaryDnsServer", QJsonValue(m_primaryDnsServer)); json.insert("dnsServer", QJsonValue(m_dnsServer));
json.insert("secondaryDnsServer", QJsonValue(m_secondaryDnsServer));
} }
QJsonArray allowedIPAddesses; QJsonArray allowedIPAddesses;
@ -101,15 +100,11 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
out << "MTU = " << m_deviceMTU << "\n"; out << "MTU = " << m_deviceMTU << "\n";
} }
if (!m_primaryDnsServer.isNull()) { if (!m_dnsServer.isNull()) {
QStringList dnsServers; QStringList dnsServers(m_dnsServer);
dnsServers.append(m_primaryDnsServer);
if (!m_secondaryDnsServer.isNull()) {
dnsServers.append(m_secondaryDnsServer);
}
// If the DNS is not the Gateway, it's a user defined DNS // If the DNS is not the Gateway, it's a user defined DNS
// thus, not add any other :) // thus, not add any other :)
if (m_primaryDnsServer == m_serverIpv4Gateway) { if (m_dnsServer == m_serverIpv4Gateway) {
dnsServers.append(m_serverIpv6Gateway); dnsServers.append(m_serverIpv6Gateway);
} }
out << "DNS = " << dnsServers.join(", ") << "\n"; out << "DNS = " << dnsServers.join(", ") << "\n";
@ -130,12 +125,6 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
if (!m_responsePacketJunkSize.isNull()) { if (!m_responsePacketJunkSize.isNull()) {
out << "S2 = " << m_responsePacketJunkSize << "\n"; out << "S2 = " << m_responsePacketJunkSize << "\n";
} }
if (!m_cookieReplyPacketJunkSize.isNull()) {
out << "S3 = " << m_cookieReplyPacketJunkSize << "\n";
}
if (!m_transportPacketJunkSize.isNull()) {
out << "S4 = " << m_transportPacketJunkSize << "\n";
}
if (!m_initPacketMagicHeader.isNull()) { if (!m_initPacketMagicHeader.isNull()) {
out << "H1 = " << m_initPacketMagicHeader << "\n"; out << "H1 = " << m_initPacketMagicHeader << "\n";
} }
@ -149,16 +138,6 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
out << "H4 = " << m_transportPacketMagicHeader << "\n"; out << "H4 = " << m_transportPacketMagicHeader << "\n";
} }
for (const QString& key : m_specialJunk.keys()) {
out << key << " = " << m_specialJunk[key] << "\n";
}
for (const QString& key : m_controlledJunk.keys()) {
out << key << " = " << m_controlledJunk[key] << "\n";
}
if (!m_specialHandshakeTimeout.isNull()) {
out << "Itime = " << m_specialHandshakeTimeout << "\n";
}
// If any extra config was provided, append it now. // If any extra config was provided, append it now.
for (const QString& key : extra.keys()) { for (const QString& key : extra.keys()) {
out << key << " = " << extra[key] << "\n"; out << key << " = " << extra[key] << "\n";

View file

@ -32,8 +32,7 @@ class InterfaceConfig {
QString m_serverIpv4AddrIn; QString m_serverIpv4AddrIn;
QString m_serverPskKey; QString m_serverPskKey;
QString m_serverIpv6AddrIn; QString m_serverIpv6AddrIn;
QString m_primaryDnsServer; QString m_dnsServer;
QString m_secondaryDnsServer;
int m_serverPort = 0; int m_serverPort = 0;
int m_deviceMTU = 1420; int m_deviceMTU = 1420;
QList<IPAddress> m_allowedIPAddressRanges; QList<IPAddress> m_allowedIPAddressRanges;
@ -50,15 +49,10 @@ class InterfaceConfig {
QString m_junkPacketMaxSize; QString m_junkPacketMaxSize;
QString m_initPacketJunkSize; QString m_initPacketJunkSize;
QString m_responsePacketJunkSize; QString m_responsePacketJunkSize;
QString m_cookieReplyPacketJunkSize;
QString m_transportPacketJunkSize;
QString m_initPacketMagicHeader; QString m_initPacketMagicHeader;
QString m_responsePacketMagicHeader; QString m_responsePacketMagicHeader;
QString m_underloadPacketMagicHeader; QString m_underloadPacketMagicHeader;
QString m_transportPacketMagicHeader; QString m_transportPacketMagicHeader;
QMap<QString, QString> m_specialJunk;
QMap<QString, QString> m_controlledJunk;
QString m_specialHandshakeTimeout;
QJsonObject toJson() const; QJsonObject toJson() const;
QString toWgConf( QString toWgConf(

View file

@ -149,14 +149,7 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
json.insert("serverPort", wgConfig.value(amnezia::config_key::port).toInt()); json.insert("serverPort", wgConfig.value(amnezia::config_key::port).toInt());
json.insert("serverIpv4Gateway", wgConfig.value(amnezia::config_key::hostName)); json.insert("serverIpv4Gateway", wgConfig.value(amnezia::config_key::hostName));
// json.insert("serverIpv6Gateway", QJsonValue(hop.m_server.ipv6Gateway())); // json.insert("serverIpv6Gateway", QJsonValue(hop.m_server.ipv6Gateway()));
json.insert("dnsServer", rawConfig.value(amnezia::config_key::dns1));
json.insert("primaryDnsServer", rawConfig.value(amnezia::config_key::dns1));
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (!rawConfig.value(amnezia::config_key::dns1).toString().
contains(amnezia::protocols::dns::amneziaDnsIp)) {
json.insert("secondaryDnsServer", rawConfig.value(amnezia::config_key::dns2));
}
QJsonArray jsAllowedIPAddesses; QJsonArray jsAllowedIPAddesses;
@ -244,61 +237,28 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize)); json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize)); json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize)); json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize));
json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize));
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader)); json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader)); json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader)); json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader)); json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1));
json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2));
json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3));
json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4));
json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5));
json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1));
json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2));
json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3));
json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout));
} else if (!wgConfig.value(amnezia::config_key::junkPacketCount).isUndefined() } else if (!wgConfig.value(amnezia::config_key::junkPacketCount).isUndefined()
&& !wgConfig.value(amnezia::config_key::junkPacketMinSize).isUndefined() && !wgConfig.value(amnezia::config_key::junkPacketMinSize).isUndefined()
&& !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined() && !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined()
&& !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined() && !wgConfig.value(amnezia::config_key::initPacketJunkSize).isUndefined()
&& !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined() && !wgConfig.value(amnezia::config_key::responsePacketJunkSize).isUndefined()
&& !wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize).isUndefined()
&& !wgConfig.value(amnezia::config_key::transportPacketJunkSize).isUndefined()
&& !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined() && !wgConfig.value(amnezia::config_key::initPacketMagicHeader).isUndefined()
&& !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined() && !wgConfig.value(amnezia::config_key::responsePacketMagicHeader).isUndefined()
&& !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined() && !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined()
&& !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined() && !wgConfig.value(amnezia::config_key::transportPacketMagicHeader).isUndefined()) {
&& !wgConfig.value(amnezia::config_key::specialJunk1).isUndefined()
&& !wgConfig.value(amnezia::config_key::specialJunk2).isUndefined()
&& !wgConfig.value(amnezia::config_key::specialJunk3).isUndefined()
&& !wgConfig.value(amnezia::config_key::specialJunk4).isUndefined()
&& !wgConfig.value(amnezia::config_key::specialJunk5).isUndefined()
&& !wgConfig.value(amnezia::config_key::controlledJunk1).isUndefined()
&& !wgConfig.value(amnezia::config_key::controlledJunk2).isUndefined()
&& !wgConfig.value(amnezia::config_key::controlledJunk3).isUndefined()
&& !wgConfig.value(amnezia::config_key::specialHandshakeTimeout).isUndefined()) {
json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount)); json.insert(amnezia::config_key::junkPacketCount, wgConfig.value(amnezia::config_key::junkPacketCount));
json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize)); json.insert(amnezia::config_key::junkPacketMinSize, wgConfig.value(amnezia::config_key::junkPacketMinSize));
json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize)); json.insert(amnezia::config_key::junkPacketMaxSize, wgConfig.value(amnezia::config_key::junkPacketMaxSize));
json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize)); json.insert(amnezia::config_key::initPacketJunkSize, wgConfig.value(amnezia::config_key::initPacketJunkSize));
json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize)); json.insert(amnezia::config_key::responsePacketJunkSize, wgConfig.value(amnezia::config_key::responsePacketJunkSize));
json.insert(amnezia::config_key::cookieReplyPacketJunkSize, wgConfig.value(amnezia::config_key::cookieReplyPacketJunkSize));
json.insert(amnezia::config_key::transportPacketJunkSize, wgConfig.value(amnezia::config_key::transportPacketJunkSize));
json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader)); json.insert(amnezia::config_key::initPacketMagicHeader, wgConfig.value(amnezia::config_key::initPacketMagicHeader));
json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader)); json.insert(amnezia::config_key::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader)); json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader)); json.insert(amnezia::config_key::transportPacketMagicHeader, wgConfig.value(amnezia::config_key::transportPacketMagicHeader));
json.insert(amnezia::config_key::specialJunk1, wgConfig.value(amnezia::config_key::specialJunk1));
json.insert(amnezia::config_key::specialJunk2, wgConfig.value(amnezia::config_key::specialJunk2));
json.insert(amnezia::config_key::specialJunk3, wgConfig.value(amnezia::config_key::specialJunk3));
json.insert(amnezia::config_key::specialJunk4, wgConfig.value(amnezia::config_key::specialJunk4));
json.insert(amnezia::config_key::specialJunk5, wgConfig.value(amnezia::config_key::specialJunk5));
json.insert(amnezia::config_key::controlledJunk1, wgConfig.value(amnezia::config_key::controlledJunk1));
json.insert(amnezia::config_key::controlledJunk2, wgConfig.value(amnezia::config_key::controlledJunk2));
json.insert(amnezia::config_key::controlledJunk3, wgConfig.value(amnezia::config_key::controlledJunk3));
json.insert(amnezia::config_key::specialHandshakeTimeout, wgConfig.value(amnezia::config_key::specialHandshakeTimeout));
} }
write(json); write(json);

View file

@ -4,10 +4,7 @@ struct WGConfig: Decodable {
let initPacketMagicHeader, responsePacketMagicHeader: String? let initPacketMagicHeader, responsePacketMagicHeader: String?
let underloadPacketMagicHeader, transportPacketMagicHeader: String? let underloadPacketMagicHeader, transportPacketMagicHeader: String?
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String? let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
let initPacketJunkSize, responsePacketJunkSize, cookieReplyPacketJunkSize, transportPacketJunkSize: String? let initPacketJunkSize, responsePacketJunkSize: String?
let specialJunk1, specialJunk2, specialJunk3, specialJunk4, specialJunk5: String?
let controlledJunk1, controlledJunk2, controlledJunk3: String?
let specialHandshakeTimeout: String?
let dns1: String let dns1: String
let dns2: String let dns2: String
let mtu: String let mtu: String
@ -26,10 +23,7 @@ struct WGConfig: Decodable {
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2" case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4" case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax" case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2", cookieReplyPacketJunkSize = "S3", transportPacketJunkSize = "S4" case initPacketJunkSize = "S1", responsePacketJunkSize = "S2"
case specialJunk1 = "I1", specialJunk2 = "I2", specialJunk3 = "I3", specialJunk4 = "I4", specialJunk5 = "I5"
case controlledJunk1 = "J1", controlledJunk2 = "J2", controlledJunk3 = "J3"
case specialHandshakeTimeout = "Itime"
case dns1 case dns1
case dns2 case dns2
case mtu case mtu
@ -46,59 +40,19 @@ struct WGConfig: Decodable {
} }
var settings: String { var settings: String {
guard junkPacketCount != nil else { return "" } junkPacketCount == nil ? "" :
"""
Jc = \(junkPacketCount!)
Jmin = \(junkPacketMinSize!)
Jmax = \(junkPacketMaxSize!)
S1 = \(initPacketJunkSize!)
S2 = \(responsePacketJunkSize!)
H1 = \(initPacketMagicHeader!)
H2 = \(responsePacketMagicHeader!)
H3 = \(underloadPacketMagicHeader!)
H4 = \(transportPacketMagicHeader!)
var settingsLines: [String] = [] """
// Required parameters when junkPacketCount is present
settingsLines.append("Jc = \(junkPacketCount!)")
settingsLines.append("Jmin = \(junkPacketMinSize!)")
settingsLines.append("Jmax = \(junkPacketMaxSize!)")
settingsLines.append("S1 = \(initPacketJunkSize!)")
settingsLines.append("S2 = \(responsePacketJunkSize!)")
settingsLines.append("H1 = \(initPacketMagicHeader!)")
settingsLines.append("H2 = \(responsePacketMagicHeader!)")
settingsLines.append("H3 = \(underloadPacketMagicHeader!)")
settingsLines.append("H4 = \(transportPacketMagicHeader!)")
// Optional parameters - only add if not nil and not empty
if let s3 = cookieReplyPacketJunkSize, !s3.isEmpty {
settingsLines.append("S3 = \(s3)")
}
if let s4 = transportPacketJunkSize, !s4.isEmpty {
settingsLines.append("S4 = \(s4)")
}
if let i1 = specialJunk1, !i1.isEmpty {
settingsLines.append("I1 = \(i1)")
}
if let i2 = specialJunk2, !i2.isEmpty {
settingsLines.append("I2 = \(i2)")
}
if let i3 = specialJunk3, !i3.isEmpty {
settingsLines.append("I3 = \(i3)")
}
if let i4 = specialJunk4, !i4.isEmpty {
settingsLines.append("I4 = \(i4)")
}
if let i5 = specialJunk5, !i5.isEmpty {
settingsLines.append("I5 = \(i5)")
}
if let j1 = controlledJunk1, !j1.isEmpty {
settingsLines.append("J1 = \(j1)")
}
if let j2 = controlledJunk2, !j2.isEmpty {
settingsLines.append("J2 = \(j2)")
}
if let j3 = controlledJunk3, !j3.isEmpty {
settingsLines.append("J3 = \(j3)")
}
if let itime = specialHandshakeTimeout, !itime.isEmpty {
settingsLines.append("Itime = \(itime)")
}
return settingsLines.joined(separator: "\n")
} }
var str: String { var str: String {

View file

@ -507,8 +507,6 @@ bool IosController::setupWireGuard()
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]); wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]); wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]); wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]); wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
@ -607,23 +605,11 @@ bool IosController::setupAwg()
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]); wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]); wgConfig.insert(config_key::responsePacketJunkSize, config[config_key::responsePacketJunkSize]);
wgConfig.insert(config_key::cookieReplyPacketJunkSize, config[config_key::cookieReplyPacketJunkSize]);
wgConfig.insert(config_key::transportPacketJunkSize, config[config_key::transportPacketJunkSize]);
wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]); wgConfig.insert(config_key::junkPacketCount, config[config_key::junkPacketCount]);
wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]); wgConfig.insert(config_key::junkPacketMinSize, config[config_key::junkPacketMinSize]);
wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]); wgConfig.insert(config_key::junkPacketMaxSize, config[config_key::junkPacketMaxSize]);
wgConfig.insert(config_key::specialJunk1, config[config_key::specialJunk1]);
wgConfig.insert(config_key::specialJunk2, config[config_key::specialJunk2]);
wgConfig.insert(config_key::specialJunk3, config[config_key::specialJunk3]);
wgConfig.insert(config_key::specialJunk4, config[config_key::specialJunk4]);
wgConfig.insert(config_key::specialJunk5, config[config_key::specialJunk5]);
wgConfig.insert(config_key::controlledJunk1, config[config_key::controlledJunk1]);
wgConfig.insert(config_key::controlledJunk2, config[config_key::controlledJunk2]);
wgConfig.insert(config_key::controlledJunk3, config[config_key::controlledJunk3]);
wgConfig.insert(config_key::specialHandshakeTimeout, config[config_key::specialHandshakeTimeout]);
QJsonDocument wgConfigDoc(wgConfig); QJsonDocument wgConfigDoc(wgConfig);
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact)); QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));

View file

@ -121,12 +121,6 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
if (!config.m_responsePacketJunkSize.isEmpty()) { if (!config.m_responsePacketJunkSize.isEmpty()) {
out << "s2=" << config.m_responsePacketJunkSize << "\n"; out << "s2=" << config.m_responsePacketJunkSize << "\n";
} }
if (!config.m_cookieReplyPacketJunkSize.isEmpty()) {
out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n";
}
if (!config.m_transportPacketJunkSize.isEmpty()) {
out << "s4=" << config.m_transportPacketJunkSize << "\n";
}
if (!config.m_initPacketMagicHeader.isEmpty()) { if (!config.m_initPacketMagicHeader.isEmpty()) {
out << "h1=" << config.m_initPacketMagicHeader << "\n"; out << "h1=" << config.m_initPacketMagicHeader << "\n";
} }
@ -140,26 +134,13 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
out << "h4=" << config.m_transportPacketMagicHeader << "\n"; out << "h4=" << config.m_transportPacketMagicHeader << "\n";
} }
for (const QString& key : config.m_specialJunk.keys()) {
out << key.toLower() << "=" << config.m_specialJunk.value(key) << "\n";
}
for (const QString& key : config.m_controlledJunk.keys()) {
out << key.toLower() << "=" << config.m_controlledJunk.value(key) << "\n";
}
if (!config.m_specialHandshakeTimeout.isEmpty()) {
out << "itime=" << config.m_specialHandshakeTimeout << "\n";
}
int err = uapiErrno(uapiCommand(message)); int err = uapiErrno(uapiCommand(message));
if (err != 0) { if (err != 0) {
logger.error() << "Interface configuration failed:" << strerror(err); logger.error() << "Interface configuration failed:" << strerror(err);
} else { } else {
if (config.m_killSwitchEnabled) { if (config.m_killSwitchEnabled) {
FirewallParams params { }; FirewallParams params { };
params.dnsServers.append(config.m_primaryDnsServer); params.dnsServers.append(config.m_dnsServer);
if (!config.m_secondaryDnsServer.isEmpty()) {
params.dnsServers.append(config.m_secondaryDnsServer);
}
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
params.blockAll = true; params.blockAll = true;
if (config.m_excludedAddresses.size()) { if (config.m_excludedAddresses.size()) {

View file

@ -43,16 +43,8 @@ namespace {
#include "macosfirewall.h" #include "macosfirewall.h"
#include <QDir> #define ResourceDir qApp->applicationDirPath() + "/pf"
#include <QStandardPaths> #define DaemonDataDir qApp->applicationDirPath() + "/pf"
// Read-only rules bundled with the application.
#define ResourceDir (qApp->applicationDirPath() + "/pf")
// Writable location that does NOT live inside the signed bundle. Using a
// constant path under /Library/Application Support keeps the signature intact
// and is accessible to the root helper.
#define DaemonDataDir QStringLiteral("/Library/Application Support/AmneziaVPN/pf")
#include <QProcess> #include <QProcess>
@ -129,8 +121,6 @@ void MacOSFirewall::install()
logger.info() << "Installing PF root anchor"; logger.info() << "Installing PF root anchor";
installRootAnchors(); installRootAnchors();
// Ensure writable directory exists, then store the token there.
QDir().mkpath(DaemonDataDir);
execute(QStringLiteral("pfctl -E 2>&1 | grep -F 'Token : ' | cut -c9- > '%1/pf.token'").arg(DaemonDataDir)); execute(QStringLiteral("pfctl -E 2>&1 | grep -F 'Token : ' | cut -c9- > '%1/pf.token'").arg(DaemonDataDir));
} }

View file

@ -119,12 +119,6 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
if (!config.m_responsePacketJunkSize.isEmpty()) { if (!config.m_responsePacketJunkSize.isEmpty()) {
out << "s2=" << config.m_responsePacketJunkSize << "\n"; out << "s2=" << config.m_responsePacketJunkSize << "\n";
} }
if (!config.m_cookieReplyPacketJunkSize.isEmpty()) {
out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n";
}
if (!config.m_transportPacketJunkSize.isEmpty()) {
out << "s4=" << config.m_transportPacketJunkSize << "\n";
}
if (!config.m_initPacketMagicHeader.isEmpty()) { if (!config.m_initPacketMagicHeader.isEmpty()) {
out << "h1=" << config.m_initPacketMagicHeader << "\n"; out << "h1=" << config.m_initPacketMagicHeader << "\n";
} }
@ -138,43 +132,30 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
out << "h4=" << config.m_transportPacketMagicHeader << "\n"; out << "h4=" << config.m_transportPacketMagicHeader << "\n";
} }
for (const QString& key : config.m_specialJunk.keys()) {
out << key.toLower() << "=" << config.m_specialJunk.value(key) << "\n";
}
for (const QString& key : config.m_controlledJunk.keys()) {
out << key.toLower() << "=" << config.m_controlledJunk.value(key) << "\n";
}
if (!config.m_specialHandshakeTimeout.isEmpty()) {
out << "itime=" << config.m_specialHandshakeTimeout << "\n";
}
int err = uapiErrno(uapiCommand(message)); int err = uapiErrno(uapiCommand(message));
if (err != 0) { if (err != 0) {
logger.error() << "Interface configuration failed:" << strerror(err); logger.error() << "Interface configuration failed:" << strerror(err);
} else { } else {
if (config.m_killSwitchEnabled) { if (config.m_killSwitchEnabled) {
FirewallParams params { }; FirewallParams params { };
params.dnsServers.append(config.m_primaryDnsServer); params.dnsServers.append(config.m_dnsServer);
if (!config.m_secondaryDnsServer.isEmpty()) {
params.dnsServers.append(config.m_secondaryDnsServer);
}
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
params.blockAll = true; params.blockAll = true;
if (config.m_excludedAddresses.size()) { if (config.m_excludedAddresses.size()) {
params.allowNets = true; params.allowNets = true;
foreach (auto net, config.m_excludedAddresses) { foreach (auto net, config.m_excludedAddresses) {
params.allowAddrs.append(net.toUtf8()); params.allowAddrs.append(net.toUtf8());
} }
} }
} else { } else {
params.blockNets = true; params.blockNets = true;
foreach (auto net, config.m_allowedIPAddressRanges) { foreach (auto net, config.m_allowedIPAddressRanges) {
params.blockAddrs.append(net.toString()); params.blockAddrs.append(net.toString());
} }
}
applyFirewallRules(params);
} }
applyFirewallRules(params);
}
} }
return (err == 0); return (err == 0);
} }

View file

@ -291,32 +291,15 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
"Block Internet", config.m_serverPublicKey)) { "Block Internet", config.m_serverPublicKey)) {
return false; return false;
} }
if (!config.m_primaryDnsServer.isEmpty()) { if (!config.m_dnsServer.isEmpty()) {
if (!allowTrafficTo(QHostAddress(config.m_primaryDnsServer), 53, HIGH_WEIGHT, if (!allowTrafficTo(QHostAddress(config.m_dnsServer), 53, HIGH_WEIGHT,
"Allow DNS-Server", config.m_serverPublicKey)) { "Allow DNS-Server", config.m_serverPublicKey)) {
return false; return false;
} }
// In some cases, we might configure a 2nd DNS server for IPv6, however // In some cases, we might configure a 2nd DNS server for IPv6, however
// this should probably be cleaned up by converting m_dnsServer into // this should probably be cleaned up by converting m_dnsServer into
// a QStringList instead. // a QStringList instead.
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) { if (config.m_dnsServer == config.m_serverIpv4Gateway) {
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
config.m_serverPublicKey)) {
return false;
}
}
}
if (!config.m_secondaryDnsServer.isEmpty()) {
if (!allowTrafficTo(QHostAddress(config.m_secondaryDnsServer), 53, HIGH_WEIGHT,
"Allow DNS-Server", config.m_serverPublicKey)) {
return false;
}
// In some cases, we might configure a 2nd DNS server for IPv6, however
// this should probably be cleaned up by converting m_dnsServer into
// a QStringList instead.
if (config.m_secondaryDnsServer == config.m_serverIpv4Gateway) {
if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53, if (!allowTrafficTo(QHostAddress(config.m_serverIpv6Gateway), 53,
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server", HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
config.m_serverPublicKey)) { config.m_serverPublicKey)) {

View file

@ -130,7 +130,6 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) {
// Enable the windows firewall // Enable the windows firewall
NET_IFINDEX ifindex; NET_IFINDEX ifindex;
ConvertInterfaceLuidToIndex(&luid, &ifindex); ConvertInterfaceLuidToIndex(&luid, &ifindex);
m_firewall->allowAllTraffic();
m_firewall->enableInterface(ifindex); m_firewall->enableInterface(ifindex);
} }

View file

@ -343,7 +343,7 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
// killSwitch toggle // killSwitch toggle
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index()); IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
} }
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway); m_configData.insert("vpnGateway", m_vpnGateway);

View file

@ -72,21 +72,10 @@ namespace amnezia
constexpr char junkPacketMaxSize[] = "Jmax"; constexpr char junkPacketMaxSize[] = "Jmax";
constexpr char initPacketJunkSize[] = "S1"; constexpr char initPacketJunkSize[] = "S1";
constexpr char responsePacketJunkSize[] = "S2"; constexpr char responsePacketJunkSize[] = "S2";
constexpr char cookieReplyPacketJunkSize[] = "S3";
constexpr char transportPacketJunkSize[] = "S4";
constexpr char initPacketMagicHeader[] = "H1"; constexpr char initPacketMagicHeader[] = "H1";
constexpr char responsePacketMagicHeader[] = "H2"; constexpr char responsePacketMagicHeader[] = "H2";
constexpr char underloadPacketMagicHeader[] = "H3"; constexpr char underloadPacketMagicHeader[] = "H3";
constexpr char transportPacketMagicHeader[] = "H4"; constexpr char transportPacketMagicHeader[] = "H4";
constexpr char specialJunk1[] = "I1";
constexpr char specialJunk2[] = "I2";
constexpr char specialJunk3[] = "I3";
constexpr char specialJunk4[] = "I4";
constexpr char specialJunk5[] = "I5";
constexpr char controlledJunk1[] = "J1";
constexpr char controlledJunk2[] = "J2";
constexpr char controlledJunk3[] = "J3";
constexpr char specialHandshakeTimeout[] = "Itime";
constexpr char openvpn[] = "openvpn"; constexpr char openvpn[] = "openvpn";
constexpr char wireguard[] = "wireguard"; constexpr char wireguard[] = "wireguard";
@ -227,22 +216,10 @@ namespace amnezia
constexpr char defaultJunkPacketMaxSize[] = "30"; constexpr char defaultJunkPacketMaxSize[] = "30";
constexpr char defaultInitPacketJunkSize[] = "15"; constexpr char defaultInitPacketJunkSize[] = "15";
constexpr char defaultResponsePacketJunkSize[] = "18"; constexpr char defaultResponsePacketJunkSize[] = "18";
constexpr char defaultCookieReplyPacketJunkSize[] = "20";
constexpr char defaultTransportPacketJunkSize[] = "23";
constexpr char defaultInitPacketMagicHeader[] = "1020325451"; constexpr char defaultInitPacketMagicHeader[] = "1020325451";
constexpr char defaultResponsePacketMagicHeader[] = "3288052141"; constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
constexpr char defaultTransportPacketMagicHeader[] = "2528465083"; constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858"; constexpr char defaultUnderloadPacketMagicHeader[] = "1766607858";
constexpr char defaultSpecialJunk1[] = "";
constexpr char defaultSpecialJunk2[] = "";
constexpr char defaultSpecialJunk3[] = "";
constexpr char defaultSpecialJunk4[] = "";
constexpr char defaultSpecialJunk5[] = "";
constexpr char defaultControlledJunk1[] = "";
constexpr char defaultControlledJunk2[] = "";
constexpr char defaultControlledJunk3[] = "";
constexpr char defaultSpecialHandshakeTimeout[] = "";
} }
namespace socks5Proxy namespace socks5Proxy

View file

@ -98,13 +98,8 @@ ErrorCode XrayProtocol::startTun2Sock()
if (vpnState == Vpn::ConnectionState::Connected) { if (vpnState == Vpn::ConnectionState::Connected) {
setConnectionState(Vpn::ConnectionState::Connecting); setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr; QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString())); dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
// We don't use secondary DNS if primary DNS is AmneziaDNS dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
if (!m_configData.value(amnezia::config_key::dns1).toString().
contains(amnezia::protocols::dns::amneziaDnsIp)) {
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QThread::msleep(8000); QThread::msleep(8000);
#endif #endif
@ -139,7 +134,7 @@ ErrorCode XrayProtocol::startTun2Sock()
// killSwitch toggle // killSwitch toggle
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index()); IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
} }
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index()); m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway); m_configData.insert("vpnGateway", m_vpnGateway);

View file

@ -239,7 +239,6 @@
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file> <file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file> <file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
<file>ui/qml/Components/OtpCodeDrawer.qml</file> <file>ui/qml/Components/OtpCodeDrawer.qml</file>
<file>ui/qml/Components/AwgTextField.qml</file>
</qresource> </qresource>
<qresource prefix="/countriesFlags"> <qresource prefix="/countriesFlags">
<file>images/flagKit/ZW.svg</file> <file>images/flagKit/ZW.svg</file>

View file

@ -44,4 +44,3 @@ RUN echo -e " \n\
ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ] ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]
CMD [ "" ] CMD [ "" ]

View file

@ -23,5 +23,4 @@ H1 = $INIT_PACKET_MAGIC_HEADER
H2 = $RESPONSE_PACKET_MAGIC_HEADER H2 = $RESPONSE_PACKET_MAGIC_HEADER
H3 = $UNDERLOAD_PACKET_MAGIC_HEADER H3 = $UNDERLOAD_PACKET_MAGIC_HEADER
H4 = $TRANSPORT_PACKET_MAGIC_HEADER H4 = $TRANSPORT_PACKET_MAGIC_HEADER
EOF EOF

View file

@ -1,7 +1,6 @@
if which apt-get > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/dpkg/lock-frontend";\ if which apt-get > /dev/null 2>&1; then LOCK_FILE="/var/lib/dpkg/lock-frontend";\
elif which dnf > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/cache/dnf/* /var/run/dnf/* /var/lib/dnf/* /var/lib/rpm/*";\ elif which dnf > /dev/null 2>&1; then LOCK_FILE="/var/run/dnf.pid";\
elif which yum > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/yum.pid";\ elif which yum > /dev/null 2>&1; then LOCK_FILE="/var/run/yum.pid";\
elif which zypper > /dev/null 2>&1; then LOCK_CMD="cat"; LOCK_FILE="/var/run/zypp.pid";\ elif which pacman > /dev/null 2>&1; then LOCK_FILE="/var/lib/pacman/db.lck";\
elif which pacman > /dev/null 2>&1; then LOCK_CMD="fuser"; LOCK_FILE="/var/lib/pacman/db.lck";\
else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\ else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\
if command -v $LOCK_CMD > /dev/null 2>&1; then sudo $LOCK_CMD $LOCK_FILE 2>/dev/null; else echo "$LOCK_CMD not installed"; fi if command -v fuser > /dev/null 2>&1; then sudo fuser $LOCK_FILE 2>/dev/null; else echo "fuser not installed"; fi

View file

@ -1,7 +1,6 @@
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\ if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\ elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\ elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); opt="--version";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\ elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
else pm="uname"; opt="-a";\ else pm="uname"; opt="-a";\
fi;\ fi;\

View file

@ -1,7 +1,6 @@
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\ if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian";\
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\ elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora";\
elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\ elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos";\
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="opensuse";\
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\ elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux";\
else echo "Packet manager not found"; exit 1; fi;\ else echo "Packet manager not found"; exit 1; fi;\
echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\ echo "Dist: $dist, Packet manager: $pm, Install command: $silent_inst, Check pkgs command: $check_pkgs, Docker pkg: $docker_pkg";\

View file

@ -18,7 +18,6 @@ namespace
{ {
constexpr char cloak[] = "cloak"; constexpr char cloak[] = "cloak";
constexpr char awg[] = "awg"; constexpr char awg[] = "awg";
constexpr char vless[] = "vless";
constexpr char apiEndpoint[] = "api_endpoint"; constexpr char apiEndpoint[] = "api_endpoint";
constexpr char accessToken[] = "api_key"; constexpr char accessToken[] = "api_key";
@ -36,6 +35,10 @@ namespace
constexpr char serviceInfo[] = "service_info"; constexpr char serviceInfo[] = "service_info";
constexpr char serviceProtocol[] = "service_protocol"; constexpr char serviceProtocol[] = "service_protocol";
constexpr char aesKey[] = "aes_key";
constexpr char aesIv[] = "aes_iv";
constexpr char aesSalt[] = "aes_salt";
constexpr char apiPayload[] = "api_payload"; constexpr char apiPayload[] = "api_payload";
constexpr char keyPayload[] = "key_payload"; constexpr char keyPayload[] = "key_payload";
@ -44,185 +47,6 @@ namespace
constexpr char config[] = "config"; constexpr char config[] = "config";
} }
struct ProtocolData
{
OpenVpnConfigurator::ConnectionData certRequest;
QString wireGuardClientPrivKey;
QString wireGuardClientPubKey;
QString xrayUuid;
};
struct GatewayRequestData
{
QString osVersion;
QString appVersion;
QString installationUuid;
QString userCountryCode;
QString serverCountryCode;
QString serviceType;
QString serviceProtocol;
QJsonObject authData;
QJsonObject toJsonObject() const
{
QJsonObject obj;
if (!osVersion.isEmpty()) {
obj[configKey::osVersion] = osVersion;
}
if (!appVersion.isEmpty()) {
obj[configKey::appVersion] = appVersion;
}
if (!installationUuid.isEmpty()) {
obj[configKey::uuid] = installationUuid;
}
if (!userCountryCode.isEmpty()) {
obj[configKey::userCountryCode] = userCountryCode;
}
if (!serverCountryCode.isEmpty()) {
obj[configKey::serverCountryCode] = serverCountryCode;
}
if (!serviceType.isEmpty()) {
obj[configKey::serviceType] = serviceType;
}
if (!serviceProtocol.isEmpty()) {
obj[configKey::serviceProtocol] = serviceProtocol;
}
if (!authData.isEmpty()) {
obj[configKey::authData] = authData;
}
return obj;
}
};
ProtocolData generateProtocolData(const QString &protocol)
{
ProtocolData protocolData;
if (protocol == configKey::cloak) {
protocolData.certRequest = OpenVpnConfigurator::createCertRequest();
} else if (protocol == configKey::awg) {
auto connData = WireguardConfigurator::genClientKeys();
protocolData.wireGuardClientPubKey = connData.clientPubKey;
protocolData.wireGuardClientPrivKey = connData.clientPrivKey;
} else if (protocol == configKey::vless) {
protocolData.xrayUuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
}
return protocolData;
}
void appendProtocolDataToApiPayload(const QString &protocol, const ProtocolData &protocolData, QJsonObject &apiPayload)
{
if (protocol == configKey::cloak) {
apiPayload[configKey::certificate] = protocolData.certRequest.request;
} else if (protocol == configKey::awg) {
apiPayload[configKey::publicKey] = protocolData.wireGuardClientPubKey;
} else if (protocol == configKey::vless) {
apiPayload[configKey::publicKey] = protocolData.xrayUuid;
}
}
ErrorCode fillServerConfig(const QString &protocol, const ProtocolData &apiPayloadData, const QByteArray &apiResponseBody,
QJsonObject &serverConfig)
{
QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString();
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
qDebug() << "empty vpn key";
return ErrorCode::ApiConfigEmptyError;
}
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QString configStr = ba;
if (protocol == configKey::cloak) {
configStr.replace("<key>", "<key>\n");
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
} else if (protocol == configKey::awg) {
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
auto containers = newServerConfig.value(config_key::containers).toArray();
if (containers.isEmpty()) {
qDebug() << "missing containers field";
return ErrorCode::ApiConfigEmptyError;
}
auto container = containers.at(0).toObject();
QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
auto serverProtocolConfig = container.value(containerName).toObject();
auto clientProtocolConfig =
QJsonDocument::fromJson(serverProtocolConfig.value(config_key::last_config).toString().toUtf8()).object();
//TODO looks like this block can be removed after v1 configs EOL
serverProtocolConfig[config_key::junkPacketCount] = clientProtocolConfig.value(config_key::junkPacketCount);
serverProtocolConfig[config_key::junkPacketMinSize] = clientProtocolConfig.value(config_key::junkPacketMinSize);
serverProtocolConfig[config_key::junkPacketMaxSize] = clientProtocolConfig.value(config_key::junkPacketMaxSize);
serverProtocolConfig[config_key::initPacketJunkSize] = clientProtocolConfig.value(config_key::initPacketJunkSize);
serverProtocolConfig[config_key::responsePacketJunkSize] = clientProtocolConfig.value(config_key::responsePacketJunkSize);
serverProtocolConfig[config_key::initPacketMagicHeader] = clientProtocolConfig.value(config_key::initPacketMagicHeader);
serverProtocolConfig[config_key::responsePacketMagicHeader] = clientProtocolConfig.value(config_key::responsePacketMagicHeader);
serverProtocolConfig[config_key::underloadPacketMagicHeader] = clientProtocolConfig.value(config_key::underloadPacketMagicHeader);
serverProtocolConfig[config_key::transportPacketMagicHeader] = clientProtocolConfig.value(config_key::transportPacketMagicHeader);
serverProtocolConfig[config_key::cookieReplyPacketJunkSize] = clientProtocolConfig.value(config_key::cookieReplyPacketJunkSize);
serverProtocolConfig[config_key::transportPacketJunkSize] = clientProtocolConfig.value(config_key::transportPacketJunkSize);
serverProtocolConfig[config_key::specialJunk1] = clientProtocolConfig.value(config_key::specialJunk1);
serverProtocolConfig[config_key::specialJunk2] = clientProtocolConfig.value(config_key::specialJunk2);
serverProtocolConfig[config_key::specialJunk3] = clientProtocolConfig.value(config_key::specialJunk3);
serverProtocolConfig[config_key::specialJunk4] = clientProtocolConfig.value(config_key::specialJunk4);
serverProtocolConfig[config_key::specialJunk5] = clientProtocolConfig.value(config_key::specialJunk5);
serverProtocolConfig[config_key::controlledJunk1] = clientProtocolConfig.value(config_key::controlledJunk1);
serverProtocolConfig[config_key::controlledJunk2] = clientProtocolConfig.value(config_key::controlledJunk2);
serverProtocolConfig[config_key::controlledJunk3] = clientProtocolConfig.value(config_key::controlledJunk3);
serverProtocolConfig[config_key::specialHandshakeTimeout] = clientProtocolConfig.value(config_key::specialHandshakeTimeout);
//
container[containerName] = serverProtocolConfig;
containers.replace(0, container);
newServerConfig[config_key::containers] = containers;
configStr = QString(QJsonDocument(newServerConfig).toJson());
}
QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
serverConfig[config_key::description] = newServerConfig.value(config_key::description);
serverConfig[config_key::name] = newServerConfig.value(config_key::name);
}
auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
serverConfig[config_key::defaultContainer] = defaultContainer;
QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
auto apiConfig = QJsonObject::fromVariantMap(map);
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
apiConfig.insert(apiDefs::key::supportedProtocols,
QJsonDocument::fromJson(apiResponseBody).object().value(apiDefs::key::supportedProtocols).toArray());
}
serverConfig[configKey::apiConfig] = apiConfig;
return ErrorCode::NoError;
}
} }
ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &serversModel, ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &serversModel,
@ -239,26 +63,24 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
return false; return false;
} }
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex()); auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
QString(APP_VERSION),
m_settings->getInstallationUuid(true),
apiConfigObject.value(configKey::userCountryCode).toString(),
serverCountryCode,
apiConfigObject.value(configKey::serviceType).toString(),
m_apiServicesModel->getSelectedServiceProtocol(),
serverConfigObject.value(configKey::authData).toObject() };
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString(); QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
ProtocolData protocolData = generateProtocolData(protocol); ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
QJsonObject apiPayload = gatewayRequestData.toJsonObject(); QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload); apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
apiPayload[configKey::serverCountryCode] = serverCountryCode;
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/native_config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/native_config"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode); emit errorOccurred(errorCode);
return false; return false;
@ -266,7 +88,7 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object(); QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object();
QString nativeConfig = jsonConfig.value(configKey::config).toString(); QString nativeConfig = jsonConfig.value(configKey::config).toString();
nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", protocolData.wireGuardClientPrivKey); nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
SystemController::saveFile(fileName, nativeConfig); SystemController::saveFile(fileName, nativeConfig);
return true; return true;
@ -274,22 +96,24 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode) bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
{ {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex()); auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
QString(APP_VERSION), ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
m_settings->getInstallationUuid(true),
apiConfigObject.value(configKey::userCountryCode).toString(),
serverCountryCode,
apiConfigObject.value(configKey::serviceType).toString(),
m_apiServicesModel->getSelectedServiceProtocol(),
serverConfigObject.value(configKey::authData).toObject() };
QJsonObject apiPayload = gatewayRequestData.toJsonObject(); QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
apiPayload[configKey::serverCountryCode] = serverCountryCode;
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_native_config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_native_config"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) { if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
emit errorOccurred(errorCode); emit errorOccurred(errorCode);
return false; return false;
@ -320,11 +144,14 @@ void ApiConfigsController::copyVpnKeyToClipboard()
bool ApiConfigsController::fillAvailableServices() bool ApiConfigsController::fillAvailableServices()
{ {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload; QJsonObject apiPayload;
apiPayload[configKey::osVersion] = QSysInfo::productType(); apiPayload[configKey::osVersion] = QSysInfo::productType();
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/services"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
if (!responseBody.contains("services")) { if (!responseBody.contains("services")) {
errorCode = ErrorCode::ApiServicesMissingError; errorCode = ErrorCode::ApiServicesMissingError;
@ -343,36 +170,34 @@ bool ApiConfigsController::fillAvailableServices()
bool ApiConfigsController::importServiceFromGateway() bool ApiConfigsController::importServiceFromGateway()
{ {
GatewayRequestData gatewayRequestData { QSysInfo::productType(), if (m_serversModel->isServerFromApiAlreadyExists(m_apiServicesModel->getCountryCode(), m_apiServicesModel->getSelectedServiceType(),
QString(APP_VERSION), m_apiServicesModel->getSelectedServiceProtocol())) {
m_settings->getInstallationUuid(true),
m_apiServicesModel->getCountryCode(),
"",
m_apiServicesModel->getSelectedServiceType(),
m_apiServicesModel->getSelectedServiceProtocol(),
QJsonObject() };
if (m_serversModel->isServerFromApiAlreadyExists(gatewayRequestData.userCountryCode, gatewayRequestData.serviceType,
gatewayRequestData.serviceProtocol)) {
emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded); emit errorOccurred(ErrorCode::ApiConfigAlreadyAdded);
return false; return false;
} }
ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol); GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
QJsonObject apiPayload = gatewayRequestData.toJsonObject(); auto installationUuid = m_settings->getInstallationUuid(true);
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload); auto userCountryCode = m_apiServicesModel->getCountryCode();
auto serviceType = m_apiServicesModel->getSelectedServiceType();
auto serviceProtocol = m_apiServicesModel->getSelectedServiceProtocol();
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::uuid] = installationUuid;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
QJsonObject serverConfig; QJsonObject serverConfig;
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, serverConfig); fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject(); QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject();
apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode()); apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode());
@ -393,33 +218,39 @@ bool ApiConfigsController::importServiceFromGateway()
bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName, bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
bool reloadServiceConfig) bool reloadServiceConfig)
{ {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
auto serverConfig = m_serversModel->getServerConfig(serverIndex); auto serverConfig = m_serversModel->getServerConfig(serverIndex);
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject(); auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
auto authData = serverConfig.value(configKey::authData).toObject();
GatewayRequestData gatewayRequestData { QSysInfo::productType(), auto installationUuid = m_settings->getInstallationUuid(true);
QString(APP_VERSION), auto userCountryCode = apiConfig.value(configKey::userCountryCode).toString();
m_settings->getInstallationUuid(true), auto serviceType = apiConfig.value(configKey::serviceType).toString();
apiConfig.value(configKey::userCountryCode).toString(), auto serviceProtocol = apiConfig.value(configKey::serviceProtocol).toString();
newCountryCode,
apiConfig.value(configKey::serviceType).toString(),
apiConfig.value(configKey::serviceProtocol).toString(),
serverConfig.value(configKey::authData).toObject() };
ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol); ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
QJsonObject apiPayload = gatewayRequestData.toJsonObject(); QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload); apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::uuid] = installationUuid;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
if (!newCountryCode.isEmpty()) {
apiPayload[configKey::serverCountryCode] = newCountryCode;
}
if (!authData.isEmpty()) {
apiPayload[configKey::authData] = authData;
}
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
QJsonObject newServerConfig; QJsonObject newServerConfig;
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, newServerConfig); fillServerConfig(serviceProtocol, apiPayloadData, responseBody, newServerConfig);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject(); QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode)); newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
@ -428,7 +259,7 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
newApiConfig.insert(apiDefs::key::vpnKey, apiConfig.value(apiDefs::key::vpnKey)); newApiConfig.insert(apiDefs::key::vpnKey, apiConfig.value(apiDefs::key::vpnKey));
newServerConfig.insert(configKey::apiConfig, newApiConfig); newServerConfig.insert(configKey::apiConfig, newApiConfig);
newServerConfig.insert(configKey::authData, gatewayRequestData.authData); newServerConfig.insert(configKey::authData, authData);
if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) { if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) {
newServerConfig.insert(config_key::name, serverConfig.value(config_key::name)); newServerConfig.insert(config_key::name, serverConfig.value(config_key::name));
@ -463,13 +294,10 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
auto installationUuid = m_settings->getInstallationUuid(true); auto installationUuid = m_settings->getInstallationUuid(true);
QString serviceProtocol = serverConfig.value(configKey::protocol).toString(); QString serviceProtocol = serverConfig.value(configKey::protocol).toString();
ProtocolData protocolData = generateProtocolData(serviceProtocol); ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
QJsonObject apiPayload; QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
apiPayload[configKey::uuid] = installationUuid; apiPayload[configKey::uuid] = installationUuid;
apiPayload[configKey::osVersion] = QSysInfo::productType();
apiPayload[configKey::appVersion] = QString(APP_VERSION);
apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString(); apiPayload[configKey::accessToken] = serverConfig.value(configKey::accessToken).toString();
apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString(); apiPayload[configKey::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString();
@ -477,11 +305,7 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
if (errorCode == ErrorCode::NoError) { if (errorCode == ErrorCode::NoError) {
errorCode = fillServerConfig(serviceProtocol, protocolData, responseBody, serverConfig); fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
m_serversModel->editServer(serverConfig, serverIndex); m_serversModel->editServer(serverConfig, serverIndex);
emit updateServerFromApiFinished(); emit updateServerFromApiFinished();
@ -494,6 +318,9 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
bool ApiConfigsController::deactivateDevice() bool ApiConfigsController::deactivateDevice()
{ {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
auto serverIndex = m_serversModel->getProcessedServerIndex(); auto serverIndex = m_serversModel->getProcessedServerIndex();
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
@ -502,19 +329,19 @@ bool ApiConfigsController::deactivateDevice()
return true; return true;
} }
GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
QString(APP_VERSION), ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
m_settings->getInstallationUuid(true),
apiConfigObject.value(configKey::userCountryCode).toString(),
apiConfigObject.value(configKey::serverCountryCode).toString(),
apiConfigObject.value(configKey::serviceType).toString(),
"",
serverConfigObject.value(configKey::authData).toObject() };
QJsonObject apiPayload = gatewayRequestData.toJsonObject(); QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
apiPayload[configKey::serverCountryCode] = apiConfigObject.value(configKey::serverCountryCode);
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[configKey::uuid] = m_settings->getInstallationUuid(true);
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) { if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
emit errorOccurred(errorCode); emit errorOccurred(errorCode);
return false; return false;
@ -528,6 +355,9 @@ bool ApiConfigsController::deactivateDevice()
bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode) bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode)
{ {
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
auto serverIndex = m_serversModel->getProcessedServerIndex(); auto serverIndex = m_serversModel->getProcessedServerIndex();
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
@ -536,19 +366,19 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
return true; return true;
} }
GatewayRequestData gatewayRequestData { QSysInfo::productType(), QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
QString(APP_VERSION), ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
uuid,
apiConfigObject.value(configKey::userCountryCode).toString(),
serverCountryCode,
apiConfigObject.value(configKey::serviceType).toString(),
"",
serverConfigObject.value(configKey::authData).toObject() };
QJsonObject apiPayload = gatewayRequestData.toJsonObject(); QJsonObject apiPayload = fillApiPayload(protocol, apiPayloadData);
apiPayload[configKey::userCountryCode] = apiConfigObject.value(configKey::userCountryCode);
apiPayload[configKey::serverCountryCode] = serverCountryCode;
apiPayload[configKey::serviceType] = apiConfigObject.value(configKey::serviceType);
apiPayload[configKey::authData] = serverConfigObject.value(configKey::authData);
apiPayload[configKey::uuid] = uuid;
apiPayload[apiDefs::key::cliVersion] = QString(APP_VERSION);
QByteArray responseBody; QByteArray responseBody;
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody); ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) { if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
emit errorOccurred(errorCode); emit errorOccurred(errorCode);
return false; return false;
@ -587,29 +417,108 @@ bool ApiConfigsController::isConfigValid()
return true; return true;
} }
void ApiConfigsController::setCurrentProtocol(const QString &protocolName) ApiConfigsController::ApiPayloadData ApiConfigsController::generateApiPayloadData(const QString &protocol)
{ {
auto serverIndex = m_serversModel->getProcessedServerIndex(); ApiConfigsController::ApiPayloadData apiPayload;
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); if (protocol == configKey::cloak) {
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); apiPayload.certRequest = OpenVpnConfigurator::createCertRequest();
} else if (protocol == configKey::awg) {
apiConfigObject[configKey::serviceProtocol] = protocolName; auto connData = WireguardConfigurator::genClientKeys();
apiPayload.wireGuardClientPubKey = connData.clientPubKey;
serverConfigObject.insert(configKey::apiConfig, apiConfigObject); apiPayload.wireGuardClientPrivKey = connData.clientPrivKey;
}
m_serversModel->editServer(serverConfigObject, serverIndex); return apiPayload;
} }
bool ApiConfigsController::isVlessProtocol() QJsonObject ApiConfigsController::fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData)
{ {
auto serverIndex = m_serversModel->getProcessedServerIndex(); QJsonObject obj;
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex); if (protocol == configKey::cloak) {
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject(); obj[configKey::certificate] = apiPayloadData.certRequest.request;
} else if (protocol == configKey::awg) {
if (apiConfigObject[configKey::serviceProtocol].toString() == "vless") { obj[configKey::publicKey] = apiPayloadData.wireGuardClientPubKey;
return true;
} }
return false;
obj[configKey::osVersion] = QSysInfo::productType();
obj[configKey::appVersion] = QString(APP_VERSION);
return obj;
}
void ApiConfigsController::fillServerConfig(const QString &protocol, const ApiPayloadData &apiPayloadData,
const QByteArray &apiResponseBody, QJsonObject &serverConfig)
{
QString data = QJsonDocument::fromJson(apiResponseBody).object().value(config_key::config).toString();
data.replace("vpn://", "");
QByteArray ba = QByteArray::fromBase64(data.toUtf8(), QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
if (ba.isEmpty()) {
emit errorOccurred(ErrorCode::ApiConfigEmptyError);
return;
}
QByteArray ba_uncompressed = qUncompress(ba);
if (!ba_uncompressed.isEmpty()) {
ba = ba_uncompressed;
}
QString configStr = ba;
if (protocol == configKey::cloak) {
configStr.replace("<key>", "<key>\n");
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
} else if (protocol == configKey::awg) {
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
auto containers = newServerConfig.value(config_key::containers).toArray();
if (containers.isEmpty()) {
return; // todo process error
}
auto container = containers.at(0).toObject();
QString containerName = ContainerProps::containerTypeToString(DockerContainer::Awg);
auto containerConfig = container.value(containerName).toObject();
auto protocolConfig = QJsonDocument::fromJson(containerConfig.value(config_key::last_config).toString().toUtf8()).object();
containerConfig[config_key::junkPacketCount] = protocolConfig.value(config_key::junkPacketCount);
containerConfig[config_key::junkPacketMinSize] = protocolConfig.value(config_key::junkPacketMinSize);
containerConfig[config_key::junkPacketMaxSize] = protocolConfig.value(config_key::junkPacketMaxSize);
containerConfig[config_key::initPacketJunkSize] = protocolConfig.value(config_key::initPacketJunkSize);
containerConfig[config_key::responsePacketJunkSize] = protocolConfig.value(config_key::responsePacketJunkSize);
containerConfig[config_key::initPacketMagicHeader] = protocolConfig.value(config_key::initPacketMagicHeader);
containerConfig[config_key::responsePacketMagicHeader] = protocolConfig.value(config_key::responsePacketMagicHeader);
containerConfig[config_key::underloadPacketMagicHeader] = protocolConfig.value(config_key::underloadPacketMagicHeader);
containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
container[containerName] = containerConfig;
containers.replace(0, container);
newServerConfig[config_key::containers] = containers;
configStr = QString(QJsonDocument(newServerConfig).toJson());
}
QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
serverConfig[config_key::description] = newServerConfig.value(config_key::description);
serverConfig[config_key::name] = newServerConfig.value(config_key::name);
}
auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
serverConfig[config_key::defaultContainer] = defaultContainer;
QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
auto apiConfig = QJsonObject::fromVariantMap(map);
if (newServerConfig.value(config_key::configVersion).toInt() == apiDefs::ConfigSource::AmneziaGateway) {
apiConfig.insert(configKey::serviceInfo, QJsonDocument::fromJson(apiResponseBody).object().value(configKey::serviceInfo).toObject());
}
serverConfig[configKey::apiConfig] = apiConfig;
return;
} }
QList<QString> ApiConfigsController::getQrCodes() QList<QString> ApiConfigsController::getQrCodes()
@ -626,10 +535,3 @@ QString ApiConfigsController::getVpnKey()
{ {
return m_vpnKey; return m_vpnKey;
} }
ErrorCode ApiConfigsController::executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody)
{
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
m_settings->isStrictKillSwitchEnabled());
return gatewayController.post(endpoint, apiPayload, responseBody);
}

View file

@ -35,9 +35,6 @@ public slots:
bool isConfigValid(); bool isConfigValid();
void setCurrentProtocol(const QString &protocolName);
bool isVlessProtocol();
signals: signals:
void errorOccurred(ErrorCode errorCode); void errorOccurred(ErrorCode errorCode);
@ -49,12 +46,23 @@ signals:
void vpnKeyExportReady(); void vpnKeyExportReady();
private: private:
struct ApiPayloadData
{
OpenVpnConfigurator::ConnectionData certRequest;
QString wireGuardClientPrivKey;
QString wireGuardClientPubKey;
};
ApiPayloadData generateApiPayloadData(const QString &protocol);
QJsonObject fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData);
void fillServerConfig(const QString &protocol, const ApiPayloadData &apiPayloadData, const QByteArray &apiResponseBody,
QJsonObject &serverConfig);
QList<QString> getQrCodes(); QList<QString> getQrCodes();
int getQrCodesCount(); int getQrCodesCount();
QString getVpnKey(); QString getVpnKey();
ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody);
QList<QString> m_qrCodes; QList<QString> m_qrCodes;
QString m_vpnKey; QString m_vpnKey;

View file

@ -12,7 +12,6 @@
#include "core/errorstrings.h" #include "core/errorstrings.h"
#include "core/qrCodeUtils.h" #include "core/qrCodeUtils.h"
#include "core/serialization/serialization.h" #include "core/serialization/serialization.h"
#include "protocols/protocols_defs.h"
#include "systemController.h" #include "systemController.h"
#include "utilities.h" #include "utilities.h"
@ -287,19 +286,6 @@ void ImportController::processNativeWireGuardConfig()
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3"; clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4"; clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
// clientProtocolConfig[config_key::cookieReplyPacketJunkSize] = "0";
// clientProtocolConfig[config_key::transportPacketJunkSize] = "0";
// clientProtocolConfig[config_key::specialJunk1] = "";
// clientProtocolConfig[config_key::specialJunk2] = "";
// clientProtocolConfig[config_key::specialJunk3] = "";
// clientProtocolConfig[config_key::specialJunk4] = "";
// clientProtocolConfig[config_key::specialJunk5] = "";
// clientProtocolConfig[config_key::controlledJunk1] = "";
// clientProtocolConfig[config_key::controlledJunk2] = "";
// clientProtocolConfig[config_key::controlledJunk3] = "";
// clientProtocolConfig[config_key::specialHandshakeTimeout] = "0";
clientProtocolConfig[config_key::isObfuscationEnabled] = true; clientProtocolConfig[config_key::isObfuscationEnabled] = true;
serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson()); serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(clientProtocolConfig).toJson());
@ -452,33 +438,21 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray; lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
QString protocolName = "wireguard"; QString protocolName = "wireguard";
if (!configMap.value(config_key::junkPacketCount).isEmpty() && !configMap.value(config_key::junkPacketMinSize).isEmpty()
const QStringList requiredJunkFields = { config_key::junkPacketCount, config_key::junkPacketMinSize, && !configMap.value(config_key::junkPacketMaxSize).isEmpty() && !configMap.value(config_key::initPacketJunkSize).isEmpty()
config_key::junkPacketMaxSize, config_key::initPacketJunkSize, && !configMap.value(config_key::responsePacketJunkSize).isEmpty() && !configMap.value(config_key::initPacketMagicHeader).isEmpty()
config_key::responsePacketJunkSize, config_key::initPacketMagicHeader, && !configMap.value(config_key::responsePacketMagicHeader).isEmpty()
config_key::responsePacketMagicHeader, config_key::underloadPacketMagicHeader, && !configMap.value(config_key::underloadPacketMagicHeader).isEmpty()
config_key::transportPacketMagicHeader }; && !configMap.value(config_key::transportPacketMagicHeader).isEmpty()) {
lastConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
const QStringList optionalJunkFields = { // config_key::cookieReplyPacketJunkSize, lastConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
// config_key::transportPacketJunkSize, lastConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3, lastConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
config_key::specialJunk4, config_key::specialJunk5, config_key::controlledJunk1, lastConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
config_key::controlledJunk2, config_key::controlledJunk3, config_key::specialHandshakeTimeout lastConfig[config_key::initPacketMagicHeader] = configMap.value(config_key::initPacketMagicHeader);
}; lastConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
lastConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
bool hasAllRequiredFields = std::all_of(requiredJunkFields.begin(), requiredJunkFields.end(), lastConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
[&configMap](const QString &field) { return !configMap.value(field).isEmpty(); });
if (hasAllRequiredFields) {
for (const QString &field : requiredJunkFields) {
lastConfig[field] = configMap.value(field);
}
for (const QString &field : optionalJunkFields) {
if (!configMap.value(field).isEmpty()) {
lastConfig[field] = configMap.value(field);
}
}
protocolName = "awg"; protocolName = "awg";
m_configType = ConfigTypes::Awg; m_configType = ConfigTypes::Awg;
} }

View file

@ -8,7 +8,6 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QtConcurrent> #include <QtConcurrent>
#include "core/api/apiUtils.h"
#include "core/controllers/serverController.h" #include "core/controllers/serverController.h"
#include "core/controllers/vpnConfigurationController.h" #include "core/controllers/vpnConfigurationController.h"
#include "core/networkUtilities.h" #include "core/networkUtilities.h"
@ -16,6 +15,7 @@
#include "ui/models/protocols/awgConfigModel.h" #include "ui/models/protocols/awgConfigModel.h"
#include "ui/models/protocols/wireguardConfigModel.h" #include "ui/models/protocols/wireguardConfigModel.h"
#include "utilities.h" #include "utilities.h"
#include "core/api/apiUtils.h"
namespace namespace
{ {
@ -79,36 +79,12 @@ void InstallController::install(DockerContainer container, int port, TransportPr
int s1 = QRandomGenerator::global()->bounded(15, 150); int s1 = QRandomGenerator::global()->bounded(15, 150);
int s2 = QRandomGenerator::global()->bounded(15, 150); int s2 = QRandomGenerator::global()->bounded(15, 150);
// int s3 = QRandomGenerator::global()->bounded(15, 150); while (s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) {
// int s4 = QRandomGenerator::global()->bounded(15, 150);
// Ensure all values are unique and don't create equal packet sizes
QSet<int> usedValues;
usedValues.insert(s1);
while (usedValues.contains(s2) || s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) {
s2 = QRandomGenerator::global()->bounded(15, 150); s2 = QRandomGenerator::global()->bounded(15, 150);
} }
usedValues.insert(s2);
// while (usedValues.contains(s3)
// || s1 + AwgConstant::messageInitiationSize == s3 + AwgConstant::messageCookieReplySize
// || s2 + AwgConstant::messageResponseSize == s3 + AwgConstant::messageCookieReplySize) {
// s3 = QRandomGenerator::global()->bounded(15, 150);
// }
// usedValues.insert(s3);
// while (usedValues.contains(s4)
// || s1 + AwgConstant::messageInitiationSize == s4 + AwgConstant::messageTransportSize
// || s2 + AwgConstant::messageResponseSize == s4 + AwgConstant::messageTransportSize
// || s3 + AwgConstant::messageCookieReplySize == s4 + AwgConstant::messageTransportSize) {
// s4 = QRandomGenerator::global()->bounded(15, 150);
// }
QString initPacketJunkSize = QString::number(s1); QString initPacketJunkSize = QString::number(s1);
QString responsePacketJunkSize = QString::number(s2); QString responsePacketJunkSize = QString::number(s2);
// QString cookieReplyPacketJunkSize = QString::number(s3);
// QString transportPacketJunkSize = QString::number(s4);
QSet<QString> headersValue; QSet<QString> headersValue;
while (headersValue.size() != 4) { while (headersValue.size() != 4) {
@ -132,21 +108,6 @@ void InstallController::install(DockerContainer container, int port, TransportPr
containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader; containerConfig[config_key::responsePacketMagicHeader] = responsePacketMagicHeader;
containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader; containerConfig[config_key::underloadPacketMagicHeader] = underloadPacketMagicHeader;
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader; containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
// TODO:
// containerConfig[config_key::cookieReplyPacketJunkSize] = cookieReplyPacketJunkSize;
// containerConfig[config_key::transportPacketJunkSize] = transportPacketJunkSize;
// containerConfig[config_key::specialJunk1] = specialJunk1;
// containerConfig[config_key::specialJunk2] = specialJunk2;
// containerConfig[config_key::specialJunk3] = specialJunk3;
// containerConfig[config_key::specialJunk4] = specialJunk4;
// containerConfig[config_key::specialJunk5] = specialJunk5;
// containerConfig[config_key::controlledJunk1] = controlledJunk1;
// containerConfig[config_key::controlledJunk2] = controlledJunk2;
// containerConfig[config_key::controlledJunk3] = controlledJunk3;
// containerConfig[config_key::specialHandshakeTimeout] = specialHandshakeTimeout;
} else if (container == DockerContainer::Sftp) { } else if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName); containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
containerConfig.insert(config_key::password, Utils::getRandomString(16)); containerConfig.insert(config_key::password, Utils::getRandomString(16));
@ -440,19 +401,6 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
containerConfig[config_key::transportPacketMagicHeader] = containerConfig[config_key::transportPacketMagicHeader] =
serverConfigMap.value(config_key::transportPacketMagicHeader); serverConfigMap.value(config_key::transportPacketMagicHeader);
// containerConfig[config_key::cookieReplyPacketJunkSize] = serverConfigMap.value(config_key::cookieReplyPacketJunkSize);
// containerConfig[config_key::transportPacketJunkSize] = serverConfigMap.value(config_key::transportPacketJunkSize);
// containerConfig[config_key::specialJunk1] = serverConfigMap.value(config_key::specialJunk1);
// containerConfig[config_key::specialJunk2] = serverConfigMap.value(config_key::specialJunk2);
// containerConfig[config_key::specialJunk3] = serverConfigMap.value(config_key::specialJunk3);
// containerConfig[config_key::specialJunk4] = serverConfigMap.value(config_key::specialJunk4);
// containerConfig[config_key::specialJunk5] = serverConfigMap.value(config_key::specialJunk5);
// containerConfig[config_key::controlledJunk1] = serverConfigMap.value(config_key::controlledJunk1);
// containerConfig[config_key::controlledJunk2] = serverConfigMap.value(config_key::controlledJunk2);
// containerConfig[config_key::controlledJunk3] = serverConfigMap.value(config_key::controlledJunk3);
// containerConfig[config_key::specialHandshakeTimeout] = serverConfigMap.value(config_key::specialHandshakeTimeout);
} else if (protocol == Proto::WireGuard) { } else if (protocol == Proto::WireGuard) {
QString serverConfig = serverController->getTextFileFromContainer(container, credentials, QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
protocols::wireguard::serverConfigPath, errorCode); protocols::wireguard::serverConfigPath, errorCode);

View file

@ -37,7 +37,7 @@ void ListViewFocusController::viewAtCurrentIndex() const
} }
case Section::Delegate: { case Section::Delegate: {
QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index QMetaObject::invokeMethod(m_listView, "positionViewAtIndex", Q_ARG(int, m_delegateIndex), // Index
Q_ARG(int, 2)); // PositionMode (0 = Visible) Q_ARG(int, 6)); // PositionMode (0 = Beginning; 1 = Center; 2 = End; 3 = Visible; 4 = Contain; 5 = SnapPosition)
break; break;
} }
case Section::Footer: { case Section::Footer: {
@ -207,6 +207,7 @@ void ListViewFocusController::focusNextItem()
m_focusedItemIndex++; m_focusedItemIndex++;
m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex)); m_focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(m_focusedItemIndex));
m_focusedItem->forceActiveFocus(Qt::TabFocusReason); m_focusedItem->forceActiveFocus(Qt::TabFocusReason);
qDebug() << "Next focus is set to item: " << m_focusedItem;
} }
void ListViewFocusController::focusPreviousItem() void ListViewFocusController::focusPreviousItem()
@ -238,6 +239,7 @@ void ListViewFocusController::resetFocusChain()
m_focusChain.clear(); m_focusChain.clear();
m_focusedItem = nullptr; m_focusedItem = nullptr;
m_focusedItemIndex = -1; m_focusedItemIndex = -1;
qDebug() << "Focus chain was reset";
} }
void ListViewFocusController::reloadFocusChain() void ListViewFocusController::reloadFocusChain()

View file

@ -75,12 +75,6 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
} }
return false; return false;
} }
case IsProtocolSelectionSupportedRole: {
if (m_accountInfoData.supportedProtocols.size() > 1) {
return true;
}
return false;
}
} }
return QVariant(); return QVariant();
@ -101,10 +95,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons
accountInfoData.configType = apiUtils::getConfigType(serverConfig); accountInfoData.configType = apiUtils::getConfigType(serverConfig);
for (const auto &protocol : accountInfoObject.value(apiDefs::key::supportedProtocols).toArray()) {
accountInfoData.supportedProtocols.push_back(protocol.toString());
}
m_accountInfoData = accountInfoData; m_accountInfoData = accountInfoData;
m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject(); m_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject();
@ -169,7 +159,6 @@ QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
roles[ServiceDescriptionRole] = "serviceDescription"; roles[ServiceDescriptionRole] = "serviceDescription";
roles[IsComponentVisibleRole] = "isComponentVisible"; roles[IsComponentVisibleRole] = "isComponentVisible";
roles[HasExpiredWorkerRole] = "hasExpiredWorker"; roles[HasExpiredWorkerRole] = "hasExpiredWorker";
roles[IsProtocolSelectionSupportedRole] = "isProtocolSelectionSupported";
return roles; return roles;
} }

View file

@ -18,8 +18,7 @@ public:
ServiceDescriptionRole, ServiceDescriptionRole,
EndDateRole, EndDateRole,
IsComponentVisibleRole, IsComponentVisibleRole,
HasExpiredWorkerRole, HasExpiredWorkerRole
IsProtocolSelectionSupportedRole
}; };
explicit ApiAccountInfoModel(QObject *parent = nullptr); explicit ApiAccountInfoModel(QObject *parent = nullptr);
@ -52,8 +51,6 @@ private:
int maxDeviceCount; int maxDeviceCount;
apiDefs::ConfigType configType; apiDefs::ConfigType configType;
QStringList supportedProtocols;
}; };
AccountInfoData m_accountInfoData; AccountInfoData m_accountInfoData;

View file

@ -28,17 +28,7 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break; case Roles::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; case Roles::ClientJunkPacketMinSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; case Roles::ClientJunkPacketMaxSizeRole: m_clientProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
case Roles::ClientSpecialJunk1Role: m_clientProtocolConfig.insert(config_key::specialJunk1, value.toString()); break;
case Roles::ClientSpecialJunk2Role: m_clientProtocolConfig.insert(config_key::specialJunk2, value.toString()); break;
case Roles::ClientSpecialJunk3Role: m_clientProtocolConfig.insert(config_key::specialJunk3, value.toString()); break;
case Roles::ClientSpecialJunk4Role: m_clientProtocolConfig.insert(config_key::specialJunk4, value.toString()); break;
case Roles::ClientSpecialJunk5Role: m_clientProtocolConfig.insert(config_key::specialJunk5, value.toString()); break;
case Roles::ClientControlledJunk1Role: m_clientProtocolConfig.insert(config_key::controlledJunk1, value.toString()); break;
case Roles::ClientControlledJunk2Role: m_clientProtocolConfig.insert(config_key::controlledJunk2, value.toString()); break;
case Roles::ClientControlledJunk3Role: m_clientProtocolConfig.insert(config_key::controlledJunk3, value.toString()); break;
case Roles::ClientSpecialHandshakeTimeoutRole:
m_clientProtocolConfig.insert(config_key::specialHandshakeTimeout, value.toString());
break;
case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break; case Roles::ServerJunkPacketCountRole: m_serverProtocolConfig.insert(config_key::junkPacketCount, value.toString()); break;
case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break; case Roles::ServerJunkPacketMinSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString()); break;
case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break; case Roles::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
@ -46,12 +36,6 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
case Roles::ServerResponsePacketJunkSizeRole: case Roles::ServerResponsePacketJunkSizeRole:
m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString()); m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString());
break; break;
// case Roles::ServerCookieReplyPacketJunkSizeRole:
// m_serverProtocolConfig.insert(config_key::cookieReplyPacketJunkSize, value.toString());
// break;
// case Roles::ServerTransportPacketJunkSizeRole:
// m_serverProtocolConfig.insert(config_key::transportPacketJunkSize, value.toString());
// break;
case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break; case Roles::ServerInitPacketMagicHeaderRole: m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString()); break;
case Roles::ServerResponsePacketMagicHeaderRole: case Roles::ServerResponsePacketMagicHeaderRole:
m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString()); m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString());
@ -82,23 +66,12 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const
case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount); case Roles::ClientJunkPacketCountRole: return m_clientProtocolConfig.value(config_key::junkPacketCount);
case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize); case Roles::ClientJunkPacketMinSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMinSize);
case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize); case Roles::ClientJunkPacketMaxSizeRole: return m_clientProtocolConfig.value(config_key::junkPacketMaxSize);
case Roles::ClientSpecialJunk1Role: return m_clientProtocolConfig.value(config_key::specialJunk1);
case Roles::ClientSpecialJunk2Role: return m_clientProtocolConfig.value(config_key::specialJunk2);
case Roles::ClientSpecialJunk3Role: return m_clientProtocolConfig.value(config_key::specialJunk3);
case Roles::ClientSpecialJunk4Role: return m_clientProtocolConfig.value(config_key::specialJunk4);
case Roles::ClientSpecialJunk5Role: return m_clientProtocolConfig.value(config_key::specialJunk5);
case Roles::ClientControlledJunk1Role: return m_clientProtocolConfig.value(config_key::controlledJunk1);
case Roles::ClientControlledJunk2Role: return m_clientProtocolConfig.value(config_key::controlledJunk2);
case Roles::ClientControlledJunk3Role: return m_clientProtocolConfig.value(config_key::controlledJunk3);
case Roles::ClientSpecialHandshakeTimeoutRole: return m_clientProtocolConfig.value(config_key::specialHandshakeTimeout);
case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount); case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount);
case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize); case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize);
case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize); case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize);
case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize); case Roles::ServerInitPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::initPacketJunkSize);
case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize); case Roles::ServerResponsePacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::responsePacketJunkSize);
// case Roles::ServerCookieReplyPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize);
// case Roles::ServerTransportPacketJunkSizeRole: return m_serverProtocolConfig.value(config_key::transportPacketJunkSize);
case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader); case Roles::ServerInitPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::initPacketMagicHeader);
case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader); case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader);
case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader); case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader);
@ -121,8 +94,7 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
m_serverProtocolConfig.insert(config_key::transport_proto, m_serverProtocolConfig.insert(config_key::transport_proto,
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto)); serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config); m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
m_serverProtocolConfig[config_key::subnet_address] = m_serverProtocolConfig[config_key::subnet_address] = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); m_serverProtocolConfig[config_key::port] = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
m_serverProtocolConfig[config_key::junkPacketCount] = m_serverProtocolConfig[config_key::junkPacketCount] =
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
@ -134,10 +106,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
m_serverProtocolConfig[config_key::responsePacketJunkSize] = m_serverProtocolConfig[config_key::responsePacketJunkSize] =
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
// m_serverProtocolConfig[config_key::cookieReplyPacketJunkSize] =
// serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize);
// m_serverProtocolConfig[config_key::transportPacketJunkSize] =
// serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize);
m_serverProtocolConfig[config_key::initPacketMagicHeader] = m_serverProtocolConfig[config_key::initPacketMagicHeader] =
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
m_serverProtocolConfig[config_key::responsePacketMagicHeader] = m_serverProtocolConfig[config_key::responsePacketMagicHeader] =
@ -156,24 +124,6 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString()); clientProtocolConfig.value(config_key::junkPacketMinSize).toString(m_serverProtocolConfig[config_key::junkPacketMinSize].toString());
m_clientProtocolConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize] =
clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString()); clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(m_serverProtocolConfig[config_key::junkPacketMaxSize].toString());
m_clientProtocolConfig[config_key::specialJunk1] =
clientProtocolConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1);
m_clientProtocolConfig[config_key::specialJunk2] =
clientProtocolConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2);
m_clientProtocolConfig[config_key::specialJunk3] =
clientProtocolConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3);
m_clientProtocolConfig[config_key::specialJunk4] =
clientProtocolConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4);
m_clientProtocolConfig[config_key::specialJunk5] =
clientProtocolConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5);
m_clientProtocolConfig[config_key::controlledJunk1] =
clientProtocolConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1);
m_clientProtocolConfig[config_key::controlledJunk2] =
clientProtocolConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2);
m_clientProtocolConfig[config_key::controlledJunk3] =
clientProtocolConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3);
m_clientProtocolConfig[config_key::specialHandshakeTimeout] =
clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout);
endResetModel(); endResetModel();
} }
@ -191,15 +141,6 @@ QJsonObject AwgConfigModel::getConfig()
jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount]; jsonConfig[config_key::junkPacketCount] = m_clientProtocolConfig[config_key::junkPacketCount];
jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize]; jsonConfig[config_key::junkPacketMinSize] = m_clientProtocolConfig[config_key::junkPacketMinSize];
jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize]; jsonConfig[config_key::junkPacketMaxSize] = m_clientProtocolConfig[config_key::junkPacketMaxSize];
jsonConfig[config_key::specialJunk1] = m_clientProtocolConfig[config_key::specialJunk1];
jsonConfig[config_key::specialJunk2] = m_clientProtocolConfig[config_key::specialJunk2];
jsonConfig[config_key::specialJunk3] = m_clientProtocolConfig[config_key::specialJunk3];
jsonConfig[config_key::specialJunk4] = m_clientProtocolConfig[config_key::specialJunk4];
jsonConfig[config_key::specialJunk5] = m_clientProtocolConfig[config_key::specialJunk5];
jsonConfig[config_key::controlledJunk1] = m_clientProtocolConfig[config_key::controlledJunk1];
jsonConfig[config_key::controlledJunk2] = m_clientProtocolConfig[config_key::controlledJunk2];
jsonConfig[config_key::controlledJunk3] = m_clientProtocolConfig[config_key::controlledJunk3];
jsonConfig[config_key::specialHandshakeTimeout] = m_clientProtocolConfig[config_key::specialHandshakeTimeout];
m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson()); m_serverProtocolConfig[config_key::last_config] = QString(QJsonDocument(jsonConfig).toJson());
} }
@ -218,17 +159,6 @@ bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2)
return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2); return (AwgConstant::messageInitiationSize + s1 == AwgConstant::messageResponseSize + s2);
} }
// bool AwgConfigModel::isPacketSizeEqual(const int s1, const int s2, const int s3, const int s4)
// {
// int initSize = AwgConstant::messageInitiationSize + s1;
// int responseSize = AwgConstant::messageResponseSize + s2;
// int cookieSize = AwgConstant::messageCookieReplySize + s3;
// int transportSize = AwgConstant::messageTransportSize + s4;
// return (initSize == responseSize || initSize == cookieSize || initSize == transportSize || responseSize == cookieSize
// || responseSize == transportSize || cookieSize == transportSize);
// }
bool AwgConfigModel::isServerSettingsEqual() bool AwgConfigModel::isServerSettingsEqual()
{ {
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject()); const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
@ -248,24 +178,12 @@ QHash<int, QByteArray> AwgConfigModel::roleNames() const
roles[ClientJunkPacketCountRole] = "clientJunkPacketCount"; roles[ClientJunkPacketCountRole] = "clientJunkPacketCount";
roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize"; roles[ClientJunkPacketMinSizeRole] = "clientJunkPacketMinSize";
roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize"; roles[ClientJunkPacketMaxSizeRole] = "clientJunkPacketMaxSize";
roles[ClientSpecialJunk1Role] = "clientSpecialJunk1";
roles[ClientSpecialJunk2Role] = "clientSpecialJunk2";
roles[ClientSpecialJunk3Role] = "clientSpecialJunk3";
roles[ClientSpecialJunk4Role] = "clientSpecialJunk4";
roles[ClientSpecialJunk5Role] = "clientSpecialJunk5";
roles[ClientControlledJunk1Role] = "clientControlledJunk1";
roles[ClientControlledJunk2Role] = "clientControlledJunk2";
roles[ClientControlledJunk3Role] = "clientControlledJunk3";
roles[ClientSpecialHandshakeTimeoutRole] = "clientSpecialHandshakeTimeout";
roles[ServerJunkPacketCountRole] = "serverJunkPacketCount"; roles[ServerJunkPacketCountRole] = "serverJunkPacketCount";
roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize"; roles[ServerJunkPacketMinSizeRole] = "serverJunkPacketMinSize";
roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize"; roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize";
roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize"; roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize";
roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize"; roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize";
roles[ServerCookieReplyPacketJunkSizeRole] = "serverCookieReplyPacketJunkSize";
roles[ServerTransportPacketJunkSizeRole] = "serverTransportPacketJunkSize";
roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader"; roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader";
roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader"; roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader";
roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader"; roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader";
@ -282,16 +200,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount); clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize); clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize); clientJunkPacketMaxSize = clientProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
clientSpecialJunk1 = clientProtocolConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1);
clientSpecialJunk2 = clientProtocolConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2);
clientSpecialJunk3 = clientProtocolConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3);
clientSpecialJunk4 = clientProtocolConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4);
clientSpecialJunk5 = clientProtocolConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5);
clientControlledJunk1 = clientProtocolConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1);
clientControlledJunk2 = clientProtocolConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2);
clientControlledJunk3 = clientProtocolConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3);
clientSpecialHandshakeTimeout =
clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout);
subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress); subnetAddress = serverProtocolConfig.value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress);
port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort); port = serverProtocolConfig.value(config_key::port).toString(protocols::awg::defaultPort);
@ -301,10 +209,6 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
serverResponsePacketJunkSize = serverResponsePacketJunkSize =
serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize); serverProtocolConfig.value(config_key::responsePacketJunkSize).toString(protocols::awg::defaultResponsePacketJunkSize);
// serverCookieReplyPacketJunkSize =
// serverProtocolConfig.value(config_key::cookieReplyPacketJunkSize).toString(protocols::awg::defaultCookieReplyPacketJunkSize);
// serverTransportPacketJunkSize =
// serverProtocolConfig.value(config_key::transportPacketJunkSize).toString(protocols::awg::defaultTransportPacketJunkSize);
serverInitPacketMagicHeader = serverInitPacketMagicHeader =
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader); serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
serverResponsePacketMagicHeader = serverResponsePacketMagicHeader =
@ -320,8 +224,6 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize || serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize || serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
// || serverCookieReplyPacketJunkSize != other.serverCookieReplyPacketJunkSize
// || serverTransportPacketJunkSize != other.serverTransportPacketJunkSize
|| serverInitPacketMagicHeader != other.serverInitPacketMagicHeader || serverInitPacketMagicHeader != other.serverInitPacketMagicHeader
|| serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader || serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader
|| serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader || serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader
@ -334,12 +236,7 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const
{ {
if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount
|| clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize || clientJunkPacketMinSize != other.clientJunkPacketMinSize || clientJunkPacketMaxSize != other.clientJunkPacketMaxSize) {
|| clientSpecialJunk1 != other.clientSpecialJunk1 || clientSpecialJunk2 != other.clientSpecialJunk2
|| clientSpecialJunk3 != other.clientSpecialJunk3 || clientSpecialJunk4 != other.clientSpecialJunk4
|| clientSpecialJunk5 != other.clientSpecialJunk5 || clientControlledJunk1 != other.clientControlledJunk1
|| clientControlledJunk2 != other.clientControlledJunk2 || clientControlledJunk3 != other.clientControlledJunk3
|| clientSpecialHandshakeTimeout != other.clientSpecialHandshakeTimeout) {
return false; return false;
} }
return true; return true;

View file

@ -6,12 +6,9 @@
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
namespace AwgConstant namespace AwgConstant {
{
const int messageInitiationSize = 148; const int messageInitiationSize = 148;
const int messageResponseSize = 92; const int messageResponseSize = 92;
const int messageCookieReplySize = 64;
const int messageTransportSize = 32;
} }
struct AwgConfig struct AwgConfig
@ -25,23 +22,12 @@ struct AwgConfig
QString clientJunkPacketCount; QString clientJunkPacketCount;
QString clientJunkPacketMinSize; QString clientJunkPacketMinSize;
QString clientJunkPacketMaxSize; QString clientJunkPacketMaxSize;
QString clientSpecialJunk1;
QString clientSpecialJunk2;
QString clientSpecialJunk3;
QString clientSpecialJunk4;
QString clientSpecialJunk5;
QString clientControlledJunk1;
QString clientControlledJunk2;
QString clientControlledJunk3;
QString clientSpecialHandshakeTimeout;
QString serverJunkPacketCount; QString serverJunkPacketCount;
QString serverJunkPacketMinSize; QString serverJunkPacketMinSize;
QString serverJunkPacketMaxSize; QString serverJunkPacketMaxSize;
QString serverInitPacketJunkSize; QString serverInitPacketJunkSize;
QString serverResponsePacketJunkSize; QString serverResponsePacketJunkSize;
QString serverCookieReplyPacketJunkSize;
QString serverTransportPacketJunkSize;
QString serverInitPacketMagicHeader; QString serverInitPacketMagicHeader;
QString serverResponsePacketMagicHeader; QString serverResponsePacketMagicHeader;
QString serverUnderloadPacketMagicHeader; QString serverUnderloadPacketMagicHeader;
@ -49,6 +35,7 @@ struct AwgConfig
bool hasEqualServerSettings(const AwgConfig &other) const; bool hasEqualServerSettings(const AwgConfig &other) const;
bool hasEqualClientSettings(const AwgConfig &other) const; bool hasEqualClientSettings(const AwgConfig &other) const;
}; };
class AwgConfigModel : public QAbstractListModel class AwgConfigModel : public QAbstractListModel
@ -64,28 +51,16 @@ public:
ClientJunkPacketCountRole, ClientJunkPacketCountRole,
ClientJunkPacketMinSizeRole, ClientJunkPacketMinSizeRole,
ClientJunkPacketMaxSizeRole, ClientJunkPacketMaxSizeRole,
ClientSpecialJunk1Role,
ClientSpecialJunk2Role,
ClientSpecialJunk3Role,
ClientSpecialJunk4Role,
ClientSpecialJunk5Role,
ClientControlledJunk1Role,
ClientControlledJunk2Role,
ClientControlledJunk3Role,
ClientSpecialHandshakeTimeoutRole,
ServerJunkPacketCountRole, ServerJunkPacketCountRole,
ServerJunkPacketMinSizeRole, ServerJunkPacketMinSizeRole,
ServerJunkPacketMaxSizeRole, ServerJunkPacketMaxSizeRole,
ServerInitPacketJunkSizeRole, ServerInitPacketJunkSizeRole,
ServerResponsePacketJunkSizeRole, ServerResponsePacketJunkSizeRole,
ServerCookieReplyPacketJunkSizeRole,
ServerTransportPacketJunkSizeRole,
ServerInitPacketMagicHeaderRole, ServerInitPacketMagicHeaderRole,
ServerResponsePacketMagicHeaderRole, ServerResponsePacketMagicHeaderRole,
ServerUnderloadPacketMagicHeaderRole, ServerUnderloadPacketMagicHeaderRole,
ServerTransportPacketMagicHeaderRole, ServerTransportPacketMagicHeaderRole
}; };
explicit AwgConfigModel(QObject *parent = nullptr); explicit AwgConfigModel(QObject *parent = nullptr);
@ -100,7 +75,7 @@ public slots:
QJsonObject getConfig(); QJsonObject getConfig();
bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4); bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4);
bool isPacketSizeEqual(const int s1, const int s2/*, const int s3, const int s4*/); bool isPacketSizeEqual(const int s1, const int s2);
bool isServerSettingsEqual(); bool isServerSettingsEqual();

View file

@ -2,72 +2,128 @@
#include "protocols/protocols_defs.h" #include "protocols/protocols_defs.h"
OpenVpnConfigModel::OpenVpnConfigModel(QObject *parent) : QAbstractListModel(parent) OpenVpnConfigModel::OpenVpnConfigModel(QObject *parent)
: QObject(parent)
{ {
} }
int OpenVpnConfigModel::rowCount(const QModelIndex &parent) const QString OpenVpnConfigModel::subnetAddress() const
{ {
Q_UNUSED(parent); return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress);
return 1;
} }
bool OpenVpnConfigModel::setData(const QModelIndex &index, const QVariant &value, int role) void OpenVpnConfigModel::setSubnetAddress(const QString &subnetAddress)
{ {
if (!index.isValid() || index.row() < 0 || index.row() >= ContainerProps::allContainers().size()) { m_protocolConfig.insert(amnezia::config_key::subnet_address, subnetAddress);
return false;
}
switch (role) {
case Roles::SubnetAddressRole: m_protocolConfig.insert(amnezia::config_key::subnet_address, value.toString()); break;
case Roles::TransportProtoRole: m_protocolConfig.insert(config_key::transport_proto, value.toString()); break;
case Roles::PortRole: m_protocolConfig.insert(config_key::port, value.toString()); break;
case Roles::AutoNegotiateEncryprionRole: m_protocolConfig.insert(config_key::ncp_disable, !value.toBool()); break;
case Roles::HashRole: m_protocolConfig.insert(config_key::hash, value.toString()); break;
case Roles::CipherRole: m_protocolConfig.insert(config_key::cipher, value.toString()); break;
case Roles::TlsAuthRole: m_protocolConfig.insert(config_key::tls_auth, value.toBool()); break;
case Roles::BlockDnsRole: m_protocolConfig.insert(config_key::block_outside_dns, value.toBool()); break;
case Roles::AdditionalClientCommandsRole: m_protocolConfig.insert(config_key::additional_client_config, value.toString()); break;
case Roles::AdditionalServerCommandsRole: m_protocolConfig.insert(config_key::additional_server_config, value.toString()); break;
}
emit dataChanged(index, index, QList { role });
return true;
} }
QVariant OpenVpnConfigModel::data(const QModelIndex &index, int role) const QString OpenVpnConfigModel::transportProto() const
{ {
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount()) { return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
return false; }
}
switch (role) { void OpenVpnConfigModel::setTransportProto(const QString &transportProto)
case Roles::SubnetAddressRole: {
return m_protocolConfig.value(amnezia::config_key::subnet_address).toString(amnezia::protocols::openvpn::defaultSubnetAddress); m_protocolConfig.insert(config_key::transport_proto, transportProto);
case Roles::TransportProtoRole: }
return m_protocolConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto);
case Roles::PortRole: return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort); QString OpenVpnConfigModel::port() const
case Roles::AutoNegotiateEncryprionRole: {
return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable); return m_protocolConfig.value(config_key::port).toString(protocols::openvpn::defaultPort);
case Roles::HashRole: return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash); }
case Roles::CipherRole: return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher);
case Roles::TlsAuthRole: return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth); void OpenVpnConfigModel::setPort(const QString &port)
case Roles::BlockDnsRole: {
return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns); m_protocolConfig.insert(config_key::port, port);
case Roles::AdditionalClientCommandsRole: }
return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig);
case Roles::AdditionalServerCommandsRole: bool OpenVpnConfigModel::autoNegotiateEncryption() const
return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig); {
case Roles::IsPortEditable: return m_container == DockerContainer::OpenVpn ? true : false; return !m_protocolConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
case Roles::IsTransportProtoEditable: return m_container == DockerContainer::OpenVpn ? true : false; }
case Roles::HasRemoveButton: return m_container == DockerContainer::OpenVpn ? true : false;
} void OpenVpnConfigModel::setAutoNegotiateEncryption(bool enabled)
return QVariant(); {
m_protocolConfig.insert(config_key::ncp_disable, !enabled);
}
QString OpenVpnConfigModel::hash() const
{
return m_protocolConfig.value(config_key::hash).toString(protocols::openvpn::defaultHash);
}
void OpenVpnConfigModel::setHash(const QString &hash)
{
m_protocolConfig.insert(config_key::hash, hash);
}
QString OpenVpnConfigModel::cipher() const
{
return m_protocolConfig.value(config_key::cipher).toString(protocols::openvpn::defaultCipher);
}
void OpenVpnConfigModel::setCipher(const QString &cipher)
{
m_protocolConfig.insert(config_key::cipher, cipher);
}
bool OpenVpnConfigModel::tlsAuth() const
{
return m_protocolConfig.value(config_key::tls_auth).toBool(protocols::openvpn::defaultTlsAuth);
}
void OpenVpnConfigModel::setTlsAuth(bool enabled)
{
m_protocolConfig.insert(config_key::tls_auth, enabled);
}
bool OpenVpnConfigModel::blockDns() const
{
return m_protocolConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns);
}
void OpenVpnConfigModel::setBlockDns(bool enabled)
{
m_protocolConfig.insert(config_key::block_outside_dns, enabled);
}
QString OpenVpnConfigModel::additionalClientCommands() const
{
return m_protocolConfig.value(config_key::additional_client_config).toString(protocols::openvpn::defaultAdditionalClientConfig);
}
void OpenVpnConfigModel::setAdditionalClientCommands(const QString &commands)
{
m_protocolConfig.insert(config_key::additional_client_config, commands);
}
QString OpenVpnConfigModel::additionalServerCommands() const
{
return m_protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig);
}
void OpenVpnConfigModel::setAdditionalServerCommands(const QString &commands)
{
m_protocolConfig.insert(config_key::additional_server_config, commands);
}
bool OpenVpnConfigModel::isPortEditable() const
{
return m_container == DockerContainer::OpenVpn;
}
bool OpenVpnConfigModel::isTransportProtoEditable() const
{
return m_container == DockerContainer::OpenVpn;
}
bool OpenVpnConfigModel::hasRemoveButton() const
{
return m_container == DockerContainer::OpenVpn;
} }
void OpenVpnConfigModel::updateModel(const QJsonObject &config) void OpenVpnConfigModel::updateModel(const QJsonObject &config)
{ {
beginResetModel();
m_container = ContainerProps::containerFromString(config.value(config_key::container).toString()); m_container = ContainerProps::containerFromString(config.value(config_key::container).toString());
m_fullConfig = config; m_fullConfig = config;
@ -100,8 +156,6 @@ void OpenVpnConfigModel::updateModel(const QJsonObject &config)
m_protocolConfig.insert( m_protocolConfig.insert(
config_key::additional_server_config, config_key::additional_server_config,
protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig)); protocolConfig.value(config_key::additional_server_config).toString(protocols::openvpn::defaultAdditionalServerConfig));
endResetModel();
} }
QJsonObject OpenVpnConfigModel::getConfig() QJsonObject OpenVpnConfigModel::getConfig()
@ -109,26 +163,3 @@ QJsonObject OpenVpnConfigModel::getConfig()
m_fullConfig.insert(config_key::openvpn, m_protocolConfig); m_fullConfig.insert(config_key::openvpn, m_protocolConfig);
return m_fullConfig; return m_fullConfig;
} }
QHash<int, QByteArray> OpenVpnConfigModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[SubnetAddressRole] = "subnetAddress";
roles[TransportProtoRole] = "transportProto";
roles[PortRole] = "port";
roles[AutoNegotiateEncryprionRole] = "autoNegotiateEncryprion";
roles[HashRole] = "hash";
roles[CipherRole] = "cipher";
roles[TlsAuthRole] = "tlsAuth";
roles[BlockDnsRole] = "blockDns";
roles[AdditionalClientCommandsRole] = "additionalClientCommands";
roles[AdditionalServerCommandsRole] = "additionalServerCommands";
roles[IsPortEditable] = "isPortEditable";
roles[IsTransportProtoEditable] = "isTransportProtoEditable";
roles[HasRemoveButton] = "hasRemoveButton";
return roles;
}

View file

@ -1,47 +1,90 @@
#ifndef OPENVPNCONFIGMODEL_H #ifndef OPENVPNCONFIGMODEL_H
#define OPENVPNCONFIGMODEL_H #define OPENVPNCONFIGMODEL_H
#include <QAbstractListModel> #include <QObject>
#include <QJsonObject> #include <QJsonObject>
#include "containers/containers_defs.h" #include "containers/containers_defs.h"
class OpenVpnConfigModel : public QAbstractListModel class OpenVpnConfigModel : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString subnetAddress READ subnetAddress WRITE setSubnetAddress NOTIFY subnetAddressChanged)
Q_PROPERTY(QString transportProto READ transportProto WRITE setTransportProto NOTIFY transportProtoChanged)
Q_PROPERTY(QString port READ port WRITE setPort NOTIFY portChanged)
Q_PROPERTY(bool autoNegotiateEncryption READ autoNegotiateEncryption WRITE setAutoNegotiateEncryption NOTIFY autoNegotiateEncryptionChanged)
Q_PROPERTY(QString hash READ hash WRITE setHash NOTIFY hashChanged)
Q_PROPERTY(QString cipher READ cipher WRITE setCipher NOTIFY cipherChanged)
Q_PROPERTY(bool tlsAuth READ tlsAuth WRITE setTlsAuth NOTIFY tlsAuthChanged)
Q_PROPERTY(bool blockDns READ blockDns WRITE setBlockDns NOTIFY blockDnsChanged)
Q_PROPERTY(QString additionalClientCommands READ additionalClientCommands WRITE setAdditionalClientCommands NOTIFY additionalClientCommandsChanged)
Q_PROPERTY(QString additionalServerCommands READ additionalServerCommands WRITE setAdditionalServerCommands NOTIFY additionalServerCommandsChanged)
Q_PROPERTY(bool isPortEditable READ isPortEditable NOTIFY isPortEditableChanged)
Q_PROPERTY(bool isTransportProtoEditable READ isTransportProtoEditable NOTIFY isTransportProtoEditableChanged)
Q_PROPERTY(bool hasRemoveButton READ hasRemoveButton NOTIFY hasRemoveButtonChanged)
public: public:
enum Roles {
SubnetAddressRole = Qt::UserRole + 1,
TransportProtoRole,
PortRole,
AutoNegotiateEncryprionRole,
HashRole,
CipherRole,
TlsAuthRole,
BlockDnsRole,
AdditionalClientCommandsRole,
AdditionalServerCommandsRole,
IsPortEditable,
IsTransportProtoEditable,
HasRemoveButton
};
explicit OpenVpnConfigModel(QObject *parent = nullptr); explicit OpenVpnConfigModel(QObject *parent = nullptr);
~OpenVpnConfigModel() override = default;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; OpenVpnConfigModel(const OpenVpnConfigModel &) = delete;
OpenVpnConfigModel &operator=(const OpenVpnConfigModel &) = delete;
OpenVpnConfigModel(OpenVpnConfigModel &&) = delete;
OpenVpnConfigModel &operator=(OpenVpnConfigModel &&) = delete;
bool setData(const QModelIndex &index, const QVariant &value, int role) override; QString subnetAddress() const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void setSubnetAddress(const QString &subnetAddress);
QString transportProto() const;
void setTransportProto(const QString &transportProto);
QString port() const;
void setPort(const QString &port);
bool autoNegotiateEncryption() const;
void setAutoNegotiateEncryption(bool enabled);
QString hash() const;
void setHash(const QString &hash);
QString cipher() const;
void setCipher(const QString &cipher);
bool tlsAuth() const;
void setTlsAuth(bool enabled);
bool blockDns() const;
void setBlockDns(bool enabled);
QString additionalClientCommands() const;
void setAdditionalClientCommands(const QString &commands);
QString additionalServerCommands() const;
void setAdditionalServerCommands(const QString &commands);
bool isPortEditable() const;
bool isTransportProtoEditable() const;
bool hasRemoveButton() const;
Q_INVOKABLE QJsonObject getConfig();
signals:
void subnetAddressChanged(const QString &);
void transportProtoChanged(const QString &);
void portChanged(const QString &);
void autoNegotiateEncryptionChanged(bool);
void hashChanged(const QString &);
void cipherChanged(const QString &);
void tlsAuthChanged(bool);
void blockDnsChanged(bool);
void additionalClientCommandsChanged(const QString &);
void additionalServerCommandsChanged(const QString &);
void isPortEditableChanged(bool);
void isTransportProtoEditableChanged(bool);
void hasRemoveButtonChanged(bool);
public slots: public slots:
void updateModel(const QJsonObject &config); void updateModel(const QJsonObject &config);
QJsonObject getConfig();
protected:
QHash<int, QByteArray> roleNames() const override;
private: private:
DockerContainer m_container; DockerContainer m_container;

View file

@ -8,8 +8,6 @@
#include <AmneziaVPN-Swift.h> #include <AmneziaVPN-Swift.h>
#endif #endif
#include "core/api/apiUtils.h"
namespace namespace
{ {
namespace configKey namespace configKey
@ -429,7 +427,7 @@ void ServersModel::updateDefaultServerContainersModel()
emit defaultServerContainersUpdated(containers); emit defaultServerContainersUpdated(containers);
} }
QJsonObject ServersModel::getServerConfig(const int serverIndex) const QJsonObject ServersModel::getServerConfig(const int serverIndex)
{ {
return m_servers.at(serverIndex).toObject(); return m_servers.at(serverIndex).toObject();
} }
@ -816,8 +814,3 @@ const QString ServersModel::getDefaultServerImagePathCollapsed()
} }
return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper()); return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper());
} }
bool ServersModel::processedServerIsPremium() const
{
return apiUtils::isPremiumServer(getServerConfig(m_processedServerIndex));
}

View file

@ -63,9 +63,6 @@ public:
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged) Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged) Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerChanged)
bool processedServerIsPremium() const;
public slots: public slots:
void setDefaultServerIndex(const int index); void setDefaultServerIndex(const int index);
@ -95,7 +92,7 @@ public slots:
void removeServer(); void removeServer();
void removeServer(const int serverIndex); void removeServer(const int serverIndex);
QJsonObject getServerConfig(const int serverIndex) const; QJsonObject getServerConfig(const int serverIndex);
void reloadDefaultServerContainerConfig(); void reloadDefaultServerContainerConfig();
void updateContainerConfig(const int containerIndex, const QJsonObject config); void updateContainerConfig(const int containerIndex, const QJsonObject config);

View file

@ -1,15 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import "../Controls2"
TextFieldWithHeaderType {
Layout.fillWidth: true
Layout.topMargin: 16
textField.validator: IntValidator { bottom: 0 }
checkEmptyText: true
}

View file

@ -10,8 +10,7 @@ import ProtocolEnum 1.0
import "../Controls2" import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
ListViewType {
ListView {
id: menuContent id: menuContent
property var rootWidth property var rootWidth
@ -21,13 +20,6 @@ ListView {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
clip: true
snapMode: ListView.SnapToItem
ScrollBar.vertical: ScrollBarType {}
property bool isFocusable: true
ButtonGroup { ButtonGroup {
id: containersRadioButtonGroup id: containersRadioButtonGroup
} }

View file

@ -47,8 +47,8 @@ DrawerType2 {
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling) PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
root.closeTriggered() root.closeTriggered()
} }
} }

View file

@ -57,7 +57,7 @@ DrawerType2 {
headerText: qsTr("Choose application") headerText: qsTr("Choose application")
} }
ListView { ListViewType {
id: listView id: listView
Layout.fillWidth: true Layout.fillWidth: true
@ -66,11 +66,6 @@ DrawerType2 {
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
clip: true
interactive: true
property bool isFocusable: true
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxyInstalledAppsModel id: proxyInstalledAppsModel
sourceModel: installedAppsModel sourceModel: installedAppsModel
@ -81,44 +76,37 @@ DrawerType2 {
} }
} }
ScrollBar.vertical: ScrollBarType {}
ButtonGroup { ButtonGroup {
id: buttonGroup id: buttonGroup
} }
delegate: Item { delegate: ColumnLayout {
implicitWidth: root.width id: delegateContent
implicitHeight: delegateContent.implicitHeight
ColumnLayout { width: listView.width
id: delegateContent
anchors.fill: parent RowLayout {
CheckBoxType {
Layout.fillWidth: true
RowLayout { text: appName
CheckBoxType { checked: isAppSelected
Layout.fillWidth: true onCheckedChanged: {
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
text: appName
checked: isAppSelected
onCheckedChanged: {
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
}
}
Image {
source: "image://installedAppImage/" + appIcon
sourceSize.width: 24
sourceSize.height: 24
Layout.rightMargin: 48
} }
} }
DividerType {} Image {
source: "image://installedAppImage/" + appIcon
sourceSize.width: 24
sourceSize.height: 24
Layout.rightMargin: 48
}
} }
DividerType {}
} }
} }
} }

View file

@ -49,7 +49,7 @@ DrawerType2 {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButtonLayout.bottom anchors.top: backButtonLayout.bottom
@ -57,14 +57,8 @@ DrawerType2 {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
property bool isFocusable: true
property int selectedIndex: LanguageModel.currentLanguageIndex property int selectedIndex: LanguageModel.currentLanguageIndex
clip: true
reuseItems: true
ScrollBar.vertical: ScrollBarType {}
model: LanguageModel model: LanguageModel
ButtonGroup { ButtonGroup {

View file

@ -15,7 +15,7 @@ import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
import "../Config" import "../Config"
ListView { ListViewType {
id: root id: root
property int selectedIndex: ServersModel.defaultIndex property int selectedIndex: ServersModel.defaultIndex
@ -28,10 +28,6 @@ ListView {
model: ServersModel model: ServersModel
ScrollBar.vertical: ScrollBarType {}
property bool isFocusable: true
Connections { Connections {
target: ServersModel target: ServersModel
function onDefaultServerIndexChanged(serverIndex) { function onDefaultServerIndexChanged(serverIndex) {
@ -39,9 +35,6 @@ ListView {
} }
} }
clip: true
reuseItems: true
delegate: Item { delegate: Item {
id: menuContentDelegate id: menuContentDelegate
objectName: "menuContentDelegate" objectName: "menuContentDelegate"

View file

@ -13,78 +13,64 @@ import "../Controls2"
import "../Controls2/TextTypes" import "../Controls2/TextTypes"
ListView { ListViewType {
id: root id: root
width: parent.width anchors.fill: parent
height: root.contentItem.height
clip: true delegate: ColumnLayout {
reuseItems: true width: root.width
property bool isFocusable: false LabelWithButtonType {
Layout.fillWidth: true
delegate: Item { text: name
implicitWidth: root.width descriptionText: description
implicitHeight: delegateContent.implicitHeight rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
ColumnLayout { clickedFunction: function() {
id: delegateContent if (isInstalled) {
var containerIndex = root.model.mapToSource(index)
ContainersModel.setProcessedContainerIndex(containerIndex)
anchors.fill: parent if (serviceType !== ProtocolEnum.Other) {
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
LabelWithButtonType {
id: containerRadioButton
implicitWidth: parent.width
text: name
descriptionText: description
rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
clickedFunction: function() {
if (isInstalled) {
var containerIndex = root.model.mapToSource(index)
ContainersModel.setProcessedContainerIndex(containerIndex)
if (serviceType !== ProtocolEnum.Other) {
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
ProtocolsModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolRaw)
return
}
}
switch (containerIndex) {
case ContainerEnum.Ipsec: {
ProtocolsModel.updateModel(config) ProtocolsModel.updateModel(config)
PageController.goToPage(PageEnum.PageProtocolRaw) PageController.goToPage(PageEnum.PageProtocolRaw)
break return
} }
case ContainerEnum.Dns: {
PageController.goToPage(PageEnum.PageServiceDnsSettings)
break
}
default: {
ProtocolsModel.updateModel(config)
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
}
}
} else {
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
} }
}
MouseArea { switch (containerIndex) {
anchors.fill: parent case ContainerEnum.Ipsec: {
cursorShape: Qt.PointingHandCursor ProtocolsModel.updateModel(config)
enabled: false PageController.goToPage(PageEnum.PageProtocolRaw)
break
}
case ContainerEnum.Dns: {
PageController.goToPage(PageEnum.PageServiceDnsSettings)
break
}
default: {
ProtocolsModel.updateModel(config)
PageController.goToPage(PageEnum.PageSettingsServerProtocol)
}
}
} else {
ContainersModel.setProcessedContainerIndex(root.model.mapToSource(index))
InstallController.setShouldCreateServer(false)
PageController.goToPage(PageEnum.PageSetupWizardProtocolSettings)
} }
} }
DividerType {} MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
enabled: false
}
} }
DividerType {}
} }
} }

View file

@ -53,7 +53,7 @@ DrawerType2 {
headerText: root.headerText headerText: root.headerText
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: header.bottom anchors.top: header.bottom
@ -61,14 +61,7 @@ DrawerType2 {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
property bool isFocusable: true model: 1 // fake model to force the ListView to be created without a model
ScrollBar.vertical: ScrollBarType {}
model: 1
clip: true
reuseItems: true
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -185,9 +178,21 @@ DrawerType2 {
Connections { Connections {
target: copyNativeConfigStringButton target: copyNativeConfigStringButton
function onClicked() { function onClicked() {
nativeConfigString.selectAll() const headerItem = configListView.headerItem;
nativeConfigString.copy() if (!headerItem) {
nativeConfigString.select(0, 0) console.error("Failed to copy: header item not found in ListView")
return
}
const nativeConfigStringItem = configListView.findChildWithObjectName(headerItem.children, "nativeConfigString");
if (!nativeConfigStringItem) {
console.error("Failed to copy: nativeConfigString item not found in ListView")
return
}
nativeConfigStringItem.selectAll()
nativeConfigStringItem.copy()
nativeConfigStringItem.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
} }
} }
@ -195,11 +200,22 @@ DrawerType2 {
Connections { Connections {
target: copyConfigTextButton target: copyConfigTextButton
function onClicked() { function onClicked() {
configText.selectAll() const headerItem = configListView.headerItem;
configText.copy() if (!headerItem) {
configText.select(0, 0) console.error("Failed to copy: header item not found in ListView")
return
}
const configTextItem = configListView.findChildWithObjectName(headerItem.children, "configText");
if (!configTextItem) {
console.error("Failed to copy: configText item not found in ListView")
return
}
configTextItem.selectAll()
configTextItem.copy()
configTextItem.select(0, 0)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
header.forceActiveFocus()
} }
} }
@ -214,30 +230,37 @@ DrawerType2 {
backButtonFunction: function() { configContentDrawer.closeTriggered() } backButtonFunction: function() { configContentDrawer.closeTriggered() }
} }
FlickableType { ListViewType {
id: configListView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout { model: 1 // fake model to force the ListView to be created without a model
id: configContent
anchors.fill: parent header: ColumnLayout {
anchors.rightMargin: 16 width: configListView.width
anchors.leftMargin: 16
Header2Type { Header2Type {
id: configContentHeader id: configContentHeader
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: root.configContentHeaderText headerText: root.configContentHeaderText
} }
TextField { TextField {
id: nativeConfigString id: nativeConfigString
objectName: "nativeConfigString"
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: false visible: false
text: ExportController.nativeConfigString text: ExportController.nativeConfigString
@ -248,10 +271,13 @@ DrawerType2 {
TextArea { TextArea {
id: configText id: configText
objectName: "configText"
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.bottomMargin: 16 Layout.bottomMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
padding: 0 padding: 0
leftPadding: 0 leftPadding: 0

View file

@ -29,8 +29,6 @@ Button {
property bool squareLeftSide: false property bool squareLeftSide: false
property FlickableType parentFlickable
property var clickedFunc property var clickedFunc
property alias buttonTextLabel: buttonText property alias buttonTextLabel: buttonText
@ -65,14 +63,6 @@ Button {
hoverEnabled: true hoverEnabled: true
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(this)
}
}
}
background: Rectangle { background: Rectangle {
id: focusBorder id: focusBorder

View file

@ -27,8 +27,6 @@ Button {
property alias focusItem: rightImage property alias focusItem: rightImage
property FlickableType parentFlickable
hoverEnabled: true hoverEnabled: true
background: Rectangle { background: Rectangle {
@ -44,22 +42,6 @@ Button {
} }
} }
function ensureVisible(item) {
if (item.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
onFocusChanged: {
ensureVisible(root)
}
focusItem.onFocusChanged: {
root.ensureVisible(focusItem)
}
contentItem: Item { contentItem: Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right

View file

@ -34,13 +34,30 @@ CheckBox {
property string imageSource: "qrc:/images/controls/check.svg" property string imageSource: "qrc:/images/controls/check.svg"
property var parentFlickable property bool isFocusable: true
onFocusChanged: {
if (root.activeFocus) { Keys.onTabPressed: {
if (root.parentFlickable) { FocusController.nextKeyTabItem()
root.parentFlickable.ensureVisible(root) }
}
} Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
} }
hoverEnabled: enabled ? true : false hoverEnabled: enabled ? true : false

View file

@ -9,6 +9,7 @@ import "TextTypes"
Item { Item {
id: root id: root
// property alias focusObjectName: eyeImage.objectName
property string text property string text
property int textMaximumLineCount: 2 property int textMaximumLineCount: 2
property int textElide: Qt.ElideRight property int textElide: Qt.ElideRight
@ -25,7 +26,6 @@ Item {
property alias rightButton: rightImage property alias rightButton: rightImage
property alias eyeButton: eyeImage property alias eyeButton: eyeImage
property FlickableType parentFlickable
property string textColor: AmneziaStyle.color.paleGray property string textColor: AmneziaStyle.color.paleGray
property string textDisabledColor: AmneziaStyle.color.mutedGray property string textDisabledColor: AmneziaStyle.color.mutedGray
@ -70,25 +70,6 @@ Item {
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
Connections {
target: rightImage
function onFocusChanged() {
if (rightImage.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor

View file

@ -6,33 +6,16 @@ ListView {
property bool isFocusable: true property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {} ScrollBar.vertical: ScrollBarType {}
clip: true clip: true
reuseItems: true reuseItems: true
snapMode: ListView.SnapToItem
function findChildWithObjectName(items, name) {
for (var i = 0; i < items.length; ++i) {
if (items[i].objectName === name)
return items[i];
}
return null;
}
} }

View file

@ -6,7 +6,7 @@ import Style 1.0
import "TextTypes" import "TextTypes"
ListView { ListViewType {
id: root id: root
property var rootWidth property var rootWidth
@ -25,13 +25,6 @@ ListView {
width: rootWidth width: rootWidth
height: root.contentItem.height height: root.contentItem.height
clip: true
reuseItems: true
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
ButtonGroup { ButtonGroup {
id: buttonGroup id: buttonGroup
} }

View file

@ -64,16 +64,6 @@ Switch {
hoverEnabled: enabled ? true : false hoverEnabled: enabled ? true : false
focusPolicy: Qt.TabFocus focusPolicy: Qt.TabFocus
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
indicator: Rectangle { indicator: Rectangle {
id: switcher id: switcher

View file

@ -21,15 +21,6 @@ Rectangle {
border.color: getBorderColor(borderNormalColor) border.color: getBorderColor(borderNormalColor)
radius: 16 radius: 16
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
MouseArea { MouseArea {
id: parentMouse id: parentMouse
anchors.fill: parent anchors.fill: parent
@ -54,6 +45,32 @@ Rectangle {
anchors.topMargin: 16 anchors.topMargin: 16
anchors.bottomMargin: 16 anchors.bottomMargin: 16
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
color: AmneziaStyle.color.paleGray color: AmneziaStyle.color.paleGray
selectionColor: AmneziaStyle.color.richBrown selectionColor: AmneziaStyle.color.richBrown
selectedTextColor: AmneziaStyle.color.paleGray selectedTextColor: AmneziaStyle.color.paleGray

View file

@ -31,15 +31,6 @@ Rectangle {
border.color: getBorderColor(borderNormalColor) border.color: getBorderColor(borderNormalColor)
radius: 16 radius: 16
property FlickableType parentFlickable: null
onFocusChanged: {
if (root.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
MouseArea { MouseArea {
id: parentMouse id: parentMouse
anchors.fill: parent anchors.fill: parent

View file

@ -37,19 +37,6 @@ Item {
implicitWidth: content.implicitWidth implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight implicitHeight: content.implicitHeight
property FlickableType parentFlickable
Connections {
target: textField
function onFocusChanged() {
if (textField.activeFocus) {
if (root.parentFlickable) {
root.parentFlickable.ensureVisible(root)
}
}
}
}
ColumnLayout { ColumnLayout {
id: content id: content
anchors.fill: parent anchors.fill: parent

View file

@ -20,7 +20,9 @@ PageType {
SortFilterProxyModel { SortFilterProxyModel {
id: proxyServersModel id: proxyServersModel
sourceModel: ServersModel sourceModel: ServersModel
filters: [ filters: [
ValueFilter { ValueFilter {
roleName: "isCurrentlyProcessed" roleName: "isCurrentlyProcessed"
@ -29,67 +31,55 @@ PageType {
] ]
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.fill: parent anchors.fill: parent
contentHeight: content.height
Column { spacing: 16
id: content
anchors.top: parent.top model: proxyServersModel
anchors.left: parent.left
anchors.right: parent.right
spacing: 16 delegate: ColumnLayout {
width: listView.width
Repeater { BaseHeaderType {
model: proxyServersModel Layout.fillWidth: true
delegate: Item { Layout.topMargin: 20
implicitWidth: parent.width Layout.leftMargin: 16
implicitHeight: delegateContent.implicitHeight Layout.rightMargin: 16
ColumnLayout { headerText: qsTr("Removing services from %1").arg(name)
id: delegateContent }
anchors.fill: parent ProgressBarType {
anchors.rightMargin: 16 id: progressBar
anchors.leftMargin: 16
BaseHeaderType { Layout.fillWidth: true
Layout.fillWidth: true Layout.topMargin: 32
Layout.topMargin: 20 Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Removing services from %1").arg(name) Timer {
} id: timer
ProgressBarType { interval: 300
id: progressBar repeat: true
running: true
Layout.fillWidth: true onTriggered: {
Layout.topMargin: 32 progressBar.value += 0.003
Timer {
id: timer
interval: 300
repeat: true
running: true
onTriggered: {
progressBar.value += 0.003
}
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
text: qsTr("Usually it takes no more than 5 minutes")
}
} }
} }
} }
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Usually it takes no more than 5 minutes")
}
} }
} }
} }

View file

@ -25,23 +25,17 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BaseHeaderType { BaseHeaderType {
id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
@ -50,16 +44,14 @@ PageType {
} }
} }
model: 1 model: 1 // fake model to force the ListView to be created without a model
clip: true
spacing: 16 spacing: 16
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
TextFieldWithHeaderType { TextFieldWithHeaderType {
id: passwordTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.topMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
@ -87,8 +79,6 @@ PageType {
width: listView.width width: listView.width
SwitcherType { SwitcherType {
id: switcher
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.rightMargin: 16 Layout.rightMargin: 16

View file

@ -30,335 +30,223 @@ PageType {
} }
} }
ListView { ListViewType {
id: listview id: listView
anchors.top: backButtonLayout.bottom anchors.top: backButtonLayout.bottom
anchors.bottom: saveButton.top anchors.bottom: saveButton.top
width: parent.width width: parent.width
clip: true
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
model: AwgConfigModel model: AwgConfigModel
delegate: Item { delegate: ColumnLayout {
id: delegateItem width: listView.width
implicitWidth: listview.width
implicitHeight: col.implicitHeight
property alias mtuTextField: mtuTextField
property bool isSaveButtonEnabled: mtuTextField.errorText === "" && property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" && junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" && junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" junkPacketCountTextField.errorText === ""
ColumnLayout { spacing: 0
id: col
anchors.top: parent.top BaseHeaderType {
anchors.left: parent.left Layout.fillWidth: true
anchors.right: parent.right Layout.leftMargin: 16
Layout.rightMargin: 16
anchors.leftMargin: 16 headerText: qsTr("AmneziaWG settings")
anchors.rightMargin: 16 }
spacing: 0 TextFieldWithHeaderType {
id: mtuTextField
BaseHeaderType { Layout.fillWidth: true
Layout.fillWidth: true Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("AmneziaWG settings") headerText: qsTr("MTU")
} textField.text: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
TextFieldWithHeaderType { textField.onEditingFinished: {
id: mtuTextField if (textField.text !== clientMtu) {
Layout.fillWidth: true clientMtu = textField.text
Layout.topMargin: 40
headerText: qsTr("MTU")
textField.text: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== clientMtu) {
clientMtu = textField.text
}
} }
checkEmptyText: true
KeyNavigation.tab: junkPacketCountTextField.textField
} }
checkEmptyText: true
}
AwgTextField { TextFieldWithHeaderType {
id: junkPacketCountTextField id: junkPacketCountTextField
headerText: "Jc - Junk packet count"
textField.text: clientJunkPacketCount
textField.onEditingFinished: { Layout.fillWidth: true
if (textField.text !== clientJunkPacketCount) { Layout.topMargin: 16
clientJunkPacketCount = textField.text Layout.leftMargin: 16
} Layout.rightMargin: 16
}
KeyNavigation.tab: junkPacketMinSizeTextField.textField headerText: "Jc - Junk packet count"
} textField.text: clientJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
AwgTextField { textField.onEditingFinished: {
id: junkPacketMinSizeTextField if (textField.text !== clientJunkPacketCount) {
headerText: "Jmin - Junk packet minimum size" clientJunkPacketCount = textField.text
textField.text: clientJunkPacketMinSize
textField.onEditingFinished: {
if (textField.text !== clientJunkPacketMinSize) {
clientJunkPacketMinSize = textField.text
}
}
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
}
AwgTextField {
id: junkPacketMaxSizeTextField
headerText: "Jmax - Junk packet maximum size"
textField.text: clientJunkPacketMaxSize
textField.onEditingFinished: {
if (textField.text !== clientJunkPacketMaxSize) {
clientJunkPacketMaxSize = textField.text
}
} }
} }
AwgTextField { checkEmptyText: true
id: specialJunk1TextField }
headerText: qsTr("I1 - First special junk packet")
textField.text: clientSpecialJunk1
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== clientSpecialJunk1) { id: junkPacketMinSizeTextField
clientSpecialJunk1 = textField.text
} Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jmin - Junk packet minimum size"
textField.text: clientJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== clientJunkPacketMinSize) {
clientJunkPacketMinSize = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: specialJunk2TextField }
headerText: qsTr("I2 - Second special junk packet")
textField.text: clientSpecialJunk2
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== clientSpecialJunk2) { id: junkPacketMaxSizeTextField
clientSpecialJunk2 = textField.text
} Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: "Jmax - Junk packet maximum size"
textField.text: clientJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== clientJunkPacketMaxSize) {
clientJunkPacketMaxSize = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: specialJunk3TextField
headerText: qsTr("I3 - Third special junk packet")
textField.text: clientSpecialJunk3
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { }
if (textField.text !== clientSpecialJunk3) {
clientSpecialJunk3 = textField.text
}
}
}
AwgTextField { Header2TextType {
id: specialJunk4TextField Layout.fillWidth: true
headerText: qsTr("I4 - Fourth special junk packet") Layout.topMargin: 16
textField.text: clientSpecialJunk4 Layout.leftMargin: 16
textField.validator: null Layout.rightMargin: 16
checkEmptyText: false
textField.onEditingFinished: { text: qsTr("Server settings")
if (textField.text !== clientSpecialJunk4) { }
clientSpecialJunk4 = textField.text
}
}
}
AwgTextField { TextFieldWithHeaderType {
id: specialJunk5TextField id: portTextField
headerText: qsTr("I5 - Fifth special junk packet")
textField.text: clientSpecialJunk5
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { Layout.fillWidth: true
if (textField.text !== clientSpecialJunk5 ) { Layout.topMargin: 8
clientSpecialJunk5 = textField.text Layout.leftMargin: 16
} Layout.rightMargin: 16
}
}
AwgTextField { enabled: false
id: controlledJunk1TextField
headerText: qsTr("J1 - First controlled junk packet")
textField.text: clientControlledJunk1
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { headerText: qsTr("Port")
if (textField.text !== clientControlledJunk1) { textField.text: port
clientControlledJunk1 = textField.text }
}
}
}
AwgTextField { TextFieldWithHeaderType {
id: controlledJunk2TextField id: initPacketJunkSizeTextField
headerText: qsTr("J2 - Second controlled junk packet")
textField.text: clientControlledJunk2
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { Layout.fillWidth: true
if (textField.text !== clientControlledJunk2) { Layout.topMargin: 16
clientControlledJunk2 = textField.text Layout.leftMargin: 16
} Layout.rightMargin: 16
}
}
AwgTextField { enabled: false
id: controlledJunk3TextField
headerText: qsTr("J3 - Third controlled junk packet")
textField.text: clientControlledJunk3
textField.validator: null
checkEmptyText: false
textField.onEditingFinished: { headerText: "S1 - Init packet junk size"
if (textField.text !== clientControlledJunk3) { textField.text: serverInitPacketJunkSize
clientControlledJunk3 = textField.text }
}
}
}
AwgTextField { TextFieldWithHeaderType {
id: iTimeTextField id: responsePacketJunkSizeTextField
headerText: qsTr("Itime - Special handshake timeout")
textField.text: clientSpecialHandshakeTimeout
checkEmptyText: false
textField.onEditingFinished: { Layout.fillWidth: true
if (textField.text !== clientSpecialHandshakeTimeout) { Layout.topMargin: 16
clientSpecialHandshakeTimeout = textField.text Layout.leftMargin: 16
} Layout.rightMargin: 16
}
}
Header2TextType { enabled: false
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Server settings") headerText: "S2 - Response packet junk size"
} textField.text: serverResponsePacketJunkSize
}
AwgTextField { TextFieldWithHeaderType {
id: portTextField id: initPacketMagicHeaderTextField
enabled: false
headerText: qsTr("Port") Layout.fillWidth: true
textField.text: port Layout.topMargin: 16
} Layout.leftMargin: 16
Layout.rightMargin: 16
AwgTextField { enabled: false
id: initPacketJunkSizeTextField
enabled: false
headerText: "S1 - Init packet junk size" headerText: "H1 - Init packet magic header"
textField.text: serverInitPacketJunkSize textField.text: serverInitPacketMagicHeader
} }
AwgTextField { TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField id: responsePacketMagicHeaderTextField
enabled: false
headerText: "S2 - Response packet junk size" Layout.fillWidth: true
textField.text: serverResponsePacketJunkSize Layout.topMargin: 16
} Layout.leftMargin: 16
Layout.rightMargin: 16
// AwgTextField { enabled: false
// id: cookieReplyPacketJunkSizeTextField
// enabled: false
// headerText: "S3 - Cookie Reply packet junk size" headerText: "H2 - Response packet magic header"
// textField.text: serverCookieReplyPacketJunkSize textField.text: serverResponsePacketMagicHeader
// } }
// AwgTextField { TextFieldWithHeaderType {
// id: transportPacketJunkSizeTextField id: underloadPacketMagicHeaderTextField
// enabled: false
// headerText: "S4 - Transport packet junk size" Layout.fillWidth: true
// textField.text: serverTransportPacketJunkSize Layout.topMargin: 16
// } Layout.leftMargin: 16
Layout.rightMargin: 16
AwgTextField { enabled: false
id: initPacketMagicHeaderTextField
enabled: false
headerText: "H1 - Init packet magic header" headerText: "H3 - Underload packet magic header"
textField.text: serverInitPacketMagicHeader textField.text: serverUnderloadPacketMagicHeader
} }
AwgTextField { TextFieldWithHeaderType {
id: responsePacketMagicHeaderTextField id: transportPacketMagicHeaderTextField
enabled: false
headerText: "H2 - Response packet magic header" Layout.fillWidth: true
textField.text: serverResponsePacketMagicHeader Layout.topMargin: 16
} Layout.leftMargin: 16
Layout.rightMargin: 16
AwgTextField { enabled: false
id: underloadPacketMagicHeaderTextField
enabled: false
headerText: "H3 - Underload packet magic header"
textField.text: serverUnderloadPacketMagicHeader
}
AwgTextField {
id: transportPacketMagicHeaderTextField
enabled: false
headerText: "H4 - Transport packet magic header"
textField.text: serverTransportPacketMagicHeader
}
headerText: "H4 - Transport packet magic header"
textField.text: serverTransportPacketMagicHeader
} }
} }
} }
@ -375,18 +263,17 @@ PageType {
anchors.rightMargin: 16 anchors.rightMargin: 16
anchors.leftMargin: 16 anchors.leftMargin: 16
enabled: listview.currentItem.isSaveButtonEnabled enabled: listView.currentItem.isSaveButtonEnabled
text: qsTr("Save") text: qsTr("Save")
onActiveFocusChanged: { onActiveFocusChanged: {
if(activeFocus) { if(activeFocus) {
listview.positionViewAtEnd() listView.positionViewAtEnd()
} }
} }
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?") var headerText = qsTr("Save settings?")
var descriptionText = qsTr("Only the settings for this device will be changed") var descriptionText = qsTr("Only the settings for this device will be changed")
var yesButtonText = qsTr("Continue") var yesButtonText = qsTr("Continue")
@ -401,11 +288,9 @@ PageType {
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig()) InstallController.updateContainer(AwgConfigModel.getConfig())
} }
var noButtonFunction = function() {
if (!GC.isMobile()) { var noButtonFunction = function() {}
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }

View file

@ -33,320 +33,339 @@ PageType {
} }
} }
ListView { ListViewType {
id: listview id: listView
property bool isFocusable: true
anchors.top: backButtonLayout.bottom anchors.top: backButtonLayout.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
clip: true
model: AwgConfigModel model: AwgConfigModel
delegate: Item { delegate: ColumnLayout {
id: delegateItem id: delegateItem
implicitWidth: listview.width
implicitHeight: col.implicitHeight width: listView.width
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
ColumnLayout { spacing: 0
id: col
anchors.top: parent.top BaseHeaderType {
anchors.left: parent.left Layout.fillWidth: true
anchors.right: parent.right Layout.leftMargin: 16
Layout.rightMargin: 16
anchors.leftMargin: 16 headerText: qsTr("AmneziaWG settings")
anchors.rightMargin: 16 }
spacing: 0 TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
BaseHeaderType { Layout.fillWidth: true
Layout.fillWidth: true Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("AmneziaWG settings") enabled: delegateItem.isEnabled
}
TextFieldWithHeaderType { headerText: qsTr("VPN address subnet")
id: vpnAddressSubnetTextField textField.text: subnetAddress
Layout.fillWidth: true textField.onEditingFinished: {
Layout.topMargin: 40 if (textField.text !== subnetAddress) {
subnetAddress = textField.text
enabled: delegateItem.isEnabled
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
textField.onEditingFinished: {
if (textField.text !== subnetAddress) {
subnetAddress = textField.text
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
AwgTextField {
id: junkPacketCountTextField
headerText: qsTr("Jc - Junk packet count")
textField.text: serverJunkPacketCount
textField.onEditingFinished: {
if (textField.text !== serverJunkPacketCount) {
serverJunkPacketCount = textField.text
}
} }
} }
AwgTextField { checkEmptyText: true
id: junkPacketMinSizeTextField }
headerText: qsTr("Jmin - Junk packet minimum size")
textField.text: serverJunkPacketMinSize
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== serverJunkPacketMinSize) { id: portTextField
serverJunkPacketMinSize = textField.text Layout.fillWidth: true
} Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: junkPacketMaxSizeTextField }
headerText: qsTr("Jmax - Junk packet maximum size")
textField.text: serverJunkPacketMaxSize
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== serverJunkPacketMaxSize) { id: junkPacketCountTextField
serverJunkPacketMaxSize = textField.text Layout.fillWidth: true
} Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jc - Junk packet count")
textField.text: serverJunkPacketCount
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text === "") {
textField.text = "0"
}
if (textField.text !== serverJunkPacketCount) {
serverJunkPacketCount = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: initPacketJunkSizeTextField }
headerText: qsTr("S1 - Init packet junk size")
textField.text: serverInitPacketJunkSize
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== serverInitPacketJunkSize) { id: junkPacketMinSizeTextField
serverInitPacketJunkSize = textField.text Layout.fillWidth: true
} Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jmin - Junk packet minimum size")
textField.text: serverJunkPacketMinSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== serverJunkPacketMinSize) {
serverJunkPacketMinSize = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: responsePacketJunkSizeTextField }
headerText: qsTr("S2 - Response packet junk size")
textField.text: serverResponsePacketJunkSize
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== serverResponsePacketJunkSize) { id: junkPacketMaxSizeTextField
serverResponsePacketJunkSize = textField.text Layout.fillWidth: true
} Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Jmax - Junk packet maximum size")
textField.text: serverJunkPacketMaxSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== serverJunkPacketMaxSize) {
serverJunkPacketMaxSize = textField.text
} }
} }
// AwgTextField { checkEmptyText: true
// id: cookieReplyPacketJunkSizeTextField }
// headerText: qsTr("S3 - Cookie reply packet junk size")
// textField.text: serverCookieReplyPacketJunkSize
// textField.onEditingFinished: { TextFieldWithHeaderType {
// if (textField.text !== serverCookieReplyPacketJunkSize) { id: initPacketJunkSizeTextField
// serverCookieReplyPacketJunkSize = textField.text Layout.fillWidth: true
// } Layout.topMargin: 16
// } Layout.leftMargin: 16
// } Layout.rightMargin: 16
// AwgTextField { headerText: qsTr("S1 - Init packet junk size")
// id: transportPacketJunkSizeTextField textField.text: serverInitPacketJunkSize
// headerText: qsTr("S4 - Transport packet junk size") textField.validator: IntValidator { bottom: 0 }
// textField.text: serverTransportPacketJunkSize
// textField.onEditingFinished: { textField.onEditingFinished: {
// if (textField.text !== serverTransportPacketJunkSize) { if (textField.text !== serverInitPacketJunkSize) {
// serverTransportPacketJunkSize = textField.text serverInitPacketJunkSize = textField.text
// }
// }
// }
AwgTextField {
id: initPacketMagicHeaderTextField
headerText: qsTr("H1 - Init packet magic header")
textField.text: serverInitPacketMagicHeader
textField.onEditingFinished: {
if (textField.text !== serverInitPacketMagicHeader) {
serverInitPacketMagicHeader = textField.text
}
} }
} }
AwgTextField { checkEmptyText: true
id: responsePacketMagicHeaderTextField
headerText: qsTr("H2 - Response packet magic header")
textField.text: serverResponsePacketMagicHeader
textField.onEditingFinished: { onActiveFocusChanged: {
if (textField.text !== serverResponsePacketMagicHeader) { if(activeFocus) {
serverResponsePacketMagicHeader = textField.text listview.positionViewAtEnd()
} }
}
}
TextFieldWithHeaderType {
id: responsePacketJunkSizeTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("S2 - Response packet junk size")
textField.text: serverResponsePacketJunkSize
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== serverResponsePacketJunkSize) {
serverResponsePacketJunkSize = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: underloadPacketMagicHeaderTextField
headerText: qsTr("H3 - Underload packet magic header")
textField.text: serverUnderloadPacketMagicHeader
textField.onEditingFinished: { onActiveFocusChanged: {
if (textField.text !== serverUnderloadPacketMagicHeader) { if(activeFocus) {
serverUnderloadPacketMagicHeader = textField.text listview.positionViewAtEnd()
} }
}
}
TextFieldWithHeaderType {
id: initPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H1 - Init packet magic header")
textField.text: serverInitPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== serverInitPacketMagicHeader) {
serverInitPacketMagicHeader = textField.text
} }
} }
AwgTextField { checkEmptyText: true
id: transportPacketMagicHeaderTextField }
headerText: qsTr("H4 - Transport packet magic header")
textField.text: serverTransportPacketMagicHeader
textField.onEditingFinished: { TextFieldWithHeaderType {
if (textField.text !== serverTransportPacketMagicHeader) { id: responsePacketMagicHeaderTextField
serverTransportPacketMagicHeader = textField.text Layout.fillWidth: true
} Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H2 - Response packet magic header")
textField.text: serverResponsePacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== serverResponsePacketMagicHeader) {
serverResponsePacketMagicHeader = textField.text
} }
} }
checkEmptyText: true
}
BasicButtonType { TextFieldWithHeaderType {
id: saveRestartButton id: transportPacketMagicHeaderTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.fillWidth: true headerText: qsTr("H4 - Transport packet magic header")
Layout.topMargin: 24 textField.text: serverTransportPacketMagicHeader
Layout.bottomMargin: 24 textField.validator: IntValidator { bottom: 0 }
enabled: underloadPacketMagicHeaderTextField.errorText === "" && textField.onEditingFinished: {
transportPacketMagicHeaderTextField.errorText === "" && if (textField.text !== serverTransportPacketMagicHeader) {
responsePacketMagicHeaderTextField.errorText === "" && serverTransportPacketMagicHeader = textField.text
initPacketMagicHeaderTextField.errorText === "" && }
responsePacketJunkSizeTextField.errorText === "" && }
// cookieReplyHeaderJunkTextField.errorText === "" &&
// transportHeaderJunkTextField.errorText === "" &&
initPacketJunkSizeTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" &&
portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
text: qsTr("Save") checkEmptyText: true
}
onActiveFocusChanged: { TextFieldWithHeaderType {
if(activeFocus) { id: underloadPacketMagicHeaderTextField
listview.positionViewAtEnd() Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("H3 - Underload packet magic header")
textField.text: serverUnderloadPacketMagicHeader
textField.validator: IntValidator { bottom: 0 }
textField.onEditingFinished: {
if (textField.text !== serverUnderloadPacketMagicHeader) {
serverUnderloadPacketMagicHeader = textField.text
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
transportPacketMagicHeaderTextField.errorText === "" &&
responsePacketMagicHeaderTextField.errorText === "" &&
initPacketMagicHeaderTextField.errorText === "" &&
responsePacketJunkSizeTextField.errorText === "" &&
initPacketJunkSizeTextField.errorText === "" &&
junkPacketMaxSizeTextField.errorText === "" &&
junkPacketMinSizeTextField.errorText === "" &&
junkPacketCountTextField.errorText === "" &&
portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
text: qsTr("Save")
onActiveFocusChanged: {
if(activeFocus) {
listView.positionViewAtEnd()
}
}
clickedFunc: function() {
if (delegateItem.isEnabled) {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text,
transportPacketMagicHeaderTextField.textField.text,
responsePacketMagicHeaderTextField.textField.text,
initPacketMagicHeaderTextField.textField.text)) {
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
return
}
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
parseInt(responsePacketJunkSizeTextField.textField.text))) {
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
return
} }
} }
clickedFunc: function() { var headerText = qsTr("Save settings?")
forceActiveFocus() var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
if (delegateItem.isEnabled) { var yesButtonFunction = function() {
if (AwgConfigModel.isHeadersEqual(underloadPacketMagicHeaderTextField.textField.text, if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
transportPacketMagicHeaderTextField.textField.text, PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
responsePacketMagicHeaderTextField.textField.text, return
initPacketMagicHeaderTextField.textField.text)) {
PageController.showErrorMessage(qsTr("The values of the H1-H4 fields must be unique"))
return
}
if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
parseInt(responsePacketJunkSizeTextField.textField.text))) {
PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92)"))
return
}
// if (AwgConfigModel.isPacketSizeEqual(parseInt(initPacketJunkSizeTextField.textField.text),
// parseInt(responsePacketJunkSizeTextField.textField.text),
// parseInt(cookieReplyPacketJunkSizeTextField.textField.text),
// parseInt(transportPacketJunkSizeTextField.textField.text))) {
// PageController.showErrorMessage(qsTr("The value of the field S1 + message initiation size (148) must not equal S2 + message response size (92) + S3 + cookie reply size (64) + S4 + transport packet size (32)"))
// return
// }
} }
var headerText = qsTr("Save settings?") PageController.goToPage(PageEnum.PageSetupWizardInstalling);
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.") InstallController.updateContainer(AwgConfigModel.getConfig())
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(AwgConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
var noButtonFunction = function() {}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
} }

View file

@ -16,212 +16,161 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType {
id: backButton
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.left: parent.left
anchors.right: parent.right
Column { property int selectedIndex: 0
id: content
anchors.top: parent.top enabled: ServersModel.isProcessedServerHasWriteAccess()
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() header: ColumnLayout {
ListView { width: listView.width
id: listview
property int selectedIndex: 0 BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
width: parent.width headerText: qsTr("Cloak settings")
height: listview.contentItem.height }
}
clip: true model: CloakConfigModel
reuseItems: true
model: CloakConfigModel delegate: ColumnLayout {
delegate: Item { width: listView.width
id: delegateItem
property alias trafficFromField: trafficFromField property alias trafficFromField: trafficFromField
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
implicitWidth: listview.width spacing: 0
implicitHeight: col.implicitHeight
ColumnLayout { TextFieldWithHeaderType {
id: col id: trafficFromField
anchors.top: parent.top Layout.fillWidth: true
anchors.left: parent.left Layout.topMargin: 32
anchors.right: parent.right Layout.leftMargin: 16
Layout.rightMargin: 16
anchors.leftMargin: 16 headerText: qsTr("Disguised as traffic from")
anchors.rightMargin: 16 textField.text: site
spacing: 0 textField.onEditingFinished: {
if (textField.text !== site) {
var tmpText = textField.text
tmpText = tmpText.toLocaleLowerCase()
BaseHeaderType { var indexHttps = tmpText.indexOf("https://")
Layout.fillWidth: true if (indexHttps === 0) {
headerText: qsTr("Cloak settings") tmpText = textField.text.substring(8)
} } else {
site = textField.text
TextFieldWithHeaderType {
id: trafficFromField
Layout.fillWidth: true
Layout.topMargin: 32
enabled: delegateItem.isEnabled
headerText: qsTr("Disguised as traffic from")
textField.text: site
textField.onEditingFinished: {
if (textField.text !== site) {
var tmpText = textField.text
tmpText = tmpText.toLocaleLowerCase()
var indexHttps = tmpText.indexOf("https://")
if (indexHttps === 0) {
tmpText = textField.text.substring(8)
} else {
site = textField.text
}
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
model: ListModel {
ListElement { name : "chacha20-ietf-poly1305" }
ListElement { name : "xchacha20-ietf-poly1305" }
ListElement { name : "aes-256-gcm" }
ListElement { name : "aes-192-gcm" }
ListElement { name : "aes-128-gcm" }
}
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
cipherDropDown.text = cipher
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
selectedIndex = i
}
}
}
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: trafficFromField.errorText === "" &&
portTextField.errorText === ""
text: qsTr("Save")
clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.updateContainer(CloakConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
} }
} }
} }
} }
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
}
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
model: ListModel {
ListElement { name : "chacha20-ietf-poly1305" }
ListElement { name : "xchacha20-ietf-poly1305" }
ListElement { name : "aes-256-gcm" }
ListElement { name : "aes-192-gcm" }
ListElement { name : "aes-128-gcm" }
}
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
cipherDropDown.text = cipher
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
selectedIndex = i
}
}
}
}
}
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Save")
clickedFunc: function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(CloakConfigModel.getConfig())
}
}
} }
} }
} }

View file

@ -17,428 +17,465 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.right: parent.right
anchors.left: parent.left
Column { enabled: ServersModel.isProcessedServerHasWriteAccess()
id: content
anchors.top: parent.top header: ColumnLayout {
anchors.left: parent.left width: listView.width
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
ListView { headerText: qsTr("OpenVPN settings")
id: listview }
}
width: parent.width model: ListModel {
height: listview.contentItem.height ListElement { type: "subnetHeader" }
ListElement { type: "networkProtocolText" }
ListElement { type: "protoSelector" }
ListElement { type: "portTextField" }
ListElement { type: "encryptionSection" }
ListElement { type: "checkboxSection" }
ListElement { type: "clientCommands" }
ListElement { type: "serverCommands" }
}
clip: true delegate: DelegateChooser {
interactive: false
model: OpenVpnConfigModel role: "type"
delegate: Item { DelegateChoice {
id: delegateItem // property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
roleValue: "subnetHeader"
ColumnLayout {
width: listView.width
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField TextFieldWithHeaderType {
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() id: vpnAddressSubnetTextField
implicitWidth: listview.width Layout.fillWidth: true
implicitHeight: col.implicitHeight Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
ColumnLayout { headerText: qsTr("VPN address subnet")
id: col textField.text: OpenVpnConfigModel.subnetAddress
anchors.top: parent.top textField.onEditingFinished: {
anchors.left: parent.left if (textField.text !== OpenVpnConfigModel.subnetAddress) {
anchors.right: parent.right OpenVpnConfigModel.subnetAddress = textField.text
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
headerText: qsTr("OpenVPN settings")
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 32
enabled: delegateItem.isEnabled
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
parentFlickable: fl
textField.onEditingFinished: {
if (textField.text !== subnetAddress) {
subnetAddress = textField.text
}
} }
}
}
}
}
checkEmptyText: true DelegateChoice {
roleValue: "networkProtocolText"
ColumnLayout {
width: listView.width
ParagraphTextType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Network protocol")
}
}
}
DelegateChoice {
roleValue: "protoSelector"
ColumnLayout {
width: listView.width
TransportProtoSelector {
id: transportProtoSelector
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
rootWidth: root.width
enabled: OpenVpnConfigModel.isTransportProtoEditable
currentIndex: {
return OpenVpnConfigModel.transportProto === "tcp" ? 1 : 0
} }
ParagraphTextType { onCurrentIndexChanged: {
Layout.fillWidth: true if (OpenVpnConfigModel.transportProto === "tcp" && currentIndex === 0) {
Layout.topMargin: 32 OpenVpnConfigModel.transportProto = "udp"
} else if (OpenVpnConfigModel.transportProto === "udp" && currentIndex === 1) {
text: qsTr("Network protocol") OpenVpnConfigModel.transportProto = "tcp"
}
} }
}
}
}
DelegateChoice {
roleValue: "portTextField"
ColumnLayout {
width: listView.width
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: OpenVpnConfigModel.isPortEditable
headerText: qsTr("Port")
textField.text: OpenVpnConfigModel.port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== OpenVpnConfigModel.port) {
OpenVpnConfigModel.port = textField.text
}
}
}
}
}
DelegateChoice {
roleValue: "encryptionSection"
ColumnLayout {
width: listView.width
SwitcherType {
id: autoNegotiateEncryprionSwitcher
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Auto-negotiate encryption")
checked: OpenVpnConfigModel.autoNegotiateEncryption
onCheckedChanged: {
if (checked !== OpenVpnConfigModel.autoNegotiateEncryprion) {
OpenVpnConfigModel.autoNegotiateEncryprion = checked
}
}
}
DropDownType {
id: hashDropDown
Layout.fillWidth: true
Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked
descriptionText: qsTr("Hash")
headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: hashListView
TransportProtoSelector {
id: transportProtoSelector
Layout.fillWidth: true
Layout.topMargin: 16
rootWidth: root.width rootWidth: root.width
enabled: isTransportProtoEditable model: ListModel {
ListElement { name : qsTr("SHA512") }
currentIndex: { ListElement { name : qsTr("SHA384") }
return transportProto === "tcp" ? 1 : 0 ListElement { name : qsTr("SHA256") }
ListElement { name : qsTr("SHA3-512") }
ListElement { name : qsTr("SHA3-384") }
ListElement { name : qsTr("SHA3-256") }
ListElement { name : qsTr("whirlpool") }
ListElement { name : qsTr("BLAKE2b512") }
ListElement { name : qsTr("BLAKE2s256") }
ListElement { name : qsTr("SHA1") }
} }
onCurrentIndexChanged: { clickedFunction: function() {
if (transportProto === "tcp" && currentIndex === 0) { hashDropDown.text = selectedText
transportProto = "udp" OpenVpnConfigModel.hash = hashDropDown.text
} else if (transportProto === "udp" && currentIndex === 1) { hashDropDown.closeTriggered()
transportProto = "tcp"
}
}
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
parentFlickable: fl
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
} }
checkEmptyText: true Component.onCompleted: {
} hashDropDown.text = OpenVpnConfigModel.hash
SwitcherType { for (var i = 0; i < hashListView.model.count; i++) {
id: autoNegotiateEncryprionSwitcher if (hashListView.model.get(i).name === hashDropDown.text) {
currentIndex = i
Layout.fillWidth: true
Layout.topMargin: 24
parentFlickable: fl
text: qsTr("Auto-negotiate encryption")
checked: autoNegotiateEncryprion
onCheckedChanged: {
if (checked !== autoNegotiateEncryprion) {
autoNegotiateEncryprion = checked
}
}
}
DropDownType {
id: hashDropDown
Layout.fillWidth: true
Layout.topMargin: 20
enabled: !autoNegotiateEncryprionSwitcher.checked
descriptionText: qsTr("Hash")
headerText: qsTr("Hash")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: hashListView
rootWidth: root.width
model: ListModel {
ListElement { name : qsTr("SHA512") }
ListElement { name : qsTr("SHA384") }
ListElement { name : qsTr("SHA256") }
ListElement { name : qsTr("SHA3-512") }
ListElement { name : qsTr("SHA3-384") }
ListElement { name : qsTr("SHA3-256") }
ListElement { name : qsTr("whirlpool") }
ListElement { name : qsTr("BLAKE2b512") }
ListElement { name : qsTr("BLAKE2s256") }
ListElement { name : qsTr("SHA1") }
}
clickedFunction: function() {
hashDropDown.text = selectedText
hash = hashDropDown.text
hashDropDown.closeTriggered()
}
Component.onCompleted: {
hashDropDown.text = hash
for (var i = 0; i < hashListView.model.count; i++) {
if (hashListView.model.get(i).name === hashDropDown.text) {
currentIndex = i
}
} }
} }
} }
} }
}
DropDownType { DropDownType {
id: cipherDropDown id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 16
enabled: !autoNegotiateEncryprionSwitcher.checked Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
descriptionText: qsTr("Cipher") enabled: !autoNegotiateEncryprionSwitcher.checked
headerText: qsTr("Cipher")
drawerParent: root descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
listView: ListViewWithRadioButtonType { drawerParent: root
id: cipherListView
rootWidth: root.width listView: ListViewWithRadioButtonType {
id: cipherListView
model: ListModel { rootWidth: root.width
ListElement { name : qsTr("AES-256-GCM") }
ListElement { name : qsTr("AES-192-GCM") }
ListElement { name : qsTr("AES-128-GCM") }
ListElement { name : qsTr("AES-256-CBC") }
ListElement { name : qsTr("AES-192-CBC") }
ListElement { name : qsTr("AES-128-CBC") }
ListElement { name : qsTr("ChaCha20-Poly1305") }
ListElement { name : qsTr("ARIA-256-CBC") }
ListElement { name : qsTr("CAMELLIA-256-CBC") }
ListElement { name : qsTr("none") }
}
clickedFunction: function() { model: ListModel {
cipherDropDown.text = selectedText ListElement { name : qsTr("AES-256-GCM") }
cipher = cipherDropDown.text ListElement { name : qsTr("AES-192-GCM") }
cipherDropDown.closeTriggered() ListElement { name : qsTr("AES-128-GCM") }
} ListElement { name : qsTr("AES-256-CBC") }
ListElement { name : qsTr("AES-192-CBC") }
ListElement { name : qsTr("AES-128-CBC") }
ListElement { name : qsTr("ChaCha20-Poly1305") }
ListElement { name : qsTr("ARIA-256-CBC") }
ListElement { name : qsTr("CAMELLIA-256-CBC") }
ListElement { name : qsTr("none") }
}
Component.onCompleted: { clickedFunction: function() {
cipherDropDown.text = cipher cipherDropDown.text = selectedText
OpenVpnConfigModel.cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
for (var i = 0; i < cipherListView.model.count; i++) { Component.onCompleted: {
if (cipherListView.model.get(i).name === cipherDropDown.text) { cipherDropDown.text = OpenVpnConfigModel.cipher
currentIndex = i
} for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
currentIndex = i
} }
} }
} }
} }
}
}
}
Rectangle { DelegateChoice {
id: contentRect roleValue: "checkboxSection"
Layout.fillWidth: true ColumnLayout {
Layout.topMargin: 32 width: listView.width
Layout.preferredHeight: checkboxLayout.implicitHeight
color: AmneziaStyle.color.onyxBlack
radius: 16
Connections { Rectangle {
target: tlsAuthCheckBox id: contentRect
enabled: !GC.isMobile()
function onFocusChanged() { Layout.fillWidth: true
if (tlsAuthCheckBox.activeFocus) { Layout.topMargin: 32
fl.ensureVisible(contentRect) Layout.leftMargin: 16
Layout.rightMargin: 16
Layout.preferredHeight: checkboxLayout.implicitHeight
color: AmneziaStyle.color.onyxBlack
radius: 16
ColumnLayout {
id: checkboxLayout
anchors.fill: parent
CheckBoxType {
id: tlsAuthCheckBox
Layout.fillWidth: true
text: qsTr("TLS auth")
checked: OpenVpnConfigModel.tlsAuth
onCheckedChanged: {
if (checked !== OpenVpnConfigModel.tlsAuth) {
console.log("tlsAuth changed to: " + checked)
OpenVpnConfigModel.tlsAuth = checked
} }
} }
} }
ColumnLayout { DividerType {}
id: checkboxLayout
anchors.fill: parent CheckBoxType {
CheckBoxType { id: blockDnsCheckBox
id: tlsAuthCheckBox
Layout.fillWidth: true
text: qsTr("TLS auth") Layout.fillWidth: true
checked: tlsAuth
onCheckedChanged: { text: qsTr("Block DNS requests outside of VPN")
if (checked !== tlsAuth) { checked: OpenVpnConfigModel.blockDns
console.log("tlsAuth changed to: " + checked)
tlsAuth = checked
}
}
}
DividerType {} onCheckedChanged: {
if (checked !== OpenVpnConfigModel.blockDns) {
CheckBoxType { OpenVpnConfigModel.blockDns = checked
id: blockDnsCheckBox
Layout.fillWidth: true
text: qsTr("Block DNS requests outside of VPN")
checked: blockDns
onCheckedChanged: {
if (checked !== blockDns) {
blockDns = checked
}
} }
} }
} }
} }
}
}
}
SwitcherType { DelegateChoice {
id: additionalClientCommandsSwitcher roleValue: "clientCommands"
Layout.fillWidth: true ColumnLayout {
Layout.topMargin: 32
parentFlickable: fl
checked: additionalClientCommands !== "" width: listView.width
text: qsTr("Additional client configuration commands") SwitcherType {
id: additionalClientCommandsSwitcher
onCheckedChanged: { Layout.fillWidth: true
if (!checked) { Layout.topMargin: 32
additionalClientCommands = "" Layout.leftMargin: 16
} Layout.rightMargin: 16
checked: OpenVpnConfigModel.additionalClientCommands !== ""
text: qsTr("Additional client configuration commands")
onCheckedChanged: {
if (!checked) {
OpenVpnConfigModel.additionalClientCommands = ""
}
// listView.positionViewAtIndex(index, ListView.Beginning)
}
}
TextAreaType {
id: additionalClientCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: additionalClientCommandsSwitcher.checked
textAreaText: OpenVpnConfigModel.additionalClientCommands
placeholderText: qsTr("Commands:")
textArea.onEditingFinished: {
if (OpenVpnConfigModel.additionalClientCommands !== textAreaText) {
OpenVpnConfigModel.additionalClientCommands = textAreaText
} }
} }
}
}
}
TextAreaType { DelegateChoice {
id: additionalClientCommandsTextArea roleValue: "serverCommands"
Layout.fillWidth: true ColumnLayout {
Layout.topMargin: 16 width: listView.width
visible: additionalClientCommandsSwitcher.checked SwitcherType {
id: additionalServerCommandsSwitcher
parentFlickable: fl Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
textAreaText: additionalClientCommands checked: OpenVpnConfigModel.additionalServerCommands !== ""
placeholderText: qsTr("Commands:")
textArea.onEditingFinished: { text: qsTr("Additional server configuration commands")
if (additionalClientCommands !== textAreaText) {
additionalClientCommands = textAreaText onCheckedChanged: {
} if (!checked) {
OpenVpnConfigModel.additionalServerCommands = ""
} }
// listView.positionViewAtIndex(index, ListView.Beginning)
} }
}
SwitcherType { TextAreaType {
id: additionalServerCommandsSwitcher id: additionalServerCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
checked: additionalServerCommands !== "" Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Additional server configuration commands") visible: additionalServerCommandsSwitcher.checked
onCheckedChanged: { textAreaText: OpenVpnConfigModel.additionalServerCommands
if (!checked) { placeholderText: qsTr("Commands:")
additionalServerCommands = ""
} textArea.onEditingFinished: {
if (OpenVpnConfigModel.additionalServerCommands !== textAreaText) {
OpenVpnConfigModel.additionalServerCommands = textAreaText
} }
} }
TextAreaType {
id: additionalServerCommandsTextArea
Layout.fillWidth: true
Layout.topMargin: 16
visible: additionalServerCommandsSwitcher.checked
textAreaText: additionalServerCommands
placeholderText: qsTr("Commands:")
parentFlickable: fl
textArea.onEditingFinished: {
if (additionalServerCommands !== textAreaText) {
additionalServerCommands = textAreaText
}
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: vpnAddressSubnetTextField.errorText === "" &&
portTextField.errorText === ""
text: qsTr("Save")
parentFlickable: fl
onClicked: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
}
} }
} }
} }
} }
footer: ColumnLayout {
width: listView.width
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Save")
clickedFunc: function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(OpenVpnConfigModel.getConfig())
}
}
}
} }
} }

View file

@ -19,164 +19,154 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: header id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
} listView.positionViewAtBeginning()
}
BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: header.bottom
anchors.left: parent.left anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
contentHeight: content.height anchors.left: parent.left
Column { header: ColumnLayout {
id: content width: listView.width
anchors.top: parent.top BaseHeaderType {
anchors.left: parent.left Layout.fillWidth: true
anchors.right: parent.right Layout.leftMargin: 16
anchors.topMargin: 32 Layout.rightMargin: 16
Layout.bottomMargin: 16
ListView { headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
id: listView }
width: parent.width }
height: contentItem.height
clip: true
interactive: false
model: ProtocolsModel
activeFocusOnTab: true model: ProtocolsModel
focus: true
delegate: Item { delegate: ColumnLayout {
implicitWidth: parent.width width: listView.width
implicitHeight: delegateContent.implicitHeight
property alias focusItem: button LabelWithButtonType {
id: button
ColumnLayout { Layout.fillWidth: true
id: delegateContent Layout.leftMargin: 16
Layout.rightMargin: 16
anchors.fill: parent text: qsTr("Show connection options")
LabelWithButtonType { clickedFunction: function() {
id: button configContentDrawer.openTriggered()
}
Layout.fillWidth: true MouseArea {
anchors.fill: button
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
text: qsTr("Show connection options") DividerType {}
clickedFunction: function() { DrawerType2 {
configContentDrawer.openTriggered() id: configContentDrawer
}
MouseArea { expandedHeight: root.height * 0.9
anchors.fill: button
cursorShape: Qt.PointingHandCursor parent: root
enabled: false anchors.fill: parent
expandedStateContent: Item {
implicitHeight: configContentDrawer.expandedHeight
BackButtonType {
id: drawerBackButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 16
backButtonFunction: function() {
configContentDrawer.closeTriggered()
}
}
ListViewType {
id: drawerListView
anchors.top: drawerBackButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: drawerListView.width
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName)
} }
} }
DividerType {} model: 1 // fake model to force the ListView to be created without a model
DrawerType2 { delegate: ColumnLayout {
id: configContentDrawer width: drawerListView.width
expandedHeight: root.height * 0.9 TextArea {
id: configText
parent: root Layout.fillWidth: true
anchors.fill: parent Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
expandedStateContent: Item { padding: 0
implicitHeight: configContentDrawer.expandedHeight height: 24
BackButtonType { color: AmneziaStyle.color.paleGray
id: backButton1 selectionColor: AmneziaStyle.color.richBrown
selectedTextColor: AmneziaStyle.color.paleGray
anchors.top: parent.top font.pixelSize: 16
anchors.left: parent.left font.weight: Font.Medium
anchors.right: parent.right font.family: "PT Root UI VF"
anchors.topMargin: 16
backButtonFunction: function() { text: rawConfig
configContentDrawer.closeTriggered()
}
}
FlickableType { wrapMode: Text.Wrap
anchors.top: backButton1.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
ColumnLayout { background: Rectangle {
id: configContent color: AmneziaStyle.color.transparent
anchors.fill: parent
anchors.rightMargin: 16
anchors.leftMargin: 16
Header2Type {
Layout.fillWidth: true
Layout.topMargin: 16
headerText: qsTr("Connection options %1").arg(protocolName)
}
TextArea {
id: configText
Layout.fillWidth: true
Layout.topMargin: 16
Layout.bottomMargin: 16
padding: 0
leftPadding: 0
height: 24
color: AmneziaStyle.color.paleGray
selectionColor: AmneziaStyle.color.richBrown
selectedTextColor: AmneziaStyle.color.paleGray
font.pixelSize: 16
font.weight: Font.Medium
font.family: "PT Root UI VF"
text: rawConfig
wrapMode: Text.Wrap
background: Rectangle {
color: AmneziaStyle.color.transparent
}
}
}
} }
} }
} }
} }
} }
} }
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: removeButton id: removeButton
@ -198,11 +188,7 @@ PageType {
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer() InstallController.removeProcessedContainer()
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }

View file

@ -16,179 +16,138 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.right: parent.right
anchors.left: parent.left
Column { enabled: ServersModel.isProcessedServerHasWriteAccess()
id: content
anchors.top: parent.top model: ShadowSocksConfigModel
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() delegate: ColumnLayout {
width: listView.width
ListView { spacing: 0
id: listview
width: parent.width BaseHeaderType {
height: listview.contentItem.height Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
clip: true headerText: qsTr("Shadowsocks settings")
interactive: false }
model: ShadowSocksConfigModel TextFieldWithHeaderType {
id: portTextField
delegate: Item { Layout.fillWidth: true
id: delegateItem Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() enabled: isPortEditable
implicitWidth: listview.width headerText: qsTr("Port")
implicitHeight: col.implicitHeight textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
ColumnLayout { textField.onEditingFinished: {
id: col if (textField.text !== port) {
port = textField.text
}
}
}
anchors.top: parent.top DropDownType {
anchors.left: parent.left id: cipherDropDown
anchors.right: parent.right
anchors.leftMargin: 16 Layout.fillWidth: true
anchors.rightMargin: 16 Layout.topMargin: 20
Layout.leftMargin: 16
Layout.rightMargin: 16
spacing: 0 enabled: isCipherEditable
BaseHeaderType { descriptionText: qsTr("Cipher")
Layout.fillWidth: true headerText: qsTr("Cipher")
headerText: qsTr("Shadowsocks settings")
}
TextFieldWithHeaderType { drawerParent: root
id: portTextField
Layout.fillWidth: true listView: ListViewWithRadioButtonType {
Layout.topMargin: 40
enabled: delegateItem.isEnabled id: cipherListView
headerText: qsTr("Port") rootWidth: root.width
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: { model: ListModel {
if (textField.text !== port) { ListElement { name : "chacha20-ietf-poly1305" }
port = textField.text ListElement { name : "xchacha20-ietf-poly1305" }
} ListElement { name : "aes-256-gcm" }
ListElement { name : "aes-192-gcm" }
ListElement { name : "aes-128-gcm" }
}
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
cipherDropDown.text = cipher
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
currentIndex = i
} }
checkEmptyText: true
}
DropDownType {
id: cipherDropDown
Layout.fillWidth: true
Layout.topMargin: 20
enabled: delegateItem.isEnabled
descriptionText: qsTr("Cipher")
headerText: qsTr("Cipher")
drawerParent: root
listView: ListViewWithRadioButtonType {
id: cipherListView
rootWidth: root.width
model: ListModel {
ListElement { name : "chacha20-ietf-poly1305" }
ListElement { name : "xchacha20-ietf-poly1305" }
ListElement { name : "aes-256-gcm" }
ListElement { name : "aes-192-gcm" }
ListElement { name : "aes-128-gcm" }
}
clickedFunction: function() {
cipherDropDown.text = selectedText
cipher = cipherDropDown.text
cipherDropDown.closeTriggered()
}
Component.onCompleted: {
cipherDropDown.text = cipher
for (var i = 0; i < cipherListView.model.count; i++) {
if (cipherListView.model.get(i).name === cipherDropDown.text) {
currentIndex = i
}
}
}
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: portTextField.errorText === ""
text: qsTr("Save")
clickedFunc: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
} }
} }
} }
} }
BasicButtonType {
id: saveRestartButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: isPortEditable | isCipherEditable
text: qsTr("Save")
clickedFunc: function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(ShadowSocksConfigModel.getConfig())
}
}
} }
} }
} }

View file

@ -16,160 +16,124 @@ import "../Components"
PageType { PageType {
id: root id: root
Item { BackButtonType {
id: focusItem id: backButton
onFocusChanged: {
if (activeFocus) {
fl.ensureVisible(focusItem)
}
}
KeyNavigation.tab: backButton
}
ColumnLayout {
id: backButtonLayout
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
KeyNavigation.tab: listview.currentItem.mtuTextField.textField listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + saveButton.implicitHeight + saveButton.anchors.bottomMargin + saveButton.anchors.topMargin anchors.right: parent.right
anchors.left: parent.left
Column { model: WireGuardConfigModel
id: content
anchors.top: parent.top delegate: ColumnLayout {
anchors.left: parent.left width: listView.width
anchors.right: parent.right
ListView { property alias mtuTextField: mtuTextField
id: listview property bool isSaveButtonEnabled: mtuTextField.errorText === ""
width: parent.width spacing: 0
height: listview.contentItem.height
clip: true BaseHeaderType {
interactive: false Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
model: WireGuardConfigModel headerText: qsTr("WG settings")
}
delegate: Item { TextFieldWithHeaderType {
id: delegateItem id: mtuTextField
implicitWidth: listview.width Layout.fillWidth: true
implicitHeight: col.implicitHeight Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
property alias mtuTextField: mtuTextField headerText: qsTr("MTU")
property bool isSaveButtonEnabled: mtuTextField.errorText === "" textField.text: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
ColumnLayout { textField.onEditingFinished: {
id: col if (textField.text !== clientMtu) {
clientMtu = textField.text
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
headerText: qsTr("WG settings")
}
TextFieldWithHeaderType {
id: mtuTextField
Layout.fillWidth: true
Layout.topMargin: 40
headerText: qsTr("MTU")
textField.text: clientMtu
textField.validator: IntValidator { bottom: 576; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== clientMtu) {
clientMtu = textField.text
}
}
checkEmptyText: true
KeyNavigation.tab: saveButton
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
text: qsTr("Server settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
enabled: false
headerText: qsTr("Port")
textField.text: port
}
} }
} }
checkEmptyText: true
}
Header2TextType {
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Server settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: false
headerText: qsTr("Port")
textField.text: port
} }
} }
}
BasicButtonType { footer: ColumnLayout {
id: saveButton width: listView.width
anchors.right: root.right BasicButtonType {
anchors.left: root.left id: saveButton
anchors.bottom: root.bottom
anchors.topMargin: 24 Layout.fillWidth: true
anchors.bottomMargin: 24 Layout.topMargin: 24
anchors.rightMargin: 16 Layout.bottomMargin: 24
anchors.leftMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16
enabled: listview.currentItem.isSaveButtonEnabled enabled: listView.currentItem.isSaveButtonEnabled
text: qsTr("Save") text: qsTr("Save")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus() var headerText = qsTr("Save settings?")
var headerText = qsTr("Save settings?") var descriptionText = qsTr("Only the settings for this device will be changed")
var descriptionText = qsTr("Only the settings for this device will be changed") var yesButtonText = qsTr("Continue")
var yesButtonText = qsTr("Continue") var noButtonText = qsTr("Cancel")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) { if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection")) PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return return
} }
PageController.goToPage(PageEnum.PageSetupWizardInstalling); PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(WireGuardConfigModel.getConfig()) InstallController.updateContainer(WireGuardConfigModel.getConfig())
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
if (!GC.isMobile()) { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
saveButton.forceActiveFocus()
} }
} }
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
} }

View file

@ -16,153 +16,134 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.right: parent.right
anchors.left: parent.left
Column { enabled: ServersModel.isProcessedServerHasWriteAccess()
id: content
anchors.top: parent.top model: WireGuardConfigModel
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() delegate: ColumnLayout {
width: listView.width
ListView { property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
id: listview
width: parent.width spacing: 0
height: listview.contentItem.height
clip: true BaseHeaderType {
interactive: false Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
model: WireGuardConfigModel headerText: qsTr("WG settings")
}
delegate: Item { TextFieldWithHeaderType {
id: delegateItem id: vpnAddressSubnetTextField
property alias focusItemId: vpnAddressSubnetTextField Layout.fillWidth: true
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() Layout.topMargin: 40
Layout.leftMargin: 16
Layout.rightMargin: 16
implicitWidth: listview.width enabled: delegateItem.isEnabled
implicitHeight: col.implicitHeight
ColumnLayout { headerText: qsTr("VPN address subnet")
id: col textField.text: subnetAddress
anchors.top: parent.top textField.onEditingFinished: {
anchors.left: parent.left if (textField.text !== subnetAddress) {
anchors.right: parent.right subnetAddress = textField.text
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
headerText: qsTr("WG settings")
}
TextFieldWithHeaderType {
id: vpnAddressSubnetTextField
Layout.fillWidth: true
Layout.topMargin: 40
enabled: delegateItem.isEnabled
headerText: qsTr("VPN address subnet")
textField.text: subnetAddress
textField.onEditingFinished: {
if (textField.text !== subnetAddress) {
subnetAddress = textField.text
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
text: qsTr("Save")
onClicked: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(WireGuardConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
}
} }
} }
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: portTextField.errorText === "" &&
vpnAddressSubnetTextField.errorText === ""
text: qsTr("Save")
onClicked: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(WireGuardConfigModel.getConfig())
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveRestartButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
} }
} }
} }

View file

@ -17,163 +17,114 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType {
id: backButton
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.left: parent.left
anchors.right: parent.right
Column { enabled: ServersModel.isProcessedServerHasWriteAccess()
id: content model: XrayConfigModel
anchors.top: parent.top delegate: ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() width: listView.width
ListView { property alias focusItemId: textFieldWithHeaderType.textField
id: listview
width: parent.width spacing: 0
height: listview.contentItem.height
clip: true BaseHeaderType {
interactive: false Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("XRay settings")
}
model: XrayConfigModel TextFieldWithHeaderType {
id: textFieldWithHeaderType
delegate: Item { Layout.fillWidth: true
id: delegateItem Layout.topMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
property alias focusItemId: textFieldWithHeaderType.textField headerText: qsTr("Disguised as traffic from")
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess() textField.text: site
implicitWidth: listview.width textField.onEditingFinished: {
implicitHeight: col.implicitHeight if (textField.text !== site) {
var tmpText = textField.text
tmpText = tmpText.toLocaleLowerCase()
ColumnLayout { if (tmpText.startsWith("https://")) {
id: col tmpText = textField.text.substring(8)
site = tmpText
anchors.top: parent.top } else {
anchors.left: parent.left site = textField.text
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
BaseHeaderType {
Layout.fillWidth: true
headerText: qsTr("XRay settings")
}
TextFieldWithHeaderType {
id: textFieldWithHeaderType
Layout.fillWidth: true
Layout.topMargin: 32
enabled: delegateItem.isEnabled
headerText: qsTr("Disguised as traffic from")
textField.text: site
textField.onEditingFinished: {
if (textField.text !== site) {
var tmpText = textField.text
tmpText = tmpText.toLocaleLowerCase()
if (tmpText.startsWith("https://")) {
tmpText = textField.text.substring(8)
site = tmpText
} else {
site = textField.text
}
}
}
checkEmptyText: true
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
enabled: portTextField.errorText === ""
text: qsTr("Save")
onClicked: function() {
forceActiveFocus()
var headerText = qsTr("Save settings?")
var descriptionText = qsTr("All users with whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(XrayConfigModel.getConfig())
//focusItem.forceActiveFocus()
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
saveButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
} }
} }
} }
} }
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
enabled: delegateItem.isEnabled
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
if (textField.text !== port) {
port = textField.text
}
}
checkEmptyText: true
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Save")
onClicked: {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Unable change settings while there is an active connection"))
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
InstallController.updateContainer(XrayConfigModel.getConfig())
}
Keys.onEnterPressed: saveButton.clicked()
Keys.onReturnPressed: saveButton.clicked()
}
} }
} }
} }

View file

@ -16,50 +16,47 @@ import "../Components"
PageType { PageType {
id: root id: root
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType {
id: backButton
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.right: parent.right
anchors.left: parent.left
ColumnLayout { header: ColumnLayout {
id: content width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
BaseHeaderType { BaseHeaderType {
id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.bottomMargin: 24
headerText: "AmneziaDNS" headerText: "AmneziaDNS"
descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") + descriptionText: qsTr("A DNS service is installed on your server, and it is only accessible via VPN.\n") +
qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.") qsTr("The DNS address is the same as the address of your server. You can configure DNS in the settings, under the connections tab.")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: removeButton Layout.fillWidth: true
Layout.leftMargin: 16
Layout.topMargin: 24 Layout.rightMargin: 16
width: parent.width
text: qsTr("Remove ") + ContainersModel.getProcessedContainerName() text: qsTr("Remove ") + ContainersModel.getProcessedContainerName()
textColor: AmneziaStyle.color.vibrantRed textColor: AmneziaStyle.color.vibrantRed
@ -71,19 +68,14 @@ PageType {
var yesButtonFunction = function() { var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& SettingsController.isAmneziaDnsEnabled()) { && SettingsController.isAmneziaDnsEnabled()) {
PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server")) PageController.showNotificationMessage(qsTr("Cannot remove AmneziaDNS from running server"))
} else } else {
{
PageController.goToPage(PageEnum.PageDeinstalling) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer() InstallController.removeProcessedContainer()
} }
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
if (!GC.isMobile()) {
removeButton.rightButton.forceActiveFocus()
}
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }

View file

@ -24,258 +24,215 @@ PageType {
} }
} }
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.right: parent.right
anchors.left: parent.left
Column { enabled: ServersModel.isProcessedServerHasWriteAccess()
id: content
anchors.top: parent.top model: SftpConfigModel
anchors.left: parent.left
anchors.right: parent.right
enabled: ServersModel.isProcessedServerHasWriteAccess() delegate: ColumnLayout {
width: listView.width
ListView { spacing: 0
id: listview
width: parent.width BaseHeaderType {
height: listview.contentItem.height Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
clip: true headerText: qsTr("SFTP settings")
interactive: false }
model: SftpConfigModel LabelWithButtonType {
id: hostLabel
onFocusChanged: { Layout.fillWidth: true
if (focus) { Layout.topMargin: 32
listview.currentItem.listViewFocusItem.forceActiveFocus() Layout.leftMargin: 16
} Layout.rightMargin: 16
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
LabelWithButtonType {
id: portLabel
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Port")
descriptionText: port
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
LabelWithButtonType {
id: usernameLabel
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("User name")
descriptionText: username
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
LabelWithButtonType {
id: passwordLabel
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Password")
descriptionText: password
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
BasicButtonType {
id: mountButton
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
text: qsTr("Mount folder on device")
clickedFunc: function() {
PageController.showBusyIndicator(true)
InstallController.mountSftpDrive(port, password, username)
PageController.showBusyIndicator(false)
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
readonly property string windowsFirstLink: "<a href=\"https://github.com/billziss-gh/winfsp/releases/latest\" style=\"color: #FBB26A;\">WinFsp</a>"
readonly property string windowsSecondLink: "<a href=\"https://github.com/billziss-gh/sshfs-win/releases\" style=\"color: #FBB26A;\">SSHFS-Win</a>"
readonly property string macosFirstLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">macFUSE</a>"
readonly property string macosSecondLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">SSHFS</a>"
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
textFormat: Text.RichText
text: {
var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps: <br>")
if (Qt.platform.os === "windows") {
str += qsTr("<br>1. Install the latest version of ") + windowsFirstLink + "\n"
str += qsTr("<br>2. Install the latest version of ") + windowsSecondLink + "\n"
} else if (Qt.platform.os === "osx") {
str += qsTr("<br>1. Install the latest version of ") + macosFirstLink + "\n"
str += qsTr("<br>2. Install the latest version of ") + macosSecondLink + "\n"
} else if (Qt.platform.os === "linux") {
return ""
} else return ""
return str
} }
delegate: Item { MouseArea {
implicitWidth: listview.width anchors.fill: parent
implicitHeight: col.implicitHeight acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
property alias listViewFocusItem: hostLabel.rightButton BasicButtonType {
id: detailedInstructionsButton
ColumnLayout { Layout.topMargin: 16
id: col Layout.bottomMargin: 16
Layout.leftMargin: 8
implicitHeight: 32
anchors.top: parent.top defaultColor: AmneziaStyle.color.transparent
anchors.left: parent.left hoveredColor: AmneziaStyle.color.translucentWhite
anchors.right: parent.right pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
spacing: 0 text: qsTr("Detailed instructions")
BaseHeaderType { clickedFunc: function() {
Layout.fillWidth: true // Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("SFTP settings")
}
LabelWithButtonType {
id: hostLabel
Layout.fillWidth: true
Layout.topMargin: 32
parentFlickable: fl
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
LabelWithButtonType {
id: portLabel
Layout.fillWidth: true
text: qsTr("Port")
descriptionText: port
descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
LabelWithButtonType {
id: usernameLabel
Layout.fillWidth: true
text: qsTr("User name")
descriptionText: username
descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
LabelWithButtonType {
id: passwordLabel
Layout.fillWidth: true
text: qsTr("Password")
descriptionText: password
descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
BasicButtonType {
id: mountButton
visible: !GC.isMobile()
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.paleGray
borderWidth: 1
parentFlickable: fl
text: qsTr("Mount folder on device")
clickedFunc: function() {
PageController.showBusyIndicator(true)
InstallController.mountSftpDrive(port, password, username)
PageController.showBusyIndicator(false)
}
}
ParagraphTextType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
readonly property string windowsFirstLink: "<a href=\"https://github.com/billziss-gh/winfsp/releases/latest\" style=\"color: #FBB26A;\">WinFsp</a>"
readonly property string windowsSecondLink: "<a href=\"https://github.com/billziss-gh/sshfs-win/releases\" style=\"color: #FBB26A;\">SSHFS-Win</a>"
readonly property string macosFirstLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">macFUSE</a>"
readonly property string macosSecondLink: "<a href=\"https://osxfuse.github.io/\" style=\"color: #FBB26A;\">SSHFS</a>"
onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
textFormat: Text.RichText
text: {
var str = qsTr("In order to mount remote SFTP folder as local drive, perform following steps: <br>")
if (Qt.platform.os === "windows") {
str += qsTr("<br>1. Install the latest version of ") + windowsFirstLink + "\n"
str += qsTr("<br>2. Install the latest version of ") + windowsSecondLink + "\n"
} else if (Qt.platform.os === "osx") {
str += qsTr("<br>1. Install the latest version of ") + macosFirstLink + "\n"
str += qsTr("<br>2. Install the latest version of ") + macosSecondLink + "\n"
} else if (Qt.platform.os === "linux") {
return ""
} else return ""
return str
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
}
BasicButtonType {
id: detailedInstructionsButton
Layout.topMargin: 16
Layout.bottomMargin: 16
Layout.leftMargin: 8
implicitHeight: 32
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
pressedColor: AmneziaStyle.color.sheerWhite
disabledColor: AmneziaStyle.color.mutedGray
textColor: AmneziaStyle.color.goldenApricot
text: qsTr("Detailed instructions")
parentFlickable: fl
clickedFunc: function() {
// Qt.openUrlExternally("https://github.com/amnezia-vpn/desktop-client/releases/latest")
}
}
}
} }
} }
} }

View file

@ -25,327 +25,290 @@ PageType {
} }
} }
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType { onFocusChanged: {
id: backButton if (this.activeFocus) {
listView.positionViewAtBeginning()
}
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: listview.implicitHeight anchors.right: parent.right
anchors.left: parent.left
ListView { model: Socks5ProxyConfigModel
id: listview
width: parent.width delegate: ColumnLayout {
height: listview.contentItem.height width: listView.width
clip: true spacing: 0
interactive: false
model: Socks5ProxyConfigModel BaseHeaderType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
onFocusChanged: { headerText: qsTr("SOCKS5 settings")
if (focus) { }
listview.currentItem.focusItemId.forceActiveFocus()
LabelWithButtonType {
Layout.fillWidth: true
Layout.topMargin: 32
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Host")
descriptionText: ServersModel.getProcessedServerData("hostName")
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
} }
} }
delegate: Item { LabelWithButtonType {
implicitWidth: listview.width Layout.fillWidth: true
implicitHeight: content.implicitHeight Layout.rightMargin: 16
Layout.bottomMargin: 16
property alias focusItemId: hostLabel.rightButton text: qsTr("Port")
descriptionText: port
ColumnLayout { descriptionOnTop: true
id: content
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("User name")
descriptionText: username
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Password")
descriptionText: password
descriptionOnTop: true
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
}
}
DrawerType2 {
id: changeSettingsDrawer
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.9
expandedStateContent: ColumnLayout {
property string tempPort: port
property string tempUsername: username
property string tempPassword: password
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 32
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0 spacing: 0
Connections {
target: changeSettingsDrawer
function onOpened() {
tempPort = port
tempUsername = username
tempPassword = password
}
function onClosed() {
port = tempPort
username = tempUsername
password = tempPassword
portTextField.textField.text = port
usernameTextField.textField.text = username
passwordTextField.textField.text = password
}
}
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.bottomMargin: 16
headerText: qsTr("SOCKS5 settings") headerText: qsTr("SOCKS5 settings")
} }
LabelWithButtonType { TextFieldWithHeaderType {
id: hostLabel id: portTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 40
Layout.rightMargin: 16
Layout.bottomMargin: 16
parentFlickable: fl headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
text: qsTr("Host") textField.onEditingFinished: {
descriptionText: ServersModel.getProcessedServerData("hostName") textField.text = textField.text.replace(/^\s+|\s+$/g, '')
if (textField.text !== port) {
descriptionOnTop: true port = textField.text
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
} }
} }
} }
LabelWithButtonType { TextFieldWithHeaderType {
id: portLabel id: usernameTextField
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("Port") headerText: qsTr("Username")
descriptionText: port textField.placeholderText: "username"
textField.text: username
textField.maximumLength: 32
descriptionOnTop: true textField.onEditingFinished: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
parentFlickable: fl if (textField.text !== username) {
username = textField.text
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
} }
} }
} }
LabelWithButtonType { TextFieldWithHeaderType {
id: usernameLabel id: passwordTextField
property bool hidePassword: true
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.rightMargin: 16
Layout.bottomMargin: 16
text: qsTr("User name") headerText: qsTr("Password")
descriptionText: username textField.placeholderText: "password"
textField.text: password
textField.maximumLength: 32
descriptionOnTop: true textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
: ""
parentFlickable: fl clickedFunc: function() {
hidePassword = !hidePassword
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
}
LabelWithButtonType { textField.onFocusChanged: {
id: passwordLabel textField.text = textField.text.replace(/^\s+|\s+$/g, '')
Layout.fillWidth: true if (textField.text !== password) {
password = textField.text
text: qsTr("Password")
descriptionText: password
descriptionOnTop: true
parentFlickable: fl
rightImageSource: "qrc:/images/controls/copy.svg"
rightImageColor: AmneziaStyle.color.paleGray
buttonImageSource: hideDescription ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg"
clickedFunction: function() {
GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
}
}
DrawerType2 {
id: changeSettingsDrawer
parent: root
anchors.fill: parent
expandedHeight: root.height * 0.9
expandedStateContent: ColumnLayout {
property string tempPort: port
property string tempUsername: username
property string tempPassword: password
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 32
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 0
Connections {
target: changeSettingsDrawer
function onOpened() {
tempPort = port
tempUsername = username
tempPassword = password
}
function onClosed() {
port = tempPort
username = tempUsername
password = tempPassword
portTextField.textField.text = port
usernameTextField.textField.text = username
passwordTextField.textField.text = password
}
}
BaseHeaderType {
Layout.fillWidth: true
headerText: qsTr("SOCKS5 settings")
}
TextFieldWithHeaderType {
id: portTextField
Layout.fillWidth: true
Layout.topMargin: 40
parentFlickable: fl
headerText: qsTr("Port")
textField.text: port
textField.maximumLength: 5
textField.validator: IntValidator { bottom: 1; top: 65535 }
textField.onEditingFinished: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
if (textField.text !== port) {
port = textField.text
}
}
}
TextFieldWithHeaderType {
id: usernameTextField
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
headerText: qsTr("Username")
textField.placeholderText: "username"
textField.text: username
textField.maximumLength: 32
textField.onEditingFinished: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
if (textField.text !== username) {
username = textField.text
}
}
}
TextFieldWithHeaderType {
id: passwordTextField
property bool hidePassword: true
Layout.fillWidth: true
Layout.topMargin: 16
parentFlickable: fl
headerText: qsTr("Password")
textField.placeholderText: "password"
textField.text: password
textField.maximumLength: 32
textField.echoMode: hidePassword ? TextInput.Password : TextInput.Normal
buttonImageSource: textField.text !== "" ? (hidePassword ? "qrc:/images/controls/eye.svg" : "qrc:/images/controls/eye-off.svg")
: ""
clickedFunc: function() {
hidePassword = !hidePassword
}
textField.onFocusChanged: {
textField.text = textField.text.replace(/^\s+|\s+$/g, '')
if (textField.text !== password) {
password = textField.text
}
}
}
BasicButtonType {
id: saveButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
text: qsTr("Change connection settings")
clickedFunc: function() {
forceActiveFocus()
if (!portTextField.textField.acceptableInput) {
portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
return
}
if (usernameTextField.textField.text && passwordTextField.textField.text === "") {
passwordTextField.errorText = qsTr("Password cannot be empty")
return
} else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) {
usernameTextField.errorText = qsTr("Username cannot be empty")
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
tempPort = portTextField.textField.text
tempUsername = usernameTextField.textField.text
tempPassword = passwordTextField.textField.text
changeSettingsDrawer.closeTriggered()
}
} }
} }
} }
BasicButtonType { BasicButtonType {
id: changeSettingsButton id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
text: qsTr("Change connection settings") text: qsTr("Change connection settings")
clickedFunc: function() { clickedFunc: function() {
forceActiveFocus() if (!portTextField.textField.acceptableInput) {
changeSettingsDrawer.openTriggered() portTextField.errorText = qsTr("The port must be in the range of 1 to 65535")
return
}
if (usernameTextField.textField.text && passwordTextField.textField.text === "") {
passwordTextField.errorText = qsTr("Password cannot be empty")
return
} else if (usernameTextField.textField.text === "" && passwordTextField.textField.text) {
usernameTextField.errorText = qsTr("Username cannot be empty")
return
}
PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.updateContainer(Socks5ProxyConfigModel.getConfig())
tempPort = portTextField.textField.text
tempUsername = usernameTextField.textField.text
tempPassword = passwordTextField.textField.text
changeSettingsDrawer.closeTriggered()
} }
} }
} }
} }
BasicButtonType {
id: changeSettingsButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Change connection settings")
clickedFunc: function() {
changeSettingsDrawer.openTriggered()
}
}
} }
} }
} }

View file

@ -25,34 +25,25 @@ PageType {
} }
} }
ColumnLayout { BackButtonType {
id: backButtonLayout id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
BackButtonType {
id: backButton
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButtonLayout.bottom
anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight anchors.right: parent.right
anchors.left: parent.left
ColumnLayout { header: ColumnLayout {
id: content width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -61,11 +52,19 @@ PageType {
headerText: qsTr("Tor website settings") headerText: qsTr("Tor website settings")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: websiteName id: websiteName
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 32 Layout.topMargin: 32
Layout.bottomMargin: 24
text: qsTr("Website address") text: qsTr("Website address")
descriptionText: { descriptionText: {
@ -83,15 +82,16 @@ PageType {
clickedFunction: function() { clickedFunction: function() {
GC.copyToClipBoard(descriptionText) GC.copyToClipBoard(descriptionText)
PageController.showNotificationMessage(qsTr("Copied")) PageController.showNotificationMessage(qsTr("Copied"))
if (!GC.isMobile()) {
this.rightButton.forceActiveFocus()
}
} }
} }
}
footer: ColumnLayout {
width: listView.width
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 40 Layout.topMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16

View file

@ -14,130 +14,62 @@ import "../Config"
PageType { PageType {
id: root id: root
FlickableType { ListViewType {
id: fl id: listView
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout { anchors.fill: parent
id: content
anchors.top: parent.top header: ColumnLayout {
anchors.left: parent.left width: listView.width
anchors.right: parent.right
spacing: 0
BaseHeaderType { BaseHeaderType {
id: header id: header
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 24 Layout.topMargin: 24
Layout.bottomMargin: 16
Layout.rightMargin: 16 Layout.rightMargin: 16
Layout.leftMargin: 16 Layout.leftMargin: 16
headerText: qsTr("Settings") headerText: qsTr("Settings")
} }
}
model: settingsEntries
delegate: ColumnLayout {
width: listView.width
spacing: 0
LabelWithButtonType { LabelWithButtonType {
id: account
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Servers") visible: isVisible
text: title
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/server.svg" leftImageSource: leftImagePath
clickedFunction: function() { clickedFunction: clickedHandler
PageController.goToPage(PageEnum.PageSettingsServersList)
}
}
DividerType {}
LabelWithButtonType {
id: connection
Layout.fillWidth: true
text: qsTr("Connection")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/radio.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
}
DividerType {}
LabelWithButtonType {
id: application
Layout.fillWidth: true
text: qsTr("Application")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/app.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
}
DividerType {}
LabelWithButtonType {
id: backup
Layout.fillWidth: true
text: qsTr("Backup")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/save.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
}
DividerType {}
LabelWithButtonType {
id: about
Layout.fillWidth: true
text: qsTr("About AmneziaVPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/amnezia.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
}
DividerType {}
LabelWithButtonType {
id: devConsole
visible: SettingsController.isDevModeEnabled
Layout.fillWidth: true
text: qsTr("Dev console")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
leftImageSource: "qrc:/images/controls/bug.svg"
clickedFunction: function() {
PageController.goToPage(PageEnum.PageDevMenu)
}
} }
DividerType { DividerType {
visible: SettingsController.isDevModeEnabled visible: isVisible
} }
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: close id: close
visible: GC.isDesktop() visible: GC.isDesktop()
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: about.height Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Close application") text: qsTr("Close application")
leftImageSource: "qrc:/images/controls/x-circle.svg" leftImageSource: "qrc:/images/controls/x-circle.svg"
@ -149,8 +81,87 @@ PageType {
} }
DividerType { DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: GC.isDesktop() visible: GC.isDesktop()
} }
} }
} }
property list<QtObject> settingsEntries: [
servers,
connection,
application,
backup,
about,
devConsole
]
QtObject {
id: servers
property string title: qsTr("Servers")
readonly property string leftImagePath: "qrc:/images/controls/server.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsServersList)
}
}
QtObject {
id: connection
property string title: qsTr("Connection")
readonly property string leftImagePath: "qrc:/images/controls/radio.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsConnection)
}
}
QtObject {
id: application
property string title: qsTr("Application")
readonly property string leftImagePath: "qrc:/images/controls/app.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsApplication)
}
}
QtObject {
id: backup
property string title: qsTr("Backup")
readonly property string leftImagePath: "qrc:/images/controls/save.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsBackup)
}
}
QtObject {
id: about
property string title: qsTr("About AmneziaVPN")
readonly property string leftImagePath: "qrc:/images/controls/amnezia.svg"
property bool isVisible: true
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageSettingsAbout)
}
}
QtObject {
id: devConsole
property string title: qsTr("Dev console")
readonly property string leftImagePath: "qrc:/images/controls/bug.svg"
property bool isVisible: SettingsController.isDevModeEnabled
readonly property var clickedHandler: function() {
PageController.goToPage(PageEnum.PageDevMenu)
}
}
} }

View file

@ -29,58 +29,7 @@ PageType {
} }
} }
QtObject { ListViewType {
id: telegramGroup
readonly property string title: qsTr("Telegram group")
readonly property string description: qsTr("To discuss features")
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
}
QtObject {
id: mail
readonly property string title: qsTr("support@amnezia.org")
readonly property string description: qsTr("For reviews and bug reports")
readonly property string imageSource: "qrc:/images/controls/mail.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
}
}
QtObject {
id: github
readonly property string title: qsTr("GitHub")
readonly property string description: qsTr("Discover the source code")
readonly property string imageSource: "qrc:/images/controls/github.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
QtObject {
id: website
readonly property string title: qsTr("Website")
readonly property string description: qsTr("Visit official website")
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
property list<QtObject> contacts: [
telegramGroup,
mail,
github,
website
]
ListView {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
@ -88,38 +37,6 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
model: contacts
clip: true
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -170,6 +87,8 @@ PageType {
} }
} }
model: contacts
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width
@ -257,4 +176,55 @@ PageType {
} }
} }
} }
QtObject {
id: telegramGroup
readonly property string title: qsTr("Telegram group")
readonly property string description: qsTr("To discuss features")
readonly property string imageSource: "qrc:/images/controls/telegram.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_vpn_en"))
}
}
QtObject {
id: mail
readonly property string title: qsTr("support@amnezia.org")
readonly property string description: qsTr("For reviews and bug reports")
readonly property string imageSource: "qrc:/images/controls/mail.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("mailto:support@amnezia.org"))
}
}
QtObject {
id: github
readonly property string title: qsTr("GitHub")
readonly property string description: qsTr("Discover the source code")
readonly property string imageSource: "qrc:/images/controls/github.svg"
readonly property var handler: function() {
Qt.openUrlExternally(qsTr("https://github.com/amnezia-vpn/amnezia-client"))
}
}
QtObject {
id: website
readonly property string title: qsTr("Website")
readonly property string description: qsTr("Visit official website")
readonly property string imageSource: "qrc:/images/controls/amnezia.svg"
readonly property var handler: function() {
Qt.openUrlExternally(LanguageModel.getCurrentSiteUrl())
}
}
property list<QtObject> contacts: [
telegramGroup,
mail,
github,
website
]
} }

View file

@ -22,22 +22,28 @@ PageType {
property string configExtension: ".conf" property string configExtension: ".conf"
property string configCaption: qsTr("Save AmneziaVPN config") property string configCaption: qsTr("Save AmneziaVPN config")
BackButtonType {
id: backButton
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 20
}
ListViewType { ListViewType {
id: listView id: listView
anchors.fill: parent anchors.top: backButton.bottom
anchors.topMargin: 20 anchors.bottom: parent.bottom
anchors.bottomMargin: 24 anchors.right: parent.right
anchors.left: parent.left
model: ApiCountryModel model: ApiCountryModel
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
BackButtonType {
id: backButton
}
BaseHeaderType { BaseHeaderType {
id: header id: header
@ -104,20 +110,16 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: drawerListView
anchors.top: moreOptionsDrawerBackButton.bottom anchors.top: moreOptionsDrawerBackButton.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom
contentHeight: moreOptionsDrawerContent.height header: ColumnLayout {
width: drawerListView.width
ColumnLayout {
id: moreOptionsDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
@ -125,9 +127,17 @@ PageType {
headerText: moreOptionsDrawer.countryName + qsTr(" configuration file") headerText: moreOptionsDrawer.countryName + qsTr(" configuration file")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: drawerListView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Generate a new configuration file") text: qsTr("Generate a new configuration file")
descriptionText: qsTr("The previously created one will stop working") descriptionText: qsTr("The previously created one will stop working")
@ -138,9 +148,16 @@ PageType {
} }
DividerType {} DividerType {}
}
footer: ColumnLayout {
width: drawerListView.width
LabelWithButtonType { LabelWithButtonType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Revoke the current configuration file") text: qsTr("Revoke the current configuration file")
clickedFunction: function() { clickedFunction: function() {
@ -212,8 +229,7 @@ PageType {
} }
moreOptionsDrawer.closeTriggered() moreOptionsDrawer.closeTriggered()
} }
var noButtonFunction = function() { var noButtonFunction = function() {}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }

View file

@ -158,32 +158,6 @@ PageType {
readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible") readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible")
SwitcherType {
id: switcher
readonly property bool isVlessProtocol: ApiConfigsController.isVlessProtocol()
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
Layout.leftMargin: 16
visible: ApiAccountInfoModel.data("isProtocolSelectionSupported")
text: qsTr("Use VLESS protocol")
checked: switcher.isVlessProtocol
onToggled: function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot change protocol during active connection"))
} else {
PageController.showBusyIndicator(true)
ApiConfigsController.setCurrentProtocol(switcher.isVlessProtocol ? "awg" : "vless")
ApiConfigsController.updateServiceFromGateway(ServersModel.processedIndex, "", "", true)
PageController.showBusyIndicator(false)
}
}
}
WarningType { WarningType {
id: warning id: warning

View file

@ -50,6 +50,7 @@ PageType {
readonly property string name: qsTr("Only the apps from the list should have access via VPN") readonly property string name: qsTr("Only the apps from the list should have access via VPN")
readonly property int type: routeMode.onlyForwardApps readonly property int type: routeMode.onlyForwardApps
} }
QtObject { QtObject {
id: allExceptApps id: allExceptApps
@ -146,77 +147,56 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: listView
anchors.top: header.bottom anchors.top: header.bottom
anchors.topMargin: 16 anchors.bottom: addAppButton.top
contentHeight: col.implicitHeight + addAppButton.implicitHeight + addAppButton.anchors.bottomMargin + addAppButton.anchors.topMargin anchors.left: parent.left
anchors.right: parent.right
enabled: root.pageEnabled model: SortFilterProxyModel {
id: proxyAppSplitTunnelingModel
sourceModel: AppSplitTunnelingModel
filters: RegExpFilter {
roleName: "appPath"
pattern: ".*" + searchField.textField.text + ".*"
caseSensitivity: Qt.CaseInsensitive
}
sorters: [
RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder }
]
}
Column { delegate: ColumnLayout {
id: col width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
ListView { LabelWithButtonType {
id: apps Layout.fillWidth: true
width: parent.width
height: apps.contentItem.height
model: SortFilterProxyModel { Layout.leftMargin: 16
id: proxyAppSplitTunnelingModel Layout.rightMargin: 16
sourceModel: AppSplitTunnelingModel
filters: RegExpFilter { text: appPath
roleName: "appPath" rightImageSource: "qrc:/images/controls/trash.svg"
pattern: ".*" + searchField.textField.text + ".*" rightImageColor: AmneziaStyle.color.paleGray
caseSensitivity: Qt.CaseInsensitive
clickedFunction: function() {
var headerText = qsTr("Remove ") + appPath + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index))
} }
sorters: [ var noButtonFunction = function() {
RoleSorter { roleName: "appPath"; sortOrder: Qt.AscendingOrder }
]
}
clip: true
interactive: false
delegate: Item {
implicitWidth: apps.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
LabelWithButtonType {
Layout.fillWidth: true
text: appPath
rightImageSource: "qrc:/images/controls/trash.svg"
rightImageColor: AmneziaStyle.color.paleGray
clickedFunction: function() {
var headerText = qsTr("Remove ") + appPath + "?"
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
AppSplitTunnelingController.removeApp(proxyAppSplitTunnelingModel.mapToSource(index))
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {}
} }
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
DividerType {}
} }
} }

View file

@ -23,20 +23,16 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height anchors.left: parent.left
anchors.right: parent.right
ColumnLayout { header: ColumnLayout {
id: content width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -45,9 +41,17 @@ PageType {
headerText: qsTr("Application") headerText: qsTr("Application")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: switcher id: switcherAllowScreenshots
visible: GC.isMobile() visible: GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -61,10 +65,6 @@ PageType {
SettingsController.toggleScreenshotsEnabled(checked) SettingsController.toggleScreenshotsEnabled(checked)
} }
} }
// KeyNavigation.tab: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted ?
// labelWithButtonNotification.rightButton : labelWithButtonLanguage.rightButton
parentFlickable: fl
} }
DividerType { DividerType {
@ -73,15 +73,15 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonNotification id: labelWithButtonNotification
visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted visible: Qt.platform.os === "android" && !SettingsController.isNotificationPermissionGranted
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Enable notifications") text: qsTr("Enable notifications")
descriptionText: qsTr("Enable notifications to show the VPN state in the status bar") descriptionText: qsTr("Enable notifications to show the VPN state in the status bar")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
SettingsController.requestNotificationPermission() SettingsController.requestNotificationPermission()
} }
@ -93,6 +93,7 @@ PageType {
SwitcherType { SwitcherType {
id: switcherAutoStart id: switcherAutoStart
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -101,8 +102,6 @@ PageType {
text: qsTr("Auto start") text: qsTr("Auto start")
descriptionText: qsTr("Launch the application every time the device is starts") descriptionText: qsTr("Launch the application every time the device is starts")
parentFlickable: fl
checked: SettingsController.isAutoStartEnabled() checked: SettingsController.isAutoStartEnabled()
onCheckedChanged: { onCheckedChanged: {
if (checked !== SettingsController.isAutoStartEnabled()) { if (checked !== SettingsController.isAutoStartEnabled()) {
@ -117,6 +116,7 @@ PageType {
SwitcherType { SwitcherType {
id: switcherAutoConnect id: switcherAutoConnect
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -125,8 +125,6 @@ PageType {
text: qsTr("Auto connect") text: qsTr("Auto connect")
descriptionText: qsTr("Connect to VPN on app start") descriptionText: qsTr("Connect to VPN on app start")
parentFlickable: fl
checked: SettingsController.isAutoConnectEnabled() checked: SettingsController.isAutoConnectEnabled()
onCheckedChanged: { onCheckedChanged: {
if (checked !== SettingsController.isAutoConnectEnabled()) { if (checked !== SettingsController.isAutoConnectEnabled()) {
@ -141,6 +139,7 @@ PageType {
SwitcherType { SwitcherType {
id: switcherStartMinimized id: switcherStartMinimized
visible: !GC.isMobile() visible: !GC.isMobile()
Layout.fillWidth: true Layout.fillWidth: true
@ -149,8 +148,6 @@ PageType {
text: qsTr("Start minimized") text: qsTr("Start minimized")
descriptionText: qsTr("Launch application minimized") descriptionText: qsTr("Launch application minimized")
parentFlickable: fl
checked: SettingsController.isStartMinimizedEnabled() checked: SettingsController.isStartMinimizedEnabled()
onCheckedChanged: { onCheckedChanged: {
if (checked !== SettingsController.isStartMinimizedEnabled()) { if (checked !== SettingsController.isStartMinimizedEnabled()) {
@ -162,17 +159,21 @@ PageType {
DividerType { DividerType {
visible: !GC.isMobile() visible: !GC.isMobile()
} }
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonLanguage id: labelWithButtonLanguage
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Language") text: qsTr("Language")
descriptionText: LanguageModel.currentLanguageName descriptionText: LanguageModel.currentLanguageName
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
selectLanguageDrawer.openTriggered() selectLanguageDrawer.openTriggered()
} }
@ -182,14 +183,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonLogging id: labelWithButtonLogging
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Logging") text: qsTr("Logging")
descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled") descriptionText: SettingsController.isLoggingEnabled ? qsTr("Enabled") : qsTr("Disabled")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsLogging) PageController.goToPage(PageEnum.PageSettingsLogging)
} }
@ -199,14 +199,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: labelWithButtonReset id: labelWithButtonReset
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Reset settings and remove all data from the application") text: qsTr("Reset settings and remove all data from the application")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
textColor: AmneziaStyle.color.vibrantRed textColor: AmneziaStyle.color.vibrantRed
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
var headerText = qsTr("Reset settings and remove all data from the application?") var headerText = qsTr("Reset settings and remove all data from the application?")
var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.") var descriptionText = qsTr("All settings will be reset to default. All installed AmneziaVPN services will still remain on the server.")

View file

@ -43,49 +43,60 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height anchors.left: parent.left
anchors.right: parent.right
ColumnLayout { header: ColumnLayout {
id: content
anchors.top: parent.top width: listView.width
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Back up your configuration") headerText: qsTr("Back up your configuration")
descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.") descriptionText: qsTr("You can save your settings to a backup file to restore them the next time you install the application.")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
spacing: 16
WarningType { WarningType {
Layout.topMargin: 16
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
textString: qsTr("The backup will contain your passwords and private keys for all servers added " + textString: qsTr("The backup will contain your passwords and private keys for all servers added " +
"to AmneziaVPN. Keep this information in a secure place.") "to AmneziaVPN. Keep this information in a secure place.")
iconPath: "qrc:/images/controls/alert-circle.svg" iconPath: "qrc:/images/controls/alert-circle.svg"
} }
BasicButtonType { BasicButtonType {
id: makeBackupButton id: makeBackupButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 14 Layout.topMargin: 14
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Make a backup") text: qsTr("Make a backup")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
var fileName = "" var fileName = ""
if (GC.isMobile()) { if (GC.isMobile()) {
@ -108,8 +119,11 @@ PageType {
BasicButtonType { BasicButtonType {
id: restoreBackupButton id: restoreBackupButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: -8 Layout.topMargin: -8
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
@ -120,8 +134,6 @@ PageType {
text: qsTr("Restore from backup") text: qsTr("Restore from backup")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
var filePath = SystemController.getFileName(qsTr("Open backup file"), var filePath = SystemController.getFileName(qsTr("Open backup file"),
qsTr("Backup files (*.backup)")) qsTr("Backup files (*.backup)"))

View file

@ -23,18 +23,17 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height anchors.left: parent.left
anchors.right: parent.right
ColumnLayout { header: ColumnLayout {
id: content
anchors.top: parent.top width: listView.width
anchors.left: parent.left
anchors.right: parent.right
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -43,9 +42,17 @@ PageType {
headerText: qsTr("Connection") headerText: qsTr("Connection")
} }
}
model: 1 // fake model to force the ListView to be created without a model
delegate: ColumnLayout {
width: listView.width
SwitcherType { SwitcherType {
id: amneziaDnsSwitch id: amneziaDnsSwitch
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
@ -64,14 +71,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: dnsServersButton id: dnsServersButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("DNS servers") text: qsTr("DNS servers")
descriptionText: qsTr("When AmneziaDNS is not used or installed") descriptionText: qsTr("When AmneziaDNS is not used or installed")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsDns) PageController.goToPage(PageEnum.PageSettingsDns)
} }
@ -81,14 +87,13 @@ PageType {
LabelWithButtonType { LabelWithButtonType {
id: splitTunnelingButton id: splitTunnelingButton
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Site-based split tunneling") text: qsTr("Site-based split tunneling")
descriptionText: qsTr("Allows you to select which sites you want to access through the VPN") descriptionText: qsTr("Allows you to select which sites you want to access through the VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsSplitTunneling) PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
} }
@ -96,8 +101,15 @@ PageType {
DividerType {} DividerType {}
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: splitTunnelingButton2 id: splitTunnelingButton2
visible: root.isAppSplitTinnelingEnabled visible: root.isAppSplitTinnelingEnabled
Layout.fillWidth: true Layout.fillWidth: true
@ -106,8 +118,6 @@ PageType {
descriptionText: qsTr("Allows you to use the VPN only for certain Apps") descriptionText: qsTr("Allows you to use the VPN only for certain Apps")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling) PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
} }
@ -127,8 +137,6 @@ PageType {
descriptionText: qsTr("Blocks network connections without VPN") descriptionText: qsTr("Blocks network connections without VPN")
rightImageSource: "qrc:/images/controls/chevron-right.svg" rightImageSource: "qrc:/images/controls/chevron-right.svg"
parentFlickable: fl
clickedFunction: function() { clickedFunction: function() {
PageController.goToPage(PageEnum.PageSettingsKillSwitch) PageController.goToPage(PageEnum.PageSettingsKillSwitch)
} }

View file

@ -21,13 +21,21 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
onFocusChanged: {
if (this.activeFocus) {
listView.positionViewAtBeginning()
}
}
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.height anchors.right: parent.right
anchors.left: parent.left
property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex) property var isServerFromApi: ServersModel.isServerFromApi(ServersModel.defaultIndex)
@ -39,25 +47,23 @@ PageType {
} }
} }
ColumnLayout { header: ColumnLayout {
id: content width: listView.width
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.rightMargin: 16
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("DNS servers") headerText: qsTr("DNS servers")
} }
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("If AmneziaDNS is not used or installed") text: qsTr("If AmneziaDNS is not used or installed")
} }
@ -65,6 +71,9 @@ PageType {
id: primaryDns id: primaryDns
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Primary DNS") headerText: qsTr("Primary DNS")
textField.text: SettingsController.primaryDns textField.text: SettingsController.primaryDns
@ -77,6 +86,9 @@ PageType {
id: secondaryDns id: secondaryDns
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Secondary DNS") headerText: qsTr("Secondary DNS")
textField.text: SettingsController.secondaryDns textField.text: SettingsController.secondaryDns
@ -84,10 +96,21 @@ PageType {
regularExpression: InstallController.ipAddressRegExp() regularExpression: InstallController.ipAddressRegExp()
} }
} }
}
model: 1 // fake model to force the ListView to be created without a model
spacing: 16
delegate: ColumnLayout {
width: listView.width
BasicButtonType { BasicButtonType {
id: restoreDefaultButton id: restoreDefaultButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.topMargin: 16
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
@ -116,11 +139,16 @@ PageType {
showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction) showQuestionDrawer(headerText, "", yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
}
footer: ColumnLayout {
width: listView.width
BasicButtonType { BasicButtonType {
id: saveButton id: saveButton
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16
text: qsTr("Save") text: qsTr("Save")
@ -136,5 +164,4 @@ PageType {
} }
} }
} }
} }

View file

@ -82,8 +82,7 @@ PageType {
Layout.rightMargin: 16 Layout.rightMargin: 16
visible: false visible: false
enabled: false enabled: false //SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
// enabled: SettingsController.isKillSwitchEnabled && !ConnectionController.isConnected
checked: SettingsController.strictKillSwitchEnabled checked: SettingsController.strictKillSwitchEnabled
text: qsTr("Strict KillSwitch") text: qsTr("Strict KillSwitch")

View file

@ -25,7 +25,7 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
@ -33,10 +33,6 @@ PageType {
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -101,8 +97,7 @@ PageType {
} }
model: logTypes model: logTypes
clip: true
reuseItems: true
snapMode: ListView.SnapOneItem snapMode: ListView.SnapOneItem
delegate: ColumnLayout { delegate: ColumnLayout {

View file

@ -18,10 +18,6 @@ PageType {
signal lastItemTabClickedSignal() signal lastItemTabClickedSignal()
onFocusChanged: content.isServerWithWriteAccess ?
labelWithButton.forceActiveFocus() :
labelWithButton3.forceActiveFocus()
Connections { Connections {
target: InstallController target: InstallController
@ -63,218 +59,194 @@ PageType {
target: ServersModel target: ServersModel
function onProcessedServerIndexChanged() { function onProcessedServerIndexChanged() {
content.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess() listView.isServerWithWriteAccess = ServersModel.isProcessedServerHasWriteAccess()
} }
} }
FlickableType { ListViewType {
id: fl id: listView
anchors.top: parent.top
anchors.bottom: parent.bottom
contentHeight: content.height
ColumnLayout { property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess()
id: content
anchors.top: parent.top anchors.fill: parent
anchors.left: parent.left
anchors.right: parent.right
property bool isServerWithWriteAccess: ServersModel.isProcessedServerHasWriteAccess() model: serverActions
delegate: ColumnLayout {
width: listView.width
LabelWithButtonType { LabelWithButtonType {
id: labelWithButton
visible: content.isServerWithWriteAccess
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Check the server for previously installed Amnezia services") visible: isVisible
descriptionText: qsTr("Add them to the application if they were not displayed")
text: title
descriptionText: description
textColor: tColor
clickedFunction: function() { clickedFunction: function() {
clickedHandler()
}
}
DividerType {
visible: isVisible
}
}
}
property list<QtObject> serverActions: [
check,
reboot,
remove,
clear,
reset,
switch_to_premium,
]
QtObject {
id: check
property bool isVisible: true
readonly property string title: qsTr("Check the server for previously installed Amnezia services")
readonly property string description: qsTr("Add them to the application if they were not displayed")
readonly property var tColor: AmneziaStyle.color.paleGray
readonly property var clickedHandler: function() {
PageController.showBusyIndicator(true)
InstallController.scanServerForInstalledContainers()
PageController.showBusyIndicator(false)
}
}
QtObject {
id: reboot
property bool isVisible: true
readonly property string title: qsTr("Reboot server")
readonly property string description: ""
readonly property var tColor: AmneziaStyle.color.vibrantRed
readonly property var clickedHandler: function() {
var headerText = qsTr("Do you want to reboot the server?")
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection"))
} else {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
InstallController.scanServerForInstalledContainers() InstallController.rebootProcessedServer()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
} }
} }
var noButtonFunction = function() {
DividerType {
visible: content.isServerWithWriteAccess
} }
LabelWithButtonType { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: labelWithButton2 }
visible: content.isServerWithWriteAccess }
Layout.fillWidth: true
text: qsTr("Reboot server") QtObject {
textColor: AmneziaStyle.color.vibrantRed id: remove
clickedFunction: function() { property bool isVisible: true
var headerText = qsTr("Do you want to reboot the server?") readonly property string title: qsTr("Remove server from application")
var descriptionText = qsTr("The reboot process may take approximately 30 seconds. Are you sure you wish to proceed?") readonly property string description: ""
var yesButtonText = qsTr("Continue") readonly property var tColor: AmneziaStyle.color.vibrantRed
var noButtonText = qsTr("Cancel") readonly property var clickedHandler: function() {
var headerText = qsTr("Do you want to remove the server from application?")
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot reboot server during active connection")) PageController.showNotificationMessage(qsTr("Cannot remove server during active connection"))
} else { } else {
PageController.showBusyIndicator(true) PageController.showBusyIndicator(true)
InstallController.rebootProcessedServer() InstallController.removeProcessedServer()
PageController.showBusyIndicator(false) PageController.showBusyIndicator(false)
}
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton2.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
var noButtonFunction = function() {
DividerType {
visible: content.isServerWithWriteAccess
} }
LabelWithButtonType { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: labelWithButton3 }
Layout.fillWidth: true }
text: qsTr("Remove server from application") QtObject {
textColor: AmneziaStyle.color.vibrantRed id: clear
clickedFunction: function() { property bool isVisible: true
var headerText = qsTr("Do you want to remove the server from application?") readonly property string title: qsTr("Clear server from Amnezia software")
var descriptionText = qsTr("All installed AmneziaVPN services will still remain on the server.") readonly property string description: ""
var yesButtonText = qsTr("Continue") readonly property var tColor: AmneziaStyle.color.vibrantRed
var noButtonText = qsTr("Cancel") readonly property var clickedHandler: function() {
var headerText = qsTr("Do you want to clear server from Amnezia software?")
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot remove server during active connection")) PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection"))
} else { } else {
PageController.showBusyIndicator(true) PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedServer() InstallController.removeAllContainers()
PageController.showBusyIndicator(false)
}
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton3.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
var noButtonFunction = function() {
DividerType {} }
LabelWithButtonType { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: labelWithButton4 }
visible: content.isServerWithWriteAccess }
Layout.fillWidth: true
text: qsTr("Clear server from Amnezia software") QtObject {
textColor: AmneziaStyle.color.vibrantRed id: reset
clickedFunction: function() { property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
var headerText = qsTr("Do you want to clear server from Amnezia software?") readonly property string title: qsTr("Reset API config")
var descriptionText = qsTr("All users whom you shared a connection with will no longer be able to connect to it.") readonly property string description: ""
var yesButtonText = qsTr("Continue") readonly property var tColor: AmneziaStyle.color.vibrantRed
var noButtonText = qsTr("Cancel") readonly property var clickedHandler: function() {
var headerText = qsTr("Do you want to reset API config?")
var descriptionText = ""
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() { var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) { if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot clear server from Amnezia software during active connection")) PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection"))
} else { } else {
PageController.goToPage(PageEnum.PageDeinstalling) PageController.showBusyIndicator(true)
InstallController.removeAllContainers() InstallController.removeApiConfig(ServersModel.processedIndex)
} PageController.showBusyIndicator(false)
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton4.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
} }
} }
var noButtonFunction = function() {
DividerType {
visible: content.isServerWithWriteAccess
} }
LabelWithButtonType { showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
id: labelWithButton5 }
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") }
Layout.fillWidth: true
text: qsTr("Reset API config") QtObject {
textColor: AmneziaStyle.color.vibrantRed id: switch_to_premium
clickedFunction: function() { property bool isVisible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
var headerText = qsTr("Do you want to reset API config?") readonly property string title: qsTr("Switch to the new Amnezia Premium subscription")
var descriptionText = "" readonly property string description: ""
var yesButtonText = qsTr("Continue") readonly property var tColor: AmneziaStyle.color.vibrantRed
var noButtonText = qsTr("Cancel") readonly property var clickedHandler: function() {
PageController.goToPageHome()
var yesButtonFunction = function() { ApiPremV1MigrationController.showMigrationDrawer()
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected) {
PageController.showNotificationMessage(qsTr("Cannot reset API config during active connection"))
} else {
PageController.showBusyIndicator(true)
InstallController.removeApiConfig(ServersModel.processedIndex)
PageController.showBusyIndicator(false)
}
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
labelWithButton5.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
}
DividerType {
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi")
}
LabelWithButtonType {
id: labelWithButton6
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
Layout.fillWidth: true
text: qsTr("Switch to the new Amnezia Premium subscription")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
PageController.goToPageHome()
ApiPremV1MigrationController.showMigrationDrawer()
}
}
DividerType {
visible: ServersModel.getProcessedServerData("isServerFromTelegramApi") && ServersModel.processedServerIsPremium
}
} }
} }
} }

View file

@ -21,249 +21,205 @@ PageType {
property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex()) property bool isClearCacheVisible: ServersModel.isProcessedServerHasWriteAccess() && !ContainersModel.isServiceContainer(ContainersModel.getProcessedContainerIndex())
ColumnLayout { BackButtonType {
id: header id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.topMargin: 20 anchors.topMargin: 20
}
BackButtonType { ListViewType {
id: backButton id: listView
}
BaseHeaderType { anchors.top: backButton.bottom
Layout.fillWidth: true anchors.bottom: parent.bottom
Layout.leftMargin: 16 anchors.right: parent.right
Layout.rightMargin: 16 anchors.left: parent.left
Layout.bottomMargin: 32
headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings") header: ColumnLayout {
} width: listView.width
ListView { BaseHeaderType {
id: protocols Layout.fillWidth: true
Layout.fillWidth: true Layout.leftMargin: 16
height: protocols.contentItem.height Layout.rightMargin: 16
clip: true Layout.bottomMargin: 32
interactive: true
property bool isFocusable: true headerText: ContainersModel.getProcessedContainerName() + qsTr(" settings")
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
model: ProtocolsModel
delegate: Item {
implicitWidth: protocols.width
implicitHeight: delegateContent.implicitHeight
ColumnLayout {
id: delegateContent
anchors.fill: parent
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
LabelWithButtonType {
id: clientSettings
Layout.fillWidth: true
text: protocolName + qsTr(" connection settings")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
visible: delegateContent.isClientSettingsVisible
clickedFunction: function() {
if (isClientProtocolExists) {
switch (protocolIndex) {
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
}
PageController.goToPage(clientProtocolPage);
} else {
PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration"))
}
}
MouseArea {
anchors.fill: clientSettings
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
visible: delegateContent.isClientSettingsVisible
}
LabelWithButtonType {
id: serverSettings
Layout.fillWidth: true
text: protocolName + qsTr(" server settings")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
visible: delegateContent.isServerSettingsVisible
clickedFunction: function() {
switch (protocolIndex) {
case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
}
PageController.goToPage(serverProtocolPage);
}
MouseArea {
anchors.fill: serverSettings
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
visible: delegateContent.isServerSettingsVisible
}
}
}
footer: ColumnLayout {
width: header.width
LabelWithButtonType {
id: clearCacheButton
Layout.fillWidth: true
visible: root.isClearCacheVisible
text: qsTr("Clear profile")
clickedFunction: function() {
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
PageController.showNotificationMessage(message)
return
}
PageController.showBusyIndicator(true)
InstallController.clearCachedProfile()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
// if (!GC.isMobile()) {
// focusItem.forceActiveFocus()
// }
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
anchors.fill: clearCacheButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isClearCacheVisible
}
LabelWithButtonType {
id: removeButton
Layout.fillWidth: true
visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
} else
{
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer()
}
}
var noButtonFunction = function() {
if (!GC.isMobile()) {
focusItem.forceActiveFocus()
}
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
anchors.fill: removeButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: ServersModel.isProcessedServerHasWriteAccess()
}
} }
} }
model: ProtocolsModel
delegate: ColumnLayout {
id: delegateContent
width: listView.width
property bool isClientSettingsVisible: protocolIndex === ProtocolEnum.WireGuard || protocolIndex === ProtocolEnum.Awg
property bool isServerSettingsVisible: ServersModel.isProcessedServerHasWriteAccess()
LabelWithButtonType {
id: clientSettings
Layout.fillWidth: true
text: protocolName + qsTr(" connection settings")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
visible: delegateContent.isClientSettingsVisible
clickedFunction: function() {
if (isClientProtocolExists) {
switch (protocolIndex) {
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
}
PageController.goToPage(clientProtocolPage);
} else {
PageController.showNotificationMessage(qsTr("Click the \"connect\" button to create a connection configuration"))
}
}
MouseArea {
anchors.fill: clientSettings
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
visible: delegateContent.isClientSettingsVisible
}
LabelWithButtonType {
id: serverSettings
Layout.fillWidth: true
text: protocolName + qsTr(" server settings")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
visible: delegateContent.isServerSettingsVisible
clickedFunction: function() {
switch (protocolIndex) {
case ProtocolEnum.OpenVpn: OpenVpnConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.ShadowSocks: ShadowSocksConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Cloak: CloakConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.WireGuard: WireGuardConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Awg: AwgConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Xray: XrayConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Sftp: SftpConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Ipsec: Ikev2ConfigModel.updateModel(ProtocolsModel.getConfig()); break;
case ProtocolEnum.Socks5Proxy: Socks5ProxyConfigModel.updateModel(ProtocolsModel.getConfig()); break;
}
PageController.goToPage(serverProtocolPage);
}
MouseArea {
anchors.fill: serverSettings
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
visible: delegateContent.isServerSettingsVisible
}
}
footer: ColumnLayout {
width: listView.width
LabelWithButtonType {
id: clearCacheButton
Layout.fillWidth: true
visible: root.isClearCacheVisible
text: qsTr("Clear profile")
clickedFunction: function() {
var headerText = qsTr("Clear %1 profile?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("The connection configuration will be deleted for this device only")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ConnectionController.isConnected && ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
var message = qsTr("Unable to clear %1 profile while there is an active connection").arg(ContainersModel.getProcessedContainerName())
PageController.showNotificationMessage(message)
return
}
PageController.showBusyIndicator(true)
InstallController.clearCachedProfile()
PageController.showBusyIndicator(false)
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
anchors.fill: clearCacheButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
visible: root.isClearCacheVisible
}
LabelWithButtonType {
id: removeButton
Layout.fillWidth: true
visible: ServersModel.isProcessedServerHasWriteAccess()
text: qsTr("Remove ")
textColor: AmneziaStyle.color.vibrantRed
clickedFunction: function() {
var headerText = qsTr("Remove %1 from server?").arg(ContainersModel.getProcessedContainerName())
var descriptionText = qsTr("All users with whom you shared a connection will no longer be able to connect to it.")
var yesButtonText = qsTr("Continue")
var noButtonText = qsTr("Cancel")
var yesButtonFunction = function() {
if (ServersModel.isDefaultServerCurrentlyProcessed() && ConnectionController.isConnected
&& ServersModel.getDefaultServerData("defaultContainer") === ContainersModel.getProcessedContainerIndex()) {
PageController.showNotificationMessage(qsTr("Cannot remove active container"))
} else
{
PageController.goToPage(PageEnum.PageDeinstalling)
InstallController.removeProcessedContainer()
}
}
var noButtonFunction = function() {
}
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
}
MouseArea {
anchors.fill: removeButton
cursorShape: Qt.PointingHandCursor
enabled: false
}
}
DividerType {
visible: ServersModel.isProcessedServerHasWriteAccess()
}
}
} }
} }

View file

@ -40,25 +40,20 @@ PageType {
} }
} }
ListView { ListViewType {
id: servers id: servers
objectName: "servers" objectName: "servers"
width: parent.width width: parent.width
anchors.top: header.bottom anchors.top: header.bottom
anchors.topMargin: 16 anchors.topMargin: 16
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: 500
property bool isFocusable: true
model: ServersModel model: ServersModel
clip: true
reuseItems: true
delegate: Item { delegate: Item {
implicitWidth: servers.width implicitWidth: servers.width
implicitHeight: delegateContent.implicitHeight implicitHeight: delegateContent.implicitHeight

View file

@ -161,7 +161,7 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: header.bottom anchors.top: header.bottom
@ -172,8 +172,6 @@ PageType {
enabled: root.pageEnabled enabled: root.pageEnabled
property bool isFocusable: true
model: SortFilterProxyModel { model: SortFilterProxyModel {
id: proxySitesModel id: proxySitesModel
sourceModel: SitesModel sourceModel: SitesModel
@ -193,13 +191,7 @@ PageType {
] ]
} }
clip: true
reuseItems: true
delegate: ColumnLayout { delegate: ColumnLayout {
id: delegateContent
width: listView.width width: listView.width
LabelWithButtonType { LabelWithButtonType {
@ -236,7 +228,6 @@ PageType {
} }
} }
Rectangle { Rectangle {
anchors.fill: addSiteButton anchors.fill: addSiteButton
anchors.bottomMargin: -24 anchors.bottomMargin: -24
@ -376,20 +367,16 @@ PageType {
} }
} }
FlickableType { ListViewType {
id: importSitesDrawerListView
anchors.top: importSitesDrawerBackButton.bottom anchors.top: importSitesDrawerBackButton.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: importSitesDrawerContent.height header: ColumnLayout {
width: importSitesDrawerListView.width
ColumnLayout {
id: importSitesDrawerContent
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
Header2Type { Header2Type {
Layout.fillWidth: true Layout.fillWidth: true
@ -397,49 +384,67 @@ PageType {
headerText: qsTr("Import a list of sites") headerText: qsTr("Import a list of sites")
} }
}
model: importOptions
delegate: ColumnLayout {
width: importSitesDrawerListView.width
LabelWithButtonType { LabelWithButtonType {
id: importSitesButton2
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Replace site list") text: title
clickedFunction: function() { clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"), clickedHandler()
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, true)
}
} }
} }
DividerType {} DividerType {}
LabelWithButtonType {
id: importSitesButton3
Layout.fillWidth: true
text: qsTr("Add imported sites to existing ones")
clickedFunction: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
importSitesDrawerContent.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.closeTriggered()
moreActionsDrawer.closeTriggered()
}
DividerType {}
} }
} }
} }
} }
property list<QtObject> importOptions: [
replaceOption,
addOption,
]
QtObject {
id: replaceOption
readonly property string title: qsTr("Replace site list")
readonly property var clickedHandler: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
root.importSites(fileName, true)
}
}
}
QtObject {
id: addOption
readonly property string title: qsTr("Add imported sites to existing ones")
readonly property var clickedHandler: function() {
var fileName = SystemController.getFileName(qsTr("Open sites file"),
qsTr("Sites files (*.json)"))
if (fileName !== "") {
root.importSites(fileName, false)
}
}
}
function importSites(fileName, replaceExistingSites) {
PageController.showBusyIndicator(true)
SitesController.importSites(fileName, replaceExistingSites)
PageController.showBusyIndicator(false)
importSitesDrawer.closeTriggered()
moreActionsDrawer.closeTriggered()
}
} }

View file

@ -15,25 +15,31 @@ import "../Components"
PageType { PageType {
id: root id: root
FlickableType { BackButtonType {
id: fl id: backButton
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.left: parent.left
contentHeight: content.height + continueButton.implicitHeight + continueButton.anchors.bottomMargin + continueButton.anchors.topMargin anchors.right: parent.right
anchors.topMargin: 20
ColumnLayout { onFocusChanged: {
id: content if (this.activeFocus) {
listView.positionViewAtBeginning()
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
BackButtonType {
id: backButton
Layout.topMargin: 20
} }
}
}
ListViewType {
id: listView
anchors.top: backButton.bottom
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.left: parent.left
header: ColumnLayout {
width: listView.width
BaseHeaderType { BaseHeaderType {
Layout.fillWidth: true Layout.fillWidth: true
@ -45,53 +51,28 @@ PageType {
headerText: ApiServicesModel.getSelectedServiceData("name") headerText: ApiServicesModel.getSelectedServiceData("name")
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription") descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
} }
}
model: inputFields
spacing: 0
delegate: ColumnLayout {
width: listView.width
LabelWithImageType { LabelWithImageType {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: 16 Layout.margins: 16
imageSource: "qrc:/images/controls/map-pin.svg" imageSource: imagePath
leftText: qsTr("For the region") leftText: lText
rightText: ApiServicesModel.getSelectedServiceData("region") rightText: rText
} }
}
LabelWithImageType { footer: ColumnLayout {
Layout.fillWidth: true width: listView.width
Layout.margins: 16
imageSource: "qrc:/images/controls/tag.svg" spacing: 0
leftText: qsTr("Price")
rightText: ApiServicesModel.getSelectedServiceData("price")
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/history.svg"
leftText: qsTr("Work period")
rightText: ApiServicesModel.getSelectedServiceData("timeLimit")
visible: rightText !== ""
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/gauge.svg"
leftText: qsTr("Speed")
rightText: ApiServicesModel.getSelectedServiceData("speed")
}
LabelWithImageType {
Layout.fillWidth: true
Layout.margins: 16
imageSource: "qrc:/images/controls/info.svg"
leftText: qsTr("Features")
rightText: ""
}
ParagraphTextType { ParagraphTextType {
Layout.fillWidth: true Layout.fillWidth: true
@ -113,34 +94,84 @@ PageType {
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
} }
} }
}
}
BasicButtonType { BasicButtonType {
id: continueButton id: continueButton
anchors.right: parent.right Layout.fillWidth: true
anchors.left: parent.left Layout.topMargin: 32
anchors.bottom: parent.bottom Layout.bottomMargin: 32
Layout.leftMargin: 16
Layout.rightMargin: 16
anchors.topMargin: 32 text: qsTr("Connect")
anchors.rightMargin: 16
anchors.leftMargin: 16
anchors.bottomMargin: 32
text: qsTr("Connect") clickedFunc: function() {
var endpoint = ApiServicesModel.getStoreEndpoint()
clickedFunc: function() { if (endpoint !== undefined && endpoint !== "") {
var endpoint = ApiServicesModel.getStoreEndpoint() Qt.openUrlExternally(endpoint)
if (endpoint !== undefined && endpoint !== "") { PageController.closePage()
Qt.openUrlExternally(endpoint) PageController.closePage()
PageController.closePage() } else {
PageController.closePage() PageController.showBusyIndicator(true)
} else { ApiConfigsController.importServiceFromGateway()
PageController.showBusyIndicator(true) PageController.showBusyIndicator(false)
ApiConfigsController.importServiceFromGateway() }
PageController.showBusyIndicator(false) }
} }
} }
} }
property list<QtObject> inputFields: [
region,
price,
timeLimit,
speed,
features
]
QtObject {
id: region
readonly property string imagePath: "qrc:/images/controls/map-pin.svg"
readonly property string lText: qsTr("For the region")
readonly property string rText: ApiServicesModel.getSelectedServiceData("region")
property bool isVisible: true
}
QtObject {
id: price
readonly property string imagePath: "qrc:/images/controls/tag.svg"
readonly property string lText: qsTr("Price")
readonly property string rText: ApiServicesModel.getSelectedServiceData("price")
property bool isVisible: true
}
QtObject {
id: timeLimit
readonly property string imagePath: "qrc:/images/controls/history.svg"
readonly property string lText: qsTr("Work period")
readonly property string rText: ApiServicesModel.getSelectedServiceData("timeLimit")
property bool isVisible: rText !== ""
}
QtObject {
id: speed
readonly property string imagePath: "qrc:/images/controls/gauge.svg"
readonly property string lText: qsTr("Speed")
readonly property string rText: ApiServicesModel.getSelectedServiceData("speed")
property bool isVisible: true
}
QtObject {
id: features
readonly property string imagePath: "qrc:/images/controls/info.svg"
readonly property string lText: qsTr("Features")
readonly property string rText: ""
property bool isVisible: true
}
} }

View file

@ -40,7 +40,7 @@ PageType {
} }
} }
ListView { ListViewType {
id: servicesListView id: servicesListView
anchors.top: header.bottom anchors.top: header.bottom
@ -48,17 +48,11 @@ PageType {
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.topMargin: 16 anchors.topMargin: 16
spacing: 0 spacing: 0
property bool isFocusable: true
clip: true
reuseItems: true
model: ApiServicesModel model: ApiServicesModel
ScrollBar.vertical: ScrollBarType {}
delegate: Item { delegate: Item {
implicitWidth: servicesListView.width implicitWidth: servicesListView.width
implicitHeight: delegateContent.implicitHeight implicitHeight: delegateContent.implicitHeight

View file

@ -27,21 +27,13 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.fill: parent anchors.fill: parent
property bool isFocusable: true
ScrollBar.vertical: ScrollBarType {}
model: variants model: variants
clip: true
reuseItems: true
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width

View file

@ -28,41 +28,14 @@ PageType {
} }
} }
ListView { ListViewType {
id: listView id: listView
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
anchors.left: parent.left anchors.left: parent.left
property bool isFocusable: true
Keys.onTabPressed: {
FocusController.nextKeyTabItem()
}
Keys.onBacktabPressed: {
FocusController.previousKeyTabItem()
}
Keys.onUpPressed: {
FocusController.nextKeyUpItem()
}
Keys.onDownPressed: {
FocusController.nextKeyDownItem()
}
Keys.onLeftPressed: {
FocusController.nextKeyLeftItem()
}
Keys.onRightPressed: {
FocusController.nextKeyRightItem()
}
ScrollBar.vertical: ScrollBarType {}
header: ColumnLayout { header: ColumnLayout {
width: listView.width width: listView.width
@ -78,8 +51,6 @@ PageType {
model: inputFields model: inputFields
spacing: 16 spacing: 16
clip: true
reuseItems: true
delegate: ColumnLayout { delegate: ColumnLayout {
width: listView.width width: listView.width

View file

@ -20,6 +20,7 @@ PageType {
SortFilterProxyModel { SortFilterProxyModel {
id: proxyContainersModel id: proxyContainersModel
sourceModel: ContainersModel sourceModel: ContainersModel
filters: [ filters: [
ValueFilter { ValueFilter {
@ -42,102 +43,95 @@ PageType {
anchors.topMargin: 20 anchors.topMargin: 20
} }
FlickableType { ButtonGroup {
id: fl id: buttonGroup
}
ListViewType {
id: listView
property int dockerContainer
property int containerDefaultPort
property int containerDefaultTransportProto
anchors.top: backButton.bottom anchors.top: backButton.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
contentHeight: content.implicitHeight + setupLaterButton.anchors.bottomMargin anchors.left: parent.left
anchors.right: parent.right
Column { spacing: 16
header: ColumnLayout {
id: content id: content
anchors.top: parent.top width: listView.width
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
anchors.leftMargin: 16
spacing: 16 spacing: 16
BaseHeaderType { BaseHeaderType {
id: header id: header
implicitWidth: parent.width Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
headerTextMaximumLineCount: 10 headerTextMaximumLineCount: 10
headerText: qsTr("Choose Installation Type") headerText: qsTr("Choose Installation Type")
} }
}
ButtonGroup { model: proxyContainersModel
id: buttonGroup currentIndex: 0
}
ListView { delegate: ColumnLayout {
id: containers
width: parent.width
height: containers.contentItem.height
spacing: 16
currentIndex: 0 width: listView.width
clip: true
interactive: false
model: proxyContainersModel
property int dockerContainer CardType {
property int containerDefaultPort id: card
property int containerDefaultTransportProto
property bool isFocusable: true Layout.fillWidth: true
Layout.rightMargin: 16
Layout.leftMargin: 16
Layout.bottomMargin: 16
delegate: Item { headerText: easySetupHeader
implicitWidth: containers.width bodyText: easySetupDescription
implicitHeight: delegateContent.implicitHeight
ColumnLayout { ButtonGroup.group: buttonGroup
id: delegateContent
anchors.top: parent.top onClicked: function() {
anchors.left: parent.left checked = true
anchors.right: parent.right isEasySetup = true
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
CardType { listView.dockerContainer = dockerContainer
id: card listView.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
listView.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
Layout.fillWidth: true
headerText: easySetupHeader
bodyText: easySetupDescription
ButtonGroup.group: buttonGroup
onClicked: function() {
isEasySetup = true
var defaultContainerProto = ContainerProps.defaultProtocol(dockerContainer)
containers.dockerContainer = dockerContainer
containers.containerDefaultPort = ProtocolProps.getPortForInstall(defaultContainerProto)
containers.containerDefaultTransportProto = ProtocolProps.defaultTransportProto(defaultContainerProto)
}
}
}
} }
Component.onCompleted: { Keys.onReturnPressed: this.clicked()
var item = containers.itemAtIndex(containers.currentIndex) Keys.onEnterPressed: this.clicked()
if (item !== null) {
var button = item.children[0].children[0]
button.checked = true
button.clicked()
}
}
} }
}
footer: ColumnLayout {
width: listView.width
spacing: 16
DividerType { DividerType {
implicitWidth: parent.width Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
} }
CardType { CardType {
implicitWidth: parent.width Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
headerText: qsTr("Manual") headerText: qsTr("Manual")
bodyText: qsTr("Choose a VPN protocol") bodyText: qsTr("Choose a VPN protocol")
@ -146,25 +140,29 @@ PageType {
onClicked: function() { onClicked: function() {
isEasySetup = false isEasySetup = false
checked = true
} }
Keys.onReturnPressed: this.clicked()
Keys.onEnterPressed: this.clicked()
} }
BasicButtonType { BasicButtonType {
id: continueButton id: continueButton
implicitWidth: parent.width Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
text: qsTr("Continue") text: qsTr("Continue")
parentFlickable: fl
clickedFunc: function() { clickedFunc: function() {
if (root.isEasySetup) { if (root.isEasySetup) {
ContainersModel.setProcessedContainerIndex(containers.dockerContainer) ContainersModel.setProcessedContainerIndex(listView.dockerContainer)
PageController.goToPage(PageEnum.PageSetupWizardInstalling) PageController.goToPage(PageEnum.PageSetupWizardInstalling)
InstallController.install(containers.dockerContainer, InstallController.install(listView.dockerContainer,
containers.containerDefaultPort, listView.containerDefaultPort,
containers.containerDefaultTransportProto) listView.containerDefaultTransportProto)
} else { } else {
PageController.goToPage(PageEnum.PageSetupWizardProtocols) PageController.goToPage(PageEnum.PageSetupWizardProtocols)
} }
@ -174,9 +172,11 @@ PageType {
BasicButtonType { BasicButtonType {
id: setupLaterButton id: setupLaterButton
implicitWidth: parent.width Layout.fillWidth: true
anchors.topMargin: 8 Layout.topMargin: 8
anchors.bottomMargin: 24 Layout.bottomMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
defaultColor: AmneziaStyle.color.transparent defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite hoveredColor: AmneziaStyle.color.translucentWhite
@ -185,9 +185,6 @@ PageType {
textColor: AmneziaStyle.color.paleGray textColor: AmneziaStyle.color.paleGray
borderWidth: 1 borderWidth: 1
Keys.onTabPressed: lastItemTabClicked(focusItem)
parentFlickable: fl
visible: { visible: {
if (PageController.isTriggeredByConnectButton()) { if (PageController.isTriggeredByConnectButton()) {
PageController.setTriggeredByConnectButton(false) PageController.setTriggeredByConnectButton(false)
@ -205,5 +202,15 @@ PageType {
} }
} }
} }
Component.onCompleted: {
var item = listView.itemAtIndex(listView.currentIndex)
if (item !== null) {
var button = item.children[0]
button.checked = true
button.clicked()
}
}
} }
} }

View file

@ -85,92 +85,76 @@ PageType {
] ]
} }
FlickableType { ListViewType {
id: listView
anchors.fill: parent anchors.fill: parent
contentHeight: content.height
Column { currentIndex: -1
id: content
anchors.top: parent.top model: proxyContainersModel
anchors.left: parent.left
anchors.right: parent.right
spacing: 16 delegate: ColumnLayout {
width: listView.width
ListView { BaseHeaderType {
id: container Layout.fillWidth: true
width: parent.width Layout.topMargin: 20
height: container.contentItem.height Layout.leftMargin: 16
currentIndex: -1 Layout.rightMargin: 16
clip: true
interactive: false
model: proxyContainersModel
delegate: Item { headerText: qsTr("Installing")
implicitWidth: container.width descriptionText: name
implicitHeight: delegateContent.implicitHeight }
ColumnLayout { ProgressBarType {
id: delegateContent id: progressBar
anchors.fill: parent Layout.fillWidth: true
anchors.rightMargin: 16 Layout.topMargin: 32
anchors.leftMargin: 16 Layout.leftMargin: 16
Layout.rightMargin: 16
BaseHeaderType { Timer {
Layout.fillWidth: true id: timer
Layout.topMargin: 20
headerText: qsTr("Installing") interval: 300
descriptionText: name repeat: true
} running: root.isTimerRunning
onTriggered: {
ProgressBarType { progressBar.value += 0.003
id: progressBar
Layout.fillWidth: true
Layout.topMargin: 32
Timer {
id: timer
interval: 300
repeat: true
running: root.isTimerRunning
onTriggered: {
progressBar.value += 0.003
}
}
}
ParagraphTextType {
id: progressText
Layout.fillWidth: true
Layout.topMargin: 8
text: root.progressBarText
}
BasicButtonType {
id: cancelIntallationButton
Layout.fillWidth: true
Layout.topMargin: 24
visible: root.isCancelButtonVisible
text: qsTr("Cancel installation")
clickedFunc: function() {
InstallController.cancelInstallation()
PageController.showBusyIndicator(true)
}
}
} }
} }
} }
ParagraphTextType {
id: progressText
Layout.fillWidth: true
Layout.topMargin: 8
Layout.leftMargin: 16
Layout.rightMargin: 16
text: root.progressBarText
}
BasicButtonType {
id: cancelIntallationButton
Layout.fillWidth: true
Layout.topMargin: 24
Layout.leftMargin: 16
Layout.rightMargin: 16
visible: root.isCancelButtonVisible
text: qsTr("Cancel installation")
clickedFunc: function() {
InstallController.cancelInstallation()
PageController.showBusyIndicator(true)
}
}
} }
} }
} }

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