mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-23 02:00:20 +07:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 60975c9596 | |||
| db4a1a62e5 | |||
| 581773ce03 | |||
| 46058f614e | |||
| 9cab51fb00 | |||
| 918be16372 | |||
| 175477d31f | |||
| cd70b7e619 | |||
| 22011e263e | |||
| 88a2b9a07a | |||
| 248f487d4e | |||
| 572ef09296 | |||
| 03078236ab | |||
| b39a0a1d94 | |||
| e94fc688ba | |||
| 558f613acc | |||
| d800a95a1d | |||
| b8f100d4fa | |||
| 51618fb882 | |||
| 14f537ba76 | |||
| 3458ed78d7 | |||
| 4bc571f609 | |||
| ee61f842e5 | |||
| 758b25947c | |||
| b036c38981 | |||
| eab2b8e45a | |||
| dfdec2bf4b |
@@ -297,24 +297,24 @@ jobs:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
ANDROID_BUILD_PLATFORM: android-34
|
ANDROID_BUILD_PLATFORM: android-34
|
||||||
QT_VERSION: 6.6.2
|
QT_VERSION: 6.7.2
|
||||||
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
|
||||||
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 'Install desktop Qt'
|
- name: 'Install desktop Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{ env.QT_VERSION }}
|
version: ${{ env.QT_VERSION }}
|
||||||
host: 'linux'
|
host: 'linux'
|
||||||
target: 'desktop'
|
target: 'desktop'
|
||||||
arch: 'gcc_64'
|
arch: 'linux_gcc_64'
|
||||||
modules: ${{ env.QT_MODULES }}
|
modules: ${{ env.QT_MODULES }}
|
||||||
dir: ${{ runner.temp }}
|
dir: ${{ runner.temp }}
|
||||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||||
|
|
||||||
- name: 'Install android_x86_64 Qt'
|
- name: 'Install android_x86_64 Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{ env.QT_VERSION }}
|
version: ${{ env.QT_VERSION }}
|
||||||
host: 'linux'
|
host: 'linux'
|
||||||
@@ -325,7 +325,7 @@ jobs:
|
|||||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||||
|
|
||||||
- name: 'Install android_x86 Qt'
|
- name: 'Install android_x86 Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{ env.QT_VERSION }}
|
version: ${{ env.QT_VERSION }}
|
||||||
host: 'linux'
|
host: 'linux'
|
||||||
@@ -336,7 +336,7 @@ jobs:
|
|||||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||||
|
|
||||||
- name: 'Install android_armv7 Qt'
|
- name: 'Install android_armv7 Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{ env.QT_VERSION }}
|
version: ${{ env.QT_VERSION }}
|
||||||
host: 'linux'
|
host: 'linux'
|
||||||
@@ -347,7 +347,7 @@ jobs:
|
|||||||
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
extra: '--external 7z --base ${{ env.QT_MIRROR }}'
|
||||||
|
|
||||||
- name: 'Install android_arm64_v8a Qt'
|
- name: 'Install android_arm64_v8a Qt'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: ${{ env.QT_VERSION }}
|
version: ${{ env.QT_VERSION }}
|
||||||
host: 'linux'
|
host: 'linux'
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
|||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 4.7.0.0
|
project(${PROJECT} VERSION 4.8.0.0
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
|||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 57)
|
set(APP_ANDROID_VERSION_CODE 58)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.6.0.3/AmneziaVPN_4.6.0.3_x64.exe"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/win.png" width="150" style="max-width: 100%;"></a>
|
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.7.0.0/AmneziaVPN_4.7.0.0_x64.exe"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/win.png" width="150" style="max-width: 100%;"></a>
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.6.0.3/AmneziaVPN_4.6.0.3.dmg"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/mac.png" width="150" style="max-width: 100%;"></a>
|
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.7.0.0/AmneziaVPN_4.7.0.0.dmg"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/mac.png" width="150" style="max-width: 100%;"></a>
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.6.0.3/AmneziaVPN_Linux_4.6.0.3.tar.zip"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/lin.png" width="150" style="max-width: 100%;"></a>
|
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/download/4.7.0.0/AmneziaVPN_Linux_4.7.0.0.tar.zip"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/lin.png" width="150" style="max-width: 100%;"></a>
|
||||||
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/tag/4.6.0.3"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/andr.png" width="150" style="max-width: 100%;"></a>
|
<a href="https://github.com/amnezia-vpn/amnezia-client/releases/tag/4.7.0.0"><img src="https://github.com/amnezia-vpn/amnezia-client/blob/dev/metadata/img-readme/andr.png" width="150" style="max-width: 100%;"></a>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@@ -28,11 +28,12 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Very easy to use - enter your IP address, SSH login, and password, and Amnezia will automatically install VPN docker containers to your server and connect to the VPN.
|
- Very easy to use - enter your IP address, SSH login, password and Amnezia will automatically install VPN docker containers to your server and connect to the VPN.
|
||||||
- OpenVPN, Shadowsocks, WireGuard, and IKEv2 protocols support.
|
- Classic VPN-protocols: OpenVPN, WireGuard and IKEv2 protocols.
|
||||||
- Masking VPN with OpenVPN over Cloak plugin
|
- Protocols with traffic Masking (Obfuscation): OpenVPN over [Cloak](https://github.com/cbeuw/Cloak) plugin, Shadowsocks (OpenVPN over Shadowsocks), [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) and XRay.
|
||||||
- Split tunneling support - add any sites to the client to enable VPN only for them (only for desktops)
|
- Split tunneling support - add any sites to the client to enable VPN only for them or add Apps (only for Android and Desktop).
|
||||||
- Windows, MacOS, Linux, Android, iOS releases.
|
- Windows, MacOS, Linux, Android, iOS releases.
|
||||||
|
- Support for AmneziaWG protocol configuration on [Keenetic beta firmware](https://docs.keenetic.com/ua/air/kn-1611/en/6319-latest-development-release.html#UUID-186c4108-5afd-c10b-f38a-cdff6c17fab3_section-idm33192196168192-improved).
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
|
|||||||
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
|
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
|
||||||
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Telegram support channel (Myanmar)
|
- [https://t.me/amnezia_vpn_mm](https://t.me/amnezia_vpn_mm) - Telegram support channel (Myanmar)
|
||||||
- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Telegram support channel (Russian)
|
- [https://t.me/amnezia_vpn](https://t.me/amnezia_vpn) - Telegram support channel (Russian)
|
||||||
|
- [https://vpnpay.io/en/amnezia-premium/](https://vpnpay.io/en/amnezia-premium/) - Amnezia Premium
|
||||||
|
|
||||||
## Tech
|
## Tech
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
Submodule client/3rd/qtkeychain updated: 74776e2a3e...7460df6a97
@@ -27,6 +27,9 @@ add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
|
|||||||
add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}")
|
add_definitions(-DPROD_AGW_PUBLIC_KEY="$ENV{PROD_AGW_PUBLIC_KEY}")
|
||||||
add_definitions(-DPROD_PROXY_STORAGE_KEY="$ENV{PROD_PROXY_STORAGE_KEY}")
|
add_definitions(-DPROD_PROXY_STORAGE_KEY="$ENV{PROD_PROXY_STORAGE_KEY}")
|
||||||
|
|
||||||
|
add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
|
||||||
|
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
set(PACKAGES ${PACKAGES} Multimedia)
|
set(PACKAGES ${PACKAGES} Multimedia)
|
||||||
endif()
|
endif()
|
||||||
@@ -110,6 +113,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/cmake/3rdparty.cmake)
|
|||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../ipc
|
${CMAKE_CURRENT_LIST_DIR}/../ipc
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../common/logger
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
@@ -131,7 +135,6 @@ set(HEADERS ${HEADERS}
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/protocols_defs.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/qml_register_protocols.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
|
${CMAKE_CURRENT_LIST_DIR}/ui/pages.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/property_helper.h
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
|
${CMAKE_CURRENT_LIST_DIR}/ui/qautostart.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
|
${CMAKE_CURRENT_LIST_DIR}/protocols/vpnprotocol.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/version.h
|
${CMAKE_CURRENT_BINARY_DIR}/version.h
|
||||||
@@ -140,6 +143,7 @@ set(HEADERS ${HEADERS}
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/core/serialization/serialization.h
|
${CMAKE_CURRENT_LIST_DIR}/core/serialization/serialization.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
|
${CMAKE_CURRENT_LIST_DIR}/core/serialization/transfer.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
|
${CMAKE_CURRENT_LIST_DIR}/core/enums/apiEnums.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mozilla headres
|
# Mozilla headres
|
||||||
@@ -190,6 +194,7 @@ set(SOURCES ${SOURCES}
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/core/serialization/trojan.cpp
|
${CMAKE_CURRENT_LIST_DIR}/core/serialization/trojan.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
|
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
|
${CMAKE_CURRENT_LIST_DIR}/core/serialization/vmess_new.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../common/logger/logger.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mozilla sources
|
# Mozilla sources
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ void AmneziaApplication::init()
|
|||||||
bool enabled = m_settings->isSaveLogs();
|
bool enabled = m_settings->isSaveLogs();
|
||||||
#ifndef Q_OS_ANDROID
|
#ifndef Q_OS_ANDROID
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (!Logger::init()) {
|
if (!Logger::init(false)) {
|
||||||
qWarning() << "Initialization of debug subsystem failed";
|
qWarning() << "Initialization of debug subsystem failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
<manifest
|
<manifest
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="org.amnezia.vpn"
|
|
||||||
android:versionName="-- %%INSERT_VERSION_NAME%% --"
|
android:versionName="-- %%INSERT_VERSION_NAME%% --"
|
||||||
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
|
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
@@ -46,7 +45,7 @@
|
|||||||
android:configChanges="uiMode|screenSize|smallestScreenSize|screenLayout|orientation|density
|
android:configChanges="uiMode|screenSize|smallestScreenSize|screenLayout|orientation|density
|
||||||
|fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc"
|
|fontScale|layoutDirection|locale|keyboard|keyboardHidden|navigation|mcc|mnc"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="stateUnchanged|adjustResize"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@@ -68,9 +67,6 @@
|
|||||||
android:name="android.app.lib_name"
|
android:name="android.app.lib_name"
|
||||||
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
|
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="android.app.extract_android_style"
|
|
||||||
android:value="minimal" />
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
@@ -88,6 +84,13 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:theme="@style/Translucent" />
|
android:theme="@style/Translucent" />
|
||||||
|
|
||||||
|
<activity android:name=".AuthActivity"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:taskAffinity=""
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/Translucent" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ImportConfigActivity"
|
android:name=".ImportConfigActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
|
|||||||
@@ -3,3 +3,6 @@
|
|||||||
// android.bundle.enableUncompressedNativeLibs is deprecated
|
// android.bundle.enableUncompressedNativeLibs is deprecated
|
||||||
// disable adding gradle property android.bundle.enableUncompressedNativeLibs by androiddeployqt
|
// disable adding gradle property android.bundle.enableUncompressedNativeLibs by androiddeployqt
|
||||||
useLegacyPackaging
|
useLegacyPackaging
|
||||||
|
|
||||||
|
// package name for androiddeployqt
|
||||||
|
namespace = "org.amnezia.vpn"
|
||||||
|
|||||||
@@ -115,9 +115,11 @@ dependencies {
|
|||||||
implementation(project(":xray"))
|
implementation(project(":xray"))
|
||||||
implementation(libs.androidx.core)
|
implementation(libs.androidx.core)
|
||||||
implementation(libs.androidx.activity)
|
implementation(libs.androidx.activity)
|
||||||
|
implementation(libs.androidx.fragment)
|
||||||
implementation(libs.kotlinx.coroutines)
|
implementation(libs.kotlinx.coroutines)
|
||||||
implementation(libs.kotlinx.serialization.protobuf)
|
implementation(libs.kotlinx.serialization.protobuf)
|
||||||
implementation(libs.bundles.androidx.camera)
|
implementation(libs.bundles.androidx.camera)
|
||||||
implementation(libs.google.mlkit)
|
implementation(libs.google.mlkit)
|
||||||
implementation(libs.androidx.datastore)
|
implementation(libs.androidx.datastore)
|
||||||
|
implementation(libs.androidx.biometric)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "8.2.0"
|
agp = "8.5.2"
|
||||||
kotlin = "1.9.20"
|
kotlin = "1.9.24"
|
||||||
androidx-core = "1.12.0"
|
androidx-core = "1.13.1"
|
||||||
androidx-activity = "1.8.1"
|
androidx-activity = "1.9.1"
|
||||||
androidx-annotation = "1.7.0"
|
androidx-annotation = "1.8.2"
|
||||||
androidx-camera = "1.3.0"
|
androidx-biometric = "1.2.0-alpha05"
|
||||||
|
androidx-camera = "1.3.4"
|
||||||
|
androidx-fragment = "1.8.2"
|
||||||
androidx-security-crypto = "1.1.0-alpha06"
|
androidx-security-crypto = "1.1.0-alpha06"
|
||||||
androidx-datastore = "1.1.0-beta01"
|
androidx-datastore = "1.1.1"
|
||||||
kotlinx-coroutines = "1.7.3"
|
kotlinx-coroutines = "1.8.1"
|
||||||
kotlinx-serialization = "1.6.3"
|
kotlinx-serialization = "1.6.3"
|
||||||
google-mlkit = "17.2.0"
|
google-mlkit = "17.3.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
|
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }
|
||||||
androidx-activity = { module = "androidx.activity:activity-ktx", version.ref = "androidx-activity" }
|
androidx-activity = { module = "androidx.activity:activity-ktx", version.ref = "androidx-activity" }
|
||||||
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
|
androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
|
||||||
|
androidx-biometric = { module = "androidx.biometric:biometric-ktx", version.ref = "androidx-biometric" }
|
||||||
androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "androidx-camera" }
|
androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "androidx-camera" }
|
||||||
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-camera" }
|
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-camera" }
|
||||||
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidx-camera" }
|
androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidx-camera" }
|
||||||
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "androidx-camera" }
|
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "androidx-camera" }
|
||||||
|
androidx-fragment = { module = "androidx.fragment:fragment-ktx", version.ref = "androidx-fragment" }
|
||||||
androidx-security-crypto = { module = "androidx.security:security-crypto-ktx", version.ref = "androidx-security-crypto" }
|
androidx-security-crypto = { module = "androidx.security:security-crypto-ktx", version.ref = "androidx-security-crypto" }
|
||||||
androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" }
|
androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" }
|
||||||
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
|
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
|
||||||
|
|||||||
Binary file not shown.
+1
-3
@@ -1,7 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
Vendored
+5
-2
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -84,7 +86,8 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
|||||||
Vendored
+12
-10
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ open class OpenVpn : Protocol() {
|
|||||||
scope = CoroutineScope(Dispatchers.IO)
|
scope = CoroutineScope(Dispatchers.IO)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
val configBuilder = OpenVpnConfig.Builder()
|
val configBuilder = OpenVpnConfig.Builder()
|
||||||
|
|
||||||
openVpnClient = OpenVpnClient(
|
openVpnClient = OpenVpnClient(
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ abstract class Protocol {
|
|||||||
|
|
||||||
protected abstract fun internalInit()
|
protected abstract fun internalInit()
|
||||||
|
|
||||||
abstract fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
|
abstract suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean)
|
||||||
|
|
||||||
abstract fun stopVpn()
|
abstract fun stopVpn()
|
||||||
|
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar"))))
|
api(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar"))))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<color name="black">#FF0E0E11</color>
|
||||||
<style name="NoActionBar">
|
<style name="NoActionBar">
|
||||||
|
<item name="android:windowBackground">@color/black</item>
|
||||||
|
<item name="android:colorBackground">@color/black</item>
|
||||||
<item name="android:windowActionBar">false</item>
|
<item name="android:windowActionBar">false</item>
|
||||||
<item name="android:windowNoTitle">true</item>
|
<item name="android:windowNoTitle">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ dependencyResolutionManagement {
|
|||||||
includeBuild("./gradle/plugins")
|
includeBuild("./gradle/plugins")
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.settings") version "8.2.0"
|
id("com.android.settings") version "8.5.2"
|
||||||
id("settings-property-delegate")
|
id("settings-property-delegate")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ class AmneziaActivity : QtActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.d(TAG, "Create Amnezia activity: $intent")
|
Log.d(TAG, "Create Amnezia activity: $intent")
|
||||||
|
window.apply {
|
||||||
|
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||||
|
statusBarColor = getColor(R.color.black)
|
||||||
|
}
|
||||||
mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||||
val proto = mainScope.async(Dispatchers.IO) {
|
val proto = mainScope.async(Dispatchers.IO) {
|
||||||
VpnStateStore.getVpnState().vpnProto
|
VpnStateStore.getVpnState().vpnProto
|
||||||
@@ -610,6 +614,14 @@ class AmneziaActivity : QtActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
fun setNavigationBarColor(color: Int) {
|
||||||
|
Log.v(TAG, "Change navigation bar color: ${"#%08X".format(color)}")
|
||||||
|
mainScope.launch {
|
||||||
|
window.navigationBarColor = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun minimizeApp() {
|
fun minimizeApp() {
|
||||||
Log.v(TAG, "Minimize application")
|
Log.v(TAG, "Minimize application")
|
||||||
@@ -684,6 +696,17 @@ class AmneziaActivity : QtActivity() {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
fun requestAuthentication() {
|
||||||
|
Log.v(TAG, "Request authentication")
|
||||||
|
mainScope.launch {
|
||||||
|
qtInitialized.await()
|
||||||
|
Intent(this@AmneziaActivity, AuthActivity::class.java).also {
|
||||||
|
startActivity(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utils methods
|
* Utils methods
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
@@ -111,6 +112,10 @@ open class AmneziaVpnService : VpnService() {
|
|||||||
get() = clientMessengers.any { it.value.name == ACTIVITY_MESSENGER_NAME }
|
get() = clientMessengers.any { it.value.name == ACTIVITY_MESSENGER_NAME }
|
||||||
|
|
||||||
private val connectionExceptionHandler = CoroutineExceptionHandler { _, e ->
|
private val connectionExceptionHandler = CoroutineExceptionHandler { _, e ->
|
||||||
|
connectionJob?.cancel()
|
||||||
|
connectionJob = null
|
||||||
|
disconnectionJob?.cancel()
|
||||||
|
disconnectionJob = null
|
||||||
protocolState.value = DISCONNECTED
|
protocolState.value = DISCONNECTED
|
||||||
when (e) {
|
when (e) {
|
||||||
is IllegalArgumentException,
|
is IllegalArgumentException,
|
||||||
@@ -531,7 +536,7 @@ open class AmneziaVpnService : VpnService() {
|
|||||||
protocolState.value = DISCONNECTING
|
protocolState.value = DISCONNECTING
|
||||||
|
|
||||||
disconnectionJob = connectionScope.launch {
|
disconnectionJob = connectionScope.launch {
|
||||||
connectionJob?.join()
|
connectionJob?.cancelAndJoin()
|
||||||
connectionJob = null
|
connectionJob = null
|
||||||
|
|
||||||
vpnProto?.protocol?.stopVpn()
|
vpnProto?.protocol?.stopVpn()
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package org.amnezia.vpn
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.biometric.BiometricManager
|
||||||
|
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||||
|
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||||
|
import androidx.biometric.BiometricPrompt
|
||||||
|
import androidx.biometric.BiometricPrompt.AuthenticationResult
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import org.amnezia.vpn.qt.QtAndroidController
|
||||||
|
import org.amnezia.vpn.util.Log
|
||||||
|
|
||||||
|
private const val TAG = "AuthActivity"
|
||||||
|
|
||||||
|
private const val AUTHENTICATORS = BIOMETRIC_STRONG or DEVICE_CREDENTIAL
|
||||||
|
|
||||||
|
class AuthActivity : FragmentActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val biometricManager = BiometricManager.from(applicationContext)
|
||||||
|
when (biometricManager.canAuthenticate(AUTHENTICATORS)) {
|
||||||
|
BiometricManager.BIOMETRIC_SUCCESS -> {
|
||||||
|
showBiometricPrompt(biometricManager)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> {
|
||||||
|
Log.w(TAG, "Unknown biometric status")
|
||||||
|
showBiometricPrompt(biometricManager)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> {
|
||||||
|
Log.e(TAG, "The specified options are incompatible with the current Android " +
|
||||||
|
"version ${Build.VERSION.SDK_INT}")
|
||||||
|
}
|
||||||
|
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
|
||||||
|
Log.w(TAG, "The hardware is unavailable")
|
||||||
|
}
|
||||||
|
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
|
||||||
|
Log.w(TAG, "No biometric or device credential is enrolled")
|
||||||
|
}
|
||||||
|
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
|
||||||
|
Log.w(TAG, "There is no suitable hardware")
|
||||||
|
}
|
||||||
|
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> {
|
||||||
|
Log.w(TAG, "A security vulnerability has been discovered with one or " +
|
||||||
|
"more hardware sensors")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QtAndroidController.onAuthResult(true)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showBiometricPrompt(biometricManager: BiometricManager) {
|
||||||
|
val executor = ContextCompat.getMainExecutor(applicationContext)
|
||||||
|
val biometricPrompt = BiometricPrompt(this, executor,
|
||||||
|
object : BiometricPrompt.AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationSucceeded(result: AuthenticationResult) {
|
||||||
|
super.onAuthenticationSucceeded(result)
|
||||||
|
Log.d(TAG, "Authentication succeeded")
|
||||||
|
QtAndroidController.onAuthResult(true)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
super.onAuthenticationFailed()
|
||||||
|
Log.w(TAG, "Authentication failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
super.onAuthenticationError(errorCode, errString)
|
||||||
|
Log.e(TAG, "Authentication error $errorCode: $errString")
|
||||||
|
QtAndroidController.onAuthResult(false)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||||
|
.setAllowedAuthenticators(AUTHENTICATORS)
|
||||||
|
.setTitle("AmneziaVPN")
|
||||||
|
.setSubtitle(biometricManager.getStrings(AUTHENTICATORS)?.promptMessage)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
biometricPrompt.authenticate(promptInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package org.amnezia.vpn;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.app.KeyguardManager;
|
|
||||||
import android.content.Intent;
|
|
||||||
import org.qtproject.qt.android.bindings.QtActivity;
|
|
||||||
|
|
||||||
|
|
||||||
import static android.content.Context.KEYGUARD_SERVICE;
|
|
||||||
|
|
||||||
public class AuthHelper extends QtActivity {
|
|
||||||
|
|
||||||
static final String TAG = "AuthHelper";
|
|
||||||
|
|
||||||
public static Intent getAuthIntent(Context context) {
|
|
||||||
KeyguardManager mKeyguardManager = (KeyguardManager)context.getSystemService(KEYGUARD_SERVICE);
|
|
||||||
if (mKeyguardManager.isDeviceSecure()) {
|
|
||||||
return mKeyguardManager.createConfirmDeviceCredentialIntent(null, null);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -33,10 +33,10 @@ class ImportConfigActivity : ComponentActivity() {
|
|||||||
intent?.let(::readConfig)
|
intent?.let(::readConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
Log.d(TAG, "onNewIntent: $intent")
|
Log.d(TAG, "onNewIntent: $intent")
|
||||||
intent?.let(::readConfig)
|
intent.let(::readConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readConfig(intent: Intent) {
|
private fun readConfig(intent: Intent) {
|
||||||
|
|||||||
@@ -25,5 +25,7 @@ object QtAndroidController {
|
|||||||
|
|
||||||
external fun onConfigImported(data: String)
|
external fun onConfigImported(data: String)
|
||||||
|
|
||||||
|
external fun onAuthResult(result: Boolean)
|
||||||
|
|
||||||
external fun decodeQrCode(data: String): Boolean
|
external fun decodeQrCode(data: String): Boolean
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ class NetworkState(
|
|||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
|
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
|
||||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val numberAttempts = 3
|
val numberAttempts = 300
|
||||||
var attemptCount = 0
|
var attemptCount = 0
|
||||||
while(true) {
|
while(true) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+38
-1
@@ -1,7 +1,12 @@
|
|||||||
package org.amnezia.vpn.protocol.wireguard
|
package org.amnezia.vpn.protocol.wireguard
|
||||||
|
|
||||||
import android.net.VpnService.Builder
|
import android.net.VpnService.Builder
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.Locale
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.amnezia.awg.GoBackend
|
import org.amnezia.awg.GoBackend
|
||||||
import org.amnezia.vpn.protocol.Protocol
|
import org.amnezia.vpn.protocol.Protocol
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
||||||
@@ -79,12 +84,44 @@ open class Wireguard : Protocol() {
|
|||||||
if (!isInitialized) loadSharedLibrary(context, "wg-go")
|
if (!isInitialized) loadSharedLibrary(context, "wg-go")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
val wireguardConfig = parseConfig(config)
|
val wireguardConfig = parseConfig(config)
|
||||||
|
val startTime = System.currentTimeMillis()
|
||||||
start(wireguardConfig, vpnBuilder, protect)
|
start(wireguardConfig, vpnBuilder, protect)
|
||||||
|
waitForConnection(startTime)
|
||||||
state.value = CONNECTED
|
state.value = CONNECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun waitForConnection(startTime: Long) {
|
||||||
|
Log.d(TAG, "Waiting for connection")
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
|
||||||
|
try {
|
||||||
|
delay(1000)
|
||||||
|
var log = getLogcat(time)
|
||||||
|
Log.d(TAG, "First waiting log: $log")
|
||||||
|
// check that there is a connection log,
|
||||||
|
// to avoid infinite connection
|
||||||
|
if (!log.contains("Attaching to interface")) {
|
||||||
|
Log.w(TAG, "Logs do not contain a connection log")
|
||||||
|
return@withContext
|
||||||
|
}
|
||||||
|
while (!log.contains("Received handshake response")) {
|
||||||
|
delay(1000)
|
||||||
|
log = getLogcat(time)
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.e(TAG, "Failed to get logcat: $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLogcat(time: String): String =
|
||||||
|
ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
.start()
|
||||||
|
.inputStream.reader().readText()
|
||||||
|
|
||||||
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
||||||
val configDataJson = config.getJSONObject("wireguard_config_data")
|
val configDataJson = config.getJSONObject("wireguard_config_data")
|
||||||
val configData = parseConfigData(configDataJson.getString("config"))
|
val configData = parseConfigData(configDataJson.getString("config"))
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class Xray : Protocol() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
Log.w(TAG, "XRay already running")
|
Log.w(TAG, "XRay already running")
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ link_directories(${CMAKE_CURRENT_SOURCE_DIR}/platforms/android)
|
|||||||
set(HEADERS ${HEADERS}
|
set(HEADERS ${HEADERS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_controller.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_controller.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.h
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.h
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.h
|
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.h
|
||||||
)
|
)
|
||||||
@@ -35,7 +34,6 @@ set(HEADERS ${HEADERS}
|
|||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_controller.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_controller.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/android_utils.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/platforms/android/authResultReceiver.cpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/protocols/android_vpnprotocol.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/core/installedAppsImageProvider.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,9 +9,10 @@
|
|||||||
#include "QRsa.h"
|
#include "QRsa.h"
|
||||||
|
|
||||||
#include "amnezia_application.h"
|
#include "amnezia_application.h"
|
||||||
#include "core/enums/apiEnums.h"
|
|
||||||
#include "configurators/wireguard_configurator.h"
|
#include "configurators/wireguard_configurator.h"
|
||||||
|
#include "core/enums/apiEnums.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,7 @@ namespace
|
|||||||
constexpr char keyPayload[] = "key_payload";
|
constexpr char keyPayload[] = "key_payload";
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList proxyStorageUrl = {""};
|
const QStringList proxyStorageUrl = { "" };
|
||||||
|
|
||||||
ErrorCode checkErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply)
|
ErrorCode checkErrors(const QList<QSslError> &sslErrors, QNetworkReply *reply)
|
||||||
{
|
{
|
||||||
@@ -65,7 +66,8 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiController::ApiController(const QString &gatewayEndpoint, QObject *parent) : QObject(parent), m_gatewayEndpoint(gatewayEndpoint)
|
ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent)
|
||||||
|
: QObject(parent), m_gatewayEndpoint(gatewayEndpoint), m_isDevEnvironment(isDevEnvironment)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +145,7 @@ QStringList ApiController::getProxyUrls()
|
|||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
QList<QSslError> sslErrors;
|
QList<QSslError> sslErrors;
|
||||||
QNetworkReply* reply;
|
QNetworkReply *reply;
|
||||||
|
|
||||||
for (const auto &proxyStorageUrl : proxyStorageUrl) {
|
for (const auto &proxyStorageUrl : proxyStorageUrl) {
|
||||||
request.setUrl(proxyStorageUrl);
|
request.setUrl(proxyStorageUrl);
|
||||||
@@ -281,7 +283,7 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
|
|||||||
|
|
||||||
request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
|
request.setUrl(QString("%1v1/services").arg(m_gatewayEndpoint));
|
||||||
|
|
||||||
QNetworkReply* reply;
|
QNetworkReply *reply;
|
||||||
reply = amnApp->manager()->get(request);
|
reply = amnApp->manager()->get(request);
|
||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
@@ -300,7 +302,8 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
|
|||||||
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
if (reply->error() != QNetworkReply::NetworkError::TimeoutError && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
|
||||||
|
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
@@ -355,11 +358,12 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
|||||||
|
|
||||||
EVP_PKEY *publicKey = nullptr;
|
EVP_PKEY *publicKey = nullptr;
|
||||||
try {
|
try {
|
||||||
QByteArray key = PROD_AGW_PUBLIC_KEY;
|
QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
|
||||||
QSimpleCrypto::QRsa rsa;
|
QSimpleCrypto::QRsa rsa;
|
||||||
publicKey = rsa.getPublicKeyFromByteArray(key);
|
publicKey = rsa.getPublicKeyFromByteArray(key);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
qCritical() << "error loading public key from environment variables";
|
qCritical() << "error loading public key from environment variables";
|
||||||
|
Utils::logException();
|
||||||
return ErrorCode::ApiMissingAgwPublicKey;
|
return ErrorCode::ApiMissingAgwPublicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +379,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
|||||||
requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
|
requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
|
||||||
requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
|
requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
|
||||||
|
|
||||||
QNetworkReply* reply = manager.post(request, QJsonDocument(requestBody).toJson());
|
QNetworkReply *reply = manager.post(request, QJsonDocument(requestBody).toJson());
|
||||||
|
|
||||||
QEventLoop wait;
|
QEventLoop wait;
|
||||||
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
@@ -395,7 +399,8 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
|
|||||||
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
|
||||||
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList<QSslError> &errors) { sslErrors = errors; });
|
||||||
wait.exec();
|
wait.exec();
|
||||||
if (reply->error() != QNetworkReply::NetworkError::TimeoutError && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
if (reply->error() != QNetworkReply::NetworkError::TimeoutError
|
||||||
|
&& reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ApiController : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ApiController(const QString &gatewayEndpoint, QObject *parent = nullptr);
|
explicit ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent = nullptr);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
|
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
|
||||||
@@ -44,6 +44,7 @@ private:
|
|||||||
|
|
||||||
QString m_gatewayEndpoint;
|
QString m_gatewayEndpoint;
|
||||||
QStringList m_proxyUrls;
|
QStringList m_proxyUrls;
|
||||||
|
bool m_isDevEnvironment;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APICONTROLLER_H
|
#endif // APICONTROLLER_H
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ ErrorCode ServerController::runScript(const ServerCredentials &credentials, QStr
|
|||||||
}
|
}
|
||||||
|
|
||||||
qDebug().noquote() << lineToExec;
|
qDebug().noquote() << lineToExec;
|
||||||
Logger::appendSshLog("Run command:" + lineToExec);
|
|
||||||
|
|
||||||
error = m_sshClient.executeCommand(lineToExec, cbReadStdOut, cbReadStdErr);
|
error = m_sshClient.executeCommand(lineToExec, cbReadStdOut, cbReadStdErr);
|
||||||
if (error != ErrorCode::NoError) {
|
if (error != ErrorCode::NoError) {
|
||||||
@@ -100,7 +99,6 @@ ErrorCode ServerController::runContainerScript(const ServerCredentials &credenti
|
|||||||
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
|
const std::function<ErrorCode(const QString &, libssh::Client &)> &cbReadStdErr)
|
||||||
{
|
{
|
||||||
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
QString fileName = "/opt/amnezia/" + Utils::getRandomString(16) + ".sh";
|
||||||
Logger::appendSshLog("Run container script for " + ContainerProps::containerToString(container) + ":\n" + script);
|
|
||||||
|
|
||||||
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
ErrorCode e = uploadTextFileToContainer(container, credentials, script, fileName);
|
||||||
if (e)
|
if (e)
|
||||||
|
|||||||
-107
@@ -1,107 +0,0 @@
|
|||||||
#ifndef LOGGER_H
|
|
||||||
#define LOGGER_H
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QString>
|
|
||||||
#include <QTextStream>
|
|
||||||
|
|
||||||
#include "ui/property_helper.h"
|
|
||||||
|
|
||||||
#include "mozilla/shared/loglevel.h"
|
|
||||||
|
|
||||||
class Logger : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
AUTO_PROPERTY(QString, sshLog)
|
|
||||||
AUTO_PROPERTY(QString, allLog)
|
|
||||||
|
|
||||||
public:
|
|
||||||
static Logger& Instance();
|
|
||||||
|
|
||||||
static void appendSshLog(const QString &log);
|
|
||||||
static void appendAllLog(const QString &log);
|
|
||||||
|
|
||||||
|
|
||||||
static bool init();
|
|
||||||
static void deInit();
|
|
||||||
static bool setServiceLogsEnabled(bool enabled);
|
|
||||||
static bool openLogsFolder();
|
|
||||||
static bool openServiceLogsFolder();
|
|
||||||
static QString appLogFileNamePath();
|
|
||||||
static void clearLogs();
|
|
||||||
static void clearServiceLogs();
|
|
||||||
static void cleanUp();
|
|
||||||
|
|
||||||
static QString userLogsFilePath();
|
|
||||||
static QString getLogFile();
|
|
||||||
|
|
||||||
// compat with Mozilla logger
|
|
||||||
Logger(const QString &className) { m_className = className; }
|
|
||||||
const QString& className() const { return m_className; }
|
|
||||||
|
|
||||||
class Log {
|
|
||||||
public:
|
|
||||||
Log(Logger* logger, LogLevel level);
|
|
||||||
~Log();
|
|
||||||
|
|
||||||
Log& operator<<(uint64_t t);
|
|
||||||
Log& operator<<(const char* t);
|
|
||||||
Log& operator<<(const QString& t);
|
|
||||||
Log& operator<<(const QStringList& t);
|
|
||||||
Log& operator<<(const QByteArray& t);
|
|
||||||
Log& operator<<(const QJsonObject& t);
|
|
||||||
Log& operator<<(QTextStreamFunction t);
|
|
||||||
Log& operator<<(const void* t);
|
|
||||||
|
|
||||||
// Q_ENUM
|
|
||||||
template <typename T>
|
|
||||||
typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, Log&>::type
|
|
||||||
operator<<(T t) {
|
|
||||||
const QMetaObject* meta = qt_getEnumMetaObject(t);
|
|
||||||
const char* name = qt_getEnumName(t);
|
|
||||||
addMetaEnum(typename QFlags<T>::Int(t), meta, name);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void addMetaEnum(quint64 value, const QMetaObject* meta, const char* name);
|
|
||||||
|
|
||||||
Logger* m_logger;
|
|
||||||
LogLevel m_logLevel;
|
|
||||||
|
|
||||||
struct Data {
|
|
||||||
Data() : m_ts(&m_buffer, QIODevice::WriteOnly) {}
|
|
||||||
|
|
||||||
QString m_buffer;
|
|
||||||
QTextStream m_ts;
|
|
||||||
};
|
|
||||||
|
|
||||||
Data* m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
Log error();
|
|
||||||
Log warning();
|
|
||||||
Log info();
|
|
||||||
Log debug();
|
|
||||||
QString sensitive(const QString& input);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Logger() {}
|
|
||||||
Logger(Logger const &) = delete;
|
|
||||||
Logger& operator= (Logger const&) = delete;
|
|
||||||
|
|
||||||
static QString userLogsDir();
|
|
||||||
|
|
||||||
static QFile m_file;
|
|
||||||
static QTextStream m_textStream;
|
|
||||||
static QString m_logFileName;
|
|
||||||
|
|
||||||
friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
|
||||||
|
|
||||||
// compat with Mozilla logger
|
|
||||||
QString m_className;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // LOGGER_H
|
|
||||||
@@ -98,6 +98,7 @@ bool AndroidController::initialize()
|
|||||||
{"onStatisticsUpdate", "(JJ)V", reinterpret_cast<void *>(onStatisticsUpdate)},
|
{"onStatisticsUpdate", "(JJ)V", reinterpret_cast<void *>(onStatisticsUpdate)},
|
||||||
{"onFileOpened", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onFileOpened)},
|
{"onFileOpened", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onFileOpened)},
|
||||||
{"onConfigImported", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onConfigImported)},
|
{"onConfigImported", "(Ljava/lang/String;)V", reinterpret_cast<void *>(onConfigImported)},
|
||||||
|
{"onAuthResult", "(Z)V", reinterpret_cast<void *>(onAuthResult)},
|
||||||
{"decodeQrCode", "(Ljava/lang/String;)Z", reinterpret_cast<bool *>(decodeQrCode)}
|
{"decodeQrCode", "(Ljava/lang/String;)Z", reinterpret_cast<bool *>(decodeQrCode)}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -210,6 +211,11 @@ void AndroidController::setScreenshotsEnabled(bool enabled)
|
|||||||
callActivityMethod("setScreenshotsEnabled", "(Z)V", enabled);
|
callActivityMethod("setScreenshotsEnabled", "(Z)V", enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidController::setNavigationBarColor(unsigned int color)
|
||||||
|
{
|
||||||
|
callActivityMethod("setNavigationBarColor", "(I)V", color);
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidController::minimizeApp()
|
void AndroidController::minimizeApp()
|
||||||
{
|
{
|
||||||
callActivityMethod("minimizeApp", "()V");
|
callActivityMethod("minimizeApp", "()V");
|
||||||
@@ -265,6 +271,22 @@ void AndroidController::requestNotificationPermission()
|
|||||||
callActivityMethod("requestNotificationPermission", "()V");
|
callActivityMethod("requestNotificationPermission", "()V");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AndroidController::requestAuthentication()
|
||||||
|
{
|
||||||
|
QEventLoop wait;
|
||||||
|
bool result;
|
||||||
|
connect(this, &AndroidController::authenticationResult, this,
|
||||||
|
[&result, &wait](const bool &authResult){
|
||||||
|
qDebug() << "Android authentication result:" << authResult;
|
||||||
|
result = authResult;
|
||||||
|
wait.quit();
|
||||||
|
},
|
||||||
|
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
|
||||||
|
callActivityMethod("requestAuthentication", "()V");
|
||||||
|
wait.exec();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Moving log processing to the Android side
|
// Moving log processing to the Android side
|
||||||
jclass AndroidController::log;
|
jclass AndroidController::log;
|
||||||
jmethodID AndroidController::logDebug;
|
jmethodID AndroidController::logDebug;
|
||||||
@@ -462,6 +484,14 @@ void AndroidController::onConfigImported(JNIEnv *env, jobject thiz, jstring data
|
|||||||
emit AndroidController::instance()->configImported(AndroidUtils::convertJString(env, data));
|
emit AndroidController::instance()->configImported(AndroidUtils::convertJString(env, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void AndroidController::onAuthResult(JNIEnv *env, jobject thiz, jboolean result)
|
||||||
|
{
|
||||||
|
Q_UNUSED(thiz);
|
||||||
|
|
||||||
|
emit AndroidController::instance()->authenticationResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool AndroidController::decodeQrCode(JNIEnv *env, jobject thiz, jstring data)
|
bool AndroidController::decodeQrCode(JNIEnv *env, jobject thiz, jstring data)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,11 +41,13 @@ public:
|
|||||||
void exportLogsFile(const QString &fileName);
|
void exportLogsFile(const QString &fileName);
|
||||||
void clearLogs();
|
void clearLogs();
|
||||||
void setScreenshotsEnabled(bool enabled);
|
void setScreenshotsEnabled(bool enabled);
|
||||||
|
void setNavigationBarColor(unsigned int color);
|
||||||
void minimizeApp();
|
void minimizeApp();
|
||||||
QJsonArray getAppList();
|
QJsonArray getAppList();
|
||||||
QPixmap getAppIcon(const QString &package, QSize *size, const QSize &requestedSize);
|
QPixmap getAppIcon(const QString &package, QSize *size, const QSize &requestedSize);
|
||||||
bool isNotificationPermissionGranted();
|
bool isNotificationPermissionGranted();
|
||||||
void requestNotificationPermission();
|
void requestNotificationPermission();
|
||||||
|
bool requestAuthentication();
|
||||||
|
|
||||||
static bool initLogging();
|
static bool initLogging();
|
||||||
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
|
static void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message);
|
||||||
@@ -63,6 +65,7 @@ signals:
|
|||||||
void configImported(QString config);
|
void configImported(QString config);
|
||||||
void importConfigFromOutside(QString config);
|
void importConfigFromOutside(QString config);
|
||||||
void initConnectionState(Vpn::ConnectionState state);
|
void initConnectionState(Vpn::ConnectionState state);
|
||||||
|
void authenticationResult(bool result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isWaitingStatus = true;
|
bool isWaitingStatus = true;
|
||||||
@@ -89,6 +92,7 @@ private:
|
|||||||
static void onStatisticsUpdate(JNIEnv *env, jobject thiz, jlong rxBytes, jlong txBytes);
|
static void onStatisticsUpdate(JNIEnv *env, jobject thiz, jlong rxBytes, jlong txBytes);
|
||||||
static void onConfigImported(JNIEnv *env, jobject thiz, jstring data);
|
static void onConfigImported(JNIEnv *env, jobject thiz, jstring data);
|
||||||
static void onFileOpened(JNIEnv *env, jobject thiz, jstring uri);
|
static void onFileOpened(JNIEnv *env, jobject thiz, jstring uri);
|
||||||
|
static void onAuthResult(JNIEnv *env, jobject thiz, jboolean result);
|
||||||
static bool decodeQrCode(JNIEnv *env, jobject thiz, jstring data);
|
static bool decodeQrCode(JNIEnv *env, jobject thiz, jstring data);
|
||||||
|
|
||||||
template <typename Ret, typename ...Args>
|
template <typename Ret, typename ...Args>
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
#include "authResultReceiver.h"
|
|
||||||
|
|
||||||
AuthResultReceiver::AuthResultReceiver(QSharedPointer<AuthResultNotifier> ¬ifier) : m_notifier(notifier)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void AuthResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data)
|
|
||||||
{
|
|
||||||
qDebug() << "receiverRequestCode" << receiverRequestCode << "resultCode" << resultCode;
|
|
||||||
|
|
||||||
if (resultCode == -1) { // ResultOK
|
|
||||||
emit m_notifier->authSuccessful();
|
|
||||||
} else {
|
|
||||||
emit m_notifier->authFailed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#ifndef AUTHRESULTRECEIVER_H
|
|
||||||
#define AUTHRESULTRECEIVER_H
|
|
||||||
|
|
||||||
#include <QJniObject>
|
|
||||||
|
|
||||||
#include <private/qandroidextras_p.h>
|
|
||||||
|
|
||||||
class AuthResultNotifier : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
AuthResultNotifier(QObject *parent = nullptr) : QObject(parent) {};
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void authFailed();
|
|
||||||
void authSuccessful();
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Auth result handler for Android */
|
|
||||||
class AuthResultReceiver final : public QAndroidActivityResultReceiver
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AuthResultReceiver(QSharedPointer<AuthResultNotifier> ¬ifier);
|
|
||||||
|
|
||||||
void handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &data) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QSharedPointer<AuthResultNotifier> m_notifier;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // AUTHRESULTRECEIVER_H
|
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "Winsvc.h"
|
#include "Winsvc.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The WindowsServiceManager provides controll over the MozillaVPNBroker
|
* @brief The WindowsServiceManager provides control over the MozillaVPNBroker
|
||||||
* service via SCM
|
* service via SCM
|
||||||
*/
|
*/
|
||||||
class WindowsServiceManager : public QObject {
|
class WindowsServiceManager : public QObject {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "ikev2_vpn_protocol_windows.h"
|
#include "ikev2_vpn_protocol_windows.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
|
|
||||||
static Ikev2Protocol* self = nullptr;
|
static Ikev2Protocol* self = nullptr;
|
||||||
static std::mutex rasDialFuncMutex;
|
static std::mutex rasDialFuncMutex;
|
||||||
|
|
||||||
@@ -80,10 +81,10 @@ void Ikev2Protocol::newConnectionStateEventReceived(UINT unMsg, tagRASCONNSTATE
|
|||||||
case RASCS_AuthNotify:
|
case RASCS_AuthNotify:
|
||||||
//qDebug()<<__FUNCTION__ << __LINE__;
|
//qDebug()<<__FUNCTION__ << __LINE__;
|
||||||
if (dwError != 0) {
|
if (dwError != 0) {
|
||||||
//qDebug() << "have error" << dwError;
|
qDebug() << "have error" << dwError;
|
||||||
setConnectionState(Vpn::ConnectionState::Disconnected);
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
||||||
} else {
|
} else {
|
||||||
//qDebug() << "RASCS_AuthNotify but no error" << dwError;
|
qDebug() << "RASCS_AuthNotify but no error" << dwError;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RASCS_AuthRetry:
|
case RASCS_AuthRetry:
|
||||||
@@ -179,11 +180,13 @@ ErrorCode Ikev2Protocol::start()
|
|||||||
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
|
QByteArray cert = QByteArray::fromBase64(m_config[config_key::cert].toString().toUtf8());
|
||||||
setConnectionState(Vpn::ConnectionState::Connecting);
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
||||||
|
|
||||||
QTemporaryFile certFile;
|
QTemporaryFile * certFile = new QTemporaryFile;
|
||||||
certFile.setAutoRemove(false);
|
certFile->setAutoRemove(false);
|
||||||
certFile.open();
|
certFile->open();
|
||||||
certFile.write(cert);
|
QString m_filename = certFile->fileName();
|
||||||
certFile.close();
|
certFile->write(cert);
|
||||||
|
certFile->close();
|
||||||
|
delete certFile;
|
||||||
|
|
||||||
{
|
{
|
||||||
auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
|
auto certInstallProcess = IpcClient::CreatePrivilegedProcess();
|
||||||
@@ -193,19 +196,19 @@ ErrorCode Ikev2Protocol::start()
|
|||||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
certInstallProcess->waitForSource(1000);
|
certInstallProcess->waitForSource();
|
||||||
if (!certInstallProcess->isInitialized()) {
|
if (!certInstallProcess->isInitialized()) {
|
||||||
qWarning() << "IpcProcess replica is not connected!";
|
qWarning() << "IpcProcess replica is not connected!";
|
||||||
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
||||||
return ErrorCode::AmneziaServiceConnectionFailed;
|
return ErrorCode::AmneziaServiceConnectionFailed;
|
||||||
}
|
}
|
||||||
certInstallProcess->setProgram(PermittedProcess::CertUtil);
|
certInstallProcess->setProgram(PermittedProcess::CertUtil);
|
||||||
QStringList arguments({"-f" , "-importpfx",
|
|
||||||
"-p", m_config[config_key::password].toString(),
|
|
||||||
certFile.fileName(), "NoExport"
|
|
||||||
});
|
|
||||||
certInstallProcess->setArguments(arguments);
|
|
||||||
|
|
||||||
|
QStringList arguments({"-f", "-importpfx", "-p", m_config[config_key::password].toString(),
|
||||||
|
QDir::toNativeSeparators(m_filename), "NoExport"
|
||||||
|
});
|
||||||
|
|
||||||
|
certInstallProcess->setArguments(arguments);
|
||||||
certInstallProcess->start();
|
certInstallProcess->start();
|
||||||
}
|
}
|
||||||
// /*
|
// /*
|
||||||
@@ -222,14 +225,13 @@ ErrorCode Ikev2Protocol::start()
|
|||||||
{
|
{
|
||||||
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
|
if ( !create_new_vpn(tunnelName(), m_config[config_key::hostName].toString())){
|
||||||
qDebug() <<"Can't create the VPN connect";
|
qDebug() <<"Can't create the VPN connect";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto adapterConfigProcess = new QProcess;
|
QProcess adapterConfigProcess;
|
||||||
|
adapterConfigProcess.setProgram("powershell");
|
||||||
adapterConfigProcess->setProgram("powershell");
|
|
||||||
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
|
QString arguments = QString("-command \"Set-VpnConnectionIPsecConfiguration\" "
|
||||||
"-ConnectionName '%1' "
|
"-ConnectionName '%1' "
|
||||||
"-AuthenticationTransformConstants GCMAES128 "
|
"-AuthenticationTransformConstants GCMAES128 "
|
||||||
@@ -240,19 +242,20 @@ ErrorCode Ikev2Protocol::start()
|
|||||||
"-DHGroup Group14 "
|
"-DHGroup Group14 "
|
||||||
"-PassThru -Force\"")
|
"-PassThru -Force\"")
|
||||||
.arg(tunnelName());
|
.arg(tunnelName());
|
||||||
adapterConfigProcess->setNativeArguments(arguments);
|
|
||||||
|
|
||||||
adapterConfigProcess->start();
|
adapterConfigProcess.setNativeArguments(arguments);
|
||||||
adapterConfigProcess->waitForFinished(5000);
|
|
||||||
}
|
adapterConfigProcess.start();
|
||||||
//*/
|
adapterConfigProcess.waitForFinished(5000);
|
||||||
{
|
}
|
||||||
|
//*/
|
||||||
|
{
|
||||||
if (!connect_to_vpn(tunnelName())) {
|
if (!connect_to_vpn(tunnelName())) {
|
||||||
qDebug()<<"We can't connect to VPN";
|
qDebug()<<"We can't connect to VPN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//setConnectionState(Connecting);
|
//setConnectionState(Connecting);
|
||||||
return ErrorCode::NoError;
|
return ErrorCode::NoError;
|
||||||
}
|
}
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
bool Ikev2Protocol::create_new_vpn(const QString & vpn_name,
|
||||||
@@ -299,6 +302,7 @@ bool Ikev2Protocol::connect_to_vpn(const QString & vpn_name){
|
|||||||
auto ret = RasDial(NULL, NULL, &RasDialParams, 0,
|
auto ret = RasDial(NULL, NULL, &RasDialParams, 0,
|
||||||
&RasDialFuncCallback,
|
&RasDialFuncCallback,
|
||||||
&hRasConn);
|
&hRasConn);
|
||||||
|
|
||||||
if (ret == ERROR_SUCCESS){
|
if (ret == ERROR_SUCCESS){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,13 +174,25 @@ bool SecureQSettings::restoreAppConfig(const QByteArray &json)
|
|||||||
QByteArray SecureQSettings::encryptText(const QByteArray &value) const
|
QByteArray SecureQSettings::encryptText(const QByteArray &value) const
|
||||||
{
|
{
|
||||||
QSimpleCrypto::QBlockCipher cipher;
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
return cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv());
|
QByteArray result;
|
||||||
|
try {
|
||||||
|
result = cipher.encryptAesBlockCipher(value, getEncKey(), getEncIv());
|
||||||
|
} catch (...) { // todo change error handling in QSimpleCrypto?
|
||||||
|
qCritical() << "error when encrypting the settings value";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray SecureQSettings::decryptText(const QByteArray &ba) const
|
QByteArray SecureQSettings::decryptText(const QByteArray &ba) const
|
||||||
{
|
{
|
||||||
QSimpleCrypto::QBlockCipher cipher;
|
QSimpleCrypto::QBlockCipher cipher;
|
||||||
return cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv());
|
QByteArray result;
|
||||||
|
try {
|
||||||
|
result = cipher.decryptAesBlockCipher(ba, getEncKey(), getEncIv());
|
||||||
|
} catch (...) { // todo change error handling in QSimpleCrypto?
|
||||||
|
qCritical() << "error when decrypting the settings value";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SecureQSettings::encryptionRequired() const
|
bool SecureQSettings::encryptionRequired() const
|
||||||
|
|||||||
+16
-1
@@ -227,7 +227,7 @@ void Settings::setSaveLogs(bool enabled)
|
|||||||
if (!isSaveLogs()) {
|
if (!isSaveLogs()) {
|
||||||
Logger::deInit();
|
Logger::deInit();
|
||||||
} else {
|
} else {
|
||||||
if (!Logger::init()) {
|
if (!Logger::init(false)) {
|
||||||
qWarning() << "Initialization of debug subsystem failed";
|
qWarning() << "Initialization of debug subsystem failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,22 @@ void Settings::setGatewayEndpoint(const QString &endpoint)
|
|||||||
m_gatewayEndpoint = endpoint;
|
m_gatewayEndpoint = endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Settings::setDevGatewayEndpoint()
|
||||||
|
{
|
||||||
|
m_gatewayEndpoint = DEV_AGW_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
QString Settings::getGatewayEndpoint()
|
QString Settings::getGatewayEndpoint()
|
||||||
{
|
{
|
||||||
return m_gatewayEndpoint;
|
return m_gatewayEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Settings::isDevGatewayEnv()
|
||||||
|
{
|
||||||
|
return m_isDevGatewayEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::toggleDevGatewayEnv(bool enabled)
|
||||||
|
{
|
||||||
|
m_isDevGatewayEnv = enabled;
|
||||||
|
}
|
||||||
|
|||||||
+5
-1
@@ -183,7 +183,7 @@ public:
|
|||||||
|
|
||||||
bool isScreenshotsEnabled() const
|
bool isScreenshotsEnabled() const
|
||||||
{
|
{
|
||||||
return value("Conf/screenshotsEnabled", false).toBool();
|
return value("Conf/screenshotsEnabled", true).toBool();
|
||||||
}
|
}
|
||||||
void setScreenshotsEnabled(bool enabled)
|
void setScreenshotsEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
@@ -217,7 +217,10 @@ public:
|
|||||||
|
|
||||||
void resetGatewayEndpoint();
|
void resetGatewayEndpoint();
|
||||||
void setGatewayEndpoint(const QString &endpoint);
|
void setGatewayEndpoint(const QString &endpoint);
|
||||||
|
void setDevGatewayEndpoint();
|
||||||
QString getGatewayEndpoint();
|
QString getGatewayEndpoint();
|
||||||
|
bool isDevGatewayEnv();
|
||||||
|
void toggleDevGatewayEnv(bool enabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void saveLogsChanged(bool enabled);
|
void saveLogsChanged(bool enabled);
|
||||||
@@ -234,6 +237,7 @@ private:
|
|||||||
mutable SecureQSettings m_settings;
|
mutable SecureQSettings m_settings;
|
||||||
|
|
||||||
QString m_gatewayEndpoint;
|
QString m_gatewayEndpoint;
|
||||||
|
bool m_isDevGatewayEnv;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGS_H
|
#endif // SETTINGS_H
|
||||||
|
|||||||
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
+1053
-699
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
@@ -10,9 +10,6 @@
|
|||||||
|
|
||||||
#include "core/controllers/vpnConfigurationController.h"
|
#include "core/controllers/vpnConfigurationController.h"
|
||||||
#include "systemController.h"
|
#include "systemController.h"
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
#include "platforms/android/android_utils.h"
|
|
||||||
#endif
|
|
||||||
#include "qrcodegen.hpp"
|
#include "qrcodegen.hpp"
|
||||||
|
|
||||||
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
ExportController::ExportController(const QSharedPointer<ServersModel> &serversModel, const QSharedPointer<ContainersModel> &containersModel,
|
||||||
@@ -24,12 +21,6 @@ ExportController::ExportController(const QSharedPointer<ServersModel> &serversMo
|
|||||||
m_clientManagementModel(clientManagementModel),
|
m_clientManagementModel(clientManagementModel),
|
||||||
m_settings(settings)
|
m_settings(settings)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
m_authResultNotifier.reset(new AuthResultNotifier);
|
|
||||||
m_authResultReceiver.reset(new AuthResultReceiver(m_authResultNotifier));
|
|
||||||
connect(m_authResultNotifier.get(), &AuthResultNotifier::authFailed, this, [this]() { emit exportErrorOccurred(tr("Access error!")); });
|
|
||||||
connect(m_authResultNotifier.get(), &AuthResultNotifier::authSuccessful, this, &ExportController::generateFullAccessConfig);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExportController::generateFullAccessConfig()
|
void ExportController::generateFullAccessConfig()
|
||||||
@@ -63,26 +54,6 @@ void ExportController::generateFullAccessConfig()
|
|||||||
emit exportConfigChanged();
|
emit exportConfigChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_ANDROID)
|
|
||||||
void ExportController::generateFullAccessConfigAndroid()
|
|
||||||
{
|
|
||||||
/* We use builtin keyguard for ssh key export protection on Android */
|
|
||||||
QJniObject activity = AndroidUtils::getActivity();
|
|
||||||
auto appContext = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
|
|
||||||
if (appContext.isValid()) {
|
|
||||||
auto intent = QJniObject::callStaticObjectMethod("org/amnezia/vpn/AuthHelper", "getAuthIntent",
|
|
||||||
"(Landroid/content/Context;)Landroid/content/Intent;", appContext.object());
|
|
||||||
if (intent.isValid()) {
|
|
||||||
if (intent.object<jobject>() != nullptr) {
|
|
||||||
QtAndroidPrivate::startActivity(intent.object<jobject>(), 1, m_authResultReceiver.get());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
generateFullAccessConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ExportController::generateConnectionConfig(const QString &clientName)
|
void ExportController::generateConnectionConfig(const QString &clientName)
|
||||||
{
|
{
|
||||||
clearPreviousConfig();
|
clearPreviousConfig();
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
#include "ui/models/clientManagementModel.h"
|
#include "ui/models/clientManagementModel.h"
|
||||||
#include "ui/models/containers_model.h"
|
#include "ui/models/containers_model.h"
|
||||||
#include "ui/models/servers_model.h"
|
#include "ui/models/servers_model.h"
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
#include "platforms/android/authResultReceiver.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ExportController : public QObject
|
class ExportController : public QObject
|
||||||
{
|
{
|
||||||
@@ -25,9 +22,6 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void generateFullAccessConfig();
|
void generateFullAccessConfig();
|
||||||
#if defined(Q_OS_ANDROID)
|
|
||||||
void generateFullAccessConfigAndroid();
|
|
||||||
#endif
|
|
||||||
void generateConnectionConfig(const QString &clientName);
|
void generateConnectionConfig(const QString &clientName);
|
||||||
void generateOpenVpnConfig(const QString &clientName);
|
void generateOpenVpnConfig(const QString &clientName);
|
||||||
void generateWireGuardConfig(const QString &clientName);
|
void generateWireGuardConfig(const QString &clientName);
|
||||||
@@ -74,11 +68,6 @@ private:
|
|||||||
QString m_config;
|
QString m_config;
|
||||||
QString m_nativeConfigString;
|
QString m_nativeConfigString;
|
||||||
QList<QString> m_qrCodes;
|
QList<QString> m_qrCodes;
|
||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
QSharedPointer<AuthResultNotifier> m_authResultNotifier;
|
|
||||||
QSharedPointer<QAndroidActivityResultReceiver> m_authResultReceiver;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EXPORTCONTROLLER_H
|
#endif // EXPORTCONTROLLER_H
|
||||||
|
|||||||
@@ -799,7 +799,7 @@ void InstallController::addEmptyServer()
|
|||||||
|
|
||||||
bool InstallController::fillAvailableServices()
|
bool InstallController::fillAvailableServices()
|
||||||
{
|
{
|
||||||
ApiController apiController(m_settings->getGatewayEndpoint());
|
ApiController apiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv());
|
||||||
|
|
||||||
QByteArray responseBody;
|
QByteArray responseBody;
|
||||||
ErrorCode errorCode = apiController.getServicesList(responseBody);
|
ErrorCode errorCode = apiController.getServicesList(responseBody);
|
||||||
@@ -821,7 +821,7 @@ bool InstallController::installServiceFromApi()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiController apiController(m_settings->getGatewayEndpoint());
|
ApiController apiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv());
|
||||||
QJsonObject serverConfig;
|
QJsonObject serverConfig;
|
||||||
|
|
||||||
ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(),
|
ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(),
|
||||||
@@ -849,7 +849,7 @@ bool InstallController::installServiceFromApi()
|
|||||||
bool InstallController::updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
bool InstallController::updateServiceFromApi(const int serverIndex, const QString &newCountryCode, const QString &newCountryName,
|
||||||
bool reloadServiceConfig)
|
bool reloadServiceConfig)
|
||||||
{
|
{
|
||||||
ApiController apiController(m_settings->getGatewayEndpoint());
|
ApiController apiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv());
|
||||||
|
|
||||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
|
||||||
@@ -885,7 +885,7 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
|
|||||||
|
|
||||||
void InstallController::updateServiceFromTelegram(const int serverIndex)
|
void InstallController::updateServiceFromTelegram(const int serverIndex)
|
||||||
{
|
{
|
||||||
ApiController *apiController = new ApiController(m_settings->getGatewayEndpoint());
|
ApiController *apiController = new ApiController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv());
|
||||||
|
|
||||||
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
#include "platforms/android/android_controller.h"
|
#include "platforms/android/android_controller.h"
|
||||||
#include "platforms/android/android_utils.h"
|
|
||||||
#include <QJniObject>
|
|
||||||
#endif
|
#endif
|
||||||
#if defined Q_OS_MAC
|
#if defined Q_OS_MAC
|
||||||
#include "ui/macos_util.h"
|
#include "ui/macos_util.h"
|
||||||
@@ -22,18 +20,8 @@ PageController::PageController(const QSharedPointer<ServersModel> &serversModel,
|
|||||||
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
|
: QObject(parent), m_serversModel(serversModel), m_settings(settings)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
// Change color of navigation and status bar's
|
|
||||||
auto initialPageNavigationBarColor = getInitialPageNavigationBarColor();
|
auto initialPageNavigationBarColor = getInitialPageNavigationBarColor();
|
||||||
AndroidUtils::runOnAndroidThreadSync([&initialPageNavigationBarColor]() {
|
AndroidController::instance()->setNavigationBarColor(initialPageNavigationBarColor);
|
||||||
QJniObject activity = AndroidUtils::getActivity();
|
|
||||||
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
|
|
||||||
if (window.isValid()) {
|
|
||||||
window.callMethod<void>("addFlags", "(I)V", 0x80000000);
|
|
||||||
window.callMethod<void>("clearFlags", "(I)V", 0x04000000);
|
|
||||||
window.callMethod<void>("setStatusBarColor", "(I)V", 0xFF0E0E11);
|
|
||||||
window.callMethod<void>("setNavigationBarColor", "(I)V", initialPageNavigationBarColor);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_MACX
|
#if defined Q_OS_MACX
|
||||||
@@ -115,14 +103,7 @@ unsigned int PageController::getInitialPageNavigationBarColor()
|
|||||||
void PageController::updateNavigationBarColor(const int color)
|
void PageController::updateNavigationBarColor(const int color)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
// Change color of navigation bar
|
AndroidController::instance()->setNavigationBarColor(color);
|
||||||
AndroidUtils::runOnAndroidThreadSync([&color]() {
|
|
||||||
QJniObject activity = AndroidUtils::getActivity();
|
|
||||||
QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
|
|
||||||
if (window.isValid()) {
|
|
||||||
window.callMethod<void>("setNavigationBarColor", "(I)V", color);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +112,7 @@ void PageController::showOnStartup()
|
|||||||
if (!m_settings->isStartMinimized()) {
|
if (!m_settings->isStartMinimized()) {
|
||||||
emit raiseMainWindow();
|
emit raiseMainWindow();
|
||||||
} else {
|
} else {
|
||||||
#ifdef Q_OS_WIN
|
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
||||||
emit hideMainWindow();
|
emit hideMainWindow();
|
||||||
#elif defined Q_OS_MACX
|
#elif defined Q_OS_MACX
|
||||||
setDockIconVisible(false);
|
setDockIconVisible(false);
|
||||||
|
|||||||
@@ -88,7 +88,12 @@ void SettingsController::toggleLogging(bool enable)
|
|||||||
|
|
||||||
void SettingsController::openLogsFolder()
|
void SettingsController::openLogsFolder()
|
||||||
{
|
{
|
||||||
Logger::openLogsFolder();
|
Logger::openLogsFolder(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsController::openServiceLogsFolder()
|
||||||
|
{
|
||||||
|
Logger::openLogsFolder(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsController::exportLogsFile(const QString &fileName)
|
void SettingsController::exportLogsFile(const QString &fileName)
|
||||||
@@ -100,12 +105,21 @@ void SettingsController::exportLogsFile(const QString &fileName)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsController::exportServiceLogsFile(const QString &fileName)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
AndroidController::instance()->exportLogsFile(fileName);
|
||||||
|
#else
|
||||||
|
SystemController::saveFile(fileName, Logger::getServiceLogFile());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsController::clearLogs()
|
void SettingsController::clearLogs()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_ANDROID
|
#ifdef Q_OS_ANDROID
|
||||||
AndroidController::instance()->clearLogs();
|
AndroidController::instance()->clearLogs();
|
||||||
#else
|
#else
|
||||||
Logger::clearLogs();
|
Logger::clearLogs(false);
|
||||||
Logger::clearServiceLogs();
|
Logger::clearServiceLogs();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -283,5 +297,31 @@ void SettingsController::setGatewayEndpoint(const QString &endpoint)
|
|||||||
|
|
||||||
QString SettingsController::getGatewayEndpoint()
|
QString SettingsController::getGatewayEndpoint()
|
||||||
{
|
{
|
||||||
return m_settings->getGatewayEndpoint();
|
return m_settings->isDevGatewayEnv() ? "Dev endpoint" : m_settings->getGatewayEndpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SettingsController::isDevGatewayEnv()
|
||||||
|
{
|
||||||
|
return m_settings->isDevGatewayEnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsController::toggleDevGatewayEnv(bool enabled)
|
||||||
|
{
|
||||||
|
m_settings->toggleDevGatewayEnv(enabled);
|
||||||
|
if (enabled) {
|
||||||
|
m_settings->setDevGatewayEndpoint();
|
||||||
|
} else {
|
||||||
|
m_settings->resetGatewayEndpoint();
|
||||||
|
}
|
||||||
|
emit gatewayEndpointChanged(m_settings->getGatewayEndpoint());
|
||||||
|
emit devGatewayEnvChanged(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SettingsController::isOnTv()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
return AndroidController::instance()->isOnTv();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
|
|
||||||
Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled)
|
Q_PROPERTY(bool isDevModeEnabled READ isDevModeEnabled NOTIFY devModeEnabled)
|
||||||
Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged)
|
Q_PROPERTY(QString gatewayEndpoint READ getGatewayEndpoint WRITE setGatewayEndpoint NOTIFY gatewayEndpointChanged)
|
||||||
|
Q_PROPERTY(bool isDevGatewayEnv READ isDevGatewayEnv WRITE toggleDevGatewayEnv NOTIFY devGatewayEnvChanged)
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void toggleAmneziaDns(bool enable);
|
void toggleAmneziaDns(bool enable);
|
||||||
@@ -42,7 +43,9 @@ public slots:
|
|||||||
void toggleLogging(bool enable);
|
void toggleLogging(bool enable);
|
||||||
|
|
||||||
void openLogsFolder();
|
void openLogsFolder();
|
||||||
|
void openServiceLogsFolder();
|
||||||
void exportLogsFile(const QString &fileName);
|
void exportLogsFile(const QString &fileName);
|
||||||
|
void exportServiceLogsFile(const QString &fileName);
|
||||||
void clearLogs();
|
void clearLogs();
|
||||||
|
|
||||||
void backupAppConfig(const QString &fileName);
|
void backupAppConfig(const QString &fileName);
|
||||||
@@ -81,6 +84,10 @@ public slots:
|
|||||||
void resetGatewayEndpoint();
|
void resetGatewayEndpoint();
|
||||||
void setGatewayEndpoint(const QString &endpoint);
|
void setGatewayEndpoint(const QString &endpoint);
|
||||||
QString getGatewayEndpoint();
|
QString getGatewayEndpoint();
|
||||||
|
bool isDevGatewayEnv();
|
||||||
|
void toggleDevGatewayEnv(bool enabled);
|
||||||
|
|
||||||
|
bool isOnTv();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void primaryDnsChanged();
|
void primaryDnsChanged();
|
||||||
@@ -103,6 +110,7 @@ signals:
|
|||||||
|
|
||||||
void devModeEnabled();
|
void devModeEnabled();
|
||||||
void gatewayEndpointChanged(const QString &endpoint);
|
void gatewayEndpointChanged(const QString &endpoint);
|
||||||
|
void devGatewayEnvChanged(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSharedPointer<ServersModel> m_serversModel;
|
QSharedPointer<ServersModel> m_serversModel;
|
||||||
|
|||||||
@@ -125,3 +125,12 @@ void SystemController::setQmlRoot(QObject *qmlRoot)
|
|||||||
{
|
{
|
||||||
m_qmlRoot = qmlRoot;
|
m_qmlRoot = qmlRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SystemController::isAuthenticated()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
return AndroidController::instance()->requestAuthentication();
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public slots:
|
|||||||
|
|
||||||
void setQmlRoot(QObject *qmlRoot);
|
void setQmlRoot(QObject *qmlRoot);
|
||||||
|
|
||||||
|
bool isAuthenticated();
|
||||||
signals:
|
signals:
|
||||||
void fileDialogClosed(const bool isAccepted);
|
void fileDialogClosed(const bool isAccepted);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ namespace
|
|||||||
constexpr char availableCountries[] = "available_countries";
|
constexpr char availableCountries[] = "available_countries";
|
||||||
|
|
||||||
constexpr char storeEndpoint[] = "store_endpoint";
|
constexpr char storeEndpoint[] = "store_endpoint";
|
||||||
|
|
||||||
|
constexpr char isAvailable[] = "is_available";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace serviceType
|
namespace serviceType
|
||||||
@@ -63,8 +65,12 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
|||||||
return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
|
return tr("Classic VPN for comfortable work, downloading large files and watching videos. "
|
||||||
"Works for any sites. Speed up to %1 MBit/s")
|
"Works for any sites. Speed up to %1 MBit/s")
|
||||||
.arg(speed);
|
.arg(speed);
|
||||||
} else {
|
} else if (serviceType == serviceType::amneziaFree){
|
||||||
return tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
|
QString description = tr("VPN to access blocked sites in regions with high levels of Internet censorship. ");
|
||||||
|
if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
|
||||||
|
description += tr("<p><a style=\"color: #EB5757;\">Not available in your region. If you have VPN enabled, disable it, return to the previous screen, and try again.</a>");
|
||||||
|
}
|
||||||
|
return description;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ServiceDescriptionRole: {
|
case ServiceDescriptionRole: {
|
||||||
@@ -75,6 +81,14 @@ QVariant ApiServicesModel::data(const QModelIndex &index, int role) const
|
|||||||
return tr("Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship");
|
return tr("Amnezia Free is a free VPN to bypass blocking in countries with high levels of internet censorship");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case IsServiceAvailableRole: {
|
||||||
|
if (serviceType == serviceType::amneziaFree) {
|
||||||
|
if (service.value(configKey::isAvailable).isBool() && !service.value(configKey::isAvailable).toBool()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case SpeedRole: {
|
case SpeedRole: {
|
||||||
auto speed = serviceInfo.value(configKey::speed).toString();
|
auto speed = serviceInfo.value(configKey::speed).toString();
|
||||||
return tr("%1 MBit/s").arg(speed);
|
return tr("%1 MBit/s").arg(speed);
|
||||||
@@ -193,6 +207,7 @@ QHash<int, QByteArray> ApiServicesModel::roleNames() const
|
|||||||
roles[NameRole] = "name";
|
roles[NameRole] = "name";
|
||||||
roles[CardDescriptionRole] = "cardDescription";
|
roles[CardDescriptionRole] = "cardDescription";
|
||||||
roles[ServiceDescriptionRole] = "serviceDescription";
|
roles[ServiceDescriptionRole] = "serviceDescription";
|
||||||
|
roles[IsServiceAvailableRole] = "isServiceAvailable";
|
||||||
roles[SpeedRole] = "speed";
|
roles[SpeedRole] = "speed";
|
||||||
roles[WorkPeriodRole] = "workPeriod";
|
roles[WorkPeriodRole] = "workPeriod";
|
||||||
roles[RegionRole] = "region";
|
roles[RegionRole] = "region";
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public:
|
|||||||
NameRole = Qt::UserRole + 1,
|
NameRole = Qt::UserRole + 1,
|
||||||
CardDescriptionRole,
|
CardDescriptionRole,
|
||||||
ServiceDescriptionRole,
|
ServiceDescriptionRole,
|
||||||
|
IsServiceAvailableRole,
|
||||||
SpeedRole,
|
SpeedRole,
|
||||||
WorkPeriodRole,
|
WorkPeriodRole,
|
||||||
RegionRole,
|
RegionRole,
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
#ifndef PROPERTY_HELPER_H
|
|
||||||
#define PROPERTY_HELPER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#define AUTO_PROPERTY(TYPE, NAME) \
|
|
||||||
Q_PROPERTY(TYPE NAME READ NAME WRITE set_ ## NAME NOTIFY NAME ## Changed ) \
|
|
||||||
public: \
|
|
||||||
TYPE NAME() const { return m_ ## NAME ; } \
|
|
||||||
void set_ ## NAME(TYPE value) { \
|
|
||||||
if (m_ ## NAME == value) return; \
|
|
||||||
m_ ## NAME = value; \
|
|
||||||
emit NAME ## Changed(value); \
|
|
||||||
} \
|
|
||||||
Q_SIGNAL void NAME ## Changed(TYPE value);\
|
|
||||||
private: \
|
|
||||||
TYPE m_ ## NAME{};
|
|
||||||
|
|
||||||
#define READONLY_PROPERTY(TYPE, NAME) \
|
|
||||||
Q_PROPERTY(TYPE NAME READ NAME CONSTANT ) \
|
|
||||||
public: \
|
|
||||||
TYPE NAME() const { return m_ ## NAME ; } \
|
|
||||||
private: \
|
|
||||||
void NAME(TYPE value) {m_ ## NAME = value; } \
|
|
||||||
TYPE m_ ## NAME{};
|
|
||||||
|
|
||||||
#endif // PROPERTY_HELPER_H
|
|
||||||
@@ -14,6 +14,7 @@ Button {
|
|||||||
property string defaultButtonColor: AmneziaStyle.color.paleGray
|
property string defaultButtonColor: AmneziaStyle.color.paleGray
|
||||||
property string progressButtonColor: AmneziaStyle.color.paleGray
|
property string progressButtonColor: AmneziaStyle.color.paleGray
|
||||||
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
|
property string connectedButtonColor: AmneziaStyle.color.goldenApricot
|
||||||
|
property bool buttonActiveFocus: activeFocus && (Qt.platform.os !== "android" || SettingsController.isOnTv())
|
||||||
|
|
||||||
implicitWidth: 190
|
implicitWidth: 190
|
||||||
implicitHeight: 190
|
implicitHeight: 190
|
||||||
@@ -50,14 +51,14 @@ Button {
|
|||||||
verticalOffset: 0
|
verticalOffset: 0
|
||||||
radius: 10
|
radius: 10
|
||||||
samples: 25
|
samples: 25
|
||||||
color: root.activeFocus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.goldenApricot
|
color: root.buttonActiveFocus ? AmneziaStyle.color.paleGray : AmneziaStyle.color.goldenApricot
|
||||||
source: backgroundCircle
|
source: backgroundCircle
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapePath {
|
ShapePath {
|
||||||
fillColor: AmneziaStyle.color.transparent
|
fillColor: AmneziaStyle.color.transparent
|
||||||
strokeColor: AmneziaStyle.color.paleGray
|
strokeColor: AmneziaStyle.color.paleGray
|
||||||
strokeWidth: root.activeFocus ? 1 : 0
|
strokeWidth: root.buttonActiveFocus ? 1 : 0
|
||||||
capStyle: ShapePath.RoundCap
|
capStyle: ShapePath.RoundCap
|
||||||
|
|
||||||
PathAngleArc {
|
PathAngleArc {
|
||||||
@@ -81,14 +82,14 @@ Button {
|
|||||||
return defaultButtonColor
|
return defaultButtonColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strokeWidth: root.activeFocus ? 2 : 3
|
strokeWidth: root.buttonActiveFocus ? 2 : 3
|
||||||
capStyle: ShapePath.RoundCap
|
capStyle: ShapePath.RoundCap
|
||||||
|
|
||||||
PathAngleArc {
|
PathAngleArc {
|
||||||
centerX: backgroundCircle.width / 2
|
centerX: backgroundCircle.width / 2
|
||||||
centerY: backgroundCircle.height / 2
|
centerY: backgroundCircle.height / 2
|
||||||
radiusX: 93 - (root.activeFocus ? 2 : 0)
|
radiusX: 93 - (root.buttonActiveFocus ? 2 : 0)
|
||||||
radiusY: 93 - (root.activeFocus ? 2 : 0)
|
radiusY: 93 - (root.buttonActiveFocus ? 2 : 0)
|
||||||
startAngle: 0
|
startAngle: 0
|
||||||
sweepAngle: 360
|
sweepAngle: 360
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ Button {
|
|||||||
visible: text !== ""
|
visible: text !== ""
|
||||||
|
|
||||||
color: AmneziaStyle.color.mutedGray
|
color: AmneziaStyle.color.mutedGray
|
||||||
|
textFormat: Text.RichText
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ Item {
|
|||||||
property string buttonImageSource
|
property string buttonImageSource
|
||||||
property string rightImageSource
|
property string rightImageSource
|
||||||
property string leftImageSource
|
property string leftImageSource
|
||||||
property bool isLeftImageHoverEnabled: true //todo separete this qml file to 3
|
property bool isLeftImageHoverEnabled: true
|
||||||
|
property bool isSmallLeftImage: false
|
||||||
|
|
||||||
property alias rightButton: rightImage
|
property alias rightButton: rightImage
|
||||||
property alias eyeButton: eyeImage
|
property alias eyeButton: eyeImage
|
||||||
@@ -114,9 +115,9 @@ Item {
|
|||||||
|
|
||||||
visible: leftImageSource ? true : false
|
visible: leftImageSource ? true : false
|
||||||
|
|
||||||
Layout.preferredHeight: rightImageSource || !isLeftImageHoverEnabled ? leftImage.implicitHeight : 56
|
Layout.preferredHeight: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage) ? 40 : 56
|
||||||
Layout.preferredWidth: rightImageSource || !isLeftImageHoverEnabled ? leftImage.implicitWidth : 56
|
Layout.preferredWidth: (rightImageSource || !isLeftImageHoverEnabled || isSmallLeftImage)? 40 : 56
|
||||||
Layout.rightMargin: rightImageSource || !isLeftImageHoverEnabled ? 16 : 0
|
Layout.rightMargin: isSmallLeftImage ? 8 : (rightImageSource || !isLeftImageHoverEnabled) ? 16 : 0
|
||||||
|
|
||||||
radius: 12
|
radius: 12
|
||||||
color: AmneziaStyle.color.transparent
|
color: AmneziaStyle.color.transparent
|
||||||
|
|||||||
@@ -102,8 +102,7 @@ Switch {
|
|||||||
contentItem: ColumnLayout {
|
contentItem: ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
|
||||||
ListItemTitleType {
|
ListItemTitleType {
|
||||||
|
|||||||
@@ -89,6 +89,21 @@ PageType {
|
|||||||
|
|
||||||
// KeyNavigation.tab: saveButton
|
// KeyNavigation.tab: saveButton
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwitcherType {
|
||||||
|
id: switcher
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Dev gateway environment")
|
||||||
|
checked: SettingsController.isDevGatewayEnv
|
||||||
|
onToggled: function() {
|
||||||
|
SettingsController.isDevGatewayEnv = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ PageType {
|
|||||||
id: mailButton
|
id: mailButton
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: qsTr("Mail")
|
text: qsTr("support@amnezia.org")
|
||||||
descriptionText: qsTr("For reviews and bug reports")
|
descriptionText: qsTr("For reviews and bug reports")
|
||||||
leftImageSource: "qrc:/images/controls/mail.svg"
|
leftImageSource: "qrc:/images/controls/mail.svg"
|
||||||
|
|
||||||
@@ -128,6 +128,8 @@ PageType {
|
|||||||
parentFlickable: fl
|
parentFlickable: fl
|
||||||
|
|
||||||
clickedFunction: function() {
|
clickedFunction: function() {
|
||||||
|
GC.copyToClipBoard(text)
|
||||||
|
PageController.showNotificationMessage(qsTr("Copied"))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,18 +16,6 @@ import "../Controls2/TextTypes"
|
|||||||
PageType {
|
PageType {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: SettingsController
|
|
||||||
|
|
||||||
function onLoggingStateChanged() {
|
|
||||||
if (SettingsController.isLoggingEnabled) {
|
|
||||||
var message = qsTr("Logging is enabled. Note that logs will be automatically \
|
|
||||||
disabled after 14 days, and all log files will be deleted.")
|
|
||||||
PageController.showNotificationMessage(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultActiveFocusItem: focusItem
|
defaultActiveFocusItem: focusItem
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -58,13 +46,12 @@ disabled after 14 days, and all log files will be deleted.")
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.leftMargin: 16
|
spacing: 0
|
||||||
anchors.rightMargin: 16
|
|
||||||
|
|
||||||
spacing: 16
|
|
||||||
|
|
||||||
HeaderType {
|
HeaderType {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Logging")
|
headerText: qsTr("Logging")
|
||||||
descriptionText: qsTr("Enabling this function will save application's logs automatically. " +
|
descriptionText: qsTr("Enabling this function will save application's logs automatically. " +
|
||||||
@@ -75,11 +62,13 @@ disabled after 14 days, and all log files will be deleted.")
|
|||||||
id: switcher
|
id: switcher
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.topMargin: 16
|
Layout.topMargin: 16
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Save logs")
|
text: qsTr("Enable logs")
|
||||||
|
|
||||||
checked: SettingsController.isLoggingEnabled
|
checked: SettingsController.isLoggingEnabled
|
||||||
KeyNavigation.tab: openFolderButton
|
//KeyNavigation.tab: openFolderButton
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if (checked !== SettingsController.isLoggingEnabled) {
|
if (checked !== SettingsController.isLoggingEnabled) {
|
||||||
SettingsController.isLoggingEnabled = checked
|
SettingsController.isLoggingEnabled = checked
|
||||||
@@ -87,100 +76,20 @@ disabled after 14 days, and all log files will be deleted.")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
// id: labelWithButton2
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -8
|
||||||
|
|
||||||
ColumnLayout {
|
text: qsTr("Clear logs")
|
||||||
Layout.alignment: Qt.AlignBaseline
|
leftImageSource: "qrc:/images/controls/trash.svg"
|
||||||
Layout.preferredWidth: GC.isMobile() ? 0 : root.width / 3
|
isSmallLeftImage: true
|
||||||
visible: !GC.isMobile()
|
|
||||||
|
|
||||||
ImageButtonType {
|
// KeyNavigation.tab: labelWithButton3
|
||||||
id: openFolderButton
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
|
|
||||||
implicitWidth: 56
|
clickedFunction: function() {
|
||||||
implicitHeight: 56
|
|
||||||
|
|
||||||
image: "qrc:/images/controls/folder-open.svg"
|
|
||||||
KeyNavigation.tab: saveButton
|
|
||||||
|
|
||||||
onClicked: SettingsController.openLogsFolder()
|
|
||||||
Keys.onReturnPressed: openFolderButton.clicked()
|
|
||||||
Keys.onEnterPressed: openFolderButton.clicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
CaptionTextType {
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Open folder with logs")
|
|
||||||
color: AmneziaStyle.color.paleGray
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.alignment: Qt.AlignBaseline
|
|
||||||
Layout.preferredWidth: root.width / ( GC.isMobile() ? 2 : 3 )
|
|
||||||
|
|
||||||
ImageButtonType {
|
|
||||||
id: saveButton
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
|
|
||||||
implicitWidth: 56
|
|
||||||
implicitHeight: 56
|
|
||||||
|
|
||||||
image: "qrc:/images/controls/save.svg"
|
|
||||||
KeyNavigation.tab: clearButton
|
|
||||||
|
|
||||||
Keys.onReturnPressed: saveButton.clicked()
|
|
||||||
Keys.onEnterPressed: saveButton.clicked()
|
|
||||||
onClicked: {
|
|
||||||
var fileName = ""
|
|
||||||
if (GC.isMobile()) {
|
|
||||||
fileName = "AmneziaVPN.log"
|
|
||||||
} else {
|
|
||||||
fileName = SystemController.getFileName(qsTr("Save"),
|
|
||||||
qsTr("Logs files (*.log)"),
|
|
||||||
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN",
|
|
||||||
true,
|
|
||||||
".log")
|
|
||||||
}
|
|
||||||
if (fileName !== "") {
|
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
SettingsController.exportLogsFile(fileName)
|
|
||||||
PageController.showBusyIndicator(false)
|
|
||||||
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CaptionTextType {
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
text: qsTr("Save logs to file")
|
|
||||||
color: AmneziaStyle.color.paleGray
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.alignment: Qt.AlignBaseline
|
|
||||||
Layout.preferredWidth: root.width / ( GC.isMobile() ? 2 : 3 )
|
|
||||||
|
|
||||||
ImageButtonType {
|
|
||||||
id: clearButton
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
|
|
||||||
implicitWidth: 56
|
|
||||||
implicitHeight: 56
|
|
||||||
|
|
||||||
image: "qrc:/images/controls/delete.svg"
|
|
||||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
|
||||||
|
|
||||||
Keys.onReturnPressed: clearButton.clicked()
|
|
||||||
Keys.onEnterPressed: clearButton.clicked()
|
|
||||||
onClicked: function() {
|
|
||||||
var headerText = qsTr("Clear logs?")
|
var headerText = qsTr("Clear logs?")
|
||||||
var yesButtonText = qsTr("Continue")
|
var yesButtonText = qsTr("Continue")
|
||||||
var noButtonText = qsTr("Cancel")
|
var noButtonText = qsTr("Cancel")
|
||||||
@@ -204,14 +113,162 @@ disabled after 14 days, and all log files will be deleted.")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CaptionTextType {
|
ListItemTitleType {
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
text: qsTr("Clear logs")
|
text: qsTr("Client logs")
|
||||||
color: AmneziaStyle.color.paleGray
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
color: AmneziaStyle.color.mutedGray
|
||||||
|
text: qsTr("AmneziaVPN logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
// id: labelWithButton2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -8
|
||||||
|
Layout.bottomMargin: -8
|
||||||
|
|
||||||
|
text: qsTr("Open logs folder")
|
||||||
|
leftImageSource: "qrc:/images/controls/folder-open.svg"
|
||||||
|
isSmallLeftImage: true
|
||||||
|
|
||||||
|
// KeyNavigation.tab: labelWithButton3
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
SettingsController.openLogsFolder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
// id: labelWithButton2
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -8
|
||||||
|
Layout.bottomMargin: -8
|
||||||
|
|
||||||
|
text: qsTr("Export logs")
|
||||||
|
leftImageSource: "qrc:/images/controls/save.svg"
|
||||||
|
isSmallLeftImage: true
|
||||||
|
|
||||||
|
// KeyNavigation.tab: labelWithButton3
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var fileName = ""
|
||||||
|
if (GC.isMobile()) {
|
||||||
|
fileName = "AmneziaVPN.log"
|
||||||
|
} else {
|
||||||
|
fileName = SystemController.getFileName(qsTr("Save"),
|
||||||
|
qsTr("Logs files (*.log)"),
|
||||||
|
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN",
|
||||||
|
true,
|
||||||
|
".log")
|
||||||
|
}
|
||||||
|
if (fileName !== "") {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
SettingsController.exportLogsFile(fileName)
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {}
|
||||||
|
|
||||||
|
ListItemTitleType {
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Service logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
ParagraphTextType {
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
|
||||||
|
color: AmneziaStyle.color.mutedGray
|
||||||
|
text: qsTr("AmneziaVPN-service logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
// id: labelWithButton2
|
||||||
|
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -8
|
||||||
|
Layout.bottomMargin: -8
|
||||||
|
|
||||||
|
text: qsTr("Open logs folder")
|
||||||
|
leftImageSource: "qrc:/images/controls/folder-open.svg"
|
||||||
|
isSmallLeftImage: true
|
||||||
|
|
||||||
|
// KeyNavigation.tab: labelWithButton3
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
SettingsController.openServiceLogsFolder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
}
|
||||||
|
|
||||||
|
LabelWithButtonType {
|
||||||
|
// id: labelWithButton2
|
||||||
|
|
||||||
|
visible: !GC.isMobile()
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: -8
|
||||||
|
Layout.bottomMargin: -8
|
||||||
|
|
||||||
|
text: qsTr("Export logs")
|
||||||
|
leftImageSource: "qrc:/images/controls/save.svg"
|
||||||
|
isSmallLeftImage: true
|
||||||
|
|
||||||
|
// KeyNavigation.tab: labelWithButton3
|
||||||
|
|
||||||
|
clickedFunction: function() {
|
||||||
|
var fileName = ""
|
||||||
|
if (GC.isMobile()) {
|
||||||
|
fileName = "AmneziaVPN-service.log"
|
||||||
|
} else {
|
||||||
|
fileName = SystemController.getFileName(qsTr("Save"),
|
||||||
|
qsTr("Logs files (*.log)"),
|
||||||
|
StandardPaths.standardLocations(StandardPaths.DocumentsLocation) + "/AmneziaVPN-service",
|
||||||
|
true,
|
||||||
|
".log")
|
||||||
|
}
|
||||||
|
if (fileName !== "") {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
SettingsController.exportServiceLogsFile(fileName)
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
PageController.showNotificationMessage(qsTr("Logs file saved"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DividerType {
|
||||||
|
visible: !GC.isMobile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ PageType {
|
|||||||
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
rightImageSource: "qrc:/images/controls/chevron-right.svg"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
if (isServiceAvailable) {
|
||||||
ApiServicesModel.setServiceIndex(index)
|
ApiServicesModel.setServiceIndex(index)
|
||||||
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
PageController.goToPage(PageEnum.PageSetupWizardApiServiceInfo)
|
||||||
}
|
}
|
||||||
@@ -97,4 +98,5 @@ PageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,51 @@ PageType {
|
|||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
|
||||||
headerText: qsTr("Connection")
|
headerText: qsTr("Connection")
|
||||||
|
|
||||||
|
actionButtonImage: PageController.isStartPageVisible() ? "qrc:/images/controls/more-vertical.svg" : ""
|
||||||
|
actionButtonFunction: function() {
|
||||||
|
moreActionsDrawer.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawerType2 {
|
||||||
|
id: moreActionsDrawer
|
||||||
|
|
||||||
|
parent: root
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
expandedHeight: root.height * 0.35
|
||||||
|
|
||||||
|
expandedContent: ColumnLayout {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: 16
|
||||||
|
anchors.rightMargin: 16
|
||||||
|
|
||||||
|
HeaderType {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 32
|
||||||
|
|
||||||
|
headerText: qsTr("Settings")
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitcherType {
|
||||||
|
id: switcher
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 16
|
||||||
|
|
||||||
|
text: qsTr("Enable logs")
|
||||||
|
|
||||||
|
checked: SettingsController.isLoggingEnabled
|
||||||
|
onCheckedChanged: {
|
||||||
|
if (checked !== SettingsController.isLoggingEnabled) {
|
||||||
|
SettingsController.isLoggingEnabled = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ParagraphTextType {
|
ParagraphTextType {
|
||||||
@@ -119,8 +164,6 @@ PageType {
|
|||||||
CardWithIconsType {
|
CardWithIconsType {
|
||||||
id: apiInstalling
|
id: apiInstalling
|
||||||
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.rightMargin: 16
|
Layout.rightMargin: 16
|
||||||
Layout.leftMargin: 16
|
Layout.leftMargin: 16
|
||||||
|
|||||||
@@ -263,7 +263,8 @@ PageType {
|
|||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
if (!port.textField.acceptableInput &&
|
if (!port.textField.acceptableInput &&
|
||||||
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite") {
|
ContainerProps.containerTypeToString(dockerContainer) !== "torwebsite" &&
|
||||||
|
ContainerProps.containerTypeToString(dockerContainer) !== "ikev2") {
|
||||||
port.errorText = qsTr("The port must be in the range of 1 to 65535")
|
port.errorText = qsTr("The port must be in the range of 1 to 65535")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,22 +140,23 @@ PageType {
|
|||||||
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
Keys.onTabPressed: lastItemTabClicked(focusItem)
|
||||||
|
|
||||||
clickedFunc: function() {
|
clickedFunc: function() {
|
||||||
|
PageController.showBusyIndicator(true)
|
||||||
|
|
||||||
|
if (Qt.platform.os === "android" && !SystemController.isAuthenticated()) {
|
||||||
|
PageController.showBusyIndicator(false)
|
||||||
|
ExportController.exportErrorOccurred(qsTr("Access error!"))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
ExportController.generateFullAccessConfig()
|
||||||
|
}
|
||||||
|
|
||||||
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
shareConnectionDrawer.headerText = qsTr("Connection to ") + serverSelector.text
|
||||||
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
shareConnectionDrawer.configContentHeaderText = qsTr("File with connection settings to ") + serverSelector.text
|
||||||
|
|
||||||
shareConnectionDrawer.open()
|
shareConnectionDrawer.open()
|
||||||
shareConnectionDrawer.contentVisible = false
|
shareConnectionDrawer.contentVisible = true
|
||||||
PageController.showBusyIndicator(true)
|
|
||||||
|
|
||||||
if (Qt.platform.os === "android") {
|
|
||||||
ExportController.generateFullAccessConfigAndroid();
|
|
||||||
} else {
|
|
||||||
ExportController.generateFullAccessConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
PageController.showBusyIndicator(false)
|
PageController.showBusyIndicator(false)
|
||||||
|
|
||||||
shareConnectionDrawer.contentVisible = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,14 @@ PageType {
|
|||||||
PageController.showNotificationMessage(qsTr("Settings restored from backup file"))
|
PageController.showNotificationMessage(qsTr("Settings restored from backup file"))
|
||||||
PageController.goToPageHome()
|
PageController.goToPageHome()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onLoggingStateChanged() {
|
||||||
|
if (SettingsController.isLoggingEnabled) {
|
||||||
|
var message = qsTr("Logging is enabled. Note that logs will be automatically" +
|
||||||
|
"disabled after 14 days, and all log files will be deleted.")
|
||||||
|
PageController.showNotificationMessage(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackViewType {
|
StackViewType {
|
||||||
|
|||||||
+19
-16
@@ -69,22 +69,6 @@ QString Utils::JsonToString(const QJsonArray &array, QJsonDocument::JsonFormat f
|
|||||||
return doc.toJson(format);
|
return doc.toJson(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Utils::systemLogPath()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
QStringList locationList = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
|
||||||
QString primaryLocation = "ProgramData";
|
|
||||||
foreach (const QString &location, locationList) {
|
|
||||||
if (location.contains(primaryLocation)) {
|
|
||||||
return QString("%1/%2/log").arg(location).arg(APPLICATION_NAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
#else
|
|
||||||
return QString("/var/log/%1").arg(APPLICATION_NAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Utils::initializePath(const QString &path)
|
bool Utils::initializePath(const QString &path)
|
||||||
{
|
{
|
||||||
QDir dir;
|
QDir dir;
|
||||||
@@ -227,6 +211,25 @@ QString Utils::tun2socksPath()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Utils::logException(const std::exception &e)
|
||||||
|
{
|
||||||
|
qCritical() << e.what();
|
||||||
|
try {
|
||||||
|
std::rethrow_if_nested(e);
|
||||||
|
} catch (const std::exception &nested) {
|
||||||
|
logException(nested);
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::logException(const std::exception_ptr &eptr)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (eptr) std::rethrow_exception(eptr);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
logException(e);
|
||||||
|
} catch (...) {}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
// Inspired from http://stackoverflow.com/a/15281070/1529139
|
// Inspired from http://stackoverflow.com/a/15281070/1529139
|
||||||
// and http://stackoverflow.com/q/40059902/1529139
|
// and http://stackoverflow.com/q/40059902/1529139
|
||||||
|
|||||||
+3
-1
@@ -23,7 +23,6 @@ public:
|
|||||||
static QJsonObject JsonFromString(const QString &string);
|
static QJsonObject JsonFromString(const QString &string);
|
||||||
static QString executable(const QString &baseName, bool absPath);
|
static QString executable(const QString &baseName, bool absPath);
|
||||||
static QString usrExecutable(const QString &baseName);
|
static QString usrExecutable(const QString &baseName);
|
||||||
static QString systemLogPath();
|
|
||||||
static bool createEmptyFile(const QString &path);
|
static bool createEmptyFile(const QString &path);
|
||||||
static bool initializePath(const QString &path);
|
static bool initializePath(const QString &path);
|
||||||
|
|
||||||
@@ -35,6 +34,9 @@ public:
|
|||||||
static QString certUtilPath();
|
static QString certUtilPath();
|
||||||
static QString tun2socksPath();
|
static QString tun2socksPath();
|
||||||
|
|
||||||
|
static void logException(const std::exception &e);
|
||||||
|
static void logException(const std::exception_ptr &eptr = std::current_exception());
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
|
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,18 +4,18 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMetaEnum>
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QMetaEnum>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "version.h"
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
#include <core/ipcclient.h>
|
#include <core/ipcclient.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_IOS
|
#ifdef Q_OS_IOS
|
||||||
@@ -25,8 +25,9 @@
|
|||||||
QFile Logger::m_file;
|
QFile Logger::m_file;
|
||||||
QTextStream Logger::m_textStream;
|
QTextStream Logger::m_textStream;
|
||||||
QString Logger::m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
|
QString Logger::m_logFileName = QString("%1.log").arg(APPLICATION_NAME);
|
||||||
|
QString Logger::m_serviceLogFileName = QString("%1.log").arg(SERVICE_NAME);
|
||||||
|
|
||||||
void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
{
|
{
|
||||||
if (msg.simplified().isEmpty()) {
|
if (msg.simplified().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -37,12 +38,12 @@ void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, cons
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") || msg.startsWith("Populating font") || msg.startsWith("stale focus object")) {
|
if (msg.startsWith("Unknown property") || msg.startsWith("Could not create pixmap") || msg.startsWith("Populating font")
|
||||||
|
|| msg.startsWith("stale focus object")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush;
|
Logger::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush;
|
||||||
Logger::appendAllLog(qFormatLogMessage(type, context, msg));
|
|
||||||
|
|
||||||
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
|
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
|
||||||
}
|
}
|
||||||
@@ -53,36 +54,24 @@ Logger &Logger::Instance()
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::appendSshLog(const QString &log)
|
bool Logger::init(bool isServiceLogger)
|
||||||
{
|
{
|
||||||
QString dt = QDateTime::currentDateTime().toString();
|
QString path = isServiceLogger ? systemLogDir() : userLogsDir();
|
||||||
Instance().m_sshLog.append(dt + ": " + log + "\n");
|
QString logFileName = isServiceLogger ? m_serviceLogFileName : m_logFileName ;
|
||||||
emit Instance().sshLogChanged(Instance().sshLog());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::appendAllLog(const QString &log)
|
|
||||||
{
|
|
||||||
Instance().m_allLog.append(log + "\n");
|
|
||||||
emit Instance().allLogChanged(Instance().allLog());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Logger::init()
|
|
||||||
{
|
|
||||||
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
|
|
||||||
|
|
||||||
QString path = userLogsDir();
|
|
||||||
QDir appDir(path);
|
QDir appDir(path);
|
||||||
if (!appDir.mkpath(path)) {
|
if (!appDir.mkpath(path)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_file.setFileName(appDir.filePath(m_logFileName));
|
m_file.setFileName(appDir.filePath(logFileName));
|
||||||
if (!m_file.open(QIODevice::Append)) {
|
if (!m_file.open(QIODevice::Append)) {
|
||||||
qWarning() << "Cannot open log file:" << m_logFileName;
|
qWarning() << "Cannot open log file:" << logFileName;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_file.setTextModeEnabled(true);
|
m_file.setTextModeEnabled(true);
|
||||||
m_textStream.setDevice(&m_file);
|
m_textStream.setDevice(&m_file);
|
||||||
|
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
|
||||||
|
|
||||||
#if !defined(QT_DEBUG) || defined(Q_OS_IOS)
|
#if !defined(QT_DEBUG) || defined(Q_OS_IOS)
|
||||||
qInstallMessageHandler(debugMessageHandler);
|
qInstallMessageHandler(debugMessageHandler);
|
||||||
@@ -99,7 +88,8 @@ void Logger::deInit()
|
|||||||
m_file.close();
|
m_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logger::setServiceLogsEnabled(bool enabled) {
|
bool Logger::setServiceLogsEnabled(bool enabled)
|
||||||
|
{
|
||||||
#ifdef AMNEZIA_DESKTOP
|
#ifdef AMNEZIA_DESKTOP
|
||||||
IpcClient *m_IpcClient = new IpcClient;
|
IpcClient *m_IpcClient = new IpcClient;
|
||||||
|
|
||||||
@@ -112,8 +102,7 @@ bool Logger::setServiceLogsEnabled(bool enabled) {
|
|||||||
|
|
||||||
if (m_IpcClient->Interface()) {
|
if (m_IpcClient->Interface()) {
|
||||||
m_IpcClient->Interface()->setLogsEnabled(enabled);
|
m_IpcClient->Interface()->setLogsEnabled(enabled);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
qWarning() << "Error occurred setting up service logs";
|
qWarning() << "Error occurred setting up service logs";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -127,11 +116,32 @@ QString Logger::userLogsDir()
|
|||||||
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log";
|
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/log";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Logger::systemLogDir()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
QStringList locationList = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
||||||
|
QString primaryLocation = "ProgramData";
|
||||||
|
foreach (const QString &location, locationList) {
|
||||||
|
if (location.contains(primaryLocation)) {
|
||||||
|
return QString("%1/%2/log").arg(location).arg(APPLICATION_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
#else
|
||||||
|
return QString("/var/log/%1").arg(APPLICATION_NAME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
QString Logger::userLogsFilePath()
|
QString Logger::userLogsFilePath()
|
||||||
{
|
{
|
||||||
return userLogsDir() + QDir::separator() + m_logFileName;
|
return userLogsDir() + QDir::separator() + m_logFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Logger::serviceLogsFilePath()
|
||||||
|
{
|
||||||
|
return systemLogDir() + QDir::separator() + m_serviceLogFileName;
|
||||||
|
}
|
||||||
|
|
||||||
QString Logger::getLogFile()
|
QString Logger::getLogFile()
|
||||||
{
|
{
|
||||||
m_file.flush();
|
m_file.flush();
|
||||||
@@ -145,12 +155,26 @@ QString Logger::getLogFile()
|
|||||||
#else
|
#else
|
||||||
return qtLog;
|
return qtLog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logger::openLogsFolder()
|
QString Logger::getServiceLogFile()
|
||||||
{
|
{
|
||||||
QString path = userLogsDir();
|
m_file.flush();
|
||||||
|
QFile file(serviceLogsFilePath());
|
||||||
|
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
QString qtLog = file.readAll();
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
return QString().fromStdString(AmneziaVPN::swiftUpdateLogData(qtLog.toStdString()));
|
||||||
|
#else
|
||||||
|
return qtLog;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logger::openLogsFolder(bool isServiceLogger)
|
||||||
|
{
|
||||||
|
QString path = isServiceLogger ? systemLogDir() : userLogsDir();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
path = "file:///" + path;
|
path = "file:///" + path;
|
||||||
#endif
|
#endif
|
||||||
@@ -161,27 +185,12 @@ bool Logger::openLogsFolder()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Logger::openServiceLogsFolder()
|
void Logger::clearLogs(bool isServiceLogger)
|
||||||
{
|
|
||||||
QString path = Utils::systemLogPath();
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
path = "file:///" + path;
|
|
||||||
#endif
|
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Logger::appLogFileNamePath()
|
|
||||||
{
|
|
||||||
return m_file.fileName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::clearLogs()
|
|
||||||
{
|
{
|
||||||
bool isLogActive = m_file.isOpen();
|
bool isLogActive = m_file.isOpen();
|
||||||
m_file.close();
|
m_file.close();
|
||||||
|
|
||||||
QFile file(userLogsFilePath());
|
QFile file(isServiceLogger ? serviceLogsFilePath() : userLogsFilePath());
|
||||||
|
|
||||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||||
file.resize(0);
|
file.resize(0);
|
||||||
@@ -192,7 +201,7 @@ void Logger::clearLogs()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (isLogActive) {
|
if (isLogActive) {
|
||||||
init();
|
init(isServiceLogger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,8 +219,7 @@ void Logger::clearServiceLogs()
|
|||||||
|
|
||||||
if (m_IpcClient->Interface()) {
|
if (m_IpcClient->Interface()) {
|
||||||
m_IpcClient->Interface()->clearLogs();
|
m_IpcClient->Interface()->clearLogs();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
qWarning() << "Error occurred cleaning up service logs";
|
qWarning() << "Error occurred cleaning up service logs";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -219,26 +227,41 @@ void Logger::clearServiceLogs()
|
|||||||
|
|
||||||
void Logger::cleanUp()
|
void Logger::cleanUp()
|
||||||
{
|
{
|
||||||
clearLogs();
|
clearLogs(false);
|
||||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||||
dir.removeRecursively();
|
dir.removeRecursively();
|
||||||
|
|
||||||
clearServiceLogs();
|
clearLogs(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Log::Log(Logger* logger, LogLevel logLevel)
|
Logger::Log::Log(Logger *logger, LogLevel logLevel) : m_logger(logger), m_logLevel(logLevel), m_data(new Data())
|
||||||
: m_logger(logger), m_logLevel(logLevel), m_data(new Data()) {}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Logger::Log::~Log() {
|
Logger::Log::~Log()
|
||||||
|
{
|
||||||
qDebug() << "Amnezia" << m_logger->className() << m_data->m_buffer.trimmed();
|
qDebug() << "Amnezia" << m_logger->className() << m_data->m_buffer.trimmed();
|
||||||
delete m_data;
|
delete m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Log Logger::error() { return Log(this, LogLevel::Error); }
|
Logger::Log Logger::error()
|
||||||
Logger::Log Logger::warning() { return Log(this, LogLevel::Warning); }
|
{
|
||||||
Logger::Log Logger::info() { return Log(this, LogLevel::Info); }
|
return Log(this, LogLevel::Error);
|
||||||
Logger::Log Logger::debug() { return Log(this, LogLevel::Debug); }
|
}
|
||||||
QString Logger::sensitive(const QString& input) {
|
Logger::Log Logger::warning()
|
||||||
|
{
|
||||||
|
return Log(this, LogLevel::Warning);
|
||||||
|
}
|
||||||
|
Logger::Log Logger::info()
|
||||||
|
{
|
||||||
|
return Log(this, LogLevel::Info);
|
||||||
|
}
|
||||||
|
Logger::Log Logger::debug()
|
||||||
|
{
|
||||||
|
return Log(this, LogLevel::Debug);
|
||||||
|
}
|
||||||
|
QString Logger::sensitive(const QString &input)
|
||||||
|
{
|
||||||
#ifdef Q_DEBUG
|
#ifdef Q_DEBUG
|
||||||
return input;
|
return input;
|
||||||
#else
|
#else
|
||||||
@@ -247,48 +270,51 @@ QString Logger::sensitive(const QString& input) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define CREATE_LOG_OP_REF(x) \
|
#define CREATE_LOG_OP_REF(x) \
|
||||||
Logger::Log& Logger::Log::operator<<(x t) { \
|
Logger::Log &Logger::Log::operator<<(x t) \
|
||||||
|
{ \
|
||||||
m_data->m_ts << t << ' '; \
|
m_data->m_ts << t << ' '; \
|
||||||
return *this; \
|
return *this; \
|
||||||
}
|
}
|
||||||
|
|
||||||
CREATE_LOG_OP_REF(uint64_t);
|
CREATE_LOG_OP_REF(uint64_t);
|
||||||
CREATE_LOG_OP_REF(const char*);
|
CREATE_LOG_OP_REF(const char *);
|
||||||
CREATE_LOG_OP_REF(const QString&);
|
CREATE_LOG_OP_REF(const QString &);
|
||||||
CREATE_LOG_OP_REF(const QByteArray&);
|
CREATE_LOG_OP_REF(const QByteArray &);
|
||||||
CREATE_LOG_OP_REF(const void*);
|
CREATE_LOG_OP_REF(const void *);
|
||||||
|
|
||||||
#undef CREATE_LOG_OP_REF
|
#undef CREATE_LOG_OP_REF
|
||||||
|
|
||||||
Logger::Log& Logger::Log::operator<<(const QStringList& t) {
|
Logger::Log &Logger::Log::operator<<(const QStringList &t)
|
||||||
|
{
|
||||||
m_data->m_ts << '[' << t.join(",") << ']' << ' ';
|
m_data->m_ts << '[' << t.join(",") << ']' << ' ';
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Log& Logger::Log::operator<<(const QJsonObject& t) {
|
Logger::Log &Logger::Log::operator<<(const QJsonObject &t)
|
||||||
|
{
|
||||||
m_data->m_ts << QJsonDocument(t).toJson(QJsonDocument::Indented) << ' ';
|
m_data->m_ts << QJsonDocument(t).toJson(QJsonDocument::Indented) << ' ';
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Log& Logger::Log::operator<<(QTextStreamFunction t) {
|
Logger::Log &Logger::Log::operator<<(QTextStreamFunction t)
|
||||||
|
{
|
||||||
m_data->m_ts << t;
|
m_data->m_ts << t;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::Log::addMetaEnum(quint64 value, const QMetaObject* meta,
|
void Logger::Log::addMetaEnum(quint64 value, const QMetaObject *meta, const char *name)
|
||||||
const char* name) {
|
{
|
||||||
QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
|
QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
|
||||||
|
|
||||||
QString out;
|
QString out;
|
||||||
QTextStream ts(&out);
|
QTextStream ts(&out);
|
||||||
|
|
||||||
if (const char* scope = me.scope()) {
|
if (const char *scope = me.scope()) {
|
||||||
ts << scope << "::";
|
ts << scope << "::";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* key = me.valueToKey(static_cast<int>(value));
|
const char *key = me.valueToKey(static_cast<int>(value));
|
||||||
const bool scoped = me.isScoped();
|
const bool scoped = me.isScoped();
|
||||||
if (scoped || !key) {
|
if (scoped || !key) {
|
||||||
ts << me.enumName() << (!key ? "(" : "::");
|
ts << me.enumName() << (!key ? "(" : "::");
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#include "mozilla/shared/loglevel.h"
|
||||||
|
|
||||||
|
class Logger : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Logger &Instance();
|
||||||
|
|
||||||
|
static bool init(bool isServiceLogger);
|
||||||
|
static void deInit();
|
||||||
|
|
||||||
|
static bool setServiceLogsEnabled(bool enabled);
|
||||||
|
|
||||||
|
static bool openLogsFolder(bool isServiceLogger);
|
||||||
|
|
||||||
|
static void clearLogs(bool isServiceLogger);
|
||||||
|
static void clearServiceLogs();
|
||||||
|
static void cleanUp();
|
||||||
|
|
||||||
|
static QString userLogsFilePath();
|
||||||
|
static QString serviceLogsFilePath();
|
||||||
|
static QString systemLogDir();
|
||||||
|
|
||||||
|
static QString getLogFile();
|
||||||
|
static QString getServiceLogFile();
|
||||||
|
|
||||||
|
// compat with Mozilla logger
|
||||||
|
Logger(const QString &className)
|
||||||
|
{
|
||||||
|
m_className = className;
|
||||||
|
}
|
||||||
|
const QString &className() const
|
||||||
|
{
|
||||||
|
return m_className;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Log
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Log(Logger *logger, LogLevel level);
|
||||||
|
~Log();
|
||||||
|
|
||||||
|
Log &operator<<(uint64_t t);
|
||||||
|
Log &operator<<(const char *t);
|
||||||
|
Log &operator<<(const QString &t);
|
||||||
|
Log &operator<<(const QStringList &t);
|
||||||
|
Log &operator<<(const QByteArray &t);
|
||||||
|
Log &operator<<(const QJsonObject &t);
|
||||||
|
Log &operator<<(QTextStreamFunction t);
|
||||||
|
Log &operator<<(const void *t);
|
||||||
|
|
||||||
|
// Q_ENUM
|
||||||
|
template<typename T> typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, Log &>::type operator<<(T t)
|
||||||
|
{
|
||||||
|
const QMetaObject *meta = qt_getEnumMetaObject(t);
|
||||||
|
const char *name = qt_getEnumName(t);
|
||||||
|
addMetaEnum(typename QFlags<T>::Int(t), meta, name);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addMetaEnum(quint64 value, const QMetaObject *meta, const char *name);
|
||||||
|
|
||||||
|
Logger *m_logger;
|
||||||
|
LogLevel m_logLevel;
|
||||||
|
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
Data() : m_ts(&m_buffer, QIODevice::WriteOnly)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString m_buffer;
|
||||||
|
QTextStream m_ts;
|
||||||
|
};
|
||||||
|
|
||||||
|
Data *m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
Log error();
|
||||||
|
Log warning();
|
||||||
|
Log info();
|
||||||
|
Log debug();
|
||||||
|
QString sensitive(const QString &input);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger() {};
|
||||||
|
Logger(Logger const &) = delete;
|
||||||
|
Logger &operator=(Logger const &) = delete;
|
||||||
|
|
||||||
|
static QString userLogsDir();
|
||||||
|
|
||||||
|
static QFile m_file;
|
||||||
|
static QTextStream m_textStream;
|
||||||
|
static QString m_logFileName;
|
||||||
|
static QString m_serviceLogFileName;
|
||||||
|
|
||||||
|
friend void debugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||||
|
|
||||||
|
// compat with Mozilla logger
|
||||||
|
QString m_className;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOGGER_H
|
||||||
+33
-53
@@ -1,32 +1,32 @@
|
|||||||
#include "ipcserver.h"
|
#include "ipcserver.h"
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QLocalSocket>
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
#include "router.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "router.h"
|
||||||
|
|
||||||
#include "../client/protocols/protocols_defs.h"
|
#include "../client/protocols/protocols_defs.h"
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "tapcontroller_win.h"
|
#include "../client/platforms/windows/daemon/windowsdaemon.h"
|
||||||
#include "../client/platforms/windows/daemon/windowsfirewall.h"
|
#include "../client/platforms/windows/daemon/windowsfirewall.h"
|
||||||
#include "../client/platforms/windows/daemon/windowsdaemon.h"
|
#include "tapcontroller_win.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include "../client/platforms/linux/daemon/linuxfirewall.h"
|
#include "../client/platforms/linux/daemon/linuxfirewall.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
#include "../client/platforms/macos/daemon/macosfirewall.h"
|
#include "../client/platforms/macos/daemon/macosfirewall.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IpcServer::IpcServer(QObject *parent):
|
IpcServer::IpcServer(QObject *parent) : IpcInterfaceSource(parent)
|
||||||
IpcInterfaceSource(parent)
|
|
||||||
|
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int IpcServer::createPrivilegedProcess()
|
int IpcServer::createPrivilegedProcess()
|
||||||
{
|
{
|
||||||
@@ -58,23 +58,10 @@ int IpcServer::createPrivilegedProcess()
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(pd.serverNode.data(), &QRemoteObjectHost::error, this, [pd](QRemoteObjectNode::ErrorCode errorCode) {
|
QObject::connect(pd.serverNode.data(), &QRemoteObjectHost::error, this,
|
||||||
qDebug() << "QRemoteObjectHost::error" << errorCode;
|
[pd](QRemoteObjectNode::ErrorCode errorCode) { qDebug() << "QRemoteObjectHost::error" << errorCode; });
|
||||||
});
|
|
||||||
|
|
||||||
QObject::connect(pd.serverNode.data(), &QRemoteObjectHost::destroyed, this, [pd]() {
|
QObject::connect(pd.serverNode.data(), &QRemoteObjectHost::destroyed, this, [pd]() { qDebug() << "QRemoteObjectHost::destroyed"; });
|
||||||
qDebug() << "QRemoteObjectHost::destroyed";
|
|
||||||
});
|
|
||||||
|
|
||||||
// connect(pd.ipcProcess.data(), &IpcServerProcess::finished, this, [this, pid=m_localpid](int exitCode, QProcess::ExitStatus exitStatus){
|
|
||||||
// qDebug() << "IpcServerProcess finished" << exitCode << exitStatus;
|
|
||||||
//// if (m_processes.contains(pid)) {
|
|
||||||
//// m_processes[pid].ipcProcess.reset();
|
|
||||||
//// m_processes[pid].serverNode.reset();
|
|
||||||
//// m_processes[pid].localServer.reset();
|
|
||||||
//// m_processes.remove(pid);
|
|
||||||
//// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
m_processes.insert(m_localpid, pd);
|
m_processes.insert(m_localpid, pd);
|
||||||
|
|
||||||
@@ -105,7 +92,7 @@ bool IpcServer::routeDeleteList(const QString &gw, const QStringList &ips)
|
|||||||
qDebug() << "IpcServer::routeDeleteList";
|
qDebug() << "IpcServer::routeDeleteList";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return Router::routeDeleteList(gw ,ips);
|
return Router::routeDeleteList(gw, ips);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcServer::flushDns()
|
void IpcServer::flushDns()
|
||||||
@@ -158,12 +145,13 @@ void IpcServer::cleanUp()
|
|||||||
qDebug() << "IpcServer::cleanUp";
|
qDebug() << "IpcServer::cleanUp";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Logger::deinit();
|
Logger::deInit();
|
||||||
Logger::cleanUp();
|
Logger::cleanUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcServer::clearLogs() {
|
void IpcServer::clearLogs()
|
||||||
Logger::clearLogs();
|
{
|
||||||
|
Logger::clearLogs(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IpcServer::createTun(const QString &dev, const QString &subnet)
|
bool IpcServer::createTun(const QString &dev, const QString &subnet)
|
||||||
@@ -176,7 +164,7 @@ bool IpcServer::deleteTun(const QString &dev)
|
|||||||
return Router::deleteTun(dev);
|
return Router::deleteTun(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IpcServer::updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers)
|
bool IpcServer::updateResolvers(const QString &ifname, const QList<QHostAddress> &resolvers)
|
||||||
{
|
{
|
||||||
return Router::updateResolvers(ifname, resolvers);
|
return Router::updateResolvers(ifname, resolvers);
|
||||||
}
|
}
|
||||||
@@ -197,14 +185,12 @@ void IpcServer::setLogsEnabled(bool enabled)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Logger::init();
|
Logger::init(true);
|
||||||
}
|
} else {
|
||||||
else {
|
Logger::deInit();
|
||||||
Logger::deinit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex)
|
bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterIndex)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -220,13 +206,11 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd
|
|||||||
QStringList allownets;
|
QStringList allownets;
|
||||||
QStringList blocknets;
|
QStringList blocknets;
|
||||||
|
|
||||||
if (splitTunnelType == 0)
|
if (splitTunnelType == 0) {
|
||||||
{
|
|
||||||
blockAll = true;
|
blockAll = true;
|
||||||
allowNets = true;
|
allowNets = true;
|
||||||
allownets.append(configStr.value(amnezia::config_key::hostName).toString());
|
allownets.append(configStr.value(amnezia::config_key::hostName).toString());
|
||||||
} else if (splitTunnelType == 1)
|
} else if (splitTunnelType == 1) {
|
||||||
{
|
|
||||||
blockNets = true;
|
blockNets = true;
|
||||||
for (auto v : splitTunnelSites) {
|
for (auto v : splitTunnelSites) {
|
||||||
blocknets.append(v.toString());
|
blocknets.append(v.toString());
|
||||||
@@ -268,18 +252,17 @@ bool IpcServer::enableKillSwitch(const QJsonObject &configStr, int vpnAdapterInd
|
|||||||
|
|
||||||
// double-check + ensure our firewall is installed and enabled. This is necessary as
|
// double-check + ensure our firewall is installed and enabled. This is necessary as
|
||||||
// other software may disable pfctl before re-enabling with their own rules (e.g other VPNs)
|
// other software may disable pfctl before re-enabling with their own rules (e.g other VPNs)
|
||||||
if (!MacOSFirewall::isInstalled()) MacOSFirewall::install();
|
if (!MacOSFirewall::isInstalled())
|
||||||
|
MacOSFirewall::install();
|
||||||
|
|
||||||
MacOSFirewall::ensureRootAnchorPriority();
|
MacOSFirewall::ensureRootAnchorPriority();
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("000.allowLoopback"), true);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("000.allowLoopback"), true);
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("100.blockAll"), blockAll);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("100.blockAll"), blockAll);
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("110.allowNets"), allowNets);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("110.allowNets"), allowNets);
|
||||||
MacOSFirewall::setAnchorTable(QStringLiteral("110.allowNets"), allowNets,
|
MacOSFirewall::setAnchorTable(QStringLiteral("110.allowNets"), allowNets, QStringLiteral("allownets"), allownets);
|
||||||
QStringLiteral("allownets"), allownets);
|
|
||||||
|
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("120.blockNets"), blockNets);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("120.blockNets"), blockNets);
|
||||||
MacOSFirewall::setAnchorTable(QStringLiteral("120.blockNets"), blockNets,
|
MacOSFirewall::setAnchorTable(QStringLiteral("120.blockNets"), blockNets, QStringLiteral("blocknets"), blocknets);
|
||||||
QStringLiteral("blocknets"), blocknets);
|
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("200.allowVPN"), true);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("200.allowVPN"), true);
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("250.blockIPv6"), true);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("250.blockIPv6"), true);
|
||||||
MacOSFirewall::setAnchorEnabled(QStringLiteral("290.allowDHCP"), true);
|
MacOSFirewall::setAnchorEnabled(QStringLiteral("290.allowDHCP"), true);
|
||||||
@@ -330,10 +313,8 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
|||||||
|
|
||||||
// Use APP split tunnel
|
// Use APP split tunnel
|
||||||
if (splitTunnelType == 0 || splitTunnelType == 2) {
|
if (splitTunnelType == 0 || splitTunnelType == 2) {
|
||||||
config.m_allowedIPAddressRanges.append(
|
config.m_allowedIPAddressRanges.append(IPAddress(QHostAddress("0.0.0.0"), 0));
|
||||||
IPAddress(QHostAddress("0.0.0.0"), 0));
|
config.m_allowedIPAddressRanges.append(IPAddress(QHostAddress("::"), 0));
|
||||||
config.m_allowedIPAddressRanges.append(
|
|
||||||
IPAddress(QHostAddress("::"), 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splitTunnelType == 1) {
|
if (splitTunnelType == 1) {
|
||||||
@@ -343,8 +324,7 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
|||||||
config.m_allowedIPAddressRanges.append(
|
config.m_allowedIPAddressRanges.append(
|
||||||
IPAddress(QHostAddress(ipRange.split('/')[0]), atoi(ipRange.split('/')[1].toLocal8Bit())));
|
IPAddress(QHostAddress(ipRange.split('/')[0]), atoi(ipRange.split('/')[1].toLocal8Bit())));
|
||||||
} else {
|
} else {
|
||||||
config.m_allowedIPAddressRanges.append(
|
config.m_allowedIPAddressRanges.append(IPAddress(QHostAddress(ipRange), 32));
|
||||||
IPAddress(QHostAddress(ipRange), 32));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,7 +337,7 @@ bool IpcServer::enablePeerTraffic(const QJsonObject &configStr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QJsonValue& i : configStr.value(amnezia::config_key::splitTunnelApps).toArray()) {
|
for (const QJsonValue &i : configStr.value(amnezia::config_key::splitTunnelApps).toArray()) {
|
||||||
if (!i.isString()) {
|
if (!i.isString()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ set(HEADERS
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.h
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.h
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/localserver.h
|
${CMAKE_CURRENT_LIST_DIR}/localserver.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/logger.h
|
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/router.h
|
${CMAKE_CURRENT_LIST_DIR}/router.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/systemservice.h
|
${CMAKE_CURRENT_LIST_DIR}/systemservice.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/version.h
|
${CMAKE_CURRENT_BINARY_DIR}/version.h
|
||||||
@@ -31,7 +31,7 @@ set(SOURCES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserver.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc/ipcserverprocess.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/localserver.cpp
|
${CMAKE_CURRENT_LIST_DIR}/localserver.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/logger.cpp
|
${CMAKE_CURRENT_LIST_DIR}/../../common/logger/logger.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
${CMAKE_CURRENT_LIST_DIR}/main.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/router.cpp
|
${CMAKE_CURRENT_LIST_DIR}/router.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/systemservice.cpp
|
${CMAKE_CURRENT_LIST_DIR}/systemservice.cpp
|
||||||
@@ -238,6 +238,7 @@ include_directories(
|
|||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../client
|
${CMAKE_CURRENT_LIST_DIR}/../../client
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../../ipc
|
${CMAKE_CURRENT_LIST_DIR}/../../ipc
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/../../common/logger
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,185 +0,0 @@
|
|||||||
#include "logger.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QMetaEnum>
|
|
||||||
#include <QStandardPaths>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "version.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
QFile Logger::m_file;
|
|
||||||
QTextStream Logger::m_textStream;
|
|
||||||
QString Logger::m_logFileName = QString("%1.log").arg(SERVICE_NAME);
|
|
||||||
|
|
||||||
void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
|
|
||||||
{
|
|
||||||
if (msg.simplified().isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::m_textStream << qFormatLogMessage(type, context, msg) << Qt::endl << Qt::flush;
|
|
||||||
|
|
||||||
std::cout << qFormatLogMessage(type, context, msg).toStdString() << std::endl << std::flush;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Logger::init()
|
|
||||||
{
|
|
||||||
if (m_file.isOpen()) return true;
|
|
||||||
|
|
||||||
QString path = Utils::systemLogPath();
|
|
||||||
QDir appDir(path);
|
|
||||||
if (!appDir.mkpath(path)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
qSetMessagePattern("%{time yyyy-MM-dd hh:mm:ss} %{type} %{message}");
|
|
||||||
|
|
||||||
m_file.setFileName(appDir.filePath(m_logFileName));
|
|
||||||
if (!m_file.open(QIODevice::Append)) {
|
|
||||||
qWarning() << "Cannot open log file:" << m_logFileName;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_file.setTextModeEnabled(true);
|
|
||||||
m_textStream.setDevice(&m_file);
|
|
||||||
qInstallMessageHandler(debugMessageHandler);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::deinit()
|
|
||||||
{
|
|
||||||
m_file.close();
|
|
||||||
m_textStream.setDevice(nullptr);
|
|
||||||
qInstallMessageHandler(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Logger::serviceLogFileNamePath()
|
|
||||||
{
|
|
||||||
return m_file.fileName();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::clearLogs()
|
|
||||||
{
|
|
||||||
bool isLogActive = m_file.isOpen();
|
|
||||||
m_file.close();
|
|
||||||
|
|
||||||
|
|
||||||
QString path = Utils::systemLogPath();
|
|
||||||
QDir appDir(path);
|
|
||||||
QFile file;
|
|
||||||
file.setFileName(appDir.filePath(m_logFileName));
|
|
||||||
|
|
||||||
file.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
|
||||||
file.resize(0);
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
if (isLogActive) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::cleanUp()
|
|
||||||
{
|
|
||||||
clearLogs();
|
|
||||||
deinit();
|
|
||||||
|
|
||||||
QString path = Utils::systemLogPath();
|
|
||||||
QDir appDir(path);
|
|
||||||
|
|
||||||
{
|
|
||||||
QFile file;
|
|
||||||
file.setFileName(appDir.filePath(m_logFileName));
|
|
||||||
file.remove();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
QFile file;
|
|
||||||
file.setFileName(appDir.filePath("openvpn.log"));
|
|
||||||
file.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
QDir dir(Utils::systemLogPath());
|
|
||||||
dir.removeRecursively();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Logger::Log::Log(Logger* logger, LogLevel logLevel)
|
|
||||||
: m_logger(logger), m_logLevel(logLevel), m_data(new Data()) {}
|
|
||||||
|
|
||||||
Logger::Log::~Log() {
|
|
||||||
qDebug() << "Amnezia" << m_logger->className() << m_data->m_buffer.trimmed();
|
|
||||||
delete m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::Log Logger::error() { return Log(this, LogLevel::Error); }
|
|
||||||
Logger::Log Logger::warning() { return Log(this, LogLevel::Warning); }
|
|
||||||
Logger::Log Logger::info() { return Log(this, LogLevel::Info); }
|
|
||||||
Logger::Log Logger::debug() { return Log(this, LogLevel::Debug); }
|
|
||||||
QString Logger::sensitive(const QString& input) {
|
|
||||||
#ifdef Q_DEBUG
|
|
||||||
return input;
|
|
||||||
#else
|
|
||||||
Q_UNUSED(input);
|
|
||||||
return QString(8, 'X');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define CREATE_LOG_OP_REF(x) \
|
|
||||||
Logger::Log& Logger::Log::operator<<(x t) { \
|
|
||||||
m_data->m_ts << t << ' '; \
|
|
||||||
return *this; \
|
|
||||||
}
|
|
||||||
|
|
||||||
CREATE_LOG_OP_REF(uint64_t);
|
|
||||||
CREATE_LOG_OP_REF(const char*);
|
|
||||||
CREATE_LOG_OP_REF(const QString&);
|
|
||||||
CREATE_LOG_OP_REF(const QByteArray&);
|
|
||||||
CREATE_LOG_OP_REF(const void*);
|
|
||||||
|
|
||||||
#undef CREATE_LOG_OP_REF
|
|
||||||
|
|
||||||
Logger::Log& Logger::Log::operator<<(const QStringList& t) {
|
|
||||||
m_data->m_ts << '[' << t.join(",") << ']' << ' ';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::Log& Logger::Log::operator<<(const QJsonObject& t) {
|
|
||||||
m_data->m_ts << QJsonDocument(t).toJson(QJsonDocument::Indented) << ' ';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::Log& Logger::Log::operator<<(QTextStreamFunction t) {
|
|
||||||
m_data->m_ts << t;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Logger::Log::addMetaEnum(quint64 value, const QMetaObject* meta,
|
|
||||||
const char* name) {
|
|
||||||
QMetaEnum me = meta->enumerator(meta->indexOfEnumerator(name));
|
|
||||||
|
|
||||||
QString out;
|
|
||||||
QTextStream ts(&out);
|
|
||||||
|
|
||||||
if (const char* scope = me.scope()) {
|
|
||||||
ts << scope << "::";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* key = me.valueToKey(static_cast<int>(value));
|
|
||||||
const bool scoped = me.isScoped();
|
|
||||||
if (scoped || !key) {
|
|
||||||
ts << me.enumName() << (!key ? "(" : "::");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key) {
|
|
||||||
ts << key;
|
|
||||||
} else {
|
|
||||||
ts << value << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
m_data->m_ts << out;
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#ifndef LOGGER_H
|
|
||||||
#define LOGGER_H
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QString>
|
|
||||||
#include <QTextStream>
|
|
||||||
|
|
||||||
#include "mozilla/shared/loglevel.h"
|
|
||||||
|
|
||||||
class Logger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bool init();
|
|
||||||
static void deinit();
|
|
||||||
|
|
||||||
static QString serviceLogFileNamePath();
|
|
||||||
|
|
||||||
static void clearLogs();
|
|
||||||
static void cleanUp();
|
|
||||||
|
|
||||||
// compat with Mozilla logger
|
|
||||||
Logger(const QString &className) { m_className = className; }
|
|
||||||
const QString& className() const { return m_className; }
|
|
||||||
|
|
||||||
class Log {
|
|
||||||
public:
|
|
||||||
Log(Logger* logger, LogLevel level);
|
|
||||||
~Log();
|
|
||||||
|
|
||||||
Log& operator<<(uint64_t t);
|
|
||||||
Log& operator<<(const char* t);
|
|
||||||
Log& operator<<(const QString& t);
|
|
||||||
Log& operator<<(const QStringList& t);
|
|
||||||
Log& operator<<(const QByteArray& t);
|
|
||||||
Log& operator<<(const QJsonObject& t);
|
|
||||||
Log& operator<<(QTextStreamFunction t);
|
|
||||||
Log& operator<<(const void* t);
|
|
||||||
|
|
||||||
// Q_ENUM
|
|
||||||
template <typename T>
|
|
||||||
typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, Log&>::type
|
|
||||||
operator<<(T t) {
|
|
||||||
const QMetaObject* meta = qt_getEnumMetaObject(t);
|
|
||||||
const char* name = qt_getEnumName(t);
|
|
||||||
addMetaEnum(typename QFlags<T>::Int(t), meta, name);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void addMetaEnum(quint64 value, const QMetaObject* meta, const char* name);
|
|
||||||
|
|
||||||
Logger* m_logger;
|
|
||||||
LogLevel m_logLevel;
|
|
||||||
|
|
||||||
struct Data {
|
|
||||||
Data() : m_ts(&m_buffer, QIODevice::WriteOnly) {}
|
|
||||||
|
|
||||||
QString m_buffer;
|
|
||||||
QTextStream m_ts;
|
|
||||||
};
|
|
||||||
|
|
||||||
Data* m_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
Log error();
|
|
||||||
Log warning();
|
|
||||||
Log info();
|
|
||||||
Log debug();
|
|
||||||
QString sensitive(const QString& input);
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend void debugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
|
||||||
|
|
||||||
static QFile m_file;
|
|
||||||
static QString m_logFileName;
|
|
||||||
static QTextStream m_textStream;
|
|
||||||
|
|
||||||
// compat with Mozilla logger
|
|
||||||
QString m_className;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // LOGGER_H
|
|
||||||
@@ -44,7 +44,7 @@ int runApplication(int argc, char** argv)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Utils::initializePath(Utils::systemLogPath());
|
Utils::initializePath(Logger::systemLogDir());
|
||||||
|
|
||||||
if (argc >= 2) {
|
if (argc >= 2) {
|
||||||
qInfo() << "Started as console application";
|
qInfo() << "Started as console application";
|
||||||
|
|||||||
Reference in New Issue
Block a user