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