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() +}