< Summary

Line coverage
89%
Covered lines: 51
Uncovered lines: 6
Coverable lines: 57
Total lines: 547
Line coverage: 89.4%
Branch coverage
80%
Covered branches: 16
Total branches: 20
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/obj/Release/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs

File '/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/obj/Release/net8.0/System.Text.RegularExpressions.Generator/System.Text.RegularExpressions.Generator.RegexGenerator/RegexGenerator.g.cs' does not exist (any more).

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Observability/SensitiveDataRedactor.cs

#LineLine coverage
 1using System.Text.Json;
 2using System.Text.RegularExpressions;
 3
 4namespace OzonOrdersWeb.Observability;
 5
 6public sealed partial class SensitiveDataRedactor
 7{
 8    private const string Redacted = "[REDACTED]";
 19    private static readonly string[] SensitiveNames =
 110    [
 111        "password", "passwd", "pass", "pwd", "token", "access_token", "refresh_token",
 112        "authorization", "cookie", "secret", "clientsecret", "client_secret",
 113        "apikey", "api_key", "privatekey", "private_key", "connectionstring"
 114    ];
 15
 16    public string Redact(string? value, int maxCharacters)
 17    {
 43818        if (string.IsNullOrWhiteSpace(value))
 19        {
 20120            return string.Empty;
 21        }
 22
 23723        var redacted = TryRedactJson(value) ?? RedactText(value);
 23724        return redacted.Length <= maxCharacters
 23725            ? redacted
 23726            : string.Concat(redacted.AsSpan(0, maxCharacters), "…[TRUNCATED]");
 27    }
 28
 29    public string RedactUri(Uri? uri, int maxCharacters)
 30    {
 14231        if (uri is null)
 32        {
 033            return string.Empty;
 34        }
 35
 14236        return Redact(uri.ToString(), maxCharacters);
 37    }
 38
 39    private static string? TryRedactJson(string value)
 40    {
 41        try
 42        {
 23743            using var document = JsonDocument.Parse(value);
 144            using var stream = new MemoryStream();
 145            using var writer = new Utf8JsonWriter(stream);
 146            WriteElement(writer, document.RootElement, null);
 147            writer.Flush();
 148            return System.Text.Encoding.UTF8.GetString(stream.ToArray());
 49        }
 23650        catch (JsonException)
 51        {
 23652            return null;
 53        }
 23754    }
 55
 56    private static void WriteElement(Utf8JsonWriter writer, JsonElement element, string? propertyName)
 57    {
 558        if (propertyName is not null && IsSensitive(propertyName))
 59        {
 260            writer.WriteStringValue(Redacted);
 261            return;
 62        }
 63
 364        switch (element.ValueKind)
 65        {
 66            case JsonValueKind.Object:
 267                writer.WriteStartObject();
 1268                foreach (var property in element.EnumerateObject())
 69                {
 470                    writer.WritePropertyName(property.Name);
 471                    WriteElement(writer, property.Value, property.Name);
 72                }
 273                writer.WriteEndObject();
 274                break;
 75            case JsonValueKind.Array:
 076                writer.WriteStartArray();
 077                foreach (var item in element.EnumerateArray())
 78                {
 079                    WriteElement(writer, item, null);
 80                }
 081                writer.WriteEndArray();
 082                break;
 83            default:
 184                element.WriteTo(writer);
 85                break;
 86        }
 187    }
 88
 89    private static string RedactText(string value)
 90    {
 23691        var result = AuthorizationRegex().Replace(value, "$1[REDACTED]");
 23692        result = EmbeddedJsonSecretRegex().Replace(result, "$1\"[REDACTED]\"");
 23693        result = XmlSecretRegex().Replace(result, "$1[REDACTED]$2");
 24594        result = SecretPairRegex().Replace(result, match => $"{match.Groups[1].Value}{Redacted}");
 23695        result = ConnectionPasswordRegex().Replace(result, "$1[REDACTED]");
 23696        result = TokenLiteralRegex().Replace(result, Redacted);
 23697        result = PrivateKeyRegex().Replace(result, "[REDACTED PRIVATE KEY]");
 23698        return result;
 99    }
 100
 101    private static bool IsSensitive(string name) =>
 44102        SensitiveNames.Any(sensitive => name.Contains(sensitive, StringComparison.OrdinalIgnoreCase));
 103
 104    [GeneratedRegex("(?i)((?:password|passwd|pass|pwd|token|secret|api[_-]?key|client[_-]?secret|authorization|cookie|pr
 105    private static partial Regex SecretPairRegex();
 106
 107    [GeneratedRegex("(?i)(Authorization\\s*:\\s*)(?:Bearer|Basic)\\s+[^\\s,;]+")]
 108    private static partial Regex AuthorizationRegex();
 109
 110    [GeneratedRegex("(?i)(Password\\s*=\\s*)[^;]+")]
 111    private static partial Regex ConnectionPasswordRegex();
 112
 113    [GeneratedRegex("(?i)(\"(?:password|passwd|pass|pwd|token|secret|api[_-]?key|client[_-]?secret|authorization|cookie|
 114    private static partial Regex EmbeddedJsonSecretRegex();
 115
 116    [GeneratedRegex("(<(?:password|passwd|pass|pwd|token|secret|api[_-]?key)[^>]*>).*?(</[^>]+>)", RegexOptions.IgnoreCa
 117    private static partial Regex XmlSecretRegex();
 118
 119    [GeneratedRegex("\\b(?:github_pat_|gh[pousr]_)[A-Za-z0-9_]{20,}\\b")]
 120    private static partial Regex TokenLiteralRegex();
 121
 122    [GeneratedRegex("-----BEGIN [A-Z ]*PRIVATE KEY-----.*?-----END [A-Z ]*PRIVATE KEY-----", RegexOptions.Singleline)]
 123    private static partial Regex PrivateKeyRegex();
 124}