diff --git a/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt b/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt
index 891bb5852..b970b83c3 100644
--- a/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt
+++ b/app/core/src/main/java/com/fsck/k9/message/html/UriMatcher.kt
@@ -31,4 +31,20 @@ object UriMatcher {
parser.parseUri(text, startIndex)
}.filterNotNull().toList()
}
+
+ @Suppress("ReturnCount")
+ fun isValidUri(text: CharSequence): Boolean {
+ val matchResult = URI_SCHEME.matchAt(text, 0) ?: return false
+
+ val matchGroup = matchResult.groups[1]!!
+ if (matchGroup.range.first != 0) {
+ return false
+ }
+
+ val scheme = matchGroup.value.lowercase()
+ val parser = SUPPORTED_URIS[scheme] ?: throw AssertionError("Scheme not found: $scheme")
+ val uriMatch = parser.parseUri(text, startPos = 0) ?: return false
+
+ return uriMatch.startIndex == 0 && uriMatch.endIndex == text.length
+ }
}
diff --git a/app/core/src/test/java/com/fsck/k9/message/html/UriMatcherTest.kt b/app/core/src/test/java/com/fsck/k9/message/html/UriMatcherTest.kt
index fd0b02ecd..16ef2dcdc 100644
--- a/app/core/src/test/java/com/fsck/k9/message/html/UriMatcherTest.kt
+++ b/app/core/src/test/java/com/fsck/k9/message/html/UriMatcherTest.kt
@@ -1,10 +1,13 @@
package com.fsck.k9.message.html
+import assertk.Assert
import assertk.assertThat
import assertk.assertions.hasSize
import assertk.assertions.isEmpty
import assertk.assertions.isEqualTo
+import assertk.assertions.isFalse
import assertk.assertions.isNotEqualTo
+import assertk.assertions.isTrue
import org.junit.Test
class UriMatcherTest {
@@ -82,6 +85,27 @@ class UriMatcherTest {
)
}
+ @Test
+ fun `valid URIs`() {
+ assertThat("http://domain.example").isValidUri()
+ assertThat("https://domain.example/").isValidUri()
+ assertThat("mailto:user@domain.example").isValidUri()
+ }
+
+ @Test
+ fun `not URIs`() {
+ assertThat("some text here").isNotValidUri()
+ assertThat("some text including the string http:").isNotValidUri()
+ assertThat("some text including an email address without URI scheme: user@domain.example").isNotValidUri()
+ }
+
+ @Test
+ fun `valid URIs surrounded by other characters`() {
+ assertThat("text https://domain.example/").isNotValidUri()
+ assertThat("https://domain.example/ text").isNotValidUri()
+ assertThat("").isNotValidUri()
+ }
+
private fun assertNoMatch(text: String) {
val uriMatches = UriMatcher.findUris(text)
assertThat(uriMatches).isEmpty()
@@ -104,3 +128,11 @@ class UriMatcherTest {
}
}
}
+
+private fun Assert.isValidUri() = given { actual ->
+ assertThat(UriMatcher.isValidUri(actual)).isTrue()
+}
+
+private fun Assert.isNotValidUri() = given { actual ->
+ assertThat(UriMatcher.isValidUri(actual)).isFalse()
+}