1
0
mirror of https://github.com/bitwarden/server synced 2025-12-06 00:03:34 +00:00

[PM-7730] Deprecate type-specific cipher properties in favor of opaque Data string (#6354)

* Marked structured fields as obsolete and add Data field to the request model

* Fixed lint issues

* Deprecated properties

* Changed to 1mb
This commit is contained in:
SmithThe4th
2025-09-19 16:17:32 -04:00
committed by GitHub
parent 3ac3b8c8d9
commit d384c0cfe6
2 changed files with 70 additions and 30 deletions

View File

@@ -7,8 +7,6 @@ using Bit.Core.Utilities;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Enums;
using Bit.Core.Vault.Models.Data;
using NS = Newtonsoft.Json;
using NSL = Newtonsoft.Json.Linq;
namespace Bit.Api.Vault.Models.Request;
@@ -40,11 +38,26 @@ public class CipherRequestModel
// TODO: Rename to Attachments whenever the above is finally removed.
public Dictionary<string, CipherAttachmentModel> Attachments2 { get; set; }
[Obsolete("Use Data instead.")]
public CipherLoginModel Login { get; set; }
[Obsolete("Use Data instead.")]
public CipherCardModel Card { get; set; }
[Obsolete("Use Data instead.")]
public CipherIdentityModel Identity { get; set; }
[Obsolete("Use Data instead.")]
public CipherSecureNoteModel SecureNote { get; set; }
[Obsolete("Use Data instead.")]
public CipherSSHKeyModel SSHKey { get; set; }
/// <summary>
/// JSON string containing cipher-specific data
/// </summary>
[StringLength(500000)]
public string Data { get; set; }
public DateTime? LastKnownRevisionDate { get; set; } = null;
public DateTime? ArchivedDate { get; set; }
@@ -73,29 +86,42 @@ public class CipherRequestModel
public Cipher ToCipher(Cipher existingCipher)
{
switch (existingCipher.Type)
// If Data field is provided, use it directly
if (!string.IsNullOrWhiteSpace(Data))
{
case CipherType.Login:
var loginObj = NSL.JObject.FromObject(ToCipherLoginData(),
new NS.JsonSerializer { NullValueHandling = NS.NullValueHandling.Ignore });
// TODO: Switch to JsonNode in .NET 6 https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-use-dom-utf8jsonreader-utf8jsonwriter?pivots=dotnet-6-0
loginObj[nameof(CipherLoginData.Uri)]?.Parent?.Remove();
existingCipher.Data = loginObj.ToString(NS.Formatting.None);
break;
case CipherType.Card:
existingCipher.Data = JsonSerializer.Serialize(ToCipherCardData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.Identity:
existingCipher.Data = JsonSerializer.Serialize(ToCipherIdentityData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.SecureNote:
existingCipher.Data = JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.SSHKey:
existingCipher.Data = JsonSerializer.Serialize(ToCipherSSHKeyData(), JsonHelpers.IgnoreWritingNull);
break;
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
existingCipher.Data = Data;
}
else
{
// Fallback to structured fields
switch (existingCipher.Type)
{
case CipherType.Login:
var loginData = ToCipherLoginData();
var loginJson = JsonSerializer.Serialize(loginData, JsonHelpers.IgnoreWritingNull);
var loginObj = JsonDocument.Parse(loginJson);
var loginDict = JsonSerializer.Deserialize<Dictionary<string, object>>(loginJson);
loginDict?.Remove(nameof(CipherLoginData.Uri));
existingCipher.Data = JsonSerializer.Serialize(loginDict, JsonHelpers.IgnoreWritingNull);
break;
case CipherType.Card:
existingCipher.Data = JsonSerializer.Serialize(ToCipherCardData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.Identity:
existingCipher.Data =
JsonSerializer.Serialize(ToCipherIdentityData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.SecureNote:
existingCipher.Data =
JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.SSHKey:
existingCipher.Data = JsonSerializer.Serialize(ToCipherSSHKeyData(), JsonHelpers.IgnoreWritingNull);
break;
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
}
}
existingCipher.Reprompt = Reprompt;

View File

@@ -24,6 +24,7 @@ public class CipherMiniResponseModel : ResponseModel
Id = cipher.Id;
Type = cipher.Type;
Data = cipher.Data;
CipherData cipherData;
switch (cipher.Type)
@@ -31,30 +32,25 @@ public class CipherMiniResponseModel : ResponseModel
case CipherType.Login:
var loginData = JsonSerializer.Deserialize<CipherLoginData>(cipher.Data);
cipherData = loginData;
Data = loginData;
Login = new CipherLoginModel(loginData);
break;
case CipherType.SecureNote:
var secureNoteData = JsonSerializer.Deserialize<CipherSecureNoteData>(cipher.Data);
Data = secureNoteData;
cipherData = secureNoteData;
SecureNote = new CipherSecureNoteModel(secureNoteData);
break;
case CipherType.Card:
var cardData = JsonSerializer.Deserialize<CipherCardData>(cipher.Data);
Data = cardData;
cipherData = cardData;
Card = new CipherCardModel(cardData);
break;
case CipherType.Identity:
var identityData = JsonSerializer.Deserialize<CipherIdentityData>(cipher.Data);
Data = identityData;
cipherData = identityData;
Identity = new CipherIdentityModel(identityData);
break;
case CipherType.SSHKey:
var sshKeyData = JsonSerializer.Deserialize<CipherSSHKeyData>(cipher.Data);
Data = sshKeyData;
cipherData = sshKeyData;
SSHKey = new CipherSSHKeyModel(sshKeyData);
break;
@@ -80,15 +76,33 @@ public class CipherMiniResponseModel : ResponseModel
public Guid Id { get; set; }
public Guid? OrganizationId { get; set; }
public CipherType Type { get; set; }
public dynamic Data { get; set; }
public string Data { get; set; }
[Obsolete("Use Data instead.")]
public string Name { get; set; }
[Obsolete("Use Data instead.")]
public string Notes { get; set; }
[Obsolete("Use Data instead.")]
public CipherLoginModel Login { get; set; }
[Obsolete("Use Data instead.")]
public CipherCardModel Card { get; set; }
[Obsolete("Use Data instead.")]
public CipherIdentityModel Identity { get; set; }
[Obsolete("Use Data instead.")]
public CipherSecureNoteModel SecureNote { get; set; }
[Obsolete("Use Data instead.")]
public CipherSSHKeyModel SSHKey { get; set; }
[Obsolete("Use Data instead.")]
public IEnumerable<CipherFieldModel> Fields { get; set; }
[Obsolete("Use Data instead.")]
public IEnumerable<CipherPasswordHistoryModel> PasswordHistory { get; set; }
public IEnumerable<AttachmentResponseModel> Attachments { get; set; }
public bool OrganizationUseTotp { get; set; }