Skip to content
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

[API Proposal]: System.Text.Json modify property value in runtime #57997

Closed
thangnn91 opened this issue Aug 24, 2021 · 3 comments
Closed

[API Proposal]: System.Text.Json modify property value in runtime #57997

thangnn91 opened this issue Aug 24, 2021 · 3 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Text.Json untriaged New issue has not been triaged by the area owner

Comments

@thangnn91
Copy link

Background and motivation

I'm using Audit.Net library for my project.
Default, in their newest version, they use System.Text.Json to Mongo log
I looking up many sources, but I can't resolve my problem
I want to dynamically replace property value while Serialize object (both clear type or anonymous type) because of security issue
Eg:

public class LoginModel
{
    public string User { get; set; }
     public string Password { get; set; }
}`

var serializerOptions = new JsonSerializerOptions
{
     Converters = { //custom serialize object here}
};
var loginModel = new LoginModel {
   User ="test",
   Password = "test"
};

string  loginJson = JsonSerializer.Serialize(loginModel, serializerOptions);

My expexted result is: {"User":"test","Password":"**********"}

With Audit.Net previous version, I easily do it in Newtonsoft.Json by using a ContractResolver
Here is my custom ContractResolver class:

public class DynamicContractResolver : DefaultContractResolver
    {
        private readonly string[] props;

        public DynamicContractResolver(params string[] prop)
        {
            this.props = prop;
        }

        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            PropertyInfo propertyInfo = member as PropertyInfo;

            if (propertyInfo == null)
            {
                return property;
            }
            if (property.PropertyType.IsArray || property.PropertyType.Namespace == "Google.Protobuf.Collections")
                property.Ignored = true;
            else if (propertyInfo.CanWrite && this.props.Contains(property.PropertyName))
            {
                property.ValueProvider = new ReplaveValueProvider(propertyInfo, this.props);
            }
            return property;
        }

    }
    public class ReplaveValueProvider : IValueProvider
    {
        readonly PropertyInfo _MemberInfo;
        readonly string[] _prop_rep;
        public ReplaveValueProvider(PropertyInfo memberInfo, string[] prop_rep)
        {
            _MemberInfo = memberInfo;
            _prop_rep = prop_rep;
        }
        public object GetValue(object target)
        {
            object result = _MemberInfo.GetValue(target);
            if (result != null && _MemberInfo.PropertyType == typeof(string))
            {
                var valueText = result.ToString();
                if (!string.IsNullOrEmpty(valueText) && valueText.Contains("{") && valueText.Contains("}"))
                {
                    JObject jObj;
                    if (Helper.TryParseJSON(result.ToString(), out jObj))
                    {
                        foreach (var p in _prop_rep)
                        {
                            if (jObj.ContainsKey(p))
                                jObj[p] = "*********";
                        }
                        result = jObj.ToString(Formatting.None);
                        return result;
                    }
                }
                result = "*********";
            }
            else if (_MemberInfo.PropertyType == typeof(int) || _MemberInfo.PropertyType == typeof(long)) result = 0;
            return result;

        }

        public void SetValue(object target, object value)
        {
            _MemberInfo.SetValue(target, value);
        }
    }

Add custom contract to JsonSerializerSettings

var jsonSerializerSettings = new JsonSerializerSettings()
                {
                    Converters = new List<JsonConverter>() { new JavaScriptDateTimeConverter() },
                    DateFormatString = "dd/MM/yyyy HH:mm:ss.fff",
                    ContractResolver = new DynamicContractResolver(sensitiveDataJson.ToArray())
                }));

Hope for your suggestions!

API Proposal

System.Text.Json.JsonSerializerOptions

API Usage

System.Text.Json.JsonSerializer.Serialize(object, serializerOptions);

Risks

No response

@thangnn91 thangnn91 added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Aug 24, 2021
@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels Aug 24, 2021
@ghost
Copy link

ghost commented Aug 24, 2021

Tagging subscribers to this area: @eiriktsarpalis, @layomia
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

I'm using Audit.Net library for my project.
Default, in their newest version, they use System.Text.Json to Mongo log
I looking up many sources, but I can't resolve my problem
I want to dynamically replace property value while Serialize object (both clear type or anonymous type) because of security issue
Eg:

public class LoginModel
{
    public string User { get; set; }
     public string Password { get; set; }
}`

