< Summary

Information
Class: Chronicis.Api.Utilities.LogSanitizer
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Utilities/LogSanitizer.cs
Line coverage
100%
Covered lines: 17
Uncovered lines: 0
Coverable lines: 17
Total lines: 91
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Sanitize(...)100%88100%
SanitizeObject(...)100%22100%
SanitizeMultiple(...)100%11100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Api/Utilities/LogSanitizer.cs

#LineLine coverage
 1using System.Text.RegularExpressions;
 2
 3namespace Chronicis.Api.Utilities;
 4
 5/// <summary>
 6/// Provides aggressive sanitization of user input before logging to prevent log injection attacks.
 7/// </summary>
 8public static partial class LogSanitizer
 9{
 10    private const int MaxLogLength = 1000;
 11    private const string TruncationMarker = "...[TRUNCATED]";
 12    private const string SanitizedMarker = "[SANITIZED]";
 13
 14    /// <summary>
 15    /// Sanitizes a string value for safe logging by removing control characters and truncating length.
 16    /// </summary>
 17    /// <param name="value">The value to sanitize. Can be null.</param>
 18    /// <returns>A sanitized version of the input safe for logging.</returns>
 19    public static string? Sanitize(string? value)
 20    {
 1521        if (string.IsNullOrEmpty(value))
 22        {
 323            return value;
 24        }
 25
 26        // First pass: Remove control characters
 1227        var sanitized = ControlCharRegex().Replace(value, "");
 28
 29        // Second pass: Remove URL-encoded dangerous characters
 1230        sanitized = DangerousRegex().Replace(sanitized, "");
 31
 32        // Remove any remaining whitespace sequences longer than 1 space
 1233        sanitized = MultiSpaceRegex().Replace(sanitized, " ");
 34
 35        // Trim the result
 1236        sanitized = sanitized.Trim();
 37
 38        // Check if we sanitized anything
 1239        var wasSanitized = sanitized != value;
 40
 41        // Truncate if too long
 1242        if (sanitized.Length > MaxLogLength)
 43        {
 144            sanitized = sanitized[..MaxLogLength] + TruncationMarker;
 145            wasSanitized = true;
 46        }
 47
 48        // Add marker if content was modified
 1249        if (wasSanitized && !string.IsNullOrWhiteSpace(sanitized))
 50        {
 851            sanitized = $"{sanitized} {SanitizedMarker}";
 52        }
 53
 1254        return sanitized;
 55    }
 56
 57    /// <summary>
 58    /// Sanitizes an object by converting it to string and then sanitizing.
 59    /// Handles null values gracefully.
 60    /// </summary>
 61    /// <param name="value">The object to sanitize. Can be null.</param>
 62    /// <returns>A sanitized string representation safe for logging.</returns>
 63    public static string? SanitizeObject(object? value)
 64    {
 365        if (value == null)
 66        {
 167            return null;
 68        }
 69
 270        return Sanitize(value.ToString());
 71    }
 72
 73    /// <summary>
 74    /// Sanitizes multiple values for logging.
 75    /// </summary>
 76    /// <param name="values">Array of values to sanitize.</param>
 77    /// <returns>Array of sanitized values in the same order.</returns>
 78    public static string?[] SanitizeMultiple(params string?[] values)
 79    {
 280        return values.Select(Sanitize).ToArray();
 81    }
 82
 83    [GeneratedRegex(@"[\x00-\x1F\x7F-\x9F]")]
 84    private static partial Regex ControlCharRegex();
 85
 86    [GeneratedRegex(@"(\r\n|\r|\n|\t|%0[aAdD]|%0[aA]|%0[dD])")]
 87    private static partial Regex DangerousRegex();
 88
 89    [GeneratedRegex(@"\s{2,}")]
 90    private static partial Regex MultiSpaceRegex();
 91}