mirror of
https://github.com/Radarr/Radarr
synced 2026-01-24 00:13:43 +01:00
perf(backend): cache additional regex patterns (#89)
* perf(backend): cache regex patterns for better performance - TransmissionBase: add static VersionRegex, share with Transmission - SearchCriteriaBase: cache RepeatingPlusRegex - SearchMovieComparer: cache QueryYearRegex - XbmcMetadata: cache WatchedRegex Avoids regex compilation on each method call. Partially addresses #36 * fix(security): add regex timeout to prevent ReDoS vulnerabilities All cached regex patterns now include TimeSpan.FromSeconds(1) timeout to prevent potential denial of service from malicious input patterns. --------- Co-authored-by: admin <admin@ardentleatherworks.com>
This commit is contained in:
parent
b17381f53f
commit
168ea24266
5 changed files with 11 additions and 6 deletions
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
|
@ -78,7 +77,7 @@ protected override ValidationFailure ValidateVersion()
|
|||
|
||||
_logger.Debug("Transmission version information: {0}", versionString);
|
||||
|
||||
var versionResult = Regex.Match(versionString, @"(?<!\(|(\d|\.)+)(\d|\.)+(?!\)|(\d|\.)+)").Value;
|
||||
var versionResult = VersionRegex.Match(versionString).Value;
|
||||
var version = Version.Parse(versionResult);
|
||||
|
||||
if (version < new Version(2, 40))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ namespace NzbDrone.Core.Download.Clients.Transmission
|
|||
{
|
||||
public abstract class TransmissionBase : TorrentClientBase<TransmissionSettings>
|
||||
{
|
||||
protected static readonly Regex VersionRegex = new Regex(@"(?<!\(|(\d|\.)+)(\d|\.)+(?!\)|(\d|\.)+)", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
|
||||
|
||||
public abstract bool SupportsLabels { get; }
|
||||
|
||||
protected readonly ITransmissionProxy _proxy;
|
||||
|
|
@ -331,7 +333,7 @@ protected bool HasClientVersion(int major, int minor)
|
|||
{
|
||||
var rawVersion = _proxy.GetClientVersion(Settings);
|
||||
|
||||
var versionResult = Regex.Match(rawVersion, @"(?<!\(|(\d|\.)+)(\d|\.)+(?!\)|(\d|\.)+)").Value;
|
||||
var versionResult = VersionRegex.Match(rawVersion).Value;
|
||||
var clientVersion = Version.Parse(versionResult);
|
||||
|
||||
return clientVersion >= new Version(major, minor);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ public XbmcMetadata(IDetectXbmcNfo detectNfo,
|
|||
|
||||
private static readonly Regex MovieImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|clearart|discart|keyart|landscape|logo|backdrop|clearlogo)\.(?:png|jpe?g)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex MovieFileImageRegex = new Regex(@"(?<type>-thumb|-poster|-banner|-fanart|-clearart|-discart|-keyart|-landscape|-logo|-backdrop|-clearlogo)\.(?:png|jpe?g)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex WatchedRegex = new Regex("<watched>true</watched>", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
|
||||
|
||||
public override string Name => "Kodi (XBMC) / Emby";
|
||||
|
||||
|
|
@ -489,7 +490,7 @@ private bool GetExistingWatchedStatus(Movie movie, string movieFilePath)
|
|||
|
||||
var fileContent = _diskProvider.ReadAllText(fullPath);
|
||||
|
||||
return Regex.IsMatch(fileContent, "<watched>true</watched>");
|
||||
return WatchedRegex.IsMatch(fileContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
|
@ -12,6 +13,7 @@ public abstract class SearchCriteriaBase
|
|||
private static readonly Regex SpecialCharacter = new Regex(@"['.\u0060\u00B4\u2018\u2019]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex NonWord = new Regex(@"[\W]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex BeginningThe = new Regex(@"^the\s", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex RepeatingPlusRegex = new Regex(@"\+{2,}", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
|
||||
|
||||
public Movie Movie { get; set; }
|
||||
public List<string> SceneTitles { get; set; }
|
||||
|
|
@ -32,7 +34,7 @@ public static string GetCleanSceneTitle(string title)
|
|||
cleanTitle = NonWord.Replace(cleanTitle, "+");
|
||||
|
||||
// remove any repeating +s
|
||||
cleanTitle = Regex.Replace(cleanTitle, @"\+{2,}", "+");
|
||||
cleanTitle = RepeatingPlusRegex.Replace(cleanTitle, "+");
|
||||
cleanTitle = cleanTitle.RemoveAccent();
|
||||
return cleanTitle.Trim('+', ' ');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ public class SearchMovieComparer : IComparer<Movie>
|
|||
private static readonly Regex RegexCleanPunctuation = new Regex("[-._:]", RegexOptions.Compiled);
|
||||
private static readonly Regex RegexCleanCountryYearPostfix = new Regex(@"(?<=.+)( \([A-Z]{2}\)| \(\d{4}\)| \([A-Z]{2}\) \(\d{4}\))$", RegexOptions.Compiled);
|
||||
private static readonly Regex ArticleRegex = new Regex(@"^(a|an|the)\s", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex QueryYearRegex = new Regex(@"^(?<query>.+)\s+(?:\((?<year>\d{4})\)|(?<year>\d{4}))$", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
|
||||
|
||||
public string SearchQuery { get; private set; }
|
||||
|
||||
|
|
@ -21,7 +22,7 @@ public SearchMovieComparer(string searchQuery)
|
|||
{
|
||||
SearchQuery = searchQuery;
|
||||
|
||||
var match = Regex.Match(SearchQuery, @"^(?<query>.+)\s+(?:\((?<year>\d{4})\)|(?<year>\d{4}))$");
|
||||
var match = QueryYearRegex.Match(SearchQuery);
|
||||
if (match.Success)
|
||||
{
|
||||
_searchQueryWithoutYear = match.Groups["query"].Value.ToLowerInvariant();
|
||||
|
|
|
|||
Loading…
Reference in a new issue