mirror of
https://github.com/bitwarden/android.git
synced 2026-03-26 08:12:00 -05:00
Add logic to ensure url has a valid https protocol (#3933)
This commit is contained in:
@@ -5,6 +5,8 @@ import android.view.accessibility.AccessibilityNodeInfo
|
||||
import androidx.core.net.toUri
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.model.FillableFields
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.getSupportedBrowserOrNull
|
||||
import com.x8bit.bitwarden.data.autofill.accessibility.util.toUriOrNull
|
||||
import com.x8bit.bitwarden.data.platform.util.hasHttpProtocol
|
||||
|
||||
/**
|
||||
* The default implementation for the [AccessibilityParser].
|
||||
@@ -29,10 +31,19 @@ class AccessibilityParserImpl : AccessibilityParser {
|
||||
rootNode
|
||||
.findAccessibilityNodeInfosByViewId("$packageName:id/$viewId")
|
||||
.map { accessibilityNodeInfo ->
|
||||
browser.urlExtractor(accessibilityNodeInfo.text.toString())
|
||||
browser
|
||||
.urlExtractor(accessibilityNodeInfo.text.toString())
|
||||
?.trim()
|
||||
?.let { rawUrl ->
|
||||
if (rawUrl.contains(other = ".") && !rawUrl.hasHttpProtocol()) {
|
||||
"https://$rawUrl"
|
||||
} else {
|
||||
rawUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.firstOrNull()
|
||||
?.toUri()
|
||||
?.toUriOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ fun String.toUriOrNull(): URI? =
|
||||
fun String.isAndroidApp(): Boolean =
|
||||
this.startsWith(ANDROID_APP_PROTOCOL)
|
||||
|
||||
/**
|
||||
* Whether this [String] starts with an http or https protocol.
|
||||
*/
|
||||
fun String.hasHttpProtocol(): Boolean =
|
||||
this.startsWith(prefix = "http://") || this.startsWith(prefix = "https://")
|
||||
|
||||
/**
|
||||
* Try and extract the web host from this [String] if it represents an Android app.
|
||||
*/
|
||||
|
||||
@@ -61,7 +61,7 @@ class AccessibilityParserTest {
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `parseForUriOrPackageName should return the site url as a URI when package is a supported browser and URL is found`() {
|
||||
fun `parseForUriOrPackageName should return the site url un-augmented with https protocol as a URI when package is a supported browser and URL is found`() {
|
||||
val testBrowser = Browser(packageName = "com.android.chrome", urlFieldId = "url_bar")
|
||||
val url = "https://www.google.com"
|
||||
val urlNode = mockk<AccessibilityNodeInfo> {
|
||||
@@ -81,4 +81,50 @@ class AccessibilityParserTest {
|
||||
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `parseForUriOrPackageName should return the site url un-augmented with http protocol as a URI when package is a supported browser and URL is found`() {
|
||||
val testBrowser = Browser(packageName = "com.android.chrome", urlFieldId = "url_bar")
|
||||
val url = "http://www.google.com"
|
||||
val urlNode = mockk<AccessibilityNodeInfo> {
|
||||
every { text } returns url
|
||||
}
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns testBrowser.packageName
|
||||
every {
|
||||
findAccessibilityNodeInfosByViewId(
|
||||
"$packageName:id/${testBrowser.possibleUrlFieldIds.first()}",
|
||||
)
|
||||
} returns listOf(urlNode)
|
||||
}
|
||||
val expectedResult = url.toUri()
|
||||
|
||||
val result = accessibilityParser.parseForUriOrPackageName(rootNode = rootNode)
|
||||
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `parseForUriOrPackageName should return the site url augmented with https protocol as a URI when package is a supported browser and URL is found`() {
|
||||
val testBrowser = Browser(packageName = "com.android.chrome", urlFieldId = "url_bar")
|
||||
val url = "www.google.com"
|
||||
val urlNode = mockk<AccessibilityNodeInfo> {
|
||||
every { text } returns url
|
||||
}
|
||||
val rootNode = mockk<AccessibilityNodeInfo> {
|
||||
every { packageName } returns testBrowser.packageName
|
||||
every {
|
||||
findAccessibilityNodeInfosByViewId(
|
||||
"$packageName:id/${testBrowser.possibleUrlFieldIds.first()}",
|
||||
)
|
||||
} returns listOf(urlNode)
|
||||
}
|
||||
val expectedResult = "https://$url".toUri()
|
||||
|
||||
val result = accessibilityParser.parseForUriOrPackageName(rootNode = rootNode)
|
||||
|
||||
assertEquals(expectedResult, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.x8bit.bitwarden.data.platform.manager.ResourceCacheManager
|
||||
import com.x8bit.bitwarden.data.platform.util.findLastSubstringIndicesOrNull
|
||||
import com.x8bit.bitwarden.data.platform.util.getDomainOrNull
|
||||
import com.x8bit.bitwarden.data.platform.util.getWebHostFromAndroidUriOrNull
|
||||
import com.x8bit.bitwarden.data.platform.util.hasHttpProtocol
|
||||
import com.x8bit.bitwarden.data.platform.util.isAndroidApp
|
||||
import com.x8bit.bitwarden.data.platform.util.parseDomainOrNull
|
||||
import com.x8bit.bitwarden.data.platform.util.toUriOrNull
|
||||
@@ -48,6 +49,21 @@ class StringExtensionsTest {
|
||||
assertFalse("com.x8bit.bitwarden".isAndroidApp())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hasHttpProtocol should return false when doesn't start with an appropriate protocol`() {
|
||||
assertFalse("androidapp://com.x8bit.bitwarden".hasHttpProtocol())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hasHttpProtocol should return true when it starts with the http protocol`() {
|
||||
assertTrue("http://www.google.com".hasHttpProtocol())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hasHttpProtocol should return true when it starts with the https protocol`() {
|
||||
assertTrue("https://www.google.com".hasHttpProtocol())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getWebHostFromAndroidUriOrNull should return null when not android app`() {
|
||||
assertNull("com.x8bit.bitwarden".getWebHostFromAndroidUriOrNull())
|
||||
|
||||
Reference in New Issue
Block a user