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 filterSuggestionsForCategory(String input, List suggestions) { return suggestions.stream() .filter(filterString -> filterString.getFilterEnglish().startsWith(input.toLowerCase()) diff --git a/Kitodo/src/main/java/org/kitodo/production/helper/VariableReplacer.java b/Kitodo/src/main/java/org/kitodo/production/helper/VariableReplacer.java index 3532ac2fa75..3d58270b5d5 100644 --- a/Kitodo/src/main/java/org/kitodo/production/helper/VariableReplacer.java +++ b/Kitodo/src/main/java/org/kitodo/production/helper/VariableReplacer.java @@ -69,10 +69,13 @@ private enum MetadataLevel { /** * This regular expression is used to search for placeholders that need to * be replaced. + * + *

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