2015-12-08 22:57:38 -05:00
using System ;
2017-03-21 00:04:39 -04:00
using System.Collections.Generic ;
2021-12-14 15:05:07 +00:00
using System.ComponentModel.DataAnnotations ;
2017-04-04 22:07:30 -04:00
using System.Linq ;
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
2015-12-08 22:57:38 -05:00
{
2016-06-08 22:00:31 -04:00
public class CipherRequestModel
2015-12-08 22:57:38 -05:00
{
public CipherType Type { get ; set ; }
2015-12-30 21:40:19 -05:00
[StringLength(36)]
2017-03-21 00:04:39 -04:00
public string OrganizationId { get ; set ; }
2017-09-20 23:52:45 -04:00
public string FolderId { get ; set ; }
public bool Favorite { get ; set ; }
2021-04-29 15:43:44 +02:00
public CipherRepromptType Reprompt { get ; set ; }
2015-12-08 22:57:38 -05:00
[Required]
[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)]
2017-09-21 10:52:23 -04:00
public string Notes { get ; set ; }
2018-02-28 21:23:46 -05:00
public IEnumerable < CipherFieldModel > Fields { get ; set ; }
2018-07-27 17:49:27 -04:00
public IEnumerable < CipherPasswordHistoryModel > PasswordHistory { get ; set ; }
2018-11-14 17:19:04 -05:00
[Obsolete]
2017-09-21 10:52:23 -04:00
public Dictionary < string , string > Attachments { get ; set ; }
2018-11-14 17:19:04 -05:00
// TODO: Rename to Attachments whenever the above is finally removed.
public Dictionary < string , CipherAttachmentModel > Attachments2 { get ; set ; }
2017-09-21 10:52:23 -04:00
2018-02-28 21:23:46 -05:00
public CipherLoginModel Login { get ; set ; }
public CipherCardModel Card { get ; set ; }
public CipherIdentityModel Identity { get ; set ; }
public CipherSecureNoteModel SecureNote { get ; set ; }
2020-11-23 08:48:05 -06:00
public DateTime ? LastKnownRevisionDate { get ; set ; } = null ;
2017-09-21 10:52:23 -04:00
2018-10-19 12:07:31 -04:00
public CipherDetails ToCipherDetails ( Guid userId , bool allowOrgIdSet = true )
2017-09-20 23:52:45 -04:00
{
2018-10-19 12:07:31 -04:00
var hasOrgId = ! string . IsNullOrWhiteSpace ( OrganizationId ) ;
2017-09-20 23:52:45 -04:00
var cipher = new CipherDetails
{
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 )
{
existingCipher . FolderId = string . IsNullOrWhiteSpace ( FolderId ) ? null : ( Guid ? ) new Guid ( FolderId ) ;
existingCipher . Favorite = Favorite ;
ToCipher ( existingCipher ) ;
return existingCipher ;
}
public Cipher ToCipher ( Cipher existingCipher )
2017-03-21 00:04:39 -04:00
{
2020-03-27 14:36:37 -04:00
switch ( existingCipher . Type )
2015-12-08 22:57:38 -05:00
{
2017-01-02 21:52:13 -05:00
case CipherType . Login :
2022-01-21 09:36:25 -05:00
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
2018-03-01 09:29:49 -05:00
loginObj [ nameof ( CipherLoginData . Uri ) ] ? . Parent ? . Remove ( ) ;
2022-01-21 09:36:25 -05:00
existingCipher . Data = loginObj . ToString ( NS . Formatting . None ) ;
2016-06-08 22:00:31 -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 ) ;
2017-09-21 10:52:23 -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 ) ;
2017-10-06 15:47:31 -04:00
break ;
2017-09-21 10:52:23 -04:00
case CipherType . SecureNote :
2022-01-21 09:36:25 -05:00
existingCipher . Data = JsonSerializer . Serialize ( ToCipherSecureNoteData ( ) , JsonHelpers . IgnoreWritingNull ) ;
2017-09-21 10:52:23 -04:00
break ;
2016-06-08 22:00:31 -04:00
default :
2017-10-06 15:47:31 -04:00
throw new ArgumentException ( "Unsupported type: " + nameof ( Type ) + "." ) ;
2015-12-08 22:57:38 -05:00
}
2016-06-08 22:00:31 -04:00
2021-05-04 20:36:35 +02:00
existingCipher . Reprompt = Reprompt ;
2018-11-14 17:19:04 -05:00
var hasAttachments2 = ( Attachments2 ? . Count ? ? 0 ) > 0 ;
var hasAttachments = ( Attachments ? . Count ? ? 0 ) > 0 ;
2020-03-27 14:36:37 -04:00
if ( ! hasAttachments2 & & ! hasAttachments )
2017-09-13 16:54:23 -04:00
{
return existingCipher ;
}
2017-07-10 14:30:12 -04:00
var attachments = existingCipher . GetAttachments ( ) ;
2020-03-27 14:36:37 -04:00
if ( ( attachments ? . Count ? ? 0 ) = = 0 )
2017-07-10 14:30:12 -04:00
{
2017-09-13 16:54:23 -04:00
return existingCipher ;
}
2017-07-10 14:30:12 -04:00
2020-03-27 14:36:37 -04:00
if ( hasAttachments2 )
2018-11-14 17:19:04 -05:00
{
2020-03-27 14:36:37 -04:00
foreach ( var attachment in attachments . Where ( a = > Attachments2 . ContainsKey ( a . Key ) ) )
2018-11-14 17:19:04 -05:00
{
var attachment2 = Attachments2 [ attachment . Key ] ;
attachment . Value . FileName = attachment2 . FileName ;
attachment . Value . Key = attachment2 . Key ;
}
}
2020-03-27 14:36:37 -04:00
else if ( hasAttachments )
2017-09-13 16:54:23 -04:00
{
2020-03-27 14:36:37 -04:00
foreach ( var attachment in attachments . Where ( a = > Attachments . ContainsKey ( a . Key ) ) )
2018-11-14 17:19:04 -05:00
{
attachment . Value . FileName = Attachments [ attachment . Key ] ;
attachment . Value . Key = null ;
}
2017-07-10 14:30:12 -04:00
}
2017-09-13 16:54:23 -04:00
existingCipher . SetAttachments ( attachments ) ;
2017-07-10 14:30:12 -04:00
return existingCipher ;
}
2017-09-20 23:52:45 -04:00
public Cipher ToOrganizationCipher ( )
{
2020-03-27 14:36:37 -04:00
if ( string . IsNullOrWhiteSpace ( OrganizationId ) )
2017-09-20 23:52:45 -04:00
{
throw new ArgumentNullException ( nameof ( OrganizationId ) ) ;
}
return ToCipher ( new Cipher
{
Type = Type ,
OrganizationId = new Guid ( OrganizationId )
} ) ;
}
2017-09-21 10:52:23 -04:00
2017-09-28 13:11:56 -04:00
public CipherDetails ToOrganizationCipherDetails ( Guid orgId )
{
return ToCipherDetails ( new CipherDetails
{
Type = Type ,
OrganizationId = orgId ,
Edit = true
} ) ;
}
2021-12-14 15:05:07 +00:00
private CipherLoginData ToCipherLoginData ( )
{
return new CipherLoginData
{
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 ,
} ;
}
private CipherIdentityData ToCipherIdentityData ( )
{
return new CipherIdentityData
{
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 ,
} ;
}
private CipherCardData ToCipherCardData ( )
{
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 ,
} ;
}
private CipherSecureNoteData ToCipherSecureNoteData ( )
{
return new CipherSecureNoteData
{
Name = Name ,
Notes = Notes ,
Fields = Fields ? . Select ( f = > f . ToCipherFieldData ( ) ) ,
PasswordHistory = PasswordHistory ? . Select ( ph = > ph . ToCipherPasswordHistoryData ( ) ) ,
Type = SecureNote . Type ,
} ;
}
2017-09-20 23:52:45 -04:00
}
public class CipherWithIdRequestModel : CipherRequestModel
{
[Required]
2018-11-14 17:19:04 -05:00
public Guid ? Id { get ; set ; }
2017-07-10 14:30:12 -04:00
}
2018-10-19 12:07:31 -04:00
public class CipherCreateRequestModel : IValidatableObject
{
public IEnumerable < Guid > CollectionIds { get ; set ; }
[Required]
public CipherRequestModel Cipher { get ; set ; }
public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
{
2020-03-27 14:36:37 -04:00
if ( ! string . IsNullOrWhiteSpace ( Cipher . OrganizationId ) & & ( ! CollectionIds ? . Any ( ) ? ? true ) )
2018-10-19 12:07:31 -04:00
{
yield return new ValidationResult ( "You must select at least one collection." ,
new string [ ] { nameof ( CollectionIds ) } ) ;
}
}
}
2017-04-12 12:42:00 -04:00
public class CipherShareRequestModel : IValidatableObject
2017-03-21 00:04:39 -04:00
{
2017-04-04 22:07:30 -04:00
[Required]
2017-04-27 09:19:30 -04:00
public IEnumerable < string > CollectionIds { get ; set ; }
2017-03-21 00:04:39 -04:00
[Required]
2017-09-13 16:54:23 -04:00
public CipherRequestModel Cipher { get ; set ; }
2017-04-04 22:07:30 -04:00
2017-04-12 12:42:00 -04:00
public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
{
2020-03-27 14:36:37 -04:00
if ( string . IsNullOrWhiteSpace ( Cipher . OrganizationId ) )
2017-04-12 12:42:00 -04:00
{
yield return new ValidationResult ( "Cipher OrganizationId is required." ,
new string [ ] { nameof ( Cipher . OrganizationId ) } ) ;
}
2020-03-27 14:36:37 -04:00
if ( ! CollectionIds ? . Any ( ) ? ? true )
2017-04-12 12:42:00 -04:00
{
2017-04-27 09:19:30 -04:00
yield return new ValidationResult ( "You must select at least one collection." ,
new string [ ] { nameof ( CollectionIds ) } ) ;
2017-04-12 12:42:00 -04:00
}
}
}
2017-04-27 09:19:30 -04:00
public class CipherCollectionsRequestModel
2017-04-12 12:42:00 -04:00
{
[Required]
2017-04-27 09:19:30 -04:00
public IEnumerable < string > CollectionIds { get ; set ; }
2017-03-21 00:04:39 -04:00
}
2017-06-09 00:30:59 -04:00
public class CipherBulkDeleteRequestModel
{
[Required]
public IEnumerable < string > Ids { get ; set ; }
2020-07-22 11:38:53 -05:00
public string OrganizationId { get ; set ; }
2017-06-09 00:30:59 -04:00
}
2020-04-01 13:00:25 -04:00
public class CipherBulkRestoreRequestModel
{
[Required]
public IEnumerable < string > Ids { get ; set ; }
}
2017-06-09 00:30:59 -04:00
public class CipherBulkMoveRequestModel
{
[Required]
public IEnumerable < string > Ids { get ; set ; }
public string FolderId { get ; set ; }
}
2018-06-13 14:03:44 -04:00
2018-08-02 23:13:17 -04:00
public class CipherBulkShareRequestModel : IValidatableObject
2018-06-13 14:03:44 -04:00
{
[Required]
public IEnumerable < string > CollectionIds { get ; set ; }
[Required]
public IEnumerable < CipherWithIdRequestModel > Ciphers { get ; set ; }
public IEnumerable < ValidationResult > Validate ( ValidationContext validationContext )
{
2020-03-27 14:36:37 -04:00
if ( ! Ciphers ? . Any ( ) ? ? true )
2018-06-13 14:03:44 -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 > ( ) ;
2020-03-27 14:36:37 -04:00
foreach ( var c in Ciphers )
2018-06-13 14:03:44 -04:00
{
organizationIds . Add ( c . OrganizationId ) ;
2020-03-27 14:36:37 -04:00
if ( allHaveIds )
2018-06-13 14:03:44 -04:00
{
2018-11-14 17:19:04 -05:00
allHaveIds = ! ( ! c . Id . HasValue | | string . IsNullOrWhiteSpace ( c . OrganizationId ) ) ;
2018-06-13 14:03:44 -04:00
}
}
2020-03-27 14:36:37 -04:00
if ( ! allHaveIds )
2018-06-13 14:03:44 -04:00
{
yield return new ValidationResult ( "All Ciphers must have an Id and OrganizationId." ,
new string [ ] { nameof ( Ciphers ) } ) ;
}
2020-03-27 14:36:37 -04:00
else if ( organizationIds . Count ! = 1 )
2018-06-13 14:03:44 -04:00
{
yield return new ValidationResult ( "All ciphers must be for the same organization." ) ;
}
}
2020-03-27 14:36:37 -04:00
if ( ! CollectionIds ? . Any ( ) ? ? true )
2018-06-13 14:03:44 -04:00
{
yield return new ValidationResult ( "You must select at least one collection." ,
new string [ ] { nameof ( CollectionIds ) } ) ;
}
}
}
2015-12-08 22:57:38 -05:00
}