feat: toggle to set amnezia/wg compatibility values
closes #469 closes #518
This commit is contained in:
parent
b2e266fc9f
commit
11e385d350
|
@ -331,6 +331,15 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onTogglePrimaryTunnel(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.updatePrimaryTunnel(
|
||||
when (tunnelConfig.isPrimaryTunnel) {
|
||||
true -> null
|
||||
false -> tunnelConfig
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun rebuildConfigsAndSave(
|
||||
config: TunnelConfig,
|
||||
amConfig: org.amnezia.awg.config.Config,
|
||||
|
|
|
@ -227,6 +227,7 @@ class MainActivity : AppCompatActivity() {
|
|||
OptionsScreen(
|
||||
tunnelId = args.id,
|
||||
appUiState = appUiState,
|
||||
appViewModel = viewModel,
|
||||
)
|
||||
}
|
||||
composable<Route.Lock> {
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.compose.foundation.rememberScrollState
|
|||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.CallSplit
|
||||
import androidx.compose.material.icons.outlined.Adjust
|
||||
import androidx.compose.material.icons.outlined.Bolt
|
||||
import androidx.compose.material.icons.outlined.Edit
|
||||
import androidx.compose.material.icons.outlined.Star
|
||||
|
@ -24,24 +25,35 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
|
||||
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
|
||||
import com.zaneschepke.wireguardautotunnel.ui.Route
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.label.GroupLabel
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.LocalNavController
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.TopNavBar
|
||||
import com.zaneschepke.wireguardautotunnel.ui.screens.settings.components.ForwardButton
|
||||
import com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions.config.model.InterfaceProxy
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.isWgCompatibilityMode
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.resetAmneziaProperties
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.toAmneziaCompatibilityConfig
|
||||
|
||||
@Composable
|
||||
fun OptionsScreen(tunnelOptionsViewModel: TunnelOptionsViewModel = hiltViewModel(), appUiState: AppUiState, tunnelId: Int) {
|
||||
fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId: Int) {
|
||||
val navController = LocalNavController.current
|
||||
val config = appUiState.tunnels.first { it.id == tunnelId }
|
||||
|
||||
// TODO optimize
|
||||
|
||||
val amConfig = config.toAmConfig()
|
||||
|
||||
val isAmneziaCompatibilityEnabled = amConfig.`interface`.isWgCompatibilityMode()
|
||||
|
||||
var currentText by remember { mutableStateOf("") }
|
||||
|
||||
LaunchedEffect(config.tunnelNetworks) {
|
||||
|
@ -82,10 +94,10 @@ fun OptionsScreen(tunnelOptionsViewModel: TunnelOptionsViewModel = hiltViewModel
|
|||
trailing = {
|
||||
ScaledSwitch(
|
||||
config.isPrimaryTunnel,
|
||||
onClick = { tunnelOptionsViewModel.onTogglePrimaryTunnel(config) },
|
||||
onClick = { appViewModel.onTogglePrimaryTunnel(config) },
|
||||
)
|
||||
},
|
||||
onClick = { tunnelOptionsViewModel.onTogglePrimaryTunnel(config) },
|
||||
onClick = { appViewModel.onTogglePrimaryTunnel(config) },
|
||||
),
|
||||
SelectionItem(
|
||||
Icons.Outlined.Bolt,
|
||||
|
@ -140,7 +152,38 @@ fun OptionsScreen(tunnelOptionsViewModel: TunnelOptionsViewModel = hiltViewModel
|
|||
),
|
||||
),
|
||||
)
|
||||
// GroupLabel(stringResource(R.string.quick_actions))
|
||||
val amneziaClick = {
|
||||
val proxy = InterfaceProxy.from(amConfig.`interface`)
|
||||
val `interface` = if (!isAmneziaCompatibilityEnabled) proxy.toAmneziaCompatibilityConfig() else proxy.resetAmneziaProperties()
|
||||
appViewModel.saveConfigChanges(config, `interface` = `interface`)
|
||||
}
|
||||
GroupLabel(stringResource(R.string.quick_actions))
|
||||
SurfaceSelectionGroupButton(
|
||||
listOf(
|
||||
SelectionItem(
|
||||
Icons.Outlined.Adjust,
|
||||
title = {
|
||||
Text(
|
||||
stringResource(R.string.enable_amnezia),
|
||||
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||
)
|
||||
},
|
||||
description = {
|
||||
Text(
|
||||
stringResource(R.string.wg_compat_mode),
|
||||
style = MaterialTheme.typography.bodySmall.copy(MaterialTheme.colorScheme.outline),
|
||||
)
|
||||
},
|
||||
trailing = {
|
||||
ScaledSwitch(
|
||||
isAmneziaCompatibilityEnabled,
|
||||
onClick = { amneziaClick() },
|
||||
)
|
||||
},
|
||||
onClick = { amneziaClick() },
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
package com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
|
||||
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController
|
||||
import com.zaneschepke.wireguardautotunnel.util.StringValue
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class TunnelOptionsViewModel
|
||||
@Inject
|
||||
constructor(
|
||||
private val appDataRepository: AppDataRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
fun onDeleteRunSSID(ssid: String, tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.save(
|
||||
tunnelConfig =
|
||||
tunnelConfig.copy(
|
||||
tunnelNetworks = (tunnelConfig.tunnelNetworks - ssid).toMutableList(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun saveTunnelChanges(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.save(tunnelConfig)
|
||||
}
|
||||
|
||||
fun onSaveRunSSID(ssid: String, tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
if (ssid.isBlank()) return@launch
|
||||
val trimmed = ssid.trim()
|
||||
val tunnelsWithName = appDataRepository.tunnels.findByTunnelNetworksName(trimmed)
|
||||
|
||||
if (!tunnelConfig.tunnelNetworks.contains(trimmed) &&
|
||||
tunnelsWithName.isEmpty()
|
||||
) {
|
||||
saveTunnelChanges(
|
||||
tunnelConfig.copy(
|
||||
tunnelNetworks = (tunnelConfig.tunnelNetworks + ssid).toMutableList(),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
SnackbarController.showMessage(
|
||||
StringValue.StringResource(
|
||||
R.string.error_ssid_exists,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun onToggleIsMobileDataTunnel(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
if (tunnelConfig.isMobileDataTunnel) {
|
||||
appDataRepository.tunnels.updateMobileDataTunnel(null)
|
||||
} else {
|
||||
appDataRepository.tunnels.updateMobileDataTunnel(tunnelConfig)
|
||||
}
|
||||
}
|
||||
|
||||
fun onTogglePrimaryTunnel(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.updatePrimaryTunnel(
|
||||
when (tunnelConfig.isPrimaryTunnel) {
|
||||
true -> null
|
||||
false -> tunnelConfig
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun onToggleRestartOnPing(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.save(
|
||||
tunnelConfig.copy(
|
||||
isPingEnabled = !tunnelConfig.isPingEnabled,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun onToggleIsEthernetTunnel(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
if (tunnelConfig.isEthernetTunnel) {
|
||||
appDataRepository.tunnels.updateEthernetTunnel(null)
|
||||
} else {
|
||||
appDataRepository.tunnels.updateEthernetTunnel(tunnelConfig)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,7 +87,7 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM
|
|||
val selectedPackages = remember { mutableStateListOf<String>() }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
proxyInterface = InterfaceProxy.from(config.toWgConfig().`interface`)
|
||||
proxyInterface = InterfaceProxy.from(config.toAmConfig().`interface`)
|
||||
val pair = when {
|
||||
proxyInterface.excludedApplications.isNotEmpty() -> Pair(SplitOptions.EXCLUDE, proxyInterface.excludedApplications)
|
||||
proxyInterface.includedApplications.isNotEmpty() -> Pair(SplitOptions.INCLUDE, proxyInterface.includedApplications)
|
||||
|
|
|
@ -61,15 +61,6 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun onTogglePrimaryTunnel(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.updatePrimaryTunnel(
|
||||
when (tunnelConfig.isPrimaryTunnel) {
|
||||
true -> null
|
||||
false -> tunnelConfig
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun onToggleRestartOnPing(tunnelConfig: TunnelConfig) = viewModelScope.launch {
|
||||
appDataRepository.tunnels.save(
|
||||
tunnelConfig.copy(
|
||||
|
|
|
@ -6,14 +6,17 @@ import com.wireguard.config.Peer
|
|||
import com.zaneschepke.wireguardautotunnel.service.tunnel.BackendState
|
||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus
|
||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.TunnelStatistics
|
||||
import com.zaneschepke.wireguardautotunnel.ui.screens.tunneloptions.config.model.InterfaceProxy
|
||||
import com.zaneschepke.wireguardautotunnel.ui.theme.SilverTree
|
||||
import com.zaneschepke.wireguardautotunnel.ui.theme.Straw
|
||||
import com.zaneschepke.wireguardautotunnel.util.Constants
|
||||
import com.zaneschepke.wireguardautotunnel.util.NumberUtils
|
||||
import org.amnezia.awg.backend.Backend
|
||||
import org.amnezia.awg.config.Config
|
||||
import org.amnezia.awg.config.Interface
|
||||
import timber.log.Timber
|
||||
import java.net.InetAddress
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
fun TunnelStatistics.mapPeerStats(): Map<org.amnezia.awg.crypto.Key, TunnelStatistics.PeerStats?> {
|
||||
return this.getPeers().associateWith { key -> (this.peerStats(key)) }
|
||||
|
@ -95,3 +98,45 @@ fun Backend.BackendState.asBackendState(): BackendState {
|
|||
fun BackendState.asAmBackendState(): Backend.BackendState {
|
||||
return Backend.BackendState.valueOf(this.name)
|
||||
}
|
||||
|
||||
fun Interface.isWgCompatibilityMode(): Boolean {
|
||||
return (
|
||||
junkPacketCount.getOrNull() in 3..<5 &&
|
||||
junkPacketMinSize.getOrNull() == 40 &&
|
||||
junkPacketMaxSize.getOrNull() == 70 &&
|
||||
with(initPacketJunkSize.getOrNull()) { this == 0 || this == null } &&
|
||||
with(responsePacketJunkSize.getOrNull()) { this == 0 || this == null } &&
|
||||
initPacketMagicHeader.getOrNull() == 1L &&
|
||||
responsePacketMagicHeader.getOrNull() == 2L &&
|
||||
underloadPacketMagicHeader.getOrNull() == 3L &&
|
||||
transportPacketMagicHeader.getOrNull() == 4L
|
||||
)
|
||||
}
|
||||
|
||||
fun InterfaceProxy.toAmneziaCompatibilityConfig(): InterfaceProxy {
|
||||
return copy(
|
||||
junkPacketCount = "4",
|
||||
junkPacketMinSize = "40",
|
||||
junkPacketMaxSize = "70",
|
||||
initPacketJunkSize = "0",
|
||||
responsePacketJunkSize = "0",
|
||||
initPacketMagicHeader = "1",
|
||||
responsePacketMagicHeader = "2",
|
||||
underloadPacketMagicHeader = "3",
|
||||
transportPacketMagicHeader = "4",
|
||||
)
|
||||
}
|
||||
|
||||
fun InterfaceProxy.resetAmneziaProperties(): InterfaceProxy {
|
||||
return copy(
|
||||
junkPacketCount = "",
|
||||
junkPacketMinSize = "",
|
||||
junkPacketMaxSize = "",
|
||||
initPacketJunkSize = "",
|
||||
responsePacketJunkSize = "",
|
||||
initPacketMagicHeader = "",
|
||||
responsePacketMagicHeader = "",
|
||||
underloadPacketMagicHeader = "",
|
||||
transportPacketMagicHeader = "",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -191,4 +191,7 @@
|
|||
<string name="pre_down">Pre down</string>
|
||||
<string name="post_down">Post down</string>
|
||||
<string name="amnezia_kernel_message">Amnezia unavailable in kernel mode</string>
|
||||
<string name="enable_amnezia">Enable Amnezia</string>
|
||||
<string name="wg_compat_mode">WG compatibility mode</string>
|
||||
<string name="quick_actions">Quick actions</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue