diff --git a/src/Core/Entities/User.cs b/src/Core/Entities/User.cs index f7a3281d49..688bb91900 100644 --- a/src/Core/Entities/User.cs +++ b/src/Core/Entities/User.cs @@ -133,7 +133,7 @@ namespace Bit.Core.Entities public void SetTwoFactorProviders(Dictionary providers) { // When replacing with system.text remember to remove the extra serialization in WebAuthnTokenProvider. - TwoFactorProviders = JsonHelpers.LegacySerialize(providers); + TwoFactorProviders = JsonHelpers.LegacySerialize(providers, JsonHelpers.LegacyEnumKeyResolver); _twoFactorProviders = providers; } diff --git a/src/Core/Utilities/JsonHelpers.cs b/src/Core/Utilities/JsonHelpers.cs index 69bd30ad1e..6cb54676cd 100644 --- a/src/Core/Utilities/JsonHelpers.cs +++ b/src/Core/Utilities/JsonHelpers.cs @@ -66,22 +66,42 @@ namespace Bit.Core.Utilities private const string LegacyMessage = "Usage of Newtonsoft.Json should be kept to a minimum and will further be removed when we move to .NET 6"; [Obsolete(LegacyMessage)] - public static NS.JsonSerializerSettings LegacyDefault { get; } = new NS.JsonSerializerSettings(); + public static NS.JsonSerializerSettings LegacyEnumKeyResolver { get; } = new NS.JsonSerializerSettings + { + ContractResolver = new EnumKeyResolver(), + }; [Obsolete(LegacyMessage)] public static string LegacySerialize(object value, NS.JsonSerializerSettings settings = null) { - return NS.JsonConvert.SerializeObject(value, settings ?? LegacyDefault); + return NS.JsonConvert.SerializeObject(value, settings); } [Obsolete(LegacyMessage)] public static T LegacyDeserialize(string value, NS.JsonSerializerSettings settings = null) { - return NS.JsonConvert.DeserializeObject(value, settings ?? LegacyDefault); + return NS.JsonConvert.DeserializeObject(value, settings); } #endregion } + public class EnumKeyResolver : NS.Serialization.DefaultContractResolver + where T : struct + { + protected override NS.Serialization.JsonDictionaryContract CreateDictionaryContract(Type objectType) + { + var contract = base.CreateDictionaryContract(objectType); + var keyType = contract.DictionaryKeyType; + + if (keyType.BaseType == typeof(Enum)) + { + contract.DictionaryKeyResolver = propName => ((T)Enum.Parse(keyType, propName)).ToString(); + } + + return contract; + } + } + public class MsEpochConverter : JsonConverter { public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) diff --git a/test/Core.Test/Models/Tables/UserTests.cs b/test/Core.Test/Models/Tables/UserTests.cs index 8d2059484a..80fa623261 100644 --- a/test/Core.Test/Models/Tables/UserTests.cs +++ b/test/Core.Test/Models/Tables/UserTests.cs @@ -72,12 +72,12 @@ namespace Bit.Core.Test.Models.Tables using var jsonDocument = JsonDocument.Parse(user.TwoFactorProviders); var root = jsonDocument.RootElement; - var webAuthn = AssertHelper.AssertJsonProperty(root, "WebAuthn", JsonValueKind.Object); + var webAuthn = AssertHelper.AssertJsonProperty(root, "7", JsonValueKind.Object); AssertHelper.AssertJsonProperty(webAuthn, "Enabled", JsonValueKind.True); var webMetaData = AssertHelper.AssertJsonProperty(webAuthn, "MetaData", JsonValueKind.Object); AssertHelper.AssertJsonProperty(webMetaData, "Item", JsonValueKind.String); - var email = AssertHelper.AssertJsonProperty(root, "Email", JsonValueKind.Object); + var email = AssertHelper.AssertJsonProperty(root, "1", JsonValueKind.Object); AssertHelper.AssertJsonProperty(email, "Enabled", JsonValueKind.False); var emailMetaData = AssertHelper.AssertJsonProperty(email, "MetaData", JsonValueKind.Object); AssertHelper.AssertJsonProperty(emailMetaData, "Email", JsonValueKind.String);