Skip to content

Commit 65f6540

Browse files
authored
Add WebView version check to no-op WebMessageListener (#4623)
1 parent 54d6f08 commit 65f6540

File tree

3 files changed

+100
-2
lines changed

3 files changed

+100
-2
lines changed

app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ import com.duckduckgo.autofill.api.credential.saving.DuckAddressLoginCreator
221221
import com.duckduckgo.autofill.api.domain.app.LoginCredentials
222222
import com.duckduckgo.autofill.api.domain.app.LoginTriggerType
223223
import com.duckduckgo.autofill.api.emailprotection.EmailInjector
224+
import com.duckduckgo.browser.api.WebViewVersionProvider
224225
import com.duckduckgo.browser.api.brokensite.BrokenSiteData
225226
import com.duckduckgo.common.ui.DuckDuckGoActivity
226227
import com.duckduckgo.common.ui.DuckDuckGoFragment
@@ -243,6 +244,7 @@ import com.duckduckgo.common.ui.viewbinding.viewBinding
243244
import com.duckduckgo.common.utils.ConflatedJob
244245
import com.duckduckgo.common.utils.DispatcherProvider
245246
import com.duckduckgo.common.utils.FragmentViewModelFactory
247+
import com.duckduckgo.common.utils.extensions.compareSemanticVersion
246248
import com.duckduckgo.common.utils.extensions.html
247249
import com.duckduckgo.common.utils.extensions.websiteFromGeoLocationsApiOrigin
248250
import com.duckduckgo.common.utils.extractDomain
@@ -483,6 +485,9 @@ class BrowserTabFragment :
483485
@Inject
484486
lateinit var dummyWebMessageListenerFeature: DummyWebMessageListenerFeature
485487

488+
@Inject
489+
lateinit var webViewVersionProvider: WebViewVersionProvider
490+
486491
/**
487492
* We use this to monitor whether the user was seeing the in-context Email Protection signup prompt
488493
* This is needed because the activity stack will be cleared if an external link is opened in our browser
@@ -2343,11 +2348,15 @@ class BrowserTabFragment :
23432348
// See https://app.asana.com/0/1200204095367872/1207300292572452/f (WebMessageListener debugging)
23442349
private fun addNoOpWebMessageListener(webView: DuckDuckGoWebView) {
23452350
lifecycleScope.launch(dispatchers.main()) {
2346-
val isFeatureEnabled = withContext(dispatchers.io()) {
2347-
dummyWebMessageListenerFeature.self().isEnabled()
2351+
val (isFeatureEnabled, isSupportedWebViewVersion) = withContext(dispatchers.io()) {
2352+
val isFeatureEnabled = dummyWebMessageListenerFeature.self().isEnabled()
2353+
val isSupportedWebViewVersion = webViewVersionProvider.getFullVersion()
2354+
.compareSemanticVersion(WEB_MESSAGE_LISTENER_WEBVIEW_VERSION)?.let { it > 0 } ?: false
2355+
Pair(isFeatureEnabled, isSupportedWebViewVersion)
23482356
}
23492357

23502358
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) &&
2359+
isSupportedWebViewVersion &&
23512360
isFeatureEnabled &&
23522361
!webView.isDestroyed
23532362
) {
@@ -3225,6 +3234,8 @@ class BrowserTabFragment :
32253234

32263235
private const val BOOKMARKS_BOTTOM_SHEET_DURATION = 3500L
32273236

3237+
private const val WEB_MESSAGE_LISTENER_WEBVIEW_VERSION = "126.0.6478.40"
3238+
32283239
fun newInstance(
32293240
tabId: String,
32303241
query: String? = null,

common/common-utils/src/main/java/com/duckduckgo/common/utils/extensions/StringExtensions.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,28 @@ fun String.asLocationPermissionOrigin(): String {
6262
fun String.toTldPlusOne(): String? {
6363
return runCatching { publicSuffixDatabase.getEffectiveTldPlusOne(this) }.getOrNull()
6464
}
65+
66+
/**
67+
* Compares the current semantic version string with the target semantic version string.
68+
*
69+
* The version strings can have an arbitrary number of parts separated by dots (e.g. "x.y.z").
70+
* Each part is expected to be an integer.
71+
* If any part of the version string is not a valid integer, the function returns null.
72+
*
73+
* @param targetVersion The version string to compare against.
74+
* @return 1 if the current version is greater, -1 if it is smaller, 0 if they are equal or null if the format is invalid.
75+
*/
76+
fun String.compareSemanticVersion(targetVersion: String): Int? {
77+
val versionParts = this.split(".")
78+
val targetParts = targetVersion.split(".")
79+
80+
val maxLength = maxOf(versionParts.size, targetParts.size)
81+
82+
for (i in 0 until maxLength) {
83+
val versionPart = versionParts.getOrElse(i) { "0" }.toIntOrNull() ?: return null
84+
val targetPart = targetParts.getOrElse(i) { "0" }.toIntOrNull() ?: return null
85+
86+
if (versionPart != targetPart) return versionPart.compareTo(targetPart)
87+
}
88+
return 0
89+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.duckduckgo.common.utils.extensions
2+
3+
import junit.framework.TestCase.assertEquals
4+
import junit.framework.TestCase.assertNull
5+
import org.junit.Test
6+
7+
class StringExtensionsTest {
8+
9+
@Test
10+
fun whenSemanticVersionsAreEqualThenReturnZero() {
11+
assertEquals(0, "1.0.0".compareSemanticVersion("1.0.0"))
12+
assertEquals(0, "2.1.3.5".compareSemanticVersion("2.1.3.5"))
13+
assertEquals(0, "1.0".compareSemanticVersion("1.0.0"))
14+
assertEquals(0, "1.0.0".compareSemanticVersion("1.0"))
15+
assertEquals(0, "1.0.0".compareSemanticVersion("1.0"))
16+
assertEquals(0, "126.0.6478.40".compareSemanticVersion("126.0.6478.40"))
17+
}
18+
19+
@Test
20+
fun whenCurrentSemanticVersionIsGreaterThanTargetSemanticVersionThenReturnOne() {
21+
assertEquals(1, "1.2.0".compareSemanticVersion("1.1.9"))
22+
assertEquals(1, "1.10.0".compareSemanticVersion("1.2.5"))
23+
assertEquals(1, "2.0".compareSemanticVersion("1.9.9"))
24+
assertEquals(1, "1.2.1".compareSemanticVersion("1.2"))
25+
assertEquals(1, "1.0.1".compareSemanticVersion("1.0"))
26+
assertEquals(1, "1.1".compareSemanticVersion("1.0.0"))
27+
assertEquals(1, "1.0.0.1".compareSemanticVersion("1.0"))
28+
assertEquals(1, "127.0.6478.40".compareSemanticVersion("126.0.6478.40"))
29+
assertEquals(1, "126.1.6478.40".compareSemanticVersion("126.0.6478.40"))
30+
assertEquals(1, "126.0.6479.40".compareSemanticVersion("126.0.6478.40"))
31+
assertEquals(1, "126.0.6478.41".compareSemanticVersion("126.0.6478.40"))
32+
assertEquals(1, "127.amazon-webview-v122-6261-tablet.6261.140.26".compareSemanticVersion("126.0.6478.40"))
33+
}
34+
35+
@Test
36+
fun whenCurrentSemanticVersionIsSmallerThanTargetSemanticVersionThenReturnNegativeOne() {
37+
assertEquals(-1, "1.0.0".compareSemanticVersion("1.0.1"))
38+
assertEquals(-1, "1.2.3".compareSemanticVersion("1.2.4"))
39+
assertEquals(-1, "1.0".compareSemanticVersion("1.0.1"))
40+
assertEquals(-1, "1.0".compareSemanticVersion("1.0.0.1"))
41+
assertEquals(-1, "1.0.0".compareSemanticVersion("1.0.0.1"))
42+
assertEquals(-1, "1".compareSemanticVersion("1.0.1"))
43+
assertEquals(-1, "125.0.6478.40".compareSemanticVersion("126.0.6478.40"))
44+
assertEquals(-1, "125.1.6478.40".compareSemanticVersion("126.0.6478.40"))
45+
assertEquals(-1, "126.0.6477.40".compareSemanticVersion("126.0.6478.40"))
46+
assertEquals(-1, "126.0.6478.39".compareSemanticVersion("126.0.6478.40"))
47+
assertEquals(-1, "125.amazon-webview-v122-6261-tablet.6261.140.26".compareSemanticVersion("126.0.6478.40"))
48+
}
49+
50+
@Test
51+
fun whenSemanticVersionsAreInvalidThenReturnNull() {
52+
assertNull("1..0".compareSemanticVersion("1.0.0"))
53+
assertNull("1.0.a".compareSemanticVersion("1.0.0"))
54+
assertNull("1.0.0".compareSemanticVersion("1..0"))
55+
assertNull("1.0.0".compareSemanticVersion("1.0.a"))
56+
assertNull("a.b.c.d".compareSemanticVersion("1.0.0"))
57+
assertNull("1".compareSemanticVersion("a.1.2"))
58+
assertNull("126.amazon-webview-v122-6261-tablet.6261.140.26".compareSemanticVersion("126.0.6478.40"))
59+
assertNull("126.0.6478a.40".compareSemanticVersion("126.0.6478.40"))
60+
assertNull("126.0.6478.40a".compareSemanticVersion("126.0.6478.40"))
61+
}
62+
}

0 commit comments

Comments
 (0)