Skip to content

Commit d384c0c

Browse files
authored
[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
1 parent 3ac3b8c commit d384c0c

File tree

2 files changed

+70
-30
lines changed

2 files changed

+70
-30
lines changed

src/Api/Vault/Models/Request/CipherRequestModel.cs

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
using Bit.Core.Vault.Entities;
88
using Bit.Core.Vault.Enums;
99
using Bit.Core.Vault.Models.Data;
10-
using NS = Newtonsoft.Json;
11-
using NSL = Newtonsoft.Json.Linq;
1210

1311
namespace Bit.Api.Vault.Models.Request;
1412

@@ -40,11 +38,26 @@ public class CipherRequestModel
4038
// TODO: Rename to Attachments whenever the above is finally removed.
4139
public Dictionary<string, CipherAttachmentModel> Attachments2 { get; set; }
4240

41+
[Obsolete("Use Data instead.")]
4342
public CipherLoginModel Login { get; set; }
43+
44+
[Obsolete("Use Data instead.")]
4445
public CipherCardModel Card { get; set; }
46+
47+
[Obsolete("Use Data instead.")]
4548
public CipherIdentityModel Identity { get; set; }
49+
50+
[Obsolete("Use Data instead.")]
4651
public CipherSecureNoteModel SecureNote { get; set; }
52+
53+
[Obsolete("Use Data instead.")]
4754
public CipherSSHKeyModel SSHKey { get; set; }
55+
56+
/// <summary>
57+
/// JSON string containing cipher-specific data
58+
/// </summary>
59+
[StringLength(500000)]
60+
public string Data { get; set; }
4861
public DateTime? LastKnownRevisionDate { get; set; } = null;
4962
public DateTime? ArchivedDate { get; set; }
5063

@@ -73,29 +86,42 @@ public CipherDetails ToCipherDetails(CipherDetails existingCipher)
7386

7487
public Cipher ToCipher(Cipher existingCipher)
7588
{
76-
switch (existingCipher.Type)
89+
// If Data field is provided, use it directly
90+
if (!string.IsNullOrWhiteSpace(Data))
91+
{
92+
existingCipher.Data = Data;
93+
}
94+
else
7795
{
78-
case CipherType.Login:
79-
var loginObj = NSL.JObject.FromObject(ToCipherLoginData(),
80-
new NS.JsonSerializer { NullValueHandling = NS.NullValueHandling.Ignore });
81-
// 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
82-
loginObj[nameof(CipherLoginData.Uri)]?.Parent?.Remove();
83-
existingCipher.Data = loginObj.ToString(NS.Formatting.None);
84-
break;
85-
case CipherType.Card:
86-
existingCipher.Data = JsonSerializer.Serialize(ToCipherCardData(), JsonHelpers.IgnoreWritingNull);
87-
break;
88-
case CipherType.Identity:
89-
existingCipher.Data = JsonSerializer.Serialize(ToCipherIdentityData(), JsonHelpers.IgnoreWritingNull);
90-
break;
91-
case CipherType.SecureNote:
92-
existingCipher.Data = JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
93-
break;
94-
case CipherType.SSHKey:
95-
existingCipher.Data = JsonSerializer.Serialize(ToCipherSSHKeyData(), JsonHelpers.IgnoreWritingNull);
96-
break;
97-
default:
98-
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
96+
// Fallback to structured fields
97+
switch (existingCipher.Type)
98+
{
99+
case CipherType.Login:
100+
var loginData = ToCipherLoginData();
101+
var loginJson = JsonSerializer.Serialize(loginData, JsonHelpers.IgnoreWritingNull);
102+
var loginObj = JsonDocument.Parse(loginJson);
103+
var loginDict = JsonSerializer.Deserialize<Dictionary<string, object>>(loginJson);
104+
loginDict?.Remove(nameof(CipherLoginData.Uri));
105+
106+
existingCipher.Data = JsonSerializer.Serialize(loginDict, JsonHelpers.IgnoreWritingNull);
107+
break;
108+
case CipherType.Card:
109+
existingCipher.Data = JsonSerializer.Serialize(ToCipherCardData(), JsonHelpers.IgnoreWritingNull);
110+
break;
111+
case CipherType.Identity:
112+
existingCipher.Data =
113+
JsonSerializer.Serialize(ToCipherIdentityData(), JsonHelpers.IgnoreWritingNull);
114+
break;
115+
case CipherType.SecureNote:
116+
existingCipher.Data =
117+
JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
118+
break;
119+
case CipherType.SSHKey:
120+
existingCipher.Data = JsonSerializer.Serialize(ToCipherSSHKeyData(), JsonHelpers.IgnoreWritingNull);
121+
break;
122+
default:
123+
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
124+
}
99125
}
100126

101127
existingCipher.Reprompt = Reprompt;

src/Api/Vault/Models/Response/CipherResponseModel.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,33 @@ public CipherMiniResponseModel(Cipher cipher, IGlobalSettings globalSettings, bo
2424

2525
Id = cipher.Id;
2626
Type = cipher.Type;
27+
Data = cipher.Data;
2728

2829
CipherData cipherData;
2930
switch (cipher.Type)
3031
{
3132
case CipherType.Login:
3233
var loginData = JsonSerializer.Deserialize<CipherLoginData>(cipher.Data);
3334
cipherData = loginData;
34-
Data = loginData;
3535
Login = new CipherLoginModel(loginData);
3636
break;
3737
case CipherType.SecureNote:
3838
var secureNoteData = JsonSerializer.Deserialize<CipherSecureNoteData>(cipher.Data);
39-
Data = secureNoteData;
4039
cipherData = secureNoteData;
4140
SecureNote = new CipherSecureNoteModel(secureNoteData);
4241
break;
4342
case CipherType.Card:
4443
var cardData = JsonSerializer.Deserialize<CipherCardData>(cipher.Data);
45-
Data = cardData;
4644
cipherData = cardData;
4745
Card = new CipherCardModel(cardData);
4846
break;
4947
case CipherType.Identity:
5048
var identityData = JsonSerializer.Deserialize<CipherIdentityData>(cipher.Data);
51-
Data = identityData;
5249
cipherData = identityData;
5350
Identity = new CipherIdentityModel(identityData);
5451
break;
5552
case CipherType.SSHKey:
5653
var sshKeyData = JsonSerializer.Deserialize<CipherSSHKeyData>(cipher.Data);
57-
Data = sshKeyData;
5854
cipherData = sshKeyData;
5955
SSHKey = new CipherSSHKeyModel(sshKeyData);
6056
break;
@@ -80,15 +76,33 @@ public CipherMiniResponseModel(Cipher cipher, IGlobalSettings globalSettings, bo
8076
public Guid Id { get; set; }
8177
public Guid? OrganizationId { get; set; }
8278
public CipherType Type { get; set; }
83-
public dynamic Data { get; set; }
79+
public string Data { get; set; }
80+
81+
[Obsolete("Use Data instead.")]
8482
public string Name { get; set; }
83+
84+
[Obsolete("Use Data instead.")]
8585
public string Notes { get; set; }
86+
87+
[Obsolete("Use Data instead.")]
8688
public CipherLoginModel Login { get; set; }
89+
90+
[Obsolete("Use Data instead.")]
8791
public CipherCardModel Card { get; set; }
92+
93+
[Obsolete("Use Data instead.")]
8894
public CipherIdentityModel Identity { get; set; }
95+
96+
[Obsolete("Use Data instead.")]
8997
public CipherSecureNoteModel SecureNote { get; set; }
98+
99+
[Obsolete("Use Data instead.")]
90100
public CipherSSHKeyModel SSHKey { get; set; }
101+
102+
[Obsolete("Use Data instead.")]
91103
public IEnumerable<CipherFieldModel> Fields { get; set; }
104+
105+
[Obsolete("Use Data instead.")]
92106
public IEnumerable<CipherPasswordHistoryModel> PasswordHistory { get; set; }
93107
public IEnumerable<AttachmentResponseModel> Attachments { get; set; }
94108
public bool OrganizationUseTotp { get; set; }

0 commit comments

Comments
 (0)