1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-24 12:35:25 +01:00

Start Migration from Newtonsoft.Json to System.Text.Json (#1803)

* Start switch to System.Text.Json

* Work on switching to System.Text.Json

* Main work on STJ refactor

* Fix build errors

* Run formatting

* Delete unused file

* Use legacy for two factor providers

* Run formatter

* Add TokenProviderTests

* Run formatting

* Fix merge issues

* Switch to use JsonSerializer

* Address PR feedback

* Fix formatting

* Ran formatter

* Switch to async

* Ensure Enums are serialized as strings

* Fix formatting

* Enqueue single items as arrays

* Remove CreateAsync method on AzureQueueService
This commit is contained in:
Justin Baur 2022-01-21 09:36:25 -05:00 committed by GitHub
parent 897a76ff48
commit 5268f2781e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
91 changed files with 974 additions and 698 deletions

View File

@ -1,11 +1,12 @@
using System.Diagnostics;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Bit.Admin.Models;
using Bit.Core.Settings;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
namespace Bit.Admin.Controllers
{
@ -37,20 +38,21 @@ namespace Bit.Admin.Controllers
});
}
public async Task<IActionResult> GetLatestDockerHubVersion(string repository)
public async Task<IActionResult> GetLatestDockerHubVersion(string repository, CancellationToken cancellationToken)
{
try
{
var response = await _httpClient.GetAsync(
$"https://hub.docker.com/v2/repositories/bitwarden/{repository}/tags/");
$"https://hub.docker.com/v2/repositories/bitwarden/{repository}/tags/", cancellationToken);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var data = JObject.Parse(json);
var results = data["results"] as JArray;
foreach (var result in results)
using var jsonDocument = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync(cancellationToken), cancellationToken: cancellationToken);
var root = jsonDocument.RootElement;
var results = root.GetProperty("results");
foreach (var result in results.EnumerateArray())
{
var name = result["name"].ToString();
var name = result.GetProperty("name").GetString();
if (!string.IsNullOrWhiteSpace(name) && name.Length > 0 && char.IsNumber(name[0]))
{
return new JsonResult(name);
@ -63,17 +65,17 @@ namespace Bit.Admin.Controllers
return new JsonResult("-");
}
public async Task<IActionResult> GetInstalledWebVersion()
public async Task<IActionResult> GetInstalledWebVersion(CancellationToken cancellationToken)
{
try
{
var response = await _httpClient.GetAsync(
$"{_globalSettings.BaseServiceUri.InternalVault}/version.json");
$"{_globalSettings.BaseServiceUri.InternalVault}/version.json", cancellationToken);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var data = JObject.Parse(json);
return new JsonResult(data["version"].ToString());
using var jsonDocument = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync(cancellationToken), cancellationToken: cancellationToken);
var root = jsonDocument.RootElement;
return new JsonResult(root.GetProperty("version").GetString());
}
}
catch (HttpRequestException) { }

