Skip to content

Commit

Permalink
MetadataDictionaryConverter - Protect against bad types
Browse files Browse the repository at this point in the history
  • Loading branch information
snakefoot committed Sep 10, 2022
1 parent 4ca53d2 commit 5212353
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 9 deletions.
24 changes: 22 additions & 2 deletions src/Elastic.CommonSchema/Serialization/JsonConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information

using System;
using System.Buffers.Text;
using System.Buffers;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -18,14 +20,32 @@ public static class EcsJsonConfiguration
PropertyNamingPolicy = new SnakeCaseJsonNamingPolicy(),
Converters =
{
new EcsDocumentJsonConverterFactory()
new EcsDocumentJsonConverterFactory(),
new JsonStringConverter<System.Reflection.Assembly>(), // Cannot transfer assembly-objects over the wire
new JsonStringConverter<System.Reflection.Module>(), // Cannot transfer module-objects over the wire
new JsonStringConverter<System.Reflection.MemberInfo>(),// Cannot transfer method-addresses over the wire
new JsonStringConverter<System.Delegate>(), // Cannot transfer methods over the wire
new JsonStringConverter<System.Type>(), // Cannot transfer types over the wire
new JsonStringConverter<System.IO.Stream>(), // Stream-properties often throws exceptions
},

};

internal static readonly JsonConverter<DateTimeOffset> DateTimeOffsetConverter =
(JsonConverter<DateTimeOffset>)SerializerOptions.GetConverter(typeof(DateTimeOffset));

public static readonly EcsDocumentJsonConverter DefaultEcsDocumentJsonConverter = new();

public class JsonStringConverter<T> : JsonConverter<T>
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => default;

public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
if (value is null)
writer.WriteNullValue();
else
writer.WriteStringValue(value.ToString());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,24 @@ private object ExtractValue(ref Utf8JsonReader reader, JsonSerializerOptions opt
{
switch (reader.TokenType)
{
case JsonTokenType.String when reader.TryGetDateTime(out var date): return date;
case JsonTokenType.String: return reader.GetString();
case JsonTokenType.False: return false;
case JsonTokenType.True: return true;
case JsonTokenType.Null: return null;
case JsonTokenType.Number: return reader.TryGetInt64(out var result) ? result : reader.TryGetDouble(out var d) ? d : reader.GetDecimal();
case JsonTokenType.String when reader.TryGetDateTime(out var date):
return date;
case JsonTokenType.String:
return reader.GetString();
case JsonTokenType.False:
return false;
case JsonTokenType.True:
return true;
case JsonTokenType.Null:
return null;
case JsonTokenType.Number:
return reader.TryGetInt64(out var result) ? result : reader.TryGetDouble(out var d) ? d : reader.GetDecimal();
case JsonTokenType.StartObject:
return Read(ref reader, null, options);
case JsonTokenType.StartArray:
var list = new List<object>();
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) list.Add(ExtractValue(ref reader, options));
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
list.Add(ExtractValue(ref reader, options));
return list;
case JsonTokenType.None:
case JsonTokenType.EndObject:
Expand Down
29 changes: 29 additions & 0 deletions tests/Elastic.CommonSchema.NLog.Tests/MessageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,35 @@ public void SeesMessageWithProp() => TestLogger((logger, getLogEvents) =>
y.Should().HaveValue().And.Be(2.2);
});

[Fact]
public void SeesMessageWithEvilProp() => TestLogger((logger, getLogEvents) =>
{
logger.Info("Info {EvilValue}", new BadObject());

var logEvents = getLogEvents();
logEvents.Should().HaveCount(1);

var ecsEvents = ToEcsEvents(logEvents);

var (_, info) = ecsEvents.First();
info.Message.Should().Be("Info Elastic.CommonSchema.NLog.Tests.MessageTests+BadObject");
info.Metadata.Should().ContainKey("EvilValue");

var x = info.Metadata["EvilValue"] as System.Collections.Generic.Dictionary<string, object>;
x.Should().NotBeNull().And.NotBeEmpty();
});

class BadObject
{
// public IEnumerable<object> Recursive => new List<object>(new[] { "Hello", (object)this })

// public string EvilProperty => throw new NotSupportedException()

public System.Type TypeProperty { get; } = typeof(BadObject);

// public System.Action WeirdProperty { get; } = new System.Action(() => throw new NotSupportedException());
}

[Fact]
public void SeesMessageWithException() => TestLogger((logger, getLogEvents) =>
{
Expand Down

0 comments on commit 5212353

Please sign in to comment.