parent
7a3627bf6a
commit
4dc91b5fae
|
@ -14,7 +14,7 @@ val versionCodeIncrement = with(getBuildTaskName().lowercase()) {
|
|||
when {
|
||||
this.contains(Constants.NIGHTLY) || this.contains(Constants.PRERELEASE) -> {
|
||||
if (versionFile.exists()) {
|
||||
versionFile.readText().toInt() + 1
|
||||
versionFile.readText().trim().toInt() + 1
|
||||
} else {
|
||||
1
|
||||
}
|
||||
|
|
|
@ -202,18 +202,14 @@ constructor(
|
|||
|
||||
private suspend fun handleVpnKillSwitchChange(enabled: Boolean) {
|
||||
withContext(ioDispatcher) {
|
||||
if (enabled) {
|
||||
Timber.d("Starting kill switch")
|
||||
val allowedIps = if (appDataRepository.settings.getSettings().isLanOnKillSwitchEnabled) {
|
||||
TunnelConfig.IPV4_PUBLIC_NETWORKS
|
||||
} else {
|
||||
emptySet()
|
||||
}
|
||||
tunnelService.get().setBackendState(BackendState.KILL_SWITCH_ACTIVE, allowedIps)
|
||||
if (!enabled) return@withContext tunnelService.get().setBackendState(BackendState.SERVICE_ACTIVE, emptySet())
|
||||
Timber.d("Starting kill switch")
|
||||
val allowedIps = if (appDataRepository.settings.getSettings().isLanOnKillSwitchEnabled) {
|
||||
TunnelConfig.IPV4_PUBLIC_NETWORKS
|
||||
} else {
|
||||
Timber.d("Sending shutdown of kill switch")
|
||||
tunnelService.get().setBackendState(BackendState.SERVICE_ACTIVE, emptySet())
|
||||
emptySet()
|
||||
}
|
||||
tunnelService.get().setBackendState(BackendState.KILL_SWITCH_ACTIVE, allowedIps)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,25 +293,67 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun saveConfigChanges(config: TunnelConfig, peers: List<PeerProxy>? = null, `interface`: InterfaceProxy? = null) = viewModelScope.launch(
|
||||
ioDispatcher,
|
||||
) {
|
||||
fun updateExistingTunnelConfig(
|
||||
tunnelConfig: TunnelConfig,
|
||||
tunnelName: String? = null,
|
||||
peers: List<PeerProxy>? = null,
|
||||
`interface`: InterfaceProxy? = null,
|
||||
) = viewModelScope.launch {
|
||||
runCatching {
|
||||
val amConfig = config.toAmConfig()
|
||||
val wgConfig = config.toWgConfig()
|
||||
rebuildConfigsAndSave(config, amConfig, wgConfig, peers, `interface`)
|
||||
val amConfig = tunnelConfig.toAmConfig()
|
||||
val wgConfig = tunnelConfig.toWgConfig()
|
||||
updateTunnelConfig(tunnelConfig, tunnelName, amConfig, wgConfig, peers, `interface`)
|
||||
_popBackStack.emit(true)
|
||||
SnackbarController.showMessage(StringValue.StringResource(R.string.config_changes_saved))
|
||||
}.onFailure {
|
||||
Timber.e(it)
|
||||
SnackbarController.showMessage(
|
||||
it.message?.let { message ->
|
||||
(StringValue.DynamicString(message))
|
||||
} ?: StringValue.StringResource(R.string.unknown_error),
|
||||
)
|
||||
onConfigSaveError(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun saveNewTunnel(tunnelName: String, peers: List<PeerProxy>, `interface`: InterfaceProxy) = viewModelScope.launch {
|
||||
runCatching {
|
||||
val config = buildConfigs(peers, `interface`)
|
||||
appDataRepository.tunnels.save(
|
||||
TunnelConfig(
|
||||
name = tunnelName,
|
||||
wgQuick = config.first.toWgQuickString(true),
|
||||
amQuick = config.second.toAwgQuickString(true),
|
||||
),
|
||||
)
|
||||
_popBackStack.emit(true)
|
||||
SnackbarController.showMessage(StringValue.StringResource(R.string.config_changes_saved))
|
||||
}.onFailure {
|
||||
onConfigSaveError(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onConfigSaveError(throwable: Throwable) {
|
||||
Timber.e(throwable)
|
||||
SnackbarController.showMessage(
|
||||
throwable.message?.let { message ->
|
||||
(StringValue.DynamicString(message))
|
||||
} ?: StringValue.StringResource(R.string.unknown_error),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateTunnelConfig(
|
||||
tunnelConfig: TunnelConfig,
|
||||
tunnelName: String? = null,
|
||||
amConfig: org.amnezia.awg.config.Config,
|
||||
wgConfig: Config,
|
||||
peers: List<PeerProxy>? = null,
|
||||
`interface`: InterfaceProxy? = null,
|
||||
) {
|
||||
val configs = rebuildConfigs(amConfig, wgConfig, peers, `interface`)
|
||||
appDataRepository.tunnels.save(
|
||||
tunnelConfig.copy(
|
||||
name = tunnelName ?: tunnelConfig.name,
|
||||
amQuick = configs.second.toAwgQuickString(true),
|
||||
wgQuick = configs.first.toWgQuickString(true),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun cleanUpUninstalledApps(tunnelConfig: TunnelConfig, packages: List<String>) = viewModelScope.launch(ioDispatcher) {
|
||||
runCatching {
|
||||
val amConfig = tunnelConfig.toAmConfig()
|
||||
|
@ -323,8 +361,8 @@ constructor(
|
|||
val proxy = InterfaceProxy.from(amConfig.`interface`)
|
||||
if (proxy.includedApplications.isEmpty() && proxy.excludedApplications.isEmpty()) return@launch
|
||||
if (proxy.includedApplications.retainAll(packages.toSet()) || proxy.excludedApplications.retainAll(packages.toSet())) {
|
||||
Timber.i("Removing split tunnel package for app that no longer exists on the device")
|
||||
rebuildConfigsAndSave(tunnelConfig, amConfig, wgConfig, `interface` = proxy)
|
||||
updateTunnelConfig(tunnelConfig, amConfig = amConfig, wgConfig = wgConfig, `interface` = proxy)
|
||||
Timber.i("Removed split tunnel package for app that no longer exists on the device")
|
||||
}
|
||||
}.onFailure {
|
||||
Timber.e(it)
|
||||
|
@ -340,24 +378,38 @@ constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private suspend fun rebuildConfigsAndSave(
|
||||
config: TunnelConfig,
|
||||
private suspend fun rebuildConfigs(
|
||||
amConfig: org.amnezia.awg.config.Config,
|
||||
wgConfig: Config,
|
||||
peers: List<PeerProxy>? = null,
|
||||
`interface`: InterfaceProxy? = null,
|
||||
) {
|
||||
appDataRepository.tunnels.save(
|
||||
config.copy(
|
||||
wgQuick = Config.Builder().apply {
|
||||
): Pair<Config, org.amnezia.awg.config.Config> {
|
||||
return withContext(ioDispatcher) {
|
||||
Pair(
|
||||
Config.Builder().apply {
|
||||
addPeers(peers?.map { it.toWgPeer() } ?: wgConfig.peers)
|
||||
setInterface(`interface`?.toWgInterface() ?: wgConfig.`interface`)
|
||||
}.build().toWgQuickString(true),
|
||||
amQuick = org.amnezia.awg.config.Config.Builder().apply {
|
||||
}.build(),
|
||||
org.amnezia.awg.config.Config.Builder().apply {
|
||||
addPeers(peers?.map { it.toAmPeer() } ?: amConfig.peers)
|
||||
setInterface(`interface`?.toAmInterface() ?: amConfig.`interface`)
|
||||
}.build().toAwgQuickString(true),
|
||||
),
|
||||
)
|
||||
}.build(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun buildConfigs(peers: List<PeerProxy>, `interface`: InterfaceProxy): Pair<Config, org.amnezia.awg.config.Config> {
|
||||
return withContext(ioDispatcher) {
|
||||
Pair(
|
||||
Config.Builder().apply {
|
||||
addPeers(peers.map { it.toWgPeer() })
|
||||
setInterface(`interface`.toWgInterface())
|
||||
}.build(),
|
||||
org.amnezia.awg.config.Config.Builder().apply {
|
||||
addPeers(peers.map { it.toAmPeer() })
|
||||
setInterface(`interface`.toAmInterface())
|
||||
}.build(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId:
|
|||
val amneziaClick = {
|
||||
val proxy = InterfaceProxy.from(amConfig.`interface`)
|
||||
val `interface` = if (!isAmneziaCompatibilityEnabled) proxy.toAmneziaCompatibilityConfig() else proxy.resetAmneziaProperties()
|
||||
appViewModel.saveConfigChanges(config, `interface` = `interface`)
|
||||
appViewModel.updateExistingTunnelConfig(config, `interface` = `interface`)
|
||||
}
|
||||
GroupLabel(stringResource(R.string.quick_actions))
|
||||
SurfaceSelectionGroupButton(
|
||||
|
|
|
@ -83,13 +83,13 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
|
||||
val tunnelConfig by remember {
|
||||
derivedStateOf {
|
||||
appUiState.tunnels.first { it.id == tunnelId }
|
||||
appUiState.tunnels.firstOrNull { it.id == tunnelId }
|
||||
}
|
||||
}
|
||||
|
||||
val configPair by remember {
|
||||
derivedStateOf {
|
||||
Pair(tunnelConfig.name, tunnelConfig.toAmConfig())
|
||||
Pair(tunnelConfig?.name ?: "", tunnelConfig?.toAmConfig())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,11 +98,11 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
}
|
||||
|
||||
var interfaceState by remember {
|
||||
mutableStateOf(InterfaceProxy.from(configPair.second.`interface`))
|
||||
mutableStateOf(configPair.second?.let { InterfaceProxy.from(it.`interface`) } ?: InterfaceProxy())
|
||||
}
|
||||
|
||||
var showAmneziaValues by remember {
|
||||
mutableStateOf(configPair.second.`interface`.junkPacketCount.isPresent)
|
||||
mutableStateOf(configPair.second?.`interface`?.junkPacketCount?.isPresent == true)
|
||||
}
|
||||
|
||||
var showScripts by remember {
|
||||
|
@ -110,7 +110,7 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
}
|
||||
|
||||
val peersState = remember {
|
||||
configPair.second.peers.map { PeerProxy.from(it) }.toMutableStateList()
|
||||
(configPair.second?.peers?.map { PeerProxy.from(it) } ?: listOf(PeerProxy())).toMutableStateList()
|
||||
}
|
||||
|
||||
var showAuthPrompt by remember { mutableStateOf(false) }
|
||||
|
@ -148,13 +148,14 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
topBar = {
|
||||
TopNavBar(stringResource(R.string.edit_tunnel), trailing = {
|
||||
IconButton(onClick = {
|
||||
appViewModel.saveConfigChanges(
|
||||
tunnelConfig.copy(
|
||||
name = tunnelName,
|
||||
),
|
||||
peers = peersState,
|
||||
`interface` = interfaceState,
|
||||
)
|
||||
tunnelConfig?.let {
|
||||
appViewModel.updateExistingTunnelConfig(
|
||||
it,
|
||||
tunnelName,
|
||||
peersState,
|
||||
interfaceState,
|
||||
)
|
||||
} ?: appViewModel.saveNewTunnel(tunnelName, peersState, interfaceState)
|
||||
}) {
|
||||
val icon = Icons.Outlined.Save
|
||||
Icon(
|
||||
|
@ -226,6 +227,7 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
Modifier
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
val privateKeyEnabled = (tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID) || isAuthenticated
|
||||
OutlinedTextField(
|
||||
textStyle = MaterialTheme.typography.labelLarge,
|
||||
modifier =
|
||||
|
@ -234,16 +236,16 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
.clickable { showAuthPrompt = true },
|
||||
value = interfaceState.privateKey,
|
||||
visualTransformation =
|
||||
if ((tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID) || isAuthenticated) {
|
||||
if (privateKeyEnabled) {
|
||||
VisualTransformation.None
|
||||
} else {
|
||||
PasswordVisualTransformation()
|
||||
},
|
||||
enabled = (tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID) || isAuthenticated,
|
||||
enabled = privateKeyEnabled,
|
||||
onValueChange = { interfaceState = interfaceState.copy(privateKey = it) },
|
||||
trailingIcon = {
|
||||
IconButton(
|
||||
enabled = isAuthenticated,
|
||||
enabled = privateKeyEnabled,
|
||||
modifier = Modifier.focusRequester(FocusRequester.Default),
|
||||
onClick = {
|
||||
val keypair = KeyPair()
|
||||
|
@ -256,7 +258,7 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
|
|||
Icon(
|
||||
Icons.Rounded.Refresh,
|
||||
stringResource(R.string.rotate_keys),
|
||||
tint = if (isAuthenticated) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.outline,
|
||||
tint = if (privateKeyEnabled) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.outline,
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -127,7 +127,7 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM
|
|||
}
|
||||
SplitOptions.ALL -> Unit
|
||||
}
|
||||
viewModel.saveConfigChanges(config, `interface` = proxyInterface)
|
||||
viewModel.updateExistingTunnelConfig(config, `interface` = proxyInterface)
|
||||
}) {
|
||||
val icon = Icons.Outlined.Save
|
||||
Icon(
|
||||
|
|
Loading…
Reference in New Issue