View File

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Admin.Models;
using Bit.Core;
using Bit.Core.Entities;
using Bit.Core.Repositories;
using Bit.Core.Services;
@ -14,7 +14,6 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace Bit.Admin.Controllers
{
@ -264,14 +263,16 @@ namespace Bit.Admin.Controllers
{
var license = await _organizationService.GenerateLicenseAsync(organization,
model.InstallationId.Value, model.Version);
return File(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(license, Formatting.Indented)),
"text/plain", "bitwarden_organization_license.json");
var ms = new MemoryStream();
await JsonSerializer.SerializeAsync(ms, license, JsonHelpers.Indented);
return File(ms, "text/plain", "bitwarden_organization_license.json");
}
else if (user != null)
{
var license = await _userService.GenerateLicenseAsync(user, null, model.Version);
return File(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(license, Formatting.Indented)),
"text/plain", "bitwarden_premium_license.json");
var ms = new MemoryStream();
await JsonSerializer.SerializeAsync(ms, license, JsonHelpers.Indented);
return File(ms, "text/plain", "bitwarden_premium_license.json");
}
else
{

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.Storage.Queues;
@ -11,8 +12,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.Admin.HostedServices
{
@ -70,17 +69,19 @@ namespace Bit.Admin.HostedServices
{
try
{
var token = JToken.Parse(message.DecodeMessageText());
if (token is JArray)
using var document = JsonDocument.Parse(message.DecodeMessageText());
var root = document.RootElement;
if (root.ValueKind == JsonValueKind.Array)
{
foreach (var mailQueueMessage in token.ToObject<List<MailQueueMessage>>())
foreach (var mailQueueMessage in root.ToObject<List<MailQueueMessage>>())
{
await _mailService.SendEnqueuedMailMessageAsync(mailQueueMessage);
}
}
else if (token is JObject)
else if (root.ValueKind == JsonValueKind.Object)
{
var mailQueueMessage = token.ToObject<MailQueueMessage>();
var mailQueueMessage = root.ToObject<MailQueueMessage>();
await _mailService.SendEnqueuedMailMessageAsync(mailQueueMessage);
}
}

View File

@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Bit.Core.Settings;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Bit.Admin.HostedServices
{
@ -65,7 +64,7 @@ namespace Bit.Admin.HostedServices
request.RequestUri = new Uri("https://api.cloudflare.com/" +
$"client/v4/zones/{_adminSettings.Cloudflare.ZoneId}/firewall/access_rules/rules");
var bodyContent = JsonConvert.SerializeObject(new
request.Content = JsonContent.Create(new
{
mode = "block",
configuration = new
@ -75,7 +74,6 @@ namespace Bit.Admin.HostedServices
},
notes = $"Rate limit abuse on {DateTime.UtcNow.ToString()}."
});
request.Content = new StringContent(bodyContent, Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request, cancellationToken);
if (!response.IsSuccessStatusCode)
@ -83,8 +81,7 @@ namespace Bit.Admin.HostedServices
return;
}
var responseString = await response.Content.ReadAsStringAsync();
var accessRuleResponse = JsonConvert.DeserializeObject<AccessRuleResponse>(responseString);
var accessRuleResponse = await response.Content.ReadFromJsonAsync<AccessRuleResponse>(cancellationToken: cancellationToken);
if (!accessRuleResponse.Success)
{
return;
@ -118,8 +115,7 @@ namespace Bit.Admin.HostedServices
return;
}
var responseString = await response.Content.ReadAsStringAsync();
var listResponse = JsonConvert.DeserializeObject<ListResponse>(responseString);
var listResponse = await response.Content.ReadFromJsonAsync<ListResponse>(cancellationToken: cancellationToken);
if (!listResponse.Success)
{
return;

View File

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using Bit.Core.Utilities;
using Microsoft.Azure.Documents;
using Newtonsoft.Json.Linq;
namespace Bit.Admin.Models
{
@ -17,40 +19,48 @@ namespace Bit.Admin.Models
public class LogDetailsModel : LogModel
{
public JObject Exception { get; set; }
public JsonDocument Exception { get; set; }
public string ExceptionToString(JObject e)
public string ExceptionToString(JsonDocument e)
{
if (e == null)
{
return null;
}
var val = string.Empty;
if (e["Message"] != null && e["Message"].ToObject<string>() != null)
var root = e.RootElement;
var sb = new StringBuilder();
if (root.TryGetProperty("Message", out var messageProp) && messageProp.GetString() != null)
{
val += "Message:\n";
val += e["Message"] + "\n";
sb.AppendLine("Message:");
sb.AppendLine(messageProp.GetString());
}
if (e["StackTrace"] != null && e["StackTrace"].ToObject<string>() != null)
if (root.TryGetProperty("StackTrace", out var stackTraceProp) && stackTraceProp.GetString() != null)
{
val += "\nStack Trace:\n";
val += e["StackTrace"];
sb.AppendLine();
sb.AppendLine("Stack Trace:");
sb.Append(stackTraceProp.GetString());
}
else if (e["StackTraceString"] != null && e["StackTraceString"].ToObject<string>() != null)
else if (root.TryGetProperty("StackTraceString", out var stackTraceStringProp) && stackTraceStringProp.GetString() != null)
{
val += "\nStack Trace String:\n";
val += e["StackTraceString"];
sb.AppendLine();
sb.AppendLine("Stack Trace String:");
sb.Append(stackTraceStringProp.GetString());
}
if (e["InnerException"] != null && e["InnerException"].ToObject<JObject>() != null)
if (root.TryGetProperty("InnerException", out var innerExceptionProp) && innerExceptionProp.ValueKind == JsonValueKind.Object)
{
val += "\n\n=== Inner Exception ===\n\n";
val += ExceptionToString(e["InnerException"].ToObject<JObject>());
sb.AppendLine();
sb.AppendLine();
sb.AppendLine("=== Inner Exception ===");
sb.AppendLine();
sb.AppendLine(ExceptionToString(innerExceptionProp.ToObject<JsonDocument>()));
sb.AppendLine();
}
return val;
return sb.ToString();
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Messaging.EventGrid;
using Bit.Api.Models.Request;
@ -21,7 +22,6 @@ using Core.Models.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Api.Controllers
{
@ -802,7 +802,7 @@ namespace Bit.Api.Controllers
}
catch (Exception e)
{
_logger.LogError(e, $"Uncaught exception occurred while handling event grid event: {JsonConvert.SerializeObject(eventGridEvent)}");
_logger.LogError(e, $"Uncaught exception occurred while handling event grid event: {JsonSerializer.Serialize(eventGridEvent)}");
return;
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Api.Models.Request;
using Bit.Api.Models.Request.Accounts;
@ -17,7 +18,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace Bit.Api.Controllers
{
@ -185,7 +185,7 @@ namespace Bit.Api.Controllers
return new OrganizationAutoEnrollStatusResponseModel(organization.Id, false);
}
var data = JsonConvert.DeserializeObject<ResetPasswordDataModel>(resetPasswordPolicy.Data);
var data = JsonSerializer.Deserialize<ResetPasswordDataModel>(resetPasswordPolicy.Data);
return new OrganizationAutoEnrollStatusResponseModel(organization.Id, data?.AutoEnrollEnabled ?? false);
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Messaging.EventGrid;
using Bit.Api.Models.Request;
@ -19,7 +20,6 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Api.Controllers
{
@ -227,7 +227,7 @@ namespace Bit.Api.Controllers
var userId = _userService.GetProperUserId(User).Value;
var sendId = new Guid(id);
var send = await _sendRepository.GetByIdAsync(sendId);
var fileData = JsonConvert.DeserializeObject<SendFileData>(send?.Data);
var fileData = JsonSerializer.Deserialize<SendFileData>(send?.Data);
if (send == null || send.Type != SendType.File || (send.UserId.HasValue && send.UserId.Value != userId) ||
!send.UserId.HasValue || fileData.Id != fileId || fileData.Validated)
@ -289,7 +289,7 @@ namespace Bit.Api.Controllers
}
catch (Exception e)
{
_logger.LogError(e, $"Uncaught exception occurred while handling event grid event: {JsonConvert.SerializeObject(eventGridEvent)}");
_logger.LogError(e, $"Uncaught exception occurred while handling event grid event: {JsonSerializer.Serialize(eventGridEvent)}");
return;
}
}

View File

@ -1,6 +1,6 @@
using System;
using System.Text.Json;
using Bit.Core.Entities;
using Newtonsoft.Json;
namespace Bit.Api.Models.Public.Request
{
@ -17,7 +17,7 @@ namespace Bit.Api.Models.Public.Request
public virtual Policy ToPolicy(Policy existingPolicy)
{
existingPolicy.Enabled = Enabled.GetValueOrDefault();
existingPolicy.Data = Data != null ? JsonConvert.SerializeObject(Data) : null;
existingPolicy.Data = Data != null ? JsonSerializer.Serialize(Data) : null;
return existingPolicy;
}
}

View File

@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Newtonsoft.Json;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Public.Response
{
@ -24,7 +25,7 @@ namespace Bit.Api.Models.Public.Response
Enabled = policy.Enabled;
if (!string.IsNullOrWhiteSpace(policy.Data))
{
Data = JsonConvert.DeserializeObject<Dictionary<string, object>>(policy.Data);
Data = JsonSerializer.Deserialize<Dictionary<string, object>>(policy.Data);
}
}

View File

@ -2,13 +2,14 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
using Core.Models.Data;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NS = Newtonsoft.Json;
using NSL = Newtonsoft.Json.Linq;
namespace Bit.Api.Models.Request
{
@ -69,22 +70,20 @@ namespace Bit.Api.Models.Request
switch (existingCipher.Type)
{
case CipherType.Login:
var loginObj = JObject.FromObject(ToCipherLoginData(),
new JsonSerializer { NullValueHandling = NullValueHandling.Ignore });
var loginObj = NSL.JObject.FromObject(ToCipherLoginData(),
new NS.JsonSerializer { NullValueHandling = NS.NullValueHandling.Ignore });
// TODO: Switch to JsonNode in .NET 6 https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter?pivots=dotnet-6-0
loginObj[nameof(CipherLoginData.Uri)]?.Parent?.Remove();
existingCipher.Data = loginObj.ToString(Formatting.None);
existingCipher.Data = loginObj.ToString(NS.Formatting.None);
break;
case CipherType.Card:
existingCipher.Data = JsonConvert.SerializeObject(ToCipherCardData(),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
existingCipher.Data = JsonSerializer.Serialize(ToCipherCardData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.Identity:
existingCipher.Data = JsonConvert.SerializeObject(ToCipherIdentityData(),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
existingCipher.Data = JsonSerializer.Serialize(ToCipherIdentityData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.SecureNote:
existingCipher.Data = JsonConvert.SerializeObject(ToCipherSecureNoteData(),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
existingCipher.Data = JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
break;
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");

View File

@ -1,12 +1,12 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Api.Models.Request
{
@ -65,15 +65,13 @@ namespace Bit.Api.Models.Request
switch (existingSend.Type)
{
case SendType.File:
var fileData = JsonConvert.DeserializeObject<SendFileData>(existingSend.Data);
var fileData = JsonSerializer.Deserialize<SendFileData>(existingSend.Data);
fileData.Name = Name;
fileData.Notes = Notes;
existingSend.Data = JsonConvert.SerializeObject(fileData,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
existingSend.Data = JsonSerializer.Serialize(fileData, JsonHelpers.IgnoreWritingNull);
break;
case SendType.Text:
existingSend.Data = JsonConvert.SerializeObject(ToSendData(),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
existingSend.Data = JsonSerializer.Serialize(ToSendData(), JsonHelpers.IgnoreWritingNull);
break;
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Newtonsoft.Json;
namespace Bit.Api.Models.Request
{
@ -12,9 +12,9 @@ namespace Bit.Api.Models.Request
public User ToUser(User existingUser)
{
existingUser.EquivalentDomains = EquivalentDomains != null ? JsonConvert.SerializeObject(EquivalentDomains) : null;
existingUser.EquivalentDomains = EquivalentDomains != null ? JsonSerializer.Serialize(EquivalentDomains) : null;
existingUser.ExcludedGlobalEquivalentDomains = ExcludedGlobalEquivalentDomains != null ?
JsonConvert.SerializeObject(ExcludedGlobalEquivalentDomains) : null;
JsonSerializer.Serialize(ExcludedGlobalEquivalentDomains) : null;
return existingUser;
}
}

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;
@ -18,7 +19,7 @@ namespace Bit.Api.Models.Response
Url = $"{globalSettings.Attachment.BaseUrl}/{cipher.Id}/{id}";
FileName = data.FileName;
Key = data.Key;
Size = data.SizeString;
Size = data.Size;
SizeName = CoreHelpers.ReadableBytesSize(data.Size);
}
@ -26,7 +27,8 @@ namespace Bit.Api.Models.Response
public string Url { get; set; }
public string FileName { get; set; }
public string Key { get; set; }
public string Size { get; set; }
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long Size { get; set; }
public string SizeName { get; set; }
public static IEnumerable<AttachmentResponseModel> FromCipher(Cipher cipher, IGlobalSettings globalSettings)

View File

@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
using Core.Models.Data;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response
{
@ -28,25 +28,25 @@ namespace Bit.Api.Models.Response
switch (cipher.Type)
{
case CipherType.Login:
var loginData = JsonConvert.DeserializeObject<CipherLoginData>(cipher.Data);
var loginData = JsonSerializer.Deserialize<CipherLoginData>(cipher.Data);
cipherData = loginData;
Data = loginData;
Login = new CipherLoginModel(loginData);
break;
case CipherType.SecureNote:
var secureNoteData = JsonConvert.DeserializeObject<CipherSecureNoteData>(cipher.Data);
var secureNoteData = JsonSerializer.Deserialize<CipherSecureNoteData>(cipher.Data);
Data = secureNoteData;
cipherData = secureNoteData;
SecureNote = new CipherSecureNoteModel(secureNoteData);
break;
case CipherType.Card:
var cardData = JsonConvert.DeserializeObject<CipherCardData>(cipher.Data);
var cardData = JsonSerializer.Deserialize<CipherCardData>(cipher.Data);
Data = cardData;
cipherData = cardData;
Card = new CipherCardModel(cardData);
break;
case CipherType.Identity:
var identityData = JsonConvert.DeserializeObject<CipherIdentityData>(cipher.Data);
var identityData = JsonSerializer.Deserialize<CipherIdentityData>(cipher.Data);
Data = identityData;
cipherData = identityData;
Identity = new CipherIdentityModel(identityData);

View File

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response
{
@ -19,10 +19,10 @@ namespace Bit.Api.Models.Response
}
EquivalentDomains = user.EquivalentDomains != null ?
JsonConvert.DeserializeObject<List<List<string>>>(user.EquivalentDomains) : null;
JsonSerializer.Deserialize<List<List<string>>>(user.EquivalentDomains) : null;
var excludedGlobalEquivalentDomains = user.ExcludedGlobalEquivalentDomains != null ?
JsonConvert.DeserializeObject<List<GlobalEquivalentDomainsType>>(user.ExcludedGlobalEquivalentDomains) :
JsonSerializer.Deserialize<List<GlobalEquivalentDomainsType>>(user.ExcludedGlobalEquivalentDomains) :
new List<GlobalEquivalentDomainsType>();
var globalDomains = new List<GlobalDomains>();
var domainsToInclude = excluded ? Core.Utilities.StaticStore.GlobalDomains :

View File

@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response
{
@ -23,7 +23,7 @@ namespace Bit.Api.Models.Response
Enabled = policy.Enabled;
if (!string.IsNullOrWhiteSpace(policy.Data))
{
Data = JsonConvert.DeserializeObject<Dictionary<string, object>>(policy.Data);
Data = JsonSerializer.Deserialize<Dictionary<string, object>>(policy.Data);
}
}

View File

@ -1,11 +1,11 @@
using System;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response
{
@ -26,12 +26,12 @@ namespace Bit.Api.Models.Response
switch (send.Type)
{
case SendType.File:
var fileData = JsonConvert.DeserializeObject<SendFileData>(send.Data);
var fileData = JsonSerializer.Deserialize<SendFileData>(send.Data);
sendData = fileData;
File = new SendFileModel(fileData);
break;
case SendType.Text:
var textData = JsonConvert.DeserializeObject<SendTextData>(send.Data);
var textData = JsonSerializer.Deserialize<SendTextData>(send.Data);
sendData = textData;
Text = new SendTextModel(textData);
break;

View File

@ -1,11 +1,11 @@
using System;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response
{
@ -36,12 +36,12 @@ namespace Bit.Api.Models.Response
switch (send.Type)
{
case SendType.File:
var fileData = JsonConvert.DeserializeObject<SendFileData>(send.Data);
var fileData = JsonSerializer.Deserialize<SendFileData>(send.Data);
sendData = fileData;
File = new SendFileModel(fileData);
break;
case SendType.Text:
var textData = JsonConvert.DeserializeObject<SendTextData>(send.Data);
var textData = JsonSerializer.Deserialize<SendTextData>(send.Data);
sendData = textData;
Text = new SendTextModel(textData);
break;

View File

@ -1,4 +1,5 @@
using Bit.Core.Models.Data;
using System.Text.Json.Serialization;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Api.Models
@ -11,7 +12,7 @@ namespace Bit.Api.Models
{
Id = data.Id;
FileName = data.FileName;
Size = data.SizeString;
Size = data.Size;
SizeName = CoreHelpers.ReadableBytesSize(data.Size);
}
@ -19,7 +20,8 @@ namespace Bit.Api.Models
[EncryptedString]
[EncryptedStringLength(1000)]
public string FileName { get; set; }
public string Size { get; set; }
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long Size { get; set; }
public string SizeName { get; set; }
}
}

View File

@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Messaging.EventGrid;
using Azure.Messaging.EventGrid.SystemEvents;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace Bit.Api.Utilities
{
@ -27,7 +27,7 @@ namespace Bit.Api.Utilities
var s = await reader.ReadToEndAsync();
if (!string.IsNullOrWhiteSpace(s))
{
obj = JsonConvert.DeserializeObject<T>(s);
obj = JsonSerializer.Deserialize<T>(s);
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Api.Models.Request;
using Microsoft.AspNetCore.Http;
@ -7,7 +8,6 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
namespace Bit.Api.Utilities
{
@ -78,13 +78,6 @@ namespace Bit.Api.Utilities
{
if (ContentDispositionHeaderValue.TryParse(firstSection.ContentDisposition, out _))
{
// Request model json, then data
string requestModelJson = null;
using (var sr = new StreamReader(firstSection.Body))
{
requestModelJson = await sr.ReadToEndAsync();
}
var secondSection = await reader.ReadNextSectionAsync();
if (secondSection != null)
{
@ -94,7 +87,7 @@ namespace Bit.Api.Utilities
var fileName = HeaderUtilities.RemoveQuotes(secondContent.FileName).ToString();
using (secondSection.Body)
{
var model = JsonConvert.DeserializeObject<SendRequestModel>(requestModelJson);
var model = await JsonSerializer.DeserializeAsync<SendRequestModel>(firstSection.Body);
await callback(secondSection.Body, fileName, model);
}
}

View File

@ -1,13 +1,13 @@
using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Bit.Billing.Controllers
{
@ -53,7 +53,7 @@ namespace Bit.Billing.Controllers
try
{
var json = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(body), Formatting.Indented);
var json = JsonSerializer.Serialize(JsonSerializer.Deserialize<JsonDocument>(body), JsonHelpers.Indented);
_logger.LogInformation(Constants.BypassFiltersEventId, "Apple IAP Notification:\n\n{0}", json);
return new OkResult();
}

View File

@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Repositories;
using Bit.Core.Settings;
@ -13,7 +14,6 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Bit.Billing.Controllers
{
@ -62,23 +62,18 @@ namespace Bit.Billing.Controllers
return new BadRequestResult();
}
string body = null;
using (var reader = new StreamReader(HttpContext.Request.Body, Encoding.UTF8))
{
body = await reader.ReadToEndAsync();
}
if (string.IsNullOrWhiteSpace(body))
using var body = await JsonSerializer.DeserializeAsync<JsonDocument>(HttpContext.Request.Body);
var root = body.RootElement;
if (root.ValueKind != JsonValueKind.Object)
{
return new BadRequestResult();
}
try
{
dynamic data = JsonConvert.DeserializeObject(body);
string ticketId = data.ticket_id;
string ticketContactEmail = data.ticket_contact_email;
string ticketTags = data.ticket_tags;
var ticketId = root.GetProperty("ticket_id").GetString();
var ticketContactEmail = root.GetProperty("ticket_contact_email").GetString();
var ticketTags = root.GetProperty("ticket_tags").GetString();
if (string.IsNullOrWhiteSpace(ticketId) || string.IsNullOrWhiteSpace(ticketContactEmail))
{
return new BadRequestResult();
@ -120,9 +115,11 @@ namespace Bit.Billing.Controllers
updateBody.Add("tags", tagsToUpdate);
}
var updateRequest = new HttpRequestMessage(HttpMethod.Put,
string.Format("https://bitwarden.freshdesk.com/api/v2/tickets/{0}", ticketId));
updateRequest.Content = new StringContent(JsonConvert.SerializeObject(updateBody),
Encoding.UTF8, "application/json");
string.Format("https://bitwarden.freshdesk.com/api/v2/tickets/{0}", ticketId))
{
Content = JsonContent.Create(updateBody),
};
await CallFreshdeskApiAsync(updateRequest);
@ -132,9 +129,10 @@ namespace Bit.Billing.Controllers
{ "private", true }
};
var noteRequest = new HttpRequestMessage(HttpMethod.Post,
string.Format("https://bitwarden.freshdesk.com/api/v2/tickets/{0}/notes", ticketId));
noteRequest.Content = new StringContent(JsonConvert.SerializeObject(noteBody),
Encoding.UTF8, "application/json");
string.Format("https://bitwarden.freshdesk.com/api/v2/tickets/{0}/notes", ticketId))
{
Content = JsonContent.Create(noteBody),
};
await CallFreshdeskApiAsync(noteRequest);
}

View File

@ -1,105 +0,0 @@
using System;
using Bit.Core.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Bit.Billing.Models
{
public class AppleReceiptNotification
{
[JsonProperty("notification_type")]
public string NotificationType { get; set; }
[JsonProperty("environment")]
public string Environment { get; set; }
[JsonProperty("auto_renew_status")]
public string AutoRenewStatus { get; set; }
[JsonProperty("auto_renew_product_id")]
public string AutoRenewProductId { get; set; }
[JsonProperty("auto_renew_status_change_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime? AutoRenewStatusChangeDate { get; set; }
[JsonProperty("latest_receipt")]
public string LatestReceipt { get; set; }
[JsonProperty("latest_receipt_info")]
public AppleReceiptNotificationInfo LatestReceiptInfo { get; set; }
[JsonProperty("latest_expired_receipt")]
public string LatestExpiredReceipt { get; set; }
[JsonProperty("latest_expired_receipt_info")]
public AppleReceiptNotificationInfo LatestExpiredReceiptInfo { get; set; }
public string GetOriginalTransactionId()
{
if (LatestReceiptInfo != null)
{
return LatestReceiptInfo.OriginalTransactionId;
}
return LatestExpiredReceiptInfo?.OriginalTransactionId;
}
public string GetTransactionId()
{
if (LatestReceiptInfo != null)
{
return LatestReceiptInfo.TransactionId;
}
return LatestExpiredReceiptInfo?.TransactionId;
}
public DateTime? GetExpiresDate()
{
if (LatestReceiptInfo != null)
{
return LatestReceiptInfo.ExpiresDate;
}
return LatestExpiredReceiptInfo?.ExpiresDate;
}
public string GetReceiptData()
{
return string.IsNullOrWhiteSpace(LatestReceipt) ? LatestExpiredReceipt : LatestReceipt;
}
public class AppleReceiptNotificationInfo
{
[JsonProperty("bid")]
public string Bid { get; set; }
public string ProductId { get; set; }
[JsonProperty("original_purchase_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime? OriginalPurchaseDate { get; set; }
[JsonProperty("expires_date")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime? ExpiresDate { get; set; }
[JsonProperty("purchase_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime? PurchaseDate { get; set; }
[JsonProperty("subscription_group_identifier")]
public string SubscriptionGroupIdentifier { get; set; }
[JsonProperty("unique_identifier")]
public string UniqueIdentifier { get; set; }
[JsonProperty("original_transaction_id")]
public string OriginalTransactionId { get; set; }
[JsonProperty("transaction_id")]
public string TransactionId { get; set; }
[JsonProperty("quantity")]
public string Quantity { get; set; }
[JsonProperty("web_order_line_item_id")]
public string WebOrderLineItemId { get; set; }
[JsonProperty("item_id")]
public string ItemId { get; set; }
}
public class MsEpochConverter : DateTimeConverterBase
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(CoreHelpers.ToEpocMilliseconds((DateTime)value).ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return CoreHelpers.FromEpocMilliseconds(long.Parse(reader.Value.ToString()));
}
}
}
}

View File

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Entities
{
@ -42,7 +42,7 @@ namespace Bit.Core.Entities
try
{
_attachmentData = JsonConvert.DeserializeObject<Dictionary<string, CipherAttachment.MetaData>>(Attachments);
_attachmentData = JsonSerializer.Deserialize<Dictionary<string, CipherAttachment.MetaData>>(Attachments);
foreach (var kvp in _attachmentData)
{
kvp.Value.AttachmentId = kvp.Key;
@ -65,7 +65,7 @@ namespace Bit.Core.Entities
}
_attachmentData = data;
Attachments = JsonConvert.SerializeObject(_attachmentData);
Attachments = JsonSerializer.Serialize(_attachmentData);
}
public void AddAttachment(string id, CipherAttachment.MetaData data)

View File

@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Json;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Entities
{
@ -142,13 +142,13 @@ namespace Bit.Core.Entities
if (_twoFactorProviders == null)
{
_twoFactorProviders =
JsonConvert.DeserializeObject<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(
JsonSerializer.Deserialize<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(
TwoFactorProviders);
}
return _twoFactorProviders;
}
catch (JsonSerializationException)
catch (JsonException)
{
return null;
}
@ -163,10 +163,7 @@ namespace Bit.Core.Entities
return;
}
TwoFactorProviders = JsonConvert.SerializeObject(providers, new JsonSerializerSettings
{
ContractResolver = new EnumKeyResolver<byte>()
});
TwoFactorProviders = JsonSerializer.Serialize(providers);
_twoFactorProviders = providers;
}

View File

@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Identity;
using Newtonsoft.Json;
namespace Bit.Core.Entities
{
@ -108,13 +108,13 @@ namespace Bit.Core.Entities
if (_twoFactorProviders == null)
{
_twoFactorProviders =
JsonConvert.DeserializeObject<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(
JsonHelpers.LegacyDeserialize<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(
TwoFactorProviders);
}
return _twoFactorProviders;
}
catch (JsonSerializationException)
catch (JsonException)
{
return null;
}
@ -132,10 +132,7 @@ namespace Bit.Core.Entities
public void SetTwoFactorProviders(Dictionary<TwoFactorProviderType, TwoFactorProvider> providers)
{
TwoFactorProviders = JsonConvert.SerializeObject(providers, new JsonSerializerSettings
{
ContractResolver = new EnumKeyResolver<byte>()
});
TwoFactorProviders = JsonHelpers.LegacySerialize(providers);
_twoFactorProviders = providers;
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -10,7 +11,6 @@ using Bit.Core.Services;
using Bit.Core.Settings;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using U2F.Core.Exceptions;
using U2F.Core.Models;
using U2F.Core.Utils;
@ -107,8 +107,8 @@ namespace Bit.Core.Identity
});
}
var oldToken = JsonConvert.SerializeObject(oldChallenges);
var token = JsonConvert.SerializeObject(new
var oldToken = JsonSerializer.Serialize(oldChallenges);
var token = JsonSerializer.Serialize(new
{
appId = appId,
challenge = challengeBytes.ByteArrayToBase64String(),

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -12,7 +13,6 @@ using Fido2NetLib;
using Fido2NetLib.Objects;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
namespace Bit.Core.Identity
{
@ -98,7 +98,7 @@ namespace Bit.Core.Identity
return false;
}
var clientResponse = JsonConvert.DeserializeObject<AuthenticatorAssertionRawResponse>(token);
var clientResponse = JsonSerializer.Deserialize<AuthenticatorAssertionRawResponse>(token);
var jsonOptions = provider.MetaData["login"].ToString();
var options = AssertionOptions.FromJson(jsonOptions);

View File

@ -15,7 +15,7 @@
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center">
If you do not wish to join this organization, you can safely ignore this email.
{{#if OrganizationCanSponsor}}
{{#jsonIf OrganizationCanSponsor}}
<p style="margin-top:10px">
<b
style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
@ -24,7 +24,7 @@
Members of {{OrganizationName}} receive a complimentary Families subscription. Learn more at the
following link: https://bitwarden.com/help/article/families-for-enterprise/
</p>
{{/if}}
{{/jsonIf}}
</td>
</tr>
</table>

View File

@ -6,7 +6,7 @@ You have been invited to join the {{OrganizationName}} organization. To accept t
This link expires on {{ExpirationDate}}.
If you do not wish to join this organization, you can safely ignore this email.
{{#if OrganizationCanSponsor}}
{{#jsonIf OrganizationCanSponsor}}
Did you know? Members of {{OrganizationName}} receive a complimentary Families subscription. Learn more here: https://bitwarden.com/help/article/families-for-enterprise/
{{/if}}
{{/jsonIf}}
{{/BasicTextLayout}}

View File

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api.Request.Accounts
{
@ -43,7 +43,7 @@ namespace Bit.Core.Models.Api.Request.Accounts
if (ReferenceData != null)
{
user.ReferenceData = JsonConvert.SerializeObject(ReferenceData);
user.ReferenceData = JsonSerializer.Serialize(ReferenceData);
}
if (Key != null)

View File

@ -1,27 +1,28 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Bit.Billing.Models
{
public class AppleReceiptStatus
{
[JsonProperty("status")]
[JsonPropertyName("status")]
public int? Status { get; set; }
[JsonProperty("environment")]
[JsonPropertyName("environment")]
public string Environment { get; set; }
[JsonProperty("latest_receipt")]
[JsonPropertyName("latest_receipt")]
public string LatestReceipt { get; set; }
[JsonProperty("receipt")]
[JsonPropertyName("receipt")]
public AppleReceipt Receipt { get; set; }
[JsonProperty("latest_receipt_info")]
[JsonPropertyName("latest_receipt_info")]
public List<AppleTransaction> LatestReceiptInfo { get; set; }
[JsonProperty("pending_renewal_info")]
[JsonPropertyName("pending_renewal_info")]
public List<AppleRenewalInfo> PendingRenewalInfo { get; set; }
public string GetOriginalTransactionId()
@ -81,72 +82,59 @@ namespace Bit.Billing.Models
public class AppleReceipt
{
[JsonProperty("receipt_type")]
[JsonPropertyName("receipt_type")]
public string ReceiptType { get; set; }
[JsonProperty("bundle_id")]
[JsonPropertyName("bundle_id")]
public string BundleId { get; set; }
[JsonProperty("receipt_creation_date_ms")]
[JsonPropertyName("receipt_creation_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime ReceiptCreationDate { get; set; }
[JsonProperty("in_app")]
[JsonPropertyName("in_app")]
public List<AppleTransaction> InApp { get; set; }
}
public class AppleRenewalInfo
{
[JsonProperty("expiration_intent")]
[JsonPropertyName("expiration_intent")]
public string ExpirationIntent { get; set; }
[JsonProperty("auto_renew_product_id")]
[JsonPropertyName("auto_renew_product_id")]
public string AutoRenewProductId { get; set; }
[JsonProperty("original_transaction_id")]
[JsonPropertyName("original_transaction_id")]
public string OriginalTransactionId { get; set; }
[JsonProperty("is_in_billing_retry_period")]
[JsonPropertyName("is_in_billing_retry_period")]
public string IsInBillingRetryPeriod { get; set; }
[JsonProperty("product_id")]
[JsonPropertyName("product_id")]
public string ProductId { get; set; }
[JsonProperty("auto_renew_status")]
[JsonPropertyName("auto_renew_status")]
public string AutoRenewStatus { get; set; }
}
public class AppleTransaction
{
[JsonProperty("quantity")]
[JsonPropertyName("quantity")]
public string Quantity { get; set; }
[JsonProperty("product_id")]
[JsonPropertyName("product_id")]
public string ProductId { get; set; }
[JsonProperty("transaction_id")]
[JsonPropertyName("transaction_id")]
public string TransactionId { get; set; }
[JsonProperty("original_transaction_id")]
[JsonPropertyName("original_transaction_id")]
public string OriginalTransactionId { get; set; }
[JsonProperty("purchase_date_ms")]
[JsonPropertyName("purchase_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime PurchaseDate { get; set; }
[JsonProperty("original_purchase_date_ms")]
[JsonPropertyName("original_purchase_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime OriginalPurchaseDate { get; set; }
[JsonProperty("expires_date_ms")]
[JsonPropertyName("expires_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime ExpiresDate { get; set; }
[JsonProperty("cancellation_date_ms")]
[JsonPropertyName("cancellation_date_ms")]
[JsonConverter(typeof(MsEpochConverter))]
public DateTime? CancellationDate { get; set; }
[JsonProperty("web_order_line_item_id")]
[JsonPropertyName("web_order_line_item_id")]
public string WebOrderLineItemId { get; set; }
[JsonProperty("cancellation_reason")]
[JsonPropertyName("cancellation_reason")]
public string CancellationReason { get; set; }
}
public class MsEpochConverter : DateTimeConverterBase
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(CoreHelpers.ToEpocMilliseconds((DateTime)value).ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return CoreHelpers.FromEpocMilliseconds(long.Parse(reader.Value.ToString()));
}
}
}
}

View File

@ -4,11 +4,11 @@ using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Core.Settings;
using Newtonsoft.Json;
namespace Bit.Core.Models.Business
{

View File

@ -1,13 +1,10 @@
using System;
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Bit.Core.Models.Business
{
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class ReferenceEvent
{
public ReferenceEvent() { }
@ -23,10 +20,10 @@ namespace Bit.Core.Models.Business
}
}
[JsonConverter(typeof(StringEnumConverter))]
[JsonConverter(typeof(JsonStringEnumConverter))]
public ReferenceEventType Type { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonConverter(typeof(JsonStringEnumConverter))]
public ReferenceEventSource Source { get; set; }
public Guid Id { get; set; }
@ -52,7 +49,7 @@ namespace Bit.Core.Models.Business
public short? Storage { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonConverter(typeof(JsonStringEnumConverter))]
public SendType? SendType { get; set; }
public int? MaxAccessCount { get; set; }

View File

@ -1,16 +0,0 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace Bit.Core.Models.Business
{
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class ReferenceEventData
{
public string Id { get; set; }
public string Layout { get; set; }
public string Flow { get; set; }
}
}

View File

@ -4,9 +4,9 @@ using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Services;
using Newtonsoft.Json;
namespace Bit.Core.Models.Business
{

View File

@ -1,5 +1,5 @@
using System;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace Bit.Core.Models.Data
{
@ -15,21 +15,14 @@ namespace Bit.Core.Models.Data
{
private long _size;
[JsonIgnore]
// We serialize Size as a string since JSON (or Javascript) doesn't support full precision for long numbers
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public long Size
{
get { return _size; }
set { _size = value; }
}
// We serialize Size as a string since JSON (or Javascript) doesn't support full precision for long numbers
[JsonProperty("Size")]
public string SizeString
{
get { return _size.ToString(); }
set { _size = Convert.ToInt64(value); }
}
public string FileName { get; set; }
public string Key { get; set; }

View File

@ -2,7 +2,6 @@
using System.Collections.Generic;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Newtonsoft.Json;
namespace Bit.Core.Models.Data
{

View File

@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Bit.Core.Enums;
using Newtonsoft.Json;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Data
{
@ -37,13 +38,13 @@ namespace Bit.Core.Models.Data
if (_twoFactorProviders == null)
{
_twoFactorProviders =
JsonConvert.DeserializeObject<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(
JsonHelpers.LegacyDeserialize<Dictionary<TwoFactorProviderType, TwoFactorProvider>>(
TwoFactorProviders);
}
return _twoFactorProviders;
}
catch (JsonSerializationException)
catch (Newtonsoft.Json.JsonException)
{
return null;
}

View File

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace Bit.Core.Models.Data
{
@ -25,7 +25,6 @@ namespace Bit.Core.Models.Data
public bool ManageResetPassword { get; set; }
[JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public List<(bool Permission, string ClaimName)> ClaimsMap => new()
{
(AccessEventLogs, "accesseventlogs"),

View File

@ -1,12 +1,10 @@
using System;
using Newtonsoft.Json;
using System.Text.Json.Serialization;
namespace Bit.Core.Models.Data
{
public class SendFileData : SendData
{
private long _size;
public SendFileData() { }
public SendFileData(string name, string notes, string fileName)
@ -15,20 +13,9 @@ namespace Bit.Core.Models.Data
FileName = fileName;
}
[JsonIgnore]
public long Size
{
get { return _size; }
set { _size = value; }
}
// We serialize Size as a string since JSON (or Javascript) doesn't support full precision for long numbers
[JsonProperty("Size")]
public string SizeString
{
get { return _size.ToString(); }
set { _size = Convert.ToInt64(value); }
}
[JsonNumberHandling(JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString)]
public long Size { get; set; }
public string Id { get; set; }
public string FileName { get; set; }

View File

@ -9,6 +9,6 @@ namespace Bit.Core.Models.Mail
IEnumerable<string> BccEmails { get; set; }
string Category { get; set; }
string TemplateName { get; set; }
dynamic Model { get; set; }
object Model { get; set; }
}
}

View File

@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Models.Mail
{
@ -11,12 +11,13 @@ namespace Bit.Core.Models.Mail
public IEnumerable<string> BccEmails { get; set; }
public string Category { get; set; }
public string TemplateName { get; set; }
[JsonConverter(typeof(ExpandoObjectJsonConverter))]
public dynamic Model { get; set; }
[JsonConverter(typeof(HandlebarsObjectJsonConverter))]
public object Model { get; set; }
public MailQueueMessage() { }
public MailQueueMessage(MailMessage message, string templateName, dynamic model)
public MailQueueMessage(MailMessage message, string templateName, object model)
{
Subject = message.Subject;
ToEmails = message.ToEmails;

View File

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text.Json.Serialization;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Fido2NetLib.Objects;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using PeterO.Cbor;
using U2F.Core.Utils;
@ -102,7 +102,7 @@ namespace Bit.Core.Models
catch
{
// Handle newtonsoft parsing
Descriptor = JsonConvert.DeserializeObject<PublicKeyCredentialDescriptor>(o.Descriptor.ToString());
Descriptor = JsonHelpers.LegacyDeserialize<PublicKeyCredentialDescriptor>(o.Descriptor.ToString());
}
PublicKey = o.PublicKey;
UserHandle = o.UserHandle;

View File

@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Bit.Billing.Models;
using Bit.Core.Repositories;
@ -9,8 +11,6 @@ using Bit.Core.Settings;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.Core.Services
{
@ -97,14 +97,16 @@ namespace Bit.Core.Services
}
var url = string.Format("https://{0}.itunes.apple.com/verifyReceipt", prod ? "buy" : "sandbox");
var json = new JObject(new JProperty("receipt-data", receiptData),
new JProperty("password", _globalSettings.AppleIap.Password)).ToString();
var response = await _httpClient.PostAsync(url, new StringContent(json));
var response = await _httpClient.PostAsJsonAsync(url, new AppleVerifyReceiptRequestModel
{
ReceiptData = receiptData,
Password = _globalSettings.AppleIap.Password
});
if (response.IsSuccessStatusCode)
{
var responseJson = await response.Content.ReadAsStringAsync();
var receiptStatus = JsonConvert.DeserializeObject<AppleReceiptStatus>(responseJson);
var receiptStatus = await response.Content.ReadFromJsonAsync<AppleReceiptStatus>();
if (receiptStatus.Status == 21007)
{
return await GetReceiptStatusAsync(receiptData, false, attempt + 1, receiptStatus);
@ -124,4 +126,12 @@ namespace Bit.Core.Services
return null;
}
}
public class AppleVerifyReceiptRequestModel
{
[JsonPropertyName("receipt-data")]
public string ReceiptData { get; set; }
[JsonPropertyName("password")]
public string Password { get; set; }
}
}

View File

@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Azure.Storage.Queues;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
using Newtonsoft.Json;
using Bit.Core.Utilities;
namespace Bit.Core.Services
{
@ -13,7 +13,9 @@ namespace Bit.Core.Services
{
public AzureQueueEventWriteService(GlobalSettings globalSettings) : base(
new QueueClient(globalSettings.Events.ConnectionString, "event"),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })
JsonHelpers.IgnoreWritingNull)
{ }
public Task CreateAsync(IEvent e) => CreateManyAsync(new[] { e });
}
}

View File

@ -5,7 +5,7 @@ using System.Threading.Tasks;
using Azure.Storage.Queues;
using Bit.Core.Models.Mail;
using Bit.Core.Settings;
using Newtonsoft.Json;
using Bit.Core.Utilities;
namespace Bit.Core.Services
{
@ -13,11 +13,11 @@ namespace Bit.Core.Services
{
public AzureQueueMailService(GlobalSettings globalSettings) : base(
new QueueClient(globalSettings.Mail.ConnectionString, "mail"),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })
JsonHelpers.IgnoreWritingNull)
{ }
public Task EnqueueAsync(IMailQueueMessage message, Func<IMailQueueMessage, Task> fallback) =>
CreateAsync(message);
CreateManyAsync(new[] { message });
public Task EnqueueManyAsync(IEnumerable<IMailQueueMessage> messages, Func<IMailQueueMessage, Task> fallback) =>
CreateManyAsync(messages);

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Storage.Queues;
using Bit.Core.Context;
@ -7,8 +8,8 @@ using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -18,11 +19,6 @@ namespace Bit.Core.Services
private readonly GlobalSettings _globalSettings;
private readonly IHttpContextAccessor _httpContextAccessor;
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
public AzureQueuePushNotificationService(
GlobalSettings globalSettings,
IHttpContextAccessor httpContextAccessor)
@ -170,8 +166,8 @@ namespace Bit.Core.Services
private async Task SendMessageAsync<T>(PushType type, T payload, bool excludeCurrentContext)
{
var contextId = GetContextIdentifier(excludeCurrentContext);
var message = JsonConvert.SerializeObject(new PushNotificationData<T>(type, payload, contextId),
_jsonSettings);
var message = JsonSerializer.Serialize(new PushNotificationData<T>(type, payload, contextId),
JsonHelpers.IgnoreWritingNull);
await _queueClient.SendMessageAsync(message);
}

View File

@ -1,10 +1,11 @@
using System;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Storage.Queues;
using Bit.Core.Models.Business;
using Bit.Core.Settings;
using Newtonsoft.Json;
using Bit.Core.Utilities;
namespace Bit.Core.Services
{
@ -14,10 +15,6 @@ namespace Bit.Core.Services
private readonly QueueClient _queueClient;
private readonly GlobalSettings _globalSettings;
private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
};
public AzureQueueReferenceEventService(
GlobalSettings globalSettings)
@ -40,7 +37,7 @@ namespace Bit.Core.Services
}
try
{
var message = JsonConvert.SerializeObject(referenceEvent, _jsonSerializerSettings);
var message = JsonSerializer.Serialize(referenceEvent, JsonHelpers.IgnoreWritingNullAndCamelCase);
// Messages need to be base64 encoded
var encodedMessage = Convert.ToBase64String(Encoding.UTF8.GetBytes(message));
await _queueClient.SendMessageAsync(encodedMessage);

View File

@ -1,29 +1,22 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Storage.Queues;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
public abstract class AzureQueueService<T>
{
protected QueueClient _queueClient;
protected JsonSerializerSettings _jsonSettings;
protected JsonSerializerOptions _jsonOptions;
protected AzureQueueService(QueueClient queueClient, JsonSerializerSettings jsonSettings)
protected AzureQueueService(QueueClient queueClient, JsonSerializerOptions jsonOptions)
{
_queueClient = queueClient;
_jsonSettings = jsonSettings;
}
public async Task CreateAsync(T message)
{
var json = JsonConvert.SerializeObject(message, _jsonSettings);
var base64 = CoreHelpers.Base64EncodeString(json);
await _queueClient.SendMessageAsync(base64);
_jsonOptions = jsonOptions;
}
public async Task CreateManyAsync(IEnumerable<T> messages)
@ -33,19 +26,13 @@ namespace Bit.Core.Services
return;
}
if (!messages.Skip(1).Any())
{
await CreateAsync(messages.First());
return;
}
foreach (var json in SerializeMany(messages, _jsonSettings))
foreach (var json in SerializeMany(messages, _jsonOptions))
{
await _queueClient.SendMessageAsync(json);
}
}
protected IEnumerable<string> SerializeMany(IEnumerable<T> messages, JsonSerializerSettings jsonSettings)
protected IEnumerable<string> SerializeMany(IEnumerable<T> messages, JsonSerializerOptions jsonOptions)
{
// Calculate Base-64 encoded text with padding
int getBase64Size(int byteCount) => ((4 * byteCount / 3) + 3) & ~3;
@ -69,7 +56,7 @@ namespace Bit.Core.Services
}
var serializedMessages = messages.Select(message =>
JsonConvert.SerializeObject(message, jsonSettings));
JsonSerializer.Serialize(message, jsonOptions));
foreach (var message in serializedMessages)
{

View File

@ -3,23 +3,23 @@ using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Utilities;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.Core.Services
{
public abstract class BaseIdentityClientService
public abstract class BaseIdentityClientService : IDisposable
{
private readonly string _identityScope;
private readonly string _identityClientId;
private readonly string _identityClientSecret;
private readonly ILogger<BaseIdentityClientService> _logger;
private dynamic _decodedToken;
private JsonDocument _decodedToken;
private DateTime? _nextAuthAttempt = null;
public BaseIdentityClientService(
@ -127,9 +127,9 @@ namespace Bit.Core.Services
return false;
}
var responseContent = await response.Content.ReadAsStringAsync();
dynamic tokenResponse = JsonConvert.DeserializeObject(responseContent);
AccessToken = (string)tokenResponse.access_token;
using var jsonDocument = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
AccessToken = jsonDocument.RootElement.GetProperty("access_token").GetString();
return true;
}
@ -145,8 +145,7 @@ namespace Bit.Core.Services
{
if (requestObject != null)
{
var stringContent = JsonConvert.SerializeObject(requestObject);
Content = new StringContent(stringContent, Encoding.UTF8, "application/json");
Content = JsonContent.Create(requestObject);
}
}
}
@ -154,17 +153,16 @@ namespace Bit.Core.Services
protected bool TokenNeedsRefresh(int minutes = 5)
{
var decoded = DecodeToken();
var exp = decoded?["exp"];
if (exp == null)
if (!decoded.RootElement.TryGetProperty("exp", out var expProp))
{
throw new InvalidOperationException("No exp in token.");
}
var expiration = CoreHelpers.FromEpocSeconds(exp.Value<long>());
var expiration = CoreHelpers.FromEpocSeconds(expProp.GetInt64());
return DateTime.UtcNow.AddMinutes(-1 * minutes) > expiration;
}
protected JObject DecodeToken()
protected JsonDocument DecodeToken()
{
if (_decodedToken != null)
{
@ -188,8 +186,13 @@ namespace Bit.Core.Services
throw new InvalidOperationException($"{nameof(AccessToken)} must have 3 parts");
}
_decodedToken = JObject.Parse(Encoding.UTF8.GetString(decodedBytes, 0, decodedBytes.Length));
_decodedToken = JsonDocument.Parse(decodedBytes);
return _decodedToken;
}
public void Dispose()
{
_decodedToken.Dispose();
}
}
}

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -12,7 +13,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Core.Models.Data;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -208,7 +208,7 @@ namespace Bit.Core.Services
UserId = cipher.UserId,
OrganizationId = cipher.OrganizationId,
AttachmentId = attachmentId,
AttachmentData = JsonConvert.SerializeObject(data)
AttachmentData = JsonSerializer.Serialize(data)
});
cipher.AddAttachment(attachmentId, data);
await _pushService.PushSyncCipherUpdateAsync(cipher, null);
@ -241,7 +241,7 @@ namespace Bit.Core.Services
UserId = cipher.UserId,
OrganizationId = cipher.OrganizationId,
AttachmentId = attachmentId,
AttachmentData = JsonConvert.SerializeObject(data)
AttachmentData = JsonSerializer.Serialize(data)
};
await _cipherRepository.UpdateAttachmentAsync(attachment);
@ -312,7 +312,7 @@ namespace Bit.Core.Services
UserId = cipher.UserId,
OrganizationId = cipher.OrganizationId,
AttachmentId = attachmentId,
AttachmentData = JsonConvert.SerializeObject(attachments[attachmentId])
AttachmentData = JsonSerializer.Serialize(attachments[attachmentId])
};
await _cipherRepository.UpdateAttachmentAsync(updatedAttachment);
@ -347,7 +347,7 @@ namespace Bit.Core.Services
UserId = cipher.UserId,
OrganizationId = cipher.OrganizationId,
AttachmentId = attachmentData.AttachmentId,
AttachmentData = JsonConvert.SerializeObject(attachmentData)
AttachmentData = JsonSerializer.Serialize(attachmentData)
};

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Entities;
@ -8,7 +10,6 @@ using Bit.Core.Models.Business.Tokenables;
using Bit.Core.Settings;
using Bit.Core.Tokens;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -77,9 +78,9 @@ namespace Bit.Core.Services
return false;
}
var responseContent = await responseMessage.Content.ReadAsStringAsync();
dynamic jsonResponse = JsonConvert.DeserializeObject(responseContent);
return (bool)jsonResponse.success;
using var jsonDocument = await responseMessage.Content.ReadFromJsonAsync<JsonDocument>();
var root = jsonDocument.RootElement;
return root.GetProperty("success").GetBoolean();
}
public bool RequireCaptchaValidation(ICurrentContext currentContext) =>

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Entities.Provider;
@ -565,6 +566,35 @@ namespace Bit.Core.Services
var clickTrackingText = (clickTrackingOff ? "clicktracking=off" : string.Empty);
writer.WriteSafeString($"<a href=\"{href}\" target=\"_blank\" {clickTrackingText}>{text}</a>");
});
Handlebars.RegisterHelper("jsonIf", (output, options, context, arguments) =>
{
// Special case for JsonElement
if (arguments[0] is JsonElement jsonElement
&& (jsonElement.ValueKind == JsonValueKind.True || jsonElement.ValueKind == JsonValueKind.False))
{
if (jsonElement.GetBoolean())
{
options.Template(output, context);
}
else
{
options.Inverse(output, context);
}
return;
}
// Fallback to normal
if (HandlebarsUtils.IsTruthy(arguments[0]))
{
options.Template(output, context);
}
else
{
options.Inverse(output, context);
}
});
}
public async Task SendEmergencyAccessInviteEmailAsync(EmergencyAccess emergencyAccess, string name, string token)

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Models.Business;
@ -13,7 +14,6 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -246,7 +246,7 @@ namespace Bit.Core.Services
}
var data = File.ReadAllText(filePath, Encoding.UTF8);
return JsonConvert.DeserializeObject<UserLicense>(data);
return JsonSerializer.Deserialize<UserLicense>(data);
}
private OrganizationLicense ReadOrganizationLicense(Organization organization)
@ -258,7 +258,7 @@ namespace Bit.Core.Services
}
var data = File.ReadAllText(filePath, Encoding.UTF8);
return JsonConvert.DeserializeObject<OrganizationLicense>(data);
return JsonSerializer.Deserialize<OrganizationLicense>(data);
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Bit.Core.Context;
@ -11,7 +12,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.NotificationHubs;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -229,7 +229,7 @@ namespace Bit.Core.Services
new Dictionary<string, string>
{
{ "type", ((byte)type).ToString() },
{ "payload", JsonConvert.SerializeObject(payload) }
{ "payload", JsonSerializer.Serialize(payload) }
}, tag);
}

View File

@ -9,7 +9,6 @@ using Bit.Core.Models;
using Bit.Core.Settings;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -18,11 +17,6 @@ namespace Bit.Core.Services
private readonly GlobalSettings _globalSettings;
private readonly IHttpContextAccessor _httpContextAccessor;
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
public NotificationsApiPushNotificationService(
GlobalSettings globalSettings,
IHttpContextAccessor httpContextAccessor,

View File

@ -15,7 +15,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Stripe;
namespace Bit.Core.Services
@ -727,8 +726,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/organization";
Directory.CreateDirectory(dir);
System.IO.File.WriteAllText($"{dir}/{organization.Id}.json",
JsonConvert.SerializeObject(license, Formatting.Indented));
using var fs = System.IO.File.OpenWrite(Path.Combine(dir, $"{organization.Id}.json"));
await JsonSerializer.SerializeAsync(fs, license, JsonHelpers.Indented);
return result;
}
@ -900,8 +899,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/organization";
Directory.CreateDirectory(dir);
System.IO.File.WriteAllText($"{dir}/{organization.Id}.json",
JsonConvert.SerializeObject(license, Formatting.Indented));
using var fs = System.IO.File.OpenWrite(Path.Combine(dir, $"{organization.Id}.json"));
await JsonSerializer.SerializeAsync(fs, license, JsonHelpers.Indented);
organization.Name = license.Name;
organization.BusinessName = license.BusinessName;
@ -1146,10 +1145,7 @@ namespace Bit.Core.Services
if (invite.Permissions != null)
{
orgUser.Permissions = System.Text.Json.JsonSerializer.Serialize(invite.Permissions, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
orgUser.Permissions = JsonSerializer.Serialize(invite.Permissions, JsonHelpers.CamelCase);
}
if (!orgUser.AccessAll && invite.Collections.Any())
@ -1765,7 +1761,7 @@ namespace Bit.Core.Services
// Block the user from withdrawal if auto enrollment is enabled
if (resetPasswordKey == null && resetPasswordPolicy.Data != null)
{
var data = JsonConvert.DeserializeObject<ResetPasswordDataModel>(resetPasswordPolicy.Data);
var data = JsonSerializer.Deserialize<ResetPasswordDataModel>(resetPasswordPolicy.Data);
if (data?.AutoEnrollEnabled ?? false)
{

View File

@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -76,15 +75,13 @@ namespace Bit.Core.Services
request.tag = string.Concat(request.tag, "-Cat_", message.Category);
}
var reqJson = JsonConvert.SerializeObject(request);
var responseMessage = await httpClient.PostAsync(
var responseMessage = await httpClient.PostAsJsonAsync(
$"https://{_globalSettings.Mail.PostalDomain}/api/v1/send/message",
new StringContent(reqJson, Encoding.UTF8, "application/json"));
request);
if (responseMessage.IsSuccessStatusCode)
{
var json = await responseMessage.Content.ReadAsStringAsync();
var response = JsonConvert.DeserializeObject<PostalResponse>(json);
var response = await responseMessage.Content.ReadFromJsonAsync<PostalResponse>();
if (response.status != "success")
{
_logger.LogError("Postal send status was not successful: {0}, {1}",

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Entities;
@ -12,7 +13,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Identity;
using Newtonsoft.Json;
namespace Bit.Core.Services
{
@ -104,8 +104,8 @@ namespace Bit.Core.Services
data.Id = fileId;
data.Size = fileLength;
data.Validated = false;
send.Data = JsonConvert.SerializeObject(data,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
send.Data = JsonSerializer.Serialize(data,
JsonHelpers.IgnoreWritingNull);
await SaveSendAsync(send);
return await _sendFileStorageService.GetSendFileUploadUrlAsync(send, fileId);
}
@ -129,7 +129,7 @@ namespace Bit.Core.Services
throw new BadRequestException("Not a File Type Send.");
}
var data = JsonConvert.DeserializeObject<SendFileData>(send.Data);
var data = JsonSerializer.Deserialize<SendFileData>(send.Data);
if (data.Validated)
{
@ -146,7 +146,7 @@ namespace Bit.Core.Services
public async Task<bool> ValidateSendFile(Send send)
{
var fileData = JsonConvert.DeserializeObject<SendFileData>(send.Data);
var fileData = JsonSerializer.Deserialize<SendFileData>(send.Data);
var (valid, realSize) = await _sendFileStorageService.ValidateFileAsync(send, fileData.Id, fileData.Size, _fileSizeLeeway);
@ -163,8 +163,8 @@ namespace Bit.Core.Services
fileData.Size = realSize.Value;
}
fileData.Validated = true;
send.Data = JsonConvert.SerializeObject(fileData,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
send.Data = JsonSerializer.Serialize(fileData,
JsonHelpers.IgnoreWritingNull);
await SaveSendAsync(send);
return valid;
@ -175,7 +175,7 @@ namespace Bit.Core.Services
await _sendRepository.DeleteAsync(send);
if (send.Type == Enums.SendType.File)
{
var data = JsonConvert.DeserializeObject<SendFileData>(send.Data);
var data = JsonSerializer.Deserialize<SendFileData>(send.Data);
await _sendFileStorageService.DeleteFileAsync(send, data.Id);
}
await _pushService.PushSyncSendDeleteAsync(send);

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Entities;
@ -19,7 +20,6 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using File = System.IO.File;
using U2fLib = U2F.Core.Crypto.U2F;
@ -983,7 +983,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/user";
Directory.CreateDirectory(dir);
File.WriteAllText($"{dir}/{user.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented));
using var fs = File.OpenWrite(Path.Combine(dir, $"{user.Id}.json"));
await JsonSerializer.SerializeAsync(fs, license, JsonHelpers.Indented);
}
else
{
@ -1068,7 +1069,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/user";
Directory.CreateDirectory(dir);
File.WriteAllText($"{dir}/{user.Id}.json", JsonConvert.SerializeObject(license, Formatting.Indented));
using var fs = File.OpenWrite(Path.Combine(dir, $"{user.Id}.json"));
await JsonSerializer.SerializeAsync(fs, license, JsonHelpers.Indented);
user.Premium = license.Premium;
user.RevisionDate = DateTime.UtcNow;

View File

@ -23,7 +23,6 @@ using Bit.Core.Settings;
using IdentityModel;
using Microsoft.AspNetCore.DataProtection;
using MimeKit;
using Newtonsoft.Json;
namespace Bit.Core.Utilities
{
@ -332,12 +331,12 @@ namespace Bit.Core.Utilities
/// <summary>
/// Creates a clone of the given object through serializing to json and deserializing.
/// This method is subject to the limitations of Newstonsoft. For example, properties with
/// This method is subject to the limitations of System.Text.Json. For example, properties with
/// inaccessible setters will not be set.
/// </summary>
public static T CloneObject<T>(T obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
return JsonSerializer.Deserialize<T>(JsonSerializer.Serialize(obj));
}
public static bool SettingHasValue(string setting)

View File

@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Bit.Core.Utilities
{
@ -41,10 +40,8 @@ namespace Bit.Core.Utilities
$"Slow down! Too many requests. Try again in {rule.Period}." : _options.QuotaExceededMessage;
httpContext.Response.Headers["Retry-After"] = retryAfter;
httpContext.Response.StatusCode = _options.HttpStatusCode;
httpContext.Response.ContentType = "application/json";
var errorModel = new ErrorResponseModel { Message = message };
return httpContext.Response.WriteAsync(JsonConvert.SerializeObject(errorModel));
return httpContext.Response.WriteAsJsonAsync(errorModel, cancellationToken: httpContext.RequestAborted);
}
public override void LogBlockedRequest(HttpContext httpContext, ClientRequestIdentity identity,

View File

@ -15,9 +15,9 @@ using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;
using Newtonsoft.Json;
namespace Bit.Core.Utilities.Duo
{
@ -175,7 +175,7 @@ namespace Bit.Core.Utilities.Duo
var res = ApiCall(method, path, parameters, timeout, out var statusCode);
try
{
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(res);
if (dict["stat"] as string == "OK")
{
return dict["response"] as T;

View File

@ -1,21 +0,0 @@
using System;
using Newtonsoft.Json.Serialization;
namespace Bit.Core.Utilities
{
public class EnumKeyResolver<T> : DefaultContractResolver where T : struct
{
protected override 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;
}
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Dynamic;
using Newtonsoft.Json;
namespace Bit.Core.Utilities
{
public class ExpandoObjectJsonConverter : JsonConverter
{
public override bool CanWrite => false;
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return serializer.Deserialize<ExpandoObject>(reader);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Bit.Core.Utilities
{
public class HandlebarsObjectJsonConverter : JsonConverter<object>
{
public override bool CanConvert(Type typeToConvert) => true;
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
}
}

View File

@ -0,0 +1,106 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using NS = Newtonsoft.Json;
namespace Bit.Core.Utilities
{
public static class JsonHelpers
{
public static JsonSerializerOptions Default { get; }
public static JsonSerializerOptions Indented { get; }
public static JsonSerializerOptions IgnoreWritingNull { get; }
public static JsonSerializerOptions CamelCase { get; }
public static JsonSerializerOptions IgnoreWritingNullAndCamelCase { get; }
static JsonHelpers()
{
Default = new JsonSerializerOptions();
Indented = new JsonSerializerOptions
{
WriteIndented = true,
};
IgnoreWritingNull = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
CamelCase = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
IgnoreWritingNullAndCamelCase = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
};
}
// NOTE: This is built into .NET 6, it SHOULD be removed when we upgrade
public static T ToObject<T>(this JsonElement element, JsonSerializerOptions options = null)
{
return JsonSerializer.Deserialize<T>(element.GetRawText(), options ?? Default);
}
public static T DeserializeOrNew<T>(string json, JsonSerializerOptions options = null)
where T : new()
{
if (string.IsNullOrWhiteSpace(json))
{
return new T();
}
return JsonSerializer.Deserialize<T>(json, options);
}
#region Legacy Newtonsoft.Json usage
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();
[Obsolete(LegacyMessage)]
public static string LegacySerialize(object value, NS.JsonSerializerSettings settings = null)
{
return NS.JsonConvert.SerializeObject(value, settings ?? LegacyDefault);
}
[Obsolete(LegacyMessage)]
public static T LegacyDeserialize<T>(string value, NS.JsonSerializerSettings settings = null)
{
return NS.JsonConvert.DeserializeObject<T>(value, settings ?? LegacyDefault);
}
#endregion
}
public class MsEpochConverter : JsonConverter<DateTime?>
{
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
if (!long.TryParse(reader.GetString(), out var milliseconds))
{
return null;
}
return CoreHelpers.FromEpocMilliseconds(milliseconds);
}
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
{
if (!value.HasValue)
{
writer.WriteNullValue();
}
writer.WriteStringValue(CoreHelpers.ToEpocMilliseconds(value.Value).ToString());
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Azure.Storage.Queues;
@ -11,8 +12,6 @@ using Bit.Core.Utilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.EventsProcessor
{
@ -109,30 +108,27 @@ namespace Bit.EventsProcessor
_logger.LogInformation("Processing message.");
var events = new List<IEvent>();
var token = JToken.Parse(message);
if (token is JArray)
using var jsonDocument = JsonDocument.Parse(message);
var root = jsonDocument.RootElement;
if (root.ValueKind == JsonValueKind.Array)
{
var indexedEntities = token.ToObject<List<EventMessage>>()
var indexedEntities = root.ToObject<List<EventMessage>>()
.SelectMany(e => EventTableEntity.IndexEvent(e));
events.AddRange(indexedEntities);
}
else if (token is JObject)
else if (root.ValueKind == JsonValueKind.Object)
{
var eventMessage = token.ToObject<EventMessage>();
var eventMessage = root.ToObject<EventMessage>();
events.AddRange(EventTableEntity.IndexEvent(eventMessage));
}
await _eventWriteService.CreateManyAsync(events);
_logger.LogInformation("Processed message.");
}
catch (JsonReaderException)
catch (JsonException)
{
_logger.LogError("JsonReaderException: Unable to parse message.");
}
catch (JsonSerializationException)
{
_logger.LogError("JsonSerializationException: Unable to serialize token.");
}
}
}
}

View File

@ -3,15 +3,14 @@ using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Core.Models.Data;
using Dapper;
using Newtonsoft.Json;
namespace Bit.Infrastructure.Dapper.Repositories
{
@ -106,8 +105,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task CreateAsync(Cipher cipher, IEnumerable<Guid> collectionIds)
{
cipher.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<CipherWithCollections>(
JsonConvert.SerializeObject(cipher));
var objWithCollections = JsonSerializer.Deserialize<CipherWithCollections>(
JsonSerializer.Serialize(cipher));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using (var connection = new SqlConnection(ConnectionString))
{
@ -133,8 +132,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task CreateAsync(CipherDetails cipher, IEnumerable<Guid> collectionIds)
{
cipher.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<CipherDetailsWithCollections>(
JsonConvert.SerializeObject(cipher));
var objWithCollections = JsonSerializer.Deserialize<CipherDetailsWithCollections>(
JsonSerializer.Serialize(cipher));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using (var connection = new SqlConnection(ConnectionString))
{
@ -170,8 +169,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task<bool> ReplaceAsync(Cipher obj, IEnumerable<Guid> collectionIds)
{
var objWithCollections = JsonConvert.DeserializeObject<CipherWithCollections>(
JsonConvert.SerializeObject(obj));
var objWithCollections = JsonSerializer.Deserialize<CipherWithCollections>(
JsonSerializer.Serialize(obj));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using (var connection = new SqlConnection(ConnectionString))

View File

@ -3,14 +3,13 @@ using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Dapper;
using Newtonsoft.Json;
namespace Bit.Infrastructure.Dapper.Repositories
{
@ -112,7 +111,7 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task CreateAsync(Collection obj, IEnumerable<SelectionReadOnly> groups)
{
obj.SetNewId();
var objWithGroups = JsonConvert.DeserializeObject<CollectionWithGroups>(JsonConvert.SerializeObject(obj));
var objWithGroups = JsonSerializer.Deserialize<CollectionWithGroups>(JsonSerializer.Serialize(obj));
objWithGroups.Groups = groups.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))
@ -126,7 +125,7 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task ReplaceAsync(Collection obj, IEnumerable<SelectionReadOnly> groups)
{
var objWithGroups = JsonConvert.DeserializeObject<CollectionWithGroups>(JsonConvert.SerializeObject(obj));
var objWithGroups = JsonSerializer.Deserialize<CollectionWithGroups>(JsonSerializer.Serialize(obj));
objWithGroups.Groups = groups.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Models.Data;
@ -10,7 +11,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Dapper;
using Newtonsoft.Json;
namespace Bit.Infrastructure.Dapper.Repositories
{
@ -95,7 +95,7 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task CreateAsync(Group obj, IEnumerable<SelectionReadOnly> collections)
{
obj.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<GroupWithCollections>(JsonConvert.SerializeObject(obj));
var objWithCollections = JsonSerializer.Deserialize<GroupWithCollections>(JsonSerializer.Serialize(obj));
objWithCollections.Collections = collections.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))
@ -109,7 +109,7 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task ReplaceAsync(Group obj, IEnumerable<SelectionReadOnly> collections)
{
var objWithCollections = JsonConvert.DeserializeObject<GroupWithCollections>(JsonConvert.SerializeObject(obj));
var objWithCollections = JsonSerializer.Deserialize<GroupWithCollections>(JsonSerializer.Serialize(obj));
objWithCollections.Collections = collections.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -11,7 +12,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Dapper;
using Newtonsoft.Json;
namespace Bit.Infrastructure.Dapper.Repositories
{
@ -244,8 +244,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task<Guid> CreateAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections)
{
obj.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<OrganizationUserWithCollections>(
JsonConvert.SerializeObject(obj));
var objWithCollections = JsonSerializer.Deserialize<OrganizationUserWithCollections>(
JsonSerializer.Serialize(obj));
objWithCollections.Collections = collections.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))
@ -261,8 +261,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task ReplaceAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections)
{
var objWithCollections = JsonConvert.DeserializeObject<OrganizationUserWithCollections>(
JsonConvert.SerializeObject(obj));
var objWithCollections = JsonSerializer.Deserialize<OrganizationUserWithCollections>(
JsonSerializer.Serialize(obj));
objWithCollections.Collections = collections.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString))

View File

@ -1,9 +1,9 @@
using System.Threading;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
namespace Bit.Notifications
{
@ -12,7 +12,7 @@ namespace Bit.Notifications
public static async Task SendNotificationToHubAsync(string notificationJson,
IHubContext<NotificationsHub> hubContext, CancellationToken cancellationToken = default(CancellationToken))
{
var notification = JsonConvert.DeserializeObject<PushNotificationData<object>>(notificationJson);
var notification = JsonSerializer.Deserialize<PushNotificationData<object>>(notificationJson);
switch (notification.Type)
{
case PushType.SyncCipherUpdate:
@ -20,7 +20,7 @@ namespace Bit.Notifications
case PushType.SyncCipherDelete:
case PushType.SyncLoginDelete:
var cipherNotification =
JsonConvert.DeserializeObject<PushNotificationData<SyncCipherPushNotification>>(
JsonSerializer.Deserialize<PushNotificationData<SyncCipherPushNotification>>(
notificationJson);
if (cipherNotification.Payload.UserId.HasValue)
{
@ -38,7 +38,7 @@ namespace Bit.Notifications
case PushType.SyncFolderCreate:
case PushType.SyncFolderDelete:
var folderNotification =
JsonConvert.DeserializeObject<PushNotificationData<SyncFolderPushNotification>>(
JsonSerializer.Deserialize<PushNotificationData<SyncFolderPushNotification>>(
notificationJson);
await hubContext.Clients.User(folderNotification.Payload.UserId.ToString())
.SendAsync("ReceiveMessage", folderNotification, cancellationToken);
@ -49,7 +49,7 @@ namespace Bit.Notifications
case PushType.SyncSettings:
case PushType.LogOut:
var userNotification =
JsonConvert.DeserializeObject<PushNotificationData<UserPushNotification>>(
JsonSerializer.Deserialize<PushNotificationData<UserPushNotification>>(
notificationJson);
await hubContext.Clients.User(userNotification.Payload.UserId.ToString())
.SendAsync("ReceiveMessage", userNotification, cancellationToken);
@ -58,7 +58,7 @@ namespace Bit.Notifications
case PushType.SyncSendUpdate:
case PushType.SyncSendDelete:
var sendNotification =
JsonConvert.DeserializeObject<PushNotificationData<SyncSendPushNotification>>(
JsonSerializer.Deserialize<PushNotificationData<SyncSendPushNotification>>(
notificationJson);
await hubContext.Clients.User(sendNotification.Payload.UserId.ToString())
.SendAsync("ReceiveMessage", sendNotification, cancellationToken);

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using AutoFixture.Xunit2;
using Bit.Api.Controllers;
@ -14,7 +15,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NSubstitute;
using Xunit;
@ -66,7 +66,7 @@ namespace Bit.Api.Test.Controllers
send.Id = default;
send.Type = SendType.Text;
send.Data = JsonConvert.SerializeObject(new Dictionary<string, string>());
send.Data = JsonSerializer.Serialize(new Dictionary<string, string>());
send.HideEmail = true;
_sendService.AccessAsync(id, null).Returns((send, false, false));
@ -81,4 +81,3 @@ namespace Bit.Api.Test.Controllers
}
}
}

View File

@ -1,9 +1,9 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using System.Text.Json;
using Bit.Core.Utilities;
using Xunit;
using Xunit.Sdk;
namespace Bit.Test.Common.Helpers
{
@ -29,10 +29,9 @@ namespace Bit.Test.Common.Helpers
if (actualPropInfo == null)
{
var settings = new JsonSerializerSettings { Formatting = Formatting.Indented };
throw new Exception(string.Concat($"Expected actual object to contain a property named {expectedPropInfo.Name}, but it does not\n",
$"Expected:\n{JsonConvert.SerializeObject(expected, settings)}\n",
$"Actual:\n{JsonConvert.SerializeObject(actual, new JsonSerializerSettings { Formatting = Formatting.Indented })}"));
$"Expected:\n{JsonSerializer.Serialize(expected, JsonHelpers.Indented)}\n",
$"Actual:\n{JsonSerializer.Serialize(actual, JsonHelpers.Indented)}"));
}
if (expectedPropInfo.PropertyType == typeof(string) || expectedPropInfo.PropertyType.IsValueType)
@ -54,5 +53,16 @@ namespace Bit.Test.Common.Helpers
Assert.Equal(expected, actual);
return true;
};
public static JsonElement AssertJsonProperty(JsonElement element, string propertyName, JsonValueKind jsonValueKind)
{
if (!element.TryGetProperty(propertyName, out var subElement))
{
throw new XunitException($"Could not find property by name '{propertyName}'");
}
Assert.Equal(jsonValueKind, subElement.ValueKind);
return subElement;
}
}
}

View File

@ -9,7 +9,7 @@ namespace Bit.Core.Test.AutoFixture.CipherAttachmentMetaData
protected virtual IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
ICustomizationComposer<CipherAttachment.MetaData> composer)
{
return composer.With(d => d.Size, fixture.Create<long>()).Without(d => d.SizeString);
return composer.With(d => d.Size, fixture.Create<long>());
}
public void Customize(IFixture fixture)
{

View File

@ -0,0 +1,41 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Identity;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.Identity
{
public class AuthenticationTokenProviderTests : BaseTokenProviderTests<AuthenticatorTokenProvider>
{
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.Authenticator;
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData
=> SetupCanGenerateData(
(
new Dictionary<string, object>
{
["Key"] = "stuff",
},
true
),
(
new Dictionary<string, object>
{
["Key"] = ""
},
false
)
);
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
public override async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
User user, SutProvider<AuthenticatorTokenProvider> sutProvider)
{
await base.RunCanGenerateTwoFactorTokenAsync(metaData, expectedResponse, user, sutProvider);
}
}
}

View File

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Identity
{
[SutProviderCustomize]
public abstract class BaseTokenProviderTests<T>
where T : IUserTwoFactorTokenProvider<User>
{
public abstract TwoFactorProviderType TwoFactorProviderType { get; }
#region Helpers
protected static IEnumerable<object[]> SetupCanGenerateData(params (Dictionary<string, object> MetaData, bool ExpectedResponse)[] data)
{
return data.Select(d =>
new object[]
{
d.MetaData,
d.ExpectedResponse,
});
}
protected virtual IUserService AdditionalSetup(SutProvider<T> sutProvider, User user)
{
var userService = Substitute.For<IUserService>();
sutProvider.GetDependency<IServiceProvider>()
.GetService(typeof(IUserService))
.Returns(userService);
SetupUserService(userService, user);
return userService;
}
protected virtual void SetupUserService(IUserService userService, User user)
{
userService
.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType, user)
.Returns(true);
}
protected static UserManager<User> SubstituteUserManager()
{
return new UserManager<User>(Substitute.For<IUserStore<User>>(),
Substitute.For<IOptions<IdentityOptions>>(),
Substitute.For<IPasswordHasher<User>>(),
Enumerable.Empty<IUserValidator<User>>(),
Enumerable.Empty<IPasswordValidator<User>>(),
Substitute.For<ILookupNormalizer>(),
Substitute.For<IdentityErrorDescriber>(),
Substitute.For<IServiceProvider>(),
Substitute.For<ILogger<UserManager<User>>>());
}
protected void MockDatabase(User user, Dictionary<string, object> metaData)
{
var providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType] = new TwoFactorProvider
{
Enabled = true,
MetaData = metaData,
},
};
user.TwoFactorProviders = JsonHelpers.LegacySerialize(providers);
}
#endregion
public virtual async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
User user, SutProvider<T> sutProvider)
{
var userManager = SubstituteUserManager();
MockDatabase(user, metaData);
AdditionalSetup(sutProvider, user);
var response = await sutProvider.Sut.CanGenerateTwoFactorTokenAsync(userManager, user);
Assert.Equal(expectedResponse, response);
}
}
}

View File

@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Identity;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Xunit;
namespace Bit.Core.Test.Identity
{
public class EmailTokenProviderTests : BaseTokenProviderTests<EmailTokenProvider>
{
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.Email;
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData
=> SetupCanGenerateData(
(
new Dictionary<string, object>
{
["Email"] = "test@email.com",
},
true
),
(
new Dictionary<string, object>
{
["NotEmail"] = "value",
},
false
),
(
new Dictionary<string, object>
{
["Email"] = "",
},
false
)
);
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
public override async Task RunCanGenerateTwoFactorTokenAsync(Dictionary<string, object> metaData, bool expectedResponse,
User user, SutProvider<EmailTokenProvider> sutProvider)
{
await base.RunCanGenerateTwoFactorTokenAsync(metaData, expectedResponse, user, sutProvider);
}
}
}

View File

@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Identity;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Identity
{
public class U2fTokenProviderTests : BaseTokenProviderTests<U2fTokenProvider>
{
public override TwoFactorProviderType TwoFactorProviderType => TwoFactorProviderType.U2f;
public static IEnumerable<object[]> CanGenerateTwoFactorTokenAsyncData()
{
return new[]
{
new object[]
{
new Dictionary<string, object>
{
["Something"] = "Hello"
},
true, // canAccessPremium
true, // expectedResponse
},
new object[]
{
new Dictionary<string, object>(),
true, // canAccessPremium
false, // expectedResponse
},
new object[]
{
new Dictionary<string, object>
{
["Key"] = "Value"
},
false, // canAccessPremium
false, // expectedResponse
},
};
}
[Theory, BitMemberAutoData(nameof(CanGenerateTwoFactorTokenAsyncData))]
public async Task CanGenerateTwoFactorTokenAsync_Success(Dictionary<string, object> metaData, bool canAccessPremium,
bool expectedResponse, User user, SutProvider<U2fTokenProvider> sutProvider)
{
var userManager = SubstituteUserManager();
MockDatabase(user, metaData);
AdditionalSetup(sutProvider, user)
.CanAccessPremium(user)
.Returns(canAccessPremium);
var response = await sutProvider.Sut.CanGenerateTwoFactorTokenAsync(userManager, user);
Assert.Equal(expectedResponse, response);
}
}
}

View File

@ -1,6 +1,6 @@
using Bit.Core.Entities;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Test.AutoFixture.CipherFixtures;
using Newtonsoft.Json;
using Xunit;
namespace Bit.Core.Test.Models
@ -12,7 +12,7 @@ namespace Bit.Core.Test.Models
[InlineOrganizationCipherAutoData]
public void Clone_CreatesExactCopy(Cipher cipher)
{
Assert.Equal(JsonConvert.SerializeObject(cipher), JsonConvert.SerializeObject(cipher.Clone()));
Assert.Equal(JsonSerializer.Serialize(cipher), JsonSerializer.Serialize(cipher.Clone()));
}
}
}

View File

@ -0,0 +1,28 @@
using System.Text.Json;
using Bit.Core.Models.Data;
using Bit.Test.Common.Helpers;
using Xunit;
namespace Bit.Core.Test.Models.Data
{
public class SendFileDataTests
{
[Fact]
public void Serialize_Success()
{
var sut = new SendFileData
{
Id = "test",
Size = 100,
FileName = "thing.pdf",
Validated = true,
};
var json = JsonSerializer.Serialize(sut);
var document = JsonDocument.Parse(json);
var root = document.RootElement;
AssertHelper.AssertJsonProperty(root, "Size", JsonValueKind.String);
Assert.False(root.TryGetProperty("SizeString", out _));
}
}
}

View File

@ -1,10 +1,6 @@
using System;
using System.Text.Json;
using AutoFixture.Xunit2;
using System.Text.Json;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Xunit;
namespace Bit.Core.Test.Models
@ -33,21 +29,30 @@ namespace Bit.Core.Test.Models
[Fact]
public void Serialization_Success()
{
// minify expected json
var expected = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(_exampleSerializedPermissions));
DefaultContractResolver contractResolver = new DefaultContractResolver
var permissions = new Permissions
{
NamingStrategy = new CamelCaseNamingStrategy()
AccessEventLogs = false,
AccessImportExport = false,
AccessReports = false,
CreateNewCollections = true,
EditAnyCollection = true,
DeleteAnyCollection = true,
EditAssignedCollections = false,
DeleteAssignedCollections = false,
ManageGroups = false,
ManagePolicies = false,
ManageSso = false,
ManageUsers = false,
ManageResetPassword = false,
};
var actual = JsonConvert.SerializeObject(
CoreHelpers.LoadClassFromJsonData<Permissions>(_exampleSerializedPermissions), new JsonSerializerSettings
{
ContractResolver = contractResolver,
});
// minify expected json
var expected = JsonSerializer.Serialize(permissions, JsonHelpers.CamelCase);
var actual = JsonSerializer.Serialize(
JsonHelpers.DeserializeOrNew<Permissions>(_exampleSerializedPermissions, JsonHelpers.CamelCase),
JsonHelpers.CamelCase);
Console.WriteLine(actual);
Assert.Equal(expected, actual);
}
}

View File

@ -1,4 +1,9 @@
using Bit.Core.Entities;
using System.Collections.Generic;
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models;
using Bit.Test.Common.Helpers;
using Xunit;
namespace Bit.Core.Test.Models.Tables
@ -39,5 +44,43 @@ namespace Bit.Core.Test.Models.Tables
Assert.Equal(expectedRemainingBytes, bytesRemaining);
}
[Fact]
public void SetTwoFactorProviders()
{
var user = new User();
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.WebAuthn] = new TwoFactorProvider
{
Enabled = true,
MetaData = new Dictionary<string, object>
{
["Item"] = "thing",
},
},
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
Enabled = false,
MetaData = new Dictionary<string, object>
{
["Email"] = "test@email.com",
},
},
});
using var jsonDocument = JsonDocument.Parse(user.TwoFactorProviders);
var root = jsonDocument.RootElement;
var webAuthn = AssertHelper.AssertJsonProperty(root, "WebAuthn", 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);
AssertHelper.AssertJsonProperty(email, "Enabled", JsonValueKind.False);
var emailMetaData = AssertHelper.AssertJsonProperty(email, "MetaData", JsonValueKind.Object);
AssertHelper.AssertJsonProperty(emailMetaData, "Email", JsonValueKind.String);
}
}
}

View File

@ -1,10 +1,17 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Models.Business;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
using Fido2NetLib;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity;
@ -17,103 +24,41 @@ namespace Bit.Core.Test.Services
{
public class UserServiceTests
{
private readonly UserService _sut;
private readonly IUserRepository _userRepository;
private readonly ICipherRepository _cipherRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IOrganizationRepository _organizationRepository;
private readonly IMailService _mailService;
private readonly IPushNotificationService _pushService;
private readonly IUserStore<User> _userStore;
private readonly IOptions<IdentityOptions> _optionsAccessor;
private readonly IPasswordHasher<User> _passwordHasher;
private readonly IEnumerable<IUserValidator<User>> _userValidators;
private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
private readonly ILookupNormalizer _keyNormalizer;
private readonly IdentityErrorDescriber _errors;
private readonly IServiceProvider _services;
private readonly ILogger<UserManager<User>> _logger;
private readonly ILicensingService _licenseService;
private readonly IEventService _eventService;
private readonly IApplicationCacheService _applicationCacheService;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly IPaymentService _paymentService;
private readonly IPolicyRepository _policyRepository;
private readonly IReferenceEventService _referenceEventService;
private readonly IFido2 _fido2;
private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly IOrganizationService _organizationService;
private readonly IProviderUserRepository _providerUserRepository;
public UserServiceTests()
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task UpdateLicenseAsync_Success(SutProvider<UserService> sutProvider,
User user, UserLicense userLicense)
{
_userRepository = Substitute.For<IUserRepository>();
_cipherRepository = Substitute.For<ICipherRepository>();
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
_organizationRepository = Substitute.For<IOrganizationRepository>();
_mailService = Substitute.For<IMailService>();
_pushService = Substitute.For<IPushNotificationService>();
_userStore = Substitute.For<IUserStore<User>>();
_optionsAccessor = Substitute.For<IOptions<IdentityOptions>>();
_passwordHasher = Substitute.For<IPasswordHasher<User>>();
_userValidators = new List<IUserValidator<User>>();
_passwordValidators = new List<IPasswordValidator<User>>();
_keyNormalizer = Substitute.For<ILookupNormalizer>();
_errors = new IdentityErrorDescriber();
_services = Substitute.For<IServiceProvider>();
_logger = Substitute.For<ILogger<UserManager<User>>>();
_licenseService = Substitute.For<ILicensingService>();
_eventService = Substitute.For<IEventService>();
_applicationCacheService = Substitute.For<IApplicationCacheService>();
_dataProtectionProvider = Substitute.For<IDataProtectionProvider>();
_paymentService = Substitute.For<IPaymentService>();
_policyRepository = Substitute.For<IPolicyRepository>();
_referenceEventService = Substitute.For<IReferenceEventService>();
_fido2 = Substitute.For<IFido2>();
_currentContext = new CurrentContext(null);
_globalSettings = new GlobalSettings();
_organizationService = Substitute.For<IOrganizationService>();
_providerUserRepository = Substitute.For<IProviderUserRepository>();
using var tempDir = new TempDirectory();
_sut = new UserService(
_userRepository,
_cipherRepository,
_organizationUserRepository,
_organizationRepository,
_mailService,
_pushService,
_userStore,
_optionsAccessor,
_passwordHasher,
_userValidators,
_passwordValidators,
_keyNormalizer,
_errors,
_services,
_logger,
_licenseService,
_eventService,
_applicationCacheService,
_dataProtectionProvider,
_paymentService,
_policyRepository,
_referenceEventService,
_fido2,
_currentContext,
_globalSettings,
_organizationService,
_providerUserRepository
);
}
var now = DateTime.UtcNow;
userLicense.Issued = now.AddDays(-10);
userLicense.Expires = now.AddDays(10);
userLicense.Version = 1;
userLicense.Premium = true;
// Remove this test when we add actual tests. It only proves that
// we've properly constructed the system under test.
[Fact]
public void ServiceExists()
{
Assert.NotNull(_sut);
user.EmailVerified = true;
user.Email = userLicense.Email;
sutProvider.GetDependency<Settings.GlobalSettings>().SelfHosted = true;
sutProvider.GetDependency<Settings.GlobalSettings>().LicenseDirectory = tempDir.Directory;
sutProvider.GetDependency<ILicensingService>()
.VerifyLicense(userLicense)
.Returns(true);
await sutProvider.Sut.UpdateLicenseAsync(user, userLicense);
var filePath = Path.Combine(tempDir.Directory, "user", $"{user.Id}.json");
Assert.True(File.Exists(filePath));
var document = JsonDocument.Parse(File.OpenRead(filePath));
var root = document.RootElement;
Assert.Equal(JsonValueKind.Object, root.ValueKind);
// Sort of a lazy way to test that it is indented but not sure of a better way
Assert.Contains('\n', root.GetRawText());
AssertHelper.AssertJsonProperty(root, "LicenseKey", JsonValueKind.String);
AssertHelper.AssertJsonProperty(root, "Id", JsonValueKind.String);
AssertHelper.AssertJsonProperty(root, "Premium", JsonValueKind.True);
var versionProp = AssertHelper.AssertJsonProperty(root, "Version", JsonValueKind.Number);
Assert.Equal(1, versionProp.GetInt32());
}
}
}

View File

@ -0,0 +1,66 @@
using System.Text.Json;
using Bit.Core.Utilities;
using Xunit;
namespace Bit.Core.Test.Helpers
{
public class JsonHelpersTests
{
private static void CompareJson<T>(T value, JsonSerializerOptions options, Newtonsoft.Json.JsonSerializerSettings settings)
{
var stgJson = JsonSerializer.Serialize(value, options);
var nsJson = Newtonsoft.Json.JsonConvert.SerializeObject(value, settings);
Assert.Equal(stgJson, nsJson);
}
[Fact]
public void DefaultJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 0,
Name = "Test",
};
CompareJson(testObject, JsonHelpers.Default, new Newtonsoft.Json.JsonSerializerSettings());
}
[Fact]
public void IndentedJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 10,
Name = "Test Name"
};
CompareJson(testObject, JsonHelpers.Indented, new Newtonsoft.Json.JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
});
}
[Fact]
public void NullValueHandlingJsonOptions()
{
var testObject = new SimpleTestObject
{
Id = 14,
Name = null,
};
CompareJson(testObject, JsonHelpers.IgnoreWritingNull, new Newtonsoft.Json.JsonSerializerSettings
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
});
}
}
public class SimpleTestObject
{
public int Id { get; set; }
public string Name { get; set; }
}
}

View File

@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Data.SqlClient;
using System.Globalization;
using System.Net.Http;
using System.Text.Json;
using Bit.Migrator;
using Newtonsoft.Json;
namespace Bit.Setup
{
@ -273,8 +273,9 @@ namespace Bit.Setup
}
var resultString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var result = JsonConvert.DeserializeObject<dynamic>(resultString);
if (!(bool)result.Enabled)
using var jsonDocument = JsonSerializer.Deserialize<JsonDocument>(resultString);
var root = jsonDocument.RootElement;
if (!root.GetProperty("Enabled").GetBoolean())
{
Console.WriteLine("Installation id has been disabled.");
return false;

View File

@ -12,7 +12,6 @@
<ItemGroup>
<PackageReference Include="Handlebars.Net" Version="1.10.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="YamlDotNet" Version="8.1.2" />
</ItemGroup>