var serializerOptions = new JsonSerializerOptions
{
     Converters = { //custom serialize object here}
};
var loginModel = new LoginModel {
   User ="test",
   Password = "test"
};

string  loginJson = JsonSerializer.Serialize(loginModel, serializerOptions);

My expexted result is: {"User":"test","Password":"**********"}

With Audit.Net previous version, I easily do it in Newtonsoft.Json by using a ContractResolver
Here is my custom ContractResolver class:

public class DynamicContractResolver : DefaultContractResolver
    {
        private readonly string[] props;

        public DynamicContractResolver(params string[] prop)
        {
            this.props = prop;
        }

        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            PropertyInfo propertyInfo = member as PropertyInfo;

            if (propertyInfo == null)
            {
                return property;
            }
            if (property.PropertyType.IsArray || property.PropertyType.Namespace == "Google.Protobuf.Collections")
                property.Ignored = true;
            else if (propertyInfo.CanWrite && this.props.Contains(property.PropertyName))
            {
                property.ValueProvider = new ReplaveValueProvider(propertyInfo, this.props);
            }
            return property;
        }

    }
    public class ReplaveValueProvider : IValueProvider
    {
        readonly PropertyInfo _MemberInfo;
        readonly string[] _prop_rep;
        public ReplaveValueProvider(PropertyInfo memberInfo, string[] prop_rep)
        {
            _MemberInfo = memberInfo;
            _prop_rep = prop_rep;
        }
        public object GetValue(object target)
        {
            object result = _MemberInfo.GetValue(target);
            if (result != null && _MemberInfo.PropertyType == typeof(string))
            {
                var valueText = result.ToString();
                if (!string.IsNullOrEmpty(valueText) && valueText.Contains("{") && valueText.Contains("}"))
                {
                    JObject jObj;
                    if (Helper.TryParseJSON(result.ToString(), out jObj))
                    {
                        foreach (var p in _prop_rep)
                        {
                            if (jObj.ContainsKey(p))
                                jObj[p] = "*********";
                        }
                        result = jObj.ToString(Formatting.None);
                        return result;
                    }
                }
                result = "*********";
            }
            else if (_MemberInfo.PropertyType == typeof(int) || _MemberInfo.PropertyType == typeof(long)) result = 0;
            return result;

        }

        public void SetValue(object target, object value)
        {
            _MemberInfo.SetValue(target, value);
        }
    }

Add custom contract to JsonSerializerSettings

var jsonSerializerSettings = new JsonSerializerSettings()
                {
                    Converters = new List<JsonConverter>() { new JavaScriptDateTimeConverter() },
                    DateFormatString = "dd/MM/yyyy HH:mm:ss.fff",
                    ContractResolver = new DynamicContractResolver(sensitiveDataJson.ToArray())
                }));

Hope for your suggestions!

API Proposal

System.Text.Json.JsonSerializerOptions

API Usage

System.Text.Json.JsonSerializer.Serialize(object, serializerOptions);

Risks

No response

Author: thangnn91
Assignees: -
Labels:

api-suggestion, area-System.Text.Json, untriaged

Milestone: -

@thangnn91 thangnn91 changed the title [API Proposal]: System.Text.Json replace property value [API Proposal]: System.Text.Json modify property value in runtime Aug 24, 2021
@huoyaoyuan
Copy link
Member

#36785 #31257

@eiriktsarpalis
Copy link
Member

Closing as duplicate of #36785.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Text.Json untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

3 participants