Allows Multiple Paths per Pattern (#491)
This commit is contained in:
Родитель
41d733abba
Коммит
284d34573c
|
@ -79,7 +79,7 @@ namespace Microsoft.ApplicationInspector.RulesEngine
|
|||
var modifiers = pattern.Modifiers?.ToList() ?? new List<string>();
|
||||
if (pattern.PatternType is PatternType.String or PatternType.Substring)
|
||||
{
|
||||
clauses.Add(new OatSubstringIndexClause(scopes, useWordBoundaries: pattern.PatternType == PatternType.String, xPath: pattern.XPath, jsonPath:pattern.JsonPath)
|
||||
clauses.Add(new OatSubstringIndexClause(scopes, useWordBoundaries: pattern.PatternType == PatternType.String, xPaths: pattern.XPaths, jsonPaths:pattern.JsonPaths)
|
||||
{
|
||||
Label = clauseNumber.ToString(CultureInfo.InvariantCulture),//important to pattern index identification
|
||||
Data = new List<string>() { pattern.Pattern },
|
||||
|
@ -95,7 +95,7 @@ namespace Microsoft.ApplicationInspector.RulesEngine
|
|||
}
|
||||
else if (pattern.PatternType == PatternType.Regex)
|
||||
{
|
||||
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPath, pattern.JsonPath)
|
||||
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPaths, pattern.JsonPaths)
|
||||
{
|
||||
Label = clauseNumber.ToString(CultureInfo.InvariantCulture),//important to pattern index identification
|
||||
Data = new List<string>() { pattern.Pattern },
|
||||
|
@ -112,7 +112,7 @@ namespace Microsoft.ApplicationInspector.RulesEngine
|
|||
}
|
||||
else if (pattern.PatternType == PatternType.RegexWord)
|
||||
{
|
||||
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPath, pattern.JsonPath)
|
||||
clauses.Add(new OatRegexWithIndexClause(scopes, null, pattern.XPaths, pattern.JsonPaths)
|
||||
{
|
||||
Label = clauseNumber.ToString(CultureInfo.InvariantCulture),//important to pattern index identification
|
||||
Data = new List<string>() { $"\\b({pattern.Pattern})\\b" },
|
||||
|
|
|
@ -6,17 +6,17 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
|
|||
{
|
||||
public class OatRegexWithIndexClause : Clause
|
||||
{
|
||||
public OatRegexWithIndexClause(PatternScope[] scopes, string? field = null, string? xPath = null, string? jsonPath = null) : base(Operation.Custom, field)
|
||||
public OatRegexWithIndexClause(PatternScope[] scopes, string? field = null, string[]? xPaths = null, string[]? jsonPaths = null) : base(Operation.Custom, field)
|
||||
{
|
||||
Scopes = scopes;
|
||||
CustomOperation = "RegexWithIndex";
|
||||
XPath = xPath;
|
||||
JsonPath = jsonPath;
|
||||
XPaths = xPaths;
|
||||
JsonPaths = jsonPaths;
|
||||
}
|
||||
|
||||
public string? JsonPath { get; }
|
||||
public string[]? JsonPaths { get; }
|
||||
|
||||
public string? XPath { get; }
|
||||
public string[]? XPaths { get; }
|
||||
|
||||
public PatternScope[] Scopes { get; }
|
||||
}
|
||||
|
|
|
@ -91,33 +91,39 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
|
|||
{
|
||||
if (StringToRegex(regexString, regexOpts) is { } regex)
|
||||
{
|
||||
if (src.XPath is not null)
|
||||
if (src.XPaths is not null)
|
||||
{
|
||||
var targets = tc.GetStringFromXPath(src.XPath);
|
||||
foreach (var target in targets)
|
||||
foreach (var xmlPath in src.XPaths)
|
||||
{
|
||||
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
|
||||
foreach (var match in matches)
|
||||
var targets = tc.GetStringFromXPath(xmlPath);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
match.Item2.Index += target.Item2.Index;
|
||||
outmatches.Add(match);
|
||||
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
|
||||
foreach (var match in matches)
|
||||
{
|
||||
match.Item2.Index += target.Item2.Index;
|
||||
outmatches.Add(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src.JsonPath is not null)
|
||||
if (src.JsonPaths is not null)
|
||||
{
|
||||
var targets = tc.GetStringFromJsonPath(src.JsonPath);
|
||||
foreach (var target in targets)
|
||||
foreach (var jsonPath in src.JsonPaths)
|
||||
{
|
||||
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
|
||||
foreach (var match in matches)
|
||||
var targets = tc.GetStringFromJsonPath(jsonPath);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
match.Item2.Index += target.Item2.Index;
|
||||
outmatches.Add(match);
|
||||
var matches = GetMatches(regex, target.Item1, tc, clause, src.Scopes);
|
||||
foreach (var match in matches)
|
||||
{
|
||||
match.Item2.Index += target.Item2.Index;
|
||||
outmatches.Add(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src.JsonPath is null && src.XPath is null)
|
||||
if (src.JsonPaths is null && src.XPaths is null)
|
||||
{
|
||||
outmatches.AddRange(GetMatches(regex, tc.FullContent, tc, clause, src.Scopes));
|
||||
}
|
||||
|
|
|
@ -6,18 +6,18 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
|
|||
{
|
||||
public class OatSubstringIndexClause : Clause
|
||||
{
|
||||
public OatSubstringIndexClause(PatternScope[] scopes, string? field = null, bool useWordBoundaries = false, string? xPath = null, string? jsonPath = null) : base(Operation.Custom, field)
|
||||
public OatSubstringIndexClause(PatternScope[] scopes, string? field = null, bool useWordBoundaries = false, string[]? xPaths = null, string[]? jsonPaths = null) : base(Operation.Custom, field)
|
||||
{
|
||||
Scopes = scopes;
|
||||
CustomOperation = "SubstringIndex";
|
||||
UseWordBoundaries = useWordBoundaries;
|
||||
XPath = xPath;
|
||||
JsonPath = jsonPath;
|
||||
XPaths = xPaths;
|
||||
JsonPaths = jsonPaths;
|
||||
}
|
||||
|
||||
public string? JsonPath { get; }
|
||||
public string[]? JsonPaths { get; }
|
||||
|
||||
public string? XPath { get; }
|
||||
public string[]? XPaths { get; }
|
||||
|
||||
public PatternScope[] Scopes { get; }
|
||||
|
||||
|
|
|
@ -63,33 +63,39 @@ namespace Microsoft.ApplicationInspector.RulesEngine.OatExtensions
|
|||
|
||||
for (int i = 0; i < stringList.Count; i++)
|
||||
{
|
||||
if (src.XPath is not null)
|
||||
if (src.XPaths is not null)
|
||||
{
|
||||
var targets = tc.GetStringFromXPath(src.XPath);
|
||||
foreach (var target in targets)
|
||||
foreach (var xmlPath in src.XPaths)
|
||||
{
|
||||
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
|
||||
foreach (var match in matches)
|
||||
var targets = tc.GetStringFromXPath(xmlPath);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
match.Index += target.Item2.Index;
|
||||
outmatches.Add((i,match));
|
||||
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
|
||||
foreach (var match in matches)
|
||||
{
|
||||
match.Index += target.Item2.Index;
|
||||
outmatches.Add((i,match));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src.JsonPath is not null)
|
||||
if (src.JsonPaths is not null)
|
||||
{
|
||||
var targets = tc.GetStringFromJsonPath(src.JsonPath);
|
||||
foreach (var target in targets)
|
||||
foreach (var jsonPath in src.JsonPaths)
|
||||
{
|
||||
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
|
||||
foreach (var match in matches)
|
||||
var targets = tc.GetStringFromJsonPath(jsonPath);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
match.Index += target.Item2.Index;
|
||||
outmatches.Add((i,match));
|
||||
var matches = GetMatches(target.Item1, stringList[i], comparisonType, tc, src);
|
||||
foreach (var match in matches)
|
||||
{
|
||||
match.Index += target.Item2.Index;
|
||||
outmatches.Add((i,match));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src.JsonPath is null && src.XPath is null)
|
||||
if (src.JsonPaths is null && src.XPaths is null)
|
||||
{
|
||||
var matches = GetMatches(tc.FullContent, stringList[i], comparisonType, tc, src);
|
||||
outmatches.AddRange(matches.Select(x => (i, x)));
|
||||
|
|
|
@ -155,29 +155,35 @@ namespace Microsoft.ApplicationInspector.RulesEngine
|
|||
}
|
||||
}
|
||||
|
||||
if (searchPattern.JsonPath is not null)
|
||||
if (searchPattern.JsonPaths is not null)
|
||||
{
|
||||
try
|
||||
foreach (var jsonPath in searchPattern.JsonPaths)
|
||||
{
|
||||
_ = JsonSelector.Parse(searchPattern.JsonPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger?.LogError("The provided JsonPath '{JsonPath}' value was not valid in Rule {Id} : {message}", searchPattern.JsonPath, rule.Id, e.Message);
|
||||
errors.Add(string.Format("The provided JsonPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPath, rule.Id, e.Message));
|
||||
try
|
||||
{
|
||||
_ = JsonSelector.Parse(jsonPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger?.LogError("The provided JsonPath '{JsonPath}' value was not valid in Rule {Id} : {message}", searchPattern.JsonPaths, rule.Id, e.Message);
|
||||
errors.Add(string.Format("The provided JsonPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPaths, rule.Id, e.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (searchPattern.XPath is not null)
|
||||
if (searchPattern.XPaths is not null)
|
||||
{
|
||||
try
|
||||
foreach (var xpath in searchPattern.XPaths)
|
||||
{
|
||||
XPathExpression.Compile(searchPattern.XPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger?.LogError("The provided XPath '{XPath}' value was not valid in Rule {Id} : {message}", searchPattern.XPath, rule.Id, e.Message);
|
||||
errors.Add(string.Format("The provided XPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPath, rule.Id, e.Message));
|
||||
try
|
||||
{
|
||||
XPathExpression.Compile(xpath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger?.LogError("The provided XPath '{XPath}' value was not valid in Rule {Id} : {message}", searchPattern.XPaths, rule.Id, e.Message);
|
||||
errors.Add(string.Format("The provided XPath '{0}' value was not valid in Rule {1} : {2}", searchPattern.JsonPaths, rule.Id, e.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,14 +48,14 @@ namespace Microsoft.ApplicationInspector.RulesEngine
|
|||
/// If set, attempt to parse the file as XML and if that is possible,
|
||||
/// before running the pattern, select down to the XPath provided
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName ="xpath")]
|
||||
public string? XPath { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName ="xpaths")]
|
||||
public string[]? XPaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set, attempt to parse the file as JSON and if that is possible,
|
||||
/// before running the pattern, select down to the JsonPath provided
|
||||
/// </summary>
|
||||
[JsonProperty(PropertyName ="jsonpath")]
|
||||
public string? JsonPath { get; set; }
|
||||
[JsonProperty(PropertyName = "jsonpaths")]
|
||||
public string[]? JsonPaths { get; set; }
|
||||
}
|
||||
}
|
|
@ -196,8 +196,8 @@ namespace AppInspector.Tests.RuleProcessor
|
|||
""scopes"": [
|
||||
""code""
|
||||
],
|
||||
""jsonpath"" : ""$.books[*].title"",
|
||||
""xpath"" : ""/bookstore/book/title""
|
||||
""jsonpaths"" : [""$.books[*].title""],
|
||||
""xpaths"" : [""/bookstore/book/title""]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
|
@ -221,7 +221,7 @@ namespace AppInspector.Tests.RuleProcessor
|
|||
""scopes"": [
|
||||
""code""
|
||||
],
|
||||
""jsonpath"" : ""$.books[*].title""
|
||||
""jsonpaths"" : [""$.books[*].title""]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
|
@ -245,7 +245,7 @@ namespace AppInspector.Tests.RuleProcessor
|
|||
""scopes"": [
|
||||
""code""
|
||||
],
|
||||
""xpath"" : ""/bookstore/book/title""
|
||||
""xpaths"" : [""/bookstore/book/title""]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
|
|
|
@ -70,8 +70,8 @@ namespace AppInspector.Tests.RuleProcessor
|
|||
""scopes"": [
|
||||
""code""
|
||||
],
|
||||
""jsonpath"" : ""$.books[*].title"",
|
||||
""xpath"" : ""/bookstore/book/title""
|
||||
""jsonpaths"" : [""$.books[*].title""],
|
||||
""xpaths"" : [""/bookstore/book/title""]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
|
@ -95,7 +95,7 @@ namespace AppInspector.Tests.RuleProcessor
|
|||
""scopes"": [
|
||||
""code""
|
||||
],
|
||||
""jsonpath"" : ""$.books[*].title""
|
||||
""jsonpaths"" : [""$.books[*].title""]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
|
@ -119,7 +119,7 @@ namespace AppInspector.Tests.RuleProcessor
|
|||
""scopes"": [
|
||||
""code""
|
||||
],
|
||||
""xpath"" : ""/bookstore/book/title""
|
||||
""xpaths"" : [""/bookstore/book/title""]
|
||||
}
|
||||
],
|
||||
""_comment"": """"
|
||||
|
|
Загрузка…
Ссылка в новой задаче