diff --git a/src/fiskaltrust.Launcher/Helpers/CustomDateTimeConverter.cs b/src/fiskaltrust.Launcher/Helpers/CustomDateTimeConverter.cs new file mode 100644 index 00000000..b687d014 --- /dev/null +++ b/src/fiskaltrust.Launcher/Helpers/CustomDateTimeConverter.cs @@ -0,0 +1,69 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; + +namespace fiskaltrust.Launcher.Helpers +{ + sealed class CustomDateTimeConverter : JsonConverter + { + private readonly static JsonConverter DEFAULT_CONVERTER = (JsonConverter)JsonSerializerOptions.Default.GetConverter(typeof(DateTime)); + static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0); + static readonly DateTimeOffset EPOCH_OFFSET = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + + static readonly Regex REGEX = new Regex("^\\\\?/Date\\(([+-]*\\d+)\\)\\\\?/$", RegexOptions.CultureInvariant); + + static readonly Regex REGEX_OFFSET = new Regex("^\\\\?/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)\\\\?/$", RegexOptions.CultureInvariant); + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + string formatted = reader.GetString()!; + + { + Match match = REGEX_OFFSET.Match(formatted); + + if (match.Success) + { + return ReadDateTimeOffset(match).DateTime; + } + } + + { + Match match = REGEX.Match(formatted); + + if (match.Success) + { + return ReadDateTime(match); + } + } + + return DEFAULT_CONVERTER.Read(ref reader, typeToConvert, options); + } + + private DateTime ReadDateTime(Match date) + { + if (!long.TryParse(date.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)) + { + throw new JsonException(); + } + + return EPOCH.AddMilliseconds(unixTime); + } + + private DateTimeOffset ReadDateTimeOffset(Match date) + { + if (!long.TryParse(date.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime) + || !int.TryParse(date.Groups[3].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours) + || !int.TryParse(date.Groups[4].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes)) + { + throw new JsonException(); + } + + int sign = date.Groups[2].Value[0] == '+' ? 1 : -1; + TimeSpan utcOffset = new TimeSpan(hours * sign, minutes * sign, 0); + return EPOCH_OFFSET.AddMilliseconds(unixTime).ToOffset(utcOffset); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) => DEFAULT_CONVERTER.Write(writer, value, options); + } +} \ No newline at end of file diff --git a/src/fiskaltrust.Launcher/Helpers/NumberToStringConverter.cs b/src/fiskaltrust.Launcher/Helpers/NumberToStringConverter.cs index 9de881f1..30b2fccb 100644 --- a/src/fiskaltrust.Launcher/Helpers/NumberToStringConverter.cs +++ b/src/fiskaltrust.Launcher/Helpers/NumberToStringConverter.cs @@ -6,6 +6,8 @@ namespace fiskaltrust.Launcher.Helpers { public class NumberToStringConverter : JsonConverter { + private readonly static JsonConverter DEFAULT_CONVERTER = (JsonConverter)JsonSerializerOptions.Default.GetConverter(typeof(string)); + public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Number) @@ -15,7 +17,7 @@ public class NumberToStringConverter : JsonConverter return number.ToString(CultureInfo.InvariantCulture); } - if (reader.TryGetDouble(out var doubleNumber)) + if (reader.TryGetDecimal(out var doubleNumber)) { return doubleNumber.ToString(CultureInfo.InvariantCulture); } @@ -29,9 +31,6 @@ public class NumberToStringConverter : JsonConverter return null; } - public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.ToString()); - } + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) => DEFAULT_CONVERTER.Write(writer, value, options); } } \ No newline at end of file diff --git a/src/fiskaltrust.Launcher/Services/HostingService.cs b/src/fiskaltrust.Launcher/Services/HostingService.cs index 3bcd8661..7ebdb262 100644 --- a/src/fiskaltrust.Launcher/Services/HostingService.cs +++ b/src/fiskaltrust.Launcher/Services/HostingService.cs @@ -18,6 +18,7 @@ using System.Security.Cryptography.X509Certificates; using System.Runtime.Versioning; using Microsoft.AspNetCore.Server.HttpSys; +using System.Text.Json; namespace fiskaltrust.Launcher.Services { @@ -133,6 +134,10 @@ private WebApplication CreateRestHost(WebApplicationBuilder builder, Uri uri, { options.SerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString; options.SerializerOptions.Converters.Add(new NumberToStringConverter()); + options.SerializerOptions.Converters.Add(new CustomDateTimeConverter()); + options.SerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + options.SerializerOptions.PropertyNamingPolicy = null; + options.SerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; }); builder.WebHost.ConfigureBinding(uri, listenOptions => ConfigureTls(listenOptions), isHttps: !string.IsNullOrEmpty(_launcherConfiguration.TlsCertificatePath) || !string.IsNullOrEmpty(_launcherConfiguration.TlsCertificateBase64), allowSynchronousIO: true, useHttpSys: _launcherConfiguration.UseHttpSysBinding!.Value); diff --git a/version.json b/version.json index 773fde25..2655135a 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "version": "2.0.0-rc.9", + "version": "2.0.0-rc.10", "releaseBranches": [ "^refs/tags/v\\d+(?:\\.\\d+)*(?:-.*)?$" ]