From a1b1ad3b021e1df918812484c11725707b2f4f14 Mon Sep 17 00:00:00 2001 From: Cenngo Date: Tue, 3 Jan 2023 22:31:02 +0300 Subject: [PATCH] update customId template generator to escape regex metachars used in template literals --- .../Utilities/RegexUtils.cs | 71 +++++++++++++++++-- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/src/Discord.Net.Interactions/Utilities/RegexUtils.cs b/src/Discord.Net.Interactions/Utilities/RegexUtils.cs index b3316106c..8f07be66a 100644 --- a/src/Discord.Net.Interactions/Utilities/RegexUtils.cs +++ b/src/Discord.Net.Interactions/Utilities/RegexUtils.cs @@ -1,5 +1,6 @@ using Discord.Interactions; using System; +using System.Collections.Generic; using System.Linq; namespace System.Text.RegularExpressions @@ -90,7 +91,7 @@ namespace System.Text.RegularExpressions return match.Count; } - internal static bool TryBuildRegexPattern(T commandInfo, string wildCardStr, out string pattern) where T: class, ICommandInfo + internal static bool TryBuildRegexPattern(T commandInfo, string wildCardStr, out string pattern) where T : class, ICommandInfo { if (commandInfo.TreatNameAsRegex) { @@ -105,14 +106,72 @@ namespace System.Text.RegularExpressions } var escapedWildCard = Regex.Escape(wildCardStr); - var unquantified = Regex.Replace(commandInfo.Name, $@"(?[^{escapedWildCard}]?)", - @"([^\n\t${delimiter}]+)${delimiter}"); + var unquantifiedPattern = $@"(?[^{escapedWildCard}]?)"; + var quantifiedPattern = $@"(?[0-9]+)(?,[0-9]*)?(?[^{escapedWildCard}]?)"; - var quantified = Regex.Replace(unquantified, $@"(?[0-9]+)(?,[0-9]*)?(?[^{escapedWildCard}]?)", - @"([^\n\t${delimiter}]{${start}${end}})${delimiter}"); + string name = commandInfo.Name; + + var matchPairs = new SortedDictionary(); + + foreach (Match match in Regex.Matches(name, unquantifiedPattern)) + matchPairs.Add(match.Index, new(MatchType.Unquantified, match)); + + foreach (Match match in Regex.Matches(name, quantifiedPattern)) + matchPairs.Add(match.Index, new(MatchType.Quantified, match)); + + var sb = new StringBuilder(); + + var previousMatch = 0; + + foreach (var matchPair in matchPairs) + { + sb.Append(Regex.Escape(name.Substring(previousMatch, matchPair.Key - previousMatch))); + Match match = matchPair.Value.Match; + MatchType type = matchPair.Value.Type; + + previousMatch = matchPair.Key + match.Length; + + var delimiter = match.Groups["delimiter"].Value; + + switch (type) + { + case MatchType.Unquantified: + { + sb.Append(@$"([^\n\t{Regex.Escape(delimiter)}]+){Regex.Escape(delimiter)}"); + } + break; + case MatchType.Quantified: + { + var start = match.Groups["start"].Value; + var end = match.Groups["end"].Value; + + sb.Append($@"([^\n\t{Regex.Escape(delimiter)}]{{{start}{end}}}){Regex.Escape(delimiter)}"); + } + break; + } + } + + pattern = "\\A" + sb.ToString() + "\\Z"; - pattern = "\\A" + quantified + "\\Z"; return true; } + + private enum MatchType + { + Quantified, + Unquantified + } + + private record MatchPair + { + public MatchType Type { get; } + public Match Match { get; } + + public MatchPair(MatchType type, Match match) + { + Type = type; + Match = match; + } + } } }