using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace MS.Microservice.Core.Security.SensitiveData;
public static class SensitiveJson
{
/// Wraps the existing System.Text.Json resolver with write-only sensitive-property handling.
public static void UseSensitiveValues(this JsonSerializerOptions options)
{
ArgumentNullException.ThrowIfNull(options);
options.TypeInfoResolver = (options.TypeInfoResolver ?? new DefaultJsonTypeInfoResolver()).WithAddedModifier(Apply);
}
private static void Apply(JsonTypeInfo type)
{
if (type.Kind != JsonTypeInfoKind.Object) return;
foreach (var member in type.Type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var classification = SensitiveValues.ClassificationOf(member);
if (classification is null) continue;
var name = member.GetCustomAttribute()?.Name
?? type.Options.PropertyNamingPolicy?.ConvertName(member.Name) ?? member.Name;
var property = type.Properties.FirstOrDefault(candidate => candidate.Name == name);
if (property?.Get is not { } get) continue;
if (classification == SensitiveKind.Secret)
{ property.Get = static _ => null; property.ShouldSerialize = static (_, _) => false; }
else
{
if (property.PropertyType != typeof(string)) throw new InvalidOperationException("Phone and email classifications require string properties.");
property.Get = instance => SensitiveValues.Protect((string?)get(instance), classification.Value);
}
}
}
}