aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt50
1 files changed, 34 insertions, 16 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt
index 992a5f79..47170717 100644
--- a/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt
@@ -126,6 +126,28 @@ 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
@@ -219,22 +241,18 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
}
FilterMode.StrictDomain -> {
check(searchAction.listMode == ListMode.FilesOnly) { "Searches with StrictDomain search mode can only list files" }
- prefilteredResultFlow
- .filter { absoluteFile ->
- val file = absoluteFile.relativeTo(root)
- val toMatch =
- directoryStructure.getIdentifierFor(file) ?: return@filter false
- // In strict domain mode, we match
- // * the search term exactly,
- // * subdomains of the search term,
- // * or the search term plus an arbitrary protocol.
- toMatch == searchAction.filter ||
- toMatch.endsWith(".${searchAction.filter}") ||
- toMatch.endsWith("://${searchAction.filter}")
- }
- .map { it.toPasswordItem(root) }
- .toList()
- .sortedWith(itemComparator)
+ val regex = generateStrictDomainRegex(searchAction.filter)
+ if (regex != null) {
+ prefilteredResultFlow
+ .filter { absoluteFile ->
+ regex.containsMatchIn(absoluteFile.relativeTo(root).path)
+ }
+ .map { it.toPasswordItem(root) }
+ .toList()
+ .sortedWith(itemComparator)
+ } else {
+ emptyList()
+ }
}
FilterMode.Fuzzy -> {
prefilteredResultFlow