diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 3ea9a177..7eeacb22 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -16,7 +16,10 @@ jobs:
QT_VERSION: 6.6.2
QIF_VERSION: 4.7
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
+ DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
+ DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
steps:
- name: 'Install Qt'
@@ -83,7 +86,10 @@ jobs:
QIF_VERSION: 4.7
BUILD_ARCH: 64
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
+ DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
+ DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
steps:
- name: 'Get sources'
@@ -146,7 +152,10 @@ jobs:
CC: cc
CXX: c++
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
+ DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
+ DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
steps:
- name: 'Setup xcode'
@@ -238,7 +247,10 @@ jobs:
QT_VERSION: 6.4.3
QIF_VERSION: 4.6
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
+ DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
+ DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
steps:
- name: 'Setup xcode'
@@ -365,10 +377,13 @@ jobs:
env:
ANDROID_BUILD_PLATFORM: android-34
- QT_VERSION: 6.7.2
+ QT_VERSION: 6.7.3
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
+ DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
+ DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
steps:
- name: 'Install desktop Qt'
diff --git a/.github/workflows/tag-deploy.yml b/.github/workflows/tag-deploy.yml
index dffb3ab1..2bcbd8c6 100644
--- a/.github/workflows/tag-deploy.yml
+++ b/.github/workflows/tag-deploy.yml
@@ -16,7 +16,10 @@ jobs:
QT_VERSION: 6.4.1
QIF_VERSION: 4.5
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
+ PROD_S3_ENDPOINT: ${{ secrets.PROD_S3_ENDPOINT }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}
+ DEV_AGW_ENDPOINT: ${{ secrets.DEV_AGW_ENDPOINT }}
+ DEV_S3_ENDPOINT: ${{ secrets.DEV_S3_ENDPOINT }}
steps:
- name: 'Install desktop Qt'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3f1de5a..b6bed4c1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
set(PROJECT AmneziaVPN)
-project(${PROJECT} VERSION 4.8.1.9
+project(${PROJECT} VERSION 4.8.2.3
DESCRIPTION "AmneziaVPN"
HOMEPAGE_URL "https://amnezia.org/"
)
@@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
set(RELEASE_DATE "${CURRENT_DATE}")
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
-set(APP_ANDROID_VERSION_CODE 65)
+set(APP_ANDROID_VERSION_CODE 2069)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(MZ_PLATFORM_NAME "linux")
diff --git a/README.md b/README.md
index e4a6bf0c..eed800f5 100644
--- a/README.md
+++ b/README.md
@@ -10,21 +10,17 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
-
-
-
-
-
-
-
+
+[Alternative download link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org/downloads)
[All releases](https://github.com/amnezia-vpn/amnezia-client/releases)
+
## Features
@@ -37,7 +33,7 @@ Amnezia is an open-source VPN client, with a key feature that enables you to dep
## Links
-- [https://amnezia.org](https://amnezia.org) - project website
+- [https://amnezia.org](https://amnezia.org) - project website | [Alternative link (mirror)](https://storage.googleapis.com/kldscp/amnezia.org)
- [https://www.reddit.com/r/AmneziaVPN](https://www.reddit.com/r/AmneziaVPN) - Reddit
- [https://t.me/amnezia_vpn_en](https://t.me/amnezia_vpn_en) - Telegram support channel (English)
- [https://t.me/amnezia_vpn_ir](https://t.me/amnezia_vpn_ir) - Telegram support channel (Farsi)
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
index f5be0638..ca74e468 100644
--- a/client/CMakeLists.txt
+++ b/client/CMakeLists.txt
@@ -25,10 +25,11 @@ execute_process(
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
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_S3_ENDPOINT="$ENV{PROD_S3_ENDPOINT}")
add_definitions(-DDEV_AGW_PUBLIC_KEY="$ENV{DEV_AGW_PUBLIC_KEY}")
add_definitions(-DDEV_AGW_ENDPOINT="$ENV{DEV_AGW_ENDPOINT}")
+add_definitions(-DDEV_S3_ENDPOINT="$ENV{DEV_S3_ENDPOINT}")
if(IOS OR MACOS_NE)
set(PACKAGES ${PACKAGES} Multimedia)
diff --git a/client/amnezia_application.cpp b/client/amnezia_application.cpp
index 2d06b443..4e25097d 100644
--- a/client/amnezia_application.cpp
+++ b/client/amnezia_application.cpp
@@ -111,10 +111,11 @@ void AmneziaApplication::init()
qFatal("Android controller initialization failed");
}
- connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, [this](QString data) {
- m_pageController->goToPageHome();
+ connect(AndroidController::instance(), &AndroidController::importConfigFromOutside, this, [this](QString data) {
+ emit m_pageController->goToPageHome();
m_importController->extractConfigFromData(data);
- m_pageController->goToPageViewConfig();
+ data.clear();
+ emit m_pageController->goToPageViewConfig();
});
m_engine->addImageProvider(QLatin1String("installedAppImage"), new InstalledAppsImageProvider);
@@ -122,16 +123,16 @@ void AmneziaApplication::init()
#ifdef Q_OS_IOS
IosController::Instance()->initialize();
- connect(IosController::Instance(), &IosController::importConfigFromOutside, [this](QString data) {
- m_pageController->goToPageHome();
+ connect(IosController::Instance(), &IosController::importConfigFromOutside, this, [this](QString data) {
+ emit m_pageController->goToPageHome();
m_importController->extractConfigFromData(data);
- m_pageController->goToPageViewConfig();
+ emit m_pageController->goToPageViewConfig();
});
- connect(IosController::Instance(), &IosController::importBackupFromOutside, [this](QString filePath) {
- m_pageController->goToPageHome();
+ connect(IosController::Instance(), &IosController::importBackupFromOutside, this, [this](QString filePath) {
+ emit m_pageController->goToPageHome();
m_pageController->goToPageSettingsBackup();
- m_settingsController->importBackupFromOutside(filePath);
+ emit m_settingsController->importBackupFromOutside(filePath);
});
QTimer::singleShot(0, this, [this]() { AmneziaVPN::toggleScreenshots(m_settings->isScreenshotsEnabled()); });
diff --git a/client/android/gradle.properties b/client/android/gradle.properties
index 5a27838c..ce651e1c 100644
--- a/client/android/gradle.properties
+++ b/client/android/gradle.properties
@@ -33,7 +33,7 @@ android.library.defaults.buildfeatures.androidresources=false
# For development copy and set local values for these parameters in local.properties
#androidCompileSdkVersion=android-34
#androidBuildToolsVersion=34.0.0
-#qtMinSdkVersion=24
+#qtMinSdkVersion=26
#qtTargetSdkVersion=34
#androidNdkVersion=26.1.10909125
#qtTargetAbiList=x86_64
diff --git a/client/android/protocolApi/src/main/kotlin/Protocol.kt b/client/android/protocolApi/src/main/kotlin/Protocol.kt
index b5c382be..6e682aa4 100644
--- a/client/android/protocolApi/src/main/kotlin/Protocol.kt
+++ b/client/android/protocolApi/src/main/kotlin/Protocol.kt
@@ -1,6 +1,5 @@
package org.amnezia.vpn.protocol
-import android.annotation.SuppressLint
import android.content.Context
import android.net.IpPrefix
import android.net.VpnService
@@ -8,9 +7,6 @@ import android.net.VpnService.Builder
import android.os.Build
import android.system.OsConstants
import androidx.annotation.RequiresApi
-import java.io.File
-import java.io.FileOutputStream
-import java.util.zip.ZipFile
import kotlinx.coroutines.flow.MutableStateFlow
import org.amnezia.vpn.util.Log
import org.amnezia.vpn.util.net.InetNetwork
diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
index d5026425..b2c2ff71 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt
@@ -21,6 +21,7 @@ import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.provider.Settings
+import android.view.MotionEvent
import android.view.WindowManager.LayoutParams
import android.webkit.MimeTypeMap
import android.widget.Toast
@@ -158,7 +159,7 @@ class AmneziaActivity : QtActivity() {
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- Log.d(TAG, "Create Amnezia activity: $intent")
+ Log.d(TAG, "Create Amnezia activity")
loadLibs()
window.apply {
addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
@@ -200,7 +201,7 @@ class AmneziaActivity : QtActivity() {
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED
)
) {
- Log.d(
+ Log.v(
TAG, "Notification state changed: ${it?.action}, blocked = " +
"${it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)}"
)
@@ -214,7 +215,7 @@ class AmneziaActivity : QtActivity() {
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
- Log.d(TAG, "onNewIntent: $intent")
+ Log.v(TAG, "onNewIntent: $intent")
intent?.let(::processIntent)
}
@@ -403,7 +404,7 @@ class AmneziaActivity : QtActivity() {
@MainThread
private fun startVpn(vpnConfig: String) {
getVpnProto(vpnConfig)?.let { proto ->
- Log.d(TAG, "Proto from config: $proto, current proto: $vpnProto")
+ Log.v(TAG, "Proto from config: $proto, current proto: $vpnProto")
if (isServiceConnected) {
if (proto.serviceClass == vpnProto?.serviceClass) {
vpnProto = proto
@@ -516,7 +517,7 @@ class AmneziaActivity : QtActivity() {
startActivityForResult(it, CREATE_FILE_ACTION_CODE, ActivityResultHandler(
onSuccess = {
it?.data?.let { uri ->
- Log.d(TAG, "Save file to $uri")
+ Log.v(TAG, "Save file to $uri")
try {
contentResolver.openOutputStream(uri)?.use { os ->
os.bufferedWriter().use { it.write(data) }
@@ -565,7 +566,7 @@ class AmneziaActivity : QtActivity() {
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
onAny = {
val uri = it?.data?.toString() ?: ""
- Log.d(TAG, "Open file: $uri")
+ Log.v(TAG, "Open file: $uri")
mainScope.launch {
qtInitialized.await()
QtAndroidController.onFileOpened(uri)
@@ -720,6 +721,66 @@ class AmneziaActivity : QtActivity() {
}
}
+ // workaround for a bug in Qt that causes the mouse click event not to be handled
+ // also disable right-click, as it causes the application to crash
+ private var lastButtonState = 0
+ private fun MotionEvent.fixCopy(): MotionEvent = MotionEvent.obtain(
+ downTime,
+ eventTime,
+ action,
+ pointerCount,
+ (0 until pointerCount).map { i ->
+ MotionEvent.PointerProperties().apply {
+ getPointerProperties(i, this)
+ }
+ }.toTypedArray(),
+ (0 until pointerCount).map { i ->
+ MotionEvent.PointerCoords().apply {
+ getPointerCoords(i, this)
+ }
+ }.toTypedArray(),
+ metaState,
+ MotionEvent.BUTTON_PRIMARY,
+ xPrecision,
+ yPrecision,
+ deviceId,
+ edgeFlags,
+ source,
+ flags
+ )
+
+ private fun handleMouseEvent(ev: MotionEvent, superDispatch: (MotionEvent?) -> Boolean): Boolean {
+ when (ev.action) {
+ MotionEvent.ACTION_DOWN -> {
+ lastButtonState = ev.buttonState
+ if (ev.buttonState == MotionEvent.BUTTON_SECONDARY) return true
+ }
+
+ MotionEvent.ACTION_UP -> {
+ when (lastButtonState) {
+ MotionEvent.BUTTON_SECONDARY -> return true
+ MotionEvent.BUTTON_PRIMARY -> {
+ val modEvent = ev.fixCopy()
+ return superDispatch(modEvent).apply { modEvent.recycle() }
+ }
+ }
+ }
+ }
+ return superDispatch(ev)
+ }
+
+ override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
+ if (ev != null && ev.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
+ return handleMouseEvent(ev) { super.dispatchTouchEvent(it) }
+ }
+ return super.dispatchTouchEvent(ev)
+ }
+
+ override fun dispatchTrackballEvent(ev: MotionEvent?): Boolean {
+ ev?.let { return handleMouseEvent(ev) { super.dispatchTrackballEvent(it) }}
+ return super.dispatchTrackballEvent(ev)
+ }
+
/**
* Utils methods
*/
diff --git a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
index 937127ee..8d108bc3 100644
--- a/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
+++ b/client/android/src/org/amnezia/vpn/AmneziaVpnService.kt
@@ -300,7 +300,7 @@ open class AmneziaVpnService : VpnService() {
arrayOf(ACTION_CONNECT, ACTION_DISCONNECT), ContextCompat.RECEIVER_NOT_EXPORTED
) {
it?.action?.let { action ->
- Log.d(TAG, "Broadcast request received: $action")
+ Log.v(TAG, "Broadcast request received: $action")
when (action) {
ACTION_CONNECT -> connect()
ACTION_DISCONNECT -> disconnect()
@@ -317,7 +317,7 @@ open class AmneziaVpnService : VpnService() {
)
) {
val state = it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)
- Log.d(TAG, "Notification state changed: ${it?.action}, blocked = $state")
+ Log.v(TAG, "Notification state changed: ${it?.action}, blocked = $state")
if (state == false) {
enableNotification()
} else {
@@ -450,7 +450,7 @@ open class AmneziaVpnService : VpnService() {
serviceNotification.isNotificationEnabled() &&
getSystemService()?.isInteractive != false
) {
- Log.d(TAG, "Launch traffic stats update")
+ Log.v(TAG, "Launch traffic stats update")
trafficStats.reset()
startTrafficStatsUpdateJob()
}
diff --git a/client/android/src/org/amnezia/vpn/AuthActivity.kt b/client/android/src/org/amnezia/vpn/AuthActivity.kt
index 2593315c..46401548 100644
--- a/client/android/src/org/amnezia/vpn/AuthActivity.kt
+++ b/client/android/src/org/amnezia/vpn/AuthActivity.kt
@@ -66,7 +66,7 @@ class AuthActivity : FragmentActivity() {
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: AuthenticationResult) {
super.onAuthenticationSucceeded(result)
- Log.d(TAG, "Authentication succeeded")
+ Log.v(TAG, "Authentication succeeded")
QtAndroidController.onAuthResult(true)
finish()
}
diff --git a/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt b/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt
index 9faa30d0..49823a36 100644
--- a/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt
+++ b/client/android/src/org/amnezia/vpn/ImportConfigActivity.kt
@@ -29,20 +29,20 @@ class ImportConfigActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- Log.d(TAG, "Create Import Config Activity: $intent")
+ Log.v(TAG, "Create Import Config Activity: $intent")
intent?.let(::readConfig)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
- Log.d(TAG, "onNewIntent: $intent")
+ Log.v(TAG, "onNewIntent: $intent")
intent.let(::readConfig)
}
private fun readConfig(intent: Intent) {
when (intent.action) {
ACTION_SEND -> {
- Log.d(TAG, "Process SEND action, type: ${intent.type}")
+ Log.v(TAG, "Process SEND action, type: ${intent.type}")
when (intent.type) {
"application/octet-stream" -> {
intent.getUriCompat()?.let { uri ->
@@ -60,7 +60,7 @@ class ImportConfigActivity : ComponentActivity() {
}
ACTION_VIEW -> {
- Log.d(TAG, "Process VIEW action, scheme: ${intent.scheme}")
+ Log.v(TAG, "Process VIEW action, scheme: ${intent.scheme}")
when (intent.scheme) {
"file", "content" -> {
intent.data?.let { uri ->
diff --git a/client/android/src/org/amnezia/vpn/ServiceNotification.kt b/client/android/src/org/amnezia/vpn/ServiceNotification.kt
index f4707731..47e8f263 100644
--- a/client/android/src/org/amnezia/vpn/ServiceNotification.kt
+++ b/client/android/src/org/amnezia/vpn/ServiceNotification.kt
@@ -62,7 +62,7 @@ class ServiceNotification(private val context: Context) {
fun buildNotification(serverName: String?, protocol: String?, state: ProtocolState): Notification {
val speedString = if (state == CONNECTED) zeroSpeed else null
- Log.d(TAG, "Build notification: $serverName, $state")
+ Log.v(TAG, "Build notification: $serverName, $state")
return notificationBuilder
.setSmallIcon(R.drawable.ic_amnezia_round)
@@ -88,17 +88,15 @@ class ServiceNotification(private val context: Context) {
fun isNotificationEnabled(): Boolean {
if (!context.isNotificationPermissionGranted()) return false
if (!notificationManager.areNotificationsEnabled()) return false
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
- ?.let { it.importance != NotificationManager.IMPORTANCE_NONE } ?: true
- }
- return true
+ return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)?.let {
+ it.importance != NotificationManager.IMPORTANCE_NONE
+ } ?: true
}
@SuppressLint("MissingPermission")
fun updateNotification(serverName: String?, protocol: String?, state: ProtocolState) {
if (context.isNotificationPermissionGranted()) {
- Log.d(TAG, "Update notification: $serverName, $state")
+ Log.v(TAG, "Update notification: $serverName, $state")
notificationManager.notify(NOTIFICATION_ID, buildNotification(serverName, protocol, state))
}
}
diff --git a/client/android/utils/src/main/kotlin/LibraryLoader.kt b/client/android/utils/src/main/kotlin/LibraryLoader.kt
index f1c6465e..8def18d0 100644
--- a/client/android/utils/src/main/kotlin/LibraryLoader.kt
+++ b/client/android/utils/src/main/kotlin/LibraryLoader.kt
@@ -46,7 +46,7 @@ object LibraryLoader {
System.loadLibrary(libraryName)
return
} catch (_: UnsatisfiedLinkError) {
- Log.d(TAG, "Failed to load library, try to extract it from apk")
+ Log.w(TAG, "Failed to load library, try to extract it from apk")
}
var tempFile: File? = null
try {
diff --git a/client/android/utils/src/main/kotlin/Log.kt b/client/android/utils/src/main/kotlin/Log.kt
index a656b9ea..da11c200 100644
--- a/client/android/utils/src/main/kotlin/Log.kt
+++ b/client/android/utils/src/main/kotlin/Log.kt
@@ -1,8 +1,6 @@
package org.amnezia.vpn.util
import android.content.Context
-import android.icu.text.DateFormat
-import android.icu.text.SimpleDateFormat
import android.os.Build
import android.os.Process
import java.io.File
@@ -12,8 +10,6 @@ import java.nio.channels.FileChannel
import java.nio.channels.FileLock
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
-import java.util.Date
-import java.util.Locale
import java.util.concurrent.locks.ReentrantLock
import org.amnezia.vpn.util.Log.Priority.D
import org.amnezia.vpn.util.Log.Priority.E
@@ -41,11 +37,7 @@ private const val LOG_MAX_FILE_SIZE = 1024 * 1024
* | | | create a report and/or terminate the process |
*/
object Log {
- private val dateTimeFormat: Any =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)
- else object : ThreadLocal() {
- override fun initialValue(): DateFormat = SimpleDateFormat(DATE_TIME_PATTERN, Locale.US)
- }
+ private val dateTimeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)
private lateinit var logDir: File
private val logFile: File by lazy { File(logDir, LOG_FILE_NAME) }
@@ -143,12 +135,7 @@ object Log {
}
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
- val date = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- LocalDateTime.now().format(dateTimeFormat as DateTimeFormatter)
- } else {
- @Suppress("UNCHECKED_CAST")
- (dateTimeFormat as ThreadLocal).get()?.format(Date())
- }
+ val date = LocalDateTime.now().format(dateTimeFormat)
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
"$tag: $msg\n"
}
diff --git a/client/android/utils/src/main/kotlin/net/NetworkState.kt b/client/android/utils/src/main/kotlin/net/NetworkState.kt
index b71bf393..1cab5535 100644
--- a/client/android/utils/src/main/kotlin/net/NetworkState.kt
+++ b/client/android/utils/src/main/kotlin/net/NetworkState.kt
@@ -42,18 +42,12 @@ class NetworkState(
private val networkCallback: NetworkCallback by lazy(NONE) {
object : NetworkCallback() {
override fun onAvailable(network: Network) {
- Log.d(TAG, "onAvailable: $network")
+ Log.v(TAG, "onAvailable: $network")
}
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
- Log.d(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- checkNetworkState(network, networkCapabilities)
- } else {
- handler.post {
- checkNetworkState(network, networkCapabilities)
- }
- }
+ Log.v(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
+ checkNetworkState(network, networkCapabilities)
}
private fun checkNetworkState(network: Network, networkCapabilities: NetworkCapabilities) {
@@ -73,11 +67,11 @@ class NetworkState(
}
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
- Log.d(TAG, "onBlockedStatusChanged: $network, $blocked")
+ Log.v(TAG, "onBlockedStatusChanged: $network, $blocked")
}
override fun onLost(network: Network) {
- Log.d(TAG, "onLost: $network")
+ Log.v(TAG, "onLost: $network")
}
}
}
@@ -87,7 +81,7 @@ class NetworkState(
Log.d(TAG, "Bind network listener")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ } else {
val numberAttempts = 300
var attemptCount = 0
while(true) {
@@ -108,8 +102,6 @@ class NetworkState(
}
}
}
- } else {
- connectivityManager.requestNetwork(networkRequest, networkCallback)
}
isListenerBound = true
}
diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
index ac11374b..e93834f4 100644
--- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
+++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt
@@ -66,7 +66,7 @@ open class Wireguard : Protocol() {
try {
delay(1000)
var log = getLogcat(time)
- Log.d(TAG, "First waiting log: $log")
+ Log.v(TAG, "First waiting log: $log")
// check that there is a connection log,
// to avoid infinite connection
if (!log.contains("Attaching to interface")) {
diff --git a/client/android/xray/src/main/kotlin/Xray.kt b/client/android/xray/src/main/kotlin/Xray.kt
index 6e37c9c2..08242525 100644
--- a/client/android/xray/src/main/kotlin/Xray.kt
+++ b/client/android/xray/src/main/kotlin/Xray.kt
@@ -130,8 +130,8 @@ class Xray : Protocol() {
LibXray.initXray(assetsPath)
val geoDir = File(assetsPath, "geo").absolutePath
val configPath = File(context.cacheDir, "config.json")
- Log.d(TAG, "xray.location.asset: $geoDir")
- Log.d(TAG, "config: $configPath")
+ Log.v(TAG, "xray.location.asset: $geoDir")
+ Log.v(TAG, "config: $configPath")
try {
configPath.writeText(configJson)
} catch (e: IOException) {
diff --git a/client/cmake/android.cmake b/client/cmake/android.cmake
index c96d9ab8..34ca5bff 100644
--- a/client/cmake/android.cmake
+++ b/client/cmake/android.cmake
@@ -1,6 +1,6 @@
message("Client android ${CMAKE_ANDROID_ARCH_ABI} build")
-set(APP_ANDROID_MIN_SDK 24)
+set(APP_ANDROID_MIN_SDK 26)
set(ANDROID_PLATFORM "android-${APP_ANDROID_MIN_SDK}" CACHE STRING
"The minimum API level supported by the application or library" FORCE)
diff --git a/client/core/controllers/apiController.cpp b/client/core/controllers/apiController.cpp
index 5cdaa7ae..75a3f93c 100644
--- a/client/core/controllers/apiController.cpp
+++ b/client/core/controllers/apiController.cpp
@@ -1,5 +1,8 @@
#include "apiController.h"
+#include
+#include
+
#include
#include
#include
@@ -11,6 +14,7 @@
#include "amnezia_application.h"
#include "configurators/wireguard_configurator.h"
#include "core/enums/apiEnums.h"
+#include "utilities.h"
#include "version.h"
namespace
@@ -33,6 +37,7 @@ namespace
constexpr char userCountryCode[] = "user_country_code";
constexpr char serverCountryCode[] = "server_country_code";
constexpr char serviceType[] = "service_type";
+ constexpr char serviceInfo[] = "service_info";
constexpr char aesKey[] = "aes_key";
constexpr char aesIv[] = "aes_iv";
@@ -40,9 +45,10 @@ namespace
constexpr char apiPayload[] = "api_payload";
constexpr char keyPayload[] = "key_payload";
- }
- const QStringList proxyStorageUrl = { "" };
+ constexpr char apiConfig[] = "api_config";
+ constexpr char authData[] = "auth_data";
+ }
ErrorCode checkErrors(const QList &sslErrors, QNetworkReply *reply)
{
@@ -63,6 +69,28 @@ namespace
return ErrorCode::ApiConfigDownloadError;
}
}
+
+ bool shouldBypassProxy(QNetworkReply *reply, const QByteArray &responseBody, bool checkEncryption, const QByteArray &key = "",
+ const QByteArray &iv = "", const QByteArray &salt = "")
+ {
+ if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError
+ || reply->error() == QNetworkReply::NetworkError::TimeoutError) {
+ qDebug() << "Timeout occurred";
+ return true;
+ } else if (responseBody.contains("html")) {
+ qDebug() << "The response contains an html tag";
+ return true;
+ } else if (checkEncryption) {
+ try {
+ QSimpleCrypto::QBlockCipher blockCipher;
+ static_cast(blockCipher.decryptAesBlockCipher(responseBody, key, iv, "", salt));
+ } catch (...) {
+ qDebug() << "Failed to decrypt the data";
+ return true;
+ }
+ }
+ return false;
+ }
}
ApiController::ApiController(const QString &gatewayEndpoint, bool isDevEnvironment, QObject *parent)
@@ -94,8 +122,8 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
configStr.replace("$OPENVPN_PRIV_KEY", apiPayloadData.certRequest.privKey);
} else if (protocol == configKey::awg) {
configStr.replace("$WIREGUARD_CLIENT_PRIVATE_KEY", apiPayloadData.wireGuardClientPrivKey);
- auto serverConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
- auto containers = serverConfig.value(config_key::containers).toArray();
+ auto newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
+ auto containers = newServerConfig.value(config_key::containers).toArray();
if (containers.isEmpty()) {
return; // todo process error
}
@@ -114,25 +142,35 @@ void ApiController::fillServerConfig(const QString &protocol, const ApiControlle
containerConfig[config_key::transportPacketMagicHeader] = protocolConfig.value(config_key::transportPacketMagicHeader);
container[containerName] = containerConfig;
containers.replace(0, container);
- serverConfig[config_key::containers] = containers;
- configStr = QString(QJsonDocument(serverConfig).toJson());
+ newServerConfig[config_key::containers] = containers;
+ configStr = QString(QJsonDocument(newServerConfig).toJson());
}
- QJsonObject apiConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
- serverConfig[config_key::dns1] = apiConfig.value(config_key::dns1);
- serverConfig[config_key::dns2] = apiConfig.value(config_key::dns2);
- serverConfig[config_key::containers] = apiConfig.value(config_key::containers);
- serverConfig[config_key::hostName] = apiConfig.value(config_key::hostName);
+ QJsonObject newServerConfig = QJsonDocument::fromJson(configStr.toUtf8()).object();
+ serverConfig[config_key::dns1] = newServerConfig.value(config_key::dns1);
+ serverConfig[config_key::dns2] = newServerConfig.value(config_key::dns2);
+ serverConfig[config_key::containers] = newServerConfig.value(config_key::containers);
+ serverConfig[config_key::hostName] = newServerConfig.value(config_key::hostName);
- if (apiConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
- serverConfig[config_key::configVersion] = apiConfig.value(config_key::configVersion);
- serverConfig[config_key::description] = apiConfig.value(config_key::description);
- serverConfig[config_key::name] = apiConfig.value(config_key::name);
+ if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
+ serverConfig[config_key::configVersion] = newServerConfig.value(config_key::configVersion);
+ serverConfig[config_key::description] = newServerConfig.value(config_key::description);
+ serverConfig[config_key::name] = newServerConfig.value(config_key::name);
}
- auto defaultContainer = apiConfig.value(config_key::defaultContainer).toString();
+ auto defaultContainer = newServerConfig.value(config_key::defaultContainer).toString();
serverConfig[config_key::defaultContainer] = defaultContainer;
+ QVariantMap map = serverConfig.value(configKey::apiConfig).toObject().toVariantMap();
+ map.insert(newServerConfig.value(configKey::apiConfig).toObject().toVariantMap());
+ auto apiConfig = QJsonObject::fromVariantMap(map);
+
+ if (newServerConfig.value(config_key::configVersion).toInt() == ApiConfigSources::AmneziaGateway) {
+ apiConfig.insert(configKey::serviceInfo, QJsonDocument::fromJson(apiResponseBody).object().value(configKey::serviceInfo).toObject());
+ }
+
+ serverConfig[configKey::apiConfig] = apiConfig;
+
return;
}
@@ -146,6 +184,15 @@ QStringList ApiController::getProxyUrls()
QList sslErrors;
QNetworkReply *reply;
+ QStringList proxyStorageUrl;
+ if (m_isDevEnvironment) {
+ proxyStorageUrl = QStringList { DEV_S3_ENDPOINT };
+ } else {
+ proxyStorageUrl = QStringList { PROD_S3_ENDPOINT };
+ }
+
+ QByteArray key = m_isDevEnvironment ? DEV_AGW_PUBLIC_KEY : PROD_AGW_PUBLIC_KEY;
+
for (const auto &proxyStorageUrl : proxyStorageUrl) {
request.setUrl(proxyStorageUrl);
reply = amnApp->manager()->get(request);
@@ -166,11 +213,23 @@ QStringList ApiController::getProxyUrls()
EVP_PKEY *privateKey = nullptr;
QByteArray responseBody;
try {
- QByteArray key = PROD_PROXY_STORAGE_KEY;
- QSimpleCrypto::QRsa rsa;
- privateKey = rsa.getPrivateKeyFromByteArray(key, "");
- responseBody = rsa.decrypt(encryptedResponseBody, privateKey, RSA_PKCS1_PADDING);
+ if (!m_isDevEnvironment) {
+ QCryptographicHash hash(QCryptographicHash::Sha512);
+ hash.addData(key);
+ QByteArray hashResult = hash.result().toHex();
+
+ QByteArray key = QByteArray::fromHex(hashResult.left(64));
+ QByteArray iv = QByteArray::fromHex(hashResult.mid(64, 32));
+
+ QByteArray ba = QByteArray::fromBase64(encryptedResponseBody);
+
+ QSimpleCrypto::QBlockCipher blockCipher;
+ responseBody = blockCipher.decryptAesBlockCipher(ba, key, iv);
+ } else {
+ responseBody = encryptedResponseBody;
+ }
} catch (...) {
+ Utils::logException();
qCritical() << "error loading private key from environment variables or decrypting payload";
return {};
}
@@ -292,38 +351,44 @@ ErrorCode ApiController::getServicesList(QByteArray &responseBody)
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
wait.exec();
- if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
+ responseBody = reply->readAll();
+
+ if (sslErrors.isEmpty() && shouldBypassProxy(reply, responseBody, false)) {
m_proxyUrls = getProxyUrls();
+ std::random_device randomDevice;
+ std::mt19937 generator(randomDevice());
+ std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
for (const QString &proxyUrl : m_proxyUrls) {
+ qDebug() << "Go to the next endpoint";
request.setUrl(QString("%1v1/services").arg(proxyUrl));
+ reply->deleteLater(); // delete the previous reply
reply = amnApp->manager()->get(request);
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
wait.exec();
- if (reply->error() != QNetworkReply::NetworkError::TimeoutError
- && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
+
+ responseBody = reply->readAll();
+ if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, responseBody, false)) {
break;
}
- reply->deleteLater();
}
}
- responseBody = reply->readAll();
auto errorCode = checkErrors(sslErrors, reply);
reply->deleteLater();
return errorCode;
}
ErrorCode ApiController::getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
- const QString &protocol, const QString &serverCountryCode, QJsonObject &serverConfig)
+ const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData,
+ QJsonObject &serverConfig)
{
#ifdef Q_OS_IOS
IosController::Instance()->requestInetAccess();
QThread::msleep(10);
#endif
- QNetworkAccessManager manager;
QNetworkRequest request;
request.setTransferTimeout(7000);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
@@ -339,6 +404,9 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
}
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::uuid] = installationUuid;
+ if (!authData.isEmpty()) {
+ apiPayload[configKey::authData] = authData;
+ }
QSimpleCrypto::QBlockCipher blockCipher;
QByteArray key = blockCipher.generatePrivateSalt(32);
@@ -361,6 +429,7 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
QSimpleCrypto::QRsa rsa;
publicKey = rsa.getPublicKeyFromByteArray(rsaKey);
} catch (...) {
+ Utils::logException();
qCritical() << "error loading public key from environment variables";
return ErrorCode::ApiMissingAgwPublicKey;
}
@@ -370,14 +439,16 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
encryptedApiPayload = blockCipher.encryptAesBlockCipher(QJsonDocument(apiPayload).toJson(), key, iv, "", salt);
} catch (...) { // todo change error handling in QSimpleCrypto?
+ Utils::logException();
qCritical() << "error when encrypting the request body";
+ return ErrorCode::ApiConfigDecryptionError;
}
QJsonObject requestBody;
requestBody[configKey::keyPayload] = QString(encryptedKeyPayload.toBase64());
requestBody[configKey::apiPayload] = QString(encryptedApiPayload.toBase64());
- QNetworkReply *reply = manager.post(request, QJsonDocument(requestBody).toJson());
+ QNetworkReply *reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
QEventLoop wait;
connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
@@ -386,37 +457,43 @@ ErrorCode ApiController::getConfigForService(const QString &installationUuid, co
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
wait.exec();
- if (reply->error() == QNetworkReply::NetworkError::TimeoutError || reply->error() == QNetworkReply::NetworkError::OperationCanceledError) {
- if (m_proxyUrls.isEmpty()) {
- m_proxyUrls = getProxyUrls();
- }
+ auto encryptedResponseBody = reply->readAll();
+
+ if (sslErrors.isEmpty() && shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
+ m_proxyUrls = getProxyUrls();
+ std::random_device randomDevice;
+ std::mt19937 generator(randomDevice());
+ std::shuffle(m_proxyUrls.begin(), m_proxyUrls.end(), generator);
for (const QString &proxyUrl : m_proxyUrls) {
+ qDebug() << "Go to the next endpoint";
request.setUrl(QString("%1v1/config").arg(proxyUrl));
- reply = manager.post(request, QJsonDocument(requestBody).toJson());
+ reply->deleteLater(); // delete the previous reply
+ reply = amnApp->manager()->post(request, QJsonDocument(requestBody).toJson());
QObject::connect(reply, &QNetworkReply::finished, &wait, &QEventLoop::quit);
connect(reply, &QNetworkReply::sslErrors, [this, &sslErrors](const QList &errors) { sslErrors = errors; });
wait.exec();
- if (reply->error() != QNetworkReply::NetworkError::TimeoutError
- && reply->error() != QNetworkReply::NetworkError::OperationCanceledError) {
+
+ encryptedResponseBody = reply->readAll();
+ if (!sslErrors.isEmpty() || !shouldBypassProxy(reply, encryptedResponseBody, true, key, iv, salt)) {
break;
}
- reply->deleteLater();
}
}
auto errorCode = checkErrors(sslErrors, reply);
+ reply->deleteLater();
if (errorCode) {
return errorCode;
}
- auto encryptedResponseBody = reply->readAll();
- reply->deleteLater();
try {
auto responseBody = blockCipher.decryptAesBlockCipher(encryptedResponseBody, key, iv, "", salt);
fillServerConfig(protocol, apiPayloadData, responseBody, serverConfig);
} catch (...) { // todo change error handling in QSimpleCrypto?
+ Utils::logException();
qCritical() << "error when decrypting the request body";
+ return ErrorCode::ApiConfigDecryptionError;
}
return errorCode;
diff --git a/client/core/controllers/apiController.h b/client/core/controllers/apiController.h
index 1f811498..bcb25f96 100644
--- a/client/core/controllers/apiController.h
+++ b/client/core/controllers/apiController.h
@@ -21,7 +21,7 @@ public slots:
ErrorCode getServicesList(QByteArray &responseBody);
ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
- const QString &protocol, const QString &serverCountryCode, QJsonObject &serverConfig);
+ const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData, QJsonObject &serverConfig);
signals:
void errorOccurred(ErrorCode errorCode);
diff --git a/client/core/defs.h b/client/core/defs.h
index ebc07f4b..d00d347b 100644
--- a/client/core/defs.h
+++ b/client/core/defs.h
@@ -96,6 +96,7 @@ namespace amnezia
// import and install errors
ImportInvalidConfigError = 900,
+ ImportOpenConfigError = 901,
// Android errors
AndroidError = 1000,
@@ -107,6 +108,7 @@ namespace amnezia
ApiConfigTimeoutError = 1103,
ApiConfigSslError = 1104,
ApiMissingAgwPublicKey = 1105,
+ ApiConfigDecryptionError = 1106,
// QFile errors
OpenError = 1200,
diff --git a/client/core/errorstrings.cpp b/client/core/errorstrings.cpp
index 8c16d786..49534606 100644
--- a/client/core/errorstrings.cpp
+++ b/client/core/errorstrings.cpp
@@ -50,6 +50,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::AddressPoolError): errorMessage = QObject::tr("VPN pool error: no available addresses"); break;
case (ErrorCode::ImportInvalidConfigError): errorMessage = QObject::tr("The config does not contain any containers and credentials for connecting to the server"); break;
+ case (ErrorCode::ImportOpenConfigError): errorMessage = QObject::tr("Unable to open config file"); break;
// Android errors
case (ErrorCode::AndroidError): errorMessage = QObject::tr("VPN connection error"); break;
@@ -61,6 +62,7 @@ QString errorString(ErrorCode code) {
case (ErrorCode::ApiConfigSslError): errorMessage = QObject::tr("SSL error occurred"); break;
case (ErrorCode::ApiConfigTimeoutError): errorMessage = QObject::tr("Server response timeout on api request"); break;
case (ErrorCode::ApiMissingAgwPublicKey): errorMessage = QObject::tr("Missing AGW public key"); break;
+ case (ErrorCode::ApiConfigDecryptionError): errorMessage = QObject::tr("Failed to decrypt response payload"); break;
// QFile errors
case(ErrorCode::OpenError): errorMessage = QObject::tr("QFile error: The file could not be opened"); break;
diff --git a/client/daemon/daemon.cpp b/client/daemon/daemon.cpp
index 3e237e9c..a234860b 100644
--- a/client/daemon/daemon.cpp
+++ b/client/daemon/daemon.cpp
@@ -78,7 +78,7 @@ bool Daemon::activate(const InterfaceConfig& config) {
return false;
}
- if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
+ if (!dnsutils()->restoreResolvers()) {
return false;
}
@@ -165,10 +165,6 @@ bool Daemon::activate(const InterfaceConfig& config) {
}
bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) {
- if (!supportDnsUtils()) {
- return true;
- }
-
if ((config.m_hopType == InterfaceConfig::MultiHopExit) ||
(config.m_hopType == InterfaceConfig::SingleHop)) {
QList resolvers;
@@ -423,13 +419,8 @@ bool Daemon::deactivate(bool emitSignals) {
}
// Cleanup DNS
- if (supportDnsUtils() && !dnsutils()->restoreResolvers()) {
- return false;
- }
-
- if (!wgutils()->interfaceExists()) {
- logger.warning() << "Wireguard interface does not exist.";
- return false;
+ if (!dnsutils()->restoreResolvers()) {
+ logger.warning() << "Failed to restore DNS resolvers.";
}
// Cleanup peers and routing
@@ -449,13 +440,9 @@ bool Daemon::deactivate(bool emitSignals) {
}
m_excludedAddrSet.clear();
- // Delete the interface
- if (!wgutils()->deleteInterface()) {
- return false;
- }
-
m_connections.clear();
- return true;
+ // Delete the interface
+ return wgutils()->deleteInterface();
}
QString Daemon::logs() {
diff --git a/client/daemon/daemon.h b/client/daemon/daemon.h
index d3d8c34d..3d418d70 100644
--- a/client/daemon/daemon.h
+++ b/client/daemon/daemon.h
@@ -69,7 +69,6 @@ class Daemon : public QObject {
virtual WireguardUtils* wgutils() const = 0;
virtual bool supportIPUtils() const { return false; }
virtual IPUtils* iputils() { return nullptr; }
- virtual bool supportDnsUtils() const { return false; }
virtual DnsUtils* dnsutils() { return nullptr; }
static bool parseStringList(const QJsonObject& obj, const QString& name,
diff --git a/client/daemon/daemonlocalserverconnection.cpp b/client/daemon/daemonlocalserverconnection.cpp
index 1a49b7e5..edbc4c9b 100644
--- a/client/daemon/daemonlocalserverconnection.cpp
+++ b/client/daemon/daemonlocalserverconnection.cpp
@@ -92,6 +92,17 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
logger.debug() << "Command received:" << type;
+ // It is expected that sometimes the client will request backend logs
+ // before the first authentication. In these cases we just return empty
+ // logs.
+ if (type == "logs") {
+ QJsonObject obj;
+ obj.insert("type", "logs");
+ obj.insert("logs", "");
+ write(obj);
+ return;
+ }
+
if (type == "activate") {
InterfaceConfig config;
if (!Daemon::parseConfig(obj, config)) {
@@ -115,8 +126,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
if (type == "status") {
QJsonObject obj = Daemon::instance()->getStatus();
obj.insert("type", "status");
- m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
- m_socket->write("\n");
+ write(obj);
return;
}
@@ -124,8 +134,7 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) {
QJsonObject obj;
obj.insert("type", "logs");
obj.insert("logs", Daemon::instance()->logs().replace("\n", "|"));
- m_socket->write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
- m_socket->write("\n");
+ write(obj);
return;
}
diff --git a/client/mozilla/localsocketcontroller.cpp b/client/mozilla/localsocketcontroller.cpp
index 4d040288..5e9f0f97 100644
--- a/client/mozilla/localsocketcontroller.cpp
+++ b/client/mozilla/localsocketcontroller.cpp
@@ -34,8 +34,8 @@ LocalSocketController::LocalSocketController() {
m_socket = new QLocalSocket(this);
connect(m_socket, &QLocalSocket::connected, this,
&LocalSocketController::daemonConnected);
- connect(m_socket, &QLocalSocket::disconnected, this,
- &LocalSocketController::disconnected);
+ connect(m_socket, &QLocalSocket::disconnected, this,
+ [&] { errorOccurred(QLocalSocket::PeerClosedError); });
connect(m_socket, &QLocalSocket::errorOccurred, this,
&LocalSocketController::errorOccurred);
connect(m_socket, &QLocalSocket::readyRead, this,
diff --git a/client/platforms/linux/daemon/linuxdaemon.h b/client/platforms/linux/daemon/linuxdaemon.h
index 7f5d27b7..dbac8cee 100644
--- a/client/platforms/linux/daemon/linuxdaemon.h
+++ b/client/platforms/linux/daemon/linuxdaemon.h
@@ -22,7 +22,6 @@ class LinuxDaemon final : public Daemon {
protected:
WireguardUtils* wgutils() const override { return m_wgutils; }
- bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
bool supportIPUtils() const override { return true; }
IPUtils* iputils() override { return m_iputils; }
diff --git a/client/platforms/macos/daemon/macosdaemon.h b/client/platforms/macos/daemon/macosdaemon.h
index a48c326c..4181648e 100644
--- a/client/platforms/macos/daemon/macosdaemon.h
+++ b/client/platforms/macos/daemon/macosdaemon.h
@@ -21,7 +21,6 @@ class MacOSDaemon final : public Daemon {
protected:
WireguardUtils* wgutils() const override { return m_wgutils; }
- bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
bool supportIPUtils() const override { return true; }
IPUtils* iputils() override { return m_iputils; }
diff --git a/client/platforms/windows/daemon/windowsdaemon.h b/client/platforms/windows/daemon/windowsdaemon.h
index 9d051bae..7e38c41e 100644
--- a/client/platforms/windows/daemon/windowsdaemon.h
+++ b/client/platforms/windows/daemon/windowsdaemon.h
@@ -26,7 +26,6 @@ class WindowsDaemon final : public Daemon {
protected:
bool run(Op op, const InterfaceConfig& config) override;
WireguardUtils* wgutils() const override { return m_wgutils; }
- bool supportDnsUtils() const override { return true; }
DnsUtils* dnsutils() override { return m_dnsutils; }
private:
diff --git a/client/platforms/windows/daemon/windowssplittunnel.cpp b/client/platforms/windows/daemon/windowssplittunnel.cpp
index 39941933..c4e893b2 100644
--- a/client/platforms/windows/daemon/windowssplittunnel.cpp
+++ b/client/platforms/windows/daemon/windowssplittunnel.cpp
@@ -502,7 +502,7 @@ QString WindowsSplitTunnel::convertPath(const QString& path) {
// device should contain : for e.g C:
return "";
}
- QByteArray buffer(2048, 0xFF);
+ QByteArray buffer(2048, 0xFFu);
auto ok = QueryDosDeviceW(qUtf16Printable(driveLetter),
(wchar_t*)buffer.data(), buffer.size() / 2);
diff --git a/client/platforms/windows/daemon/wireguardutilswindows.cpp b/client/platforms/windows/daemon/wireguardutilswindows.cpp
index a68551d7..1a220235 100644
--- a/client/platforms/windows/daemon/wireguardutilswindows.cpp
+++ b/client/platforms/windows/daemon/wireguardutilswindows.cpp
@@ -248,7 +248,7 @@ bool WireguardUtilsWindows::updateRoutePrefix(const IPAddress& prefix) {
}
if (result != NO_ERROR) {
logger.error() << "Failed to create route to"
- << logger.sensitive(prefix.toString())
+ << prefix.toString()
<< "result:" << result;
}
return result == NO_ERROR;
@@ -265,7 +265,7 @@ bool WireguardUtilsWindows::deleteRoutePrefix(const IPAddress& prefix) {
}
if (result != NO_ERROR) {
logger.error() << "Failed to delete route to"
- << logger.sensitive(prefix.toString())
+ << prefix.toString()
<< "result:" << result;
}
return result == NO_ERROR;
diff --git a/client/platforms/windows/windowscommons.cpp b/client/platforms/windows/windowscommons.cpp
index c0a14dda..4c0d8176 100644
--- a/client/platforms/windows/windowscommons.cpp
+++ b/client/platforms/windows/windowscommons.cpp
@@ -21,7 +21,7 @@
#include "platforms/windows/windowsutils.h"
constexpr const char* VPN_NAME = "AmneziaVPN";
-constexpr const char* WIREGUARD_DIR = "WireGuard";
+constexpr const char* WIREGUARD_DIR = "AmneziaWG";
constexpr const char* DATA_DIR = "Data";
namespace {
diff --git a/client/translations/amneziavpn_ar_EG.ts b/client/translations/amneziavpn_ar_EG.ts
index 0aa5e32d..29135f65 100644
--- a/client/translations/amneziavpn_ar_EG.ts
+++ b/client/translations/amneziavpn_ar_EG.ts
@@ -89,60 +89,60 @@
ConnectionController
-
-
-
+
+
+
Connect
اتصل
-
+
VPN Protocols is not installed.
Please install VPN container at first
لم يتم تثبيت بروتوكولات VPN, من فضلك قم بتنزيل حاوية VPN اولاً
-
+
Connecting...
اتصال...
-
+
Connected
تم الاتصال
-
+
Reconnecting...
إعادة الاتصال...
-
+
Disconnecting...
إنهاء الاتصال...
-
+
Preparing...
جاري التحضير...
-
+
Settings updated successfully, reconnnection...
تم تحديث الاعدادات بنجاح, جاري إعادة الاتصال...
-
+
Settings updated successfully
تم تحديث الاعدادات بنجاح
-
+
The selected protocol is not supported on the current platform
البروتوكول المحدد غير مدعوم علي المنصة الحالية
-
+
unable to create configuration
غير قادر علي إنشاء تكوين
@@ -253,23 +253,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- غير قادر علي فتح الملف
+ غير قادر علي فتح الملف
-
-
Invalid configuration file
- ملف تكوين غير صحيح
+ ملف تكوين غير صحيح
-
+
Scanned %1 of %2.
تم فحص%1 من %2.
-
+
In the imported configuration, potentially dangerous lines were found:
في التكوين المستورد، تم العثور على سطور يحتمل أن تكون خطرة:
@@ -277,24 +274,24 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 تم التثبيت بنجاح.
-
+
%1 is already installed on the server.
%1 بالفعل مٌثبت علي الخادم.
-
+
Added containers that were already installed on the server
تمت إضافة الحاويات التي كانت مٌثبتة بالفعل علي الخادم
-
+
Already installed containers were found on the server. All installed containers have been added to the application
@@ -302,62 +299,62 @@ Already installed containers were found on the server. All installed containers
تمت إضافة جميع الحاويات المٌثبتة إلي التطبيق
-
+
Settings updated successfully
تم تحديث الاعدادات بنجاح
-
+
Server '%1' was rebooted
تمت إعادة تشغيل الخادم%1
-
+
Server '%1' was removed
تمت إزالة الخادم '%1'
-
+
All containers from server '%1' have been removed
قد تم حذفها '%1' جميع الحاويات من الخادم
-
+
%1 has been removed from the server '%2'
%1 تم حدف '%2' اسم الخادم
-
+
Api config removed
تم حذف تكوين Api
-
+
%1 cached profile cleared
تم مسح ملف تعريف %1 المخزن مؤقتًا
-
+
Please login as the user
من فضلك قم بتسجيل الدخول كمستخدم
-
+
Server added successfully
تمت إضافة الخادم بنجاح
-
+
%1 installed successfully.
تم تحميل %1 بنجاح
-
+
API config reloaded
تمت إعادة تحميل تكوين API
-
+
Successfully changed the country of connection to %1
تم تغيير بلد الاتصال بنجاح إلى %1
@@ -2318,97 +2315,107 @@ Already installed containers were found on the server. All installed containers
PageSetupWizardConfigSource
-
+
Connection
الاتصال
-
+
Settings
إعدادات
-
+
Enable logs
+ Support tag
+ علامة الدعم
+
+
+
+ Copied
+
+
+
+
Insert the key, add a configuration file or scan the QR-code
أدخل المفتاح، أضف ملف تكوين أو امسح رمز الاستجابة السريعة
-
+
Insert key
أدخل مفتاح
-
+
Insert
أدخل
-
+
Continue
واصل
-
+
Other connection options
اختيارات اتصال اخري
-
+
VPN by Amnezia
VPN بواسطة Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
اتصل بخدمات VPN الكلاسيكية المدفوعة والمجانية من Amnezia
-
+
Self-hosted VPN
VPN ذاتية الاستضافة
-
+
Configure Amnezia VPN on your own server
قم بتكوين Amnezia VPN على الخادم الخاص بك
-
+
Restore from backup
استرجاع من ملف يحتوي علي نسخة احتياطية
-
+
Open backup file
افتح ملف نسخ احتياطي
-
+
Backup files (*.backup)
ملفات نٌسخ احتياطية (*.backup)
-
+
File with connection settings
ملف إعدادات اتصال
-
+
Open config file
افتح ملف تكوين
-
+
QR code
رمز QR
-
+
I have nothing
ليس لدي اي شئ
@@ -2771,67 +2778,67 @@ Already installed containers were found on the server. All installed containers
ابحث
-
+
Creation date: %1
تاريخ الإنشاء: %1
-
+
Latest handshake: %1
اخر تصافح: %1
-
+
Data received: %1
البيانات المستلمة: %1
-
+
Data sent: %1
البيانات المٌرسلة: %1
-
+
Allowed IPs: %1
-
+
Rename
إعادة التسمية
-
+
Client name
اسم العميل
-
+
Save
احفظ
-
+
Revoke
سحب وإبطال
-
+
Revoke the config for a user - %1?
سحب وإبطال للمستخدم - %1?
-
+
The user will no longer be able to connect to your server.
المستخدم لن يكون قادر علي الاتصال بعد الان.
-
+
Continue
واصل
-
+
Cancel
إلغاء
@@ -2944,17 +2951,17 @@ Already installed containers were found on the server. All installed containers
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
تم تعطيل التسجيل بعد 14 يومًا، وتم حذف ملفات السجل
-
+
Settings restored from backup file
تم تحميل الإعدادات من ملف نسخة احتياطية
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3293,22 +3300,22 @@ Already installed containers were found on the server. All installed containers
انتهت مدة الاتصال بالخادم
-
+
VPN connection error
-
+
Error when retrieving configuration from API
خطأ عند استرداد التكوين من API
-
+
This config has already been added to the application
هذا التكوين بالفعل تمت إضافتة للبرنامج
-
+
ErrorCode: %1.
@@ -3383,57 +3390,67 @@ Already installed containers were found on the server. All installed containers
التكوين لا يحتوي علي اي حاويات و اعتماد للأتصال بالخادم
-
+
+ Unable to open config file
+
+
+
+
In the response from the server, an empty config was received
في الاستجابة من الخادم، تم تلقي تكوين فارغ
-
+
SSL error occurred
حدث خطأ SSL
-
+
Server response timeout on api request
انتهت مهلة استجابة الخادم عند طلب واجهة برمجة التطبيقات
-
+
Missing AGW public key
مفتاح AGW عام مفقود
-
+
+ Failed to decrypt response payload
+
+
+
+
QFile error: The file could not be opened
خطأ QFile: لا يمكن فتح الملف
-
+
QFile error: An error occurred when reading from the file
خطأ QFile: ظهر خطأ اثناء القراءه من الملف
-
+
QFile error: The file could not be accessed
خطأ QFile: لا يمكن الوصول للملف
-
+
QFile error: An unspecified error occurred
خطأ QFile: ظهر خطأ غير محدد
-
+
QFile error: A fatal error occurred
خطأ QFile: حدث خطأ فادح
-
+
QFile error: The operation was aborted
خطأ QFile: تم إحباط العملية
-
+
Internal error
خطأ داخلي
@@ -4031,7 +4048,7 @@ While it offers a blend of security, stability, and speed, it's essential t
VpnConnection
-
+
Mbps
diff --git a/client/translations/amneziavpn_fa_IR.ts b/client/translations/amneziavpn_fa_IR.ts
index f3ed01be..a01eaba9 100644
--- a/client/translations/amneziavpn_fa_IR.ts
+++ b/client/translations/amneziavpn_fa_IR.ts
@@ -88,63 +88,63 @@
ConnectionController
-
+
VPN Protocols is not installed.
Please install VPN container at first
پروتکل ویپیان نصب نشده است
لطفا کانتینر ویپیان را نصب کنید
-
+
Connecting...
در حال ارتباط...
-
+
Connected
متصل
-
+
Preparing...
در حال آمادهسازی...
-
+
Settings updated successfully, reconnnection...
تنظیمات به روز رسانی شد
در حال اتصال دوباره...
-
+
Settings updated successfully
تنظیمات با موفقیت بهروزرسانی شدند
-
+
The selected protocol is not supported on the current platform
پروتکل انتخابشده در پلتفرم فعلی پشتیبانی نمیشود.
-
+
unable to create configuration
نمیتوان پیکربندی را ایجاد کرد.
-
+
Reconnecting...
اتصال دوباره...
-
-
-
+
+
+
Connect
اتصال
-
+
Disconnecting...
قطع ارتباط...
@@ -258,23 +258,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- نمیتوان فایل را باز کرد.
+ نمیتوان فایل را باز کرد.
-
-
Invalid configuration file
- فایل پیکربندی نامعتبر است.
+ فایل پیکربندی نامعتبر است.
-
+
Scanned %1 of %2.
ارزیابی %1 از %2.
-
+
In the imported configuration, potentially dangerous lines were found:
در پیکربندی وارد شده، خطوطی که ممکن است خطرناک باشند، یافت شدند:
@@ -282,86 +279,86 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 با موفقیت نصب شد.
-
+
%1 is already installed on the server.
%1 در حال حاضر بر روی سرور نصب شده است.
-
+
Added containers that were already installed on the server
کانتینرهایی که بر روی سرور موجود بودند اضافه شدند
-
+
Already installed containers were found on the server. All installed containers have been added to the application
کانتینرهای نصب شده بر روی سرور شناسایی شدند. تمام کانتینترهای نصب شده به نرم افزار اضافه شدند
-
+
Settings updated successfully
تنظیمات با موفقیت بهروزرسانی شدند
-
+
Server '%1' was rebooted
سرور %1 راه اندازی مجدد شد
-
+
Server '%1' was removed
سرور %1 حذف شد
-
+
All containers from server '%1' have been removed
تمام کانتینترها از سرور %1 حذف شدند
-
+
%1 has been removed from the server '%2'
%1 از سرور %2 حذف شد
-
+
Api config removed
پیکربندی API حذف شد.
-
+
%1 cached profile cleared
%1 پروفایل ذخیره شده پاک شد.
-
+
Please login as the user
لطفا به عنوان کاربر وارد شوید
-
+
Server added successfully
سرور با موفقیت اضافه شد
-
+
%1 installed successfully.
%1 با موفقیت نصب شد.
-
+
API config reloaded
پیکربندی API دوباره بارگذاری شد.
-
+
Successfully changed the country of connection to %1
کشور اتصال با موفقیت به %1 تغییر یافت.
@@ -2433,7 +2430,7 @@ It's okay as long as it's from someone you trust.
چی داری؟
-
+
File with connection settings
فایل شامل تنظیمات اتصال
@@ -2442,92 +2439,102 @@ It's okay as long as it's from someone you trust.
فایل شامل تنظیمات اتصال یا بکآپ
-
+
Connection
ارتباط
-
+
Settings
تنظیمات
-
+
Enable logs
+ Support tag
+
+
+
+
+ Copied
+ کپی شد
+
+
+
Insert the key, add a configuration file or scan the QR-code
کلید را وارد کنید، فایل پیکربندی را اضافه کنید یا کد QR را اسکن کنید
-
+
Insert key
کلید را وارد کنید
-
+
Insert
وارد کردن
-
+
Continue
ادامه دهید
-
+
Other connection options
گزینههای اتصال دیگر
-
+
VPN by Amnezia
VPN توسط Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
اتصال به سرویسهای VPN کلاسیک پولی و رایگان از Amnezia
-
+
Self-hosted VPN
Self-hosted VPN
-
+
Configure Amnezia VPN on your own server
پیکربندی VPN Amnezia بر روی سرور خودتان
-
+
Restore from backup
بازیابی از پشتیبان
-
+
Open backup file
باز کردن فایل پشتیبان
-
+
Backup files (*.backup)
Backup files (*.backup)
-
+
Open config file
باز کردن فایل تنظیمات
-
+
QR code
QR-Code
-
+
I have nothing
من هیچی ندارم
@@ -2939,27 +2946,27 @@ It's okay as long as it's from someone you trust.
جستجو
-
+
Creation date: %1
تاریخ ایجاد: %1
-
+
Latest handshake: %1
آخرین ارتباط: %1
-
+
Data received: %1
دادههای دریافت شده: %1
-
+
Data sent: %1
دادههای ارسال شده: %1
-
+
Allowed IPs: %1
@@ -2968,42 +2975,42 @@ It's okay as long as it's from someone you trust.
تاریخ ایجاد:
-
+
Rename
تغییر نام
-
+
Client name
نام کلاینت
-
+
Save
ذخیره
-
+
Revoke
ابطال
-
+
Revoke the config for a user - %1?
لغو پیکربندی برای یک کاربر - %1?
-
+
The user will no longer be able to connect to your server.
کاربر دیگر نمیتواند به سرور وصل شود.
-
+
Continue
ادامه
-
+
Cancel
کنسل
@@ -3090,17 +3097,17 @@ It's okay as long as it's from someone you trust.
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
ثبت وقایع پس از ۱۴ روز غیرفعال شد و فایلهای ثبت وقایع حذف شدند
-
+
Settings restored from backup file
تنظیمات از فایل پشتیبان بازیابی شد
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3484,22 +3491,22 @@ It's okay as long as it's from someone you trust.
تنظیمات شامل هیچ کانتینر یا اعتبارنامهای برای اتصال به سرور نیست
-
+
VPN connection error
خطای اتصال VPN
-
+
Error when retrieving configuration from API
خطا هنگام بازیابی پیکربندی از API
-
+
This config has already been added to the application
این پیکربندی قبلاً به برنامه اضافه شده است
-
+
ErrorCode: %1.
کد خطا: %1.
@@ -3569,57 +3576,67 @@ It's okay as long as it's from someone you trust.
VPN pool error: no available addresses
-
+
+ Unable to open config file
+
+
+
+
In the response from the server, an empty config was received
در پاسخ از سرور، پیکربندی خالی دریافت شد
-
+
SSL error occurred
SSL error occurred
-
+
Server response timeout on api request
Server response timeout on api request
-
+
Missing AGW public key
-
- QFile error: The file could not be opened
-
-
-
-
- QFile error: An error occurred when reading from the file
+
+ Failed to decrypt response payload
- QFile error: The file could not be accessed
+ QFile error: The file could not be opened
- QFile error: An unspecified error occurred
+ QFile error: An error occurred when reading from the file
- QFile error: A fatal error occurred
+ QFile error: The file could not be accessed
+ QFile error: An unspecified error occurred
+
+
+
+
+ QFile error: A fatal error occurred
+
+
+
+
QFile error: The operation was aborted
-
+
Internal error
Internal error
@@ -4239,7 +4256,7 @@ For more detailed information, you can
VpnConnection
-
+
Mbps
Mbps
diff --git a/client/translations/amneziavpn_hi_IN.ts b/client/translations/amneziavpn_hi_IN.ts
index 036c0d7e..7281ebd5 100644
--- a/client/translations/amneziavpn_hi_IN.ts
+++ b/client/translations/amneziavpn_hi_IN.ts
@@ -89,61 +89,61 @@
ConnectionController
-
-
-
+
+
+
Connect
कनेक्ट
-
+
VPN Protocols is not installed.
Please install VPN container at first
पीएन प्रोटोकॉल स्थापित नहीं है.
कृपया पहले वीपीएन कंटेनर स्थापित करें
-
+
Connected
जुड़ा हुआ
-
+
The selected protocol is not supported on the current platform
चयनित प्रोटोकॉल वर्तमान प्लेटफ़ॉर्म पर समर्थित नहीं है
-
+
unable to create configuration
कॉन्फ़िगरेशन बनाने में असमर्थ
-
+
Connecting...
कनेक्ट...
-
+
Reconnecting...
पुनः कनेक्ट हो रहा है...
-
+
Disconnecting...
डिस्कनेक्ट हो रहा है...
-
+
Preparing...
तैयार कर रहे हैं...
-
+
Settings updated successfully, reconnnection...
सेटिंग्स सफलतापूर्वक अपडेट हो गईं...
-
+
Settings updated successfully
सेटिंग्स सफलतापूर्वक अपडेट हो गईं
@@ -254,23 +254,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- फाइल खोलने में असमर्थ
+ फाइल खोलने में असमर्थ
-
-
Invalid configuration file
- अमान्य कॉन्फ़िगरेशन फ़ाइल
+ अमान्य कॉन्फ़िगरेशन फ़ाइल
-
+
Scanned %1 of %2.
%2 में से %1 स्कैन किया गया.
-
+
In the imported configuration, potentially dangerous lines were found:
@@ -278,86 +275,86 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 सफलतापूर्वक स्थापित हुआ.
-
+
%1 is already installed on the server.
%1 पहले से ही सर्वर पर स्थापित है.
-
+
Added containers that were already installed on the server
सर्वर पर पहले से स्थापित कंटेनर जोड़े गए
-
+
Already installed containers were found on the server. All installed containers have been added to the application
सर्वर पर पहले से स्थापित कंटेनर पाए गए। सभी स्थापित कंटेनरों को एप्लिकेशन में जोड़ दिया गया है
-
+
Settings updated successfully
सेटिंग्स सफलतापूर्वक अपडेट हो गईं
-
+
Server '%1' was rebooted
सर्वर '%1' रीबूट किया गया था
-
+
Server '%1' was removed
सर्वर '%1' रीबूट किया गया था
-
+
All containers from server '%1' have been removed
सर्वर '%1' से सभी कंटेनर हटा दिए गए हैं
-
+
%1 has been removed from the server '%2'
%1 को सर्वर '%2' से हटा दिया गया है
-
+
Api config removed
-
+
%1 cached profile cleared
%1 कैश्ड प्रोफ़ाइल साफ़ की गई
-
+
Please login as the user
कृपया उपयोगकर्ता के रूप में लॉगिन करें
-
+
Server added successfully
सर्वर सफलतापूर्वक जोड़ा गया
-
+
%1 installed successfully.
-
+
API config reloaded
-
+
Successfully changed the country of connection to %1
@@ -2382,97 +2379,107 @@ Already installed containers were found on the server. All installed containers
कनेक्शन सेटिंग्स वाली फ़ाइल
-
+
Connection
कनेक्शन
-
+
Settings
समायोजन
-
+
Enable logs
- Insert the key, add a configuration file or scan the QR-code
-
-
-
-
- Insert key
+ Support tag
+ Copied
+ कॉपी किया गया
+
+
+
+ Insert the key, add a configuration file or scan the QR-code
+
+
+
+
+ Insert key
+
+
+
+
Insert
डालना
-
+
Continue
जारी रखना
-
+
Other connection options
-
+
VPN by Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
-
+
Self-hosted VPN
-
+
Configure Amnezia VPN on your own server
-
+
Restore from backup
बैकअप से बहाल करना
-
+
Open backup file
बैकअप फ़ाइल खोलें
-
+
Backup files (*.backup)
बैकअप फ़ाइलें (*.backup)
-
+
File with connection settings
कनेक्शन सेटिंग्स वाली फ़ाइल
-
+
Open config file
कॉन्फ़िग फ़ाइल खोलें
-
+
QR code
क्यू आर संहिता
-
+
I have nothing
मेरे पास कुछ नहीं है
@@ -2857,27 +2864,27 @@ Already installed containers were found on the server. All installed containers
खोज
-
+
Creation date: %1
निर्माण दिनांक: %1
-
+
Latest handshake: %1
नवीनतम हाथ मिलाना: %1
-
+
Data received: %1
प्राप्त डेटा: %1
-
+
Data sent: %1
डेटा भेजा गया: %1
-
+
Allowed IPs: %1
@@ -2886,42 +2893,42 @@ Already installed containers were found on the server. All installed containers
निर्माण तिथि:
-
+
Rename
नाम बदलें
-
+
Client name
ग्राहक नाम
-
+
Save
सहेजें
-
+
Revoke
निरस्त करें
-
+
Revoke the config for a user - %1?
किसी उपयोक्ता के लिए कॉन्फ़िगरेशन निरस्त करें - %1?
-
+
The user will no longer be able to connect to your server.
उपयोगकर्ता अब आपके सर्वर से कनेक्ट नहीं हो पाएगा.
-
+
Continue
जारी रखना
-
+
Cancel
रद्द करना
@@ -3039,17 +3046,17 @@ Already installed containers were found on the server. All installed containers
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
14 दिनों के बाद लॉगिंग अक्षम कर दी गई, लॉग फ़ाइलें हटा दी गईं
-
+
Settings restored from backup file
बैकअप फ़ाइल से सेटिंग्स पुनर्स्थापित की गईं
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3398,42 +3405,52 @@ Already installed containers were found on the server. All installed containers
सर्वर से कनेक्ट होने का समय समाप्त
-
+
+ Unable to open config file
+
+
+
+
VPN connection error
VPN कनेक्शन त्रुटि
-
+
Error when retrieving configuration from API
एपीआई से कॉन्फ़िगरेशन पुनर्प्राप्त करते समय त्रुटि
-
+
This config has already been added to the application
यह कॉन्फ़िगरेशन पहले ही एप्लिकेशन में जोड़ा जा चुका है
-
+
In the response from the server, an empty config was received
-
+
SSL error occurred
-
+
Server response timeout on api request
-
+
Missing AGW public key
-
+
+ Failed to decrypt response payload
+
+
+
+
ErrorCode: %1.
ErrorCode: %1.
@@ -3498,37 +3515,37 @@ Already installed containers were found on the server. All installed containers
कॉन्फ़िगरेशन में सर्वर से कनेक्ट करने के लिए कोई कंटेनर और क्रेडेंशियल नहीं है
-
+
QFile error: The file could not be opened
Qफ़ाइल त्रुटि: फ़ाइल खोली नहीं जा सकी
-
+
QFile error: An error occurred when reading from the file
Qफ़ाइल त्रुटि: फ़ाइल से पढ़ते समय एक त्रुटि उत्पन्न हुई
-
+
QFile error: The file could not be accessed
Qफ़ाइल त्रुटि: फ़ाइल तक नहीं पहुंचा जा सका
-
+
QFile error: An unspecified error occurred
Qफ़ाइल त्रुटि: एक अनिर्दिष्ट त्रुटि उत्पन्न हुई
-
+
QFile error: A fatal error occurred
Qफ़ाइल त्रुटि: एक घातक त्रुटि उत्पन्न हुई
-
+
QFile error: The operation was aborted
Qफ़ाइल त्रुटि: ऑपरेशन निरस्त कर दिया गया था
-
+
Internal error
आंतरिक त्रुटि
@@ -4127,7 +4144,7 @@ While it offers a blend of security, stability, and speed, it's essential t
VpnConnection
-
+
Mbps
diff --git a/client/translations/amneziavpn_my_MM.ts b/client/translations/amneziavpn_my_MM.ts
index 1e391587..66a81863 100644
--- a/client/translations/amneziavpn_my_MM.ts
+++ b/client/translations/amneziavpn_my_MM.ts
@@ -88,62 +88,62 @@
ConnectionController
-
+
VPN Protocols is not installed.
Please install VPN container at first
VPN ပရိုတိုကောများကို မထည့်သွင်းရသေးပါ။
ကျေးဇူးပြု၍ VPN ကွန်တိန်နာကို အရင်ထည့်သွင်းပါ။
-
+
Connecting...
ချိတ်ဆက်နေပါပြီ...
-
+
Connected
ချိတ်ဆက်ပြီးသွားပါပြီ
-
+
Preparing...
ပြင်ဆင်နေသည်...
-
+
Settings updated successfully, reconnnection...
ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ၊ ပြန်လည်ချိတ်ဆက်နေပါသည်...
-
+
Settings updated successfully
ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ
-
+
The selected protocol is not supported on the current platform
ရွေးချယ်ထားသော ပရိုတိုကောကို လက်ရှိပလက်ဖောင်းပေါ်တွင် အထောက်အပံ့မပေးထားပါ
-
+
unable to create configuration
configuration ဖန်တီး၍မရပါ
-
+
Reconnecting...
ပြန်လည်ချိတ်ဆက်နေပါသည်...
-
-
-
+
+
+
Connect
ချိတ်ဆက်မည်
-
+
Disconnecting...
အဆက်အသွယ်ဖြတ်နေပါသည်...
@@ -254,23 +254,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- ဖိုင်ကိုဖွင့်၍မရပါ
+ ဖိုင်ကိုဖွင့်၍မရပါ
-
-
Invalid configuration file
- Configuration ဖိုင် မမှန်ကန်ပါ
+ Configuration ဖိုင် မမှန်ကန်ပါ
-
+
Scanned %1 of %2.
%2 ၏ %1 ကို စကင်န်ဖတ်ထားသည်.
-
+
In the imported configuration, potentially dangerous lines were found:
တင်သွင်းသည့် configuration တွင်၊ အန္တရာယ်ရှိနိုင်သည့်စာလိုင်းများကို တွေ့ရှိခဲ့သည်:
@@ -278,86 +275,86 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 ကို အောင်မြင်စွာ ထည့်သွင်းပြီးပါပြီ.
-
+
%1 is already installed on the server.
%1 ကို ဆာဗာတွင် ထည့်သွင်းပြီးဖြစ်သည်.
-
+
Added containers that were already installed on the server
ဆာဗာတွင် ထည့်သွင်းပြီးသား ကွန်တိန်နာများကို ပေါင်းထည့်ပြီးပါပြီ။
-
+
Already installed containers were found on the server. All installed containers have been added to the application
ထည့်သွင်းပြီးသား ကွန်တိန်နာများကို ဆာဗာပေါ်တွင် တွေ့ရှိခဲ့သည်။ ထည့်သွင်းထားသည့် ကွန်တိန်နာအားလုံးကို အပလီကေးရှင်းထဲသို့ ပေါင်းထည့်ပြီးပါပြီ။
-
+
Settings updated successfully
ဆက်တင်များကို အောင်မြင်စွာ အပ်ဒိတ်လုပ်ပြီးပါပြီ။
-
+
Server '%1' was rebooted
ဆာဗာ '%1' ကို ပြန်လည်စတင်ခဲ့သည်။
-
+
Server '%1' was removed
ဆာဗာ '%1' ကို ဖယ်ရှားခဲ့သည်။
-
+
All containers from server '%1' have been removed
ဆာဗာ '%1' မှ ကွန်တိန်နာအားလုံးကို ဖယ်ရှားလိုက်ပါပြီ။
-
+
%1 has been removed from the server '%2'
%1 ကို ဆာဗာ '%2' မှ ဖယ်ရှားလိုက်ပါပြီ
-
+
Api config removed
Api config ကိုဖယ်ရှားလိုက်သည်
-
+
%1 cached profile cleared
ကက်ရှ်လုပ်ထားတဲ့ ပရိုဖိုင် %1 ခုကို ရှင်းပြီးပါပြီ
-
+
Please login as the user
အသုံးပြုသူအဖြစ် log in ဝင်ရောက်ပါ
-
+
Server added successfully
ဆာဗာကို အောင်မြင်စွာ ထည့်သွင်းပြီးပါပြီ
-
+
%1 installed successfully.
%1 ခုကို အောင်မြင်စွာ ထည့်သွင်းပြီးပါပြီ.
-
+
API config reloaded
API config ကို ပြန်လည်စတင်လိုက်ပါပြီ
-
+
Successfully changed the country of connection to %1
ချိတ်ဆက်မှုနိုင်ငံကို %1 သို့ အောင်မြင်စွာ ပြောင်းလဲလိုက်ပါပြီ
@@ -2327,97 +2324,107 @@ Already installed containers were found on the server. All installed containers
PageSetupWizardConfigSource
-
+
File with connection settings
ချိတ်ဆက်မှုဆက်တင်များပါဝင်သောဖိုင်
-
+
Connection
ချိတ်ဆက်မှု
-
+
Settings
ဆက်တင်များ
-
+
Enable logs
+ Support tag
+ ကူညီပံ့ပိုးမှု tag
+
+
+
+ Copied
+ ကူးယူပြီးပါပြီ
+
+
+
Insert the key, add a configuration file or scan the QR-code
Key ကိုထည့်မည်၊ ဖွဲ့စည်းမှုဖိုင်တစ်ခုကိုထည့်မည် သို့မဟုတ် QR-ကုဒ်ကို စကင်န်ဖတ်မည်
-
+
Insert key
Key ကိုထည့်သွင်းမည်
-
+
Insert
ထည့်သွင်းမည်
-
+
Continue
ဆက်လက်လုပ်ဆောင်မည်
-
+
Other connection options
အခြားချိတ်ဆက်မှုရွေးချယ်စရာများ
-
+
VPN by Amnezia
Amnezia မှ VPN
-
+
Connect to classic paid and free VPN services from Amnezia
Amnezia မှ အခပေးနှင့် အခမဲ့ မူလ VPN ဝန်ဆောင်မှုများသို့ ချိတ်ဆက်မည်
-
+
Self-hosted VPN
ကိုယ်တိုင် host လုပ်ထားသော VPN
-
+
Configure Amnezia VPN on your own server
Amnezia VPN ကို သင်၏ကိုယ်ပိုင်ဆာဗာပေါ်တွင် စီစဥ်ချိန်ညှိမည်
-
+
Restore from backup
အရံဖိုင်မှ ပြန်လည်ရယူမည်
-
+
Open backup file
အရံဖိုင်ကို ဖွင့်မည်
-
+
Backup files (*.backup)
အရံဖိုင်များ (*.backup)
-
+
Open config file
config ဖိုင်ကိုဖွင့်မည်
-
+
QR code
QR-ကုဒ်
-
+
I have nothing
ကျွန်ုပ်တွင်ဘာမှမရှိပါ
@@ -2805,67 +2812,67 @@ Already installed containers were found on the server. All installed containers
ရှာဖွေမည်
-
+
Creation date: %1
ဖန်တီးပြုလုပ်သည့်ရက်စွဲ: %1
-
+
Latest handshake: %1
နောက်ဆုံး handshake လုပ်ခြင်း: %1
-
+
Data received: %1
လက်ခံရရှိသည့်ဒေတာ: %1
-
+
Data sent: %1
ပေးပို့လိုက်သည့်ဒေတာ: %1
-
+
Allowed IPs: %1
-
+
Rename
အမည်ပြောင်းမည်
-
+
Client name
ကလိုင်းရင့်အမည်
-
+
Save
သိမ်းဆည်းမည်
-
+
Revoke
ပြန်ရုပ်သိမ်းမည်
-
+
Revoke the config for a user - %1?
အသုံးပြုသူ %1 အတွက် config ကို ပြန်လည်ရုပ်သိမ်းမည်လား?
-
+
The user will no longer be able to connect to your server.
ဤအသုံးပြုသူသည် သင့်ဆာဗာသို့ ချိတ်ဆက်နိုင်တော့မည်မဟုတ်ပါ.
-
+
Continue
ဆက်လက်လုပ်ဆောင်မည်
-
+
Cancel
ပယ်ဖျက်မည်
@@ -2952,17 +2959,17 @@ Already installed containers were found on the server. All installed containers
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
၁၄ ရက်အကြာတွင် Logging ကို ပိတ်ခဲ့သည်၊ မှတ်တမ်းဖိုင်များကို ဖျက်ပစ်လိုက်ပြီဖြစ်သည်
-
+
Settings restored from backup file
ဆက်တင်များကို အရံဖိုင်မှ ပြန်လည်ရယူပြီးပါပြီ
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3294,17 +3301,17 @@ Already installed containers were found on the server. All installed containers
Config တွင် ဆာဗာသို့ချိတ်ဆက်ရန်အတွက် ကွန်တိန်နာများနှင့် အထောက်အထားများ မပါဝင်ပါ
-
+
Error when retrieving configuration from API
API မှ စီစဉ်သတ်မှတ်မှုကို ရယူသည့်အခါ အမှားအယွင်းဖြစ်ပေါ်နေသည်
-
+
This config has already been added to the application
ဤ config ကို အပလီကေးရှင်းထဲသို့ ထည့်သွင်းပြီးဖြစ်သည်
-
+
ErrorCode: %1.
မှားယွင်းမှုကုတ်: %1.
@@ -3374,62 +3381,72 @@ Already installed containers were found on the server. All installed containers
VPN pool မှားယွင်းမှု: ရရှိနိုင်သောလိပ်စာများမရှိပါ
-
+
+ Unable to open config file
+
+
+
+
VPN connection error
VPN ချိတ်ဆက်မှုမှားယွင်းနေပါသည်
-
+
In the response from the server, an empty config was received
ဆာဗာမှ တုံ့ပြန်မှုတွင်၊ config အလွတ်တစ်ခုကို လက်ခံရရှိခဲ့သည်
-
+
SSL error occurred
SSL မှားယွင်းမှုဖြစ်သွားသည်
-
+
Server response timeout on api request
Api တောင်းဆိုမှုတွင် ဆာဗာတုံ့ပြန်မှု အချိန်ကုန်သွားသည်
-
+
Missing AGW public key
AGW public key ပျောက်ဆုံးနေသည်
-
+
+ Failed to decrypt response payload
+
+
+
+
QFile error: The file could not be opened
QFile မှားယွင်းမှု: ဖိုင်ကို ဖွင့်၍မရပါ
-
+
QFile error: An error occurred when reading from the file
QFile မှားယွင်းမှု: ဖိုင်ကိုဖတ်နေစဥ်အတွင်း မှားယွင်းမှုဖြစ်သွားသည်
-
+
QFile error: The file could not be accessed
QFile မှားယွင်းမှု: ဖိုင်ကို ဝင်၍မရပါ
-
+
QFile error: An unspecified error occurred
QFile မှားယွင်းမှု: သတ်မှတ်မထားသော မှားယွင်းမှုတစ်ခု ဖြစ်ပွားခဲ့သည်
-
+
QFile error: A fatal error occurred
QFile မှားယွင်းမှု: ကြီးမားသော မှားယွင်းမှုတစ်ခု ဖြစ်ပွားခဲ့သည်
-
+
QFile error: The operation was aborted
QFile မှားယွင်းမှု: လုပ်ငန်းစဥ်ကို ဖျက်သိမ်းလိုက်ရသည်
-
+
Internal error
စက်တွင်းဖြစ်သော မှားယွင်းမှု
@@ -4036,7 +4053,7 @@ For more detailed information, you can
VpnConnection
-
+
Mbps
Mbps
diff --git a/client/translations/amneziavpn_ru_RU.ts b/client/translations/amneziavpn_ru_RU.ts
index c059f186..e48df0fa 100644
--- a/client/translations/amneziavpn_ru_RU.ts
+++ b/client/translations/amneziavpn_ru_RU.ts
@@ -88,62 +88,62 @@
ConnectionController
-
+
VPN Protocols is not installed.
Please install VPN container at first
VPN-протоколы не установлены.
Пожалуйста, установите протокол
-
+
Connecting...
Подключение...
-
+
Connected
Подключено
-
+
Preparing...
Подготовка...
-
+
Settings updated successfully, reconnnection...
Настройки успешно обновлены, переподключение...
-
+
Settings updated successfully
Настройки успешно обновлены
-
+
The selected protocol is not supported on the current platform
Выбранный протокол не поддерживается на данном устройстве
-
+
unable to create configuration
не удалось создать конфигурацию
-
+
Reconnecting...
Переподключение...
-
-
-
+
+
+
Connect
Подключиться
-
+
Disconnecting...
Отключение...
@@ -258,23 +258,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- Невозможно открыть файл
+ Невозможно открыть файл
-
-
Invalid configuration file
- Неверный файл конфигурации
+ Неверный файл конфигурации
-
+
Scanned %1 of %2.
Отсканировано %1 из %2.
-
+
In the imported configuration, potentially dangerous lines were found:
В импортированной конфигурации были обнаружены потенциально опасные строки:
@@ -282,86 +279,86 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 успешно установлен.
-
+
%1 is already installed on the server.
%1 уже установлен на сервер.
-
+
Added containers that were already installed on the server
Добавлены сервисы и протоколы, которые были ранее установлены на сервер
-
+
Already installed containers were found on the server. All installed containers have been added to the application
На сервере обнаружены установленные протоколы и сервисы. Все они были добавлены в приложение
-
+
Settings updated successfully
Настройки успешно обновлены
-
+
Server '%1' was rebooted
Сервер '%1' был перезагружен
-
+
Server '%1' was removed
Сервер '%1' был удален
-
+
All containers from server '%1' have been removed
Все протоколы и сервисы были удалены с сервера '%1'
-
+
%1 has been removed from the server '%2'
%1 был удален с сервера '%2'
-
+
Api config removed
Конфигурация API удалена
-
+
%1 cached profile cleared
%1 закэшированный профиль очищен
-
+
Please login as the user
Пожалуйста, войдите в систему от имени пользователя
-
+
Server added successfully
Сервер успешно добавлен
-
+
%1 installed successfully.
%1 успешно установлен.
-
+
API config reloaded
Конфигурация API перезагружена
-
+
Successfully changed the country of connection to %1
Изменение страны подключения на %1
@@ -2505,7 +2502,7 @@ It's okay as long as it's from someone you trust.
Что у вас есть?
-
+
File with connection settings
Файл с настройками подключения
@@ -2514,92 +2511,102 @@ It's okay as long as it's from someone you trust.
Файл с настройками подключения или резервной копией
-
+
Connection
Соединение
-
+
Settings
Настройки
-
+
Enable logs
+ Support tag
+
+
+
+
+ Copied
+ Скопировано
+
+
+
Insert the key, add a configuration file or scan the QR-code
Вставьте ключ, добавьте файл конфигурации или отсканируйте QR-код
-
+
Insert key
Вставьте ключ
-
+
Insert
Вставить
-
+
Continue
Продолжить
-
+
Other connection options
Другие варианты подключения
-
+
VPN by Amnezia
VPN от Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
Подключайтесь к классическим платным и бесплатным VPN-сервисам от Amnezia
-
+
Self-hosted VPN
Self-hosted VPN
-
+
Configure Amnezia VPN on your own server
Настроить VPN на собственном сервере
-
+
Restore from backup
Восстановить из резервной копии
-
+
Open backup file
Открыть резервную копию
-
+
Backup files (*.backup)
Файлы резервных копий (*.backup)
-
+
Open config file
Открыть файл с конфигурацией
-
+
QR code
QR-код
-
+
I have nothing
У меня ничего нет
@@ -3068,27 +3075,27 @@ and will not be shared or disclosed to the Amnezia or any third parties
Поиск
-
+
Creation date: %1
Дата создания: %1
-
+
Latest handshake: %1
Последнее рукопожатие: %1
-
+
Data received: %1
Получено данных: %1
-
+
Data sent: %1
Отправлено данных: %1
-
+
Allowed IPs: %1
@@ -3097,42 +3104,42 @@ and will not be shared or disclosed to the Amnezia or any third parties
Дата создания:
-
+
Rename
Переименовать
-
+
Client name
Имя клиента
-
+
Save
Сохранить
-
+
Revoke
Отозвать
-
+
Revoke the config for a user - %1?
Отозвать конфигурацию для пользователя - %1?
-
+
The user will no longer be able to connect to your server.
Пользователь больше не сможет подключаться к вашему серверу.
-
+
Continue
Продолжить
-
+
Cancel
Отменить
@@ -3223,17 +3230,17 @@ and will not be shared or disclosed to the Amnezia or any third parties
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
Логирование было отключено по прошествии 14 дней, файлы логов были удалены.
-
+
Settings restored from backup file
Настройки восстановлены из бэкап файла
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3630,17 +3637,17 @@ and will not be shared or disclosed to the Amnezia or any third parties
Конфигурация не содержит каких-либо контейнеров и учетных данных для подключения к серверу
-
+
Error when retrieving configuration from API
Ошибка при получении конфигурации из API
-
+
This config has already been added to the application
Данная конфигурация уже была добавлена в приложение
-
+
ErrorCode: %1.
Код ошибки: %1.
@@ -3699,62 +3706,72 @@ and will not be shared or disclosed to the Amnezia or any third parties
Ошибка пула VPN: нет доступных адресов
-
+
+ Unable to open config file
+
+
+
+
VPN connection error
Ошибка VPN-соединения
-
+
In the response from the server, an empty config was received
В ответе от сервера была получена пустая конфигурация
-
+
SSL error occurred
Произошла ошибка SSL
-
+
Server response timeout on api request
Тайм-аут ответа сервера на запрос API
-
+
Missing AGW public key
-
+
+ Failed to decrypt response payload
+
+
+
+
QFile error: The file could not be opened
Ошибка QFile: не удалось открыть файл
-
+
QFile error: An error occurred when reading from the file
Ошибка QFile: произошла ошибка при чтении из файла
-
+
QFile error: The file could not be accessed
Ошибка QFile: не удалось получить доступ к файлу
-
+
QFile error: An unspecified error occurred
Ошибка QFile: произошла неизвестная ошибка
-
+
QFile error: A fatal error occurred
Ошибка QFile: произошла фатальная ошибка
-
+
QFile error: The operation was aborted
Ошибка QFile: операция была прервана
-
+
Internal error
Внутренняя ошибка
@@ -4454,7 +4471,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
VpnConnection
-
+
Mbps
Мбит/с
diff --git a/client/translations/amneziavpn_uk_UA.ts b/client/translations/amneziavpn_uk_UA.ts
index 1acb34f9..b34cc88f 100644
--- a/client/translations/amneziavpn_uk_UA.ts
+++ b/client/translations/amneziavpn_uk_UA.ts
@@ -111,62 +111,62 @@
ConnectionController
-
+
VPN Protocols is not installed.
Please install VPN container at first
VPN протоколи не встановлено.
Будь-ласка, встановіть VPN контейнер
-
+
unable to create configuration
Неможливо створити конфігурацію
-
+
Connecting...
Підключення...
-
+
Connected
Підключено
-
+
Preparing...
Підготовка...
-
+
Settings updated successfully, reconnnection...
Налаштування оновлено, підключення...
-
+
Settings updated successfully
Налаштування оновлено
-
+
The selected protocol is not supported on the current platform
Вибраний протокол не підтримується на цьому пристрої
-
+
Reconnecting...
Перепідключення...
-
-
-
+
+
+
Connect
Підключитись
-
+
Disconnecting...
Відключаємось...
@@ -285,23 +285,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- Неможливо відкрити файл
+ Неможливо відкрити файл
-
-
Invalid configuration file
- Недійсний файл конфігурації
+ Недійсний файл конфігурації
-
+
Scanned %1 of %2.
Відскановано %1 з %2.
-
+
In the imported configuration, potentially dangerous lines were found:
У імпортованій конфігурації знайдено потенційно небезпечні рядки:
@@ -309,85 +306,85 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 встановлено.
-
+
%1 is already installed on the server.
%1 вже встановлено на сервері.
-
+
Added containers that were already installed on the server
Додані сервіси і протоколи, які були раніше встановлені на сервері
-
+
Already installed containers were found on the server. All installed containers have been added to the application
На сервері знайдені сервіси та протоколи, всі вони додані в застосунок
-
+
Settings updated successfully
Налаштування оновлено
-
+
Server '%1' was rebooted
Сервер '%1' перезавантажено
-
+
Server '%1' was removed
Сервер '%1' був видалений
-
+
All containers from server '%1' have been removed
Всі сервіси та протоколи були видалені з сервера '%1'
-
+
%1 has been removed from the server '%2'
%1 був видалений з сервера '%2'
-
+
Api config removed
Конфігурацію API видалено
-
+
%1 cached profile cleared
Кешований профіль %1 очищено
-
+
Please login as the user
Буль-ласка, увійдіть в систему від імені користувача
-
+
Server added successfully
Сервер додано
-
+
%1 installed successfully.
%1 встановлено успішно.
-
+
API config reloaded
Конфігурацію API перезавантажено
-
+
Successfully changed the country of connection to %1
Успішно змінено країну підключення на %1
@@ -2591,7 +2588,7 @@ It's okay as long as it's from someone you trust.
Виберіть що у вас є
-
+
File with connection settings
Файл з налаштуваннями підключення
@@ -2600,92 +2597,102 @@ It's okay as long as it's from someone you trust.
Файл з налаштуваннями підключення або бекап
-
+
Connection
Підключення
-
+
Settings
Налаштування
-
+
Enable logs
+ Support tag
+
+
+
+
+ Copied
+ Скопійовано
+
+
+
Insert the key, add a configuration file or scan the QR-code
Вставте ключ, додайте файл конфігурації або відскануйте QR-код
-
+
Insert key
Вставити ключ
-
+
Insert
Вставити
-
+
Continue
Продовжити
-
+
Other connection options
Інші параметри підключення
-
+
VPN by Amnezia
VPN від Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
Підключайтеся до звичайних платних та безкоштовних VPN-сервісів від Amnezia
-
+
Self-hosted VPN
Self-hosted VPN
-
+
Configure Amnezia VPN on your own server
Налаштуйте Amnezia VPN на власному сервері
-
+
Restore from backup
Відновити із бекапа
-
+
Open backup file
Відкрити бекап файл
-
+
Backup files (*.backup)
Файли резервної копії (*.backup)
-
+
Open config file
Відкрити файл з конфігурацією
-
+
QR code
QR-код
-
+
I have nothing
У мене нічого нема
@@ -3163,27 +3170,27 @@ and will not be shared or disclosed to the Amnezia or any third parties
Пошук
-
+
Creation date: %1
Дата створення: %1
-
+
Latest handshake: %1
Останнє з'єднання: %1
-
+
Data received: %1
Отримано даних: %1
-
+
Data sent: %1
Відправлено даних: %1
-
+
Allowed IPs: %1
@@ -3192,42 +3199,42 @@ and will not be shared or disclosed to the Amnezia or any third parties
Дата створення:
-
+
Rename
Перейменувати
-
+
Client name
Назва клієнта
-
+
Save
Зберегти
-
+
Revoke
Відкликати
-
+
Revoke the config for a user - %1?
Відкликати доступ для користувача - %1?
-
+
The user will no longer be able to connect to your server.
Користувач більше не зможе підключатись до вашого сервера
-
+
Continue
Продовжити
-
+
Cancel
Відмінити
@@ -3317,17 +3324,17 @@ and will not be shared or disclosed to the Amnezia or any third parties
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
Логування було вимкнене через 14 днів, файли журналів були видалені
-
+
Settings restored from backup file
Відновлення налаштувань із бекап файлу
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3726,17 +3733,17 @@ and will not be shared or disclosed to the Amnezia or any third parties
Конфігурація не містить контейнерів і облікових даних для підключення до серверу
-
+
Error when retrieving configuration from API
-
+
This config has already been added to the application
Ця конфігурація вже була додана в застосунок
-
+
ErrorCode: %1.
@@ -3795,62 +3802,72 @@ and will not be shared or disclosed to the Amnezia or any third parties
VPN pool error: no available addresses
-
+
+ Unable to open config file
+
+
+
+
VPN connection error
-
+
In the response from the server, an empty config was received
-
+
SSL error occurred
-
+
Server response timeout on api request
-
+
Missing AGW public key
-
- QFile error: The file could not be opened
-
-
-
-
- QFile error: An error occurred when reading from the file
+
+ Failed to decrypt response payload
- QFile error: The file could not be accessed
+ QFile error: The file could not be opened
- QFile error: An unspecified error occurred
+ QFile error: An error occurred when reading from the file
- QFile error: A fatal error occurred
+ QFile error: The file could not be accessed
+ QFile error: An unspecified error occurred
+
+
+
+
+ QFile error: A fatal error occurred
+
+
+
+
QFile error: The operation was aborted
-
+
Internal error
Internal error
@@ -4531,7 +4548,7 @@ This means that AmneziaWG keeps the fast performance of the original while addin
VpnConnection
-
+
Mbps
Mbps
diff --git a/client/translations/amneziavpn_ur_PK.ts b/client/translations/amneziavpn_ur_PK.ts
index 495aa6ac..0eeddd04 100644
--- a/client/translations/amneziavpn_ur_PK.ts
+++ b/client/translations/amneziavpn_ur_PK.ts
@@ -89,60 +89,60 @@
ConnectionController
-
-
-
+
+
+
Connect
جوڑنا
-
+
The selected protocol is not supported on the current platform
منتخب کردہ پروٹوکول موجودہ پلیٹ فارم پر تعاون یافتہ نہیں ہے
-
+
VPN Protocols is not installed.
Please install VPN container at first
وی پی این پروٹوکول انسٹال نہیں ہے,براہ کرم پہلےوی پی این کنٹینر انسٹال کریں
-
+
unable to create configuration
تشکیل تیار کرنے میں ناکام
-
+
Connecting...
جوڑاجارھاھے....
-
+
Connected
جوڑاجارھاھے
-
+
Reconnecting...
دوبارہ جوڑنےکی کوشش...
-
+
Disconnecting...
منقطع کرنا...
-
+
Preparing...
تیاری کیا جا رہا ہے...
-
+
Settings updated successfully, reconnnection...
ترتیب ک ھوگی،دوبارہ جوڑنےکی کوشش...
-
+
Settings updated successfully
دوبارہ ترتیب تاذہ کامیاب
@@ -252,23 +252,20 @@ Can't be disabled for current server
ImportController
-
Unable to open file
- فائل کو کھولنے سے قاصر ہے
+ فائل کو کھولنے سے قاصر ہے
-
-
Invalid configuration file
- غلط کنفیگریشن فائل
+ غلط کنفیگریشن فائل
-
+
Scanned %1 of %2.
سکین%1 کی%2.
-
+
In the imported configuration, potentially dangerous lines were found:
@@ -276,86 +273,86 @@ Can't be disabled for current server
InstallController
-
+
%1 installed successfully.
%1 کامیابی سےنصب.
-
+
%1 is already installed on the server.
%1 پہلے ہی سرور پر انسٹال ہے.
-
+
Added containers that were already installed on the server
وہ کنٹینرز شامل کیے گئے جو پہلے سے سرور پر نصب تھے
-
+
Already installed containers were found on the server. All installed containers have been added to the application
سرور پر پہلے سے نصب کنٹینرز پائے گئے۔ تمام نصب کنٹینرز کو ایپلی کیشن میں شامل کر دیا گیا ہے
-
+
Settings updated successfully
ترتیب کامیابی کے ساتھ اپ ڈیٹ ہو گئی
-
+
Server '%1' was rebooted
سرور %1 دوبارہ چالو کیا گیا تھا
-
+
Server '%1' was removed
سرور %1 ہٹا دیا گیا تھا
-
+
All containers from server '%1' have been removed
سرور '%1' سے تمام کنٹینرز ہٹا دیے گئے ہیں
-
+
%1 has been removed from the server '%2'
سرور '%2' سے %1 ہٹا دیا گیا ہے
-
+
Api config removed
-
+
%1 cached profile cleared
%1 کیش کردہ پروفائل ختم کر دی گئی
-
+
Please login as the user
براہ کرم صارف کے طور پر لاگ ان کریں
-
+
Server added successfully
سرور کامیابی سے شامل کیا گیا
-
+
%1 installed successfully.
-
+
API config reloaded
-
+
Successfully changed the country of connection to %1
@@ -2386,97 +2383,107 @@ Already installed containers were found on the server. All installed containers
کنکشن کی ترتیبات یا بیک اپ والی فائل
-
+
Connection
کنکشن
-
+
Settings
ترتیبات
-
+
Enable logs
- Insert the key, add a configuration file or scan the QR-code
-
-
-
-
- Insert key
+ Support tag
+ Copied
+
+
+
+
+ Insert the key, add a configuration file or scan the QR-code
+
+
+
+
+ Insert key
+
+
+
+
Insert
داخل کریں
-
+
Continue
-
+
Other connection options
-
+
VPN by Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
-
+
Self-hosted VPN
-
+
Configure Amnezia VPN on your own server
-
+
Restore from backup
بیک اپ سے بحال کریں
-
+
Open backup file
بیک اپ فائل کو کھولیں
-
+
Backup files (*.backup)
بیک اپ فائلیں (*.backup)
-
+
File with connection settings
کنکشن کی ترتیبات والی فائل
-
+
Open config file
کنفیگ فائل کو کھولیں
-
+
QR code
QR کوڈ
-
+
I have nothing
میرے پاس کچھ نہیں ہے
@@ -2861,27 +2868,27 @@ Already installed containers were found on the server. All installed containers
تلاش
-
+
Creation date: %1
-
+
Latest handshake: %1
-
+
Data received: %1
-
+
Data sent: %1
-
+
Allowed IPs: %1
@@ -2890,42 +2897,42 @@ Already installed containers were found on the server. All installed containers
تخلیق کی تاریخ:
-
+
Rename
نام تبدیل
-
+
Client name
کلائنٹ کا نام
-
+
Save
محفوظ
-
+
Revoke
واپس لین
-
+
Revoke the config for a user - %1?
کیا آپ مستعمل کے لئے کنفیگ کو واپس لینا چاہتے ہیں - %1؟
-
+
The user will no longer be able to connect to your server.
صارف آپ کے سرور سے متصل ہونے کا اختیار نہیں رہے گا.
-
+
Continue
جاری رکھیں
-
+
Cancel
منسوخ
@@ -3043,17 +3050,17 @@ Already installed containers were found on the server. All installed containers
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
لاگنگ کو 14 دنوں کے بعد غیر فعال کر دیا گیا، لاگ فائلوں کو حذف کر دیا گیا
-
+
Settings restored from backup file
ترتیبات بیک اپ فائل سے بحال کردی گئی ہیں
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3392,22 +3399,22 @@ Already installed containers were found on the server. All installed containers
سرور سے منسلک ہونے کا ٹائم آؤٹ
-
+
VPN connection error
VPN کنکشن کی خرابی
-
+
Error when retrieving configuration from API
آپی سے کنفیگریشن بازیافت کرتے وقت خرابی
-
+
This config has already been added to the application
یہ تشکیل پہلے ہی ایپلی کیشن میں شامل کی جا چکی ہے
-
+
ErrorCode: %1.
ایرر کوڈ: %1.
@@ -3482,57 +3489,67 @@ Already installed containers were found on the server. All installed containers
ترتیب میں سرور سے منسلک ہونے کے لیے کوئی کنٹینرز اور اسناد نہیں ہیں
-
- In the response from the server, an empty config was received
+
+ Unable to open config file
- SSL error occurred
+ In the response from the server, an empty config was received
- Server response timeout on api request
+ SSL error occurred
+ Server response timeout on api request
+
+
+
+
Missing AGW public key
-
+
+ Failed to decrypt response payload
+
+
+
+
QFile error: The file could not be opened
QFile کی خرابی: فائل کو نہیں کھولا جا سکا
-
+
QFile error: An error occurred when reading from the file
کیو فائل کی خرابی: فائل سے پڑھتے وقت ایک خرابی پیش آگئی
-
+
QFile error: The file could not be accessed
QFile کی خرابی: فائل تک رسائی نہیں ہو سکی
-
+
QFile error: An unspecified error occurred
کیو فائل میں خرابی: ایک غیر متعینہ خرابی پیش آگئی
-
+
QFile error: A fatal error occurred
کیو فائل میں خرابی: ایک مہلک خرابی پیش آگئی
-
+
QFile error: The operation was aborted
کیو فائل کی خرابی: آپریشن روک دیا گیا تھا
-
+
Internal error
داخلی خامی
@@ -4073,7 +4090,7 @@ While it offers a blend of security, stability, and speed, it's essential t
VpnConnection
-
+
Mbps
ایم بی پی ایس
diff --git a/client/translations/amneziavpn_zh_CN.ts b/client/translations/amneziavpn_zh_CN.ts
index c3f15afb..563089a9 100644
--- a/client/translations/amneziavpn_zh_CN.ts
+++ b/client/translations/amneziavpn_zh_CN.ts
@@ -89,60 +89,60 @@
ConnectionController
-
-
-
+
+
+
Connect
连接
-
+
VPN Protocols is not installed.
Please install VPN container at first
请先安装VPN协议
-
+
Connecting...
连接中
-
+
Connected
已连接
-
+
Reconnecting...
重连中
-
+
Disconnecting...
断开中
-
+
Preparing...
-
+
Settings updated successfully, reconnnection...
配置已更新, 重连中...
-
+
Settings updated successfully
配置更新成功
-
+
The selected protocol is not supported on the current platform
当前平台不支持所选协议
-
+
unable to create configuration
@@ -257,23 +257,12 @@ Can't be disabled for current server
ImportController
-
- Unable to open file
-
-
-
-
-
- Invalid configuration file
-
-
-
-
+
Scanned %1 of %2.
扫描 %1 of %2.
-
+
In the imported configuration, potentially dangerous lines were found:
@@ -289,75 +278,75 @@ Can't be disabled for current server
已安装在服务器上
-
+
%1 installed successfully.
%1 安装成功。
-
+
%1 is already installed on the server.
服务器上已经安装 %1。
-
+
Added containers that were already installed on the server
添加已安装在服务器上的容器
-
+
Already installed containers were found on the server. All installed containers have been added to the application
在服务上发现已经安装协议并添加至应用
-
+
Settings updated successfully
配置更新成功
-
+
Server '%1' was rebooted
服务器 '%1' 已重新启动
-
+
Server '%1' was removed
已移除服务器 '%1'
-
+
All containers from server '%1' have been removed
服务器 '%1' 的所有容器已移除
-
+
%1 has been removed from the server '%2'
%1 已从服务器 '%2' 上移除
-
+
Api config removed
-
+
%1 cached profile cleared
-
+
%1 installed successfully.
-
+
API config reloaded
-
+
Successfully changed the country of connection to %1
@@ -378,12 +367,12 @@ Already installed containers were found on the server. All installed containers
协议已从
-
+
Please login as the user
请以用户身份登录
-
+
Server added successfully
增加服务器成功
@@ -2549,97 +2538,107 @@ It's okay as long as it's from someone you trust.
包含连接配置或备份的文件
-
+
Connection
连接
-
+
Settings
设置
-
+
Enable logs
- Insert the key, add a configuration file or scan the QR-code
-
-
-
-
- Insert key
+ Support tag
+ Copied
+
+
+
+
+ Insert the key, add a configuration file or scan the QR-code
+
+
+
+
+ Insert key
+
+
+
+
Insert
插入
-
+
Continue
继续
-
+
Other connection options
-
+
VPN by Amnezia
-
+
Connect to classic paid and free VPN services from Amnezia
-
+
Self-hosted VPN
-
+
Configure Amnezia VPN on your own server
-
+
Restore from backup
从备份还原
-
+
Open backup file
打开备份文件
-
+
Backup files (*.backup)
-
+
File with connection settings
包含连接配置的文件
-
+
Open config file
打开配置文件
-
+
QR code
二维码
-
+
I have nothing
我没有
@@ -3067,27 +3066,27 @@ and will not be shared or disclosed to the Amnezia or any third parties
搜索
-
+
Creation date: %1
-
+
Latest handshake: %1
-
+
Data received: %1
-
+
Data sent: %1
-
+
Allowed IPs: %1
@@ -3096,42 +3095,42 @@ and will not be shared or disclosed to the Amnezia or any third parties
创建日期:
-
+
Rename
重新命名
-
+
Client name
客户名称
-
+
Save
保存
-
+
Revoke
撤销
-
+
Revoke the config for a user - %1?
撤销用户的配置- %1?
-
+
The user will no longer be able to connect to your server.
该用户将无法再连接到您的服务器.
-
+
Continue
继续
-
+
Cancel
取消
@@ -3288,17 +3287,17 @@ and will not be shared or disclosed to the Amnezia or any third parties
PageStart
-
+
Logging was disabled after 14 days, log files were deleted
-
+
Settings restored from backup file
从备份文件还原配置
-
+
Logging is enabled. Note that logs will be automaticallydisabled after 14 days, and all log files will be deleted.
@@ -3651,6 +3650,11 @@ and will not be shared or disclosed to the Amnezia or any third parties
SCP error: Generic failure
+
+
+ Unable to open config file
+
+
Sftp error: End-of-file encountered
Sftp错误: End-of-file encountered
@@ -3704,72 +3708,77 @@ and will not be shared or disclosed to the Amnezia or any third parties
Sftp 错误: 远程驱动器中没有媒介
-
+
VPN connection error
VPN 连接错误
-
+
Error when retrieving configuration from API
从 API 检索配置时出错
-
+
This config has already been added to the application
该配置已添加到应用程序中
-
+
In the response from the server, an empty config was received
-
+
SSL error occurred
-
+
Server response timeout on api request
-
+
Missing AGW public key
-
- QFile error: The file could not be opened
-
-
-
-
- QFile error: An error occurred when reading from the file
+
+ Failed to decrypt response payload
- QFile error: The file could not be accessed
+ QFile error: The file could not be opened
- QFile error: An unspecified error occurred
+ QFile error: An error occurred when reading from the file
- QFile error: A fatal error occurred
+ QFile error: The file could not be accessed
+ QFile error: An unspecified error occurred
+
+
+
+
+ QFile error: A fatal error occurred
+
+
+
+
QFile error: The operation was aborted
-
+
ErrorCode: %1.
错误代码: %1.
@@ -3837,7 +3846,7 @@ and will not be shared or disclosed to the Amnezia or any third parties
该配置不包含任何用于连接到服务器的容器和凭据。
-
+
Internal error
@@ -4517,7 +4526,7 @@ While it offers a blend of security, stability, and speed, it's essential t
VpnConnection
-
+
Mbps
diff --git a/client/ui/controllers/connectionController.cpp b/client/ui/controllers/connectionController.cpp
index c7f95000..f8516f6e 100644
--- a/client/ui/controllers/connectionController.cpp
+++ b/client/ui/controllers/connectionController.cpp
@@ -34,13 +34,13 @@ ConnectionController::ConnectionController(const QSharedPointer &s
void ConnectionController::openConnection()
{
-// #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
-// if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
-// {
-// emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
-// return;
-// }
-// #endif
+#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
+ if (!Utils::processIsRunning(Utils::executable(SERVICE_NAME, false), true))
+ {
+ emit connectionErrorOccurred(ErrorCode::AmneziaServiceNotRunning);
+ return;
+ }
+#endif
int serverIndex = m_serversModel->getDefaultServerIndex();
QJsonObject serverConfig = m_serversModel->getServerConfig(serverIndex);
@@ -51,6 +51,9 @@ void ConnectionController::openConnection()
if (configVersion == ApiConfigSources::Telegram
&& !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
emit updateApiConfigFromTelegram();
+ } else if (configVersion == ApiConfigSources::AmneziaGateway
+ && !m_serversModel->data(serverIndex, ServersModel::Roles::HasInstalledContainers).toBool()) {
+ emit updateApiConfigFromGateway();
} else if (configVersion && m_serversModel->isApiKeyExpired(serverIndex)) {
qDebug() << "attempt to update api config by end_date event";
if (configVersion == ApiConfigSources::Telegram) {
diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp
index 261551ea..f7e96bff 100644
--- a/client/ui/controllers/importController.cpp
+++ b/client/ui/controllers/importController.cpp
@@ -39,11 +39,12 @@ namespace
const QString amneziaConfigPatternUserName = "userName";
const QString amneziaConfigPatternPassword = "password";
const QString amneziaFreeConfigPattern = "api_key";
+ const QString amneziaPremiumConfigPattern = "auth_data";
const QString backupPattern = "Servers/serversList";
if (config.contains(backupPattern)) {
return ConfigTypes::Backup;
- } else if (config.contains(amneziaConfigPattern) || config.contains(amneziaFreeConfigPattern)
+ } else if (config.contains(amneziaConfigPattern) || config.contains(amneziaFreeConfigPattern) || config.contains(amneziaPremiumConfigPattern)
|| (config.contains(amneziaConfigPatternHostName) && config.contains(amneziaConfigPatternUserName)
&& config.contains(amneziaConfigPatternPassword))) {
return ConfigTypes::Amnezia;
@@ -84,7 +85,7 @@ bool ImportController::extractConfigFromFile(const QString &fileName)
return extractConfigFromData(data);
}
- emit importErrorOccurred(tr("Unable to open file"), false);
+ emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
return false;
}
@@ -188,12 +189,12 @@ bool ImportController::extractConfigFromData(QString data)
if (!m_serversModel->getServersCount()) {
emit restoreAppConfig(config.toUtf8());
} else {
- emit importErrorOccurred(tr("Invalid configuration file"), false);
+ emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
}
break;
}
case ConfigTypes::Invalid: {
- emit importErrorOccurred(tr("Invalid configuration file"), false);
+ emit importErrorOccurred(ErrorCode::ImportInvalidConfigError, false);
break;
}
}
diff --git a/client/ui/controllers/importController.h b/client/ui/controllers/importController.h
index 61205253..05e320a5 100644
--- a/client/ui/controllers/importController.h
+++ b/client/ui/controllers/importController.h
@@ -54,7 +54,6 @@ public slots:
signals:
void importFinished();
- void importErrorOccurred(const QString &errorMessage, bool goToPageHome);
void importErrorOccurred(ErrorCode errorCode, bool goToPageHome);
void qrDecodingFinished();
diff --git a/client/ui/controllers/installController.cpp b/client/ui/controllers/installController.cpp
old mode 100644
new mode 100755
index c6f17057..306e7f38
--- a/client/ui/controllers/installController.cpp
+++ b/client/ui/controllers/installController.cpp
@@ -32,32 +32,8 @@ namespace
constexpr char availableCountries[] = "available_countries";
constexpr char apiConfig[] = "api_config";
+ constexpr char authData[] = "auth_data";
}
-
-#ifdef Q_OS_WINDOWS
- QString getNextDriverLetter()
- {
- QProcess drivesProc;
- drivesProc.start("wmic logicaldisk get caption");
- drivesProc.waitForFinished();
- QString drives = drivesProc.readAll();
- qDebug() << drives;
-
- QString letters = "CFGHIJKLMNOPQRSTUVWXYZ";
- QString letter;
- for (int i = letters.size() - 1; i > 0; i--) {
- letter = letters.at(i);
- if (!drives.contains(letter + ":"))
- break;
- }
- if (letter == "C:") {
- // set err info
- qDebug() << "Can't find free drive letter";
- return "";
- }
- return letter;
- }
-#endif
}
InstallController::InstallController(const QSharedPointer &serversModel, const QSharedPointer &containersModel,
@@ -135,10 +111,10 @@ void InstallController::install(DockerContainer container, int port, TransportPr
containerConfig[config_key::transportPacketMagicHeader] = transportPacketMagicHeader;
} else if (container == DockerContainer::Sftp) {
containerConfig.insert(config_key::userName, protocols::sftp::defaultUserName);
- containerConfig.insert(config_key::password, Utils::getRandomString(10));
+ containerConfig.insert(config_key::password, Utils::getRandomString(16));
} else if (container == DockerContainer::Socks5Proxy) {
containerConfig.insert(config_key::userName, protocols::socks5Proxy::defaultUserName);
- containerConfig.insert(config_key::password, Utils::getRandomString(10));
+ containerConfig.insert(config_key::password, Utils::getRandomString(16));
}
config.insert(config_key::container, ContainerProps::containerToString(container));
@@ -667,7 +643,7 @@ void InstallController::mountSftpDrive(const QString &port, const QString &passw
QString hostname = serverCredentials.hostName;
#ifdef Q_OS_WINDOWS
- mountPath = getNextDriverLetter() + ":";
+ mountPath = Utils::getNextDriverLetter() + ":";
// QString cmd = QString("net use \\\\sshfs\\%1@x.x.x.x!%2 /USER:%1 %3")
// .arg(labelTftpUserNameText())
// .arg(labelTftpPortText())
@@ -768,7 +744,7 @@ bool InstallController::checkSshConnection(QSharedPointer serv
} else {
if (output.contains(tr("Please login as the user"))) {
output.replace("\n", "");
- emit installationErrorOccurred(output);
+ emit wrongInstallationUser(output);
return false;
}
}
@@ -826,7 +802,7 @@ bool InstallController::installServiceFromApi()
ErrorCode errorCode = apiController.getConfigForService(m_settings->getInstallationUuid(true), m_apiServicesModel->getCountryCode(),
m_apiServicesModel->getSelectedServiceType(),
- m_apiServicesModel->getSelectedServiceProtocol(), "", serverConfig);
+ m_apiServicesModel->getSelectedServiceProtocol(), "", QJsonObject(), serverConfig);
if (errorCode != ErrorCode::NoError) {
emit installationErrorOccurred(errorCode);
return false;
@@ -853,24 +829,26 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
auto serverConfig = m_serversModel->getServerConfig(serverIndex);
auto apiConfig = serverConfig.value(configKey::apiConfig).toObject();
+ auto authData = serverConfig.value(configKey::authData).toObject();
QJsonObject newServerConfig;
- ErrorCode errorCode =
- apiController.getConfigForService(m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(),
- apiConfig.value(configKey::serviceType).toString(),
- apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode, newServerConfig);
+ ErrorCode errorCode = apiController.getConfigForService(
+ m_settings->getInstallationUuid(true), apiConfig.value(configKey::userCountryCode).toString(),
+ apiConfig.value(configKey::serviceType).toString(), apiConfig.value(configKey::serviceProtocol).toString(), newCountryCode,
+ authData, newServerConfig);
if (errorCode != ErrorCode::NoError) {
emit installationErrorOccurred(errorCode);
return false;
}
QJsonObject newApiConfig = newServerConfig.value(configKey::apiConfig).toObject();
- newApiConfig.insert(configKey::serviceInfo, apiConfig.value(configKey::serviceInfo));
newApiConfig.insert(configKey::userCountryCode, apiConfig.value(configKey::userCountryCode));
newApiConfig.insert(configKey::serviceType, apiConfig.value(configKey::serviceType));
newApiConfig.insert(configKey::serviceProtocol, apiConfig.value(configKey::serviceProtocol));
newServerConfig.insert(configKey::apiConfig, newApiConfig);
+ newServerConfig.insert(configKey::authData, authData);
+ newServerConfig.insert(config_key::crc, serverConfig.value(config_key::crc));
m_serversModel->editServer(newServerConfig, serverIndex);
if (reloadServiceConfig) {
diff --git a/client/ui/controllers/installController.h b/client/ui/controllers/installController.h
index 7eea216a..d7ab3553 100644
--- a/client/ui/controllers/installController.h
+++ b/client/ui/controllers/installController.h
@@ -75,8 +75,8 @@ signals:
void removeAllContainersFinished(const QString &finishedMessage);
void removeProcessedContainerFinished(const QString &finishedMessage);
- void installationErrorOccurred(const QString &errorMessage);
void installationErrorOccurred(ErrorCode errorCode);
+ void wrongInstallationUser(const QString &message);
void serverAlreadyExists(int serverIndex);
diff --git a/client/ui/models/apiCountryModel.cpp b/client/ui/models/apiCountryModel.cpp
index ae58329f..922a9d56 100644
--- a/client/ui/models/apiCountryModel.cpp
+++ b/client/ui/models/apiCountryModel.cpp
@@ -39,6 +39,9 @@ QVariant ApiCountryModel::data(const QModelIndex &index, int role) const
case CountryNameRole: {
return countryInfo.value(configKey::serverCountryName).toString();
}
+ case CountryImageCodeRole: {
+ return countryInfo.value(configKey::serverCountryCode).toString().toUpper();
+ }
}
return QVariant();
@@ -76,5 +79,6 @@ QHash ApiCountryModel::roleNames() const
QHash roles;
roles[CountryNameRole] = "countryName";
roles[CountryCodeRole] = "countryCode";
+ roles[CountryImageCodeRole] = "countryImageCode";
return roles;
}
diff --git a/client/ui/models/apiCountryModel.h b/client/ui/models/apiCountryModel.h
index 8789158b..b9e243d0 100644
--- a/client/ui/models/apiCountryModel.h
+++ b/client/ui/models/apiCountryModel.h
@@ -11,7 +11,8 @@ class ApiCountryModel : public QAbstractListModel
public:
enum Roles {
CountryNameRole = Qt::UserRole + 1,
- CountryCodeRole
+ CountryCodeRole,
+ CountryImageCodeRole
};
explicit ApiCountryModel(QObject *parent = nullptr);
diff --git a/client/ui/models/clientManagementModel.cpp b/client/ui/models/clientManagementModel.cpp
index 7d3be2cb..7445d60f 100644
--- a/client/ui/models/clientManagementModel.cpp
+++ b/client/ui/models/clientManagementModel.cpp
@@ -77,6 +77,7 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
{
beginResetModel();
m_clientsTable = QJsonArray();
+ endResetModel();
ErrorCode error = ErrorCode::NoError;
@@ -90,10 +91,10 @@ ErrorCode ClientManagementModel::updateModel(const DockerContainer container, co
const QByteArray clientsTableString = serverController->getTextFileFromContainer(container, credentials, clientsTableFile, error);
if (error != ErrorCode::NoError) {
logger.error() << "Failed to get the clientsTable file from the server";
- endResetModel();
return error;
}
+ beginResetModel();
m_clientsTable = QJsonDocument::fromJson(clientsTableString).array();
if (m_clientsTable.isEmpty()) {
@@ -601,5 +602,6 @@ QHash ClientManagementModel::roleNames() const
roles[LatestHandshakeRole] = "latestHandshake";
roles[DataReceivedRole] = "dataReceived";
roles[DataSentRole] = "dataSent";
+ roles[AllowedIpsRole] = "allowedIps";
return roles;
}
diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp
index 85e5dae2..c87499a7 100644
--- a/client/ui/models/servers_model.cpp
+++ b/client/ui/models/servers_model.cpp
@@ -771,5 +771,5 @@ const QString ServersModel::getDefaultServerImagePathCollapsed()
if (countryCode.isEmpty()) {
return "";
}
- return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode);
+ return QString("qrc:/countriesFlags/images/flagKit/%1.svg").arg(countryCode.toUpper());
}
diff --git a/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml b/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
index 234e5142..120313cd 100644
--- a/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
+++ b/client/ui/qml/Pages2/PageSettingsApiLanguageList.qml
@@ -90,7 +90,7 @@ PageType {
Layout.rightMargin: 32
Layout.alignment: Qt.AlignRight
- source: "qrc:/countriesFlags/images/flagKit/" + countryCode + ".svg"
+ source: "qrc:/countriesFlags/images/flagKit/" + countryImageCode + ".svg"
}
}
diff --git a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
index 7f7cf9e1..7c031997 100644
--- a/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardConfigSource.qml
@@ -49,6 +49,8 @@ PageType {
HeaderType {
+ property bool isVisible: SettingsController.getInstallationUuid() !== "" || PageController.isStartPageVisible()
+
Layout.fillWidth: true
Layout.topMargin: 24
Layout.rightMargin: 16
@@ -56,7 +58,7 @@ PageType {
headerText: qsTr("Connection")
- actionButtonImage: PageController.isStartPageVisible() ? "qrc:/images/controls/more-vertical.svg" : ""
+ actionButtonImage: isVisible ? "qrc:/images/controls/more-vertical.svg" : ""
actionButtonFunction: function() {
moreActionsDrawer.open()
}
@@ -67,18 +69,19 @@ PageType {
parent: root
anchors.fill: parent
- expandedHeight: root.height * 0.35
+ expandedHeight: root.height * 0.5
expandedContent: ColumnLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
- anchors.leftMargin: 16
- anchors.rightMargin: 16
+ spacing: 0
HeaderType {
Layout.fillWidth: true
Layout.topMargin: 32
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
headerText: qsTr("Settings")
}
@@ -87,9 +90,12 @@ PageType {
id: switcher
Layout.fillWidth: true
Layout.topMargin: 16
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
text: qsTr("Enable logs")
+ visible: PageController.isStartPageVisible()
checked: SettingsController.isLoggingEnabled
onCheckedChanged: {
if (checked !== SettingsController.isLoggingEnabled) {
@@ -98,6 +104,28 @@ PageType {
}
}
+ LabelWithButtonType {
+ id: supportUuid
+ Layout.fillWidth: true
+ Layout.topMargin: 16
+
+ text: qsTr("Support tag")
+ descriptionText: SettingsController.getInstallationUuid()
+
+ descriptionOnTop: true
+
+ rightImageSource: "qrc:/images/controls/copy.svg"
+ rightImageColor: AmneziaStyle.color.paleGray
+
+ visible: SettingsController.getInstallationUuid() !== ""
+ clickedFunction: function() {
+ GC.copyToClipBoard(descriptionText)
+ PageController.showNotificationMessage(qsTr("Copied"))
+ if (!GC.isMobile()) {
+ this.rightButton.forceActiveFocus()
+ }
+ }
+ }
}
}
}
diff --git a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml
index 3aac1555..92048f36 100644
--- a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml
+++ b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml
@@ -37,7 +37,7 @@ PageType {
Connections {
target: ImportController
- function onImportErrorOccurred(errorMessage, goToPageHome) {
+ function onImportErrorOccurred(error, goToPageHome) {
if (goToPageHome) {
PageController.goToStartPage()
} else {
diff --git a/client/ui/qml/Pages2/PageShare.qml b/client/ui/qml/Pages2/PageShare.qml
index 6640df36..617b1091 100644
--- a/client/ui/qml/Pages2/PageShare.qml
+++ b/client/ui/qml/Pages2/PageShare.qml
@@ -772,7 +772,8 @@ PageType {
}
}
- anchors.fill: parent
+ width: root.width
+ height: root.height
expandedContent: ColumnLayout {
id: expandedContent
@@ -783,8 +784,6 @@ PageType {
anchors.leftMargin: 16
anchors.rightMargin: 16
- spacing: 8
-
onImplicitHeightChanged: {
clientInfoDrawer.expandedHeight = expandedContent.implicitHeight + 32
}
@@ -797,57 +796,54 @@ PageType {
}
}
- Header2Type {
- Layout.fillWidth: true
-
- headerText: clientName
- }
-
- ColumnLayout
- {
- id: textColumn
- property string textColor: AmneziaStyle.color.mutedGray
+ Header2TextType {
+ Layout.maximumWidth: parent.width
Layout.bottomMargin: 24
- ParagraphTextType {
- color: textColumn.textColor
- visible: creationDate
- Layout.fillWidth: true
+ text: clientName
+ maximumLineCount: 2
+ wrapMode: Text.Wrap
+ elide: Qt.ElideRight
+ }
- text: qsTr("Creation date: %1").arg(creationDate)
- }
+ ParagraphTextType {
+ color: AmneziaStyle.color.mutedGray
+ visible: creationDate
+ Layout.fillWidth: true
- ParagraphTextType {
- color: textColumn.textColor
- visible: latestHandshake
- Layout.fillWidth: true
+ text: qsTr("Creation date: %1").arg(creationDate)
+ }
- text: qsTr("Latest handshake: %1").arg(latestHandshake)
- }
+ ParagraphTextType {
+ color: AmneziaStyle.color.mutedGray
+ visible: latestHandshake
+ Layout.fillWidth: true
- ParagraphTextType {
- color: textColumn.textColor
- visible: dataReceived
- Layout.fillWidth: true
+ text: qsTr("Latest handshake: %1").arg(latestHandshake)
+ }
- text: qsTr("Data received: %1").arg(dataReceived)
- }
+ ParagraphTextType {
+ color: AmneziaStyle.color.mutedGray
+ visible: dataReceived
+ Layout.fillWidth: true
- ParagraphTextType {
- color: textColumn.textColor
- visible: dataSent
- Layout.fillWidth: true
+ text: qsTr("Data received: %1").arg(dataReceived)
+ }
- text: qsTr("Data sent: %1").arg(dataSent)
- }
+ ParagraphTextType {
+ color: AmneziaStyle.color.mutedGray
+ visible: dataSent
+ Layout.fillWidth: true
- ParagraphTextType {
- color: textColumn.textColor
- visible: allowedIps
- Layout.fillWidth: true
+ text: qsTr("Data sent: %1").arg(dataSent)
+ }
- text: qsTr("Allowed IPs: %1").arg(allowedIps)
- }
+ ParagraphTextType {
+ color: AmneziaStyle.color.mutedGray
+ visible: allowedIps
+ Layout.fillWidth: true
+
+ text: qsTr("Allowed IPs: %1").arg(allowedIps)
}
Item {
@@ -952,6 +948,7 @@ PageType {
BasicButtonType {
id: revokeButton
Layout.fillWidth: true
+ Layout.topMargin: 8
defaultColor: AmneziaStyle.color.transparent
hoveredColor: AmneziaStyle.color.translucentWhite
diff --git a/client/ui/qml/Pages2/PageStart.qml b/client/ui/qml/Pages2/PageStart.qml
index bb6663fb..640c61ef 100644
--- a/client/ui/qml/Pages2/PageStart.qml
+++ b/client/ui/qml/Pages2/PageStart.qml
@@ -123,6 +123,10 @@ PageType {
}
}
+ function onWrongInstallationUser(message) {
+ onInstallationErrorOccurred(message)
+ }
+
function onUpdateContainerFinished(message) {
PageController.showNotificationMessage(message)
PageController.closePage()
diff --git a/client/utilities.cpp b/client/utilities.cpp
old mode 100644
new mode 100755
index 4047365f..1cc69aeb
--- a/client/utilities.cpp
+++ b/client/utilities.cpp
@@ -10,18 +10,72 @@
#include
#include "utilities.h"
-#include "version.h"
+
+#ifdef Q_OS_WINDOWS
+QString printErrorMessage(DWORD errorCode) {
+ LPVOID lpMsgBuf;
+
+ DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+
+ DWORD dwLanguageId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
+
+ FormatMessageW(
+ dwFlags,
+ NULL,
+ errorCode,
+ dwLanguageId,
+ (LPWSTR)&lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ QString errorMsg = QString::fromWCharArray((LPCWSTR)lpMsgBuf);
+ LocalFree(lpMsgBuf);
+ return errorMsg.trimmed();
+}
+
+QString Utils::getNextDriverLetter()
+{
+ DWORD drivesBitmask = GetLogicalDrives();
+ if (drivesBitmask == 0) {
+ DWORD error = GetLastError();
+ qDebug() << "GetLogicalDrives failed. Error code:" << error;
+ return "";
+ }
+
+ QString letters = "FGHIJKLMNOPQRSTUVWXYZ";
+ QString availableLetter;
+
+ for (int i = letters.size() - 1; i >= 0; --i) {
+ QChar letterChar = letters.at(i);
+ int driveIndex = letterChar.toLatin1() - 'A';
+
+ if ((drivesBitmask & (1 << driveIndex)) == 0) {
+ availableLetter = letterChar;
+ break;
+ }
+ }
+
+ if (availableLetter.isEmpty()) {
+ qDebug() << "Can't find free drive letter";
+ return "";
+ }
+
+ return availableLetter;
+}
+#endif
QString Utils::getRandomString(int len)
{
- const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
-
+ const QString possibleCharacters = QStringLiteral("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString randomString;
+
for (int i = 0; i < len; ++i) {
- quint32 index = QRandomGenerator::global()->generate() % possibleCharacters.length();
- QChar nextChar = possibleCharacters.at(index);
- randomString.append(nextChar);
+ randomString.append(possibleCharacters.at(QRandomGenerator::system()->bounded(possibleCharacters.length())));
}
+
return randomString;
}
@@ -109,30 +163,34 @@ QString Utils::usrExecutable(const QString &baseName)
bool Utils::processIsRunning(const QString &fileName, const bool fullFlag)
{
#ifdef Q_OS_WIN
- QProcess process;
- process.setReadChannel(QProcess::StandardOutput);
- process.setProcessChannelMode(QProcess::MergedChannels);
- process.start("wmic.exe",
- QStringList() << "/OUTPUT:STDOUT"
- << "PROCESS"
- << "get"
- << "Caption");
- process.waitForStarted();
- process.waitForFinished();
- QString processData(process.readAll());
- QStringList processList = processData.split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
- foreach (const QString &rawLine, processList) {
- const QString line = rawLine.simplified();
- if (line.isEmpty()) {
- continue;
- }
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnapshot == INVALID_HANDLE_VALUE) {
+ qWarning() << "Utils::processIsRunning error CreateToolhelp32Snapshot";
+ return false;
+ }
- if (line == fileName) {
+ PROCESSENTRY32W pe32;
+ pe32.dwSize = sizeof(PROCESSENTRY32W);
+
+ if (!Process32FirstW(hSnapshot, &pe32)) {
+ CloseHandle(hSnapshot);
+ qWarning() << "Utils::processIsRunning error Process32FirstW";
+ return false;
+ }
+
+ do {
+ QString exeFile = QString::fromWCharArray(pe32.szExeFile);
+
+ if (exeFile.compare(fileName, Qt::CaseInsensitive) == 0) {
+ CloseHandle(hSnapshot);
return true;
}
- }
+ } while (Process32NextW(hSnapshot, &pe32));
+
+ CloseHandle(hSnapshot);
return false;
-#elif defined(Q_OS_IOS)
+
+#elif defined(Q_OS_IOS) || defined(Q_OS_ANDROID)
return false;
#else
QProcess process;
@@ -150,13 +208,45 @@ bool Utils::processIsRunning(const QString &fileName, const bool fullFlag)
#endif
}
-void Utils::killProcessByName(const QString &name)
+bool Utils::killProcessByName(const QString &name)
{
qDebug().noquote() << "Kill process" << name;
#ifdef Q_OS_WIN
- QProcess::execute("taskkill", QStringList() << "/IM" << name << "/F");
-#elif defined Q_OS_IOS
- return;
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnapshot == INVALID_HANDLE_VALUE)
+ return false;
+
+ PROCESSENTRY32W pe32;
+ pe32.dwSize = sizeof(PROCESSENTRY32W);
+
+ bool success = false;
+
+ if (Process32FirstW(hSnapshot, &pe32)) {
+ do {
+ QString exeFile = QString::fromWCharArray(pe32.szExeFile);
+
+ if (exeFile.compare(name, Qt::CaseInsensitive) == 0) {
+ HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe32.th32ProcessID);
+ if (hProcess != NULL) {
+ if (TerminateProcess(hProcess, 0)) {
+ success = true;
+ } else {
+ DWORD error = GetLastError();
+ qCritical() << "Can't terminate process" << exeFile << "(PID:" << pe32.th32ProcessID << "). Error:" << printErrorMessage(error);
+ }
+ CloseHandle(hProcess);
+ } else {
+ DWORD error = GetLastError();
+ qCritical() << "Can't open process for termination" << exeFile << "(PID:" << pe32.th32ProcessID << "). Error:" << printErrorMessage(error);
+ }
+ }
+ } while (Process32NextW(hSnapshot, &pe32));
+ }
+
+ CloseHandle(hSnapshot);
+ return success;
+#elif defined Q_OS_IOS || defined(Q_OS_ANDROID)
+ return false;
#else
QProcess::execute(QString("pkill %1").arg(name));
#endif
@@ -244,3 +334,22 @@ bool Utils::signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent)
}
#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 (...) {}
+}
diff --git a/client/utilities.h b/client/utilities.h
old mode 100644
new mode 100755
index 9bf8c82a..4a1985b1
--- a/client/utilities.h
+++ b/client/utilities.h
@@ -7,7 +7,8 @@
#include
#ifdef Q_OS_WIN
- #include "Windows.h"
+#include
+#include
#endif
class Utils : public QObject
@@ -27,15 +28,19 @@ public:
static bool initializePath(const QString &path);
static bool processIsRunning(const QString &fileName, const bool fullFlag = false);
- static void killProcessByName(const QString &name);
+ static bool killProcessByName(const QString &name);
static QString openVpnExecPath();
static QString wireguardExecPath();
static QString certUtilPath();
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
static bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent);
+ static QString getNextDriverLetter();
#endif
};
diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp
index 591e396f..ac881bd7 100644
--- a/client/vpnconnection.cpp
+++ b/client/vpnconnection.cpp
@@ -56,14 +56,15 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
{
#ifdef AMNEZIA_DESKTOP
- QString proto = m_settings->defaultContainerName(m_settings->defaultServerIndex());
+ auto container = m_settings->defaultContainer(m_settings->defaultServerIndex());
if (IpcClient::Interface()) {
if (state == Vpn::ConnectionState::Connected) {
IpcClient::Interface()->resetIpStack();
IpcClient::Interface()->flushDns();
- if (!m_vpnConfiguration.value(config_key::configVersion).toInt()) {
+ if (!m_vpnConfiguration.value(config_key::configVersion).toInt() && container != DockerContainer::Awg
+ && container != DockerContainer::WireGuard) {
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
diff --git a/metadata/img-readme/andr.png b/metadata/img-readme/andr.png
deleted file mode 100644
index a39cd52f..00000000
Binary files a/metadata/img-readme/andr.png and /dev/null differ
diff --git a/metadata/img-readme/download.png b/metadata/img-readme/download.png
new file mode 100644
index 00000000..0e6a8850
Binary files /dev/null and b/metadata/img-readme/download.png differ
diff --git a/metadata/img-readme/lin.png b/metadata/img-readme/lin.png
deleted file mode 100644
index 352eae5a..00000000
Binary files a/metadata/img-readme/lin.png and /dev/null differ
diff --git a/metadata/img-readme/mac.png b/metadata/img-readme/mac.png
deleted file mode 100644
index 2cbb32ae..00000000
Binary files a/metadata/img-readme/mac.png and /dev/null differ
diff --git a/metadata/img-readme/testiny.png b/metadata/img-readme/testiny.png
new file mode 100644
index 00000000..4f38a3a9
Binary files /dev/null and b/metadata/img-readme/testiny.png differ
diff --git a/metadata/img-readme/win.png b/metadata/img-readme/win.png
deleted file mode 100644
index 5a35cf49..00000000
Binary files a/metadata/img-readme/win.png and /dev/null differ