diff --git a/app/src/main/java/org/mozilla/fenix/ext/String.kt b/app/src/main/java/org/mozilla/fenix/ext/String.kt index c01e4db5a2..1608218fcc 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/String.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/String.kt @@ -4,7 +4,8 @@ package org.mozilla.fenix.ext -import android.net.Uri +import android.net.InetAddresses +import android.os.Build import android.text.Editable import android.util.Patterns import android.webkit.URLUtil @@ -44,8 +45,7 @@ fun String.toShortUrl(publicSuffixList: PublicSuffixList): String { return inputString } - if (uri.host?.isIpv4() == true || - uri.isIpv6() || + if (uri.host?.isIpv4OrIpv6() == true || // If inputString is just a hostname and not a FQDN, use the entire hostname. uri.host?.contains(".") == false ) { @@ -73,13 +73,25 @@ fun String.toShortUrl(publicSuffixList: PublicSuffixList): String { // impl via FFTV https://searchfox.org/mozilla-mobile/source/firefox-echo-show/app/src/main/java/org/mozilla/focus/utils/FormattedDomain.java#129 @Suppress("DEPRECATION") -fun String.isIpv4(): Boolean = Patterns.IP_ADDRESS.matcher(this).matches() +internal fun String.isIpv4(): Boolean = Patterns.IP_ADDRESS.matcher(this).matches() // impl via FFiOS: https://github.com/mozilla-mobile/firefox-ios/blob/deb9736c905cdf06822ecc4a20152df7b342925d/Shared/Extensions/NSURLExtensions.swift#L292 // True IPv6 validation is difficult. This is slightly better than nothing -private fun Uri.isIpv6(): Boolean { - val host = this.host ?: return false - return host.isNotEmpty() && host.contains(":") +internal fun String.isIpv6(): Boolean { + return this.isNotEmpty() && this.contains(":") +} + +/** + * Returns true if the string represents a valid Ipv4 or Ipv6 IP address. + * Note: does not validate a dual format Ipv6 ( "y:y:y:y:y:y:x.x.x.x" format). + * + */ +fun String.isIpv4OrIpv6(): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + InetAddresses.isNumericAddress(this) + } else { + this.isIpv4() || this.isIpv6() + } } /** @@ -103,3 +115,9 @@ fun String.simplifiedUrl(): String { * Returns an [Editable] for the provided string. */ fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this) + +/** + * Returns a Ipv6 address with consecutive sections of zeroes replaced with a double colon. + */ +fun String?.replaceConsecutiveZeros(): String? = + this?.replaceFirst(":0", ":")?.replace(":0", "") diff --git a/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt b/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt index 751f23491f..eb3b18ca14 100644 --- a/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt +++ b/app/src/test/java/org/mozilla/fenix/ext/StringTest.kt @@ -225,9 +225,31 @@ class StringTest { assertFalse("2001:db8::1 ".isIpv4()) assertFalse("2001:db8:0:1:1:1:1:1".isIpv4()) assertFalse("[2001:db8:a0b:12f0::1]".isIpv4()) + assertFalse("2001:db8: 3333:4444:5555:6666:1.2.3.4".isIpv4()) + } + + @Test + fun testIsIPv6WithIPv6() { + assertTrue("2001:db8::1".isIpv6()) + assertTrue("2001:db8:0:1:1:1:1:1".isIpv6()) + } + + @Test + fun testIsIPv6WithIPv4() { + assertFalse("192.168.1.1".isIpv6()) + assertFalse("8.8.8.8".isIpv6()) + assertFalse("63.245.215.20".isIpv6()) } // END test cases borrowed from FFTV + @Test + fun testReplaceConsecutiveZeros() { + assertEquals( + "2001:db8::ff00:42:8329", + "2001:db8:0:0:0:ff00:42:8329".replaceConsecutiveZeros() + ) + } + private infix fun String.shortenedShouldBecome(expect: String) { assertEquals(expect, this.shortened()) }