Skip to content

Commit ce88f49

Browse files
authored
Make sure that manifest URL is using base url while checking (#6530)
1 parent d20e5c2 commit ce88f49

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

app/src/main/kotlin/io/homeassistant/companion/android/settings/url/ExternalUrlViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class ExternalUrlViewModel @Inject constructor(
6363
viewModelScope.launch {
6464
serverManager.getServer(serverId)?.let {
6565
try {
66-
val formatted = UrlUtil.formattedUrlString(url)
66+
val formatted = UrlUtil.extractBaseUrl(url)
6767
serverManager.updateServer(
6868
it.copy(
6969
connection = it.connection.copy(

common/src/main/kotlin/io/homeassistant/companion/android/common/data/connectivity/DefaultConnectivityChecker.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package io.homeassistant.companion.android.common.data.connectivity
33
import androidx.annotation.StringRes
44
import io.homeassistant.companion.android.common.R as commonR
55
import io.homeassistant.companion.android.common.util.kotlinJsonMapper
6+
import io.homeassistant.companion.android.util.UrlUtil
67
import java.io.BufferedReader
78
import java.net.HttpURLConnection
89
import java.net.InetAddress
@@ -95,7 +96,7 @@ internal class DefaultConnectivityChecker @Inject constructor() : ConnectivityCh
9596

9697
override suspend fun homeAssistant(url: String): ConnectivityCheckResult = withContext(Dispatchers.IO) {
9798
try {
98-
val manifestUrl = URL("$url/manifest.json")
99+
val manifestUrl = URL("${UrlUtil.extractBaseUrl(url)}manifest.json")
99100
val connection = manifestUrl.openConnection()
100101
connection.connectTimeout = CONNECTIVITY_TIMEOUT.inWholeMilliseconds.toInt()
101102
connection.readTimeout = CONNECTIVITY_TIMEOUT.inWholeMilliseconds.toInt()

common/src/main/kotlin/io/homeassistant/companion/android/util/UrlUtil.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
1515
import timber.log.Timber
1616

1717
object UrlUtil {
18-
fun formattedUrlString(url: String): String {
18+
/**
19+
* Extracts the base URL (scheme, host, and port) from the given URL string,
20+
* stripping any path, query parameters, and fragments.
21+
*
22+
* @param url the full URL string to extract the base from
23+
* @return the base URL containing only the scheme, host, and port, with a trailing `/`
24+
* @throws MalformedHttpUrlException if [url] is empty or not a valid HTTP(S) URL
25+
*/
26+
fun extractBaseUrl(url: String): String {
1927
return if (url == "") {
2028
throw MalformedHttpUrlException()
2129
} else {

common/src/test/kotlin/io/homeassistant/companion/android/util/UrlUtilTest.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.homeassistant.companion.android.util
22

3+
import io.homeassistant.companion.android.common.data.MalformedHttpUrlException
34
import java.net.URL
45
import kotlinx.coroutines.test.runTest
56
import okhttp3.HttpUrl.Companion.toHttpUrl
@@ -10,6 +11,7 @@ import org.junit.jupiter.api.Assertions.assertNull
1011
import org.junit.jupiter.api.Assertions.assertTrue
1112
import org.junit.jupiter.api.BeforeEach
1213
import org.junit.jupiter.api.Test
14+
import org.junit.jupiter.api.Assertions.assertThrows
1315
import org.junit.jupiter.params.ParameterizedTest
1416
import org.junit.jupiter.params.provider.CsvSource
1517
import org.junit.jupiter.params.provider.ValueSource
@@ -29,6 +31,41 @@ class UrlUtilTest {
2931
baseUrl = URL("https://example.com:8123/")
3032
}
3133

34+
@ParameterizedTest
35+
@CsvSource(
36+
value = [
37+
"https://example.com:8123/path/to/page?query=1#fragment, https://example.com:8123/",
38+
"http://homeassistant.local:8123, http://homeassistant.local:8123/",
39+
"https://my.domain.com, https://my.domain.com/",
40+
"http://192.168.1.1:8123/lovelace, http://192.168.1.1:8123/",
41+
"https://ha.example.com:443, https://ha.example.com/",
42+
],
43+
)
44+
fun `Given valid URL when calling extractBaseUrl then returns scheme host and port only`(input: String, expected: String) {
45+
assertEquals(expected, UrlUtil.extractBaseUrl(input))
46+
}
47+
48+
@Test
49+
fun `Given empty string when calling extractBaseUrl then throws MalformedHttpUrlException`() {
50+
assertThrows(MalformedHttpUrlException::class.java) {
51+
UrlUtil.extractBaseUrl("")
52+
}
53+
}
54+
55+
@ParameterizedTest
56+
@ValueSource(
57+
strings = [
58+
"not a url",
59+
"ftp://example.com",
60+
"://missing-scheme",
61+
],
62+
)
63+
fun `Given invalid URL when calling extractBaseUrl then throws MalformedHttpUrlException`(input: String) {
64+
assertThrows(MalformedHttpUrlException::class.java) {
65+
UrlUtil.extractBaseUrl(input)
66+
}
67+
}
68+
3269
@ParameterizedTest
3370
@CsvSource(
3471
value = [

0 commit comments

Comments
 (0)