Merge branch 'dev' into android-7
# Conflicts: # CMakeLists.txt
This commit is contained in:
commit
a440ddd7e7
12 changed files with 67 additions and 51 deletions
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
||||||
|
|
||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
|
|
||||||
project(${PROJECT} VERSION 4.8.2.3
|
project(${PROJECT} VERSION 4.8.2.4
|
||||||
DESCRIPTION "AmneziaVPN"
|
DESCRIPTION "AmneziaVPN"
|
||||||
HOMEPAGE_URL "https://amnezia.org/"
|
HOMEPAGE_URL "https://amnezia.org/"
|
||||||
)
|
)
|
||||||
|
@ -11,7 +11,7 @@ string(TIMESTAMP CURRENT_DATE "%Y-%m-%d")
|
||||||
set(RELEASE_DATE "${CURRENT_DATE}")
|
set(RELEASE_DATE "${CURRENT_DATE}")
|
||||||
|
|
||||||
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
set(APP_MAJOR_VERSION ${CMAKE_PROJECT_VERSION_MAJOR}.${CMAKE_PROJECT_VERSION_MINOR}.${CMAKE_PROJECT_VERSION_PATCH})
|
||||||
set(APP_ANDROID_VERSION_CODE 1069)
|
set(APP_ANDROID_VERSION_CODE 1071)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
set(MZ_PLATFORM_NAME "linux")
|
set(MZ_PLATFORM_NAME "linux")
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<!-- To request network state -->
|
<!-- To request network state -->
|
||||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" android:maxSdkVersion="30" />
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package org.amnezia.vpn.protocol.wireguard
|
package org.amnezia.vpn.protocol.wireguard
|
||||||
|
|
||||||
import android.net.VpnService.Builder
|
import android.net.VpnService.Builder
|
||||||
import java.io.IOException
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import java.util.Locale
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.launch
|
||||||
import org.amnezia.awg.GoBackend
|
import org.amnezia.awg.GoBackend
|
||||||
import org.amnezia.vpn.protocol.Protocol
|
import org.amnezia.vpn.protocol.Protocol
|
||||||
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
|
||||||
|
@ -27,6 +28,8 @@ open class Wireguard : Protocol() {
|
||||||
|
|
||||||
private var tunnelHandle: Int = -1
|
private var tunnelHandle: Int = -1
|
||||||
protected open val ifName: String = "amn0"
|
protected open val ifName: String = "amn0"
|
||||||
|
private lateinit var scope: CoroutineScope
|
||||||
|
private var statusJob: Job? = null
|
||||||
|
|
||||||
override val statistics: Statistics
|
override val statistics: Statistics
|
||||||
get() {
|
get() {
|
||||||
|
@ -49,46 +52,17 @@ open class Wireguard : Protocol() {
|
||||||
|
|
||||||
override fun internalInit() {
|
override fun internalInit() {
|
||||||
if (!isInitialized) loadSharedLibrary(context, "wg-go")
|
if (!isInitialized) loadSharedLibrary(context, "wg-go")
|
||||||
|
if (this::scope.isInitialized) {
|
||||||
|
scope.cancel()
|
||||||
|
}
|
||||||
|
scope = CoroutineScope(Dispatchers.IO)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
override suspend fun startVpn(config: JSONObject, vpnBuilder: Builder, protect: (Int) -> Boolean) {
|
||||||
val wireguardConfig = parseConfig(config)
|
val wireguardConfig = parseConfig(config)
|
||||||
val startTime = System.currentTimeMillis()
|
|
||||||
start(wireguardConfig, vpnBuilder, protect)
|
start(wireguardConfig, vpnBuilder, protect)
|
||||||
waitForConnection(startTime)
|
|
||||||
state.value = CONNECTED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun waitForConnection(startTime: Long) {
|
|
||||||
Log.d(TAG, "Waiting for connection")
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val time = String.format(Locale.ROOT,"%.3f", startTime / 1000.0)
|
|
||||||
try {
|
|
||||||
delay(1000)
|
|
||||||
var log = getLogcat(time)
|
|
||||||
Log.v(TAG, "First waiting log: $log")
|
|
||||||
// check that there is a connection log,
|
|
||||||
// to avoid infinite connection
|
|
||||||
if (!log.contains("Attaching to interface")) {
|
|
||||||
Log.w(TAG, "Logs do not contain a connection log")
|
|
||||||
return@withContext
|
|
||||||
}
|
|
||||||
while (!log.contains("Received handshake response")) {
|
|
||||||
delay(1000)
|
|
||||||
log = getLogcat(time)
|
|
||||||
}
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(TAG, "Failed to get logcat: $e")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLogcat(time: String): String =
|
|
||||||
ProcessBuilder("logcat", "--buffer=main", "--format=raw", "*:S AmneziaWG/awg0", "-t", time)
|
|
||||||
.redirectErrorStream(true)
|
|
||||||
.start()
|
|
||||||
.inputStream.reader().readText()
|
|
||||||
|
|
||||||
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
protected open fun parseConfig(config: JSONObject): WireguardConfig {
|
||||||
val configData = config.getJSONObject("wireguard_config_data")
|
val configData = config.getJSONObject("wireguard_config_data")
|
||||||
return WireguardConfig.build {
|
return WireguardConfig.build {
|
||||||
|
@ -178,6 +152,43 @@ open class Wireguard : Protocol() {
|
||||||
tunnelHandle = -1
|
tunnelHandle = -1
|
||||||
throw VpnStartException("Protect VPN interface: permission not granted or revoked")
|
throw VpnStartException("Protect VPN interface: permission not granted or revoked")
|
||||||
}
|
}
|
||||||
|
launchStatusJob()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchStatusJob() {
|
||||||
|
Log.d(TAG, "Launch status job")
|
||||||
|
statusJob = scope.launch {
|
||||||
|
while (true) {
|
||||||
|
val lastHandshake = getLastHandshake()
|
||||||
|
Log.v(TAG, "lastHandshake=$lastHandshake")
|
||||||
|
if (lastHandshake == 0L) {
|
||||||
|
delay(1000)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (lastHandshake == -2L || lastHandshake > 0L) state.value = CONNECTED
|
||||||
|
else if (lastHandshake == -1L) state.value = DISCONNECTED
|
||||||
|
statusJob = null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getLastHandshake(): Long {
|
||||||
|
if (tunnelHandle == -1) {
|
||||||
|
Log.e(TAG, "Trying to get config of a non-existent tunnel")
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
val config = GoBackend.awgGetConfig(tunnelHandle)
|
||||||
|
if (config == null) {
|
||||||
|
Log.e(TAG, "Failed to get tunnel config")
|
||||||
|
return -2
|
||||||
|
}
|
||||||
|
val lastHandshake = config.lines().find { it.startsWith("last_handshake_time_sec=") }?.substring(24)?.toLong()
|
||||||
|
if (lastHandshake == null) {
|
||||||
|
Log.e(TAG, "Failed to get last_handshake_time_sec")
|
||||||
|
return -2
|
||||||
|
}
|
||||||
|
return lastHandshake
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stopVpn() {
|
override fun stopVpn() {
|
||||||
|
@ -185,6 +196,8 @@ open class Wireguard : Protocol() {
|
||||||
Log.w(TAG, "Tunnel already down")
|
Log.w(TAG, "Tunnel already down")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
statusJob?.cancel()
|
||||||
|
statusJob = null
|
||||||
val handleToClose = tunnelHandle
|
val handleToClose = tunnelHandle
|
||||||
tunnelHandle = -1
|
tunnelHandle = -1
|
||||||
GoBackend.awgTurnOff(handleToClose)
|
GoBackend.awgTurnOff(handleToClose)
|
||||||
|
|
|
@ -848,7 +848,6 @@ bool InstallController::updateServiceFromApi(const int serverIndex, const QStrin
|
||||||
|
|
||||||
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
newServerConfig.insert(configKey::apiConfig, newApiConfig);
|
||||||
newServerConfig.insert(configKey::authData, authData);
|
newServerConfig.insert(configKey::authData, authData);
|
||||||
newServerConfig.insert(config_key::crc, serverConfig.value(config_key::crc));
|
|
||||||
m_serversModel->editServer(newServerConfig, serverIndex);
|
m_serversModel->editServer(newServerConfig, serverIndex);
|
||||||
|
|
||||||
if (reloadServiceConfig) {
|
if (reloadServiceConfig) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ Popup {
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
Overlay.modal: Rectangle {
|
Overlay.modal: Rectangle {
|
||||||
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
|
color: AmneziaStyle.color.translucentMidnightBlack
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
|
|
@ -19,7 +19,7 @@ RadioButton {
|
||||||
|
|
||||||
property string textColor: AmneziaStyle.color.midnightBlack
|
property string textColor: AmneziaStyle.color.midnightBlack
|
||||||
|
|
||||||
property string pressedBorderColor: Qt.rgba(251/255, 178/255, 106/255, 0.3)
|
property string pressedBorderColor: AmneziaStyle.color.softGoldenApricot
|
||||||
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
|
property string selectedBorderColor: AmneziaStyle.color.goldenApricot
|
||||||
property string defaultBodredColor: AmneziaStyle.color.transparent
|
property string defaultBodredColor: AmneziaStyle.color.transparent
|
||||||
property int borderWidth: 0
|
property int borderWidth: 0
|
||||||
|
|
|
@ -92,7 +92,7 @@ Item {
|
||||||
id: background
|
id: background
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: root.isCollapsed ? AmneziaStyle.color.transparent : Qt.rgba(14/255, 14/255, 17/255, 0.8)
|
color: root.isCollapsed ? AmneziaStyle.color.transparent : AmneziaStyle.color.translucentMidnightBlack
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
PropertyAnimation { duration: 200 }
|
PropertyAnimation { duration: 200 }
|
||||||
|
|
|
@ -24,7 +24,7 @@ Popup {
|
||||||
|
|
||||||
Overlay.modal: Rectangle {
|
Overlay.modal: Rectangle {
|
||||||
visible: root.closeButtonVisible
|
visible: root.closeButtonVisible
|
||||||
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
|
color: AmneziaStyle.color.translucentMidnightBlack
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
|
|
|
@ -14,7 +14,7 @@ Popup {
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
Overlay.modal: Rectangle {
|
Overlay.modal: Rectangle {
|
||||||
color: Qt.rgba(14/255, 14/255, 17/255, 0.8)
|
color: AmneziaStyle.color.translucentMidnightBlack
|
||||||
}
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
|
|
@ -22,5 +22,9 @@ QtObject {
|
||||||
readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12)
|
readonly property color sheerWhite: Qt.rgba(1, 1, 1, 0.12)
|
||||||
readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08)
|
readonly property color translucentWhite: Qt.rgba(1, 1, 1, 0.08)
|
||||||
readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05)
|
readonly property color barelyTranslucentWhite: Qt.rgba(1, 1, 1, 0.05)
|
||||||
|
readonly property color translucentMidnightBlack: Qt.rgba(14/255, 14/255, 17/255, 0.8)
|
||||||
|
readonly property color softGoldenApricot: Qt.rgba(251/255, 178/255, 106/255, 0.3)
|
||||||
|
readonly property color mistyGray: Qt.rgba(215/255, 216/255, 219/255, 0.8)
|
||||||
|
readonly property color cloudyGray: Qt.rgba(215/255, 216/255, 219/255, 0.65)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,8 +316,8 @@ PageType {
|
||||||
|
|
||||||
rootButtonImageColor: AmneziaStyle.color.midnightBlack
|
rootButtonImageColor: AmneziaStyle.color.midnightBlack
|
||||||
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
|
rootButtonBackgroundColor: AmneziaStyle.color.paleGray
|
||||||
rootButtonBackgroundHoveredColor: Qt.rgba(215, 216, 219, 0.8)
|
rootButtonBackgroundHoveredColor: AmneziaStyle.color.mistyGray
|
||||||
rootButtonBackgroundPressedColor: Qt.rgba(215, 216, 219, 0.65)
|
rootButtonBackgroundPressedColor: AmneziaStyle.color.cloudyGray
|
||||||
rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
|
rootButtonHoveredBorderColor: AmneziaStyle.color.transparent
|
||||||
rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
|
rootButtonDefaultBorderColor: AmneziaStyle.color.transparent
|
||||||
rootButtonTextTopMargin: 8
|
rootButtonTextTopMargin: 8
|
||||||
|
|
|
@ -132,8 +132,8 @@ PageType {
|
||||||
implicitHeight: 32
|
implicitHeight: 32
|
||||||
|
|
||||||
defaultColor: "transparent"
|
defaultColor: "transparent"
|
||||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
text: qsTr("Reload API config")
|
text: qsTr("Reload API config")
|
||||||
|
@ -172,8 +172,8 @@ PageType {
|
||||||
implicitHeight: 32
|
implicitHeight: 32
|
||||||
|
|
||||||
defaultColor: "transparent"
|
defaultColor: "transparent"
|
||||||
hoveredColor: Qt.rgba(1, 1, 1, 0.08)
|
hoveredColor: AmneziaStyle.color.translucentWhite
|
||||||
pressedColor: Qt.rgba(1, 1, 1, 0.12)
|
pressedColor: AmneziaStyle.color.sheerWhite
|
||||||
textColor: AmneziaStyle.color.vibrantRed
|
textColor: AmneziaStyle.color.vibrantRed
|
||||||
|
|
||||||
text: qsTr("Remove from application")
|
text: qsTr("Remove from application")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue