mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-22 02:01:08 +07:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ab4f454c19 | |||
| e96dfe5800 | |||
| 768c51dbbe | |||
| 5acbdd7af6 | |||
| a6e6de33c8 | |||
| 53c7fd4d81 | |||
| 2608ea4367 | |||
| d20ed4ad01 | |||
| eae2936449 | |||
| da8ad1f6ba | |||
| 5472347969 | |||
| a43f7a6926 | |||
| 47f917de0b | |||
| dbeb7edd7a | |||
| 6cede712f5 | |||
| d328739192 | |||
| d15c0bd962 | |||
| d53c794936 | |||
| e5dcb25a4a | |||
| f9002b4f43 | |||
| 0531508a75 | |||
| 174e85a20a | |||
| e9abb6f1e2 | |||
| 5be44f9596 | |||
| 90efaaff92 | |||
| 99b554e7c3 | |||
| ac0ce8a6f6 | |||
| 9f9da885b7 | |||
| f51fd2bf3e | |||
| c8378fd32d | |||
| d767214f10 | |||
| e027c504ae | |||
| 669a95d975 | |||
| a96df5d518 | |||
| c5c81735a0 | |||
| c933745707 | |||
| 6710fd18b3 | |||
| 1b78a71529 | |||
| 1909d3c94e | |||
| 10a107716c | |||
| 5445e6637b | |||
| 2380cd5cfb | |||
| 42661618dc | |||
| 8a7e901d7a | |||
| f8bea71716 | |||
| efcc0b7efc | |||
| 4d17e913b5 | |||
| b341934863 | |||
| 127f8ed3bb | |||
| 9dca80de18 | |||
| b0a6bcc055 | |||
| f0626e2eca | |||
| 979ab42c5a | |||
| e152e84ddc | |||
| 2605978889 | |||
| a2d30efaab |
@@ -255,7 +255,20 @@ jobs:
|
||||
env:
|
||||
# Keep compat with MacOS 10.15 aka Catalina by Qt 6.4
|
||||
QT_VERSION: 6.4.3
|
||||
QIF_VERSION: 4.6
|
||||
|
||||
MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
||||
|
||||
MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }}
|
||||
MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }}
|
||||
MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }}
|
||||
|
||||
MAC_INSTALLER_SIGNER_CERT: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
||||
MAC_INSTALLER_SIGNER_ID: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
||||
MAC_INSTALL_CERT_PW: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
||||
|
||||
APPLE_DEV_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
||||
APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
||||
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||
@@ -283,11 +296,6 @@ jobs:
|
||||
set-env: 'true'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
|
||||
run: |
|
||||
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
|
||||
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
|
||||
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
@@ -301,14 +309,13 @@ jobs:
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
|
||||
bash deploy/build_macos.sh
|
||||
bash deploy/build_macos.sh -n
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_MacOS_old_installer
|
||||
path: AmneziaVPN.dmg
|
||||
path: deploy/build/pkg/AmneziaVPN.pkg
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
@@ -325,7 +332,20 @@ jobs:
|
||||
|
||||
env:
|
||||
QT_VERSION: 6.8.0
|
||||
QIF_VERSION: 4.8.1
|
||||
|
||||
MAC_TEAM_ID: ${{ secrets.MAC_TEAM_ID }}
|
||||
|
||||
MAC_APP_CERT_CERT: ${{ secrets.MAC_APP_CERT_CERT }}
|
||||
MAC_SIGNER_ID: ${{ secrets.MAC_SIGNER_ID }}
|
||||
MAC_APP_CERT_PW: ${{ secrets.MAC_APP_CERT_PW }}
|
||||
|
||||
MAC_INSTALLER_SIGNER_CERT: ${{ secrets.MAC_INSTALLER_SIGNER_CERT }}
|
||||
MAC_INSTALLER_SIGNER_ID: ${{ secrets.MAC_INSTALLER_SIGNER_ID }}
|
||||
MAC_INSTALL_CERT_PW: ${{ secrets.MAC_INSTALL_CERT_PW }}
|
||||
|
||||
APPLE_DEV_EMAIL: ${{ secrets.APPLE_DEV_EMAIL }}
|
||||
APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
|
||||
|
||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||
PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
|
||||
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
|
||||
@@ -353,11 +373,6 @@ jobs:
|
||||
set-env: 'true'
|
||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||
|
||||
- name: 'Install Qt Installer Framework ${{ env.QIF_VERSION }}'
|
||||
run: |
|
||||
mkdir -pv ${{ runner.temp }}/Qt/Tools/QtInstallerFramework
|
||||
wget https://qt.amzsvc.com/tools/ifw/${{ env.QIF_VERSION }}.zip
|
||||
unzip ${{ env.QIF_VERSION }}.zip -d ${{ runner.temp }}/Qt/Tools/QtInstallerFramework/
|
||||
|
||||
- name: 'Get sources'
|
||||
uses: actions/checkout@v4
|
||||
@@ -371,14 +386,13 @@ jobs:
|
||||
- name: 'Build project'
|
||||
run: |
|
||||
export QT_BIN_DIR="${{ runner.temp }}/Qt/${{ env.QT_VERSION }}/macos/bin"
|
||||
export QIF_BIN_DIR="${{ runner.temp }}/Qt/Tools/QtInstallerFramework/${{ env.QIF_VERSION }}/bin"
|
||||
bash deploy/build_macos.sh
|
||||
bash deploy/build_macos.sh -n
|
||||
|
||||
- name: 'Upload installer artifact'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AmneziaVPN_MacOS_installer
|
||||
path: AmneziaVPN.dmg
|
||||
path: deploy/build/pkg/AmneziaVPN.pkg
|
||||
retention-days: 7
|
||||
|
||||
- name: 'Upload unpacked artifact'
|
||||
|
||||
@@ -138,3 +138,4 @@ CMakeFiles/
|
||||
ios-ne-build.sh
|
||||
macos-ne-build.sh
|
||||
macos-signed-build.sh
|
||||
macos-with-sign-build.sh
|
||||
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||
|
||||
set(PROJECT AmneziaVPN)
|
||||
set(AMNEZIAVPN_VERSION 4.8.9.2)
|
||||
|
||||
project(${PROJECT} VERSION 4.8.7.2
|
||||
project(${PROJECT} VERSION ${AMNEZIAVPN_VERSION}
|
||||
DESCRIPTION "AmneziaVPN"
|
||||
HOMEPAGE_URL "https://amnezia.org/"
|
||||
)
|
||||
@@ -11,7 +12,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||
|
||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||
set(APP_ANDROID_VERSION_CODE 2086)
|
||||
set(APP_ANDROID_VERSION_CODE 2092)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
set(MZ_PLATFORM_NAME "linux")
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
### [English]([https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md](https://github.com/amnezia-vpn/amnezia-client/tree/dev?tab=readme-ov-file#)) | [Русский](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README_RU.md)
|
||||
|
||||
|
||||
[Amnezia](https://amnezia.org) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
|
||||
[Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is an open-source VPN client, with a key feature that enables you to deploy your own VPN server on your server.
|
||||
|
||||
[](https://amnezia.org)
|
||||
|
||||
### [Website](https://amnezia.org) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
|
||||
### [Website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) | [Alt website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror) | [Documentation](https://docs.amnezia.org) | [Troubleshooting](https://docs.amnezia.org/troubleshooting)
|
||||
|
||||
> [!TIP]
|
||||
> If the [Amnezia website](https://amnezia.org) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org ).
|
||||
> If the [Amnezia website](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en) is blocked in your region, you can use an [Alternative website link](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-en-mirror).
|
||||
|
||||
<a href="https://amnezia.org/downloads"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
||||
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
|
||||
<a href="https://amnezia.org/en/downloads?utm_source=github&utm_campaign=amnezia_button-readme-en"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
||||
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/en/downloads&utm_source=github&utm_campaign=amnezia_button-readme-en-mirrow"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-alt.svg" width="150" style="max-width: 100%;"></a>
|
||||
|
||||
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||
|
||||
|
||||
+4
-4
@@ -6,16 +6,16 @@
|
||||
[](https://gitpod.io/#https://github.com/amnezia-vpn/amnezia-client)
|
||||
|
||||
### [English](https://github.com/amnezia-vpn/amnezia-client/blob/dev/README.md) | Русский
|
||||
[AmneziaVPN](https://amnezia.org) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
||||
[AmneziaVPN](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) — это open source VPN-клиент, ключевая особенность которого заключается в возможности развернуть собственный VPN на вашем сервере.
|
||||
|
||||
[](https://amnezia.org)
|
||||
|
||||
### [Сайт](https://amnezia.org) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
||||
### [Сайт](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) | [Зеркало сайта](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror) | [Документация](https://docs.amnezia.org) | [Решение проблем](https://docs.amnezia.org/troubleshooting)
|
||||
|
||||
> [!TIP]
|
||||
> Если [сайт Amnezia](https://amnezia.org) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org).
|
||||
> Если [сайт Amnezia](https://amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru) заблокирован в вашем регионе, вы можете воспользоваться [ссылкой на зеркало](https://storage.googleapis.com/amnezia/amnezia.org?utm_source=github&utm_campaign=amnezia_website-readme-ru-mirror).
|
||||
|
||||
<a href="https://storage.googleapis.com/amnezia/q9p19109"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
||||
<a href="https://storage.googleapis.com/amnezia/amnezia.org?m-path=/ru/downloads&utm_source=github&utm_campaign=amnezia_button-readme-ru-mirror"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/download-website-ru.svg" width="150" style="max-width: 100%; margin-right: 10px"></a>
|
||||
|
||||
|
||||
[Все релизы](https://github.com/amnezia-vpn/amnezia-client/releases)
|
||||
|
||||
+1
-1
Submodule client/3rd-prebuilt updated: e3b6a33205...522e8d33a9
Vendored
+1
-1
Submodule client/3rd/amneziawg-apple updated: 76e7db556a...811af0a83b
@@ -10,6 +10,8 @@ import java.nio.channels.FileChannel
|
||||
import java.nio.channels.FileLock
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import org.amnezia.vpn.util.Log.Priority.D
|
||||
import org.amnezia.vpn.util.Log.Priority.E
|
||||
@@ -135,8 +137,8 @@ object Log {
|
||||
}
|
||||
|
||||
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
|
||||
val date = LocalDateTime.now().format(dateTimeFormat)
|
||||
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
||||
val utcDate = ZonedDateTime.now(ZoneOffset.UTC).format(dateTimeFormat)
|
||||
return "${utcDate}Z ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
|
||||
"$tag: $msg\n"
|
||||
}
|
||||
|
||||
|
||||
+10
-8
@@ -120,18 +120,20 @@ open class Wireguard : Protocol() {
|
||||
configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) }
|
||||
configData.optStringOrNull("S1")?.let { setS1(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("H2")?.let { setH2(it.toLong()) }
|
||||
configData.optStringOrNull("H3")?.let { setH3(it.toLong()) }
|
||||
configData.optStringOrNull("H4")?.let { setH4(it.toLong()) }
|
||||
configData.optStringOrNull("I1")?.let { setI1(it.toString()) }
|
||||
configData.optStringOrNull("I2")?.let { setI2(it.toString()) }
|
||||
configData.optStringOrNull("I3")?.let { setI3(it.toString()) }
|
||||
configData.optStringOrNull("I4")?.let { setI4(it.toString()) }
|
||||
configData.optStringOrNull("I5")?.let { setI5(it.toString()) }
|
||||
configData.optStringOrNull("J1")?.let { setJ1(it.toString()) }
|
||||
configData.optStringOrNull("J2")?.let { setJ2(it.toString()) }
|
||||
configData.optStringOrNull("J3")?.let { setJ3(it.toString()) }
|
||||
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()) }
|
||||
}
|
||||
|
||||
|
||||
+39
-2
@@ -20,10 +20,21 @@ open class WireguardConfig protected constructor(
|
||||
val jmax: Int?,
|
||||
val s1: Int?,
|
||||
val s2: Int?,
|
||||
val s3: Int?,
|
||||
val s4: Int?,
|
||||
val h1: Long?,
|
||||
val h2: 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) {
|
||||
|
||||
protected constructor(builder: Builder) : this(
|
||||
@@ -39,10 +50,21 @@ open class WireguardConfig protected constructor(
|
||||
builder.jmax,
|
||||
builder.s1,
|
||||
builder.s2,
|
||||
builder.s3,
|
||||
builder.s4,
|
||||
builder.h1,
|
||||
builder.h2,
|
||||
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()) {
|
||||
@@ -61,10 +83,21 @@ open class WireguardConfig protected constructor(
|
||||
appendLine("jmax=$jmax")
|
||||
appendLine("s1=$s1")
|
||||
appendLine("s2=$s2")
|
||||
s3?.let { appendLine("s3=$it") }
|
||||
s4?.let { appendLine("s4=$it") }
|
||||
appendLine("h1=$h1")
|
||||
appendLine("h2=$h2")
|
||||
appendLine("h3=$h3")
|
||||
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") }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +150,8 @@ open class WireguardConfig protected constructor(
|
||||
internal var jmax: Int? = null
|
||||
internal var s1: Int? = null
|
||||
internal var s2: Int? = null
|
||||
internal var s3: Int? = null
|
||||
internal var s4: Int? = null
|
||||
internal var h1: Long? = null
|
||||
internal var h2: Long? = null
|
||||
internal var h3: Long? = null
|
||||
@@ -148,6 +183,8 @@ open class WireguardConfig protected constructor(
|
||||
fun setJmax(jmax: Int) = apply { this.jmax = jmax }
|
||||
fun setS1(s1: Int) = apply { this.s1 = s1 }
|
||||
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 setH2(h2: Long) = apply { this.h2 = h2 }
|
||||
fun setH3(h3: Long) = apply { this.h3 = h3 }
|
||||
|
||||
@@ -18,7 +18,11 @@ set(LIBS ${LIBS}
|
||||
${FW_NETWORK_EXTENSION}
|
||||
)
|
||||
|
||||
set_target_properties(${PROJECT} PROPERTIES MACOSX_BUNDLE TRUE)
|
||||
set_target_properties(${PROJECT} PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "${CMAKE_PROJECT_VERSION_TWEAK}"
|
||||
)
|
||||
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "awg_configurator.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
@@ -39,15 +40,20 @@ QString AwgConfigurator::createConfig(const ServerCredentials &credentials, Dock
|
||||
jsonConfig[config_key::responsePacketMagicHeader] = configMap.value(config_key::responsePacketMagicHeader);
|
||||
jsonConfig[config_key::underloadPacketMagicHeader] = configMap.value(config_key::underloadPacketMagicHeader);
|
||||
jsonConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
|
||||
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::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] =
|
||||
containerConfig.value(ProtocolProps::protoToString(Proto::Awg)).toObject().value(config_key::mtu).toString(protocols::awg::defaultMtu);
|
||||
|
||||
|
||||
@@ -118,6 +118,12 @@ QString OpenVpnConfigurator::processConfigWithLocalSettings(const QPair<QString,
|
||||
QRegularExpression regex("redirect-gateway.*");
|
||||
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()) {
|
||||
config.append("\nredirect-gateway def1 ipv6 bypass-dhcp\n");
|
||||
config.append("block-ipv6\n");
|
||||
@@ -161,6 +167,12 @@ QString OpenVpnConfigurator::processConfigWithExportSettings(const QPair<QString
|
||||
QRegularExpression regex("redirect-gateway.*");
|
||||
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");
|
||||
|
||||
// Prevent ipv6 leak
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace apiDefs
|
||||
constexpr QLatin1String stackType("stack_type");
|
||||
constexpr QLatin1String serviceType("service_type");
|
||||
constexpr QLatin1String cliVersion("cli_version");
|
||||
constexpr QLatin1String supportedProtocols("supported_protocols");
|
||||
|
||||
constexpr QLatin1String vpnKey("vpn_key");
|
||||
constexpr QLatin1String config("config");
|
||||
|
||||
@@ -120,6 +120,9 @@ void CoreController::initControllers()
|
||||
connect(m_installController.get(), &InstallController::currentContainerUpdated, m_connectionController.get(),
|
||||
&ConnectionController::onCurrentContainerUpdated); // TODO remove this
|
||||
|
||||
connect(m_installController.get(), &InstallController::profileCleared,
|
||||
m_protocolsModel.get(), &ProtocolsModel::updateModel);
|
||||
|
||||
m_importController.reset(new ImportController(m_serversModel, m_containersModel, m_settings));
|
||||
m_engine->rootContext()->setContextProperty("ImportController", m_importController.get());
|
||||
|
||||
@@ -242,7 +245,10 @@ void CoreController::initNotificationHandler()
|
||||
connect(m_notificationHandler.get(), &NotificationHandler::disconnectRequested, m_connectionController.get(),
|
||||
&ConnectionController::closeConnection);
|
||||
connect(this, &CoreController::translationsUpdated, m_notificationHandler.get(), &NotificationHandler::onTranslationsUpdated);
|
||||
#endif
|
||||
|
||||
auto* trayHandler = qobject_cast<SystemTrayNotificationHandler*>(m_notificationHandler.get());
|
||||
connect(this, &CoreController::websiteUrlChanged, trayHandler, &SystemTrayNotificationHandler::updateWebsiteUrl);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CoreController::updateTranslator(const QLocale &locale)
|
||||
@@ -279,6 +285,7 @@ void CoreController::updateTranslator(const QLocale &locale)
|
||||
m_engine->retranslate();
|
||||
|
||||
emit translationsUpdated();
|
||||
emit websiteUrlChanged(m_languageModel->getCurrentSiteUrl());
|
||||
}
|
||||
|
||||
void CoreController::initErrorMessagesHandler()
|
||||
@@ -299,13 +306,10 @@ void CoreController::setQmlRoot()
|
||||
|
||||
void CoreController::initApiCountryModelUpdateHandler()
|
||||
{
|
||||
// TODO
|
||||
connect(m_serversModel.get(), &ServersModel::updateApiCountryModel, this, [this]() {
|
||||
m_apiCountryModel->updateModel(m_serversModel->getProcessedServerData("apiAvailableCountries").toJsonArray(),
|
||||
m_serversModel->getProcessedServerData("apiServerCountryCode").toString());
|
||||
});
|
||||
connect(m_serversModel.get(), &ServersModel::updateApiServicesModel, this,
|
||||
[this]() { m_apiServicesModel->updateModel(m_serversModel->getProcessedServerData("apiConfig").toJsonObject()); });
|
||||
}
|
||||
|
||||
void CoreController::initContainerModelUpdateHandler()
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <QQmlContext>
|
||||
#include <QThread>
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include "ui/systemtray_notificationhandler.h"
|
||||
#endif
|
||||
|
||||
#include "ui/controllers/api/apiConfigsController.h"
|
||||
#include "ui/controllers/api/apiSettingsController.h"
|
||||
#include "ui/controllers/api/apiPremV1MigrationController.h"
|
||||
@@ -61,6 +65,7 @@ public:
|
||||
|
||||
signals:
|
||||
void translationsUpdated();
|
||||
void websiteUrlChanged(const QString &newUrl);
|
||||
|
||||
private:
|
||||
void initModels();
|
||||
|
||||
@@ -349,7 +349,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||
if ((oldProtoConfig.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)
|
||||
!= 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)
|
||||
!= newProtoConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount))
|
||||
|| (oldProtoConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize)
|
||||
@@ -367,25 +367,11 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||
|| (oldProtoConfig.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))
|
||||
!= newProtoConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader))
|
||||
// || (oldProtoConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1))
|
||||
// != newProtoConfig.value(config_key::specialJunk1).toString(protocols::awg::defaultSpecialJunk1)
|
||||
// || (oldProtoConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2))
|
||||
// != newProtoConfig.value(config_key::specialJunk2).toString(protocols::awg::defaultSpecialJunk2)
|
||||
// || (oldProtoConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3))
|
||||
// != newProtoConfig.value(config_key::specialJunk3).toString(protocols::awg::defaultSpecialJunk3)
|
||||
// || (oldProtoConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4))
|
||||
// != newProtoConfig.value(config_key::specialJunk4).toString(protocols::awg::defaultSpecialJunk4)
|
||||
// || (oldProtoConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5))
|
||||
// != newProtoConfig.value(config_key::specialJunk5).toString(protocols::awg::defaultSpecialJunk5)
|
||||
// || (oldProtoConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1))
|
||||
// != newProtoConfig.value(config_key::controlledJunk1).toString(protocols::awg::defaultControlledJunk1)
|
||||
// || (oldProtoConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2))
|
||||
// != newProtoConfig.value(config_key::controlledJunk2).toString(protocols::awg::defaultControlledJunk2)
|
||||
// || (oldProtoConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3))
|
||||
// != newProtoConfig.value(config_key::controlledJunk3).toString(protocols::awg::defaultControlledJunk3)
|
||||
// || (oldProtoConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout))
|
||||
// != newProtoConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout))
|
||||
!= 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;
|
||||
}
|
||||
@@ -394,7 +380,7 @@ bool ServerController::isReinstallContainerRequired(DockerContainer container, c
|
||||
if ((oldProtoConfig.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)
|
||||
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
|
||||
!= newProtoConfig.value(config_key::port).toString(protocols::wireguard::defaultPort)))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -479,6 +465,8 @@ ErrorCode ServerController::buildContainerWorker(const ServerCredentials &creden
|
||||
return ErrorCode::ServerDockerOnCgroupsV2;
|
||||
if (stdOut.contains("cgroup mountpoint does not exist"))
|
||||
return ErrorCode::ServerCgroupMountpoint;
|
||||
if (stdOut.contains("have reached") && stdOut.contains("pull rate limit"))
|
||||
return ErrorCode::DockerPullRateLimit;
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -657,15 +645,9 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
|
||||
vars.append({ { "$RESPONSE_PACKET_MAGIC_HEADER", amneziaWireguarConfig.value(config_key::responsePacketMagicHeader).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({ { "$SPECIAL_JUNK_1", amneziaWireguarConfig.value(config_key::specialJunk1).toString() } });
|
||||
// vars.append({ { "$SPECIAL_JUNK_2", amneziaWireguarConfig.value(config_key::specialJunk2).toString() } });
|
||||
// vars.append({ { "$SPECIAL_JUNK_3", amneziaWireguarConfig.value(config_key::specialJunk3).toString() } });
|
||||
// vars.append({ { "$SPECIAL_JUNK_4", amneziaWireguarConfig.value(config_key::specialJunk4).toString() } });
|
||||
// vars.append({ { "$SPECIAL_JUNK_5", amneziaWireguarConfig.value(config_key::specialJunk5).toString() } });
|
||||
// vars.append({ { "$CONTROLLED_JUNK_1", amneziaWireguarConfig.value(config_key::controlledJunk1).toString() } });
|
||||
// vars.append({ { "$CONTROLLED_JUNK_2", amneziaWireguarConfig.value(config_key::controlledJunk2).toString() } });
|
||||
// vars.append({ { "$CONTROLLED_JUNK_3", amneziaWireguarConfig.value(config_key::controlledJunk3).toString() } });
|
||||
// vars.append({ { "$SPECIAL_HANDSHAKE_TIMEOUT", amneziaWireguarConfig.value(config_key::specialHandshakeTimeout).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
|
||||
vars.append({ { "$SOCKS5_PROXY_PORT", socks5ProxyConfig.value(config_key::port).toString(protocols::socks5Proxy::defaultPort) } });
|
||||
@@ -853,7 +835,7 @@ ErrorCode ServerController::isServerDpkgBusy(const ServerCredentials &credential
|
||||
|
||||
if (stdOut.contains("Packet manager not found"))
|
||||
return ErrorCode::ServerPacketManagerError;
|
||||
if (stdOut.contains("fuser not installed"))
|
||||
if (stdOut.contains("fuser not installed") || stdOut.contains("cat not installed"))
|
||||
return ErrorCode::NoError;
|
||||
|
||||
if (stdOut.isEmpty()) {
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace amnezia
|
||||
ServerUserPasswordRequired = 210,
|
||||
ServerDockerOnCgroupsV2 = 211,
|
||||
ServerCgroupMountpoint = 212,
|
||||
DockerPullRateLimit = 213,
|
||||
|
||||
// Ssh connection errors
|
||||
SshRequestDeniedError = 300,
|
||||
|
||||
@@ -28,6 +28,7 @@ QString errorString(ErrorCode code) {
|
||||
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::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
|
||||
case(ErrorCode::SshRequestDeniedError): errorMessage = QObject::tr("SSH request was denied"); break;
|
||||
|
||||
+37
-16
@@ -169,11 +169,14 @@ bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
|
||||
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
|
||||
(config.m_hopType == InterfaceConfig::SingleHop)) {
|
||||
QList<QHostAddress> resolvers;
|
||||
resolvers.append(QHostAddress(config.m_dnsServer));
|
||||
resolvers.append(QHostAddress(config.m_primaryDnsServer));
|
||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
||||
resolvers.append(QHostAddress(config.m_secondaryDnsServer));
|
||||
}
|
||||
|
||||
// If the DNS is not the Gateway, it's a user defined DNS
|
||||
// thus, not add any other :)
|
||||
if (config.m_dnsServer == config.m_serverIpv4Gateway) {
|
||||
if (config.m_primaryDnsServer == config.m_serverIpv4Gateway) {
|
||||
resolvers.append(QHostAddress(config.m_serverIpv6Gateway));
|
||||
}
|
||||
|
||||
@@ -279,15 +282,26 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||
config.m_serverIpv4Gateway = obj.value("serverIpv4Gateway").toString();
|
||||
config.m_serverIpv6Gateway = obj.value("serverIpv6Gateway").toString();
|
||||
|
||||
if (!obj.contains("dnsServer")) {
|
||||
config.m_dnsServer = QString();
|
||||
if (!obj.contains("primaryDnsServer")) {
|
||||
config.m_primaryDnsServer = QString();
|
||||
} else {
|
||||
QJsonValue value = obj.value("dnsServer");
|
||||
QJsonValue value = obj.value("primaryDnsServer");
|
||||
if (!value.isString()) {
|
||||
logger.error() << "dnsServer is not a string";
|
||||
return false;
|
||||
}
|
||||
config.m_dnsServer = value.toString();
|
||||
config.m_primaryDnsServer = 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")) {
|
||||
@@ -391,6 +405,13 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||
if (!obj.value("S2").isNull()) {
|
||||
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()) {
|
||||
config.m_initPacketMagicHeader = obj.value("H1").toString();
|
||||
}
|
||||
@@ -405,31 +426,31 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) {
|
||||
}
|
||||
|
||||
if (!obj.value("I1").isNull()) {
|
||||
config.m_specialJunk["I1"] = obj.value("I1").toString();
|
||||
config.m_specialJunk["I1"] = obj.value("I1").toString();
|
||||
}
|
||||
if (!obj.value("I2").isNull()) {
|
||||
config.m_specialJunk["I2"] = obj.value("I2").toString();
|
||||
config.m_specialJunk["I2"] = obj.value("I2").toString();
|
||||
}
|
||||
if (!obj.value("I3").isNull()) {
|
||||
config.m_specialJunk["I3"] = obj.value("I3").toString();
|
||||
config.m_specialJunk["I3"] = obj.value("I3").toString();
|
||||
}
|
||||
if (!obj.value("I4").isNull()) {
|
||||
config.m_specialJunk["I4"] = obj.value("I4").toString();
|
||||
config.m_specialJunk["I4"] = obj.value("I4").toString();
|
||||
}
|
||||
if (!obj.value("I5").isNull()) {
|
||||
config.m_specialJunk["I5"] = obj.value("I5").toString();
|
||||
config.m_specialJunk["I5"] = obj.value("I5").toString();
|
||||
}
|
||||
if (!obj.value("J1").isNull()) {
|
||||
config.m_controlledJunk["J1"] = obj.value("J1").toString();
|
||||
config.m_controlledJunk["J1"] = obj.value("J1").toString();
|
||||
}
|
||||
if (!obj.value("J2").isNull()) {
|
||||
config.m_controlledJunk["J2"] = obj.value("J2").toString();
|
||||
config.m_controlledJunk["J2"] = obj.value("J2").toString();
|
||||
}
|
||||
if (!obj.value("J3").isNull()) {
|
||||
config.m_controlledJunk["J3"] = obj.value("J3").toString();
|
||||
config.m_controlledJunk["J3"] = obj.value("J3").toString();
|
||||
}
|
||||
if (!obj.value("Itime").isNull()) {
|
||||
config.m_specialHandshakeTimeout = obj.value("Itime").toString();
|
||||
config.m_specialHandshakeTimeout = obj.value("Itime").toString();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -474,7 +495,7 @@ bool Daemon::deactivate(bool emitSignals) {
|
||||
|
||||
m_connections.clear();
|
||||
// Delete the interface
|
||||
return wgutils()->deleteInterface();
|
||||
return wgutils()->deleteInterface();
|
||||
}
|
||||
|
||||
QString Daemon::logs() {
|
||||
|
||||
@@ -28,7 +28,8 @@ QJsonObject InterfaceConfig::toJson() const {
|
||||
(m_hopType == InterfaceConfig::SingleHop)) {
|
||||
json.insert("serverIpv4Gateway", QJsonValue(m_serverIpv4Gateway));
|
||||
json.insert("serverIpv6Gateway", QJsonValue(m_serverIpv6Gateway));
|
||||
json.insert("dnsServer", QJsonValue(m_dnsServer));
|
||||
json.insert("primaryDnsServer", QJsonValue(m_primaryDnsServer));
|
||||
json.insert("secondaryDnsServer", QJsonValue(m_secondaryDnsServer));
|
||||
}
|
||||
|
||||
QJsonArray allowedIPAddesses;
|
||||
@@ -100,11 +101,15 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||
out << "MTU = " << m_deviceMTU << "\n";
|
||||
}
|
||||
|
||||
if (!m_dnsServer.isNull()) {
|
||||
QStringList dnsServers(m_dnsServer);
|
||||
if (!m_primaryDnsServer.isNull()) {
|
||||
QStringList dnsServers;
|
||||
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
|
||||
// thus, not add any other :)
|
||||
if (m_dnsServer == m_serverIpv4Gateway) {
|
||||
if (m_primaryDnsServer == m_serverIpv4Gateway) {
|
||||
dnsServers.append(m_serverIpv6Gateway);
|
||||
}
|
||||
out << "DNS = " << dnsServers.join(", ") << "\n";
|
||||
@@ -125,6 +130,12 @@ QString InterfaceConfig::toWgConf(const QMap<QString, QString>& extra) const {
|
||||
if (!m_responsePacketJunkSize.isNull()) {
|
||||
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()) {
|
||||
out << "H1 = " << m_initPacketMagicHeader << "\n";
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ class InterfaceConfig {
|
||||
QString m_serverIpv4AddrIn;
|
||||
QString m_serverPskKey;
|
||||
QString m_serverIpv6AddrIn;
|
||||
QString m_dnsServer;
|
||||
QString m_primaryDnsServer;
|
||||
QString m_secondaryDnsServer;
|
||||
int m_serverPort = 0;
|
||||
int m_deviceMTU = 1420;
|
||||
QList<IPAddress> m_allowedIPAddressRanges;
|
||||
@@ -49,6 +50,8 @@ class InterfaceConfig {
|
||||
QString m_junkPacketMaxSize;
|
||||
QString m_initPacketJunkSize;
|
||||
QString m_responsePacketJunkSize;
|
||||
QString m_cookieReplyPacketJunkSize;
|
||||
QString m_transportPacketJunkSize;
|
||||
QString m_initPacketMagicHeader;
|
||||
QString m_responsePacketMagicHeader;
|
||||
QString m_underloadPacketMagicHeader;
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
<true/>
|
||||
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
|
||||
<key>LSMultipleInstancesProhibited</key>
|
||||
<true/>
|
||||
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -149,7 +149,14 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
json.insert("serverPort", wgConfig.value(amnezia::config_key::port).toInt());
|
||||
json.insert("serverIpv4Gateway", wgConfig.value(amnezia::config_key::hostName));
|
||||
// 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;
|
||||
|
||||
@@ -237,6 +244,8 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
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::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::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
||||
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
||||
@@ -255,6 +264,8 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
&& !wgConfig.value(amnezia::config_key::junkPacketMaxSize).isUndefined()
|
||||
&& !wgConfig.value(amnezia::config_key::initPacketJunkSize).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::responsePacketMagicHeader).isUndefined()
|
||||
&& !wgConfig.value(amnezia::config_key::underloadPacketMagicHeader).isUndefined()
|
||||
@@ -273,6 +284,8 @@ void LocalSocketController::activate(const QJsonObject &rawConfig) {
|
||||
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::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::responsePacketMagicHeader, wgConfig.value(amnezia::config_key::responsePacketMagicHeader));
|
||||
json.insert(amnezia::config_key::underloadPacketMagicHeader, wgConfig.value(amnezia::config_key::underloadPacketMagicHeader));
|
||||
|
||||
@@ -4,7 +4,7 @@ struct WGConfig: Decodable {
|
||||
let initPacketMagicHeader, responsePacketMagicHeader: String?
|
||||
let underloadPacketMagicHeader, transportPacketMagicHeader: String?
|
||||
let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String?
|
||||
let initPacketJunkSize, responsePacketJunkSize: String?
|
||||
let initPacketJunkSize, responsePacketJunkSize, cookieReplyPacketJunkSize, transportPacketJunkSize: String?
|
||||
let specialJunk1, specialJunk2, specialJunk3, specialJunk4, specialJunk5: String?
|
||||
let controlledJunk1, controlledJunk2, controlledJunk3: String?
|
||||
let specialHandshakeTimeout: String?
|
||||
@@ -26,7 +26,7 @@ struct WGConfig: Decodable {
|
||||
case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2"
|
||||
case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4"
|
||||
case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax"
|
||||
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2"
|
||||
case initPacketJunkSize = "S1", responsePacketJunkSize = "S2", cookieReplyPacketJunkSize = "S3", transportPacketJunkSize = "S4"
|
||||
case specialJunk1 = "I1", specialJunk2 = "I2", specialJunk3 = "I3", specialJunk4 = "I4", specialJunk5 = "I5"
|
||||
case controlledJunk1 = "J1", controlledJunk2 = "J2", controlledJunk3 = "J3"
|
||||
case specialHandshakeTimeout = "Itime"
|
||||
@@ -46,27 +46,59 @@ struct WGConfig: Decodable {
|
||||
}
|
||||
|
||||
var settings: String {
|
||||
junkPacketCount == nil ? "" :
|
||||
"""
|
||||
Jc = \(junkPacketCount!)
|
||||
Jmin = \(junkPacketMinSize!)
|
||||
Jmax = \(junkPacketMaxSize!)
|
||||
S1 = \(initPacketJunkSize!)
|
||||
S2 = \(responsePacketJunkSize!)
|
||||
H1 = \(initPacketMagicHeader!)
|
||||
H2 = \(responsePacketMagicHeader!)
|
||||
H3 = \(underloadPacketMagicHeader!)
|
||||
H4 = \(transportPacketMagicHeader!)
|
||||
I1 = \(specialJunk1!)
|
||||
I2 = \(specialJunk2!)
|
||||
I3 = \(specialJunk3!)
|
||||
I4 = \(specialJunk4!)
|
||||
I5 = \(specialJunk5!)
|
||||
J1 = \(controlledJunk1!)
|
||||
J2 = \(controlledJunk2!)
|
||||
J3 = \(controlledJunk3!)
|
||||
Itime = \(specialHandshakeTimeout!)
|
||||
"""
|
||||
guard junkPacketCount != nil else { return "" }
|
||||
|
||||
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 {
|
||||
|
||||
@@ -507,6 +507,8 @@ bool IosController::setupWireGuard()
|
||||
|
||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||
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::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||
@@ -605,11 +607,23 @@ bool IosController::setupAwg()
|
||||
|
||||
wgConfig.insert(config_key::initPacketJunkSize, config[config_key::initPacketJunkSize]);
|
||||
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::junkPacketMinSize, config[config_key::junkPacketMinSize]);
|
||||
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);
|
||||
QString wgConfigDocStr(wgConfigDoc.toJson(QJsonDocument::Compact));
|
||||
|
||||
@@ -794,9 +808,9 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||
if (!qtController) return;
|
||||
|
||||
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil];
|
||||
|
||||
|
||||
__block bool isAccepted = false;
|
||||
|
||||
|
||||
[activityController setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
|
||||
isAccepted = completed;
|
||||
emit finished();
|
||||
@@ -808,11 +822,11 @@ bool IosController::shareText(const QStringList& filesToSend) {
|
||||
popController.sourceView = qtController.view;
|
||||
popController.sourceRect = CGRectMake(100, 100, 100, 100);
|
||||
}
|
||||
|
||||
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
|
||||
return isAccepted;
|
||||
}
|
||||
|
||||
@@ -826,7 +840,7 @@ QString IosController::openFile() {
|
||||
if (!qtController) return;
|
||||
|
||||
[qtController presentViewController:documentPicker animated:YES completion:nil];
|
||||
|
||||
|
||||
__block QString filePath;
|
||||
|
||||
documentPickerDelegate.documentPickerClosedCallback = ^(NSString *path) {
|
||||
@@ -841,7 +855,7 @@ QString IosController::openFile() {
|
||||
QEventLoop wait;
|
||||
QObject::connect(this, &IosController::finished, &wait, &QEventLoop::quit);
|
||||
wait.exec();
|
||||
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,12 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
|
||||
if (!config.m_responsePacketJunkSize.isEmpty()) {
|
||||
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()) {
|
||||
out << "h1=" << config.m_initPacketMagicHeader << "\n";
|
||||
}
|
||||
@@ -150,7 +156,10 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) {
|
||||
} else {
|
||||
if (config.m_killSwitchEnabled) {
|
||||
FirewallParams params { };
|
||||
params.dnsServers.append(config.m_dnsServer);
|
||||
params.dnsServers.append(config.m_primaryDnsServer);
|
||||
if (!config.m_secondaryDnsServer.isEmpty()) {
|
||||
params.dnsServers.append(config.m_secondaryDnsServer);
|
||||
}
|
||||
if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) {
|
||||
params.blockAll = true;
|
||||
if (config.m_excludedAddresses.size()) {
|
||||
|
||||
@@ -43,8 +43,16 @@ namespace {
|
||||
|
||||
#include "macosfirewall.h"
|
||||
|
||||
#define ResourceDir qApp->applicationDirPath() + "/pf"
|
||||
#define DaemonDataDir qApp->applicationDirPath() + "/pf"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
// 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>
|
||||
|
||||
@@ -121,6 +129,8 @@ void MacOSFirewall::install()
|
||||
logger.info() << "Installing PF root anchor";
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -119,6 +119,12 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
|
||||
if (!config.m_responsePacketJunkSize.isEmpty()) {
|
||||
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()) {
|
||||
out << "h1=" << config.m_initPacketMagicHeader << "\n";
|
||||
}
|
||||
@@ -132,30 +138,43 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) {
|
||||
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));
|
||||
if (err != 0) {
|
||||
logger.error() << "Interface configuration failed:" << strerror(err);
|
||||
} else {
|
||||
if (config.m_killSwitchEnabled) {
|
||||
FirewallParams params { };
|
||||
params.dnsServers.append(config.m_dnsServer);
|
||||
if (config.m_killSwitchEnabled) {
|
||||
FirewallParams params { };
|
||||
params.dnsServers.append(config.m_primaryDnsServer);
|
||||
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;
|
||||
if (config.m_excludedAddresses.size()) {
|
||||
params.allowNets = true;
|
||||
foreach (auto net, config.m_excludedAddresses) {
|
||||
params.allowAddrs.append(net.toUtf8());
|
||||
}
|
||||
params.allowNets = true;
|
||||
foreach (auto net, config.m_excludedAddresses) {
|
||||
params.allowAddrs.append(net.toUtf8());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
params.blockNets = true;
|
||||
foreach (auto net, config.m_allowedIPAddressRanges) {
|
||||
params.blockAddrs.append(net.toString());
|
||||
params.blockAddrs.append(net.toString());
|
||||
}
|
||||
}
|
||||
applyFirewallRules(params);
|
||||
}
|
||||
applyFirewallRules(params);
|
||||
}
|
||||
}
|
||||
return (err == 0);
|
||||
}
|
||||
|
||||
@@ -291,15 +291,32 @@ bool WindowsFirewall::enablePeerTraffic(const InterfaceConfig& config) {
|
||||
"Block Internet", config.m_serverPublicKey)) {
|
||||
return false;
|
||||
}
|
||||
if (!config.m_dnsServer.isEmpty()) {
|
||||
if (!allowTrafficTo(QHostAddress(config.m_dnsServer), 53, HIGH_WEIGHT,
|
||||
if (!config.m_primaryDnsServer.isEmpty()) {
|
||||
if (!allowTrafficTo(QHostAddress(config.m_primaryDnsServer), 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_dnsServer == config.m_serverIpv4Gateway) {
|
||||
if (config.m_primaryDnsServer == 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,
|
||||
HIGH_WEIGHT, "Allow extra IPv6 DNS-Server",
|
||||
config.m_serverPublicKey)) {
|
||||
|
||||
@@ -130,6 +130,7 @@ bool WireguardUtilsWindows::addInterface(const InterfaceConfig& config) {
|
||||
// Enable the windows firewall
|
||||
NET_IFINDEX ifindex;
|
||||
ConvertInterfaceLuidToIndex(&luid, &ifindex);
|
||||
m_firewall->allowAllTraffic();
|
||||
m_firewall->enableInterface(ifindex);
|
||||
}
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
|
||||
// killSwitch toggle
|
||||
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
|
||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
|
||||
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index());
|
||||
}
|
||||
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
||||
m_configData.insert("vpnGateway", m_vpnGateway);
|
||||
|
||||
@@ -72,6 +72,8 @@ namespace amnezia
|
||||
constexpr char junkPacketMaxSize[] = "Jmax";
|
||||
constexpr char initPacketJunkSize[] = "S1";
|
||||
constexpr char responsePacketJunkSize[] = "S2";
|
||||
constexpr char cookieReplyPacketJunkSize[] = "S3";
|
||||
constexpr char transportPacketJunkSize[] = "S4";
|
||||
constexpr char initPacketMagicHeader[] = "H1";
|
||||
constexpr char responsePacketMagicHeader[] = "H2";
|
||||
constexpr char underloadPacketMagicHeader[] = "H3";
|
||||
@@ -112,6 +114,8 @@ namespace amnezia
|
||||
|
||||
constexpr char clientId[] = "clientId";
|
||||
|
||||
constexpr char nameOverriddenByUser[] = "nameOverriddenByUser";
|
||||
|
||||
}
|
||||
|
||||
namespace protocols
|
||||
@@ -223,6 +227,9 @@ namespace amnezia
|
||||
constexpr char defaultJunkPacketMaxSize[] = "30";
|
||||
constexpr char defaultInitPacketJunkSize[] = "15";
|
||||
constexpr char defaultResponsePacketJunkSize[] = "18";
|
||||
constexpr char defaultCookieReplyPacketJunkSize[] = "20";
|
||||
constexpr char defaultTransportPacketJunkSize[] = "23";
|
||||
|
||||
constexpr char defaultInitPacketMagicHeader[] = "1020325451";
|
||||
constexpr char defaultResponsePacketMagicHeader[] = "3288052141";
|
||||
constexpr char defaultTransportPacketMagicHeader[] = "2528465083";
|
||||
@@ -235,7 +242,7 @@ namespace amnezia
|
||||
constexpr char defaultControlledJunk1[] = "";
|
||||
constexpr char defaultControlledJunk2[] = "";
|
||||
constexpr char defaultControlledJunk3[] = "";
|
||||
constexpr char defaultSpecialHandshakeTimeout[] = "0";
|
||||
constexpr char defaultSpecialHandshakeTimeout[] = "";
|
||||
}
|
||||
|
||||
namespace socks5Proxy
|
||||
|
||||
@@ -98,8 +98,13 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||
if (vpnState == Vpn::ConnectionState::Connected) {
|
||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||
QList<QHostAddress> dnsAddr;
|
||||
|
||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns1).toString()));
|
||||
dnsAddr.push_back(QHostAddress(m_configData.value(config_key::dns2).toString()));
|
||||
// We don't use secondary DNS if primary DNS is AmneziaDNS
|
||||
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
|
||||
QThread::msleep(8000);
|
||||
#endif
|
||||
@@ -134,7 +139,7 @@ ErrorCode XrayProtocol::startTun2Sock()
|
||||
// killSwitch toggle
|
||||
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
|
||||
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
|
||||
IpcClient::Interface()->enableKillSwitch(QJsonObject(), netInterfaces.at(i).index());
|
||||
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index());
|
||||
}
|
||||
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
|
||||
m_configData.insert("vpnGateway", m_vpnGateway);
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
<file>ui/qml/Components/SelectLanguageDrawer.qml</file>
|
||||
<file>ui/qml/Components/ServersListView.qml</file>
|
||||
<file>ui/qml/Components/SettingsContainersListView.qml</file>
|
||||
<file>ui/qml/Components/ShareConnectionDrawer.qml</file>
|
||||
|
||||
<file>ui/qml/Components/TransportProtoSelector.qml</file>
|
||||
<file>ui/qml/Components/AddSitePanel.qml</file>
|
||||
<file>ui/qml/Config/GlobalConfig.qml</file>
|
||||
@@ -228,6 +228,7 @@
|
||||
<file>ui/qml/Pages2/PageSetupWizardViewConfig.qml</file>
|
||||
<file>ui/qml/Pages2/PageShare.qml</file>
|
||||
<file>ui/qml/Pages2/PageShareFullAccess.qml</file>
|
||||
<file>ui/qml/Pages2/PageShareConnection.qml</file>
|
||||
<file>ui/qml/Pages2/PageStart.qml</file>
|
||||
<file>ui/qml/Components/RenameServerDrawer.qml</file>
|
||||
<file>ui/qml/Controls2/ListViewType.qml</file>
|
||||
@@ -239,6 +240,8 @@
|
||||
<file>ui/qml/Components/ApiPremV1MigrationDrawer.qml</file>
|
||||
<file>ui/qml/Components/ApiPremV1SubListDrawer.qml</file>
|
||||
<file>ui/qml/Components/OtpCodeDrawer.qml</file>
|
||||
<file>ui/qml/Components/AwgTextField.qml</file>
|
||||
<file>ui/qml/Pages2/PageSettingsApiSubscriptionKey.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/countriesFlags">
|
||||
<file>images/flagKit/ZW.svg</file>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM marko1777/awg:latest
|
||||
FROM amneziavpn/amnezia-wg:latest
|
||||
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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_FILE="/var/run/dnf.pid";\
|
||||
elif which yum > /dev/null 2>&1; then LOCK_FILE="/var/run/yum.pid";\
|
||||
elif which pacman > /dev/null 2>&1; then LOCK_FILE="/var/lib/pacman/db.lck";\
|
||||
if which apt-get > /dev/null 2>&1; then LOCK_CMD="fuser"; 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 yum > /dev/null 2>&1; then LOCK_CMD="cat"; 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_CMD="fuser"; LOCK_FILE="/var/lib/pacman/db.lck";\
|
||||
else echo "Packet manager not found"; echo "Internal error"; exit 1; fi;\
|
||||
if command -v fuser > /dev/null 2>&1; then sudo fuser $LOCK_FILE 2>/dev/null; else echo "fuser not installed"; 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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); opt="--version";\
|
||||
elif which dnf > /dev/null 2>&1; then pm=$(which dnf); opt="--version";\
|
||||
elif which yum > /dev/null 2>&1; then pm=$(which yum); opt="--version";\
|
||||
elif which zypper > /dev/null 2>&1; then pm=$(which zypper); opt="--version";\
|
||||
elif which pacman > /dev/null 2>&1; then pm=$(which pacman); opt="--version";\
|
||||
else pm="uname"; opt="-a";\
|
||||
fi;\
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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 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";\
|
||||
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";\
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM alpine:3.15
|
||||
LABEL maintainer="AmneziaVPN"
|
||||
|
||||
ARG XRAY_RELEASE="v1.8.6"
|
||||
ARG XRAY_RELEASE="v25.8.3"
|
||||
|
||||
RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz
|
||||
RUN apk --update upgrade --no-cache
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ namespace
|
||||
{
|
||||
constexpr char cloak[] = "cloak";
|
||||
constexpr char awg[] = "awg";
|
||||
constexpr char vless[] = "vless";
|
||||
|
||||
constexpr char apiEndpoint[] = "api_endpoint";
|
||||
constexpr char accessToken[] = "api_key";
|
||||
@@ -35,10 +36,6 @@ namespace
|
||||
constexpr char serviceInfo[] = "service_info";
|
||||
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 keyPayload[] = "key_payload";
|
||||
|
||||
@@ -47,6 +44,185 @@ namespace
|
||||
|
||||
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,
|
||||
@@ -63,24 +239,26 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
||||
serverCountryCode,
|
||||
apiConfigObject.value(configKey::serviceType).toString(),
|
||||
configKey::awg, // apiConfigObject.value(configKey::serviceProtocol).toString(),
|
||||
serverConfigObject.value(configKey::authData).toObject() };
|
||||
|
||||
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);
|
||||
QString protocol = gatewayRequestData.serviceProtocol;
|
||||
ProtocolData protocolData = generateProtocolData(protocol);
|
||||
|
||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/native_config"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/native_config"), apiPayload, responseBody);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
@@ -88,7 +266,7 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||
|
||||
QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object();
|
||||
QString nativeConfig = jsonConfig.value(configKey::config).toString();
|
||||
nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
|
||||
nativeConfig.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", protocolData.wireGuardClientPrivKey);
|
||||
|
||||
SystemController::saveFile(fileName, nativeConfig);
|
||||
return true;
|
||||
@@ -96,24 +274,22 @@ bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
|
||||
|
||||
bool ApiConfigsController::revokeNativeConfig(const QString &serverCountryCode)
|
||||
{
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
||||
serverCountryCode,
|
||||
apiConfigObject.value(configKey::serviceType).toString(),
|
||||
configKey::awg, // apiConfigObject.value(configKey::serviceProtocol).toString(),
|
||||
serverConfigObject.value(configKey::authData).toObject() };
|
||||
|
||||
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);
|
||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_native_config"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_native_config"), apiPayload, responseBody);
|
||||
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
@@ -144,14 +320,11 @@ void ApiConfigsController::copyVpnKeyToClipboard()
|
||||
|
||||
bool ApiConfigsController::fillAvailableServices()
|
||||
{
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
QJsonObject apiPayload;
|
||||
apiPayload[configKey::osVersion] = QSysInfo::productType();
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/services"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/services"), apiPayload, responseBody);
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
if (!responseBody.contains("services")) {
|
||||
errorCode = ErrorCode::ApiServicesMissingError;
|
||||
@@ -170,34 +343,36 @@ bool ApiConfigsController::fillAvailableServices()
|
||||
|
||||
bool ApiConfigsController::importServiceFromGateway()
|
||||
{
|
||||
if (m_serversModel->isServerFromApiAlreadyExists(m_apiServicesModel->getCountryCode(), m_apiServicesModel->getSelectedServiceType(),
|
||||
m_apiServicesModel->getSelectedServiceProtocol())) {
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
ProtocolData protocolData = generateProtocolData(gatewayRequestData.serviceProtocol);
|
||||
|
||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||
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);
|
||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody);
|
||||
|
||||
QJsonObject serverConfig;
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
|
||||
errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, serverConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
apiConfig.insert(configKey::userCountryCode, m_apiServicesModel->getCountryCode());
|
||||
@@ -218,39 +393,33 @@ bool ApiConfigsController::importServiceFromGateway()
|
||||
bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||
bool reloadServiceConfig)
|
||||
{
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||
auto authData = serverConfig.value(configKey::authData).toObject();
|
||||
|
||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||
auto userCountryCode = apiConfig.value(configKey::userCountryCode).toString();
|
||||
auto serviceType = apiConfig.value(configKey::serviceType).toString();
|
||||
auto serviceProtocol = apiConfig.value(configKey::serviceProtocol).toString();
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
m_settings->getInstallationUuid(true),
|
||||
apiConfig.value(configKey::userCountryCode).toString(),
|
||||
newCountryCode,
|
||||
apiConfig.value(configKey::serviceType).toString(),
|
||||
apiConfig.value(configKey::serviceProtocol).toString(),
|
||||
serverConfig.value(configKey::authData).toObject() };
|
||||
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||
ProtocolData protocolData = generateProtocolData(gatewayRequestData.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);
|
||||
|
||||
if (!newCountryCode.isEmpty()) {
|
||||
apiPayload[configKey::serverCountryCode] = newCountryCode;
|
||||
}
|
||||
if (!authData.isEmpty()) {
|
||||
apiPayload[configKey::authData] = authData;
|
||||
}
|
||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||
appendProtocolDataToApiPayload(gatewayRequestData.serviceProtocol, protocolData, apiPayload);
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/config"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody);
|
||||
|
||||
QJsonObject newServerConfig;
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, newServerConfig);
|
||||
errorCode = fillServerConfig(gatewayRequestData.serviceProtocol, protocolData, responseBody, newServerConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
|
||||
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
|
||||
@@ -259,8 +428,12 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const
|
||||
newApiConfig.insert(apiDefs::key::vpnKey, apiConfig.value(apiDefs::key::vpnKey));
|
||||
|
||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||
newServerConfig.insert(configKey::authData, authData);
|
||||
newServerConfig.insert(configKey::authData, gatewayRequestData.authData);
|
||||
|
||||
if (serverConfig.value(config_key::nameOverriddenByUser).toBool()) {
|
||||
newServerConfig.insert(config_key::name, serverConfig.value(config_key::name));
|
||||
newServerConfig.insert(config_key::nameOverriddenByUser, true);
|
||||
}
|
||||
m_serversModel->editServer(newServerConfig, serverIndex);
|
||||
if (reloadServiceConfig) {
|
||||
emit reloadServerFromApiFinished(tr("API config reloaded"));
|
||||
@@ -290,10 +463,13 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||
auto installationUuid = m_settings->getInstallationUuid(true);
|
||||
|
||||
QString serviceProtocol = serverConfig.value(configKey::protocol).toString();
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(serviceProtocol);
|
||||
ProtocolData protocolData = generateProtocolData(serviceProtocol);
|
||||
|
||||
QJsonObject apiPayload = fillApiPayload(serviceProtocol, apiPayloadData);
|
||||
QJsonObject apiPayload;
|
||||
appendProtocolDataToApiPayload(serviceProtocol, protocolData, apiPayload);
|
||||
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::apiEndpoint] = serverConfig.value(configKey::apiEndpoint).toString();
|
||||
|
||||
@@ -301,7 +477,11 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/proxy_config"), apiPayload, responseBody);
|
||||
|
||||
if (errorCode == ErrorCode::NoError) {
|
||||
fillServerConfig(serviceProtocol, apiPayloadData, responseBody, serverConfig);
|
||||
errorCode = fillServerConfig(serviceProtocol, protocolData, responseBody, serverConfig);
|
||||
if (errorCode != ErrorCode::NoError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_serversModel->editServer(serverConfig, serverIndex);
|
||||
emit updateServerFromApiFinished();
|
||||
@@ -314,9 +494,6 @@ bool ApiConfigsController::updateServiceFromTelegram(const int serverIndex)
|
||||
|
||||
bool ApiConfigsController::deactivateDevice()
|
||||
{
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
@@ -325,19 +502,19 @@ bool ApiConfigsController::deactivateDevice()
|
||||
return true;
|
||||
}
|
||||
|
||||
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
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 = 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);
|
||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
||||
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
@@ -351,9 +528,6 @@ bool ApiConfigsController::deactivateDevice()
|
||||
|
||||
bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const QString &serverCountryCode)
|
||||
{
|
||||
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs,
|
||||
m_settings->isStrictKillSwitchEnabled());
|
||||
|
||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
@@ -362,19 +536,19 @@ bool ApiConfigsController::deactivateExternalDevice(const QString &uuid, const Q
|
||||
return true;
|
||||
}
|
||||
|
||||
QString protocol = apiConfigObject.value(configKey::serviceProtocol).toString();
|
||||
ApiPayloadData apiPayloadData = generateApiPayloadData(protocol);
|
||||
GatewayRequestData gatewayRequestData { QSysInfo::productType(),
|
||||
QString(APP_VERSION),
|
||||
uuid,
|
||||
apiConfigObject.value(configKey::userCountryCode).toString(),
|
||||
serverCountryCode,
|
||||
apiConfigObject.value(configKey::serviceType).toString(),
|
||||
"",
|
||||
serverConfigObject.value(configKey::authData).toObject() };
|
||||
|
||||
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);
|
||||
QJsonObject apiPayload = gatewayRequestData.toJsonObject();
|
||||
|
||||
QByteArray responseBody;
|
||||
ErrorCode errorCode = gatewayController.post(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
||||
ErrorCode errorCode = executeRequest(QString("%1v1/revoke_config"), apiPayload, responseBody);
|
||||
if (errorCode != ErrorCode::NoError && errorCode != ErrorCode::ApiNotFoundError) {
|
||||
emit errorOccurred(errorCode);
|
||||
return false;
|
||||
@@ -413,117 +587,29 @@ bool ApiConfigsController::isConfigValid()
|
||||
return true;
|
||||
}
|
||||
|
||||
ApiConfigsController::ApiPayloadData ApiConfigsController::generateApiPayloadData(const QString &protocol)
|
||||
void ApiConfigsController::setCurrentProtocol(const QString &protocolName)
|
||||
{
|
||||
ApiConfigsController::ApiPayloadData apiPayload;
|
||||
if (protocol == configKey::cloak) {
|
||||
apiPayload.certRequest = OpenVpnConfigurator::createCertRequest();
|
||||
} else if (protocol == configKey::awg) {
|
||||
auto connData = WireguardConfigurator::genClientKeys();
|
||||
apiPayload.wireGuardClientPubKey = connData.clientPubKey;
|
||||
apiPayload.wireGuardClientPrivKey = connData.clientPrivKey;
|
||||
}
|
||||
return apiPayload;
|
||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
apiConfigObject[configKey::serviceProtocol] = protocolName;
|
||||
|
||||
serverConfigObject.insert(configKey::apiConfig, apiConfigObject);
|
||||
|
||||
m_serversModel->editServer(serverConfigObject, serverIndex);
|
||||
}
|
||||
|
||||
QJsonObject ApiConfigsController::fillApiPayload(const QString &protocol, const ApiPayloadData &apiPayloadData)
|
||||
bool ApiConfigsController::isVlessProtocol()
|
||||
{
|
||||
QJsonObject obj;
|
||||
if (protocol == configKey::cloak) {
|
||||
obj[configKey::certificate] = apiPayloadData.certRequest.request;
|
||||
} else if (protocol == configKey::awg) {
|
||||
obj[configKey::publicKey] = apiPayloadData.wireGuardClientPubKey;
|
||||
auto serverIndex = m_serversModel->getProcessedServerIndex();
|
||||
auto serverConfigObject = m_serversModel->getServerConfig(serverIndex);
|
||||
auto apiConfigObject = serverConfigObject.value(configKey::apiConfig).toObject();
|
||||
|
||||
if (apiConfigObject[configKey::serviceProtocol].toString() == "vless") {
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
containerConfig[config_key::specialJunk1] = protocolConfig.value(config_key::specialJunk1);
|
||||
containerConfig[config_key::specialJunk2] = protocolConfig.value(config_key::specialJunk2);
|
||||
containerConfig[config_key::specialJunk3] = protocolConfig.value(config_key::specialJunk3);
|
||||
containerConfig[config_key::specialJunk4] = protocolConfig.value(config_key::specialJunk4);
|
||||
containerConfig[config_key::specialJunk5] = protocolConfig.value(config_key::specialJunk5);
|
||||
containerConfig[config_key::controlledJunk1] = protocolConfig.value(config_key::controlledJunk1);
|
||||
containerConfig[config_key::controlledJunk2] = protocolConfig.value(config_key::controlledJunk2);
|
||||
containerConfig[config_key::controlledJunk3] = protocolConfig.value(config_key::controlledJunk3);
|
||||
containerConfig[config_key::specialHandshakeTimeout] = protocolConfig.value(config_key::specialHandshakeTimeout);
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QString> ApiConfigsController::getQrCodes()
|
||||
@@ -540,3 +626,10 @@ QString ApiConfigsController::getVpnKey()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ public slots:
|
||||
|
||||
bool isConfigValid();
|
||||
|
||||
void setCurrentProtocol(const QString &protocolName);
|
||||
bool isVlessProtocol();
|
||||
|
||||
signals:
|
||||
void errorOccurred(ErrorCode errorCode);
|
||||
|
||||
@@ -46,23 +49,12 @@ signals:
|
||||
void vpnKeyExportReady();
|
||||
|
||||
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();
|
||||
int getQrCodesCount();
|
||||
QString getVpnKey();
|
||||
|
||||
ErrorCode executeRequest(const QString &endpoint, const QJsonObject &apiPayload, QByteArray &responseBody);
|
||||
|
||||
QList<QString> m_qrCodes;
|
||||
QString m_vpnKey;
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQuickWindow>
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace {
|
||||
Logger logger("FocusController");
|
||||
}
|
||||
|
||||
FocusController::FocusController(QQmlApplicationEngine *engine, QObject *parent)
|
||||
: QObject { parent },
|
||||
m_engine { engine },
|
||||
@@ -85,7 +91,7 @@ void FocusController::dropRootObject(QObject *object)
|
||||
dropListView();
|
||||
setFocusOnDefaultItem();
|
||||
} else {
|
||||
qWarning() << "===>> TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
|
||||
logger.warning() << "TRY TO DROP WRONG ROOT OBJECT: " << m_rootObjects.top() << " SHOULD BE: " << object;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +107,7 @@ void FocusController::reload(Direction direction)
|
||||
QObject *rootObject = (m_rootObjects.empty() ? m_engine->rootObjects().value(0) : m_rootObjects.top());
|
||||
|
||||
if (!rootObject) {
|
||||
qCritical() << "No ROOT OBJECT found!";
|
||||
logger.error() << "No ROOT OBJECT found!";
|
||||
resetRootObject();
|
||||
dropListView();
|
||||
return;
|
||||
@@ -113,7 +119,7 @@ void FocusController::reload(Direction direction)
|
||||
direction == Direction::Forward ? FocusControl::isLess : FocusControl::isMore);
|
||||
|
||||
if (m_focusChain.empty()) {
|
||||
qWarning() << "Focus chain is empty!";
|
||||
logger.warning() << "Focus chain is empty!";
|
||||
resetRootObject();
|
||||
dropListView();
|
||||
return;
|
||||
@@ -131,7 +137,7 @@ void FocusController::nextItem(Direction direction)
|
||||
}
|
||||
|
||||
if (m_focusChain.empty()) {
|
||||
qWarning() << "There are no items to navigate";
|
||||
logger.warning() << "There are no items to navigate";
|
||||
setFocusOnDefaultItem();
|
||||
return;
|
||||
}
|
||||
@@ -149,7 +155,7 @@ void FocusController::nextItem(Direction direction)
|
||||
const auto focusedItem = qobject_cast<QQuickItem *>(m_focusChain.at(focusedItemIndex));
|
||||
|
||||
if (focusedItem == nullptr) {
|
||||
qWarning() << "Failed to get item to focus on. Setting focus on default";
|
||||
logger.warning() << "Failed to get item to focus on. Setting focus on default";
|
||||
setFocusOnDefaultItem();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "core/errorstrings.h"
|
||||
#include "core/qrCodeUtils.h"
|
||||
#include "core/serialization/serialization.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
#include "systemController.h"
|
||||
#include "utilities.h"
|
||||
|
||||
@@ -285,15 +286,19 @@ void ImportController::processNativeWireGuardConfig()
|
||||
clientProtocolConfig[config_key::responsePacketMagicHeader] = "2";
|
||||
clientProtocolConfig[config_key::underloadPacketMagicHeader] = "3";
|
||||
clientProtocolConfig[config_key::transportPacketMagicHeader] = "4";
|
||||
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::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;
|
||||
|
||||
@@ -447,39 +452,33 @@ QJsonObject ImportController::extractWireGuardConfig(const QString &data)
|
||||
lastConfig[config_key::allowed_ips] = allowedIpsJsonArray;
|
||||
|
||||
QString protocolName = "wireguard";
|
||||
if (!configMap.value(config_key::junkPacketCount).isEmpty() && !configMap.value(config_key::junkPacketMinSize).isEmpty()
|
||||
&& !configMap.value(config_key::junkPacketMaxSize).isEmpty() && !configMap.value(config_key::initPacketJunkSize).isEmpty()
|
||||
&& !configMap.value(config_key::responsePacketJunkSize).isEmpty() && !configMap.value(config_key::initPacketMagicHeader).isEmpty()
|
||||
&& !configMap.value(config_key::responsePacketMagicHeader).isEmpty()
|
||||
&& !configMap.value(config_key::underloadPacketMagicHeader).isEmpty()
|
||||
&& !configMap.value(config_key::transportPacketMagicHeader).isEmpty()
|
||||
&& !configMap.value(config_key::specialJunk1).isEmpty()
|
||||
&& !configMap.value(config_key::specialJunk2).isEmpty()
|
||||
&& !configMap.value(config_key::specialJunk3).isEmpty()
|
||||
&& !configMap.value(config_key::specialJunk4).isEmpty()
|
||||
&& !configMap.value(config_key::specialJunk5).isEmpty()
|
||||
&& !configMap.value(config_key::controlledJunk1).isEmpty()
|
||||
&& !configMap.value(config_key::controlledJunk2).isEmpty()
|
||||
&& !configMap.value(config_key::controlledJunk3).isEmpty()
|
||||
&& !configMap.value(config_key::specialHandshakeTimeout).isEmpty()) {
|
||||
lastConfig[config_key::junkPacketCount] = configMap.value(config_key::junkPacketCount);
|
||||
lastConfig[config_key::junkPacketMinSize] = configMap.value(config_key::junkPacketMinSize);
|
||||
lastConfig[config_key::junkPacketMaxSize] = configMap.value(config_key::junkPacketMaxSize);
|
||||
lastConfig[config_key::initPacketJunkSize] = configMap.value(config_key::initPacketJunkSize);
|
||||
lastConfig[config_key::responsePacketJunkSize] = configMap.value(config_key::responsePacketJunkSize);
|
||||
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);
|
||||
lastConfig[config_key::transportPacketMagicHeader] = configMap.value(config_key::transportPacketMagicHeader);
|
||||
lastConfig[config_key::specialJunk1] = configMap.value(config_key::specialJunk1);
|
||||
lastConfig[config_key::specialJunk2] = configMap.value(config_key::specialJunk2);
|
||||
lastConfig[config_key::specialJunk3] = configMap.value(config_key::specialJunk3);
|
||||
lastConfig[config_key::specialJunk4] = configMap.value(config_key::specialJunk4);
|
||||
lastConfig[config_key::specialJunk5] = configMap.value(config_key::specialJunk5);
|
||||
lastConfig[config_key::controlledJunk1] = configMap.value(config_key::controlledJunk1);
|
||||
lastConfig[config_key::controlledJunk2] = configMap.value(config_key::controlledJunk2);
|
||||
lastConfig[config_key::controlledJunk3] = configMap.value(config_key::controlledJunk3);
|
||||
lastConfig[config_key::specialHandshakeTimeout] = configMap.value(config_key::specialHandshakeTimeout);
|
||||
|
||||
const QStringList requiredJunkFields = { config_key::junkPacketCount, config_key::junkPacketMinSize,
|
||||
config_key::junkPacketMaxSize, config_key::initPacketJunkSize,
|
||||
config_key::responsePacketJunkSize, config_key::initPacketMagicHeader,
|
||||
config_key::responsePacketMagicHeader, config_key::underloadPacketMagicHeader,
|
||||
config_key::transportPacketMagicHeader };
|
||||
|
||||
const QStringList optionalJunkFields = { // config_key::cookieReplyPacketJunkSize,
|
||||
// config_key::transportPacketJunkSize,
|
||||
config_key::specialJunk1, config_key::specialJunk2, config_key::specialJunk3,
|
||||
config_key::specialJunk4, config_key::specialJunk5, config_key::controlledJunk1,
|
||||
config_key::controlledJunk2, config_key::controlledJunk3, config_key::specialHandshakeTimeout
|
||||
};
|
||||
|
||||
bool hasAllRequiredFields = std::all_of(requiredJunkFields.begin(), requiredJunkFields.end(),
|
||||
[&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";
|
||||
m_configType = ConfigTypes::Awg;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <QStandardPaths>
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "core/api/apiUtils.h"
|
||||
#include "core/controllers/serverController.h"
|
||||
#include "core/controllers/vpnConfigurationController.h"
|
||||
#include "core/networkUtilities.h"
|
||||
@@ -15,7 +16,6 @@
|
||||
#include "ui/models/protocols/awgConfigModel.h"
|
||||
#include "ui/models/protocols/wireguardConfigModel.h"
|
||||
#include "utilities.h"
|
||||
#include "core/api/apiUtils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -79,12 +79,36 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||
|
||||
int s1 = QRandomGenerator::global()->bounded(15, 150);
|
||||
int s2 = QRandomGenerator::global()->bounded(15, 150);
|
||||
while (s1 + AwgConstant::messageInitiationSize == s2 + AwgConstant::messageResponseSize) {
|
||||
// int s3 = QRandomGenerator::global()->bounded(15, 150);
|
||||
// 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);
|
||||
}
|
||||
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 responsePacketJunkSize = QString::number(s2);
|
||||
// QString cookieReplyPacketJunkSize = QString::number(s3);
|
||||
// QString transportPacketJunkSize = QString::number(s4);
|
||||
|
||||
QSet<QString> headersValue;
|
||||
while (headersValue.size() != 4) {
|
||||
@@ -110,6 +134,9 @@ void InstallController::install(DockerContainer container, int port, TransportPr
|
||||
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;
|
||||
@@ -376,9 +403,19 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
QJsonObject config;
|
||||
Proto mainProto = ContainerProps::defaultProtocol(container);
|
||||
const auto &protocols = ContainerProps::protocolsForContainer(container);
|
||||
|
||||
for (const auto &protocol : protocols) {
|
||||
QJsonObject containerConfig;
|
||||
if (protocol == mainProto) {
|
||||
|
||||
// for Multiprotocols (OpenVPN over SS, OpenVPN over Cloak)
|
||||
bool shouldProcessProtocol = false;
|
||||
if (container == DockerContainer::ShadowSocks || container == DockerContainer::Cloak) {
|
||||
shouldProcessProtocol = true;
|
||||
} else {
|
||||
shouldProcessProtocol = (protocol == mainProto);
|
||||
}
|
||||
|
||||
if (shouldProcessProtocol) {
|
||||
containerConfig.insert(config_key::port, port);
|
||||
containerConfig.insert(config_key::transport_proto, transportProto);
|
||||
|
||||
@@ -412,16 +449,19 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
serverConfigMap.value(config_key::underloadPacketMagicHeader);
|
||||
containerConfig[config_key::transportPacketMagicHeader] =
|
||||
serverConfigMap.value(config_key::transportPacketMagicHeader);
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||
@@ -520,14 +560,97 @@ ErrorCode InstallController::getAlreadyInstalledContainers(const ServerCredentia
|
||||
qDebug() << siteName;
|
||||
|
||||
containerConfig.insert(config_key::site, siteName);
|
||||
} else if (protocol == Proto::OpenVpn) {
|
||||
QString serverConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||
protocols::openvpn::serverConfigPath, errorCode);
|
||||
|
||||
QMap<QString, QString> serverConfigMap;
|
||||
auto serverConfigLines = serverConfig.split("\n");
|
||||
for (auto &line : serverConfigLines) {
|
||||
auto trimmedLine = line.trimmed();
|
||||
if (trimmedLine.startsWith("#") || trimmedLine.isEmpty()) {
|
||||
continue;
|
||||
} else {
|
||||
QStringList parts = trimmedLine.split(" ");
|
||||
if (parts.count() >= 2) {
|
||||
QString key = parts[0];
|
||||
QString value = parts.mid(1).join(" ");
|
||||
serverConfigMap.insert(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString serverValue = serverConfigMap.value("server");
|
||||
|
||||
if (!serverValue.isEmpty()) {
|
||||
QStringList serverParts = serverValue.split(" ");
|
||||
if (serverParts.count() >= 1) {
|
||||
containerConfig[config_key::subnet_address] = serverParts[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool ncpDisable = serverConfig.contains("ncp-disable");
|
||||
containerConfig[config_key::ncp_disable] = ncpDisable;
|
||||
|
||||
bool tlsAuth = serverConfig.contains("tls-auth");
|
||||
containerConfig[config_key::tls_auth] = tlsAuth;
|
||||
|
||||
bool blockOutsideDns = serverConfig.contains("block-outside-dns");
|
||||
|
||||
containerConfig[config_key::block_outside_dns] = blockOutsideDns;
|
||||
|
||||
QString cipher = serverConfigMap.value("cipher");
|
||||
if (!cipher.isEmpty()) {
|
||||
containerConfig[config_key::cipher] = cipher;
|
||||
}
|
||||
|
||||
QString hash = serverConfigMap.value("auth");
|
||||
if (!hash.isEmpty()) {
|
||||
containerConfig[config_key::hash] = hash;
|
||||
}
|
||||
} else if (protocol == Proto::Cloak) {
|
||||
QString cloakConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||
"/opt/amnezia/cloak/ck-config.json", errorCode);
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(cloakConfig.toUtf8());
|
||||
|
||||
if (!doc.isNull() && doc.isObject()) {
|
||||
QJsonObject cloakConfigObj = doc.object();
|
||||
|
||||
QString site = cloakConfigObj.value("RedirAddr").toString();
|
||||
if (!site.isEmpty()) {
|
||||
containerConfig[config_key::site] = site;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Failed to parse main loop Cloak JSON config";
|
||||
}
|
||||
|
||||
} else if (protocol == Proto::ShadowSocks) {
|
||||
QString shadowsocksConfig = serverController->getTextFileFromContainer(container, credentials,
|
||||
"/opt/amnezia/shadowsocks/ss-config.json", errorCode);
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(shadowsocksConfig.toUtf8());
|
||||
|
||||
if (!doc.isNull() && doc.isObject()) {
|
||||
QJsonObject ssConfigObj = doc.object();
|
||||
QString cipher = ssConfigObj.value("method").toString();
|
||||
if (!cipher.isEmpty()) {
|
||||
containerConfig[config_key::cipher] = cipher;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Failed to parse main loop Shadowsocks JSON config";
|
||||
}
|
||||
}
|
||||
|
||||
config.insert(config_key::container, ContainerProps::containerToString(container));
|
||||
}
|
||||
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
|
||||
if (shouldProcessProtocol) {
|
||||
config.insert(ProtocolProps::protoToString(protocol), containerConfig);
|
||||
}
|
||||
}
|
||||
installedContainers.insert(container, config);
|
||||
}
|
||||
|
||||
const static QRegularExpression torOrDnsRegExp("(amnezia-(?:torwebsite|dns)).*?([0-9]*)/(udp|tcp).*");
|
||||
QRegularExpressionMatch torOrDnsRegMatch = torOrDnsRegExp.match(containerInfo);
|
||||
if (torOrDnsRegMatch.hasMatch()) {
|
||||
@@ -691,6 +814,8 @@ void InstallController::clearCachedProfile(QSharedPointer<ServerController> serv
|
||||
m_clientManagementModel->revokeClient(containerConfig, container, serverCredentials, serverIndex, serverController);
|
||||
|
||||
emit cachedProfileCleared(tr("%1 cached profile cleared").arg(ContainerProps::containerHumanNames().value(container)));
|
||||
QJsonObject updatedConfig = m_settings->containerConfig(serverIndex, container);
|
||||
emit profileCleared(updatedConfig);
|
||||
}
|
||||
|
||||
QRegularExpression InstallController::ipAddressPortRegExp()
|
||||
|
||||
@@ -83,6 +83,8 @@ signals:
|
||||
|
||||
void noInstalledContainers();
|
||||
|
||||
void profileCleared(const QJsonObject &config);
|
||||
|
||||
private:
|
||||
void installServer(const DockerContainer container, const QMap<DockerContainer, QJsonObject> &installedContainers,
|
||||
const ServerCredentials &serverCredentials, const QSharedPointer<ServerController> &serverController,
|
||||
|
||||
@@ -37,7 +37,7 @@ void ListViewFocusController::viewAtCurrentIndex() const
|
||||
}
|
||||
case Section::Delegate: {
|
||||
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;
|
||||
}
|
||||
case Section::Footer: {
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace PageLoader
|
||||
PageSettingsApiInstructions,
|
||||
PageSettingsApiNativeConfigs,
|
||||
PageSettingsApiDevices,
|
||||
PageSettingsApiSubscriptionKey,
|
||||
PageSettingsKillSwitchExceptions,
|
||||
|
||||
PageServiceSftpSettings,
|
||||
@@ -71,6 +72,7 @@ namespace PageLoader
|
||||
PageProtocolAwgClientSettings,
|
||||
|
||||
PageShareFullAccess,
|
||||
PageShareConnection,
|
||||
|
||||
PageDevMenu
|
||||
};
|
||||
|
||||
@@ -35,6 +35,23 @@ SettingsController::SettingsController(const QSharedPointer<ServersModel> &serve
|
||||
#endif
|
||||
}
|
||||
|
||||
QString getPlatformName()
|
||||
{
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
return "Windows";
|
||||
#elif defined(Q_OS_ANDROID)
|
||||
return "Android";
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return "Linux";
|
||||
#elif defined(Q_OS_MACX)
|
||||
return "MacOS";
|
||||
#elif defined(Q_OS_IOS)
|
||||
return "iOS";
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsController::toggleAmneziaDns(bool enable)
|
||||
{
|
||||
m_settings->setUseAmneziaDns(enable);
|
||||
@@ -130,7 +147,10 @@ void SettingsController::backupAppConfig(const QString &fileName)
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
QJsonObject config = doc.object();
|
||||
|
||||
config["AppPlatform"] = getPlatformName();
|
||||
config["Conf/autoStart"] = Autostart::isAutostart();
|
||||
config["Conf/killSwitchEnabled"] = isKillSwitchEnabled();
|
||||
config["Conf/strictKillSwitchEnabled"] = isStrictKillSwitchEnabled();
|
||||
|
||||
SystemController::saveFile(fileName, QJsonDocument(config).toJson());
|
||||
}
|
||||
@@ -155,21 +175,41 @@ void SettingsController::restoreAppConfigFromData(const QByteArray &data)
|
||||
}
|
||||
toggleAutoStart(autoStart);
|
||||
#endif
|
||||
|
||||
m_serversModel->resetModel();
|
||||
m_languageModel->changeLanguage(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
|
||||
#if defined(Q_OS_WINDOWS) || defined(Q_OS_ANDROID)
|
||||
int appSplitTunnelingRouteMode = newConfigData.value("Conf/appsRouteMode").toInt();
|
||||
bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toBool();
|
||||
bool appSplittunnelingEnabled = newConfigData.value("Conf/appsSplitTunnelingEnabled").toString().toLower() == "true";
|
||||
m_appSplitTunnelingModel->setRouteMode(appSplitTunnelingRouteMode);
|
||||
|
||||
#if defined(Q_OS_WINDOWS)
|
||||
m_appSplitTunnelingModel->setRouteMode(static_cast<int>(Settings::AppsRouteMode::VpnAllExceptApps));
|
||||
#endif
|
||||
|
||||
if (newConfigData.contains("AppPlatform")) { //if backup is from a new version
|
||||
if (newConfigData.value("AppPlatform").toString() != getPlatformName()) {
|
||||
m_appSplitTunnelingModel->clearAppsList();
|
||||
}
|
||||
}
|
||||
|
||||
m_appSplitTunnelingModel->toggleSplitTunneling(appSplittunnelingEnabled);
|
||||
#endif
|
||||
|
||||
int siteSplitTunnelingRouteMode = newConfigData.value("Conf/routeMode").toInt();
|
||||
bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toBool();
|
||||
bool siteSplittunnelingEnabled = newConfigData.value("Conf/sitesSplitTunnelingEnabled").toString().toLower() == "true";
|
||||
m_sitesModel->setRouteMode(siteSplitTunnelingRouteMode);
|
||||
m_sitesModel->toggleSplitTunneling(siteSplittunnelingEnabled);
|
||||
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
|
||||
m_settings->setAutoConnect(false);
|
||||
m_settings->setStartMinimized(false);
|
||||
m_settings->setKillSwitchEnabled(false);
|
||||
m_settings->setStrictKillSwitchEnabled(false);
|
||||
#endif
|
||||
|
||||
emit restoreBackupFinished();
|
||||
} else {
|
||||
emit changeSettingsErrorOccurred(tr("Backup file is corrupted"));
|
||||
@@ -185,8 +225,7 @@ void SettingsController::clearSettings()
|
||||
{
|
||||
m_settings->clearSettings();
|
||||
m_serversModel->resetModel();
|
||||
m_languageModel->changeLanguage(
|
||||
static_cast<LanguageSettings::AvailableLanguageEnum>(m_languageModel->getCurrentLanguageIndex()));
|
||||
m_languageModel->changeLanguage(m_languageModel->getSystemLanguageEnum());
|
||||
|
||||
m_sitesModel->setRouteMode(Settings::RouteMode::VpnOnlyForwardSites);
|
||||
m_sitesModel->toggleSplitTunneling(false);
|
||||
|
||||
@@ -136,6 +136,8 @@ private:
|
||||
|
||||
QString m_appVersion;
|
||||
|
||||
QString getPlatform();
|
||||
|
||||
QDateTime m_loggingDisableDate;
|
||||
|
||||
bool m_isDevModeEnabled = false;
|
||||
|
||||
@@ -78,6 +78,13 @@ void SitesController::removeSite(int index)
|
||||
emit finished(tr("Site removed: %1").arg(hostname));
|
||||
}
|
||||
|
||||
void SitesController::removeSites()
|
||||
{
|
||||
m_sitesModel->removeSites();
|
||||
|
||||
emit finished(tr("Site list cleared!"));
|
||||
}
|
||||
|
||||
void SitesController::importSites(const QString &fileName, bool replaceExisting)
|
||||
{
|
||||
QByteArray jsonData;
|
||||
|
||||
@@ -19,6 +19,7 @@ public slots:
|
||||
void addSite(QString hostname);
|
||||
void removeSite(int index);
|
||||
|
||||
void removeSites();
|
||||
void importSites(const QString &fileName, bool replaceExisting);
|
||||
void exportSites(const QString &fileName);
|
||||
|
||||
|
||||
@@ -75,6 +75,12 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case IsProtocolSelectionSupportedRole: {
|
||||
if (m_accountInfoData.supportedProtocols.size() > 1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -95,6 +101,10 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons
|
||||
|
||||
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_supportInfo = accountInfoObject.value(apiDefs::key::supportInfo).toObject();
|
||||
@@ -159,6 +169,7 @@ QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
|
||||
roles[ServiceDescriptionRole] = "serviceDescription";
|
||||
roles[IsComponentVisibleRole] = "isComponentVisible";
|
||||
roles[HasExpiredWorkerRole] = "hasExpiredWorker";
|
||||
roles[IsProtocolSelectionSupportedRole] = "isProtocolSelectionSupported";
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ public:
|
||||
ServiceDescriptionRole,
|
||||
EndDateRole,
|
||||
IsComponentVisibleRole,
|
||||
HasExpiredWorkerRole
|
||||
HasExpiredWorkerRole,
|
||||
IsProtocolSelectionSupportedRole
|
||||
};
|
||||
|
||||
explicit ApiAccountInfoModel(QObject *parent = nullptr);
|
||||
@@ -51,6 +52,8 @@ private:
|
||||
int maxDeviceCount;
|
||||
|
||||
apiDefs::ConfigType configType;
|
||||
|
||||
QStringList supportedProtocols;
|
||||
};
|
||||
|
||||
AccountInfoData m_accountInfoData;
|
||||
|
||||
@@ -112,7 +112,7 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
||||
} else {
|
||||
return tr("VPN will open only popular sites blocked in your region, such as Instagram, Facebook, Twitter and others. "
|
||||
"Other sites will be opened from your real IP address, "
|
||||
"<a href=\"%1/free\" style=\"color: #FBB26A;\">more details on the website.</a>");
|
||||
"<a href=\"%1\" style=\"color: #FBB26A;\">more details on the website.</a>");
|
||||
}
|
||||
}
|
||||
case PriceRole: {
|
||||
|
||||
@@ -26,12 +26,12 @@ QVariant AppSplitTunnelingModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant();
|
||||
|
||||
switch (role) {
|
||||
case AppPathRole: {
|
||||
return m_apps.at(index.row()).appName;
|
||||
}
|
||||
default: {
|
||||
return true;
|
||||
}
|
||||
case AppPathRole: {
|
||||
return m_apps.at(index.row()).appName;
|
||||
}
|
||||
default: {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -59,6 +59,13 @@ void AppSplitTunnelingModel::removeApp(QModelIndex index)
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void AppSplitTunnelingModel::clearAppsList() {
|
||||
beginResetModel();
|
||||
m_apps.clear();
|
||||
m_settings->setVpnApps(m_currentRouteMode, m_apps);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int AppSplitTunnelingModel::getRouteMode()
|
||||
{
|
||||
return m_currentRouteMode;
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
public slots:
|
||||
bool addApp(const InstalledAppInfo &appInfo);
|
||||
void removeApp(QModelIndex index);
|
||||
void clearAppsList();
|
||||
|
||||
int getRouteMode();
|
||||
void setRouteMode(int routeMode);
|
||||
|
||||
@@ -101,6 +101,23 @@ QString LanguageModel::getCurrentLanguageName()
|
||||
return m_availableLanguages[getCurrentLanguageIndex()].name;
|
||||
}
|
||||
|
||||
LanguageSettings::AvailableLanguageEnum LanguageModel::getSystemLanguageEnum()
|
||||
{
|
||||
QLocale locale = QLocale::system();
|
||||
switch (locale.language()) {
|
||||
case QLocale::Russian: return LanguageSettings::AvailableLanguageEnum::Russian;
|
||||
case QLocale::Chinese: return LanguageSettings::AvailableLanguageEnum::China_cn;
|
||||
case QLocale::Ukrainian: return LanguageSettings::AvailableLanguageEnum::Ukrainian;
|
||||
case QLocale::Persian: return LanguageSettings::AvailableLanguageEnum::Persian;
|
||||
case QLocale::Arabic: return LanguageSettings::AvailableLanguageEnum::Arabic;
|
||||
case QLocale::Burmese: return LanguageSettings::AvailableLanguageEnum::Burmese;
|
||||
case QLocale::Urdu: return LanguageSettings::AvailableLanguageEnum::Urdu;
|
||||
case QLocale::Hindi: return LanguageSettings::AvailableLanguageEnum::Hindi;
|
||||
case QLocale::English: return LanguageSettings::AvailableLanguageEnum::English;
|
||||
default: return LanguageSettings::AvailableLanguageEnum::English;
|
||||
}
|
||||
}
|
||||
|
||||
QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
||||
{
|
||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||
@@ -110,3 +127,13 @@ QString LanguageModel::getCurrentSiteUrl(const QString &path)
|
||||
default: return QString("https://amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path)));
|
||||
}
|
||||
}
|
||||
|
||||
QString LanguageModel::getCurrentDocsUrl(const QString &path)
|
||||
{
|
||||
auto language = static_cast<LanguageSettings::AvailableLanguageEnum>(getCurrentLanguageIndex());
|
||||
switch (language) {
|
||||
case LanguageSettings::AvailableLanguageEnum::Russian:
|
||||
return "https://storage.googleapis.com/amnezia/docs" + (path.isEmpty() ? "" : (QString("?m-path=/%1").arg(path)));
|
||||
default: return QString("https://docs.amnezia.org") + (path.isEmpty() ? "" : (QString("/%1").arg(path)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
};
|
||||
|
||||
LanguageModel(std::shared_ptr<Settings> settings, QObject *parent = nullptr);
|
||||
LanguageSettings::AvailableLanguageEnum getSystemLanguageEnum();
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
@@ -60,6 +61,7 @@ public slots:
|
||||
int getLineHeightAppend();
|
||||
QString getCurrentLanguageName();
|
||||
QString getCurrentSiteUrl(const QString &path = "");
|
||||
QString getCurrentDocsUrl(const QString &path = "");
|
||||
|
||||
signals:
|
||||
void updateTranslations(const QLocale &locale);
|
||||
|
||||
@@ -25,61 +25,34 @@ bool AwgConfigModel::setData(const QModelIndex &index, const QVariant &value, in
|
||||
case Roles::PortRole: m_serverProtocolConfig.insert(config_key::port, value.toString()); break;
|
||||
|
||||
case Roles::ClientMtuRole: m_clientProtocolConfig.insert(config_key::mtu, 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::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::ClientJunkPacketCountRole: m_clientProtocolConfig.insert(config_key::junkPacketCount, 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::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::ServerJunkPacketMinSizeRole:
|
||||
m_serverProtocolConfig.insert(config_key::junkPacketMinSize, value.toString());
|
||||
break;
|
||||
case Roles::ServerJunkPacketMaxSizeRole:
|
||||
m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString());
|
||||
break;
|
||||
case Roles::ServerInitPacketJunkSizeRole:
|
||||
m_serverProtocolConfig.insert(config_key::initPacketJunkSize, 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::ServerJunkPacketMaxSizeRole: m_serverProtocolConfig.insert(config_key::junkPacketMaxSize, value.toString()); break;
|
||||
case Roles::ServerInitPacketJunkSizeRole: m_serverProtocolConfig.insert(config_key::initPacketJunkSize, value.toString()); break;
|
||||
case Roles::ServerResponsePacketJunkSizeRole:
|
||||
m_serverProtocolConfig.insert(config_key::responsePacketJunkSize, value.toString());
|
||||
break;
|
||||
case Roles::ServerInitPacketMagicHeaderRole:
|
||||
m_serverProtocolConfig.insert(config_key::initPacketMagicHeader, value.toString());
|
||||
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::ServerResponsePacketMagicHeaderRole:
|
||||
m_serverProtocolConfig.insert(config_key::responsePacketMagicHeader, value.toString());
|
||||
break;
|
||||
@@ -117,22 +90,19 @@ QVariant AwgConfigModel::data(const QModelIndex &index, int role) const
|
||||
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::ClientSpecialHandshakeTimeoutRole: return m_clientProtocolConfig.value(config_key::specialHandshakeTimeout);
|
||||
|
||||
case Roles::ServerJunkPacketCountRole: return m_serverProtocolConfig.value(config_key::junkPacketCount);
|
||||
case Roles::ServerJunkPacketMinSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMinSize);
|
||||
case Roles::ServerJunkPacketMaxSizeRole: return m_serverProtocolConfig.value(config_key::junkPacketMaxSize);
|
||||
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::ServerResponsePacketMagicHeaderRole:
|
||||
return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader);
|
||||
case Roles::ServerUnderloadPacketMagicHeaderRole:
|
||||
return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader);
|
||||
case Roles::ServerTransportPacketMagicHeaderRole:
|
||||
return m_serverProtocolConfig.value(config_key::transportPacketMagicHeader);
|
||||
case Roles::ServerResponsePacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::responsePacketMagicHeader);
|
||||
case Roles::ServerUnderloadPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::underloadPacketMagicHeader);
|
||||
case Roles::ServerTransportPacketMagicHeaderRole: return m_serverProtocolConfig.value(config_key::transportPacketMagicHeader);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@@ -147,15 +117,13 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||
|
||||
QJsonObject serverProtocolConfig = config.value(config_key::awg).toObject();
|
||||
|
||||
auto defaultTransportProto =
|
||||
ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Awg), Proto::Awg);
|
||||
auto defaultTransportProto = ProtocolProps::transportProtoToString(ProtocolProps::defaultTransportProto(Proto::Awg), Proto::Awg);
|
||||
m_serverProtocolConfig.insert(config_key::transport_proto,
|
||||
serverProtocolConfig.value(config_key::transport_proto).toString(defaultTransportProto));
|
||||
m_serverProtocolConfig[config_key::last_config] = serverProtocolConfig.value(config_key::last_config);
|
||||
m_serverProtocolConfig[config_key::subnet_address] =
|
||||
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] =
|
||||
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||
m_serverProtocolConfig[config_key::junkPacketMinSize] =
|
||||
@@ -165,33 +133,29 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||
m_serverProtocolConfig[config_key::initPacketJunkSize] =
|
||||
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||
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] =
|
||||
serverProtocolConfig.value(config_key::initPacketMagicHeader)
|
||||
.toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||
m_serverProtocolConfig[config_key::responsePacketMagicHeader] =
|
||||
serverProtocolConfig.value(config_key::responsePacketMagicHeader)
|
||||
.toString(protocols::awg::defaultResponsePacketMagicHeader);
|
||||
serverProtocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader);
|
||||
m_serverProtocolConfig[config_key::underloadPacketMagicHeader] =
|
||||
serverProtocolConfig.value(config_key::underloadPacketMagicHeader)
|
||||
.toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
||||
serverProtocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
||||
m_serverProtocolConfig[config_key::transportPacketMagicHeader] =
|
||||
serverProtocolConfig.value(config_key::transportPacketMagicHeader)
|
||||
.toString(protocols::awg::defaultTransportPacketMagicHeader);
|
||||
serverProtocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader);
|
||||
|
||||
auto lastConfig = m_serverProtocolConfig.value(config_key::last_config).toString();
|
||||
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
|
||||
m_clientProtocolConfig[config_key::mtu] = clientProtocolConfig[config_key::mtu].toString(protocols::awg::defaultMtu);
|
||||
m_clientProtocolConfig[config_key::junkPacketCount] =
|
||||
clientProtocolConfig.value(config_key::junkPacketCount)
|
||||
.toString(m_serverProtocolConfig[config_key::junkPacketCount].toString());
|
||||
clientProtocolConfig.value(config_key::junkPacketCount).toString(m_serverProtocolConfig[config_key::junkPacketCount].toString());
|
||||
m_clientProtocolConfig[config_key::junkPacketMinSize] =
|
||||
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] =
|
||||
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] =
|
||||
@@ -209,8 +173,7 @@ void AwgConfigModel::updateModel(const QJsonObject &config)
|
||||
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);
|
||||
clientProtocolConfig.value(config_key::specialHandshakeTimeout).toString(protocols::awg::defaultSpecialHandshakeTimeout);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -255,6 +218,17 @@ bool AwgConfigModel::isPacketSizeEqual(const int s1, const int 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()
|
||||
{
|
||||
const AwgConfig oldConfig(m_fullConfig.value(config_key::awg).toObject());
|
||||
@@ -289,6 +263,9 @@ QHash<int, QByteArray> AwgConfigModel::roleNames() const
|
||||
roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize";
|
||||
roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize";
|
||||
roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize";
|
||||
roles[ServerCookieReplyPacketJunkSizeRole] = "serverCookieReplyPacketJunkSize";
|
||||
roles[ServerTransportPacketJunkSizeRole] = "serverTransportPacketJunkSize";
|
||||
|
||||
roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader";
|
||||
roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader";
|
||||
roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader";
|
||||
@@ -302,61 +279,49 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig)
|
||||
auto lastConfig = serverProtocolConfig.value(config_key::last_config).toString();
|
||||
QJsonObject clientProtocolConfig = QJsonDocument::fromJson(lastConfig.toUtf8()).object();
|
||||
clientMtu = clientProtocolConfig[config_key::mtu].toString(protocols::awg::defaultMtu);
|
||||
clientJunkPacketCount =
|
||||
clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||
clientJunkPacketMinSize =
|
||||
clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||
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);
|
||||
clientJunkPacketCount = clientProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||
clientJunkPacketMinSize = clientProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||
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);
|
||||
serverJunkPacketCount =
|
||||
serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||
serverJunkPacketMinSize =
|
||||
serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||
serverJunkPacketMaxSize =
|
||||
serverProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
||||
serverInitPacketJunkSize =
|
||||
serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||
serverResponsePacketJunkSize = serverProtocolConfig.value(config_key::responsePacketJunkSize)
|
||||
.toString(protocols::awg::defaultResponsePacketJunkSize);
|
||||
serverInitPacketMagicHeader = serverProtocolConfig.value(config_key::initPacketMagicHeader)
|
||||
.toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||
serverResponsePacketMagicHeader = serverProtocolConfig.value(config_key::responsePacketMagicHeader)
|
||||
.toString(protocols::awg::defaultResponsePacketMagicHeader);
|
||||
serverUnderloadPacketMagicHeader = serverProtocolConfig.value(config_key::underloadPacketMagicHeader)
|
||||
.toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
||||
serverTransportPacketMagicHeader = serverProtocolConfig.value(config_key::transportPacketMagicHeader)
|
||||
.toString(protocols::awg::defaultTransportPacketMagicHeader);
|
||||
serverJunkPacketCount = serverProtocolConfig.value(config_key::junkPacketCount).toString(protocols::awg::defaultJunkPacketCount);
|
||||
serverJunkPacketMinSize = serverProtocolConfig.value(config_key::junkPacketMinSize).toString(protocols::awg::defaultJunkPacketMinSize);
|
||||
serverJunkPacketMaxSize = serverProtocolConfig.value(config_key::junkPacketMaxSize).toString(protocols::awg::defaultJunkPacketMaxSize);
|
||||
serverInitPacketJunkSize = serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize);
|
||||
serverResponsePacketJunkSize =
|
||||
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 =
|
||||
serverProtocolConfig.value(config_key::initPacketMagicHeader).toString(protocols::awg::defaultInitPacketMagicHeader);
|
||||
serverResponsePacketMagicHeader =
|
||||
serverProtocolConfig.value(config_key::responsePacketMagicHeader).toString(protocols::awg::defaultResponsePacketMagicHeader);
|
||||
serverUnderloadPacketMagicHeader =
|
||||
serverProtocolConfig.value(config_key::underloadPacketMagicHeader).toString(protocols::awg::defaultUnderloadPacketMagicHeader);
|
||||
serverTransportPacketMagicHeader =
|
||||
serverProtocolConfig.value(config_key::transportPacketMagicHeader).toString(protocols::awg::defaultTransportPacketMagicHeader);
|
||||
}
|
||||
|
||||
bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
||||
{
|
||||
if (subnetAddress != other.subnetAddress || port != other.port || serverJunkPacketCount != other.serverJunkPacketCount
|
||||
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize
|
||||
|| serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|
||||
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize
|
||||
|| serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
|
||||
|| serverJunkPacketMinSize != other.serverJunkPacketMinSize || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize
|
||||
|| serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize
|
||||
// || serverCookieReplyPacketJunkSize != other.serverCookieReplyPacketJunkSize
|
||||
// || serverTransportPacketJunkSize != other.serverTransportPacketJunkSize
|
||||
|| serverInitPacketMagicHeader != other.serverInitPacketMagicHeader
|
||||
|| serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader
|
||||
|| serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader
|
||||
@@ -369,12 +334,11 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const
|
||||
bool AwgConfig::hasEqualClientSettings(const AwgConfig &other) const
|
||||
{
|
||||
if (clientMtu != other.clientMtu || clientJunkPacketCount != other.clientJunkPacketCount
|
||||
|| 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
|
||||
|| 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;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
#include "containers/containers_defs.h"
|
||||
|
||||
namespace AwgConstant {
|
||||
namespace AwgConstant
|
||||
{
|
||||
const int messageInitiationSize = 148;
|
||||
const int messageResponseSize = 92;
|
||||
const int messageCookieReplySize = 64;
|
||||
const int messageTransportSize = 32;
|
||||
}
|
||||
|
||||
struct AwgConfig
|
||||
@@ -37,6 +40,8 @@ struct AwgConfig
|
||||
QString serverJunkPacketMaxSize;
|
||||
QString serverInitPacketJunkSize;
|
||||
QString serverResponsePacketJunkSize;
|
||||
QString serverCookieReplyPacketJunkSize;
|
||||
QString serverTransportPacketJunkSize;
|
||||
QString serverInitPacketMagicHeader;
|
||||
QString serverResponsePacketMagicHeader;
|
||||
QString serverUnderloadPacketMagicHeader;
|
||||
@@ -74,6 +79,9 @@ public:
|
||||
ServerJunkPacketMaxSizeRole,
|
||||
ServerInitPacketJunkSizeRole,
|
||||
ServerResponsePacketJunkSizeRole,
|
||||
ServerCookieReplyPacketJunkSizeRole,
|
||||
ServerTransportPacketJunkSizeRole,
|
||||
|
||||
ServerInitPacketMagicHeaderRole,
|
||||
ServerResponsePacketMagicHeaderRole,
|
||||
ServerUnderloadPacketMagicHeaderRole,
|
||||
@@ -92,7 +100,7 @@ public slots:
|
||||
QJsonObject getConfig();
|
||||
|
||||
bool isHeadersEqual(const QString &h1, const QString &h2, const QString &h3, const QString &h4);
|
||||
bool isPacketSizeEqual(const int s1, const int s2);
|
||||
bool isPacketSizeEqual(const int s1, const int s2/*, const int s3, const int s4*/);
|
||||
|
||||
bool isServerSettingsEqual();
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <AmneziaVPN-Swift.h>
|
||||
#endif
|
||||
|
||||
#include "core/api/apiUtils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace configKey
|
||||
@@ -66,6 +68,7 @@ bool ServersModel::setData(const QModelIndex &index, const QVariant &value, int
|
||||
} else {
|
||||
server.insert(config_key::description, value.toString());
|
||||
}
|
||||
server.insert(config_key::nameOverriddenByUser, true);
|
||||
m_settings->editServer(index.row(), server);
|
||||
m_servers.replace(index.row(), server);
|
||||
if (index.row() == m_defaultServerIndex) {
|
||||
@@ -426,7 +429,7 @@ void ServersModel::updateDefaultServerContainersModel()
|
||||
emit defaultServerContainersUpdated(containers);
|
||||
}
|
||||
|
||||
QJsonObject ServersModel::getServerConfig(const int serverIndex)
|
||||
QJsonObject ServersModel::getServerConfig(const int serverIndex) const
|
||||
{
|
||||
return m_servers.at(serverIndex).toObject();
|
||||
}
|
||||
@@ -813,3 +816,8 @@ const QString ServersModel::getDefaultServerImagePathCollapsed()
|
||||
}
|
||||
return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper());
|
||||
}
|
||||
|
||||
bool ServersModel::processedServerIsPremium() const
|
||||
{
|
||||
return apiUtils::isPremiumServer(getServerConfig(m_processedServerIndex));
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ public:
|
||||
Q_PROPERTY(bool isDefaultServerFromApi READ isDefaultServerFromApi NOTIFY defaultServerIndexChanged)
|
||||
|
||||
Q_PROPERTY(int processedIndex READ getProcessedServerIndex WRITE setProcessedServerIndex NOTIFY processedServerIndexChanged)
|
||||
Q_PROPERTY(bool processedServerIsPremium READ processedServerIsPremium NOTIFY processedServerChanged)
|
||||
|
||||
bool processedServerIsPremium() const;
|
||||
|
||||
public slots:
|
||||
void setDefaultServerIndex(const int index);
|
||||
@@ -92,7 +95,7 @@ public slots:
|
||||
void removeServer();
|
||||
void removeServer(const int serverIndex);
|
||||
|
||||
QJsonObject getServerConfig(const int serverIndex);
|
||||
QJsonObject getServerConfig(const int serverIndex) const;
|
||||
|
||||
void reloadDefaultServerContainerConfig();
|
||||
void updateContainerConfig(const int containerIndex, const QJsonObject config);
|
||||
|
||||
@@ -83,6 +83,16 @@ void SitesModel::removeSite(QModelIndex index)
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void SitesModel::removeSites()
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
m_settings->removeAllVpnSites(m_currentRouteMode);
|
||||
fillSites();
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int SitesModel::getRouteMode()
|
||||
{
|
||||
return m_currentRouteMode;
|
||||
|
||||
@@ -28,6 +28,7 @@ public slots:
|
||||
bool addSite(const QString &hostname, const QString &ip);
|
||||
void addSites(const QMap<QString, QString> &sites, bool replaceExisting);
|
||||
void removeSite(QModelIndex index);
|
||||
void removeSites();
|
||||
|
||||
int getRouteMode();
|
||||
void setRouteMode(int routeMode);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
import "../Controls2"
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
@@ -10,8 +10,7 @@ import ProtocolEnum 1.0
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: menuContent
|
||||
|
||||
property var rootWidth
|
||||
@@ -21,13 +20,6 @@ ListView {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
clip: true
|
||||
snapMode: ListView.SnapToItem
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
ButtonGroup {
|
||||
id: containersRadioButtonGroup
|
||||
}
|
||||
|
||||
@@ -1,97 +1,97 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
DrawerType2 {
|
||||
id: root
|
||||
|
||||
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
headerText: qsTr("Split tunneling")
|
||||
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: splitTunnelingSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
|
||||
text: qsTr("Split tunneling on the server")
|
||||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: siteBasedSplitTunnelingSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Site-based split tunneling")
|
||||
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: appSplitTunnelingSwitch
|
||||
visible: isAppSplitTinnelingEnabled
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("App-based split tunneling")
|
||||
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: isAppSplitTinnelingEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import PageEnum 1.0
|
||||
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
DrawerType2 {
|
||||
id: root
|
||||
|
||||
property bool isAppSplitTinnelingEnabled: Qt.platform.os === "windows" || Qt.platform.os === "android"
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
expandedStateContent: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 0
|
||||
|
||||
Header2Type {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
headerText: qsTr("Split tunneling")
|
||||
descriptionText: qsTr("Allows you to connect to some sites or applications through a VPN connection and bypass others")
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: splitTunnelingSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
|
||||
text: qsTr("Split tunneling on the server")
|
||||
descriptionText: qsTr("Enabled \nCan't be disabled for current server")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: ServersModel.isDefaultServerDefaultContainerHasSplitTunneling
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: siteBasedSplitTunnelingSwitch
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
text: qsTr("Site-based split tunneling")
|
||||
descriptionText: enabled && SitesModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
}
|
||||
|
||||
LabelWithButtonType {
|
||||
id: appSplitTunnelingSwitch
|
||||
visible: isAppSplitTinnelingEnabled
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("App-based split tunneling")
|
||||
descriptionText: AppSplitTunnelingModel.isTunnelingEnabled ? qsTr("Enabled") : qsTr("Disabled")
|
||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||
|
||||
clickedFunction: function() {
|
||||
PageController.goToPage(PageEnum.PageSettingsAppSplitTunneling)
|
||||
root.closeTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {
|
||||
visible: isAppSplitTinnelingEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ DrawerType2 {
|
||||
headerText: qsTr("Choose application")
|
||||
}
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
Layout.fillWidth: true
|
||||
@@ -66,11 +66,6 @@ DrawerType2 {
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
clip: true
|
||||
interactive: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: proxyInstalledAppsModel
|
||||
sourceModel: installedAppsModel
|
||||
@@ -81,44 +76,35 @@ DrawerType2 {
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
RowLayout {
|
||||
CheckBoxType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
RowLayout {
|
||||
CheckBoxType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
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
|
||||
text: appName
|
||||
checked: isAppSelected
|
||||
onCheckedChanged: {
|
||||
installedAppsModel.selectedStateChanged(proxyInstalledAppsModel.mapToSource(index), checked)
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
Image {
|
||||
source: "image://installedAppImage/" + appIcon
|
||||
|
||||
sourceSize.width: 24
|
||||
sourceSize.height: 24
|
||||
|
||||
Layout.rightMargin: 48
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ DrawerType2 {
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
@@ -57,14 +57,8 @@ DrawerType2 {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
property bool isFocusable: true
|
||||
property int selectedIndex: LanguageModel.currentLanguageIndex
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
model: LanguageModel
|
||||
|
||||
ButtonGroup {
|
||||
|
||||
@@ -15,7 +15,7 @@ import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: root
|
||||
|
||||
property int selectedIndex: ServersModel.defaultIndex
|
||||
@@ -28,10 +28,6 @@ ListView {
|
||||
|
||||
model: ServersModel
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Connections {
|
||||
target: ServersModel
|
||||
function onDefaultServerIndexChanged(serverIndex) {
|
||||
@@ -39,9 +35,6 @@ ListView {
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
delegate: Item {
|
||||
id: menuContentDelegate
|
||||
objectName: "menuContentDelegate"
|
||||
|
||||
@@ -13,78 +13,64 @@ import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: root
|
||||
|
||||
width: parent.width
|
||||
height: root.contentItem.height
|
||||
anchors.fill: parent
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
delegate: ColumnLayout {
|
||||
width: root.width
|
||||
|
||||
property bool isFocusable: false
|
||||
LabelWithButtonType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: root.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
text: name
|
||||
descriptionText: description
|
||||
rightImageSource: isInstalled ? "qrc:/images/controls/chevron-right.svg" : "qrc:/images/controls/download.svg"
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
clickedFunction: function() {
|
||||
if (isInstalled) {
|
||||
var containerIndex = root.model.mapToSource(index)
|
||||
ContainersModel.setProcessedContainerIndex(containerIndex)
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
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: {
|
||||
if (serviceType !== ProtocolEnum.Other) {
|
||||
if (config[ContainerProps.containerTypeToString(containerIndex)]["isThirdPartyConfig"]) {
|
||||
ProtocolsModel.updateModel(config)
|
||||
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 {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
switch (containerIndex) {
|
||||
case ContainerEnum.Ipsec: {
|
||||
ProtocolsModel.updateModel(config)
|
||||
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 {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Dialogs
|
||||
|
||||
import QtCore
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import PageEnum 1.0
|
||||
import ContainerProps 1.0
|
||||
import Style 1.0
|
||||
|
||||
import "./"
|
||||
import "../Controls2"
|
||||
import "../Controls2/TextTypes"
|
||||
import "../Config"
|
||||
import "../Components"
|
||||
|
||||
DrawerType2 {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property string configContentHeaderText
|
||||
property string shareButtonText: qsTr("Share")
|
||||
property string copyButtonText: qsTr("Copy")
|
||||
property bool isSelfHostedConfig: true
|
||||
|
||||
property string configExtension: ".vpn"
|
||||
property string configCaption: qsTr("Save AmneziaVPN config")
|
||||
property string configFileName: "amnezia_config"
|
||||
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
onClosed: {
|
||||
configExtension = ".vpn"
|
||||
configCaption = qsTr("Save AmneziaVPN config")
|
||||
configFileName = "amnezia_config"
|
||||
}
|
||||
|
||||
expandedStateContent: Item {
|
||||
implicitHeight: root.expandedHeight
|
||||
|
||||
Header2Type {
|
||||
id: header
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 20
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
|
||||
headerText: root.headerText
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listView
|
||||
|
||||
anchors.top: header.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
model: 1
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BasicButtonType {
|
||||
id: shareButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: root.shareButtonText
|
||||
leftImageSource: "qrc:/images/controls/share-2.svg"
|
||||
|
||||
clickedFunc: function() {
|
||||
var fileName = ""
|
||||
if (GC.isMobile()) {
|
||||
fileName = configFileName + configExtension
|
||||
} else {
|
||||
fileName = SystemController.getFileName(configCaption,
|
||||
qsTr("Config files (*" + configExtension + ")"),
|
||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/" + configFileName,
|
||||
true,
|
||||
configExtension)
|
||||
}
|
||||
if (fileName !== "") {
|
||||
PageController.showBusyIndicator(true)
|
||||
ExportController.exportConfig(fileName)
|
||||
PageController.showBusyIndicator(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: copyConfigTextButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
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: root.copyButtonText
|
||||
leftImageSource: "qrc:/images/controls/copy.svg"
|
||||
|
||||
Keys.onReturnPressed: { copyConfigTextButton.clicked() }
|
||||
Keys.onEnterPressed: { copyConfigTextButton.clicked() }
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: copyNativeConfigStringButton
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: false
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Copy config string")
|
||||
leftImageSource: "qrc:/images/controls/copy.svg"
|
||||
|
||||
KeyNavigation.tab: showSettingsButton
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: showSettingsButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: root.isSelfHostedConfig
|
||||
|
||||
defaultColor: AmneziaStyle.color.transparent
|
||||
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||
pressedColor: AmneziaStyle.color.sheerWhite
|
||||
disabledColor: AmneziaStyle.color.mutedGray
|
||||
textColor: AmneziaStyle.color.paleGray
|
||||
borderWidth: 1
|
||||
|
||||
text: qsTr("Show connection settings")
|
||||
|
||||
clickedFunc: function() {
|
||||
configContentDrawer.openTriggered()
|
||||
}
|
||||
}
|
||||
|
||||
DrawerType2 {
|
||||
id: configContentDrawer
|
||||
|
||||
parent: root.parent
|
||||
|
||||
anchors.fill: parent
|
||||
expandedHeight: parent.height * 0.9
|
||||
|
||||
expandedStateContent: Item {
|
||||
id: configContentContainer
|
||||
|
||||
implicitHeight: configContentDrawer.expandedHeight
|
||||
|
||||
Connections {
|
||||
target: copyNativeConfigStringButton
|
||||
function onClicked() {
|
||||
nativeConfigString.selectAll()
|
||||
nativeConfigString.copy()
|
||||
nativeConfigString.select(0, 0)
|
||||
PageController.showNotificationMessage(qsTr("Copied"))
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: copyConfigTextButton
|
||||
function onClicked() {
|
||||
configText.selectAll()
|
||||
configText.copy()
|
||||
configText.select(0, 0)
|
||||
PageController.showNotificationMessage(qsTr("Copied"))
|
||||
header.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 16
|
||||
|
||||
backButtonFunction: function() { configContentDrawer.closeTriggered() }
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
anchors.top: backButton.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: configContent.implicitHeight + configContent.anchors.topMargin + configContent.anchors.bottomMargin
|
||||
|
||||
ColumnLayout {
|
||||
id: configContent
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
Header2Type {
|
||||
id: configContentHeader
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: root.configContentHeaderText
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: nativeConfigString
|
||||
visible: false
|
||||
text: ExportController.nativeConfigString
|
||||
|
||||
onTextChanged: {
|
||||
copyNativeConfigStringButton.visible = nativeConfigString.text !== ""
|
||||
}
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: configText
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
padding: 0
|
||||
leftPadding: 0
|
||||
height: 24
|
||||
|
||||
readOnly: true
|
||||
activeFocusOnTab: false
|
||||
|
||||
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: ExportController.config
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
background: Rectangle {
|
||||
color: AmneziaStyle.color.transparent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
property bool isQrCodeVisible: root.isSelfHostedConfig ? ExportController.qrCodesCount > 0 : ApiConfigsController.qrCodesCount > 0
|
||||
|
||||
Rectangle {
|
||||
id: qrCodeContainer
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: isQrCodeVisible
|
||||
|
||||
color: "white"
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
smooth: false
|
||||
|
||||
source: root.isSelfHostedConfig ? (isQrCodeVisible ? ExportController.qrCodes[0] : "") :
|
||||
(isQrCodeVisible ? ApiConfigsController.qrCodes[0] : "")
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
Timer {
|
||||
property int index: 0
|
||||
interval: 1000
|
||||
running: isQrCodeVisible
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (isQrCodeVisible) {
|
||||
index++
|
||||
let qrCodesCount = root.isSelfHostedConfig ? ExportController.qrCodesCount : ApiConfigsController.qrCodesCount
|
||||
if (index >= qrCodesCount) {
|
||||
index = 0
|
||||
}
|
||||
|
||||
parent.source = root.isSelfHostedConfig ? ExportController.qrCodes[index] : ApiConfigsController.qrCodes[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on source {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: isQrCodeVisible
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("To read the QR code in the Amnezia app, select \"Add server\" → \"I have data to connect\" → \"QR code, key or settings file\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,220 +1,210 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Button {
|
||||
id: root
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.lightGray
|
||||
property string defaultColor: AmneziaStyle.color.paleGray
|
||||
property string disabledColor: AmneziaStyle.color.charcoalGray
|
||||
property string pressedColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string borderColor: AmneziaStyle.color.paleGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderWidth: 0
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string leftImageSource
|
||||
property string rightImageSource
|
||||
property string leftImageColor: textColor
|
||||
property bool changeLeftImageSize: true
|
||||
|
||||
property bool squareLeftSide: false
|
||||
|
||||
property FlickableType parentFlickable
|
||||
|
||||
property var clickedFunc
|
||||
|
||||
property alias buttonTextLabel: buttonText
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
implicitHeight: 56
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
id: focusBorder
|
||||
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
||||
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
radius: 16
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
|
||||
anchors.fill: focusBorder
|
||||
anchors.margins: root.activeFocus ? 2 : 0
|
||||
|
||||
radius: root.activeFocus ? 14 : 16
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
if (root.pressed) {
|
||||
return pressedColor
|
||||
}
|
||||
return root.hovered ? hoveredColor : defaultColor
|
||||
} else {
|
||||
return disabledColor
|
||||
}
|
||||
}
|
||||
border.color: borderColor
|
||||
border.width: borderWidth
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.squareLeftSide
|
||||
|
||||
z: 1
|
||||
|
||||
width: parent.radius
|
||||
height: parent.radius
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
if (root.pressed) {
|
||||
return pressedColor
|
||||
}
|
||||
return root.hovered ? hoveredColor : defaultColor
|
||||
} else {
|
||||
return disabledColor
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: focusBorder
|
||||
enabled: false
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.fill: focusBorder
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.centerIn: parent
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
source: root.leftImageSource
|
||||
visible: root.leftImageSource === "" ? false : true
|
||||
|
||||
layer {
|
||||
enabled: leftImageColor !== "" ? true : false
|
||||
effect: ColorOverlay {
|
||||
color: leftImageColor
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.changeLeftImageSize) {
|
||||
leftImage.Layout.preferredHeight = 20
|
||||
leftImage.Layout.preferredWidth = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ButtonTextType {
|
||||
id: buttonText
|
||||
|
||||
color: root.textColor
|
||||
text: root.text
|
||||
visible: root.text === "" ? false : true
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Image {
|
||||
Layout.preferredHeight: 20
|
||||
Layout.preferredWidth: 20
|
||||
|
||||
source: root.rightImageSource
|
||||
visible: root.rightImageSource === "" ? false : true
|
||||
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: textColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Button {
|
||||
id: root
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.lightGray
|
||||
property string defaultColor: AmneziaStyle.color.paleGray
|
||||
property string disabledColor: AmneziaStyle.color.charcoalGray
|
||||
property string pressedColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string borderColor: AmneziaStyle.color.paleGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderWidth: 0
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string leftImageSource
|
||||
property string rightImageSource
|
||||
property string leftImageColor: textColor
|
||||
property bool changeLeftImageSize: true
|
||||
|
||||
property bool squareLeftSide: false
|
||||
|
||||
property var clickedFunc
|
||||
|
||||
property alias buttonTextLabel: buttonText
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
implicitHeight: 56
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
background: Rectangle {
|
||||
id: focusBorder
|
||||
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
||||
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
radius: 16
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
|
||||
anchors.fill: focusBorder
|
||||
anchors.margins: root.activeFocus ? 2 : 0
|
||||
|
||||
radius: root.activeFocus ? 14 : 16
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
if (root.pressed) {
|
||||
return pressedColor
|
||||
}
|
||||
return root.hovered ? hoveredColor : defaultColor
|
||||
} else {
|
||||
return disabledColor
|
||||
}
|
||||
}
|
||||
border.color: borderColor
|
||||
border.width: borderWidth
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.squareLeftSide
|
||||
|
||||
z: 1
|
||||
|
||||
width: parent.radius
|
||||
height: parent.radius
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
if (root.pressed) {
|
||||
return pressedColor
|
||||
}
|
||||
return root.hovered ? hoveredColor : defaultColor
|
||||
} else {
|
||||
return disabledColor
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: focusBorder
|
||||
enabled: false
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.fill: focusBorder
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.centerIn: parent
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
source: root.leftImageSource
|
||||
visible: root.leftImageSource === "" ? false : true
|
||||
|
||||
layer {
|
||||
enabled: leftImageColor !== "" ? true : false
|
||||
effect: ColorOverlay {
|
||||
color: leftImageColor
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.changeLeftImageSize) {
|
||||
leftImage.Layout.preferredHeight = 20
|
||||
leftImage.Layout.preferredWidth = 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ButtonTextType {
|
||||
id: buttonText
|
||||
|
||||
color: root.textColor
|
||||
text: root.text
|
||||
visible: root.text === "" ? false : true
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Image {
|
||||
Layout.preferredHeight: 20
|
||||
Layout.preferredWidth: 20
|
||||
|
||||
source: root.rightImageSource
|
||||
visible: root.rightImageSource === "" ? false : true
|
||||
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: textColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,203 +1,185 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Button {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property string bodyText
|
||||
property string footerText
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.slateGray
|
||||
property string defaultColor: AmneziaStyle.color.onyxBlack
|
||||
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string rightImageSource
|
||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string leftImageSource
|
||||
|
||||
property real textOpacity: 1.0
|
||||
|
||||
property alias focusItem: rightImage
|
||||
|
||||
property FlickableType parentFlickable
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
anchors.fill: parent
|
||||
radius: 16
|
||||
|
||||
color: defaultColor
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
function ensureVisible(item) {
|
||||
if (item.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
ensureVisible(root)
|
||||
}
|
||||
|
||||
focusItem.onFocusChanged: {
|
||||
root.ensureVisible(focusItem)
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
source: leftImageSource
|
||||
|
||||
visible: leftImageSource !== ""
|
||||
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
Layout.leftMargin: 24
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.headerText
|
||||
visible: text !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: root.bodyText !== "" ? 0 : 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
text: root.bodyText
|
||||
visible: text !== ""
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
textFormat: Text.RichText
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: root.footerText !== "" ? 0 : 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
|
||||
ButtonTextType {
|
||||
text: root.footerText
|
||||
visible: text !== ""
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: rightImage
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: false
|
||||
image: rightImageSource
|
||||
imageColor: rightImageColor
|
||||
visible: rightImageSource ? true : false
|
||||
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
Rectangle {
|
||||
id: rightImageBackground
|
||||
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: "transparent"
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
enabled: root.enabled
|
||||
|
||||
onEntered: {
|
||||
backgroundRect.color = root.hoveredColor
|
||||
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.hoveredColor
|
||||
}
|
||||
root.textOpacity = 0.8
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundRect.color = root.defaultColor
|
||||
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 1
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 0.7
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Button {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property string bodyText
|
||||
property string footerText
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.slateGray
|
||||
property string defaultColor: AmneziaStyle.color.onyxBlack
|
||||
|
||||
property string textColor: AmneziaStyle.color.midnightBlack
|
||||
|
||||
property string rightImageSource
|
||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string leftImageSource
|
||||
|
||||
property real textOpacity: 1.0
|
||||
|
||||
property alias focusItem: rightImage
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
background: Rectangle {
|
||||
id: backgroundRect
|
||||
|
||||
anchors.fill: parent
|
||||
radius: 16
|
||||
|
||||
color: defaultColor
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
source: leftImageSource
|
||||
|
||||
visible: leftImageSource !== ""
|
||||
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
Layout.leftMargin: 24
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.headerText
|
||||
visible: text !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: root.bodyText !== "" ? 0 : 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
text: root.bodyText
|
||||
visible: text !== ""
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
textFormat: Text.RichText
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.bottomMargin: root.footerText !== "" ? 0 : 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
|
||||
ButtonTextType {
|
||||
text: root.footerText
|
||||
visible: text !== ""
|
||||
|
||||
color: AmneziaStyle.color.mutedGray
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
opacity: root.textOpacity
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: rightImage
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: false
|
||||
image: rightImageSource
|
||||
imageColor: rightImageColor
|
||||
visible: rightImageSource ? true : false
|
||||
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
Rectangle {
|
||||
id: rightImageBackground
|
||||
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: "transparent"
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
enabled: root.enabled
|
||||
|
||||
onEntered: {
|
||||
backgroundRect.color = root.hoveredColor
|
||||
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.hoveredColor
|
||||
}
|
||||
root.textOpacity = 0.8
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundRect.color = root.defaultColor
|
||||
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 1
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 0.7
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,170 +1,187 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
CheckBox {
|
||||
id: root
|
||||
|
||||
property string descriptionText
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
|
||||
property string defaultBorderColor: AmneziaStyle.color.paleGray
|
||||
property string checkedBorderColor: AmneziaStyle.color.goldenApricot
|
||||
property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string checkedImageColor: AmneziaStyle.color.goldenApricot
|
||||
property string pressedImageColor: AmneziaStyle.color.burntOrange
|
||||
property string defaultImageColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown
|
||||
|
||||
property string imageSource: "qrc:/images/controls/check.svg"
|
||||
|
||||
property var parentFlickable
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hoverEnabled: enabled ? true : false
|
||||
focusPolicy: Qt.NoFocus
|
||||
|
||||
background: Rectangle {
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent
|
||||
border.width: 1
|
||||
radius: 16
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
id: background
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
radius: 16
|
||||
|
||||
color: {
|
||||
if (root.hovered) {
|
||||
return hoveredColor
|
||||
}
|
||||
return defaultColor
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: imageBorder
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: 24
|
||||
height: 24
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: root.checked ?
|
||||
(root.enabled ?
|
||||
checkedBorderColor :
|
||||
checkedBorderDisabledColor) :
|
||||
defaultBorderColor
|
||||
border.width: 1
|
||||
radius: 4
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
|
||||
source: root.pressed ? imageSource : root.checked ? imageSource : ""
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: {
|
||||
if (root.pressed) {
|
||||
return root.pressedImageColor
|
||||
} else if (root.checked) {
|
||||
if (root.enabled) {
|
||||
return root.checkedImageColor
|
||||
} else {
|
||||
return root.checkedDisabledImageColor
|
||||
}
|
||||
} else {
|
||||
return root.defaultImageColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 8 + background.width
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
spacing: 4
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.text
|
||||
color: root.enabled ? root.textColor : root.textDisabledColor
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.descriptionText
|
||||
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
root.checked = !root.checked
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
root.checked = !root.checked
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
CheckBox {
|
||||
id: root
|
||||
|
||||
property string descriptionText
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string hoveredColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
property string defaultColor: AmneziaStyle.color.transparent
|
||||
property string pressedColor: AmneziaStyle.color.barelyTranslucentWhite
|
||||
|
||||
property string defaultBorderColor: AmneziaStyle.color.paleGray
|
||||
property string checkedBorderColor: AmneziaStyle.color.goldenApricot
|
||||
property string checkedBorderDisabledColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string checkedImageColor: AmneziaStyle.color.goldenApricot
|
||||
property string pressedImageColor: AmneziaStyle.color.burntOrange
|
||||
property string defaultImageColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledImageColor: AmneziaStyle.color.mutedBrown
|
||||
|
||||
property string imageSource: "qrc:/images/controls/check.svg"
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
hoverEnabled: enabled ? true : false
|
||||
focusPolicy: Qt.NoFocus
|
||||
|
||||
background: Rectangle {
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: root.focus ? borderFocusedColor : AmneziaStyle.color.transparent
|
||||
border.width: 1
|
||||
radius: 16
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
id: background
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
implicitWidth: 56
|
||||
implicitHeight: 56
|
||||
radius: 16
|
||||
|
||||
color: {
|
||||
if (root.hovered) {
|
||||
return hoveredColor
|
||||
}
|
||||
return defaultColor
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: imageBorder
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: 24
|
||||
height: 24
|
||||
color: AmneziaStyle.color.transparent
|
||||
border.color: root.checked ?
|
||||
(root.enabled ?
|
||||
checkedBorderColor :
|
||||
checkedBorderDisabledColor) :
|
||||
defaultBorderColor
|
||||
border.width: 1
|
||||
radius: 4
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
|
||||
source: root.pressed ? imageSource : root.checked ? imageSource : ""
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: {
|
||||
if (root.pressed) {
|
||||
return root.pressedImageColor
|
||||
} else if (root.checked) {
|
||||
if (root.enabled) {
|
||||
return root.checkedImageColor
|
||||
} else {
|
||||
return root.checkedDisabledImageColor
|
||||
}
|
||||
} else {
|
||||
return root.defaultImageColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 8 + background.width
|
||||
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
spacing: 4
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.text
|
||||
color: root.enabled ? root.textColor : root.textDisabledColor
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.descriptionText
|
||||
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
root.checked = !root.checked
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
root.checked = !root.checked
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,5 @@ Flickable {
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {
|
||||
id: scrollBar
|
||||
policy: fl.height >= fl.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,328 +1,309 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string text
|
||||
property int textMaximumLineCount: 2
|
||||
property int textElide: Qt.ElideRight
|
||||
|
||||
property string descriptionText
|
||||
|
||||
property var clickedFunction
|
||||
|
||||
property string buttonImageSource
|
||||
property string rightImageSource
|
||||
property string leftImageSource
|
||||
property bool isLeftImageHoverEnabled: true
|
||||
property bool isSmallLeftImage: false
|
||||
|
||||
property alias rightButton: rightImage
|
||||
property alias eyeButton: eyeImage
|
||||
property FlickableType parentFlickable
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
property real textOpacity: 1.0
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property bool descriptionOnTop: false
|
||||
property bool hideDescription: true
|
||||
|
||||
property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
||||
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 {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: root.enabled
|
||||
|
||||
onEntered: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.hoveredColor
|
||||
} else if (leftImageSource) {
|
||||
leftImageBackground.color = rightImage.hoveredColor
|
||||
}
|
||||
root.textOpacity = 0.8
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.defaultColor
|
||||
} else if (leftImageSource) {
|
||||
leftImageBackground.color = rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 1
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
} else if (leftImageSource) {
|
||||
leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 0.7
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
anchors.topMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
|
||||
Rectangle {
|
||||
id: leftImageBackground
|
||||
|
||||
visible: leftImageSource ? true : false
|
||||
|
||||
Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56
|
||||
Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56
|
||||
Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0
|
||||
|
||||
radius: 12
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
|
||||
anchors.centerIn: parent
|
||||
source: leftImageSource
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
property real textLineHeight: 21.6
|
||||
property real descriptionTextLineHeight: 16
|
||||
|
||||
property int textPixelSize: 18
|
||||
property int descriptionTextSize: 13
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.text
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
return root.descriptionOnTop ? root.descriptionColor : root.textColor
|
||||
} else {
|
||||
return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor
|
||||
}
|
||||
}
|
||||
|
||||
maximumLineCount: root.textMaximumLineCount
|
||||
elide: root.textElide
|
||||
|
||||
opacity: root.textOpacity
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight
|
||||
font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize
|
||||
font.letterSpacing: root.descriptionOnTop ? 0.02 : 0
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
Behavior on opacity {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
return root.descriptionOnTop ? root.textColor : root.descriptionColor
|
||||
} else {
|
||||
return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor
|
||||
}
|
||||
}
|
||||
|
||||
opacity: root.textOpacity
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight
|
||||
font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize
|
||||
font.letterSpacing: root.descriptionOnTop ? 0 : 0.02
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
Behavior on opacity {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
function replaceWithAsterisks(input) {
|
||||
return '*'.repeat(input.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: eyeImage
|
||||
visible: buttonImageSource !== ""
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: true
|
||||
image: buttonImageSource
|
||||
imageColor: rightImageColor
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
Rectangle {
|
||||
id: eyeImageBackground
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
hideDescription = !hideDescription
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
clicked()
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
clicked()
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: rightImage
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: false
|
||||
image: rightImageSource
|
||||
imageColor: rightImageColor
|
||||
visible: rightImageSource ? true : false
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
Rectangle {
|
||||
id: rightImageBackground
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: root
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
||||
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
||||
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// property alias focusObjectName: eyeImage.objectName
|
||||
property string text
|
||||
property int textMaximumLineCount: 2
|
||||
property int textElide: Qt.ElideRight
|
||||
|
||||
property string descriptionText
|
||||
|
||||
property var clickedFunction
|
||||
|
||||
property string buttonImageSource
|
||||
property string rightImageSource
|
||||
property string leftImageSource
|
||||
property bool isLeftImageHoverEnabled: true
|
||||
property bool isSmallLeftImage: false
|
||||
|
||||
property alias rightButton: rightImage
|
||||
property alias eyeButton: eyeImage
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
property real textOpacity: 1.0
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string rightImageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property bool descriptionOnTop: false
|
||||
property bool hideDescription: true
|
||||
|
||||
property bool isFocusable: !(eyeImage.visible || rightImage.visible) // TODO: this component already has focusable items
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
FocusController.nextKeyUpItem()
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
FocusController.nextKeyDownItem()
|
||||
}
|
||||
|
||||
Keys.onLeftPressed: {
|
||||
FocusController.nextKeyLeftItem()
|
||||
}
|
||||
|
||||
Keys.onRightPressed: {
|
||||
FocusController.nextKeyRightItem()
|
||||
}
|
||||
|
||||
implicitWidth: content.implicitWidth + content.anchors.topMargin + content.anchors.bottomMargin
|
||||
implicitHeight: content.implicitHeight + content.anchors.leftMargin + content.anchors.rightMargin
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: root.enabled
|
||||
|
||||
onEntered: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.hoveredColor
|
||||
} else if (leftImageSource) {
|
||||
leftImageBackground.color = rightImage.hoveredColor
|
||||
}
|
||||
root.textOpacity = 0.8
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = rightImage.defaultColor
|
||||
} else if (leftImageSource) {
|
||||
leftImageBackground.color = rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 1
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (rightImageSource) {
|
||||
rightImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
} else if (leftImageSource) {
|
||||
leftImageBackground.color = pressed ? rightImage.pressedColor : entered ? rightImage.hoveredColor : rightImage.defaultColor
|
||||
}
|
||||
root.textOpacity = 0.7
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
anchors.topMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
|
||||
Rectangle {
|
||||
id: leftImageBackground
|
||||
|
||||
visible: leftImageSource ? true : false
|
||||
|
||||
Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56
|
||||
Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56
|
||||
Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0
|
||||
|
||||
radius: 12
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Image {
|
||||
id: leftImage
|
||||
|
||||
anchors.centerIn: parent
|
||||
source: leftImageSource
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
property real textLineHeight: 21.6
|
||||
property real descriptionTextLineHeight: 16
|
||||
|
||||
property int textPixelSize: 18
|
||||
property int descriptionTextSize: 13
|
||||
|
||||
ListItemTitleType {
|
||||
text: root.text
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
return root.descriptionOnTop ? root.descriptionColor : root.textColor
|
||||
} else {
|
||||
return root.descriptionOnTop ? root.descriptionDisabledColor : root.textDisabledColor
|
||||
}
|
||||
}
|
||||
|
||||
maximumLineCount: root.textMaximumLineCount
|
||||
elide: root.textElide
|
||||
|
||||
opacity: root.textOpacity
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
lineHeight: root.descriptionOnTop ? parent.descriptionTextLineHeight : parent.textLineHeight
|
||||
font.pixelSize: root.descriptionOnTop ? parent.descriptionTextSize : parent.textPixelSize
|
||||
font.letterSpacing: root.descriptionOnTop ? 0.02 : 0
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
Behavior on opacity {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
text: (eyeImage.visible && hideDescription) ? replaceWithAsterisks(root.descriptionText) : root.descriptionText
|
||||
color: {
|
||||
if (root.enabled) {
|
||||
return root.descriptionOnTop ? root.textColor : root.descriptionColor
|
||||
} else {
|
||||
return root.descriptionOnTop ? root.textDisabledColor : root.descriptionDisabledColor
|
||||
}
|
||||
}
|
||||
|
||||
opacity: root.textOpacity
|
||||
|
||||
visible: root.descriptionText !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
lineHeight: root.descriptionOnTop ? parent.textLineHeight : parent.descriptionTextLineHeight
|
||||
font.pixelSize: root.descriptionOnTop ? parent.textPixelSize : parent.descriptionTextSize
|
||||
font.letterSpacing: root.descriptionOnTop ? 0 : 0.02
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
Behavior on opacity {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
function replaceWithAsterisks(input) {
|
||||
return '*'.repeat(input.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: eyeImage
|
||||
visible: buttonImageSource !== ""
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: true
|
||||
image: buttonImageSource
|
||||
imageColor: rightImageColor
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
Rectangle {
|
||||
id: eyeImageBackground
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
hideDescription = !hideDescription
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
clicked()
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
clicked()
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: rightImage
|
||||
|
||||
implicitWidth: 40
|
||||
implicitHeight: 40
|
||||
|
||||
hoverEnabled: false
|
||||
image: rightImageSource
|
||||
imageColor: rightImageColor
|
||||
visible: rightImageSource ? true : false
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
Rectangle {
|
||||
id: rightImageBackground
|
||||
anchors.fill: parent
|
||||
radius: 12
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: root
|
||||
color: AmneziaStyle.color.transparent
|
||||
|
||||
border.color: root.activeFocus ? root.borderFocusedColor : AmneziaStyle.color.transparent
|
||||
border.width: root.activeFocus ? root.borderFocusedWidth : 0
|
||||
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (clickedFunction && typeof clickedFunction === "function") {
|
||||
clickedFunction()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,33 +6,16 @@ ListView {
|
||||
|
||||
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 {}
|
||||
|
||||
clip: 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: root
|
||||
|
||||
property var rootWidth
|
||||
@@ -25,13 +25,6 @@ ListView {
|
||||
width: rootWidth
|
||||
height: root.contentItem.height
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
ButtonGroup {
|
||||
id: buttonGroup
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ import "../Controls2"
|
||||
ScrollBar {
|
||||
id: root
|
||||
|
||||
policy: parent.height >= parent.contentHeight ? ScrollBar.AlwaysOff : ScrollBar.AlwaysOn
|
||||
policy: ScrollBar.AsNeeded
|
||||
}
|
||||
|
||||
@@ -1,172 +1,162 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Switch {
|
||||
id: root
|
||||
|
||||
property alias descriptionText: description.text
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string checkedIndicatorColor: AmneziaStyle.color.richBrown
|
||||
property string defaultIndicatorColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown
|
||||
property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray
|
||||
property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot
|
||||
property string defaultInnerCircleColor: AmneziaStyle.color.paleGray
|
||||
property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown
|
||||
property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
|
||||
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
hoverEnabled: enabled ? true : false
|
||||
focusPolicy: Qt.TabFocus
|
||||
|
||||
property FlickableType parentFlickable: null
|
||||
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
id: switcher
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
implicitWidth: 52
|
||||
implicitHeight: 32
|
||||
|
||||
radius: 16
|
||||
color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor)
|
||||
: root.defaultIndicatorColor
|
||||
|
||||
border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor)
|
||||
: root.defaultIndicatorBorderColor)
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: innerCircle
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: root.checked ? parent.width - width - 4 : 8
|
||||
width: root.checked ? 24 : 16
|
||||
height: root.checked ? 24 : 16
|
||||
radius: 23
|
||||
color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor)
|
||||
: (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor)
|
||||
|
||||
Behavior on x {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: innerCircle
|
||||
width: 40
|
||||
height: 40
|
||||
radius: 23
|
||||
color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
rightPadding: indicator.width
|
||||
|
||||
text: root.text
|
||||
color: root.enabled ? root.textColor : root.textDisabledColor
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
Layout.fillWidth: true
|
||||
rightPadding: indicator.width
|
||||
|
||||
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
||||
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: event => handleSwitch(event)
|
||||
Keys.onReturnPressed: event => handleSwitch(event)
|
||||
Keys.onSpacePressed: event => handleSwitch(event)
|
||||
|
||||
function handleSwitch(event) {
|
||||
if (!event.isAutoRepeat) {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Switch {
|
||||
id: root
|
||||
|
||||
property alias descriptionText: description.text
|
||||
property string descriptionTextColor: AmneziaStyle.color.mutedGray
|
||||
property string descriptionTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string textColor: AmneziaStyle.color.paleGray
|
||||
property string textDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property string checkedIndicatorColor: AmneziaStyle.color.richBrown
|
||||
property string defaultIndicatorColor: AmneziaStyle.color.transparent
|
||||
property string checkedDisabledIndicatorColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
property int borderFocusedWidth: 1
|
||||
|
||||
property string checkedIndicatorBorderColor: AmneziaStyle.color.richBrown
|
||||
property string defaultIndicatorBorderColor: AmneziaStyle.color.charcoalGray
|
||||
property string checkedDisabledIndicatorBorderColor: AmneziaStyle.color.deepBrown
|
||||
|
||||
property string checkedInnerCircleColor: AmneziaStyle.color.goldenApricot
|
||||
property string defaultInnerCircleColor: AmneziaStyle.color.paleGray
|
||||
property string checkedDisabledInnerCircleColor: AmneziaStyle.color.mutedBrown
|
||||
property string defaultDisabledInnerCircleColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
property string hoveredIndicatorBackgroundColor: AmneziaStyle.color.translucentWhite
|
||||
property string defaultIndicatorBackgroundColor: AmneziaStyle.color.transparent
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
hoverEnabled: enabled ? true : false
|
||||
focusPolicy: Qt.TabFocus
|
||||
|
||||
indicator: Rectangle {
|
||||
id: switcher
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
implicitWidth: 52
|
||||
implicitHeight: 32
|
||||
|
||||
radius: 16
|
||||
color: root.checked ? (root.enabled ? root.checkedIndicatorColor : root.checkedDisabledIndicatorColor)
|
||||
: root.defaultIndicatorColor
|
||||
|
||||
border.color: root.activeFocus ? root.borderFocusedColor : (root.checked ? (root.enabled ? root.checkedIndicatorBorderColor : root.checkedDisabledIndicatorBorderColor)
|
||||
: root.defaultIndicatorBorderColor)
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: innerCircle
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: root.checked ? parent.width - width - 4 : 8
|
||||
width: root.checked ? 24 : 16
|
||||
height: root.checked ? 24 : 16
|
||||
radius: 23
|
||||
color: root.checked ? (root.enabled ? root.checkedInnerCircleColor : root.checkedDisabledInnerCircleColor)
|
||||
: (root.enabled ? root.defaultInnerCircleColor : root.defaultDisabledInnerCircleColor)
|
||||
|
||||
Behavior on x {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: innerCircle
|
||||
width: 40
|
||||
height: 40
|
||||
radius: 23
|
||||
color: root.hovered ? root.hoveredIndicatorBackgroundColor : root.defaultIndicatorBackgroundColor
|
||||
|
||||
Behavior on color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: content
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
|
||||
ListItemTitleType {
|
||||
Layout.fillWidth: true
|
||||
rightPadding: indicator.width
|
||||
|
||||
text: root.text
|
||||
color: root.enabled ? root.textColor : root.textDisabledColor
|
||||
}
|
||||
|
||||
CaptionTextType {
|
||||
id: description
|
||||
|
||||
Layout.fillWidth: true
|
||||
rightPadding: indicator.width
|
||||
|
||||
color: root.enabled ? root.descriptionTextColor : root.descriptionTextDisabledColor
|
||||
|
||||
visible: text !== ""
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: false
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: event => handleSwitch(event)
|
||||
Keys.onReturnPressed: event => handleSwitch(event)
|
||||
Keys.onSpacePressed: event => handleSwitch(event)
|
||||
|
||||
function handleSwitch(event) {
|
||||
if (!event.isAutoRepeat) {
|
||||
root.checked = !root.checked
|
||||
root.checkedChanged()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,118 +1,135 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import Style 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string placeholderText
|
||||
property string text
|
||||
property alias textArea: textArea
|
||||
property alias textAreaText: textArea.text
|
||||
|
||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
height: 148
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
border.width: 1
|
||||
border.color: getBorderColor(borderNormalColor)
|
||||
radius: 16
|
||||
|
||||
property FlickableType parentFlickable: null
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: parentMouse
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: textArea.forceActiveFocus()
|
||||
hoverEnabled: true
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
interactive: false
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: textArea.implicitHeight
|
||||
TextArea {
|
||||
id: textArea
|
||||
|
||||
width: parent.width
|
||||
|
||||
topPadding: 16
|
||||
leftPadding: 16
|
||||
anchors.topMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
placeholderText: root.placeholderText
|
||||
text: root.text
|
||||
|
||||
onCursorVisibleChanged: {
|
||||
if (textArea.cursorVisible) {
|
||||
fl.interactive = true
|
||||
} else {
|
||||
fl.interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
MouseArea {
|
||||
id: textAreaMouse
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
fl.interactive = true
|
||||
contextMenu.open()
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textArea
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
root.border.color = getBorderColor(borderFocusedColor)
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
root.border.color = getBorderColor(borderHoveredColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getBorderColor(noneFocusedColor) {
|
||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import Style 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string placeholderText
|
||||
property string text
|
||||
property alias textArea: textArea
|
||||
property alias textAreaText: textArea.text
|
||||
|
||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
height: 148
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
border.width: 1
|
||||
border.color: getBorderColor(borderNormalColor)
|
||||
radius: 16
|
||||
|
||||
MouseArea {
|
||||
id: parentMouse
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: textArea.forceActiveFocus()
|
||||
hoverEnabled: true
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
interactive: false
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: textArea.implicitHeight
|
||||
TextArea {
|
||||
id: textArea
|
||||
|
||||
width: parent.width
|
||||
|
||||
topPadding: 16
|
||||
leftPadding: 16
|
||||
anchors.topMargin: 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
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
placeholderText: root.placeholderText
|
||||
text: root.text
|
||||
|
||||
onCursorVisibleChanged: {
|
||||
if (textArea.cursorVisible) {
|
||||
fl.interactive = true
|
||||
} else {
|
||||
fl.interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
MouseArea {
|
||||
id: textAreaMouse
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
fl.interactive = true
|
||||
contextMenu.open()
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textArea
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
root.border.color = getBorderColor(borderFocusedColor)
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
root.border.color = getBorderColor(borderHoveredColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getBorderColor(noneFocusedColor) {
|
||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,180 +1,171 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string placeholderText
|
||||
property string text
|
||||
property string headerText
|
||||
property alias textArea: textArea
|
||||
property alias textAreaText: textArea.text
|
||||
|
||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string firstButtonImage
|
||||
property string secondButtonImage
|
||||
|
||||
property var firstButtonClickedFunc
|
||||
property var secondButtonClickedFunc
|
||||
|
||||
height: 148
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
border.width: 1
|
||||
border.color: getBorderColor(borderNormalColor)
|
||||
radius: 16
|
||||
|
||||
property FlickableType parentFlickable: null
|
||||
onFocusChanged: {
|
||||
if (root.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: parentMouse
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: textArea.forceActiveFocus()
|
||||
hoverEnabled: true
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 0
|
||||
|
||||
LabelTextType {
|
||||
Layout.fillWidth: true
|
||||
text: root.headerText
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: textArea
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
leftPadding: 0
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
placeholderText: root.placeholderText
|
||||
text: root.text
|
||||
|
||||
onCursorVisibleChanged: {
|
||||
if (textArea.cursorVisible) {
|
||||
fl.interactive = true
|
||||
} else {
|
||||
fl.interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
MouseArea {
|
||||
id: textAreaMouse
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
fl.interactive = true
|
||||
contextMenu.open()
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textArea
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: -8
|
||||
spacing: 0
|
||||
ImageButtonType {
|
||||
id: firstButton
|
||||
visible: root.firstButtonImage !== ""
|
||||
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
image: root.firstButtonImage
|
||||
onClicked: function() {
|
||||
if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") {
|
||||
root.firstButtonClickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: secondButton
|
||||
visible: root.secondButtonImage !== ""
|
||||
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
image: root.secondButtonImage
|
||||
onClicked: function() {
|
||||
if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") {
|
||||
root.secondButtonClickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: resetButton
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
visible: root.textAreaText !== ""
|
||||
image: "qrc:/images/controls/close.svg"
|
||||
|
||||
onClicked: function() {
|
||||
root.textAreaText = ""
|
||||
textArea.focus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
root.border.color = getBorderColor(borderFocusedColor)
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
root.border.color = getBorderColor(borderHoveredColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getBorderColor(noneFocusedColor) {
|
||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string placeholderText
|
||||
property string text
|
||||
property string headerText
|
||||
property alias textArea: textArea
|
||||
property alias textAreaText: textArea.text
|
||||
|
||||
property string borderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
property string borderNormalColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string firstButtonImage
|
||||
property string secondButtonImage
|
||||
|
||||
property var firstButtonClickedFunc
|
||||
property var secondButtonClickedFunc
|
||||
|
||||
height: 148
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
border.width: 1
|
||||
border.color: getBorderColor(borderNormalColor)
|
||||
radius: 16
|
||||
|
||||
MouseArea {
|
||||
id: parentMouse
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: textArea.forceActiveFocus()
|
||||
hoverEnabled: true
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 0
|
||||
|
||||
LabelTextType {
|
||||
Layout.fillWidth: true
|
||||
text: root.headerText
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: textArea
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
leftPadding: 0
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
color: AmneziaStyle.color.paleGray
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
placeholderTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: Font.Medium
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
placeholderText: root.placeholderText
|
||||
text: root.text
|
||||
|
||||
onCursorVisibleChanged: {
|
||||
if (textArea.cursorVisible) {
|
||||
fl.interactive = true
|
||||
} else {
|
||||
fl.interactive = false
|
||||
}
|
||||
}
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
MouseArea {
|
||||
id: textAreaMouse
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
fl.interactive = true
|
||||
contextMenu.open()
|
||||
}
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textArea
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: -8
|
||||
spacing: 0
|
||||
ImageButtonType {
|
||||
id: firstButton
|
||||
visible: root.firstButtonImage !== ""
|
||||
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
image: root.firstButtonImage
|
||||
onClicked: function() {
|
||||
if (root.firstButtonClickedFunc && typeof root.firstButtonClickedFunc === "function") {
|
||||
root.firstButtonClickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: secondButton
|
||||
visible: root.secondButtonImage !== ""
|
||||
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
image: root.secondButtonImage
|
||||
onClicked: function() {
|
||||
if (root.secondButtonClickedFunc && typeof root.secondButtonClickedFunc === "function") {
|
||||
root.secondButtonClickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ImageButtonType {
|
||||
id: resetButton
|
||||
imageColor: AmneziaStyle.color.paleGray
|
||||
|
||||
visible: root.textAreaText !== ""
|
||||
image: "qrc:/images/controls/close.svg"
|
||||
|
||||
onClicked: function() {
|
||||
root.textAreaText = ""
|
||||
textArea.focus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
root.border.color = getBorderColor(borderFocusedColor)
|
||||
}
|
||||
|
||||
onExited: {
|
||||
root.border.color = getBorderColor(borderNormalColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
root.border.color = getBorderColor(borderHoveredColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getBorderColor(noneFocusedColor) {
|
||||
return textArea.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,233 +1,220 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
property string headerTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property alias errorText: errorField.text
|
||||
property bool checkEmptyText: false
|
||||
property bool rightButtonClickedOnEnter: false
|
||||
|
||||
property string buttonText
|
||||
property string buttonImageSource
|
||||
property var clickedFunc
|
||||
|
||||
property alias textField: textField
|
||||
property string textFieldTextColor: AmneziaStyle.color.paleGray
|
||||
property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property bool textFieldEditable: true
|
||||
|
||||
property string borderColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string backgroundColor: AmneziaStyle.color.onyxBlack
|
||||
property string backgroundDisabledColor: AmneziaStyle.color.transparent
|
||||
property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
property FlickableType parentFlickable
|
||||
|
||||
Connections {
|
||||
target: textField
|
||||
function onFocusChanged() {
|
||||
if (textField.activeFocus) {
|
||||
if (root.parentFlickable) {
|
||||
root.parentFlickable.ensureVisible(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
id: backgroud
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: input.implicitHeight
|
||||
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
||||
radius: 16
|
||||
border.color: getBackgroundBorderColor(root.borderColor)
|
||||
border.width: 1
|
||||
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: input
|
||||
anchors.fill: backgroud
|
||||
ColumnLayout {
|
||||
Layout.margins: 16
|
||||
LabelTextType {
|
||||
text: root.headerText
|
||||
color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor
|
||||
|
||||
visible: text !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
enabled: root.textFieldEditable
|
||||
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
|
||||
|
||||
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
|
||||
|
||||
placeholderTextColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
height: 24
|
||||
Layout.fillWidth: true
|
||||
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
bottomPadding: 0
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
root.errorText = ""
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (root.checkEmptyText && text === "") {
|
||||
root.errorText = qsTr("The field can't be empty")
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: contextMenu.open()
|
||||
enabled: true
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textField
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmallTextType {
|
||||
id: errorField
|
||||
|
||||
text: root.errorText
|
||||
visible: root.errorText !== ""
|
||||
color: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: root
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
onPressed: function(mouse) {
|
||||
textField.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
|
||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor)
|
||||
}
|
||||
|
||||
|
||||
onExited: {
|
||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
visible: (root.buttonText !== "") || (root.buttonImageSource !== "")
|
||||
|
||||
focusPolicy: Qt.NoFocus
|
||||
text: root.buttonText
|
||||
leftImageSource: root.buttonImageSource
|
||||
|
||||
anchors.top: content.top
|
||||
anchors.bottom: content.bottom
|
||||
anchors.right: content.right
|
||||
|
||||
height: content.implicitHeight
|
||||
width: content.implicitHeight
|
||||
squareLeftSide: true
|
||||
|
||||
clickedFunc: function() {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getBackgroundBorderColor(noneFocusedColor) {
|
||||
return textField.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
clickedFunc()
|
||||
}
|
||||
|
||||
// if (KeyNavigation.tab) {
|
||||
// KeyNavigation.tab.forceActiveFocus();
|
||||
// }
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
clickedFunc()
|
||||
}
|
||||
|
||||
// if (KeyNavigation.tab) {
|
||||
// KeyNavigation.tab.forceActiveFocus();
|
||||
// }
|
||||
}
|
||||
}
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import Style 1.0
|
||||
|
||||
import "TextTypes"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string headerText
|
||||
property string headerTextDisabledColor: AmneziaStyle.color.charcoalGray
|
||||
property string headerTextColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property alias errorText: errorField.text
|
||||
property bool checkEmptyText: false
|
||||
property bool rightButtonClickedOnEnter: false
|
||||
|
||||
property string buttonText
|
||||
property string buttonImageSource
|
||||
property var clickedFunc
|
||||
|
||||
property alias textField: textField
|
||||
property string textFieldTextColor: AmneziaStyle.color.paleGray
|
||||
property string textFieldTextDisabledColor: AmneziaStyle.color.mutedGray
|
||||
|
||||
property bool textFieldEditable: true
|
||||
|
||||
property string borderColor: AmneziaStyle.color.slateGray
|
||||
property string borderFocusedColor: AmneziaStyle.color.paleGray
|
||||
|
||||
property string backgroundColor: AmneziaStyle.color.onyxBlack
|
||||
property string backgroundDisabledColor: AmneziaStyle.color.transparent
|
||||
property string bgBorderHoveredColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
id: backgroud
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: input.implicitHeight
|
||||
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
||||
radius: 16
|
||||
border.color: getBackgroundBorderColor(root.borderColor)
|
||||
border.width: 1
|
||||
|
||||
Behavior on border.color {
|
||||
PropertyAnimation { duration: 200 }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: input
|
||||
anchors.fill: backgroud
|
||||
ColumnLayout {
|
||||
Layout.margins: 16
|
||||
LabelTextType {
|
||||
text: root.headerText
|
||||
color: root.enabled ? root.headerTextColor : root.headerTextDisabledColor
|
||||
|
||||
visible: text !== ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: textField
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
Keys.onTabPressed: {
|
||||
FocusController.nextKeyTabItem()
|
||||
}
|
||||
|
||||
Keys.onBacktabPressed: {
|
||||
FocusController.previousKeyTabItem()
|
||||
}
|
||||
|
||||
enabled: root.textFieldEditable
|
||||
color: root.enabled ? root.textFieldTextColor : root.textFieldTextDisabledColor
|
||||
|
||||
inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhSensitiveData | Qt.ImhNoPredictiveText
|
||||
|
||||
placeholderTextColor: AmneziaStyle.color.charcoalGray
|
||||
|
||||
selectionColor: AmneziaStyle.color.richBrown
|
||||
selectedTextColor: AmneziaStyle.color.paleGray
|
||||
|
||||
font.pixelSize: 16
|
||||
font.weight: 400
|
||||
font.family: "PT Root UI VF"
|
||||
|
||||
height: 24
|
||||
Layout.fillWidth: true
|
||||
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
bottomPadding: 0
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: root.enabled ? root.backgroundColor : root.backgroundDisabledColor
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
root.errorText = ""
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (root.checkEmptyText && text === "") {
|
||||
root.errorText = qsTr("The field can't be empty")
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: contextMenu.open()
|
||||
enabled: true
|
||||
}
|
||||
|
||||
ContextMenuType {
|
||||
id: contextMenu
|
||||
textObj: textField
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SmallTextType {
|
||||
id: errorField
|
||||
|
||||
text: root.errorText
|
||||
visible: root.errorText !== ""
|
||||
color: AmneziaStyle.color.vibrantRed
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: root
|
||||
cursorShape: Qt.IBeamCursor
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
onPressed: function(mouse) {
|
||||
textField.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
|
||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroud.border.color = getBackgroundBorderColor(bgBorderHoveredColor)
|
||||
}
|
||||
|
||||
|
||||
onExited: {
|
||||
backgroud.border.color = getBackgroundBorderColor(root.borderColor)
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
visible: (root.buttonText !== "") || (root.buttonImageSource !== "")
|
||||
|
||||
focusPolicy: Qt.NoFocus
|
||||
text: root.buttonText
|
||||
leftImageSource: root.buttonImageSource
|
||||
|
||||
anchors.top: content.top
|
||||
anchors.bottom: content.bottom
|
||||
anchors.right: content.right
|
||||
|
||||
height: content.implicitHeight
|
||||
width: content.implicitHeight
|
||||
squareLeftSide: true
|
||||
|
||||
clickedFunc: function() {
|
||||
if (root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
root.clickedFunc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getBackgroundBorderColor(noneFocusedColor) {
|
||||
return textField.focus ? root.borderFocusedColor : noneFocusedColor
|
||||
}
|
||||
|
||||
Keys.onEnterPressed: {
|
||||
if (root.rightButtonClickedOnEnter && root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
clickedFunc()
|
||||
}
|
||||
|
||||
// if (KeyNavigation.tab) {
|
||||
// KeyNavigation.tab.forceActiveFocus();
|
||||
// }
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (root.rightButtonClickedOnEnter &&root.clickedFunc && typeof root.clickedFunc === "function") {
|
||||
clickedFunc()
|
||||
}
|
||||
|
||||
// if (KeyNavigation.tab) {
|
||||
// KeyNavigation.tab.forceActiveFocus();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ PageType {
|
||||
|
||||
SortFilterProxyModel {
|
||||
id: proxyServersModel
|
||||
|
||||
sourceModel: ServersModel
|
||||
|
||||
filters: [
|
||||
ValueFilter {
|
||||
roleName: "isCurrentlyProcessed"
|
||||
@@ -29,67 +31,55 @@ PageType {
|
||||
]
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.fill: parent
|
||||
contentHeight: content.height
|
||||
|
||||
Column {
|
||||
id: content
|
||||
spacing: 16
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
model: proxyServersModel
|
||||
|
||||
spacing: 16
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
Repeater {
|
||||
model: proxyServersModel
|
||||
delegate: Item {
|
||||
implicitWidth: parent.width
|
||||
implicitHeight: delegateContent.implicitHeight
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
ColumnLayout {
|
||||
id: delegateContent
|
||||
headerText: qsTr("Removing services from %1").arg(name)
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
ProgressBarType {
|
||||
id: progressBar
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Removing services from %1").arg(name)
|
||||
}
|
||||
Timer {
|
||||
id: timer
|
||||
|
||||
ProgressBarType {
|
||||
id: progressBar
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
|
||||
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")
|
||||
}
|
||||
interval: 300
|
||||
repeat: true
|
||||
running: true
|
||||
onTriggered: {
|
||||
progressBar.value += 0.003
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Usually it takes no more than 5 minutes")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,17 @@ PageType {
|
||||
anchors.topMargin: 20
|
||||
}
|
||||
|
||||
ListView {
|
||||
ListViewType {
|
||||
id: listView
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
ScrollBar.vertical: ScrollBarType {}
|
||||
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
@@ -50,16 +44,14 @@ PageType {
|
||||
}
|
||||
}
|
||||
|
||||
model: 1
|
||||
clip: true
|
||||
model: 1 // fake model to force the ListView to be created without a model
|
||||
|
||||
spacing: 16
|
||||
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: passwordTextField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
@@ -87,8 +79,6 @@ PageType {
|
||||
width: listView.width
|
||||
|
||||
SwitcherType {
|
||||
id: switcher
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.rightMargin: 16
|
||||
|
||||
@@ -101,8 +101,8 @@ PageType {
|
||||
visible: isLoggingEnabled ? true : false
|
||||
text: qsTr("Logging enabled")
|
||||
|
||||
Keys.onEnterPressed: loggingButton.clicked()
|
||||
Keys.onReturnPressed: loggingButton.clicked()
|
||||
Keys.onEnterPressed: this.clicked()
|
||||
Keys.onReturnPressed: this.clicked()
|
||||
|
||||
onClicked: {
|
||||
PageController.goToPage(PageEnum.PageSettingsLogging)
|
||||
@@ -147,8 +147,8 @@ PageType {
|
||||
leftImageColor: ""
|
||||
rightImageSource: "qrc:/images/controls/chevron-down.svg"
|
||||
|
||||
Keys.onEnterPressed: splitTunnelingButton.clicked()
|
||||
Keys.onReturnPressed: splitTunnelingButton.clicked()
|
||||
Keys.onEnterPressed: this.clicked()
|
||||
Keys.onReturnPressed: this.clicked()
|
||||
|
||||
onClicked: {
|
||||
homeSplitTunnelingDrawer.openTriggered()
|
||||
@@ -276,8 +276,8 @@ PageType {
|
||||
topPadding: 4
|
||||
bottomPadding: 3
|
||||
|
||||
Keys.onEnterPressed: collapsedButtonChevron.clicked()
|
||||
Keys.onReturnPressed: collapsedButtonChevron.clicked()
|
||||
Keys.onEnterPressed: this.clicked()
|
||||
Keys.onReturnPressed: this.clicked()
|
||||
|
||||
onClicked: {
|
||||
if (drawer.isCollapsedStateActive()) {
|
||||
@@ -320,6 +320,9 @@ PageType {
|
||||
|
||||
rightImageSource: hoverEnabled ? "qrc:/images/controls/chevron-down.svg" : ""
|
||||
|
||||
Keys.onEnterPressed: this.clicked()
|
||||
Keys.onReturnPressed: this.clicked()
|
||||
|
||||
onClicked: {
|
||||
ServersModel.processedIndex = ServersModel.defaultIndex
|
||||
|
||||
|
||||
@@ -16,383 +16,397 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listview
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: saveButton.top
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
width: parent.width
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
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()
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
}
|
||||
}
|
||||
|
||||
model: AwgConfigModel
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
property alias mtuTextField: mtuTextField
|
||||
property bool isSaveButtonEnabled: mtuTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === ""
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
spacing: 0
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
TextFieldWithHeaderType {
|
||||
id: mtuTextField
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
spacing: 0
|
||||
headerText: qsTr("MTU")
|
||||
textField.text: clientMtu
|
||||
textField.validator: IntValidator { bottom: 576; top: 65535 }
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("AmneziaWG 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: junkPacketCountTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketCountTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jc - Junk packet count"
|
||||
textField.text: clientJunkPacketCount
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientJunkPacketCount) {
|
||||
clientJunkPacketCount = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMinSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMinSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jmin - Junk packet minimum size"
|
||||
textField.text: clientJunkPacketMinSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientJunkPacketMinSize) {
|
||||
clientJunkPacketMinSize = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
KeyNavigation.tab: junkPacketMaxSizeTextField.textField
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMaxSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: "Jmax - Junk packet maximum size"
|
||||
textField.text: clientJunkPacketMaxSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientJunkPacketMaxSize) {
|
||||
clientJunkPacketMaxSize = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: specialJunk1TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("I1 - First special junk packet")
|
||||
textField.text: clientSpecialJunk1
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk1) {
|
||||
clientSpecialJunk1 = textField.text
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientMtu) {
|
||||
clientMtu = textField.text
|
||||
}
|
||||
}
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: specialJunk2TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: junkPacketCountTextField
|
||||
|
||||
headerText: qsTr("I2 - Second special junk packet")
|
||||
textField.text: clientSpecialJunk2
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk2) {
|
||||
clientSpecialJunk2 = textField.text
|
||||
}
|
||||
headerText: "Jc - Junk packet count"
|
||||
textField.text: clientJunkPacketCount
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientJunkPacketCount) {
|
||||
clientJunkPacketCount = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: specialJunk3TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: junkPacketMinSizeTextField
|
||||
|
||||
headerText: qsTr("I3 - Third special junk packet")
|
||||
textField.text: clientSpecialJunk3
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk3) {
|
||||
clientSpecialJunk3 = textField.text
|
||||
}
|
||||
headerText: "Jmin - Junk packet minimum size"
|
||||
textField.text: clientJunkPacketMinSize
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientJunkPacketMinSize) {
|
||||
clientJunkPacketMinSize = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: specialJunk4TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: junkPacketMaxSizeTextField
|
||||
|
||||
headerText: qsTr("I4 - Fourth special junk packet")
|
||||
textField.text: clientSpecialJunk4
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk4) {
|
||||
clientSpecialJunk4 = textField.text
|
||||
}
|
||||
headerText: "Jmax - Junk packet maximum size"
|
||||
textField.text: clientJunkPacketMaxSize
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientJunkPacketMaxSize) {
|
||||
clientJunkPacketMaxSize = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: specialJunk5TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: specialJunk1TextField
|
||||
|
||||
headerText: qsTr("I5 - Fifth special junk packet")
|
||||
textField.text: clientSpecialJunk5
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk5 ) {
|
||||
clientSpecialJunk5 = textField.text
|
||||
}
|
||||
headerText: qsTr("I1 - First special junk packet")
|
||||
textField.text: clientSpecialJunk1
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk1) {
|
||||
clientSpecialJunk1 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: controlledJunk1TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: specialJunk2TextField
|
||||
|
||||
headerText: qsTr("J1 - First controlled junk packet")
|
||||
textField.text: clientControlledJunk1
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientControlledJunk1) {
|
||||
clientControlledJunk1 = textField.text
|
||||
}
|
||||
headerText: qsTr("I2 - Second special junk packet")
|
||||
textField.text: clientSpecialJunk2
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk2) {
|
||||
clientSpecialJunk2 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: controlledJunk2TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: specialJunk3TextField
|
||||
|
||||
headerText: qsTr("J2 - Second controlled junk packet")
|
||||
textField.text: clientControlledJunk2
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientControlledJunk2) {
|
||||
clientControlledJunk2 = textField.text
|
||||
}
|
||||
headerText: qsTr("I3 - Third special junk packet")
|
||||
textField.text: clientSpecialJunk3
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk3) {
|
||||
clientSpecialJunk3 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: controlledJunk3TextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: specialJunk4TextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("J3 - Third controlled junk packet")
|
||||
textField.text: clientControlledJunk3
|
||||
headerText: qsTr("I4 - Fourth special junk packet")
|
||||
textField.text: clientSpecialJunk4
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientControlledJunk3) {
|
||||
clientControlledJunk3 = textField.text
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk4) {
|
||||
clientSpecialJunk4 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: iTimeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: specialJunk5TextField
|
||||
|
||||
headerText: qsTr("Itime - Special handshake timeout")
|
||||
textField.text: clientSpecialHandshakeTimeout
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialHandshakeTimeout) {
|
||||
clientSpecialHandshakeTimeout = textField.text
|
||||
}
|
||||
headerText: qsTr("I5 - Fifth special junk packet")
|
||||
textField.text: clientSpecialJunk5
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialJunk5 ) {
|
||||
clientSpecialJunk5 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Header2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: controlledJunk1TextField
|
||||
|
||||
text: qsTr("Server settings")
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("J1 - First controlled junk packet")
|
||||
textField.text: clientControlledJunk1
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientControlledJunk1) {
|
||||
clientControlledJunk1 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
AwgTextField {
|
||||
id: controlledJunk2TextField
|
||||
|
||||
enabled: false
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
headerText: qsTr("J2 - Second controlled junk packet")
|
||||
textField.text: clientControlledJunk2
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientControlledJunk2) {
|
||||
clientControlledJunk2 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: controlledJunk3TextField
|
||||
|
||||
enabled: false
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: "S1 - Init packet junk size"
|
||||
textField.text: serverInitPacketJunkSize
|
||||
headerText: qsTr("J3 - Third controlled junk packet")
|
||||
textField.text: clientControlledJunk3
|
||||
textField.validator: null
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientControlledJunk3) {
|
||||
clientControlledJunk3 = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: iTimeTextField
|
||||
|
||||
enabled: false
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: "S2 - Response packet junk size"
|
||||
textField.text: serverResponsePacketJunkSize
|
||||
headerText: qsTr("Itime - Special handshake timeout")
|
||||
textField.text: clientSpecialHandshakeTimeout
|
||||
checkEmptyText: false
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== clientSpecialHandshakeTimeout) {
|
||||
clientSpecialHandshakeTimeout = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Header2TextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
text: qsTr("Server settings")
|
||||
}
|
||||
|
||||
headerText: "H1 - Init packet magic header"
|
||||
textField.text: serverInitPacketMagicHeader
|
||||
}
|
||||
AwgTextField {
|
||||
id: portTextField
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
enabled: false
|
||||
|
||||
headerText: "H2 - Response packet magic header"
|
||||
textField.text: serverResponsePacketMagicHeader
|
||||
}
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
AwgTextField {
|
||||
id: initPacketJunkSizeTextField
|
||||
|
||||
enabled: false
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: "H3 - Underload packet magic header"
|
||||
textField.text: serverUnderloadPacketMagicHeader
|
||||
}
|
||||
enabled: false
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
headerText: "S1 - Init packet junk size"
|
||||
textField.text: serverInitPacketJunkSize
|
||||
}
|
||||
|
||||
enabled: false
|
||||
AwgTextField {
|
||||
id: responsePacketJunkSizeTextField
|
||||
|
||||
headerText: "H4 - Transport packet magic header"
|
||||
textField.text: serverTransportPacketMagicHeader
|
||||
}
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "S2 - Response packet junk size"
|
||||
textField.text: serverResponsePacketJunkSize
|
||||
}
|
||||
|
||||
// AwgTextField {
|
||||
// id: cookieReplyPacketJunkSizeTextField
|
||||
|
||||
// Layout.leftMargin: 16
|
||||
// Layout.rightMargin: 16
|
||||
|
||||
// enabled: false
|
||||
|
||||
// headerText: "S3 - Cookie Reply packet junk size"
|
||||
// textField.text: serverCookieReplyPacketJunkSize
|
||||
// }
|
||||
|
||||
// AwgTextField {
|
||||
// id: transportPacketJunkSizeTextField
|
||||
|
||||
// Layout.leftMargin: 16
|
||||
// Layout.rightMargin: 16
|
||||
|
||||
// enabled: false
|
||||
|
||||
// headerText: "S4 - Transport packet junk size"
|
||||
// textField.text: serverTransportPacketJunkSize
|
||||
// }
|
||||
|
||||
AwgTextField {
|
||||
id: initPacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H1 - Init packet magic header"
|
||||
textField.text: serverInitPacketMagicHeader
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H2 - Response packet magic header"
|
||||
textField.text: serverResponsePacketMagicHeader
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H3 - Underload packet magic header"
|
||||
textField.text: serverUnderloadPacketMagicHeader
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: false
|
||||
|
||||
headerText: "H4 - Transport packet magic header"
|
||||
textField.text: serverTransportPacketMagicHeader
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,18 +423,17 @@ PageType {
|
||||
anchors.rightMargin: 16
|
||||
anchors.leftMargin: 16
|
||||
|
||||
enabled: listview.currentItem.isSaveButtonEnabled
|
||||
enabled: listView.currentItem.isSaveButtonEnabled
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
listView.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
var headerText = qsTr("Save settings?")
|
||||
var descriptionText = qsTr("Only the settings for this device will be changed")
|
||||
var yesButtonText = qsTr("Continue")
|
||||
@@ -435,11 +448,9 @@ PageType {
|
||||
PageController.goToPage(PageEnum.PageSetupWizardInstalling);
|
||||
InstallController.updateContainer(AwgConfigModel.getConfig())
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
saveButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
var noButtonFunction = function() {}
|
||||
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,380 +19,343 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: listview
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
property bool isFocusable: true
|
||||
|
||||
anchors.top: backButtonLayout.bottom
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
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
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
model: AwgConfigModel
|
||||
|
||||
delegate: Item {
|
||||
delegate: ColumnLayout {
|
||||
id: delegateItem
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
|
||||
width: listView.width
|
||||
|
||||
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||
property bool isEnabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
spacing: 0
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
headerText: qsTr("AmneziaWG settings")
|
||||
}
|
||||
|
||||
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 {
|
||||
id: vpnAddressSubnetTextField
|
||||
headerText: qsTr("VPN address subnet")
|
||||
textField.text: subnetAddress
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketCountTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 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
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMinSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 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
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: junkPacketMaxSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 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
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("S1 - Init packet junk size")
|
||||
textField.text: serverInitPacketJunkSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverInitPacketJunkSize) {
|
||||
serverInitPacketJunkSize = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== subnetAddress) {
|
||||
subnetAddress = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketJunkSizeTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
headerText: qsTr("S2 - Response packet junk size")
|
||||
textField.text: serverResponsePacketJunkSize
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverResponsePacketJunkSize) {
|
||||
serverResponsePacketJunkSize = textField.text
|
||||
}
|
||||
}
|
||||
enabled: delegateItem.isEnabled
|
||||
|
||||
checkEmptyText: true
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== port) {
|
||||
port = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: initPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
headerText: qsTr("H1 - Init packet magic header")
|
||||
textField.text: serverInitPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
AwgTextField {
|
||||
id: junkPacketCountTextField
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverInitPacketMagicHeader) {
|
||||
serverInitPacketMagicHeader = textField.text
|
||||
}
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Jc - Junk packet count")
|
||||
textField.text: serverJunkPacketCount
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverJunkPacketCount) {
|
||||
serverJunkPacketCount = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
AwgTextField {
|
||||
id: junkPacketMinSizeTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Jmin - Junk packet minimum size")
|
||||
textField.text: serverJunkPacketMinSize
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverJunkPacketMinSize) {
|
||||
serverJunkPacketMinSize = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: junkPacketMaxSizeTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("Jmax - Junk packet maximum size")
|
||||
textField.text: serverJunkPacketMaxSize
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverJunkPacketMaxSize) {
|
||||
serverJunkPacketMaxSize = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: initPacketJunkSizeTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("S1 - Init packet junk size")
|
||||
textField.text: serverInitPacketJunkSize
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverInitPacketJunkSize) {
|
||||
serverInitPacketJunkSize = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: responsePacketJunkSizeTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("S2 - Response packet junk size")
|
||||
textField.text: serverResponsePacketJunkSize
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverResponsePacketJunkSize) {
|
||||
serverResponsePacketJunkSize = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AwgTextField {
|
||||
// id: cookieReplyPacketJunkSizeTextField
|
||||
|
||||
// Layout.leftMargin: 16
|
||||
// Layout.rightMargin: 16
|
||||
|
||||
// headerText: qsTr("S3 - Cookie reply packet junk size")
|
||||
// textField.text: serverCookieReplyPacketJunkSize
|
||||
|
||||
// textField.onEditingFinished: {
|
||||
// if (textField.text !== serverCookieReplyPacketJunkSize) {
|
||||
// serverCookieReplyPacketJunkSize = textField.text
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// AwgTextField {
|
||||
// id: transportPacketJunkSizeTextField
|
||||
|
||||
// Layout.leftMargin: 16
|
||||
// Layout.rightMargin: 16
|
||||
|
||||
// headerText: qsTr("S4 - Transport packet junk size")
|
||||
// textField.text: serverTransportPacketJunkSize
|
||||
|
||||
// textField.onEditingFinished: {
|
||||
// if (textField.text !== serverTransportPacketJunkSize) {
|
||||
// serverTransportPacketJunkSize = textField.text
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
AwgTextField {
|
||||
id: initPacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("H1 - Init packet magic header")
|
||||
textField.text: serverInitPacketMagicHeader
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverInitPacketMagicHeader) {
|
||||
serverInitPacketMagicHeader = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("H2 - Response packet magic header")
|
||||
textField.text: serverResponsePacketMagicHeader
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverResponsePacketMagicHeader) {
|
||||
serverResponsePacketMagicHeader = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("H3 - Underload packet magic header")
|
||||
textField.text: serverUnderloadPacketMagicHeader
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverUnderloadPacketMagicHeader) {
|
||||
serverUnderloadPacketMagicHeader = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AwgTextField {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("H4 - Transport packet magic header")
|
||||
textField.text: serverTransportPacketMagicHeader
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverTransportPacketMagicHeader) {
|
||||
serverTransportPacketMagicHeader = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 === "" &&
|
||||
// cookieReplyHeaderJunkTextField.errorText === "" &&
|
||||
// transportHeaderJunkTextField.errorText === "" &&
|
||||
initPacketJunkSizeTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === "" &&
|
||||
portTextField.errorText === "" &&
|
||||
vpnAddressSubnetTextField.errorText === ""
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listView.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: responsePacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 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
|
||||
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
|
||||
}
|
||||
// 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
|
||||
// }
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
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")
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: underloadPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 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
|
||||
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())
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
var noButtonFunction = function() {}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: transportPacketMagicHeaderTextField
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
headerText: qsTr("H4 - Transport packet magic header")
|
||||
textField.text: serverTransportPacketMagicHeader
|
||||
textField.validator: IntValidator { bottom: 0 }
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== serverTransportPacketMagicHeader) {
|
||||
serverTransportPacketMagicHeader = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
|
||||
BasicButtonType {
|
||||
id: saveRestartButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
enabled: underloadPacketMagicHeaderTextField.errorText === "" &&
|
||||
transportPacketMagicHeaderTextField.errorText === "" &&
|
||||
responsePacketMagicHeaderTextField.errorText === "" &&
|
||||
initPacketMagicHeaderTextField.errorText === "" &&
|
||||
responsePacketJunkSizeTextField.errorText === "" &&
|
||||
initPacketJunkSizeTextField.errorText === "" &&
|
||||
junkPacketMaxSizeTextField.errorText === "" &&
|
||||
junkPacketMinSizeTextField.errorText === "" &&
|
||||
junkPacketCountTextField.errorText === "" &&
|
||||
// specialJunk1TextField.errorText === "" &&
|
||||
// specialJunk2TextField.errorText === "" &&
|
||||
// specialJunk3TextField.errorText === "" &&
|
||||
// specialJunk4TextField.errorText === "" &&
|
||||
// specialJunk5TextField.errorText === "" &&
|
||||
// controlledJunk1TextField.errorText === "" &&
|
||||
// controlledJunk2TextField.errorText === "" &&
|
||||
// controlledJunk3TextField.errorText === "" &&
|
||||
// iTimeTextField.errorText === "" &&
|
||||
portTextField.errorText === "" &&
|
||||
vpnAddressSubnetTextField.errorText === ""
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus) {
|
||||
listview.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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(AwgConfigModel.getConfig())
|
||||
}
|
||||
var noButtonFunction = function() {
|
||||
if (!GC.isMobile()) {
|
||||
saveRestartButton.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
showQuestionDrawer(headerText, descriptionText, yesButtonText, noButtonText, yesButtonFunction, noButtonFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,179 +16,192 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButtonLayout.bottom
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
Column {
|
||||
id: content
|
||||
property int selectedIndex: 0
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
ListView {
|
||||
id: listview
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
property int selectedIndex: 0
|
||||
headerText: qsTr("Cloak settings")
|
||||
}
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
height: listview.contentItem.height
|
||||
model: CloakConfigModel
|
||||
|
||||
clip: true
|
||||
reuseItems: true
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
model: CloakConfigModel
|
||||
property alias trafficFromField: trafficFromField
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
spacing: 0
|
||||
|
||||
property alias trafficFromField: trafficFromField
|
||||
TextFieldWithHeaderType {
|
||||
id: trafficFromField
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
headerText: qsTr("Disguised as traffic from")
|
||||
textField.text: site
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== site) {
|
||||
var tmpText = textField.text
|
||||
tmpText = tmpText.toLocaleLowerCase()
|
||||
|
||||
spacing: 0
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
|
||||
headerText: qsTr("Cloak settings")
|
||||
var indexHttps = tmpText.indexOf("https://")
|
||||
if (indexHttps === 0) {
|
||||
tmpText = textField.text.substring(8)
|
||||
} else {
|
||||
site = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: trafficFromField
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
|
||||
headerText: qsTr("Disguised as traffic from")
|
||||
textField.text: site
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== site) {
|
||||
var tmpText = textField.text
|
||||
tmpText = tmpText.toLocaleLowerCase()
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
var indexHttps = tmpText.indexOf("https://")
|
||||
if (indexHttps === 0) {
|
||||
tmpText = textField.text.substring(8)
|
||||
} else {
|
||||
site = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== port) {
|
||||
port = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
DropDownType {
|
||||
id: cipherDropDown
|
||||
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== port) {
|
||||
port = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
descriptionText: qsTr("Cipher")
|
||||
headerText: qsTr("Cipher")
|
||||
|
||||
DropDownType {
|
||||
id: cipherDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
drawerParent: root
|
||||
|
||||
descriptionText: qsTr("Cipher")
|
||||
headerText: qsTr("Cipher")
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
|
||||
drawerParent: root
|
||||
rootWidth: root.width
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
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" }
|
||||
}
|
||||
|
||||
rootWidth: root.width
|
||||
clickedFunction: function() {
|
||||
cipherDropDown.text = selectedText
|
||||
cipher = cipherDropDown.text
|
||||
cipherDropDown.closeTriggered()
|
||||
}
|
||||
|
||||
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" }
|
||||
}
|
||||
Component.onCompleted: {
|
||||
cipherDropDown.text = cipher
|
||||
|
||||
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
|
||||
|
||||
text: qsTr("Save")
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
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())
|
||||
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
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,401 +17,414 @@ import "../Components"
|
||||
PageType {
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
id: backButtonLayout
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
|
||||
BackButtonType {
|
||||
id: backButton
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(backButton.enabled && backButton.activeFocus) {
|
||||
listView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FlickableType {
|
||||
id: fl
|
||||
anchors.top: backButtonLayout.bottom
|
||||
ListViewType {
|
||||
id: listView
|
||||
|
||||
anchors.top: backButton.bottom
|
||||
anchors.bottom: parent.bottom
|
||||
contentHeight: content.implicitHeight
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
|
||||
Column {
|
||||
id: content
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
header: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
enabled: ServersModel.isProcessedServerHasWriteAccess()
|
||||
BaseHeaderType {
|
||||
id: header
|
||||
|
||||
ListView {
|
||||
id: listview
|
||||
Layout.fillWidth: true
|
||||
Layout.rightMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
|
||||
width: parent.width
|
||||
height: listview.contentItem.height
|
||||
headerText: qsTr("OpenVPN Settings")
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
interactive: false
|
||||
model: OpenVpnConfigModel
|
||||
|
||||
model: OpenVpnConfigModel
|
||||
delegate: ColumnLayout {
|
||||
width: listView.width
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: listview.width
|
||||
implicitHeight: col.implicitHeight
|
||||
spacing: 0
|
||||
|
||||
property alias vpnAddressSubnetTextField: vpnAddressSubnetTextField
|
||||
TextFieldWithHeaderType {
|
||||
id: vpnAddressSubnetTextField
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
enabled: listView.enabled
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
headerText: qsTr("VPN address subnet")
|
||||
textField.text: subnetAddress
|
||||
|
||||
spacing: 0
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== subnetAddress) {
|
||||
subnetAddress = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
BaseHeaderType {
|
||||
Layout.fillWidth: true
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
headerText: qsTr("OpenVPN settings")
|
||||
}
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: vpnAddressSubnetTextField
|
||||
text: qsTr("Network protocol")
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
TransportProtoSelector {
|
||||
id: transportProtoSelector
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
headerText: qsTr("VPN address subnet")
|
||||
textField.text: subnetAddress
|
||||
rootWidth: root.width
|
||||
|
||||
parentFlickable: fl
|
||||
enabled: isTransportProtoEditable
|
||||
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== subnetAddress) {
|
||||
subnetAddress = textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
currentIndex: {
|
||||
return transportProto === "tcp" ? 1 : 0
|
||||
}
|
||||
|
||||
ParagraphTextType {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
onCurrentIndexChanged: {
|
||||
if (transportProto === "tcp" && currentIndex === 0) {
|
||||
transportProto = "udp"
|
||||
} else if (transportProto === "udp" && currentIndex === 1) {
|
||||
transportProto = "tcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text: qsTr("Network protocol")
|
||||
}
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
|
||||
TransportProtoSelector {
|
||||
id: transportProtoSelector
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
rootWidth: root.width
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: isTransportProtoEditable
|
||||
enabled: listView.enabled
|
||||
|
||||
currentIndex: {
|
||||
return transportProto === "tcp" ? 1 : 0
|
||||
}
|
||||
headerText: qsTr("Port")
|
||||
textField.text: port
|
||||
textField.maximumLength: 5
|
||||
textField.validator: IntValidator { bottom: 1; top: 65535 }
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (transportProto === "tcp" && currentIndex === 0) {
|
||||
transportProto = "udp"
|
||||
} else if (transportProto === "udp" && currentIndex === 1) {
|
||||
transportProto = "tcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
textField.onEditingFinished: {
|
||||
if (textField.text !== port) {
|
||||
port = textField.text
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWithHeaderType {
|
||||
id: portTextField
|
||||
checkEmptyText: true
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 40
|
||||
parentFlickable: fl
|
||||
|
||||
enabled: isPortEditable
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: autoNegotiateEncryprionSwitcher
|
||||
|
||||
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 {
|
||||
id: cipherDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||
|
||||
descriptionText: qsTr("Cipher")
|
||||
headerText: qsTr("Cipher")
|
||||
|
||||
drawerParent: root
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
|
||||
rootWidth: root.width
|
||||
|
||||
model: ListModel {
|
||||
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() {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contentRect
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.preferredHeight: checkboxLayout.implicitHeight
|
||||
color: AmneziaStyle.color.onyxBlack
|
||||
radius: 16
|
||||
|
||||
Connections {
|
||||
target: tlsAuthCheckBox
|
||||
enabled: !GC.isMobile()
|
||||
|
||||
function onFocusChanged() {
|
||||
if (tlsAuthCheckBox.activeFocus) {
|
||||
fl.ensureVisible(contentRect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: checkboxLayout
|
||||
|
||||
anchors.fill: parent
|
||||
CheckBoxType {
|
||||
id: tlsAuthCheckBox
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("TLS auth")
|
||||
checked: tlsAuth
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== tlsAuth) {
|
||||
console.log("tlsAuth changed to: " + checked)
|
||||
tlsAuth = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
CheckBoxType {
|
||||
id: blockDnsCheckBox
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Block DNS requests outside of VPN")
|
||||
checked: blockDns
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== blockDns) {
|
||||
blockDns = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalClientCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
parentFlickable: fl
|
||||
|
||||
checked: additionalClientCommands !== ""
|
||||
|
||||
text: qsTr("Additional client configuration commands")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!checked) {
|
||||
additionalClientCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaType {
|
||||
id: additionalClientCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
visible: additionalClientCommandsSwitcher.checked
|
||||
|
||||
parentFlickable: fl
|
||||
|
||||
textAreaText: additionalClientCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalClientCommands !== textAreaText) {
|
||||
additionalClientCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalServerCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
parentFlickable: fl
|
||||
|
||||
checked: additionalServerCommands !== ""
|
||||
|
||||
text: qsTr("Additional server configuration commands")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!checked) {
|
||||
additionalServerCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: saveRestartButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
|
||||
text: qsTr("Save")
|
||||
parentFlickable: fl
|
||||
|
||||
clickedFunc: function() {
|
||||
forceActiveFocus()
|
||||
|
||||
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())
|
||||
SwitcherType {
|
||||
id: autoNegotiateEncryprionSwitcher
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
text: qsTr("Auto-negotiate encryption")
|
||||
checked: autoNegotiateEncryprion
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== autoNegotiateEncryprion) {
|
||||
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
|
||||
|
||||
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 {
|
||||
id: cipherDropDown
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: !autoNegotiateEncryprionSwitcher.checked
|
||||
|
||||
descriptionText: qsTr("Cipher")
|
||||
headerText: qsTr("Cipher")
|
||||
|
||||
drawerParent: root
|
||||
|
||||
listView: ListViewWithRadioButtonType {
|
||||
id: cipherListView
|
||||
|
||||
rootWidth: root.width
|
||||
|
||||
model: ListModel {
|
||||
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() {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contentRect
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
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: tlsAuth
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== tlsAuth) {
|
||||
console.log("tlsAuth changed to: " + checked)
|
||||
tlsAuth = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DividerType {}
|
||||
|
||||
CheckBoxType {
|
||||
id: blockDnsCheckBox
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Block DNS requests outside of VPN")
|
||||
checked: blockDns
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked !== blockDns) {
|
||||
blockDns = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalClientCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
checked: additionalClientCommands !== ""
|
||||
|
||||
text: qsTr("Additional client configuration commands")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!checked) {
|
||||
additionalClientCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaType {
|
||||
id: additionalClientCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: additionalClientCommandsSwitcher.checked
|
||||
|
||||
textAreaText: additionalClientCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalClientCommands !== textAreaText) {
|
||||
additionalClientCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitcherType {
|
||||
id: additionalServerCommandsSwitcher
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
checked: additionalServerCommands !== ""
|
||||
|
||||
text: qsTr("Additional server configuration commands")
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!checked) {
|
||||
additionalServerCommands = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextAreaType {
|
||||
id: additionalServerCommandsTextArea
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
visible: additionalServerCommandsSwitcher.checked
|
||||
|
||||
textAreaText: additionalServerCommands
|
||||
placeholderText: qsTr("Commands:")
|
||||
|
||||
textArea.onEditingFinished: {
|
||||
if (additionalServerCommands !== textAreaText) {
|
||||
additionalServerCommands = textAreaText
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BasicButtonType {
|
||||
id: saveButton
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 24
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
enabled: vpnAddressSubnetTextField.errorText === "" &&
|
||||
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(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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user