diff --git a/Kitodo/src/main/java/org/kitodo/production/filters/FilterMenu.java b/Kitodo/src/main/java/org/kitodo/production/filters/FilterMenu.java index 38776dfb5b4..990bed9a727 100644 --- a/Kitodo/src/main/java/org/kitodo/production/filters/FilterMenu.java +++ b/Kitodo/src/main/java/org/kitodo/production/filters/FilterMenu.java @@ -162,10 +162,10 @@ public void updateSuggestions(String input) { suggestions = createSuggestionsForProcessCategory(matcherNextCategory.group()); } else { // process value should be suggested - Pattern patternPreviousCategory = Pattern.compile("\\w+:(?!.*:)"); - Matcher matcherPreviousCategory = patternPreviousCategory.matcher(input); - String category = matcherPreviousCategory.find() ? matcherPreviousCategory.group() : ""; - suggestions = createSuggestionsForProcessValue(checkFilterCategory(category, processCategories), lastPart); + suggestions = createSuggestionsForProcessValue( + checkFilterCategory(findSuggestionCategory(input), processCategories), + lastPart + ); } } else if (Objects.nonNull(taskListView)) { if (matcherNextCategory.find()) { @@ -173,10 +173,10 @@ public void updateSuggestions(String input) { suggestions = createSuggestionsForTaskCategory(matcherNextCategory.group()); } else { // process/task value should be suggested - Pattern patternPreviousCategory = Pattern.compile("\\w+:(?!.*:)"); - Matcher matcherPreviousCategory = patternPreviousCategory.matcher(input); - String category = matcherPreviousCategory.find() ? matcherPreviousCategory.group() : ""; - suggestions = createSuggestionsForTaskValue(checkFilterCategory(category, taskCategories), lastPart); + suggestions = createSuggestionsForTaskValue( + checkFilterCategory(findSuggestionCategory(input), taskCategories), + lastPart + ); } } else if (Objects.nonNull(userListView)) { if (matcherNextCategory.find()) { @@ -187,6 +187,29 @@ public void updateSuggestions(String input) { } } + /** + * Return the last category in the filter string that is used for displaying suggestions. + * + *
Does not use regular expression matching with negative lookahead to prevent possible
+ * denial of service attack from user input. Instead, split input at colon symbol by adding
+ * space at the end such that the potential category is always split as the second last
+ * array element. Finally, finds last word in string by revesering it and finding first
+ * word instead, which has linear search complexity.
+ *
+ * @param input the filter string
+ * @return the last category in this filter string
+ */
+ private String findSuggestionCategory(String input) {
+ //
+ String[] colonSplit = (input + " ").split(":");
+ String secondLastSplit = colonSplit.length > 1 ? colonSplit[colonSplit.length - 2] : "";
+ // find the last word by reversing the string and finding the first word
+ String reversed = new StringBuilder(secondLastSplit).reverse().toString();
+ Matcher firstWordMatcher = Pattern.compile("^\\w+").matcher(reversed);
+ String firstReversedWord = firstWordMatcher.find() ? ":" + firstWordMatcher.group() : "";
+ return new StringBuilder(firstReversedWord).reverse().toString();
+ }
+
private List Uses regular expression possesive quantifier ++ in order to prevent
+ * possible denial of service attack from user input.
*/
private static final Pattern VARIABLE_FINDER_REGEX = Pattern.compile(
"(\\$?)\\((?:(prefs|processid|processtitle|projectid|stepid|stepname|generatorsource|generatorsourcepath|ocrdworkflowid)|"
- + "(?:(meta|process|product|template)\\.(?:(firstchild|topstruct)\\.)?([^)]+)|"
+ + "(?:(meta|process|product|template)\\.(?:(firstchild|topstruct)\\.)?([^)]++)|"
+ "(?:(filename|basename|relativepath))))\\)");
/**
* The map is filled with replacement instructions that are required for