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