From b70ecbdfff638c4e0901ffccc760555ebdc71039 Mon Sep 17 00:00:00 2001 From: Zane Schepke Date: Thu, 26 Oct 2023 22:05:20 -0400 Subject: [PATCH] fix: fdroid build and ssid comma Fixes bug where commas in SSID names were splitting into multiple SSIDs due to database type converters. Closes #48 Fixes bug where F-Droid pipeline was failing to build due to lack of proguard rule. Closes #47 Fixes bug where crashes could happen if config QR code or file has improperly configured data. Bump versions. --- app/build.gradle.kts | 7 ++- app/fdroid-rules.pro | 1 + app/proguard-rules.pro | 2 +- .../repository/DatabaseListConverters.kt | 6 ++- .../ui/common/prompt/CustomSnackbar.kt | 11 +++-- .../ui/screens/main/MainScreen.kt | 10 ++-- .../ui/screens/main/MainViewModel.kt | 46 ++++++++----------- .../util/WgTunnelException.kt | 14 +++++- gradle/libs.versions.toml | 14 +++--- 9 files changed, 62 insertions(+), 49 deletions(-) create mode 100644 app/fdroid-rules.pro diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cf13a73..0b6fdc1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -14,10 +14,8 @@ android { applicationId = "com.zaneschepke.wireguardautotunnel" minSdk = 26 targetSdk = 34 - versionCode = 31700 - versionName = "3.1.7" - - multiDexEnabled = true + versionCode = 31900 + versionName = "3.1.9" ksp { arg("room.schemaLocation", "$projectDir/schemas") @@ -49,6 +47,7 @@ android { productFlavors { create("fdroid") { dimension = "type" + proguardFile("fdroid-rules.pro") } create("general") { dimension = "type" diff --git a/app/fdroid-rules.pro b/app/fdroid-rules.pro new file mode 100644 index 0000000..e5480ee --- /dev/null +++ b/app/fdroid-rules.pro @@ -0,0 +1 @@ +-dontwarn com.google.errorprone.annotations.** \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb43..f1b4245 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -18,4 +18,4 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt index 6ff8d31..dd5f74f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt @@ -1,15 +1,17 @@ package com.zaneschepke.wireguardautotunnel.repository import androidx.room.TypeConverter +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json class DatabaseListConverters { @TypeConverter fun listToString(value: MutableList): String { - return value.joinToString(",") + return Json.encodeToString(value) } @TypeConverter fun stringToList(value: String): MutableList { if(value.isEmpty()) return mutableListOf() - return value.split(",").toMutableList() + return Json.decodeFromString>(value) } } \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/prompt/CustomSnackbar.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/prompt/CustomSnackbar.kt index ea95962..4732f7d 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/prompt/CustomSnackbar.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/prompt/CustomSnackbar.kt @@ -1,10 +1,12 @@ package com.zaneschepke.wireguardautotunnel.ui.common.prompt import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Info @@ -42,14 +44,15 @@ fun CustomSnackBar( if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr ) { Row( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.width(IntrinsicSize.Max).height(IntrinsicSize.Min), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceEvenly + horizontalArrangement = Arrangement.Start ) { Icon( Icons.Rounded.Info, contentDescription = stringResource(R.string.info), - tint = Color.White + tint = Color.White, + modifier = Modifier.padding(end = 10.dp) ) Text(message, color = Color.White, modifier = Modifier.padding(end = 5.dp)) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt index 4eb2fde..1e04c49 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt @@ -168,10 +168,12 @@ fun MainScreen( val scanLauncher = rememberLauncherForActivityResult( contract = ScanContract(), onResult = { - try { - viewModel.onTunnelQrResult(it.contents) - } catch (e: Exception) { - showSnackbarMessage(context.getString(R.string.qr_result_failed)) + scope.launch { + try { + viewModel.onTunnelQrResult(it.contents) + } catch (e: Exception) { + showSnackbarMessage(context.getString(R.string.qr_result_failed)) + } } } ) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt index 577154c..a22c18e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt @@ -28,6 +28,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.InputStream import java.util.zip.ZipInputStream import javax.inject.Inject @@ -117,32 +118,26 @@ class MainViewModel @Inject constructor( } private fun validateConfigString(config: String) { - if (!config.contains(application.getString(R.string.config_validation))) { - throw WgTunnelException(application.getString(R.string.config_validation)) + TunnelConfig.configFromQuick(config) + } + + suspend fun onTunnelQrResult(result: String) { + try { + validateConfigString(result) + val tunnelConfig = + TunnelConfig(name = NumberUtils.generateRandomTunnelName(), wgQuick = result) + addTunnel(tunnelConfig) + } catch (e : Exception) { + throw WgTunnelException(e) } } - fun onTunnelQrResult(result: String) { - viewModelScope.launch(Dispatchers.IO) { - try { - validateConfigString(result) - val tunnelConfig = - TunnelConfig(name = NumberUtils.generateRandomTunnelName(), wgQuick = result) - addTunnel(tunnelConfig) - } catch (e: WgTunnelException) { - throw WgTunnelException( - e.message ?: application.getString(R.string.unknown_error_message) - ) - } - } - } - - private fun saveTunnelConfigFromStream(stream: InputStream, fileName: String) { - viewModelScope.launch(Dispatchers.IO) { - val bufferReader = stream.bufferedReader(charset = Charsets.UTF_8) - val config = Config.parse(bufferReader) - val tunnelName = getNameFromFileName(fileName) - addTunnel(TunnelConfig(name = tunnelName, wgQuick = config.toWgQuickString())) + private suspend fun saveTunnelConfigFromStream(stream: InputStream, fileName: String) { + val bufferReader = stream.bufferedReader(charset = Charsets.UTF_8) + val config = Config.parse(bufferReader) + val tunnelName = getNameFromFileName(fileName) + addTunnel(TunnelConfig(name = tunnelName, wgQuick = config.toWgQuickString())) + withContext(Dispatchers.IO) { stream.close() } } @@ -161,9 +156,8 @@ class MainViewModel @Inject constructor( Constants.ZIP_FILE_EXTENSION -> saveTunnelsFromZipUri(uri) else -> throw WgTunnelException(application.getString(R.string.file_extension_message)) } - } catch (e: Exception) { - throw WgTunnelException(e.message ?: "Error importing file") + throw WgTunnelException(e) } } @@ -182,7 +176,7 @@ class MainViewModel @Inject constructor( } } - private fun saveTunnelFromConfUri(name : String, uri: Uri) { + private suspend fun saveTunnelFromConfUri(name : String, uri: Uri) { val stream = getInputStreamFromUri(uri) saveTunnelConfigFromStream(stream, name) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/WgTunnelException.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/WgTunnelException.kt index 8a34abe..d73b810 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/WgTunnelException.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/WgTunnelException.kt @@ -1,3 +1,15 @@ package com.zaneschepke.wireguardautotunnel.util -class WgTunnelException(message: String) : Exception(message) \ No newline at end of file +import com.wireguard.config.BadConfigException + +class WgTunnelException(e: Exception) : Exception() { + constructor(message : String) : this(Exception(message)) + + override val message: String = generateExceptionMessage(e) + private fun generateExceptionMessage(e : Exception) : String { + return when(e) { + is BadConfigException -> "${e.section.name} ${e.location.name} ${e.reason.name}" + else -> e.message ?: "Unknown error occurred" + } + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4a97dc7..e829263 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,20 +14,20 @@ hiltNavigationCompose = "1.0.0" junit = "4.13.2" kotlinx-serialization-json = "1.5.1" lifecycle-runtime-compose = "2.6.2" -material-icons-extended = "1.5.3" +material-icons-extended = "1.5.4" material3 = "1.1.2" navigationCompose = "2.7.4" -roomVersion = "2.6.0-rc01" +roomVersion = "2.6.0" timber = "5.0.1" tunnel = "1.0.20230706" androidGradlePlugin = "8.3.0-alpha06" kotlin="1.9.10" ksp="1.9.10-1.0.13" -composeBom="2023.10.00" -firebaseBom="32.3.1" -compose="1.5.3" -crashlytics="18.4.3" -analytics="21.3.0" +composeBom="2023.10.01" +firebaseBom="32.4.0" +compose="1.5.4" +crashlytics="18.5.0" +analytics="21.4.0" composeCompiler="1.5.3" zxingAndroidEmbedded = "4.3.0" zxingCore = "3.4.1"