diff --git a/build/_build.csproj b/build/_build.csproj index d5eadde9..dbc52a56 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 False CS0649;CS0169 @@ -10,15 +10,17 @@ - - + + + + all runtime; build; native; contentfiles; analyzers - + diff --git a/global.json b/global.json index 4c686a52..971b5004 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "9.0.301" + "version": "10.0.100", + "rollForward": "latestPatch" } } \ No newline at end of file diff --git a/src/AutoColumnizer/AutoColumnizer.csproj b/src/AutoColumnizer/AutoColumnizer.csproj index 3f5dd983..cb537385 100644 --- a/src/AutoColumnizer/AutoColumnizer.csproj +++ b/src/AutoColumnizer/AutoColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 AutoColumnizer $(SolutionDir)..\bin\$(Configuration)\plugins diff --git a/src/ColumnizerLib.UnitTests/ColumnizerLib.UnitTests.csproj b/src/ColumnizerLib.UnitTests/ColumnizerLib.UnitTests.csproj index af5aa1ac..96ae6dae 100644 --- a/src/ColumnizerLib.UnitTests/ColumnizerLib.UnitTests.csproj +++ b/src/ColumnizerLib.UnitTests/ColumnizerLib.UnitTests.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 true ColumnizerLib.UnitTests diff --git a/src/ColumnizerLib/ColumnizerLib.csproj b/src/ColumnizerLib/ColumnizerLib.csproj index 960aa76e..5f0376de 100644 --- a/src/ColumnizerLib/ColumnizerLib.csproj +++ b/src/ColumnizerLib/ColumnizerLib.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 $(SolutionDir)..\bin\Docs\ColumnizerLib.xml diff --git a/src/CsvColumnizer/CsvColumnizer.csproj b/src/CsvColumnizer/CsvColumnizer.csproj index 005a350a..bb1e079f 100644 --- a/src/CsvColumnizer/CsvColumnizer.csproj +++ b/src/CsvColumnizer/CsvColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0-windows + net10.0-windows true true diff --git a/src/DefaultPlugins/DefaultPlugins.csproj b/src/DefaultPlugins/DefaultPlugins.csproj index 20255a67..3f53e80e 100644 --- a/src/DefaultPlugins/DefaultPlugins.csproj +++ b/src/DefaultPlugins/DefaultPlugins.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 $(SolutionDir)..\bin\$(Configuration)\plugins diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index d357ea89..100bf68d 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -9,18 +9,18 @@ - + - - + + - + - - - - + + + + \ No newline at end of file diff --git a/src/FlashIconHighlighter/FlashIconHighlighter.csproj b/src/FlashIconHighlighter/FlashIconHighlighter.csproj index 50489d9a..af0c5828 100644 --- a/src/FlashIconHighlighter/FlashIconHighlighter.csproj +++ b/src/FlashIconHighlighter/FlashIconHighlighter.csproj @@ -1,7 +1,7 @@  - net8.0-windows + net10.0-windows true true true diff --git a/src/GlassfishColumnizer/GlassfishColumnizer.csproj b/src/GlassfishColumnizer/GlassfishColumnizer.csproj index 23bf3af2..3f0c708b 100644 --- a/src/GlassfishColumnizer/GlassfishColumnizer.csproj +++ b/src/GlassfishColumnizer/GlassfishColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 $(SolutionDir)..\bin\$(Configuration)\plugins GlassfishColumnizer diff --git a/src/JsonColumnizer/JsonColumnizer.csproj b/src/JsonColumnizer/JsonColumnizer.csproj index 0092f405..8a882ff2 100644 --- a/src/JsonColumnizer/JsonColumnizer.csproj +++ b/src/JsonColumnizer/JsonColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 $(SolutionDir)..\bin\$(Configuration)\plugins JsonColumnizer diff --git a/src/JsonCompactColumnizer/JsonCompactColumnizer.csproj b/src/JsonCompactColumnizer/JsonCompactColumnizer.csproj index bd18a3cc..e46da3ba 100644 --- a/src/JsonCompactColumnizer/JsonCompactColumnizer.csproj +++ b/src/JsonCompactColumnizer/JsonCompactColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0 JsonColumnizer $(SolutionDir)..\bin\$(Configuration)\plugins diff --git a/src/Log4jXmlColumnizer/Log4jXmlColumnizer.csproj b/src/Log4jXmlColumnizer/Log4jXmlColumnizer.csproj index 88d38b28..3598fe21 100644 --- a/src/Log4jXmlColumnizer/Log4jXmlColumnizer.csproj +++ b/src/Log4jXmlColumnizer/Log4jXmlColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0-windows + net10.0-windows true true diff --git a/src/LogExpert.Core/Classes/Filter/FilterParams.cs b/src/LogExpert.Core/Classes/Filter/FilterParams.cs index 68376518..e8aaa1af 100644 --- a/src/LogExpert.Core/Classes/Filter/FilterParams.cs +++ b/src/LogExpert.Core/Classes/Filter/FilterParams.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using LogExpert.Core.Classes.JsonConverters; +using LogExpert.Core.Helpers; using Newtonsoft.Json; @@ -130,12 +131,12 @@ public void CreateRegex () { if (SearchText != null) { - Regex = new Regex(SearchText, IsCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase); + Regex = RegexHelper.GetOrCreateCached(SearchText, IsCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase); } if (RangeSearchText != null && IsRangeSearch) { - RangeRex = new Regex(RangeSearchText, IsCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase); + RangeRex = RegexHelper.GetOrCreateCached(RangeSearchText, IsCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase); } } diff --git a/src/LogExpert.Core/Classes/Highlight/HighlightEntry.cs b/src/LogExpert.Core/Classes/Highlight/HighlightEntry.cs index cd0391ee..b4f18867 100644 --- a/src/LogExpert.Core/Classes/Highlight/HighlightEntry.cs +++ b/src/LogExpert.Core/Classes/Highlight/HighlightEntry.cs @@ -1,6 +1,8 @@ using System.Drawing; using System.Text.RegularExpressions; +using LogExpert.Core.Helpers; + using Newtonsoft.Json; namespace LogExpert.Core.Classes.Highlight; @@ -54,10 +56,10 @@ public Regex Regex get { _regex ??= IsRegex - ? new Regex(SearchText, IsCaseSensitive + ? RegexHelper.GetOrCreateCached(SearchText, IsCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase) - : new Regex(Regex.Escape(SearchText), + : RegexHelper.GetOrCreateCached(System.Text.RegularExpressions.Regex.Escape(SearchText), IsCaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase); diff --git a/src/LogExpert.Core/Classes/ParamParser.cs b/src/LogExpert.Core/Classes/ParamParser.cs index 6ca9731f..10ede7c6 100644 --- a/src/LogExpert.Core/Classes/ParamParser.cs +++ b/src/LogExpert.Core/Classes/ParamParser.cs @@ -1,6 +1,8 @@ using System.Text; using System.Text.RegularExpressions; +using LogExpert.Core.Helpers; + namespace LogExpert.Core.Classes; public class ParamParser (string argTemplate) @@ -38,8 +40,18 @@ public string ReplaceParams (ILogLine logLine, int lineNum, string fileName) replace = GetNextGroup(builder, ref sPos); if (reg != null && replace != null) { - var result = Regex.Replace(logLine.FullLine, reg, replace); - builder.Insert(sPos, result); + // Use RegexHelper for safe regex operations with timeout protection + try + { + var regex = RegexHelper.GetOrCreateCached(reg); + var result = regex.Replace(logLine.FullLine, replace); + builder.Insert(sPos, result); + } + catch (RegexMatchTimeoutException) + { + // If regex times out, insert the original pattern as fallback + builder.Insert(sPos, $"{{timeout: {reg}}}"); + } } } while (replace != null); return builder.ToString(); diff --git a/src/LogExpert.Core/Classes/xml/XmlLogReader.cs b/src/LogExpert.Core/Classes/xml/XmlLogReader.cs index 99ed640f..58832449 100644 --- a/src/LogExpert.Core/Classes/xml/XmlLogReader.cs +++ b/src/LogExpert.Core/Classes/xml/XmlLogReader.cs @@ -58,17 +58,37 @@ public override int ReadChar() } public override string ReadLine() + { + // Call async version synchronously for backward compatibility + // This maintains the interface but uses the improved async implementation internally + return ReadLineAsync(CancellationToken.None).GetAwaiter().GetResult(); + } + + /// + /// Reads a complete XML block asynchronously. + /// Replaces Thread.Sleep with Task.Delay for non-blocking waits. + /// + /// Cancellation token for graceful cancellation + /// Complete XML block or null if not available + public async Task ReadLineAsync(CancellationToken cancellationToken = default) { short state = 0; var tagIndex = 0; var blockComplete = false; var eof = false; var tryCounter = 5; + const int delayMs = 100; StringBuilder builder = new(); while (!eof && !blockComplete) { + // Check for cancellation + if (cancellationToken.IsCancellationRequested) + { + return null; + } + var readInt = ReadChar(); if (readInt == -1) { @@ -77,11 +97,21 @@ public override string ReadLine() { if (--tryCounter > 0) { - Thread.Sleep(100); + // Use Task.Delay instead of Thread.Sleep for non-blocking wait + try + { + await Task.Delay(delayMs, cancellationToken); + } + catch (OperationCanceledException) + { + // Gracefully handle cancellation + return null; + } continue; } else { + // Timeout - return partial block if available break; } } diff --git a/src/LogExpert.Core/Helpers/RegexHelper.cs b/src/LogExpert.Core/Helpers/RegexHelper.cs new file mode 100644 index 00000000..13b93cb5 --- /dev/null +++ b/src/LogExpert.Core/Helpers/RegexHelper.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Concurrent; +using System.Text.RegularExpressions; + +namespace LogExpert.Core.Helpers; + +/// +/// Helper class for creating and managing regex instances with safety features. +/// Provides timeout protection against catastrophic backtracking (DoS attacks) +/// and caching for improved performance. +/// +public static class RegexHelper +{ + /// + /// Default timeout for all regex operations to prevent DoS attacks. + /// This prevents catastrophic backtracking from freezing the application. + /// + public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(2); + + private static readonly ConcurrentDictionary _cache = new(); + private const int MaxCacheSize = 100; + + /// + /// Creates a regex with timeout protection. + /// + /// The regular expression pattern. + /// Regex options to use. + /// Optional timeout override. Uses DefaultTimeout if not specified. + /// A Regex instance with timeout protection. + /// Thrown if pattern is null. + /// Thrown if pattern is invalid. + public static Regex CreateSafeRegex( + string pattern, + RegexOptions options = RegexOptions.None, + TimeSpan? timeout = null) + { + ArgumentNullException.ThrowIfNull(pattern); + + return new Regex( + pattern, + options, + timeout ?? DefaultTimeout); + } + + /// + /// Gets or creates a cached regex instance. + /// This improves performance by reusing compiled regex patterns. + /// + /// The regular expression pattern. + /// Regex options to use. + /// A cached Regex instance with timeout protection. + public static Regex GetOrCreateCached( + string pattern, + RegexOptions options = RegexOptions.None) + { + var key = new RegexCacheKey(pattern, options); + + return _cache.GetOrAdd(key, k => + { + // Evict oldest entries if cache is full + if (_cache.Count >= MaxCacheSize) + { + TrimCache(); + } + + return CreateSafeRegex(k.Pattern, k.Options); + }); + } + + /// + /// Validates a regex pattern without executing it. + /// + /// The pattern to validate. + /// Output parameter containing error message if validation fails. + /// True if the pattern is valid, false otherwise. + public static bool IsValidPattern(string pattern, out string? error) + { + if (string.IsNullOrEmpty(pattern)) + { + error = "Pattern cannot be null or empty."; + return false; + } + + try + { + _ = new Regex(pattern, RegexOptions.None, TimeSpan.FromMilliseconds(100)); + error = null; + return true; + } + catch (ArgumentException ex) + { + error = ex.Message; + return false; + } + catch (RegexMatchTimeoutException) + { + // Pattern is valid syntactically, but may be complex + error = null; + return true; + } + } + + /// + /// Clears the regex cache. Useful for testing or memory management. + /// + public static void ClearCache() + { + _cache.Clear(); + } + + /// + /// Gets the current cache size. + /// + public static int CacheSize => _cache.Count; + + private static void TrimCache() + { + // Keep most recent 50 entries (half of max) + var toRemove = _cache.Keys.Take(_cache.Count - MaxCacheSize / 2).ToList(); + foreach (var key in toRemove) + { + _cache.TryRemove(key, out _); + } + } + + private record RegexCacheKey(string Pattern, RegexOptions Options); +} diff --git a/src/LogExpert.Core/LogExpert.Core.csproj b/src/LogExpert.Core/LogExpert.Core.csproj index 8b8e1e8f..09862a29 100644 --- a/src/LogExpert.Core/LogExpert.Core.csproj +++ b/src/LogExpert.Core/LogExpert.Core.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 true LogExpert.Core diff --git a/src/LogExpert.Resources/LogExpert.Resources.csproj b/src/LogExpert.Resources/LogExpert.Resources.csproj index 1337b7d9..1af925eb 100644 --- a/src/LogExpert.Resources/LogExpert.Resources.csproj +++ b/src/LogExpert.Resources/LogExpert.Resources.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 True False ..\Solution Items\Key.snk diff --git a/src/LogExpert.Tests/Helpers/RegexHelperTests.cs b/src/LogExpert.Tests/Helpers/RegexHelperTests.cs new file mode 100644 index 00000000..573755d0 --- /dev/null +++ b/src/LogExpert.Tests/Helpers/RegexHelperTests.cs @@ -0,0 +1,271 @@ +using System.Text.RegularExpressions; + +using LogExpert.Core.Helpers; + +using NUnit.Framework; + +namespace LogExpert.Tests.Helpers; + +[TestFixture] +public class RegexHelperTests +{ + [SetUp] + public void Setup() + { + // Clear cache before each test to ensure isolation + RegexHelper.ClearCache(); + } + + [Test] + public void CreateSafeRegex_ShouldHaveDefaultTimeout() + { + // Arrange & Act + var regex = RegexHelper.CreateSafeRegex("test"); + + // Assert + Assert.That(regex.MatchTimeout, Is.EqualTo(RegexHelper.DefaultTimeout)); + } + + [Test] + public void CreateSafeRegex_WithCustomTimeout_ShouldUseCustomTimeout() + { + // Arrange + var customTimeout = TimeSpan.FromSeconds(5); + + // Act + var regex = RegexHelper.CreateSafeRegex("test", RegexOptions.None, customTimeout); + + // Assert + Assert.That(regex.MatchTimeout, Is.EqualTo(customTimeout)); + } + + [Test] + public void CreateSafeRegex_WithNullPattern_ShouldThrowArgumentNullException() + { + // Act & Assert + Assert.Throws(() => RegexHelper.CreateSafeRegex(null!)); + } + + [Test] + public void CreateSafeRegex_ShouldPreventCatastrophicBacktracking() + { + // Arrange + var maliciousPattern = "^(a+)+$"; + var maliciousInput = "aaaaaaaaaaaaaaaaaX"; + var regex = RegexHelper.CreateSafeRegex(maliciousPattern); + + // Act & Assert + Assert.Throws(() => + { + regex.IsMatch(maliciousInput); + }); + } + + [Test] + public void CreateSafeRegex_WithComplexPattern_ShouldTimeout() + { + // Arrange - Another catastrophic backtracking pattern + var pattern = "(x+x+)+y"; + var input = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX"; + var regex = RegexHelper.CreateSafeRegex(pattern); + + // Act & Assert + Assert.Throws(() => + { + regex.IsMatch(input); + }); + } + + [Test] + public void GetOrCreateCached_ShouldReturnSameInstance() + { + // Arrange & Act + var regex1 = RegexHelper.GetOrCreateCached("test"); + var regex2 = RegexHelper.GetOrCreateCached("test"); + + // Assert + Assert.That(regex1, Is.SameAs(regex2)); + } + + [Test] + public void GetOrCreateCached_WithDifferentPatterns_ShouldReturnDifferentInstances() + { + // Arrange & Act + var regex1 = RegexHelper.GetOrCreateCached("test1"); + var regex2 = RegexHelper.GetOrCreateCached("test2"); + + // Assert + Assert.That(regex1, Is.Not.SameAs(regex2)); + } + + [Test] + public void GetOrCreateCached_WithDifferentOptions_ShouldReturnDifferentInstances() + { + // Arrange & Act + var regex1 = RegexHelper.GetOrCreateCached("test", RegexOptions.None); + var regex2 = RegexHelper.GetOrCreateCached("test", RegexOptions.IgnoreCase); + + // Assert + Assert.That(regex1, Is.Not.SameAs(regex2)); + } + + [Test] + public void GetOrCreateCached_ShouldCacheUpToMaxSize() + { + // Arrange - Create more patterns than cache size + var cacheSize = 100; + + // Act - Fill the cache + for (int i = 0; i < cacheSize; i++) + { + RegexHelper.GetOrCreateCached($"pattern{i}"); + } + + // Assert - Cache should be at max size + Assert.That(RegexHelper.CacheSize, Is.EqualTo(cacheSize)); + + // Act - Add more to trigger eviction + RegexHelper.GetOrCreateCached("pattern_overflow"); + + // Assert - Cache should have evicted some entries + Assert.That(RegexHelper.CacheSize, Is.LessThanOrEqualTo(cacheSize)); + } + + [Test] + public void IsValidPattern_WithValidPattern_ShouldReturnTrue() + { + // Arrange + var pattern = @"\d{4}-\d{2}-\d{2}"; + + // Act + var result = RegexHelper.IsValidPattern(pattern, out var error); + + // Assert + Assert.That(result, Is.True); + Assert.That(error, Is.Null); + } + + [Test] + public void IsValidPattern_WithInvalidPattern_ShouldReturnFalse() + { + // Arrange + var pattern = "[invalid"; + + // Act + var result = RegexHelper.IsValidPattern(pattern, out var error); + + // Assert + Assert.That(result, Is.False); + Assert.That(error, Is.Not.Null); + Assert.That(error, Does.Contain("parsing")); + } + + [Test] + public void IsValidPattern_WithNullPattern_ShouldReturnFalse() + { + // Act + var result = RegexHelper.IsValidPattern(null!, out var error); + + // Assert + Assert.That(result, Is.False); + Assert.That(error, Is.Not.Null); + } + + [Test] + public void IsValidPattern_WithEmptyPattern_ShouldReturnFalse() + { + // Act + var result = RegexHelper.IsValidPattern(string.Empty, out var error); + + // Assert + Assert.That(result, Is.False); + Assert.That(error, Is.Not.Null); + } + + [Test] + public void ClearCache_ShouldRemoveAllCachedRegex() + { + // Arrange + RegexHelper.GetOrCreateCached("test1"); + RegexHelper.GetOrCreateCached("test2"); + RegexHelper.GetOrCreateCached("test3"); + Assert.That(RegexHelper.CacheSize, Is.GreaterThan(0)); + + // Act + RegexHelper.ClearCache(); + + // Assert + Assert.That(RegexHelper.CacheSize, Is.EqualTo(0)); + } + + [Test] + public void CachedRegex_ShouldWorkCorrectly() + { + // Arrange + var pattern = @"(\d{4})-(\d{2})-(\d{2})"; + var input = "Date: 2025-11-11"; + var regex = RegexHelper.GetOrCreateCached(pattern); + + // Act + var match = regex.Match(input); + + // Assert + Assert.That(match.Success, Is.True); + Assert.That(match.Groups[1].Value, Is.EqualTo("2025")); + Assert.That(match.Groups[2].Value, Is.EqualTo("11")); + Assert.That(match.Groups[3].Value, Is.EqualTo("11")); + } + + [Test] + public void CachedRegex_WithIgnoreCase_ShouldMatchCaseInsensitively() + { + // Arrange + var pattern = "test"; + var regex = RegexHelper.GetOrCreateCached(pattern, RegexOptions.IgnoreCase); + + // Act + var match1 = regex.IsMatch("TEST"); + var match2 = regex.IsMatch("Test"); + var match3 = regex.IsMatch("test"); + + // Assert + Assert.That(match1, Is.True); + Assert.That(match2, Is.True); + Assert.That(match3, Is.True); + } + + [Test] + public void CachedRegex_ShouldHaveTimeout() + { + // Arrange & Act + var regex = RegexHelper.GetOrCreateCached("test"); + + // Assert + Assert.That(regex.MatchTimeout, Is.EqualTo(RegexHelper.DefaultTimeout)); + } + + [Test] + public void DefaultTimeout_ShouldBeTwoSeconds() + { + // Assert + Assert.That(RegexHelper.DefaultTimeout, Is.EqualTo(TimeSpan.FromSeconds(2))); + } + + [TestCase(@"\d+", "123", true)] + [TestCase(@"\d+", "abc", false)] + [TestCase(@"[A-Z]+", "ABC", true)] + [TestCase(@"[A-Z]+", "abc", false)] + [TestCase(@"^\w+@\w+\.\w+$", "test@example.com", true)] + [TestCase(@"^\w+@\w+\.\w+$", "invalid-email", false)] + public void CreateSafeRegex_CommonPatterns_ShouldWorkCorrectly(string pattern, string input, bool expectedMatch) + { + // Arrange + var regex = RegexHelper.CreateSafeRegex(pattern); + + // Act + var result = regex.IsMatch(input); + + // Assert + Assert.That(result, Is.EqualTo(expectedMatch)); + } +} diff --git a/src/LogExpert.Tests/LogExpert.Tests.csproj b/src/LogExpert.Tests/LogExpert.Tests.csproj index 71fdb0dc..ca38ba90 100644 --- a/src/LogExpert.Tests/LogExpert.Tests.csproj +++ b/src/LogExpert.Tests/LogExpert.Tests.csproj @@ -1,7 +1,7 @@  - net8.0-windows + net10.0-windows true true diff --git a/src/LogExpert.UI/Controls/BufferedDataGridView.cs b/src/LogExpert.UI/Controls/BufferedDataGridView.cs index d2f557da..5d5d4a83 100644 --- a/src/LogExpert.UI/Controls/BufferedDataGridView.cs +++ b/src/LogExpert.UI/Controls/BufferedDataGridView.cs @@ -6,6 +6,7 @@ using LogExpert.UI.Controls; using NLog; +using System.ComponentModel; namespace LogExpert.Dialogs; @@ -61,8 +62,10 @@ public Graphics Buffer } */ + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public ContextMenuStrip EditModeMenuStrip { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool PaintWithOverlays { get; set; } #endregion diff --git a/src/LogExpert.UI/Controls/ColorComboBox.cs b/src/LogExpert.UI/Controls/ColorComboBox.cs index ecafb2a1..af12e836 100644 --- a/src/LogExpert.UI/Controls/ColorComboBox.cs +++ b/src/LogExpert.UI/Controls/ColorComboBox.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Drawing.Drawing2D; using System.Runtime.Versioning; @@ -49,6 +50,7 @@ public ColorComboBox () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Color CustomColor { get => _customColor; diff --git a/src/LogExpert.UI/Controls/DateTimeDragControl.cs b/src/LogExpert.UI/Controls/DateTimeDragControl.cs index dc6ca00d..6b52da7e 100644 --- a/src/LogExpert.UI/Controls/DateTimeDragControl.cs +++ b/src/LogExpert.UI/Controls/DateTimeDragControl.cs @@ -77,16 +77,19 @@ public DateTimeDragControl () /// /// Gets or sets the minimum allowable date and time value. /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public DateTime MinDateTime { get; set; } = DateTime.MinValue; /// /// Gets or sets the maximum allowable date and time value. /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public DateTime MaxDateTime { get; set; } = DateTime.MaxValue; /// /// Gets or sets the orientation for drag operations. /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public DragOrientations DragOrientation { get => _dragOrientation; @@ -100,11 +103,13 @@ public DragOrientations DragOrientation /// /// Gets or sets the color used to highlight an element when the mouse hovers over it. /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Color HoverColor { get; set; } /// /// Gets or sets the date and time value, adjusted to exclude milliseconds. /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public DateTime DateTime { get => _dateTime.Subtract(TimeSpan.FromMilliseconds(_dateTime.Millisecond)); diff --git a/src/LogExpert.UI/Controls/KnobControl.cs b/src/LogExpert.UI/Controls/KnobControl.cs index c816e4ad..5701a9e4 100644 --- a/src/LogExpert.UI/Controls/KnobControl.cs +++ b/src/LogExpert.UI/Controls/KnobControl.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; namespace LogExpert.UI.Controls; @@ -36,10 +37,13 @@ public KnobControl () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int MinValue { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int MaxValue { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int Value { get => _value; @@ -53,6 +57,7 @@ public int Value public int Range => MaxValue - MinValue; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int DragSensitivity { get; set; } = 3; #endregion diff --git a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs index 417830cc..f87807f0 100644 --- a/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs +++ b/src/LogExpert.UI/Controls/LogWindow/LogWindow.cs @@ -319,6 +319,7 @@ public LogWindow (LogTabWindow.LogTabWindow parent, string fileName, bool isTemp #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Color BookmarkColor { get; set; } = Color.FromArgb(165, 200, 225); public ILogLineColumnizer CurrentColumnizer @@ -335,6 +336,7 @@ private set } [SupportedOSPlatform("windows")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool ShowBookmarkBubbles { get => _guiStateArgs.ShowBookmarkBubbles; @@ -351,6 +353,7 @@ public bool ShowBookmarkBubbles public string FileName { get; private set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string SessionFileName { get; set; } public bool IsMultiFile @@ -363,8 +366,10 @@ public bool IsMultiFile private readonly IConfigManager ConfigManager; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string TempTitleName { get; set; } = string.Empty; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] internal FilterPipe FilterPipe { get; set; } public string Title => IsTempFile @@ -373,12 +378,15 @@ public bool IsMultiFile public ColumnizerCallback ColumnizerCallbackObject { get; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool ForcePersistenceLoading { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string ForcedPersistenceFileName { get; set; } public Preferences Preferences => _parentLogTabWin.Preferences; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string GivenFileName { get; set; } public TimeSyncList TimeSyncList { get; private set; } diff --git a/src/LogExpert.UI/Controls/LogWindow/PatternWindow.cs b/src/LogExpert.UI/Controls/LogWindow/PatternWindow.cs index 5a5cfe3e..1347a645 100644 --- a/src/LogExpert.UI/Controls/LogWindow/PatternWindow.cs +++ b/src/LogExpert.UI/Controls/LogWindow/PatternWindow.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.ComponentModel; using System.Runtime.Versioning; using LogExpert.Core.Classes; @@ -57,24 +58,28 @@ public PatternWindow (LogWindow logWindow) #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int Fuzzy { set => fuzzyKnobControl.Value = value; get => fuzzyKnobControl.Value; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int MaxDiff { set => maxDiffKnobControl.Value = value; get => maxDiffKnobControl.Value; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int MaxMisses { set => maxMissesKnobControl.Value = value; get => maxMissesKnobControl.Value; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int Weight { set => weigthKnobControl.Value = value; diff --git a/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs b/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs index 2a13a311..3a8cd7f9 100644 --- a/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs +++ b/src/LogExpert.UI/Controls/LogWindow/TimeSpreadigControl.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Globalization; using System.Runtime.Versioning; @@ -58,8 +59,10 @@ public TimeSpreadingControl () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool ReverseAlpha { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] internal TimeSpreadCalculator TimeSpreadCalc { get => _timeSpreadCalc; diff --git a/src/LogExpert.UI/Dialogs/BookmarkCommentDlg.cs b/src/LogExpert.UI/Dialogs/BookmarkCommentDlg.cs index ae55621f..cecbdbf4 100644 --- a/src/LogExpert.UI/Dialogs/BookmarkCommentDlg.cs +++ b/src/LogExpert.UI/Dialogs/BookmarkCommentDlg.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; namespace LogExpert.Dialogs; @@ -31,6 +32,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string Comment { set => textBoxComment.Text = value; diff --git a/src/LogExpert.UI/Dialogs/BookmarkWindow.cs b/src/LogExpert.UI/Dialogs/BookmarkWindow.cs index 8124461f..d8e451ac 100644 --- a/src/LogExpert.UI/Dialogs/BookmarkWindow.cs +++ b/src/LogExpert.UI/Dialogs/BookmarkWindow.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; using LogExpert.Core.Config; @@ -64,11 +65,13 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool LineColumnVisible { set => bookmarkDataGridView.Columns[2].Visible = value; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool ShowBookmarkCommentColumn { get => checkBoxCommentColumn.Checked; diff --git a/src/LogExpert.UI/Dialogs/ChooseIconDlg.cs b/src/LogExpert.UI/Dialogs/ChooseIconDlg.cs index f8be593b..5b529089 100644 --- a/src/LogExpert.UI/Dialogs/ChooseIconDlg.cs +++ b/src/LogExpert.UI/Dialogs/ChooseIconDlg.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; using LogExpert.UI.Extensions; @@ -37,8 +38,10 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string FileName { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int IconIndex { get; set; } #endregion diff --git a/src/LogExpert.UI/Dialogs/Eminus/EminusConfigDlg.cs b/src/LogExpert.UI/Dialogs/Eminus/EminusConfigDlg.cs index ffb56c4d..35c22716 100644 --- a/src/LogExpert.UI/Dialogs/Eminus/EminusConfigDlg.cs +++ b/src/LogExpert.UI/Dialogs/Eminus/EminusConfigDlg.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Globalization; using System.Runtime.Versioning; @@ -43,6 +44,7 @@ private void LoadResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public EminusConfig Config { get; set; } #endregion diff --git a/src/LogExpert.UI/Dialogs/HighlightDialog.cs b/src/LogExpert.UI/Dialogs/HighlightDialog.cs index ce596646..1b418605 100644 --- a/src/LogExpert.UI/Dialogs/HighlightDialog.cs +++ b/src/LogExpert.UI/Dialogs/HighlightDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Globalization; using System.Runtime.Versioning; using System.Security; @@ -5,6 +6,7 @@ using LogExpert.Core.Classes.Highlight; using LogExpert.Core.Entities; +using LogExpert.Core.Helpers; using LogExpert.Core.Interface; using LogExpert.UI.Controls; using LogExpert.UI.Dialogs; @@ -96,6 +98,7 @@ private void ApplyResources () #region Properties / Indexers + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public List HighlightGroupList { get => _highlightGroupList; @@ -110,8 +113,10 @@ public List HighlightGroupList } } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public IList KeywordActionList { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string PreSelectedGroupName { get; set; } private bool IsDirty => btnApply.Image == _applyButtonImage; @@ -571,7 +576,11 @@ private void CheckRegex () throw new ArgumentException(Resources.HighlightDialog_RegexError); } - _ = Regex.IsMatch(string.Empty, textBoxSearchString.Text); + // Use RegexHelper for safer validation with timeout protection + if (!RegexHelper.IsValidPattern(textBoxSearchString.Text, out var error)) + { + throw new ArgumentException(error ?? Resources.HighlightDialog_RegexError); + } } } diff --git a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs index 24f2eb0f..bbf9db26 100644 --- a/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs +++ b/src/LogExpert.UI/Dialogs/LogTabWindow/LogTabWindow.cs @@ -211,6 +211,7 @@ public LogTabWindow (string[] fileNames, int instanceNumber, bool showInstanceNu #region Properties [SupportedOSPlatform("windows")] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public LogWindow.LogWindow CurrentLogWindow { get => _currentLogWindow; @@ -228,7 +229,9 @@ public LogWindow.LogWindow CurrentLogWindow // get { return ConfigManager.Settings; } //} + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public ILogExpertProxy LogExpertProxy { get; set; } + public IConfigManager ConfigManager { get; } #endregion diff --git a/src/LogExpert.UI/Dialogs/MultiFileMaskDialog.cs b/src/LogExpert.UI/Dialogs/MultiFileMaskDialog.cs index 13edef11..316c1567 100644 --- a/src/LogExpert.UI/Dialogs/MultiFileMaskDialog.cs +++ b/src/LogExpert.UI/Dialogs/MultiFileMaskDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; namespace LogExpert.UI.Dialogs; @@ -44,8 +45,10 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string FileNamePattern { get; set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int MaxDays { get; set; } #endregion diff --git a/src/LogExpert.UI/Dialogs/OpenUriDialog.cs b/src/LogExpert.UI/Dialogs/OpenUriDialog.cs index 0172d8ef..49230368 100644 --- a/src/LogExpert.UI/Dialogs/OpenUriDialog.cs +++ b/src/LogExpert.UI/Dialogs/OpenUriDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; namespace LogExpert.UI.Dialogs; @@ -32,6 +33,7 @@ public OpenUriDialog () //TODO Convert to System.Uri public string Uri => cmbUri.Text; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public IList UriHistory { get; set; } #endregion diff --git a/src/LogExpert.UI/Dialogs/ParamRequesterDialog.cs b/src/LogExpert.UI/Dialogs/ParamRequesterDialog.cs index a8ec5cc7..50df740a 100644 --- a/src/LogExpert.UI/Dialogs/ParamRequesterDialog.cs +++ b/src/LogExpert.UI/Dialogs/ParamRequesterDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; namespace LogExpert.Dialogs; @@ -47,6 +48,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string ParamValue { get; set; } #endregion diff --git a/src/LogExpert.UI/Dialogs/ProjectLoadDlg.cs b/src/LogExpert.UI/Dialogs/ProjectLoadDlg.cs index 1b77b0a6..304b2e3d 100644 --- a/src/LogExpert.UI/Dialogs/ProjectLoadDlg.cs +++ b/src/LogExpert.UI/Dialogs/ProjectLoadDlg.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; using LogExpert.Core.Enums; @@ -41,6 +42,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public ProjectLoadDlgResult ProjectLoadResult { get; set; } = ProjectLoadDlgResult.Cancel; #endregion diff --git a/src/LogExpert.UI/Dialogs/RegexHelperDialog.cs b/src/LogExpert.UI/Dialogs/RegexHelperDialog.cs index 9d17ba78..9770072b 100644 --- a/src/LogExpert.UI/Dialogs/RegexHelperDialog.cs +++ b/src/LogExpert.UI/Dialogs/RegexHelperDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; using System.Text.RegularExpressions; @@ -47,6 +48,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool CaseSensitive { get => _caseSensitive; @@ -57,14 +59,17 @@ public bool CaseSensitive } } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string Pattern { get => comboBoxRegex.Text; set => comboBoxRegex.Text = value; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public List ExpressionHistoryList { get; set; } = []; + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public List TesttextHistoryList { get; set; } = []; #endregion diff --git a/src/LogExpert.UI/Dialogs/SearchDialog.cs b/src/LogExpert.UI/Dialogs/SearchDialog.cs index 62f6ba13..71e64638 100644 --- a/src/LogExpert.UI/Dialogs/SearchDialog.cs +++ b/src/LogExpert.UI/Dialogs/SearchDialog.cs @@ -1,7 +1,9 @@ +using System.ComponentModel; using System.Globalization; using System.Runtime.Versioning; using System.Text.RegularExpressions; +using LogExpert.Core.Helpers; using LogExpert.Entities; using LogExpert.UI.Dialogs; @@ -56,6 +58,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public SearchParams SearchParams { get; set; } = new(); #endregion @@ -131,7 +134,11 @@ private void OnButtonOkClick (object sender, EventArgs e) throw new ArgumentException(Resources.SearchDialog_UI_Error_SearchTextEmpty); } - _ = Regex.IsMatch("", comboBoxSearchFor.Text); + // Use RegexHelper for safer validation with timeout protection + if (!RegexHelper.IsValidPattern(comboBoxSearchFor.Text, out var error)) + { + throw new ArgumentException($"Invalid regex pattern: {error}"); + } } SearchParams.SearchText = comboBoxSearchFor.Text; diff --git a/src/LogExpert.UI/Dialogs/TabRenameDialog.cs b/src/LogExpert.UI/Dialogs/TabRenameDialog.cs index a974f149..8dd1a382 100644 --- a/src/LogExpert.UI/Dialogs/TabRenameDialog.cs +++ b/src/LogExpert.UI/Dialogs/TabRenameDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; namespace LogExpert.UI.Dialogs; @@ -35,6 +36,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string TabName { get => textBoxTabName.Text; diff --git a/src/LogExpert.UI/Dialogs/ToolArgsDialog.cs b/src/LogExpert.UI/Dialogs/ToolArgsDialog.cs index 2d3148b6..c1eefe87 100644 --- a/src/LogExpert.UI/Dialogs/ToolArgsDialog.cs +++ b/src/LogExpert.UI/Dialogs/ToolArgsDialog.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Runtime.Versioning; using LogExpert.UI.Controls.LogTabWindow; @@ -49,6 +50,7 @@ private void ApplyResources () #region Properties + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public string Arg { get; set; } #endregion diff --git a/src/LogExpert.UI/LogExpert.UI.csproj b/src/LogExpert.UI/LogExpert.UI.csproj index 4d401ccd..d3b2a4d1 100644 --- a/src/LogExpert.UI/LogExpert.UI.csproj +++ b/src/LogExpert.UI/LogExpert.UI.csproj @@ -4,7 +4,7 @@ true true true - net8.0-windows + net10.0-windows true diff --git a/src/LogExpert/LogExpert.csproj b/src/LogExpert/LogExpert.csproj index 20ea2108..f63f4f8d 100644 --- a/src/LogExpert/LogExpert.csproj +++ b/src/LogExpert/LogExpert.csproj @@ -9,7 +9,7 @@ Auto $(SolutionDir)..\bin\$(Configuration) WinExe - net8.0-windows + net10.0-windows False diff --git a/src/LogExpert/Program.cs b/src/LogExpert/Program.cs index 8ce3a1a4..7db33f95 100644 --- a/src/LogExpert/Program.cs +++ b/src/LogExpert/Program.cs @@ -44,6 +44,9 @@ internal static class Program [SupportedOSPlatform("windows")] private static void Main (string[] args) { + // Set global regex timeout to prevent DoS attacks from catastrophic backtracking + AppDomain.CurrentDomain.SetData("REGEX_DEFAULT_MATCH_TIMEOUT", TimeSpan.FromSeconds(2)); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Application.ThreadException += Application_ThreadException; @@ -149,7 +152,12 @@ or ArgumentException _logger.Error($"IpcClientChannel error: {ex}"); errMsg = ex; counter--; - Thread.Sleep(500); + + // Use Task.Delay instead of Thread.Sleep for non-blocking wait + if (counter > 0) + { + Task.Delay(500).Wait(); + } } } diff --git a/src/PluginRegistry/LogExpert.PluginRegistry.csproj b/src/PluginRegistry/LogExpert.PluginRegistry.csproj index cf09bc7b..7ffeb844 100644 --- a/src/PluginRegistry/LogExpert.PluginRegistry.csproj +++ b/src/PluginRegistry/LogExpert.PluginRegistry.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 diff --git a/src/RegexColumnizer.UnitTests/RegexColumnizer.UnitTests.csproj b/src/RegexColumnizer.UnitTests/RegexColumnizer.UnitTests.csproj index be3904ad..5ff20bb2 100644 --- a/src/RegexColumnizer.UnitTests/RegexColumnizer.UnitTests.csproj +++ b/src/RegexColumnizer.UnitTests/RegexColumnizer.UnitTests.csproj @@ -1,6 +1,6 @@  - net8.0-windows + net10.0-windows true diff --git a/src/RegexColumnizer/RegexColumnizer.cs b/src/RegexColumnizer/RegexColumnizer.cs index bc66b146..0febb7e5 100644 --- a/src/RegexColumnizer/RegexColumnizer.cs +++ b/src/RegexColumnizer/RegexColumnizer.cs @@ -1,4 +1,5 @@ -using LogExpert; +using LogExpert; +using LogExpert.Core.Helpers; using System; using System.IO; using System.Linq; @@ -188,7 +189,7 @@ public void Init(RegexColumnizerConfig config) try { - Regex = new Regex(Config.Expression, RegexOptions.Compiled); + Regex = RegexHelper.GetOrCreateCached(Config.Expression, RegexOptions.Compiled); var skip = Regex.GetGroupNames().Length == 1 ? 0 : 1; columns = Regex.GetGroupNames().Skip(skip).ToArray(); } diff --git a/src/RegexColumnizer/RegexColumnizer.csproj b/src/RegexColumnizer/RegexColumnizer.csproj index ecd68455..b3244bd0 100644 --- a/src/RegexColumnizer/RegexColumnizer.csproj +++ b/src/RegexColumnizer/RegexColumnizer.csproj @@ -1,6 +1,6 @@  - net8.0-windows + net10.0-windows true true @@ -10,6 +10,7 @@ + diff --git a/src/RegexColumnizer/RegexColumnizer.manifest.json b/src/RegexColumnizer/RegexColumnizer.manifest.json new file mode 100644 index 00000000..8c21171a --- /dev/null +++ b/src/RegexColumnizer/RegexColumnizer.manifest.json @@ -0,0 +1,20 @@ +{ + "name": "RegexColumnizer", + "version": "1.0.0", + "author": "LogExpert Team", + "description": "Highly configurable columnizer using regular expressions to parse log lines into columns", + "apiVersion": "1.0", + "requires": { + "logExpert": ">=1.10.0", + "dotnet": ">=8.0" + }, + "permissions": [ + "filesystem:read", + "config:read", + "config:write" + ], + "dependencies": {}, + "main": "RegexColumnizer.dll", + "url": "https://github.com/LogExperts/LogExpert", + "license": "MIT" +} diff --git a/src/RegexColumnizer/RegexColumnizerConfigDialog.cs b/src/RegexColumnizer/RegexColumnizerConfigDialog.cs index e9cee9ea..58519135 100644 --- a/src/RegexColumnizer/RegexColumnizerConfigDialog.cs +++ b/src/RegexColumnizer/RegexColumnizerConfigDialog.cs @@ -1,3 +1,12 @@ +using System; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +using LogExpert.Core.Helpers; using System.Data; using System.Text.RegularExpressions; @@ -30,6 +39,7 @@ private void ApplyResources () btnCancel.Text = Resources.RegexColumnizerConfigDialog_UI_Button_Cancel; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public RegexColumnizerConfig Config { get; set; } private void OnBtnOkClick (object sender, EventArgs e) @@ -59,7 +69,8 @@ private bool Check () try { - Regex regex = new(tbExpression.Text); + // Use RegexHelper for safe regex creation with timeout protection + Regex regex = RegexHelper.CreateSafeRegex(tbExpression.Text); var groupNames = regex.GetGroupNames(); var offset = groupNames.Length > 1 ? 1 : 0; diff --git a/src/SftpFileSystemx64/LoginDialog.cs b/src/SftpFileSystemx64/LoginDialog.cs index ec4fbc8a..dd51cd44 100644 --- a/src/SftpFileSystemx64/LoginDialog.cs +++ b/src/SftpFileSystemx64/LoginDialog.cs @@ -1,3 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using System.ComponentModel; + namespace SftpFileSystem; public partial class LoginDialog : Form @@ -59,6 +65,7 @@ private void ApplyResources () public string Password { get; private set; } + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string Username { get => _username; diff --git a/src/SftpFileSystemx64/SftpFileSystemx64.csproj b/src/SftpFileSystemx64/SftpFileSystemx64.csproj index dd0197fb..cb1aaa9f 100644 --- a/src/SftpFileSystemx64/SftpFileSystemx64.csproj +++ b/src/SftpFileSystemx64/SftpFileSystemx64.csproj @@ -1,6 +1,6 @@  - net8.0-windows + net10.0-windows true SftpFileSystem diff --git a/src/SftpFileSystemx86/SftpFileSystemx86.csproj b/src/SftpFileSystemx86/SftpFileSystemx86.csproj index 7f60bbd8..f3f5dfe9 100644 --- a/src/SftpFileSystemx86/SftpFileSystemx86.csproj +++ b/src/SftpFileSystemx86/SftpFileSystemx86.csproj @@ -1,6 +1,6 @@  - net8.0-windows + net10.0-windows true SftpFileSystem