2022-06-29 19:46:41 -04:00
using System.ComponentModel.DataAnnotations ;
2022-01-21 09:36:25 -05:00
using System.Text.Json ;
2022-01-11 10:40:51 +01:00
using Bit.Core.Entities ;
2021-12-14 15:05:07 +00:00
using Bit.Core.Enums ;
2018-02-28 21:23:46 -05:00
using Bit.Core.Models.Data ;
2021-12-14 15:05:07 +00:00
using Bit.Core.Utilities ;
using Core.Models.Data ;
2022-01-21 09:36:25 -05:00
using NS = Newtonsoft . Json ;
using NSL = Newtonsoft . Json . Linq ;
2015-12-08 22:57:38 -05:00
2021-12-14 15:05:07 +00:00
namespace Bit.Api.Models.Request ;
2022-08-29 16:06:55 -04:00
2016-06-08 22:00:31 -04:00
public class CipherRequestModel
2015-12-08 22:57:38 -05:00
{
2016-06-08 22:00:31 -04:00
public CipherType Type { get ; set ; }
2022-08-29 16:06:55 -04:00
2015-12-30 21:40:19 -05:00
[StringLength(36)]
2017-03-21 00:04:39 -04:00
public string OrganizationId { get ; set ; }
public string FolderId { get ; set ; }
2016-06-08 22:00:31 -04:00
public bool Favorite { get ; set ; }
public CipherRepromptType Reprompt { get ; set ; }
[Required]
2015-12-08 22:57:38 -05:00
[EncryptedString]
2018-08-02 08:57:32 -04:00
[EncryptedStringLength(1000)]
2015-12-08 22:57:38 -05:00
public string Name { get ; set ; }
[EncryptedString]
2018-08-02 08:57:32 -04:00
[EncryptedStringLength(10000)]
2016-06-08 22:00:31 -04:00
public string Notes { get ; set ; }
2018-02-28 21:23:46 -05:00
public IEnumerable < CipherFieldModel > Fields { get ; set ; }
2016-06-08 22:00:31 -04:00
public IEnumerable < CipherPasswordHistoryModel > PasswordHistory { get ; set ; }
2017-03-21 00:04:39 -04:00
[Obsolete]
public Dictionary < string , string > Attachments { get ; set ; }
// TODO: Rename to Attachments whenever the above is finally removed.
2016-06-08 22:00:31 -04:00
public Dictionary < string , CipherAttachmentModel > Attachments2 { get ; set ; }
2022-08-29 16:06:55 -04:00
2017-03-21 00:04:39 -04:00
public CipherLoginModel Login { get ; set ; }
2018-02-28 21:23:46 -05:00
public CipherCardModel Card { get ; set ; }
public CipherIdentityModel Identity { get ; set ; }
public CipherSecureNoteModel SecureNote { get ; set ; }
2016-06-08 22:00:31 -04:00
public DateTime ? LastKnownRevisionDate { get ; set ; } = null ;
2022-08-29 16:06:55 -04:00
2016-06-08 22:00:31 -04:00
public CipherDetails ToCipherDetails ( Guid userId , bool allowOrgIdSet = true )
2015-12-08 22:57:38 -05:00
{
2017-03-21 00:04:39 -04:00
var hasOrgId = ! string . IsNullOrWhiteSpace ( OrganizationId ) ;
2018-10-19 12:07:31 -04:00
var cipher = new CipherDetails
2017-09-20 23:52:45 -04:00
{
Type = Type ,
2018-10-19 12:07:31 -04:00
UserId = ! hasOrgId ? ( Guid ? ) userId : null ,
OrganizationId = allowOrgIdSet & & hasOrgId ? new Guid ( OrganizationId ) : ( Guid ? ) null ,
2020-06-15 18:54:32 +02:00
Edit = true ,
ViewPassword = true ,
2017-09-20 23:52:45 -04:00
} ;
ToCipherDetails ( cipher ) ;
return cipher ;
}
public CipherDetails ToCipherDetails ( CipherDetails existingCipher )
2017-03-21 00:04:39 -04:00
{
2022-01-21 09:36:25 -05:00
existingCipher . FolderId = string . IsNullOrWhiteSpace ( FolderId ) ? null : ( Guid ? ) new Guid ( FolderId ) ;
existingCipher . Favorite = Favorite ;
ToCipher ( existingCipher ) ;
return existingCipher ;
2015-12-08 22:57:38 -05:00
}
2018-11-14 17:19:04 -05:00
2017-09-20 23:52:45 -04:00
public Cipher ToCipher ( Cipher existingCipher )
2022-08-29 16:06:55 -04:00
{
2020-03-27 14:36:37 -04:00
switch ( existingCipher . Type )
2022-08-29 15:53:48 -04:00
{
2017-01-02 21:52:13 -05:00
case CipherType . Login :
2017-09-13 16:54:23 -04:00
var loginObj = NSL . JObject . FromObject ( ToCipherLoginData ( ) ,
2022-01-21 09:36:25 -05:00
new NS . JsonSerializer { NullValueHandling = NS . NullValueHandling . Ignore } ) ;
2017-09-13 16:54:23 -04:00
// 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 ( ) ;
2022-01-21 09:36:25 -05:00
existingCipher . Data = loginObj . ToString ( NS . Formatting . None ) ;
2022-08-29 15:53:48 -04:00
break ;
2017-09-21 10:52:23 -04:00
case CipherType . Card :
2022-01-21 09:36:25 -05:00
existingCipher . Data = JsonSerializer . Serialize ( ToCipherCardData ( ) , JsonHelpers . IgnoreWritingNull ) ;
2022-08-29 15:53:48 -04:00
break ;
2017-10-06 15:47:31 -04:00
case CipherType . Identity :
2022-01-21 09:36:25 -05:00
existingCipher . Data = JsonSerializer . Serialize ( ToCipherIdentityData ( ) , JsonHelpers . IgnoreWritingNull ) ;
2022-08-29 15:53:48 -04:00
break ;
2017-09-21 10:52:23 -04:00
case CipherType . SecureNote :
2017-09-13 16:54:23 -04:00
existingCipher . Data = JsonSerializer . Serialize ( ToCipherSecureNoteData ( ) , JsonHelpers . IgnoreWritingNull ) ;
2022-08-29 15:53:48 -04:00
break ;
default :
2017-09-13 16:54:23 -04:00
throw new ArgumentException ( "Unsupported type: " + nameof ( Type ) + "." ) ;
2022-08-29 15:53:48 -04:00
}
2017-07-10 14:30:12 -04:00
existingCipher . Reprompt = Reprompt ;
2022-08-29 15:53:48 -04:00
2017-09-28 13:11:56 -04:00
var hasAttachments2 = ( Attachments2 ? . Count ? ? 0 ) > 0 ;
2021-12-14 15:05:07 +00:00
var hasAttachments = ( Attachments ? . Count ? ? 0 ) > 0 ;
2022-08-29 15:53:48 -04:00
2021-12-14 15:05:07 +00:00
if ( ! hasAttachments2 & & ! hasAttachments )
2022-08-29 16:06:55 -04:00
{
2017-07-10 14:30:12 -04:00
return existingCipher ;
}
2017-09-20 23:52:45 -04:00
var attachments = existingCipher . GetAttachments ( ) ;
if ( ( attachments ? . Count ? ? 0 ) = = 0 )
{
return existingCipher ;
}
2017-09-21 10:52:23 -04:00
2017-09-28 13:11:56 -04:00
if ( hasAttachments2 )
{
foreach ( var attachment in attachments . Where ( a = > Attachments2 . ContainsKey ( a . Key ) ) )
{
var attachment2 = Attachments2 [ attachment . Key ] ;
attachment . Value . FileName = attachment2 . FileName ;
attachment . Value . Key = attachment2 . Key ;
}
}
2021-12-14 15:05:07 +00:00
else if ( hasAttachments )
{
foreach ( var attachment in attachments . Where ( a = > Attachments . ContainsKey ( a . Key ) ) )
{
attachment . Value . FileName = Attachments [ attachment . Key ] ;
2020-03-27 14:36:37 -04:00
attachment . Value . Key = null ;
2021-12-14 15:05:07 +00:00
}
}
existingCipher . SetAttachments ( attachments ) ;
return existingCipher ;
}
public Cipher ToOrganizationCipher ( )
2022-08-29 16:06:55 -04:00
{
2021-12-14 15:05:07 +00:00
if ( string . IsNullOrWhiteSpace ( OrganizationId ) )
{
throw new ArgumentNullException ( nameof ( OrganizationId ) ) ;
}
return ToCipher ( new Cipher
{
Type = Type ,
2017-09-20 23:52:45 -04:00
OrganizationId = new Guid ( OrganizationId )
2021-12-14 15:05:07 +00:00
} ) ;
2017-09-20 23:52:45 -04:00
}
public CipherDetails ToOrganizationCipherDetails ( Guid orgId )
{
2018-11-14 17:19:04 -05:00
return ToCipherDetails ( new CipherDetails
{
2017-09-28 13:11:56 -04:00
Type = Type ,
2018-11-14 17:19:04 -05:00
OrganizationId = orgId ,
2022-08-29 16:06:55 -04:00
Edit = true
2018-11-14 17:19:04 -05:00
} ) ;
2017-07-10 14:30:12 -04:00
}
2018-10-19 12:07:31 -04:00
private CipherLoginData ToCipherLoginData ( )
{
return new CipherLoginData
{
2021-12-14 15:05:07 +00:00
Name = Name ,
2020-03-27 14:36:37 -04:00
Notes = Notes ,
Fields = Fields ? . Select ( f = > f . ToCipherFieldData ( ) ) ,
PasswordHistory = PasswordHistory ? . Select ( ph = > ph . ToCipherPasswordHistoryData ( ) ) ,
2022-08-29 16:06:55 -04:00
Uris =
2020-03-27 14:36:37 -04:00
Login . Uris ? . Where ( u = > u ! = null )
2018-10-19 12:07:31 -04:00
. Select ( u = > u . ToCipherLoginUriData ( ) ) ,
Username = Login . Username ,
Password = Login . Password ,
PasswordRevisionDate = Login . PasswordRevisionDate ,
2021-12-14 15:05:07 +00:00
Totp = Login . Totp ,
2018-10-19 12:07:31 -04:00
AutofillOnPageLoad = Login . AutofillOnPageLoad ,
} ;
}
2017-04-12 12:42:00 -04:00
private CipherIdentityData ToCipherIdentityData ( )
2017-03-21 00:04:39 -04:00
{
2017-09-13 16:54:23 -04:00
return new CipherIdentityData
2017-04-12 12:42:00 -04:00
{
2021-12-14 15:05:07 +00:00
Name = Name ,
2017-04-27 09:19:30 -04:00
Notes = Notes ,
Fields = Fields ? . Select ( f = > f . ToCipherFieldData ( ) ) ,
PasswordHistory = PasswordHistory ? . Select ( ph = > ph . ToCipherPasswordHistoryData ( ) ) ,
2022-08-29 16:06:55 -04:00
2021-12-14 15:05:07 +00:00
Title = Identity . Title ,
FirstName = Identity . FirstName ,
2017-04-27 09:19:30 -04:00
MiddleName = Identity . MiddleName ,
LastName = Identity . LastName ,
2021-12-14 15:05:07 +00:00
Address1 = Identity . Address1 ,
2017-04-27 09:19:30 -04:00
Address2 = Identity . Address2 ,
2021-12-14 15:05:07 +00:00
Address3 = Identity . Address3 ,
City = Identity . City ,
2017-04-27 09:19:30 -04:00
State = Identity . State ,
PostalCode = Identity . PostalCode ,
Country = Identity . Country ,
2021-12-14 15:05:07 +00:00
Company = Identity . Company ,
Email = Identity . Email ,
2017-04-27 09:19:30 -04:00
Phone = Identity . Phone ,
SSN = Identity . SSN ,
Username = Identity . Username ,
2021-12-14 15:05:07 +00:00
PassportNumber = Identity . PassportNumber ,
LicenseNumber = Identity . LicenseNumber ,
2017-04-27 09:19:30 -04:00
} ;
2017-04-12 12:42:00 -04:00
}
2017-04-27 09:19:30 -04:00
private CipherCardData ToCipherCardData ( )
2017-04-12 12:42:00 -04:00
{
2017-04-27 09:19:30 -04:00
return new CipherCardData
{
Name = Name ,
2021-12-14 15:05:07 +00:00
Notes = Notes ,
2017-04-27 09:19:30 -04:00
Fields = Fields ? . Select ( f = > f . ToCipherFieldData ( ) ) ,
PasswordHistory = PasswordHistory ? . Select ( ph = > ph . ToCipherPasswordHistoryData ( ) ) ,
2022-08-29 16:06:55 -04:00
2017-04-27 09:19:30 -04:00
CardholderName = Card . CardholderName ,
Brand = Card . Brand ,
Number = Card . Number ,
ExpMonth = Card . ExpMonth ,
2021-12-14 15:05:07 +00:00
ExpYear = Card . ExpYear ,
2017-04-27 09:19:30 -04:00
Code = Card . Code ,
} ;
2017-03-21 00:04:39 -04:00
}
2017-06-09 00:30:59 -04:00
private CipherSecureNoteData ToCipherSecureNoteData ( )
{
return new CipherSecureNoteData
{
Name = Name ,
2021-12-14 15:05:07 +00:00
Notes = Notes ,
2017-06-09 00:30:59 -04:00
Fields = Fields ? . Select ( f = > f . ToCipherFieldData ( ) ) ,
2020-07-22 11:38:53 -05:00
PasswordHistory = PasswordHistory ? . Select ( ph = > ph . ToCipherPasswordHistoryData ( ) ) ,
2022-08-29 16:06:55 -04:00
2020-07-22 11:38:53 -05:00
Type = SecureNote . Type ,
} ;
2017-06-09 00:30:59 -04:00
}
2022-08-29 16:06:55 -04:00
}
2017-06-09 00:30:59 -04:00
2020-04-01 13:00:25 -04:00
public class CipherWithIdRequestModel : CipherRequestModel
2022-08-29 16:06:55 -04:00
{
2018-11-14 17:19:04 -05:00
[Required]
2018-10-19 12:07:31 -04:00
public Guid ? Id { get ; set ; }
2022-08-29 16:06:55 -04:00
}
2018-06-13 14:03:44 -04:00
public class CipherCreateRequestModel : IValidatableObject
2022-08-29 16:06:55 -04:00
{
2018-10-19 12:07:31 -04:00
public IEnumerable < Guid > CollectionIds { get ; set ; }
[Required]
2018-06-13 14:03:44 -04:00
public CipherRequestModel Cipher { get ; set ; }
2022-08-29 16:06:55 -04:00
2020-04-01 13:00:25 -04:00
public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
{
if ( ! string . IsNullOrWhiteSpace ( Cipher . OrganizationId ) & & ( ! CollectionIds ? . Any ( ) ? ? true ) )
2022-08-29 16:06:55 -04:00
{
2020-04-01 13:00:25 -04:00
yield return new ValidationResult ( "You must select at least one collection." ,
new string [ ] { nameof ( CollectionIds ) } ) ;
}
}
2022-08-29 16:06:55 -04:00
}
2018-06-13 14:03:44 -04:00
public class CipherShareRequestModel : IValidatableObject
2022-08-29 16:06:55 -04:00
{
2017-04-04 22:07:30 -04:00
[Required]
2017-09-13 16:54:23 -04:00
public IEnumerable < string > CollectionIds { get ; set ; }
2017-03-21 00:04:39 -04:00
[Required]
2018-06-13 14:03:44 -04:00
public CipherRequestModel Cipher { get ; set ; }
2020-04-01 13:00:25 -04:00
2017-06-09 00:30:59 -04:00
public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
{
2017-04-27 09:19:30 -04:00
if ( string . IsNullOrWhiteSpace ( Cipher . OrganizationId ) )
2022-08-29 16:06:55 -04:00
{
2017-06-09 00:30:59 -04:00
yield return new ValidationResult ( "Cipher OrganizationId is required." ,
new string [ ] { nameof ( Cipher . OrganizationId ) } ) ;
}
2022-08-29 16:06:55 -04:00
2017-06-09 00:30:59 -04:00
if ( ! CollectionIds ? . Any ( ) ? ? true )
2022-08-29 16:06:55 -04:00
{
2017-06-09 00:30:59 -04:00
yield return new ValidationResult ( "You must select at least one collection." ,
new string [ ] { nameof ( CollectionIds ) } ) ;
}
}
2022-08-29 16:06:55 -04:00
}
2018-06-13 14:03:44 -04:00
2017-04-27 09:19:30 -04:00
public class CipherCollectionsRequestModel
2022-08-29 16:06:55 -04:00
{
2017-04-27 09:19:30 -04:00
[Required]
2017-09-13 16:54:23 -04:00
public IEnumerable < string > CollectionIds { get ; set ; }
2022-08-29 16:06:55 -04:00
}
2017-06-09 00:30:59 -04:00
public class CipherBulkDeleteRequestModel
2022-08-29 16:06:55 -04:00
{
2017-04-27 09:19:30 -04:00
[Required]
2017-09-13 16:54:23 -04:00
public IEnumerable < string > Ids { get ; set ; }
2020-07-22 11:38:53 -05:00
public string OrganizationId { get ; set ; }
2022-08-29 16:06:55 -04:00
}
2017-06-09 00:30:59 -04:00
public class CipherBulkRestoreRequestModel
2022-08-29 16:06:55 -04:00
{
2020-04-01 13:00:25 -04:00
[Required]
2017-09-13 16:54:23 -04:00
public IEnumerable < string > Ids { get ; set ; }
2022-08-29 16:06:55 -04:00
}
2017-06-09 00:30:59 -04:00
public class CipherBulkMoveRequestModel
2022-08-29 16:06:55 -04:00
{
2020-04-01 13:00:25 -04:00
[Required]
2017-09-13 16:54:23 -04:00
public IEnumerable < string > Ids { get ; set ; }
2017-03-21 00:04:39 -04:00
public string FolderId { get ; set ; }
2022-08-29 16:06:55 -04:00
}
2018-06-13 14:03:44 -04:00
public class CipherBulkShareRequestModel : IValidatableObject
2022-08-29 14:53:16 -04:00
{
2018-06-13 14:03:44 -04:00
[Required]
2020-03-27 14:36:37 -04:00
public IEnumerable < string > CollectionIds { get ; set ; }
2018-06-13 14:03:44 -04:00
[Required]
public IEnumerable < CipherWithIdRequestModel > Ciphers { get ; set ; }
2022-08-29 15:53:48 -04:00
2018-06-13 14:03:44 -04:00
public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
2022-08-29 16:06:55 -04:00
{
2020-03-27 14:36:37 -04:00
if ( ! Ciphers ? . Any ( ) ? ? true )
2022-08-29 14:53:16 -04:00
{
2018-06-13 14:03:44 -04:00
yield return new ValidationResult ( "You must select at least one cipher." ,
new string [ ] { nameof ( Ciphers ) } ) ;
2022-08-29 15:53:48 -04:00
}
else
2022-08-29 16:06:55 -04:00
{
2018-06-13 14:03:44 -04:00
var allHaveIds = true ;
var organizationIds = new HashSet < string > ( ) ;
2020-03-27 14:36:37 -04:00
foreach ( var c in Ciphers )
2022-08-29 15:53:48 -04:00
{
2017-09-20 23:52:45 -04:00
organizationIds . Add ( c . OrganizationId ) ;
2020-03-27 14:36:37 -04:00
if ( allHaveIds )
2022-08-29 15:53:48 -04:00
{
2018-06-13 14:03:44 -04:00
allHaveIds = ! ( ! c . Id . HasValue | | string . IsNullOrWhiteSpace ( c . OrganizationId ) ) ;
2022-08-29 15:53:48 -04:00
}
2022-08-29 14:53:16 -04:00
}
2022-08-29 15:53:48 -04:00
2018-06-13 14:03:44 -04:00
if ( ! allHaveIds )
2022-08-29 14:53:16 -04:00
{
2018-06-13 14:03:44 -04:00
yield return new ValidationResult ( "All Ciphers must have an Id and OrganizationId." ,
new string [ ] { nameof ( Ciphers ) } ) ;
2022-08-29 16:06:55 -04:00
}
2018-06-13 14:03:44 -04:00
else if ( organizationIds . Count ! = 1 )
2022-08-29 16:06:55 -04:00
{
2018-06-13 14:03:44 -04:00
yield return new ValidationResult ( "All ciphers must be for the same organization." ) ;
}
}
2022-08-29 16:06:55 -04:00
2021-12-14 15:05:07 +00:00
if ( ! CollectionIds ? . Any ( ) ? ? true )
2022-08-29 16:06:55 -04:00
{
2018-06-13 14:03:44 -04:00
yield return new ValidationResult ( "You must select at least one collection." ,
2018-10-19 12:07:31 -04:00
new string [ ] { nameof ( CollectionIds ) } ) ;
2022-08-29 16:06:55 -04:00
}
2018-06-13 14:03:44 -04:00
}
2015-12-08 22:57:38 -05:00
}