diff --git a/app/src/androidTest/java/com/zeapo/pwdstore/StrictDomainRegexTest.kt b/app/src/androidTest/java/com/zeapo/pwdstore/StrictDomainRegexTest.kt index c6fa1051..951ff0a1 100644 --- a/app/src/androidTest/java/com/zeapo/pwdstore/StrictDomainRegexTest.kt +++ b/app/src/androidTest/java/com/zeapo/pwdstore/StrictDomainRegexTest.kt @@ -7,42 +7,42 @@ package com.zeapo.pwdstore import kotlin.test.assertFalse import kotlin.test.assertNull import kotlin.test.assertTrue -import org.junit.Test as test +import org.junit.Test private infix fun String.matchedForDomain(domain: String) = SearchableRepositoryViewModel.generateStrictDomainRegex(domain)?.containsMatchIn(this) == true class StrictDomainRegexTest { - @test fun acceptsLiteralDomain() { + @Test fun acceptsLiteralDomain() { assertTrue("work/example.org/john.doe@example.org.gpg" matchedForDomain "example.org") assertTrue("example.org/john.doe@example.org.gpg" matchedForDomain "example.org") assertTrue("example.org.gpg" matchedForDomain "example.org") } - @test fun acceptsSubdomains() { + @Test fun acceptsSubdomains() { assertTrue("work/www.example.org/john.doe@example.org.gpg" matchedForDomain "example.org") assertTrue("www2.example.org/john.doe@example.org.gpg" matchedForDomain "example.org") assertTrue("www.login.example.org.gpg" matchedForDomain "example.org") } - @test fun rejectsPhishingAttempts() { + @Test fun rejectsPhishingAttempts() { assertFalse("example.org.gpg" matchedForDomain "xample.org") assertFalse("login.example.org.gpg" matchedForDomain "xample.org") assertFalse("example.org/john.doe@exmple.org.gpg" matchedForDomain "xample.org") assertFalse("example.org.gpg" matchedForDomain "e/xample.org") } - @test fun rejectNonGpgComponentMatches() { + @Test fun rejectNonGpgComponentMatches() { assertFalse("work/example.org" matchedForDomain "example.org") } - @test fun rejectsEmailAddresses() { + @Test fun rejectsEmailAddresses() { assertFalse("work/notexample.org/john.doe@example.org.gpg" matchedForDomain "example.org") assertFalse("work/notexample.org/john.doe@www.example.org.gpg" matchedForDomain "example.org") assertFalse("work/john.doe@www.example.org/foo.org" matchedForDomain "example.org") } - @test fun rejectsPathSeparators() { + @Test fun rejectsPathSeparators() { assertNull(SearchableRepositoryViewModel.generateStrictDomainRegex("ex/ample.org")) } } diff --git a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt index 1604cb66..b7f7ee61 100644 --- a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt +++ b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt @@ -126,28 +126,6 @@ enum class ListMode { @FlowPreview class SearchableRepositoryViewModel(application: Application) : AndroidViewModel(application) { - companion object { - - fun generateStrictDomainRegex(domain: String): Regex? { - // Valid domains do not contain path separators. - if (domain.contains('/')) - return null - // Matches the start of a path component, which is either the start of the - // string or a path separator. - val prefix = """(?:^|/)""" - val escapedFilter = Regex.escape(domain.replace("/", "")) - // Matches either the filter literally or a strict subdomain of the filter term. - // We allow a lot of freedom in what a subdomain is, as long as it is not an - // email address. - val subdomain = """(?:(?:[^/@]+\.)?$escapedFilter)""" - // Matches the end of a path component, which is either the literal ".gpg" or a - // path separator. - val suffix = """(?:\.gpg|/)""" - // Match any relative path with a component that is a subdomain of the filter. - return Regex(prefix + subdomain + suffix) - } - } - private var _updateCounter = 0 private val updateCounter: Int get() = _updateCounter @@ -371,6 +349,28 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel forceUpdateOnNextSearchAction() searchAction.postValue(updateSearchAction(searchAction.value!!)) } + + companion object { + + fun generateStrictDomainRegex(domain: String): Regex? { + // Valid domains do not contain path separators. + if (domain.contains('/')) + return null + // Matches the start of a path component, which is either the start of the + // string or a path separator. + val prefix = """(?:^|/)""" + val escapedFilter = Regex.escape(domain.replace("/", "")) + // Matches either the filter literally or a strict subdomain of the filter term. + // We allow a lot of freedom in what a subdomain is, as long as it is not an + // email address. + val subdomain = """(?:(?:[^/@]+\.)?$escapedFilter)""" + // Matches the end of a path component, which is either the literal ".gpg" or a + // path separator. + val suffix = """(?:\.gpg|/)""" + // Match any relative path with a component that is a subdomain of the filter. + return Regex(prefix + subdomain + suffix) + } + } } private object PasswordItemDiffCallback : DiffUtil.ItemCallback() {