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:
parent
513d08998b
commit
b70ecbdfff
|
@ -14,10 +14,8 @@ android {
|
||||||
applicationId = "com.zaneschepke.wireguardautotunnel"
|
applicationId = "com.zaneschepke.wireguardautotunnel"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 31700
|
versionCode = 31900
|
||||||
versionName = "3.1.7"
|
versionName = "3.1.9"
|
||||||
|
|
||||||
multiDexEnabled = true
|
|
||||||
|
|
||||||
ksp {
|
ksp {
|
||||||
arg("room.schemaLocation", "$projectDir/schemas")
|
arg("room.schemaLocation", "$projectDir/schemas")
|
||||||
|
@ -49,6 +47,7 @@ android {
|
||||||
productFlavors {
|
productFlavors {
|
||||||
create("fdroid") {
|
create("fdroid") {
|
||||||
dimension = "type"
|
dimension = "type"
|
||||||
|
proguardFile("fdroid-rules.pro")
|
||||||
}
|
}
|
||||||
create("general") {
|
create("general") {
|
||||||
dimension = "type"
|
dimension = "type"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
-dontwarn com.google.errorprone.annotations.**
|
|
@ -1,15 +1,17 @@
|
||||||
package com.zaneschepke.wireguardautotunnel.repository
|
package com.zaneschepke.wireguardautotunnel.repository
|
||||||
|
|
||||||
import androidx.room.TypeConverter
|
import androidx.room.TypeConverter
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
class DatabaseListConverters {
|
class DatabaseListConverters {
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun listToString(value: MutableList<String>): String {
|
fun listToString(value: MutableList<String>): String {
|
||||||
return value.joinToString(",")
|
return Json.encodeToString(value)
|
||||||
}
|
}
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
fun stringToList(value: String): MutableList<String> {
|
fun stringToList(value: String): MutableList<String> {
|
||||||
if(value.isEmpty()) return mutableListOf()
|
if(value.isEmpty()) return mutableListOf()
|
||||||
return value.split(",").toMutableList()
|
return Json.decodeFromString<MutableList<String>>(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
package com.zaneschepke.wireguardautotunnel.ui.common.prompt
|
package com.zaneschepke.wireguardautotunnel.ui.common.prompt
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.Info
|
import androidx.compose.material.icons.rounded.Info
|
||||||
|
@ -42,14 +44,15 @@ fun CustomSnackBar(
|
||||||
if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
|
if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.width(IntrinsicSize.Max).height(IntrinsicSize.Min),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceEvenly
|
horizontalArrangement = Arrangement.Start
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Rounded.Info,
|
Icons.Rounded.Info,
|
||||||
contentDescription = stringResource(R.string.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))
|
Text(message, color = Color.White, modifier = Modifier.padding(end = 5.dp))
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,10 +168,12 @@ fun MainScreen(
|
||||||
val scanLauncher = rememberLauncherForActivityResult(
|
val scanLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ScanContract(),
|
contract = ScanContract(),
|
||||||
onResult = {
|
onResult = {
|
||||||
try {
|
scope.launch {
|
||||||
viewModel.onTunnelQrResult(it.contents)
|
try {
|
||||||
} catch (e: Exception) {
|
viewModel.onTunnelQrResult(it.contents)
|
||||||
showSnackbarMessage(context.getString(R.string.qr_result_failed))
|
} catch (e: Exception) {
|
||||||
|
showSnackbarMessage(context.getString(R.string.qr_result_failed))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,6 +28,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -117,32 +118,26 @@ class MainViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateConfigString(config: String) {
|
private fun validateConfigString(config: String) {
|
||||||
if (!config.contains(application.getString(R.string.config_validation))) {
|
TunnelConfig.configFromQuick(config)
|
||||||
throw WgTunnelException(application.getString(R.string.config_validation))
|
}
|
||||||
|
|
||||||
|
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) {
|
private suspend fun saveTunnelConfigFromStream(stream: InputStream, fileName: String) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
val bufferReader = stream.bufferedReader(charset = Charsets.UTF_8)
|
||||||
try {
|
val config = Config.parse(bufferReader)
|
||||||
validateConfigString(result)
|
val tunnelName = getNameFromFileName(fileName)
|
||||||
val tunnelConfig =
|
addTunnel(TunnelConfig(name = tunnelName, wgQuick = config.toWgQuickString()))
|
||||||
TunnelConfig(name = NumberUtils.generateRandomTunnelName(), wgQuick = result)
|
withContext(Dispatchers.IO) {
|
||||||
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()))
|
|
||||||
stream.close()
|
stream.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,9 +156,8 @@ class MainViewModel @Inject constructor(
|
||||||
Constants.ZIP_FILE_EXTENSION -> saveTunnelsFromZipUri(uri)
|
Constants.ZIP_FILE_EXTENSION -> saveTunnelsFromZipUri(uri)
|
||||||
else -> throw WgTunnelException(application.getString(R.string.file_extension_message))
|
else -> throw WgTunnelException(application.getString(R.string.file_extension_message))
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} 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)
|
val stream = getInputStreamFromUri(uri)
|
||||||
saveTunnelConfigFromStream(stream, name)
|
saveTunnelConfigFromStream(stream, name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
package com.zaneschepke.wireguardautotunnel.util
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,20 +14,20 @@ hiltNavigationCompose = "1.0.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
kotlinx-serialization-json = "1.5.1"
|
kotlinx-serialization-json = "1.5.1"
|
||||||
lifecycle-runtime-compose = "2.6.2"
|
lifecycle-runtime-compose = "2.6.2"
|
||||||
material-icons-extended = "1.5.3"
|
material-icons-extended = "1.5.4"
|
||||||
material3 = "1.1.2"
|
material3 = "1.1.2"
|
||||||
navigationCompose = "2.7.4"
|
navigationCompose = "2.7.4"
|
||||||
roomVersion = "2.6.0-rc01"
|
roomVersion = "2.6.0"
|
||||||
timber = "5.0.1"
|
timber = "5.0.1"
|
||||||
tunnel = "1.0.20230706"
|
tunnel = "1.0.20230706"
|
||||||
androidGradlePlugin = "8.3.0-alpha06"
|
androidGradlePlugin = "8.3.0-alpha06"
|
||||||
kotlin="1.9.10"
|
kotlin="1.9.10"
|
||||||
ksp="1.9.10-1.0.13"
|
ksp="1.9.10-1.0.13"
|
||||||
composeBom="2023.10.00"
|
composeBom="2023.10.01"
|
||||||
firebaseBom="32.3.1"
|
firebaseBom="32.4.0"
|
||||||
compose="1.5.3"
|
compose="1.5.4"
|
||||||
crashlytics="18.4.3"
|
crashlytics="18.5.0"
|
||||||
analytics="21.3.0"
|
analytics="21.4.0"
|
||||||
composeCompiler="1.5.3"
|
composeCompiler="1.5.3"
|
||||||
zxingAndroidEmbedded = "4.3.0"
|
zxingAndroidEmbedded = "4.3.0"
|
||||||
zxingCore = "3.4.1"
|
zxingCore = "3.4.1"
|
||||||
|
|
Loading…
Reference in New Issue