diff options
Diffstat (limited to 'app/src/main/java')
-rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/SearchableRepositoryViewModel.kt | 50 |
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 |