From 6e34cea9d6dd990797c18c3c52dea6b22d490c8d Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 29 Nov 2016 10:57:18 +0100 Subject: [PATCH] SONAR-8436 escape param "tags" of WS api/rules/tags --- .../org/sonar/server/rule/index/RuleIndex.java | 11 ++++++++--- .../server/rule/RuleServiceMediumTest.java | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java index 20405f59bf1..9fcc1101827 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/index/RuleIndex.java @@ -33,6 +33,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; @@ -105,6 +106,7 @@ public class RuleIndex extends BaseIndex { public static final String FACET_STATUSES = "statuses"; public static final String FACET_TYPES = "types"; public static final String FACET_OLD_DEFAULT = "true"; + private static Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]"); public static final List ALL_STATUSES_EXCEPT_REMOVED = ImmutableList.copyOf( Collections2.filter(Collections2.transform(Arrays.asList(RuleStatus.values()), RuleStatusToString.INSTANCE), NotRemoved.INSTANCE)); @@ -180,8 +182,7 @@ public class RuleIndex extends BaseIndex { qb.should(simpleQueryStringQuery(query.getQueryText()) .field(FIELD_RULE_NAME + "." + SEARCH_WORDS_SUFFIX, 20f) .field(FIELD_RULE_HTML_DESCRIPTION, 3f) - .defaultOperator(SimpleQueryStringBuilder.Operator.AND) - ).boost(20f); + .defaultOperator(SimpleQueryStringBuilder.Operator.AND)).boost(20f); // Match and partial Match queries // Search by key uses the "sortable" sub-field as it requires to be case-insensitive (lower-case filtering) @@ -477,7 +478,7 @@ public class RuleIndex extends BaseIndex { .size(size) .minDocCount(1); if (query != null) { - termsAggregation.include(".*" + query + ".*"); + termsAggregation.include(".*" + escapeSpecialRegexChars(query) + ".*"); } SearchRequestBuilder request = getClient() .prepareSearch(INDEX) @@ -495,6 +496,10 @@ public class RuleIndex extends BaseIndex { return terms; } + private static String escapeSpecialRegexChars(String str) { + return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); + } + private enum ToRuleKey implements Function { INSTANCE; diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java index d56d5aff5b7..80440da8f90 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/RuleServiceMediumTest.java @@ -82,17 +82,32 @@ public class RuleServiceMediumTest { @Test public void listTags_returns_tags_filtered_by_name() { - insertRule(RuleKey.of("javascript", "S001"), newHashSet("tag1"), newHashSet("sys1", "sys2")); + insertRule(RuleKey.of("javascript", "S001"), newHashSet("tag1", "misra++"), newHashSet("sys1", "sys2")); insertRule(RuleKey.of("java", "S001"), newHashSet("tag2"), newHashSet()); assertThat(service.listTags("missing", 10)).isEmpty(); + assertThat(service.listTags("", 10)).containsOnly("tag1", "misra++", "tag2", "sys1", "sys2"); assertThat(service.listTags("tag", 10)).containsOnly("tag1", "tag2"); assertThat(service.listTags("sys", 10)).containsOnly("sys1", "sys2"); + assertThat(service.listTags("misra", 10)).containsOnly("misra++"); + assertThat(service.listTags("misra+", 10)).containsOnly("misra++"); + assertThat(service.listTags("++", 10)).containsOnly("misra++"); // LIMITATION: case sensitive assertThat(service.listTags("TAG", 10)).isEmpty(); assertThat(service.listTags("TAg", 10)).isEmpty(); assertThat(service.listTags("MISSing", 10)).isEmpty(); + + assertThat(service.listTags("misra-", 10)).isEmpty(); + } + + @Test + public void listTags_returns_empty_results_if_filter_contains_regexp_special_characters() { + insertRule(RuleKey.of("javascript", "S001"), newHashSet("misra++"), newHashSet("sys1", "sys2")); + + assertThat(service.listTags("mis[", 10)).isEmpty(); + assertThat(service.listTags("mis\\d", 10)).isEmpty(); + assertThat(service.listTags(".*", 10)).isEmpty(); } @Test -- 2.39.5