1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-25 12:45:18 +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.Diagnostics;
using System.Net.Http; using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Admin.Models; using Bit.Admin.Models;
using Bit.Core.Settings; using Bit.Core.Settings;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
namespace Bit.Admin.Controllers 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 try
{ {
var response = await _httpClient.GetAsync( 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) if (response.IsSuccessStatusCode)
{ {
var json = await response.Content.ReadAsStringAsync(); using var jsonDocument = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync(cancellationToken), cancellationToken: cancellationToken);
var data = JObject.Parse(json); var root = jsonDocument.RootElement;
var results = data["results"] as JArray;
foreach (var result in results) 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])) if (!string.IsNullOrWhiteSpace(name) && name.Length > 0 && char.IsNumber(name[0]))
{ {
return new JsonResult(name); return new JsonResult(name);
@ -63,17 +65,17 @@ namespace Bit.Admin.Controllers
return new JsonResult("-"); return new JsonResult("-");
} }
public async Task<IActionResult> GetInstalledWebVersion() public async Task<IActionResult> GetInstalledWebVersion(CancellationToken cancellationToken)
{ {
try try
{ {
var response = await _httpClient.GetAsync( var response = await _httpClient.GetAsync(
$"{_globalSettings.BaseServiceUri.InternalVault}/version.json"); $"{_globalSettings.BaseServiceUri.InternalVault}/version.json", cancellationToken);
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
var json = await response.Content.ReadAsStringAsync(); using var jsonDocument = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync(cancellationToken), cancellationToken: cancellationToken);
var data = JObject.Parse(json); var root = jsonDocument.RootElement;
return new JsonResult(data["version"].ToString()); return new JsonResult(root.GetProperty("version").GetString());
} }
} }
catch (HttpRequestException) { } catch (HttpRequestException) { }

View File

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

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Azure.Storage.Queues; using Azure.Storage.Queues;
@ -11,8 +12,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.Admin.HostedServices namespace Bit.Admin.HostedServices
{ {
@ -70,17 +69,19 @@ namespace Bit.Admin.HostedServices
{ {
try try
{ {
var token = JToken.Parse(message.DecodeMessageText()); using var document = JsonDocument.Parse(message.DecodeMessageText());
if (token is JArray) 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); 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); await _mailService.SendEnqueuedMailMessageAsync(mailQueueMessage);
} }
} }

View File

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

View File

@ -1,6 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using Bit.Core.Utilities;
using Microsoft.Azure.Documents; using Microsoft.Azure.Documents;
using Newtonsoft.Json.Linq;
namespace Bit.Admin.Models namespace Bit.Admin.Models
{ {
@ -17,40 +19,48 @@ namespace Bit.Admin.Models
public class LogDetailsModel : LogModel 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) if (e == null)
{ {
return null; return null;
} }
var val = string.Empty; var root = e.RootElement;
if (e["Message"] != null && e["Message"].ToObject<string>() != null)
var sb = new StringBuilder();
if (root.TryGetProperty("Message", out var messageProp) && messageProp.GetString() != null)
{ {
val += "Message:\n"; sb.AppendLine("Message:");
val += e["Message"] + "\n"; 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"; sb.AppendLine();
val += e["StackTrace"]; 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"; sb.AppendLine();
val += e["StackTraceString"]; 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"; sb.AppendLine();
val += ExceptionToString(e["InnerException"].ToObject<JObject>()); 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Azure.Messaging.EventGrid; using Azure.Messaging.EventGrid;
using Bit.Api.Models.Request; using Bit.Api.Models.Request;
@ -21,7 +22,6 @@ using Core.Models.Data;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Api.Controllers namespace Bit.Api.Controllers
{ {
@ -802,7 +802,7 @@ namespace Bit.Api.Controllers
} }
catch (Exception e) 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; return;
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Api.Models.Request; using Bit.Api.Models.Request;
using Bit.Api.Models.Request.Accounts; using Bit.Api.Models.Request.Accounts;
@ -17,7 +18,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace Bit.Api.Controllers namespace Bit.Api.Controllers
{ {
@ -185,7 +185,7 @@ namespace Bit.Api.Controllers
return new OrganizationAutoEnrollStatusResponseModel(organization.Id, false); 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); return new OrganizationAutoEnrollStatusResponseModel(organization.Id, data?.AutoEnrollEnabled ?? false);
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Azure.Messaging.EventGrid; using Azure.Messaging.EventGrid;
using Bit.Api.Models.Request; using Bit.Api.Models.Request;
@ -19,7 +20,6 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Api.Controllers namespace Bit.Api.Controllers
{ {
@ -227,7 +227,7 @@ namespace Bit.Api.Controllers
var userId = _userService.GetProperUserId(User).Value; var userId = _userService.GetProperUserId(User).Value;
var sendId = new Guid(id); var sendId = new Guid(id);
var send = await _sendRepository.GetByIdAsync(sendId); 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) || if (send == null || send.Type != SendType.File || (send.UserId.HasValue && send.UserId.Value != userId) ||
!send.UserId.HasValue || fileData.Id != fileId || fileData.Validated) !send.UserId.HasValue || fileData.Id != fileId || fileData.Validated)
@ -289,7 +289,7 @@ namespace Bit.Api.Controllers
} }
catch (Exception e) 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; return;
} }
} }

