Skip to content

Commit f14910b

Browse files
committed
fix(android): address auto-save SOCKS5 validation, cursor crash, HTTP status checks and dead conditional
- Add SOCKS5 auth validation guard to auto-save LaunchedEffect in SettingsScreen.kt to prevent persisting profiles with only one of socks_user/socks_pass set (regression from removal of Save button). - Guard getFileNameFromUri in ProfilesScreen.kt with nameIndex >= 0 to prevent CursorIndexOutOfBoundsException when content provider doesn't expose DISPLAY_NAME. - Check connection.responseCode before reading inputStream in ProfilesViewModel.updateRemoteProfile and importProfileFromUrl, surfacing HTTP errors via errorStream instead of generic IOException. - Replace dead conditional (selectedProfile.remoteUrl != null was always true after early return) with remoteProfile.name.isNotBlank() in updateRemoteProfile to preserve local name when remote returns blank name.
1 parent 2fc9e87 commit f14910b

3 files changed

Lines changed: 18 additions & 2 deletions

File tree

android/app/src/main/java/com/gooserelay/gooserelayvpn/ui/profiles/ProfilesScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ fun parseGooseRelayProtocol(raw: String): ProfileEntity? {
189189
private fun getFileNameFromUri(context: Context, uri: Uri): String? {
190190
return context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
191191
val nameIndex = cursor.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
192-
if (cursor.moveToFirst()) {
192+
if (cursor.moveToFirst() && nameIndex >= 0) {
193193
val full = cursor.getString(nameIndex)
194194
full.substringBeforeLast(".")
195195
} else null

android/app/src/main/java/com/gooserelay/gooserelayvpn/ui/profiles/ProfilesViewModel.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import kotlinx.coroutines.flow.first
1818
import kotlinx.coroutines.flow.stateIn
1919
import kotlinx.coroutines.launch
2020
import kotlinx.coroutines.withContext
21+
import java.io.IOException
2122
import java.net.HttpURLConnection
2223
import java.net.URL
2324
import javax.inject.Inject
@@ -87,13 +88,20 @@ class ProfilesViewModel @Inject constructor(
8788
connection.requestMethod = "GET"
8889
connection.connectTimeout = 10000
8990
connection.readTimeout = 10000
91+
val code = connection.responseCode
92+
if (code / 100 != 2) {
93+
val errorBody = try {
94+
connection.errorStream?.bufferedReader()?.use { it.readText() }?.take(200) ?: ""
95+
} catch (_: Exception) { "" }
96+
throw IOException("HTTP $code: $errorBody")
97+
}
9098
connection.inputStream.bufferedReader().use { it.readText() }
9199
}
92100

93101
val remoteProfile = parseProfileFromJson(json, remoteUrl = selectedProfile.remoteUrl)
94102
if (remoteProfile != null) {
95103
val updated = selectedProfile.copy(
96-
name = if (selectedProfile.remoteUrl != null) remoteProfile.name else selectedProfile.name,
104+
name = if (remoteProfile.name.isNotBlank()) remoteProfile.name else selectedProfile.name,
97105
debugTiming = remoteProfile.debugTiming,
98106
socksHost = remoteProfile.socksHost,
99107
socksPort = remoteProfile.socksPort,
@@ -128,6 +136,13 @@ class ProfilesViewModel @Inject constructor(
128136
connection.requestMethod = "GET"
129137
connection.connectTimeout = 10000
130138
connection.readTimeout = 10000
139+
val code = connection.responseCode
140+
if (code / 100 != 2) {
141+
val errorBody = try {
142+
connection.errorStream?.bufferedReader()?.use { it.readText() }?.take(200) ?: ""
143+
} catch (_: Exception) { "" }
144+
throw IOException("HTTP $code: $errorBody")
145+
}
131146
connection.inputStream.bufferedReader().use { it.readText() }
132147
}
133148

android/app/src/main/java/com/gooserelay/gooserelayvpn/ui/settings/SettingsScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ fun SettingsScreen(
128128
}
129129

130130
LaunchedEffect(debugTiming, socksHost, socksPort, socksUser, socksPass, googleHost, sniText, scriptKeys, tunnelKey) {
131+
if ((socksUser.isBlank()) != (socksPass.isBlank())) return@LaunchedEffect
131132
val portInt = socksPort.toIntOrNull()?.coerceIn(1, 65535)
132133
val updated = profile.copy(
133134
debugTiming = debugTiming,

0 commit comments

Comments
 (0)