-
-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature pathmask #27
base: master
Are you sure you want to change the base?
Feature pathmask #27
Changes from 7 commits
b798c30
9fc309f
7ec4223
50c80db
144b637
9c9b506
d4c2ac8
2296354
968e9b9
163a215
245da54
9326948
1f9bf0b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
using System; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
using Serilog.Core; | ||
|
||
|
@@ -13,7 +14,8 @@ static async Task Main(string[] args) | |
{ | ||
new EmailAddressMaskingOperator(), | ||
new IbanMaskingOperator(), | ||
new CreditCardMaskingOperator(false) | ||
new CreditCardMaskingOperator(false), | ||
new PathMaskingOperator() | ||
}) | ||
.WriteTo.Console() | ||
.CreateLogger(); | ||
|
@@ -43,16 +45,24 @@ static async Task Main(string[] args) | |
Key = 12345, XmlValue = "<MyElement><CreditCard>4111111111111111</CreditCard></MyElement>" | ||
}; | ||
logger.Information("Object dump with embedded credit card: {x}", x); | ||
|
||
// Path to the file is also masked | ||
logger.Information("This is path to the file: {0}", | ||
@"E:\SuperSecretPath\test.txt"); | ||
|
||
// Path to the directory is also masked | ||
logger.Information("This is path to the directory: {0}", @"C:\Admin\"); | ||
|
||
} | ||
|
||
// But outside the sensitive area nothing is masked | ||
logger.Information("Felix can be reached at [email protected]"); | ||
|
||
logger.Information("This is your path to the file: {file}", new FileInfo("test.txt").FullName); | ||
|
||
// Now, show that this works for async contexts too | ||
logger.Information("Now, show the Async works"); | ||
|
||
var t1 = LogAsSensitiveAsync(logger); | ||
var t2 = LogAsUnsensitiveAsync(logger); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Serilog.Enrichers.Sensitive; | ||
|
||
public interface IPathWrapper | ||
{ | ||
bool IsDirectory(string path); | ||
string GetFileName(string path); | ||
string GetDirectoryName(string path); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace Serilog.Enrichers.Sensitive; | ||
|
||
/// <summary> | ||
/// Represents a masking operator for path names. | ||
/// <remarks>Supports path names for Windows, Linux, and macOS.</remarks> | ||
/// </summary> | ||
public class PathMaskingOperator : RegexMaskingOperator | ||
{ | ||
private readonly IPathWrapper _pathWrapper; | ||
private readonly bool _combineMaskWithPath; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It took me a while to figure out exactly what this meant. Perhaps changing it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed to the |
||
private const string PathPattern = | ||
@"^(?:[a-zA-Z]\:|\\\\[\w-]+\\[\w-]+\$?|[\/][^\/\0]+)+(\\[^\\/:*?""<>|]*)*(\\?)?$"; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PathMaskingOperator"/> class. | ||
/// </summary> | ||
/// <param name="pathWrapper">The path wrapper.</param> | ||
/// <param name="combineMaskWithPath">This means if set to <see langword="true"/> then the mask will combine with the file name or its directory name.</param> | ||
public PathMaskingOperator(IPathWrapper pathWrapper, bool combineMaskWithPath = true) : base(PathPattern) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now path wrapper removed |
||
{ | ||
_pathWrapper = pathWrapper; | ||
_combineMaskWithPath = combineMaskWithPath; | ||
} | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PathMaskingOperator"/> class, with default <see cref="PathWrapper"/>. | ||
/// </summary> | ||
/// <param name="combineMaskWithPath">This means if set to <see langword="true"/> then the mask will combine with the file name or its directory name.</param> | ||
public PathMaskingOperator(bool combineMaskWithPath = true) : this(new PathWrapper(), combineMaskWithPath) | ||
{ | ||
} | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PathMaskingOperator"/> class. | ||
/// </summary> | ||
public PathMaskingOperator() : this(combineMaskWithPath: true) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constructor isn't necessary as the one you are calling has a default value for the parameter. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Empty ctor removed |
||
{ | ||
} | ||
[SuppressMessage("ReSharper", "InvertIf")] | ||
protected override string PreprocessMask(string mask, Match match) | ||
{ | ||
if (_combineMaskWithPath) | ||
{ | ||
var value = match.Value; | ||
return _pathWrapper.IsDirectory(value) | ||
? mask + _pathWrapper.GetDirectoryName(value) | ||
: mask + _pathWrapper.GetFileName(value); | ||
} | ||
return mask; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.IO; | ||
|
||
namespace Serilog.Enrichers.Sensitive; | ||
|
||
public class PathWrapper : IPathWrapper | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would strongly recommend to remove this abstraction, it's not adding any value right now as there is no other implementation of So I'd prefer that where you're calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only reason I made such abstraction, cuz I thought if there's a specific when some of the OS unable to get the path properly, then developer might make it own implementation. In case if this feature with abstraction would be removed and If I were such developer, I'd just delete the package and go cry. Let me know if this is still should be removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the other hand, Path.GetDIrectoryName works weird, sometimes It's unable to get the directory name correct There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand where you're coming from, however you may expect from the runtime to handle this for you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now path wrapper removed |
||
{ | ||
public bool IsDirectory(string path) | ||
{ | ||
return Path.GetExtension(path) == string.Empty; | ||
} | ||
public string GetFileName(string path) | ||
{ | ||
return Path.GetFileName(path); | ||
} | ||
public string GetDirectoryName(string path) | ||
{ | ||
return new DirectoryInfo(path).Name; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System.Text.RegularExpressions; | ||
using BenchmarkDotNet.Attributes; | ||
using BenchmarkDotNet.Engines; | ||
|
||
namespace Serilog.Enrichers.Sensitive.Tests.Benchmark; | ||
|
||
[SimpleJob(RunStrategy.Throughput, warmupCount: 1)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The existing benchmark for regexes already proves a compiled regex is faster so adding another benchmark to prove it again isn't necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Class removed |
||
public class PathMaskingOperatorBenchmarks | ||
{ | ||
private const string PathInput = "/home/me"; | ||
private const string MaskValue = "***MASKED***"; | ||
|
||
private readonly Regex PathRegex = | ||
new(@"^(?:[a-zA-Z]\:|\\\\[\w-]+\\[\w-]+\$?|[\/][^\/\0]+)+(\\[^\\/:*?""<>|]*)*(\\?)?$"); | ||
|
||
private readonly Regex PathCompiledRegex = | ||
new(@"^(?:[a-zA-Z]\:|\\\\[\w-]+\\[\w-]+\$?|[\/][^\/\0]+)+(\\[^\\/:*?""<>|]*)*(\\?)?$", | ||
RegexOptions.Compiled); | ||
|
||
[Benchmark] | ||
public string PathRegexReplace() | ||
{ | ||
string result = null; | ||
for (var i = 0; i < 10000; i++) | ||
result = PathRegex.Replace(PathInput, MaskValue); | ||
return result; | ||
} | ||
|
||
[Benchmark] | ||
public string PathRegexCompiledReplace() | ||
{ | ||
string result = null; | ||
for (var i = 0; i < 10000; i++) | ||
result = PathCompiledRegex.Replace(PathInput, MaskValue); | ||
return result; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ private static void Main(string[] args) | |
BenchmarkRunner.Run<BenchmarkCompiledEmailRegex>(); | ||
BenchmarkRunner.Run<BenchmarkCompiledIbanRegex>(); | ||
BenchmarkRunner.Run<CreditCardMarkingBenchmarks>(); | ||
BenchmarkRunner.Run<PathMaskingOperatorBenchmarks>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be removed too There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed also |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using FluentAssertions; | ||
using Xunit; | ||
|
||
namespace Serilog.Enrichers.Sensitive.Tests.Unit; | ||
|
||
public class WhenMaskingPaths | ||
{ | ||
private const string Mask = @"***\"; | ||
|
||
[Theory] | ||
[InlineData(@"C:\Users\Admin\Secret\File.dll", @"***\", false)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would expect this to be only the mask in the expected output. Right now it looks like you're keeping the directory separator which seems odd. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't really understand what do you mean |
||
[InlineData(@"C:\Users\Admin\Secret\File.dll", @"***\File.dll", true)] | ||
[InlineData(@"C:\Users\Admin\Secret\Hidden\File.dll", @"***\File.dll", true)] | ||
[InlineData(@"C:\Users\Admin\Secret\Hidden", @"***\", false)] | ||
[InlineData(@"C:\Users\Admin\Secret\Hidden", @"***\Hidden", true)] | ||
[InlineData(@"C:\Users\Admin\Secret", @"***\Secret", true)] | ||
[InlineData(@"C:\Users\", @"***\Users", true)] | ||
[InlineData(@"/home/i_use_arch_linux_btw", @"***\i_use_arch_linux_btw", true)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This made me laugh 😄 |
||
[InlineData(@"/home/i_use_arch_linux_btw", @"***\", false)] | ||
[InlineData(@"C:\", @"***\C:\", true)] | ||
[InlineData(@"C:\", @"***\", false)] | ||
[InlineData("File.txt", "File.txt", false)] | ||
[InlineData(@"This is not a path", "This is not a path", false)] | ||
public void GivenPaths_ReturnsExpectedResult(string path, string result, bool combineMaskWithPath) | ||
{ | ||
TheMaskedResultOf(path, combineMaskWithPath) | ||
.Should() | ||
.Be(result); | ||
} | ||
|
||
private static string TheMaskedResultOf(string input, bool combineMaskWithPath) | ||
{ | ||
var maskingResult = new PathMaskingOperator(combineMaskWithPath) | ||
.Mask(input, Mask); | ||
return maskingResult.Match | ||
? maskingResult.Result | ||
: input; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the default operators when I built this library was a bit of a mistake.
Could you remove it from the docs here? (I see you didn't actually add it to the list of default operators)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added to the default list of operators