View File

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

View File

@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Newtonsoft.Json; using Bit.Core.Utilities;
namespace Bit.Api.Models.Public.Response namespace Bit.Api.Models.Public.Response
{ {
@ -24,7 +25,7 @@ namespace Bit.Api.Models.Public.Response
Enabled = policy.Enabled; Enabled = policy.Enabled;
if (!string.IsNullOrWhiteSpace(policy.Data)) 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.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Core.Models.Data; using Core.Models.Data;
using Newtonsoft.Json; using NS = Newtonsoft.Json;
using Newtonsoft.Json.Linq; using NSL = Newtonsoft.Json.Linq;
namespace Bit.Api.Models.Request namespace Bit.Api.Models.Request
{ {
@ -69,22 +70,20 @@ namespace Bit.Api.Models.Request
switch (existingCipher.Type) switch (existingCipher.Type)
{ {
case CipherType.Login: case CipherType.Login:
var loginObj = JObject.FromObject(ToCipherLoginData(), var loginObj = NSL.JObject.FromObject(ToCipherLoginData(),
new JsonSerializer { NullValueHandling = NullValueHandling.Ignore }); 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(); loginObj[nameof(CipherLoginData.Uri)]?.Parent?.Remove();
existingCipher.Data = loginObj.ToString(Formatting.None); existingCipher.Data = loginObj.ToString(NS.Formatting.None);
break; break;
case CipherType.Card: case CipherType.Card:
existingCipher.Data = JsonConvert.SerializeObject(ToCipherCardData(), existingCipher.Data = JsonSerializer.Serialize(ToCipherCardData(), JsonHelpers.IgnoreWritingNull);
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break; break;
case CipherType.Identity: case CipherType.Identity:
existingCipher.Data = JsonConvert.SerializeObject(ToCipherIdentityData(), existingCipher.Data = JsonSerializer.Serialize(ToCipherIdentityData(), JsonHelpers.IgnoreWritingNull);
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break; break;
case CipherType.SecureNote: case CipherType.SecureNote:
existingCipher.Data = JsonConvert.SerializeObject(ToCipherSecureNoteData(), existingCipher.Data = JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break; break;
default: default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + "."); throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response namespace Bit.Api.Models.Response
{ {
@ -23,7 +23,7 @@ namespace Bit.Api.Models.Response
Enabled = policy.Enabled; Enabled = policy.Enabled;
if (!string.IsNullOrWhiteSpace(policy.Data)) 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;
using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response namespace Bit.Api.Models.Response
{ {
@ -26,12 +26,12 @@ namespace Bit.Api.Models.Response
switch (send.Type) switch (send.Type)
{ {
case SendType.File: case SendType.File:
var fileData = JsonConvert.DeserializeObject<SendFileData>(send.Data); var fileData = JsonSerializer.Deserialize<SendFileData>(send.Data);
sendData = fileData; sendData = fileData;
File = new SendFileModel(fileData); File = new SendFileModel(fileData);
break; break;
case SendType.Text: case SendType.Text:
var textData = JsonConvert.DeserializeObject<SendTextData>(send.Data); var textData = JsonSerializer.Deserialize<SendTextData>(send.Data);
sendData = textData; sendData = textData;
Text = new SendTextModel(textData); Text = new SendTextModel(textData);
break; break;

View File

@ -1,11 +1,11 @@
using System; using System;
using System.Text.Json;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Api.Models.Response namespace Bit.Api.Models.Response
{ {
@ -36,12 +36,12 @@ namespace Bit.Api.Models.Response
switch (send.Type) switch (send.Type)
{ {
case SendType.File: case SendType.File:
var fileData = JsonConvert.DeserializeObject<SendFileData>(send.Data); var fileData = JsonSerializer.Deserialize<SendFileData>(send.Data);
sendData = fileData; sendData = fileData;
File = new SendFileModel(fileData); File = new SendFileModel(fileData);
break; break;
case SendType.Text: case SendType.Text:
var textData = JsonConvert.DeserializeObject<SendTextData>(send.Data); var textData = JsonSerializer.Deserialize<SendTextData>(send.Data);
sendData = textData; sendData = textData;
Text = new SendTextModel(textData); Text = new SendTextModel(textData);
break; 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; using Bit.Core.Utilities;
namespace Bit.Api.Models namespace Bit.Api.Models
@ -11,7 +12,7 @@ namespace Bit.Api.Models
{ {
Id = data.Id; Id = data.Id;
FileName = data.FileName; FileName = data.FileName;
Size = data.SizeString; Size = data.Size;
SizeName = CoreHelpers.ReadableBytesSize(data.Size); SizeName = CoreHelpers.ReadableBytesSize(data.Size);
} }
@ -19,7 +20,8 @@ namespace Bit.Api.Models
[EncryptedString] [EncryptedString]
[EncryptedStringLength(1000)] [EncryptedStringLength(1000)]
public string FileName { get; set; } 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; } public string SizeName { get; set; }
} }
} }

View File

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

View File

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

View File

@ -1,13 +1,13 @@
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Text;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core; using Bit.Core;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace Bit.Billing.Controllers namespace Bit.Billing.Controllers
{ {
@ -53,7 +53,7 @@ namespace Bit.Billing.Controllers
try 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); _logger.LogInformation(Constants.BypassFiltersEventId, "Apple IAP Notification:\n\n{0}", json);
return new OkResult(); return new OkResult();
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@ -12,7 +13,6 @@ using Fido2NetLib;
using Fido2NetLib.Objects; using Fido2NetLib.Objects;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
namespace Bit.Core.Identity namespace Bit.Core.Identity
{ {
@ -98,7 +98,7 @@ namespace Bit.Core.Identity
return false; return false;
} }
var clientResponse = JsonConvert.DeserializeObject<AuthenticatorAssertionRawResponse>(token); var clientResponse = JsonSerializer.Deserialize<AuthenticatorAssertionRawResponse>(token);
var jsonOptions = provider.MetaData["login"].ToString(); var jsonOptions = provider.MetaData["login"].ToString();
var options = AssertionOptions.FromJson(jsonOptions); 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;"> <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"> <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 you do not wish to join this organization, you can safely ignore this email.
{{#if OrganizationCanSponsor}} {{#jsonIf OrganizationCanSponsor}}
<p style="margin-top:10px"> <p style="margin-top:10px">
<b <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;"> 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 Members of {{OrganizationName}} receive a complimentary Families subscription. Learn more at the
following link: https://bitwarden.com/help/article/families-for-enterprise/ following link: https://bitwarden.com/help/article/families-for-enterprise/
</p> </p>
{{/if}} {{/jsonIf}}
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -6,7 +6,7 @@ You have been invited to join the {{OrganizationName}} organization. To accept t
This link expires on {{ExpirationDate}}. This link expires on {{ExpirationDate}}.
If you do not wish to join this organization, you can safely ignore this email. 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/ 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}} {{/BasicTextLayout}}

View File

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

View File

@ -1,27 +1,28 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Bit.Billing.Models namespace Bit.Billing.Models
{ {
public class AppleReceiptStatus public class AppleReceiptStatus
{ {
[JsonProperty("status")] [JsonPropertyName("status")]
public int? Status { get; set; } public int? Status { get; set; }
[JsonProperty("environment")] [JsonPropertyName("environment")]
public string Environment { get; set; } public string Environment { get; set; }
[JsonProperty("latest_receipt")] [JsonPropertyName("latest_receipt")]
public string LatestReceipt { get; set; } public string LatestReceipt { get; set; }
[JsonProperty("receipt")] [JsonPropertyName("receipt")]
public AppleReceipt Receipt { get; set; } public AppleReceipt Receipt { get; set; }
[JsonProperty("latest_receipt_info")] [JsonPropertyName("latest_receipt_info")]
public List<AppleTransaction> LatestReceiptInfo { get; set; } public List<AppleTransaction> LatestReceiptInfo { get; set; }
[JsonProperty("pending_renewal_info")] [JsonPropertyName("pending_renewal_info")]
public List<AppleRenewalInfo> PendingRenewalInfo { get; set; } public List<AppleRenewalInfo> PendingRenewalInfo { get; set; }
public string GetOriginalTransactionId() public string GetOriginalTransactionId()
@ -81,72 +82,59 @@ namespace Bit.Billing.Models
public class AppleReceipt public class AppleReceipt
{ {
[JsonProperty("receipt_type")] [JsonPropertyName("receipt_type")]
public string ReceiptType { get; set; } public string ReceiptType { get; set; }
[JsonProperty("bundle_id")] [JsonPropertyName("bundle_id")]
public string BundleId { get; set; } public string BundleId { get; set; }
[JsonProperty("receipt_creation_date_ms")] [JsonPropertyName("receipt_creation_date_ms")]
[JsonConverter(typeof(MsEpochConverter))] [JsonConverter(typeof(MsEpochConverter))]
public DateTime ReceiptCreationDate { get; set; } public DateTime ReceiptCreationDate { get; set; }
[JsonProperty("in_app")] [JsonPropertyName("in_app")]
public List<AppleTransaction> InApp { get; set; } public List<AppleTransaction> InApp { get; set; }
} }
public class AppleRenewalInfo public class AppleRenewalInfo
{ {
[JsonProperty("expiration_intent")] [JsonPropertyName("expiration_intent")]
public string ExpirationIntent { get; set; } public string ExpirationIntent { get; set; }
[JsonProperty("auto_renew_product_id")] [JsonPropertyName("auto_renew_product_id")]
public string AutoRenewProductId { get; set; } public string AutoRenewProductId { get; set; }
[JsonProperty("original_transaction_id")] [JsonPropertyName("original_transaction_id")]
public string OriginalTransactionId { get; set; } public string OriginalTransactionId { get; set; }
[JsonProperty("is_in_billing_retry_period")] [JsonPropertyName("is_in_billing_retry_period")]
public string IsInBillingRetryPeriod { get; set; } public string IsInBillingRetryPeriod { get; set; }
[JsonProperty("product_id")] [JsonPropertyName("product_id")]
public string ProductId { get; set; } public string ProductId { get; set; }
[JsonProperty("auto_renew_status")] [JsonPropertyName("auto_renew_status")]
public string AutoRenewStatus { get; set; } public string AutoRenewStatus { get; set; }
} }
public class AppleTransaction public class AppleTransaction
{ {
[JsonProperty("quantity")] [JsonPropertyName("quantity")]
public string Quantity { get; set; } public string Quantity { get; set; }
[JsonProperty("product_id")] [JsonPropertyName("product_id")]
public string ProductId { get; set; } public string ProductId { get; set; }
[JsonProperty("transaction_id")] [JsonPropertyName("transaction_id")]
public string TransactionId { get; set; } public string TransactionId { get; set; }
[JsonProperty("original_transaction_id")] [JsonPropertyName("original_transaction_id")]
public string OriginalTransactionId { get; set; } public string OriginalTransactionId { get; set; }
[JsonProperty("purchase_date_ms")] [JsonPropertyName("purchase_date_ms")]
[JsonConverter(typeof(MsEpochConverter))] [JsonConverter(typeof(MsEpochConverter))]
public DateTime PurchaseDate { get; set; } public DateTime PurchaseDate { get; set; }
[JsonProperty("original_purchase_date_ms")] [JsonPropertyName("original_purchase_date_ms")]
[JsonConverter(typeof(MsEpochConverter))] [JsonConverter(typeof(MsEpochConverter))]
public DateTime OriginalPurchaseDate { get; set; } public DateTime OriginalPurchaseDate { get; set; }
[JsonProperty("expires_date_ms")] [JsonPropertyName("expires_date_ms")]
[JsonConverter(typeof(MsEpochConverter))] [JsonConverter(typeof(MsEpochConverter))]
public DateTime ExpiresDate { get; set; } public DateTime ExpiresDate { get; set; }
[JsonProperty("cancellation_date_ms")] [JsonPropertyName("cancellation_date_ms")]
[JsonConverter(typeof(MsEpochConverter))] [JsonConverter(typeof(MsEpochConverter))]
public DateTime? CancellationDate { get; set; } public DateTime? CancellationDate { get; set; }
[JsonProperty("web_order_line_item_id")] [JsonPropertyName("web_order_line_item_id")]
public string WebOrderLineItemId { get; set; } public string WebOrderLineItemId { get; set; }
[JsonProperty("cancellation_reason")] [JsonPropertyName("cancellation_reason")]
public string CancellationReason { get; set; } 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;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Json.Serialization;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Newtonsoft.Json;
namespace Bit.Core.Models.Business namespace Bit.Core.Models.Business
{ {

View File

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

View File

@ -1,5 +1,5 @@
using System; using System;
using Newtonsoft.Json; using System.Text.Json.Serialization;
namespace Bit.Core.Models.Data namespace Bit.Core.Models.Data
{ {
@ -15,21 +15,14 @@ namespace Bit.Core.Models.Data
{ {
private long _size; 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 public long Size
{ {
get { return _size; } get { return _size; }
set { _size = value; } 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 FileName { get; set; }
public string Key { get; set; } public string Key { get; set; }

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,6 @@ namespace Bit.Core.Models.Mail
IEnumerable<string> BccEmails { get; set; } IEnumerable<string> BccEmails { get; set; }
string Category { get; set; } string Category { get; set; }
string TemplateName { 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.Collections.Generic;
using System.Text.Json.Serialization;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Models.Mail namespace Bit.Core.Models.Mail
{ {
@ -11,12 +11,13 @@ namespace Bit.Core.Models.Mail
public IEnumerable<string> BccEmails { get; set; } public IEnumerable<string> BccEmails { get; set; }
public string Category { get; set; } public string Category { get; set; }
public string TemplateName { 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() { }
public MailQueueMessage(MailMessage message, string templateName, dynamic model) public MailQueueMessage(MailMessage message, string templateName, object model)
{ {
Subject = message.Subject; Subject = message.Subject;
ToEmails = message.ToEmails; ToEmails = message.ToEmails;

View File

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

View File

@ -2,6 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Billing.Models; using Bit.Billing.Models;
using Bit.Core.Repositories; using Bit.Core.Repositories;
@ -9,8 +11,6 @@ using Bit.Core.Settings;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.Core.Services 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 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) if (response.IsSuccessStatusCode)
{ {
var responseJson = await response.Content.ReadAsStringAsync(); var receiptStatus = await response.Content.ReadFromJsonAsync<AppleReceiptStatus>();
var receiptStatus = JsonConvert.DeserializeObject<AppleReceiptStatus>(responseJson);
if (receiptStatus.Status == 21007) if (receiptStatus.Status == 21007)
{ {
return await GetReceiptStatusAsync(receiptData, false, attempt + 1, receiptStatus); return await GetReceiptStatusAsync(receiptData, false, attempt + 1, receiptStatus);
@ -124,4 +126,12 @@ namespace Bit.Core.Services
return null; 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 Azure.Storage.Queues;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Settings; using Bit.Core.Settings;
using Newtonsoft.Json; using Bit.Core.Utilities;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -13,7 +13,9 @@ namespace Bit.Core.Services
{ {
public AzureQueueEventWriteService(GlobalSettings globalSettings) : base( public AzureQueueEventWriteService(GlobalSettings globalSettings) : base(
new QueueClient(globalSettings.Events.ConnectionString, "event"), 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 Azure.Storage.Queues;
using Bit.Core.Models.Mail; using Bit.Core.Models.Mail;
using Bit.Core.Settings; using Bit.Core.Settings;
using Newtonsoft.Json; using Bit.Core.Utilities;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -13,11 +13,11 @@ namespace Bit.Core.Services
{ {
public AzureQueueMailService(GlobalSettings globalSettings) : base( public AzureQueueMailService(GlobalSettings globalSettings) : base(
new QueueClient(globalSettings.Mail.ConnectionString, "mail"), new QueueClient(globalSettings.Mail.ConnectionString, "mail"),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }) JsonHelpers.IgnoreWritingNull)
{ } { }
public Task EnqueueAsync(IMailQueueMessage message, Func<IMailQueueMessage, Task> fallback) => public Task EnqueueAsync(IMailQueueMessage message, Func<IMailQueueMessage, Task> fallback) =>
CreateAsync(message); CreateManyAsync(new[] { message });
public Task EnqueueManyAsync(IEnumerable<IMailQueueMessage> messages, Func<IMailQueueMessage, Task> fallback) => public Task EnqueueManyAsync(IEnumerable<IMailQueueMessage> messages, Func<IMailQueueMessage, Task> fallback) =>
CreateManyAsync(messages); CreateManyAsync(messages);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Entities.Provider; using Bit.Core.Entities.Provider;
@ -565,6 +566,35 @@ namespace Bit.Core.Services
var clickTrackingText = (clickTrackingOff ? "clicktracking=off" : string.Empty); var clickTrackingText = (clickTrackingOff ? "clicktracking=off" : string.Empty);
writer.WriteSafeString($"<a href=\"{href}\" target=\"_blank\" {clickTrackingText}>{text}</a>"); 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) public async Task SendEmergencyAccessInviteEmailAsync(EmergencyAccess emergencyAccess, string name, string token)

View File

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
@ -13,7 +14,6 @@ using Bit.Core.Utilities;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -246,7 +246,7 @@ namespace Bit.Core.Services
} }
var data = File.ReadAllText(filePath, Encoding.UTF8); var data = File.ReadAllText(filePath, Encoding.UTF8);
return JsonConvert.DeserializeObject<UserLicense>(data); return JsonSerializer.Deserialize<UserLicense>(data);
} }
private OrganizationLicense ReadOrganizationLicense(Organization organization) private OrganizationLicense ReadOrganizationLicense(Organization organization)
@ -258,7 +258,7 @@ namespace Bit.Core.Services
} }
var data = File.ReadAllText(filePath, Encoding.UTF8); 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Context; using Bit.Core.Context;
@ -11,7 +12,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings; using Bit.Core.Settings;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Azure.NotificationHubs; using Microsoft.Azure.NotificationHubs;
using Newtonsoft.Json;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -229,7 +229,7 @@ namespace Bit.Core.Services
new Dictionary<string, string> new Dictionary<string, string>
{ {
{ "type", ((byte)type).ToString() }, { "type", ((byte)type).ToString() },
{ "payload", JsonConvert.SerializeObject(payload) } { "payload", JsonSerializer.Serialize(payload) }
}, tag); }, tag);
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
@ -19,7 +20,6 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using File = System.IO.File; using File = System.IO.File;
using U2fLib = U2F.Core.Crypto.U2F; using U2fLib = U2F.Core.Crypto.U2F;
@ -983,7 +983,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/user"; var dir = $"{_globalSettings.LicenseDirectory}/user";
Directory.CreateDirectory(dir); 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 else
{ {
@ -1068,7 +1069,8 @@ namespace Bit.Core.Services
var dir = $"{_globalSettings.LicenseDirectory}/user"; var dir = $"{_globalSettings.LicenseDirectory}/user";
Directory.CreateDirectory(dir); 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.Premium = license.Premium;
user.RevisionDate = DateTime.UtcNow; user.RevisionDate = DateTime.UtcNow;

View File

@ -23,7 +23,6 @@ using Bit.Core.Settings;
using IdentityModel; using IdentityModel;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using MimeKit; using MimeKit;
using Newtonsoft.Json;
namespace Bit.Core.Utilities namespace Bit.Core.Utilities
{ {
@ -332,12 +331,12 @@ namespace Bit.Core.Utilities
/// <summary> /// <summary>
/// Creates a clone of the given object through serializing to json and deserializing. /// 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. /// inaccessible setters will not be set.
/// </summary> /// </summary>
public static T CloneObject<T>(T obj) 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) public static bool SettingHasValue(string setting)

View File

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

View File

@ -15,9 +15,9 @@ using System.IO;
using System.Net; using System.Net;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Web; using System.Web;
using Newtonsoft.Json;
namespace Bit.Core.Utilities.Duo namespace Bit.Core.Utilities.Duo
{ {
@ -175,7 +175,7 @@ namespace Bit.Core.Utilities.Duo
var res = ApiCall(method, path, parameters, timeout, out var statusCode); var res = ApiCall(method, path, parameters, timeout, out var statusCode);
try try
{ {
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(res); var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(res);
if (dict["stat"] as string == "OK") if (dict["stat"] as string == "OK")
{ {
return dict["response"] as T; 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Azure.Storage.Queues; using Azure.Storage.Queues;
@ -11,8 +12,6 @@ using Bit.Core.Utilities;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Bit.EventsProcessor namespace Bit.EventsProcessor
{ {
@ -109,30 +108,27 @@ namespace Bit.EventsProcessor
_logger.LogInformation("Processing message."); _logger.LogInformation("Processing message.");
var events = new List<IEvent>(); var events = new List<IEvent>();
var token = JToken.Parse(message); using var jsonDocument = JsonDocument.Parse(message);
if (token is JArray) 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)); .SelectMany(e => EventTableEntity.IndexEvent(e));
events.AddRange(indexedEntities); 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)); events.AddRange(EventTableEntity.IndexEvent(eventMessage));
} }
await _eventWriteService.CreateManyAsync(events); await _eventWriteService.CreateManyAsync(events);
_logger.LogInformation("Processed message."); _logger.LogInformation("Processed message.");
} }
catch (JsonReaderException) catch (JsonException)
{ {
_logger.LogError("JsonReaderException: Unable to parse message."); _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;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities;
using Core.Models.Data; using Core.Models.Data;
using Dapper; using Dapper;
using Newtonsoft.Json;
namespace Bit.Infrastructure.Dapper.Repositories namespace Bit.Infrastructure.Dapper.Repositories
{ {
@ -106,8 +105,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task CreateAsync(Cipher cipher, IEnumerable<Guid> collectionIds) public async Task CreateAsync(Cipher cipher, IEnumerable<Guid> collectionIds)
{ {
cipher.SetNewId(); cipher.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<CipherWithCollections>( var objWithCollections = JsonSerializer.Deserialize<CipherWithCollections>(
JsonConvert.SerializeObject(cipher)); JsonSerializer.Serialize(cipher));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP(); objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using (var connection = new SqlConnection(ConnectionString)) using (var connection = new SqlConnection(ConnectionString))
{ {
@ -133,8 +132,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task CreateAsync(CipherDetails cipher, IEnumerable<Guid> collectionIds) public async Task CreateAsync(CipherDetails cipher, IEnumerable<Guid> collectionIds)
{ {
cipher.SetNewId(); cipher.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<CipherDetailsWithCollections>( var objWithCollections = JsonSerializer.Deserialize<CipherDetailsWithCollections>(
JsonConvert.SerializeObject(cipher)); JsonSerializer.Serialize(cipher));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP(); objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using (var connection = new SqlConnection(ConnectionString)) 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) public async Task<bool> ReplaceAsync(Cipher obj, IEnumerable<Guid> collectionIds)
{ {
var objWithCollections = JsonConvert.DeserializeObject<CipherWithCollections>( var objWithCollections = JsonSerializer.Deserialize<CipherWithCollections>(
JsonConvert.SerializeObject(obj)); JsonSerializer.Serialize(obj));
objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP(); objWithCollections.CollectionIds = collectionIds.ToGuidIdArrayTVP();
using (var connection = new SqlConnection(ConnectionString)) using (var connection = new SqlConnection(ConnectionString))

View File

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

View File

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

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data; using System.Data;
using System.Data.SqlClient; using System.Data.SqlClient;
using System.Linq; using System.Linq;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@ -11,7 +12,6 @@ using Bit.Core.Repositories;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Dapper; using Dapper;
using Newtonsoft.Json;
namespace Bit.Infrastructure.Dapper.Repositories namespace Bit.Infrastructure.Dapper.Repositories
{ {
@ -244,8 +244,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task<Guid> CreateAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections) public async Task<Guid> CreateAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections)
{ {
obj.SetNewId(); obj.SetNewId();
var objWithCollections = JsonConvert.DeserializeObject<OrganizationUserWithCollections>( var objWithCollections = JsonSerializer.Deserialize<OrganizationUserWithCollections>(
JsonConvert.SerializeObject(obj)); JsonSerializer.Serialize(obj));
objWithCollections.Collections = collections.ToArrayTVP(); objWithCollections.Collections = collections.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString)) using (var connection = new SqlConnection(ConnectionString))
@ -261,8 +261,8 @@ namespace Bit.Infrastructure.Dapper.Repositories
public async Task ReplaceAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections) public async Task ReplaceAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections)
{ {
var objWithCollections = JsonConvert.DeserializeObject<OrganizationUserWithCollections>( var objWithCollections = JsonSerializer.Deserialize<OrganizationUserWithCollections>(
JsonConvert.SerializeObject(obj)); JsonSerializer.Serialize(obj));
objWithCollections.Collections = collections.ToArrayTVP(); objWithCollections.Collections = collections.ToArrayTVP();
using (var connection = new SqlConnection(ConnectionString)) 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 System.Threading.Tasks;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models; using Bit.Core.Models;
using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
namespace Bit.Notifications namespace Bit.Notifications
{ {
@ -12,7 +12,7 @@ namespace Bit.Notifications
public static async Task SendNotificationToHubAsync(string notificationJson, public static async Task SendNotificationToHubAsync(string notificationJson,
IHubContext<NotificationsHub> hubContext, CancellationToken cancellationToken = default(CancellationToken)) IHubContext<NotificationsHub> hubContext, CancellationToken cancellationToken = default(CancellationToken))
{ {
var notification = JsonConvert.DeserializeObject<PushNotificationData<object>>(notificationJson); var notification = JsonSerializer.Deserialize<PushNotificationData<object>>(notificationJson);
switch (notification.Type) switch (notification.Type)
{ {
case PushType.SyncCipherUpdate: case PushType.SyncCipherUpdate:
@ -20,7 +20,7 @@ namespace Bit.Notifications
case PushType.SyncCipherDelete: case PushType.SyncCipherDelete:
case PushType.SyncLoginDelete: case PushType.SyncLoginDelete:
var cipherNotification = var cipherNotification =
JsonConvert.DeserializeObject<PushNotificationData<SyncCipherPushNotification>>( JsonSerializer.Deserialize<PushNotificationData<SyncCipherPushNotification>>(
notificationJson); notificationJson);
if (cipherNotification.Payload.UserId.HasValue) if (cipherNotification.Payload.UserId.HasValue)
{ {
@ -38,7 +38,7 @@ namespace Bit.Notifications
case PushType.SyncFolderCreate: case PushType.SyncFolderCreate:
case PushType.SyncFolderDelete: case PushType.SyncFolderDelete:
var folderNotification = var folderNotification =
JsonConvert.DeserializeObject<PushNotificationData<SyncFolderPushNotification>>( JsonSerializer.Deserialize<PushNotificationData<SyncFolderPushNotification>>(
notificationJson); notificationJson);
await hubContext.Clients.User(folderNotification.Payload.UserId.ToString()) await hubContext.Clients.User(folderNotification.Payload.UserId.ToString())
.SendAsync("ReceiveMessage", folderNotification, cancellationToken); .SendAsync("ReceiveMessage", folderNotification, cancellationToken);
@ -49,7 +49,7 @@ namespace Bit.Notifications
case PushType.SyncSettings: case PushType.SyncSettings:
case PushType.LogOut: case PushType.LogOut:
var userNotification = var userNotification =
JsonConvert.DeserializeObject<PushNotificationData<UserPushNotification>>( JsonSerializer.Deserialize<PushNotificationData<UserPushNotification>>(
notificationJson); notificationJson);
await hubContext.Clients.User(userNotification.Payload.UserId.ToString()) await hubContext.Clients.User(userNotification.Payload.UserId.ToString())
.SendAsync("ReceiveMessage", userNotification, cancellationToken); .SendAsync("ReceiveMessage", userNotification, cancellationToken);
@ -58,7 +58,7 @@ namespace Bit.Notifications
case PushType.SyncSendUpdate: case PushType.SyncSendUpdate:
case PushType.SyncSendDelete: case PushType.SyncSendDelete:
var sendNotification = var sendNotification =
JsonConvert.DeserializeObject<PushNotificationData<SyncSendPushNotification>>( JsonSerializer.Deserialize<PushNotificationData<SyncSendPushNotification>>(
notificationJson); notificationJson);
await hubContext.Clients.User(sendNotification.Payload.UserId.ToString()) await hubContext.Clients.User(sendNotification.Payload.UserId.ToString())
.SendAsync("ReceiveMessage", sendNotification, cancellationToken); .SendAsync("ReceiveMessage", sendNotification, cancellationToken);

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using AutoFixture.Xunit2; using AutoFixture.Xunit2;
using Bit.Api.Controllers; using Bit.Api.Controllers;
@ -14,7 +15,6 @@ using Bit.Core.Settings;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NSubstitute; using NSubstitute;
using Xunit; using Xunit;
@ -66,7 +66,7 @@ namespace Bit.Api.Test.Controllers
send.Id = default; send.Id = default;
send.Type = SendType.Text; send.Type = SendType.Text;
send.Data = JsonConvert.SerializeObject(new Dictionary<string, string>()); send.Data = JsonSerializer.Serialize(new Dictionary<string, string>());
send.HideEmail = true; send.HideEmail = true;
_sendService.AccessAsync(id, null).Returns((send, false, false)); _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;
using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Text.Json;
using Newtonsoft.Json; using Bit.Core.Utilities;
using Xunit; using Xunit;
using Xunit.Sdk;
namespace Bit.Test.Common.Helpers namespace Bit.Test.Common.Helpers
{ {
@ -29,10 +29,9 @@ namespace Bit.Test.Common.Helpers
if (actualPropInfo == null) 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", 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", $"Expected:\n{JsonSerializer.Serialize(expected, JsonHelpers.Indented)}\n",
$"Actual:\n{JsonConvert.SerializeObject(actual, new JsonSerializerSettings { Formatting = Formatting.Indented })}")); $"Actual:\n{JsonSerializer.Serialize(actual, JsonHelpers.Indented)}"));
} }
if (expectedPropInfo.PropertyType == typeof(string) || expectedPropInfo.PropertyType.IsValueType) if (expectedPropInfo.PropertyType == typeof(string) || expectedPropInfo.PropertyType.IsValueType)
@ -54,5 +53,16 @@ namespace Bit.Test.Common.Helpers
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
return true; 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, protected virtual IPostprocessComposer<CipherAttachment.MetaData> ComposerAction(IFixture fixture,
ICustomizationComposer<CipherAttachment.MetaData> composer) 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) 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 Bit.Core.Test.AutoFixture.CipherFixtures;
using Newtonsoft.Json;
using Xunit; using Xunit;
namespace Bit.Core.Test.Models namespace Bit.Core.Test.Models
@ -12,7 +12,7 @@ namespace Bit.Core.Test.Models
[InlineOrganizationCipherAutoData] [InlineOrganizationCipherAutoData]
public void Clone_CreatesExactCopy(Cipher cipher) 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 System.Text.Json;
using AutoFixture.Xunit2;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Xunit; using Xunit;
namespace Bit.Core.Test.Models namespace Bit.Core.Test.Models
@ -33,21 +29,30 @@ namespace Bit.Core.Test.Models
[Fact] [Fact]
public void Serialization_Success() public void Serialization_Success()
{ {
// minify expected json var permissions = new Permissions
var expected = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(_exampleSerializedPermissions));
DefaultContractResolver contractResolver = new DefaultContractResolver
{ {
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( // minify expected json
CoreHelpers.LoadClassFromJsonData<Permissions>(_exampleSerializedPermissions), new JsonSerializerSettings var expected = JsonSerializer.Serialize(permissions, JsonHelpers.CamelCase);
{
ContractResolver = contractResolver, var actual = JsonSerializer.Serialize(
}); JsonHelpers.DeserializeOrNew<Permissions>(_exampleSerializedPermissions, JsonHelpers.CamelCase),
JsonHelpers.CamelCase);
Console.WriteLine(actual);
Assert.Equal(expected, 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; using Xunit;
namespace Bit.Core.Test.Models.Tables namespace Bit.Core.Test.Models.Tables
@ -39,5 +44,43 @@ namespace Bit.Core.Test.Models.Tables
Assert.Equal(expectedRemainingBytes, bytesRemaining); 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Models.Business;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
using Fido2NetLib; using Fido2NetLib;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
@ -17,103 +24,41 @@ namespace Bit.Core.Test.Services
{ {
public class UserServiceTests public class UserServiceTests
{ {
private readonly UserService _sut; [Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task UpdateLicenseAsync_Success(SutProvider<UserService> sutProvider,
private readonly IUserRepository _userRepository; User user, UserLicense userLicense)
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()
{ {
_userRepository = Substitute.For<IUserRepository>(); using var tempDir = new TempDirectory();
_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>();
_sut = new UserService( var now = DateTime.UtcNow;
_userRepository, userLicense.Issued = now.AddDays(-10);
_cipherRepository, userLicense.Expires = now.AddDays(10);
_organizationUserRepository, userLicense.Version = 1;
_organizationRepository, userLicense.Premium = true;
_mailService,
_pushService,
_userStore,
_optionsAccessor,
_passwordHasher,
_userValidators,
_passwordValidators,
_keyNormalizer,
_errors,
_services,
_logger,
_licenseService,
_eventService,
_applicationCacheService,
_dataProtectionProvider,
_paymentService,
_policyRepository,
_referenceEventService,
_fido2,
_currentContext,
_globalSettings,
_organizationService,
_providerUserRepository
);
}
// Remove this test when we add actual tests. It only proves that user.EmailVerified = true;
// we've properly constructed the system under test. user.Email = userLicense.Email;
[Fact]
public void ServiceExists() sutProvider.GetDependency<Settings.GlobalSettings>().SelfHosted = true;
{ sutProvider.GetDependency<Settings.GlobalSettings>().LicenseDirectory = tempDir.Directory;
Assert.NotNull(_sut); 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.Data.SqlClient;
using System.Globalization; using System.Globalization;
using System.Net.Http; using System.Net.Http;
using System.Text.Json;
using Bit.Migrator; using Bit.Migrator;
using Newtonsoft.Json;
namespace Bit.Setup namespace Bit.Setup
{ {
@ -273,8 +273,9 @@ namespace Bit.Setup
} }
var resultString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); var resultString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var result = JsonConvert.DeserializeObject<dynamic>(resultString); using var jsonDocument = JsonSerializer.Deserialize<JsonDocument>(resultString);
if (!(bool)result.Enabled) var root = jsonDocument.RootElement;
if (!root.GetProperty("Enabled").GetBoolean())
{ {
Console.WriteLine("Installation id has been disabled."); Console.WriteLine("Installation id has been disabled.");
return false; return false;

View File

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