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.
This commit is contained in:
Zane Schepke 2023-10-26 22:05:20 -04:00
parent 513d08998b
commit b70ecbdfff
9 changed files with 62 additions and 49 deletions

View File

@ -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"

1
app/fdroid-rules.pro Normal file
View File

@ -0,0 +1 @@
-dontwarn com.google.errorprone.annotations.**

View File

@ -18,4 +18,4 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

View File

@ -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>): String {
return value.joinToString(",")
return Json.encodeToString(value)
}
@TypeConverter
fun stringToList(value: String): MutableList<String> {
if(value.isEmpty()) return mutableListOf()
return value.split(",").toMutableList()
return Json.decodeFromString<MutableList<String>>(value)
}
}

View File

@ -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))
}

View File

@ -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))
}
}
}
)

View File

@ -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)
}

View File

@ -1,3 +1,15 @@
package com.zaneschepke.wireguardautotunnel.util
class WgTunnelException(message: String) : Exception(message)
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"
}
}
}

View File

@ -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"