1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

Move request/response models (#1754)

This commit is contained in:
Oscar Hinton
2021-12-14 15:05:07 +00:00
committed by GitHub
parent 3ae573bd8d
commit 63f6dd9a24
206 changed files with 641 additions and 516 deletions

View File

@ -1,21 +0,0 @@
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class CipherAttachmentModel
{
public CipherAttachmentModel() { }
public CipherAttachmentModel(CipherAttachment.MetaData data)
{
FileName = data.FileName;
Key = data.Key;
}
[EncryptedStringLength(1000)]
public string FileName { get; set; }
[EncryptedStringLength(1000)]
public string Key { get; set; }
}
}

View File

@ -1,40 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class CipherCardModel
{
public CipherCardModel() { }
public CipherCardModel(CipherCardData data)
{
CardholderName = data.CardholderName;
Brand = data.Brand;
Number = data.Number;
ExpMonth = data.ExpMonth;
ExpYear = data.ExpYear;
Code = data.Code;
}
[EncryptedString]
[EncryptedStringLength(1000)]
public string CardholderName { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Brand { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Number { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string ExpMonth { get; set; }
[EncryptedString]
[StringLength(1000)]
public string ExpYear { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Code { get; set; }
}
}

View File

@ -1,27 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class CipherFieldModel
{
public CipherFieldModel() { }
public CipherFieldModel(CipherFieldData data)
{
Type = data.Type;
Name = data.Name;
Value = data.Value;
LinkedId = data.LinkedId ?? null;
}
public FieldType Type { get; set; }
[EncryptedStringLength(1000)]
public string Name { get; set; }
[EncryptedStringLength(5000)]
public string Value { get; set; }
public int? LinkedId { get; set; }
}
}

View File

@ -1,88 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class CipherIdentityModel
{
public CipherIdentityModel() { }
public CipherIdentityModel(CipherIdentityData data)
{
Title = data.Title;
FirstName = data.FirstName;
MiddleName = data.MiddleName;
LastName = data.LastName;
Address1 = data.Address1;
Address2 = data.Address2;
Address3 = data.Address3;
City = data.City;
State = data.State;
PostalCode = data.PostalCode;
Country = data.Country;
Company = data.Company;
Email = data.Email;
Phone = data.Phone;
SSN = data.SSN;
Username = data.Username;
PassportNumber = data.PassportNumber;
LicenseNumber = data.LicenseNumber;
}
[EncryptedString]
[EncryptedStringLength(1000)]
public string Title { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string FirstName { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string MiddleName { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string LastName { get; set; }
[EncryptedString]
[StringLength(1000)]
public string Address1 { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Address2 { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Address3 { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string City { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string State { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string PostalCode { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Country { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Company { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Email { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Phone { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string SSN { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Username { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string PassportNumber { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string LicenseNumber { get; set; }
}
}

View File

@ -1,84 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Enums;
using System.Collections.Generic;
using System.Linq;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api
{
public class CipherLoginModel
{
public CipherLoginModel() { }
public CipherLoginModel(CipherLoginData data)
{
Uris = data.Uris?.Select(u => new CipherLoginUriModel(u))?.ToList();
if (!Uris?.Any() ?? true)
{
Uri = data.Uri;
}
Username = data.Username;
Password = data.Password;
PasswordRevisionDate = data.PasswordRevisionDate;
Totp = data.Totp;
AutofillOnPageLoad = data.AutofillOnPageLoad;
}
[EncryptedString]
[EncryptedStringLength(10000)]
public string Uri
{
get => Uris?.FirstOrDefault()?.Uri;
set
{
if (string.IsNullOrWhiteSpace(value))
{
return;
}
if (Uris == null)
{
Uris = new List<CipherLoginUriModel>();
}
Uris.Add(new CipherLoginUriModel(value));
}
}
public List<CipherLoginUriModel> Uris { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Username { get; set; }
[EncryptedString]
[EncryptedStringLength(5000)]
public string Password { get; set; }
public DateTime? PasswordRevisionDate { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Totp { get; set; }
public bool? AutofillOnPageLoad { get; set; }
public class CipherLoginUriModel
{
public CipherLoginUriModel() { }
public CipherLoginUriModel(string uri)
{
Uri = uri;
}
public CipherLoginUriModel(CipherLoginData.CipherLoginUriData uri)
{
Uri = uri.Uri;
Match = uri.Match;
}
[EncryptedString]
[EncryptedStringLength(10000)]
public string Uri { get; set; }
public UriMatchType? Match { get; set; } = null;
}
}
}

View File

@ -1,25 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class CipherPasswordHistoryModel
{
public CipherPasswordHistoryModel() { }
public CipherPasswordHistoryModel(CipherPasswordHistoryData data)
{
Password = data.Password;
LastUsedDate = data.LastUsedDate;
}
[EncryptedString]
[EncryptedStringLength(5000)]
[Required]
public string Password { get; set; }
[Required]
public DateTime? LastUsedDate { get; set; }
}
}

View File

@ -1,17 +0,0 @@
using Bit.Core.Enums;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api
{
public class CipherSecureNoteModel
{
public CipherSecureNoteModel() { }
public CipherSecureNoteModel(CipherSecureNoteData data)
{
Type = data.Type;
}
public SecureNoteType Type { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api.Public
{
public abstract class AssociationWithPermissionsBaseModel
{
/// <summary>
/// The associated object's unique identifier.
/// </summary>
/// <example>bfbc8338-e329-4dc0-b0c9-317c2ebf1a09</example>
[Required]
public Guid? Id { get; set; }
/// <summary>
/// When true, the read only permission will not allow the user or group to make changes to items.
/// </summary>
[Required]
public bool? ReadOnly { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Public
{
public abstract class CollectionBaseModel
{
/// <summary>
/// External identifier for reference or linking this collection to another system.
/// </summary>
/// <example>external_id_123456</example>
[StringLength(300)]
public string ExternalId { get; set; }
}
}

View File

@ -1,27 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Public
{
public abstract class GroupBaseModel
{
/// <summary>
/// The name of the group.
/// </summary>
/// <example>Development Team</example>
[Required]
[StringLength(100)]
public string Name { get; set; }
/// <summary>
/// Determines if this group can access all collections within the organization, or only the associated
/// collections. If set to <c>true</c>, this option overrides any collection assignments.
/// </summary>
[Required]
public bool? AccessAll { get; set; }
/// <summary>
/// External identifier for reference or linking this group to another system, such as a user directory.
/// </summary>
/// <example>external_id_123456</example>
[StringLength(300)]
public string ExternalId { get; set; }
}
}

View File

@ -1,62 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
public abstract class MemberBaseModel
{
public MemberBaseModel() { }
public MemberBaseModel(OrganizationUser user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Type = user.Type;
AccessAll = user.AccessAll;
ExternalId = user.ExternalId;
ResetPasswordEnrolled = user.ResetPasswordKey != null;
}
public MemberBaseModel(OrganizationUserUserDetails user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Type = user.Type;
AccessAll = user.AccessAll;
ExternalId = user.ExternalId;
ResetPasswordEnrolled = user.ResetPasswordKey != null;
}
/// <summary>
/// The member's type (or role) within the organization.
/// </summary>
[Required]
public OrganizationUserType? Type { get; set; }
/// <summary>
/// Determines if this member can access all collections within the organization, or only the associated
/// collections. If set to <c>true</c>, this option overrides any collection assignments.
/// </summary>
[Required]
public bool? AccessAll { get; set; }
/// <summary>
/// External identifier for reference or linking this member to another system, such as a user directory.
/// </summary>
/// <example>external_id_123456</example>
[StringLength(300)]
public string ExternalId { get; set; }
/// <summary>
/// Returns <c>true</c> if the member has enrolled in Password Reset assistance within the organization
/// </summary>
[Required]
public bool ResetPasswordEnrolled { get; set; }
}
}

View File

@ -1,18 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Public
{
public abstract class PolicyBaseModel
{
/// <summary>
/// Determines if this policy is enabled and enforced.
/// </summary>
[Required]
public bool? Enabled { get; set; }
/// <summary>
/// Data for the policy.
/// </summary>
public Dictionary<string, object> Data { get; set; }
}
}

View File

@ -1,16 +0,0 @@
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api.Public
{
public class AssociationWithPermissionsRequestModel : AssociationWithPermissionsBaseModel
{
public SelectionReadOnly ToSelectionReadOnly()
{
return new SelectionReadOnly
{
Id = Id.Value,
ReadOnly = ReadOnly.Value
};
}
}
}

View File

@ -1,19 +0,0 @@
using System.Collections.Generic;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
public class CollectionUpdateRequestModel : CollectionBaseModel
{
/// <summary>
/// The associated groups that this collection is assigned to.
/// </summary>
public IEnumerable<AssociationWithPermissionsRequestModel> Groups { get; set; }
public Collection ToCollection(Collection existingCollection)
{
existingCollection.ExternalId = ExternalId;
return existingCollection;
}
}
}

View File

@ -1,51 +0,0 @@
using System;
using Bit.Core.Exceptions;
namespace Bit.Core.Models.Api.Public
{
public class EventFilterRequestModel
{
/// <summary>
/// The start date. Must be less than the end date.
/// </summary>
public DateTime? Start { get; set; }
/// <summary>
/// The end date. Must be greater than the start date.
/// </summary>
public DateTime? End { get; set; }
/// <summary>
/// The unique identifier of the user that performed the event.
/// </summary>
public Guid? ActingUserId { get; set; }
/// <summary>
/// The unique identifier of the related item that the event describes.
/// </summary>
public Guid? ItemId { get; set; }
/// <summary>
/// A cursor for use in pagination.
/// </summary>
public string ContinuationToken { get; set; }
public Tuple<DateTime, DateTime> ToDateRange()
{
if (!End.HasValue || !Start.HasValue)
{
End = DateTime.UtcNow.Date.AddDays(1).AddMilliseconds(-1);
Start = DateTime.UtcNow.Date.AddDays(-30);
}
else if (Start.Value > End.Value)
{
var newEnd = Start;
Start = End;
End = newEnd;
}
if ((End.Value - Start.Value) > TimeSpan.FromDays(367))
{
throw new BadRequestException("Date range must be < 367 days.");
}
return new Tuple<DateTime, DateTime>(Start.Value, End.Value);
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
public class GroupCreateUpdateRequestModel : GroupBaseModel
{
/// <summary>
/// The associated collections that this group can access.
/// </summary>
public IEnumerable<AssociationWithPermissionsRequestModel> Collections { get; set; }
public Group ToGroup(Guid orgId)
{
return ToGroup(new Group
{
OrganizationId = orgId
});
}
public Group ToGroup(Group existingGroup)
{
existingGroup.Name = Name;
existingGroup.AccessAll = AccessAll.Value;
existingGroup.ExternalId = ExternalId;
return existingGroup;
}
}
}

View File

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api.Public
{
public class MemberCreateRequestModel : MemberUpdateRequestModel
{
/// <summary>
/// The member's email address.
/// </summary>
/// <example>jsmith@example.com</example>
[Required]
[StringLength(256)]
[StrictEmailAddress]
public string Email { get; set; }
public override OrganizationUser ToOrganizationUser(OrganizationUser existingUser)
{
throw new NotImplementedException();
}
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
public class MemberUpdateRequestModel : MemberBaseModel
{
/// <summary>
/// The associated collections that this member can access.
/// </summary>
public IEnumerable<AssociationWithPermissionsRequestModel> Collections { get; set; }
public virtual OrganizationUser ToOrganizationUser(OrganizationUser existingUser)
{
existingUser.Type = Type.Value;
existingUser.AccessAll = AccessAll.Value;
existingUser.ExternalId = ExternalId;
return existingUser;
}
}
}

View File

@ -1,108 +0,0 @@
using Bit.Core.Models.Business;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Public
{
public class OrganizationImportRequestModel
{
/// <summary>
/// Groups to import.
/// </summary>
public OrganizationImportGroupRequestModel[] Groups { get; set; }
/// <summary>
/// Members to import.
/// </summary>
public OrganizationImportMemberRequestModel[] Members { get; set; }
/// <summary>
/// Determines if the data in this request should overwrite or append to the existing organization data.
/// </summary>
[Required]
public bool? OverwriteExisting { get; set; }
/// <summary>
/// Indicates an import of over 2000 users and/or groups is expected
/// </summary>
public bool LargeImport { get; set; } = false;
public class OrganizationImportGroupRequestModel
{
/// <summary>
/// The name of the group.
/// </summary>
/// <example>Development Team</example>
[Required]
[StringLength(100)]
public string Name { get; set; }
/// <summary>
/// External identifier for reference or linking this group to another system, such as a user directory.
/// </summary>
/// <example>external_id_123456</example>
[Required]
[StringLength(300)]
public string ExternalId { get; set; }
/// <summary>
/// The associated external ids for members in this group.
/// </summary>
public IEnumerable<string> MemberExternalIds { get; set; }
public ImportedGroup ToImportedGroup(Guid organizationId)
{
var importedGroup = new ImportedGroup
{
Group = new Table.Group
{
OrganizationId = organizationId,
Name = Name,
ExternalId = ExternalId
},
ExternalUserIds = new HashSet<string>(MemberExternalIds)
};
return importedGroup;
}
}
public class OrganizationImportMemberRequestModel : IValidatableObject
{
/// <summary>
/// The member's email address. Required for non-deleted users.
/// </summary>
/// <example>jsmith@example.com</example>
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
/// <summary>
/// External identifier for reference or linking this member to another system, such as a user directory.
/// </summary>
/// <example>external_id_123456</example>
[Required]
[StringLength(300)]
public string ExternalId { get; set; }
/// <summary>
/// Determines if this member should be removed from the organization during import.
/// </summary>
public bool Deleted { get; set; }
public ImportedOrganizationUser ToImportedOrganizationUser()
{
var importedUser = new ImportedOrganizationUser
{
Email = Email.ToLowerInvariant(),
ExternalId = ExternalId
};
return importedUser;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Email) && !Deleted)
{
yield return new ValidationResult("Email is required for enabled members.",
new string[] { nameof(Email) });
}
}
}
}
}

View File

@ -1,24 +0,0 @@
using System;
using Bit.Core.Models.Table;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api.Public
{
public class PolicyUpdateRequestModel : PolicyBaseModel
{
public Policy ToPolicy(Guid orgId)
{
return ToPolicy(new Policy
{
OrganizationId = orgId
});
}
public virtual Policy ToPolicy(Policy existingPolicy)
{
existingPolicy.Enabled = Enabled.GetValueOrDefault();
existingPolicy.Data = Data != null ? JsonConvert.SerializeObject(Data) : null;
return existingPolicy;
}
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
namespace Bit.Core.Models.Api.Public
{
public class UpdateGroupIdsRequestModel
{
/// <summary>
/// The associated group ids that this object can access.
/// </summary>
public IEnumerable<Guid> GroupIds { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
namespace Bit.Core.Models.Api.Public
{
public class UpdateMemberIdsRequestModel
{
/// <summary>
/// The associated member ids that have access to this object.
/// </summary>
public IEnumerable<Guid> MemberIds { get; set; }
}
}

View File

@ -1,18 +0,0 @@
using System;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api.Public
{
public class AssociationWithPermissionsResponseModel : AssociationWithPermissionsBaseModel
{
public AssociationWithPermissionsResponseModel(SelectionReadOnly selection)
{
if (selection == null)
{
throw new ArgumentNullException(nameof(selection));
}
Id = selection.Id;
ReadOnly = selection.ReadOnly;
}
}
}

View File

@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
/// <summary>
/// A collection.
/// </summary>
public class CollectionResponseModel : CollectionBaseModel, IResponseModel
{
public CollectionResponseModel(Collection collection, IEnumerable<SelectionReadOnly> groups)
{
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
Id = collection.Id;
ExternalId = collection.ExternalId;
Groups = groups?.Select(c => new AssociationWithPermissionsResponseModel(c));
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>collection</example>
[Required]
public string Object => "collection";
/// <summary>
/// The collection's unique identifier.
/// </summary>
/// <example>539a36c5-e0d2-4cf9-979e-51ecf5cf6593</example>
[Required]
public Guid Id { get; set; }
/// <summary>
/// The associated groups that this collection is assigned to.
/// </summary>
public IEnumerable<AssociationWithPermissionsResponseModel> Groups { get; set; }
}
}

View File

@ -1,79 +0,0 @@
using System.Linq;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Public
{
public class ErrorResponseModel : IResponseModel
{
public ErrorResponseModel(string message)
{
Message = message;
}
public ErrorResponseModel(ModelStateDictionary modelState)
{
Message = "The request's model state is invalid.";
Errors = new Dictionary<string, IEnumerable<string>>();
var keys = modelState.Keys.ToList();
var values = modelState.Values.ToList();
for (var i = 0; i < values.Count; i++)
{
var value = values[i];
if (keys.Count <= i)
{
// Keys not available for some reason.
break;
}
var key = keys[i];
if (value.ValidationState != ModelValidationState.Invalid || value.Errors.Count == 0)
{
continue;
}
var errors = value.Errors.Select(e => e.ErrorMessage);
Errors.Add(key, errors);
}
}
public ErrorResponseModel(Dictionary<string, IEnumerable<string>> errors)
: this("Errors have occurred.", errors)
{ }
public ErrorResponseModel(string errorKey, string errorValue)
: this(errorKey, new string[] { errorValue })
{ }
public ErrorResponseModel(string errorKey, IEnumerable<string> errorValues)
: this(new Dictionary<string, IEnumerable<string>> { { errorKey, errorValues } })
{ }
public ErrorResponseModel(string message, Dictionary<string, IEnumerable<string>> errors)
{
Message = message;
Errors = errors;
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>error</example>
[Required]
public string Object => "error";
/// <summary>
/// A human-readable message providing details about the error.
/// </summary>
/// <example>The request model is invalid.</example>
[Required]
public string Message { get; set; }
/// <summary>
/// If multiple errors occurred, they are listed in dictionary. Errors related to a specific
/// request parameter will include a dictionary key describing that parameter.
/// </summary>
public Dictionary<string, IEnumerable<string>> Errors { get; set; }
}
}

View File

@ -1,88 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api.Public
{
/// <summary>
/// An event log.
/// </summary>
public class EventResponseModel : IResponseModel
{
public EventResponseModel(IEvent ev)
{
if (ev == null)
{
throw new ArgumentNullException(nameof(ev));
}
Type = ev.Type;
ItemId = ev.CipherId;
CollectionId = ev.CollectionId;
GroupId = ev.GroupId;
PolicyId = ev.PolicyId;
MemberId = ev.OrganizationUserId;
ActingUserId = ev.ActingUserId;
Date = ev.Date;
Device = ev.DeviceType;
IpAddress = ev.IpAddress;
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>event</example>
[Required]
public string Object => "event";
/// <summary>
/// The type of event.
/// </summary>
[Required]
public EventType Type { get; set; }
/// <summary>
/// The unique identifier of the related item that the event describes.
/// </summary>
/// <example>3767a302-8208-4dc6-b842-030428a1cfad</example>
public Guid? ItemId { get; set; }
/// <summary>
/// The unique identifier of the related collection that the event describes.
/// </summary>
/// <example>bce212a4-25f3-4888-8a0a-4c5736d851e0</example>
public Guid? CollectionId { get; set; }
/// <summary>
/// The unique identifier of the related group that the event describes.
/// </summary>
/// <example>f29a2515-91d2-4452-b49b-5e8040e6b0f4</example>
public Guid? GroupId { get; set; }
/// <summary>
/// The unique identifier of the related policy that the event describes.
/// </summary>
/// <example>f29a2515-91d2-4452-b49b-5e8040e6b0f4</example>
public Guid? PolicyId { get; set; }
/// <summary>
/// The unique identifier of the related member that the event describes.
/// </summary>
/// <example>e68b8629-85eb-4929-92c0-b84464976ba4</example>
public Guid? MemberId { get; set; }
/// <summary>
/// The unique identifier of the user that performed the event.
/// </summary>
/// <example>a2549f79-a71f-4eb9-9234-eb7247333f94</example>
public Guid? ActingUserId { get; set; }
/// <summary>
/// The date/timestamp when the event occurred.
/// </summary>
[Required]
public DateTime Date { get; set; }
/// <summary>
/// The type of device used by the acting user when the event occurred.
/// </summary>
public DeviceType? Device { get; set; }
/// <summary>
/// The IP address of the acting user.
/// </summary>
/// <example>172.16.254.1</example>
public string IpAddress { get; set; }
}
}

View File

@ -1,46 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
/// <summary>
/// A user group.
/// </summary>
public class GroupResponseModel : GroupBaseModel, IResponseModel
{
public GroupResponseModel(Group group, IEnumerable<SelectionReadOnly> collections)
{
if (group == null)
{
throw new ArgumentNullException(nameof(group));
}
Id = group.Id;
Name = group.Name;
AccessAll = group.AccessAll;
ExternalId = group.ExternalId;
Collections = collections?.Select(c => new AssociationWithPermissionsResponseModel(c));
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>group</example>
[Required]
public string Object => "group";
/// <summary>
/// The group's unique identifier.
/// </summary>
/// <example>539a36c5-e0d2-4cf9-979e-51ecf5cf6593</example>
[Required]
public Guid Id { get; set; }
/// <summary>
/// The associated collections that this group can access.
/// </summary>
public IEnumerable<AssociationWithPermissionsResponseModel> Collections { get; set; }
}
}

View File

@ -1,7 +0,0 @@
namespace Bit.Core.Models.Api.Public
{
public interface IResponseModel
{
string Object { get; }
}
}

View File

@ -1,30 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Public
{
public class ListResponseModel<T> : IResponseModel where T : IResponseModel
{
public ListResponseModel(IEnumerable<T> data, string continuationToken = null)
{
Data = data;
ContinuationToken = continuationToken;
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>list</example>
[Required]
public string Object => "list";
/// <summary>
/// An array containing the actual response elements, paginated by any request parameters.
/// </summary>
[Required]
public IEnumerable<T> Data { get; set; }
/// <summary>
/// A cursor for use in pagination.
/// </summary>
public string ContinuationToken { get; set; }
}
}

View File

@ -1,96 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Public
{
/// <summary>
/// An organization member.
/// </summary>
public class MemberResponseModel : MemberBaseModel, IResponseModel
{
public MemberResponseModel(OrganizationUser user, IEnumerable<SelectionReadOnly> collections)
: base(user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Id = user.Id;
UserId = user.UserId;
Email = user.Email;
Status = user.Status;
Collections = collections?.Select(c => new AssociationWithPermissionsResponseModel(c));
}
public MemberResponseModel(OrganizationUserUserDetails user, bool twoFactorEnabled,
IEnumerable<SelectionReadOnly> collections)
: base(user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Id = user.Id;
UserId = user.UserId;
Name = user.Name;
Email = user.Email;
TwoFactorEnabled = twoFactorEnabled;
Status = user.Status;
Collections = collections?.Select(c => new AssociationWithPermissionsResponseModel(c));
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>member</example>
[Required]
public string Object => "member";
/// <summary>
/// The member's unique identifier within the organization.
/// </summary>
/// <example>539a36c5-e0d2-4cf9-979e-51ecf5cf6593</example>
[Required]
public Guid Id { get; set; }
/// <summary>
/// The member's unique identifier across Bitwarden.
/// </summary>
/// <example>48b47ee1-493e-4c67-aef7-014996c40eca</example>
[Required]
public Guid? UserId { get; set; }
/// <summary>
/// The member's name, set from their user account profile.
/// </summary>
/// <example>John Smith</example>
public string Name { get; set; }
/// <summary>
/// The member's email address.
/// </summary>
/// <example>jsmith@example.com</example>
[Required]
public string Email { get; set; }
/// <summary>
/// Returns <c>true</c> if the member has a two-step login method enabled on their user account.
/// </summary>
[Required]
public bool TwoFactorEnabled { get; set; }
/// <summary>
/// The member's status within the organization. All created members start with a status of "Invited".
/// Once a member accept's their invitation to join the organization, their status changes to "Accepted".
/// Accepted members are then "Confirmed" by an organization administrator. Once a member is "Confirmed",
/// their status can no longer change.
/// </summary>
[Required]
public OrganizationUserStatusType Status { get; set; }
/// <summary>
/// The associated collections that this member can access.
/// </summary>
public IEnumerable<AssociationWithPermissionsResponseModel> Collections { get; set; }
}
}

View File

@ -1,48 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api.Public
{
/// <summary>
/// A policy.
/// </summary>
public class PolicyResponseModel : PolicyBaseModel, IResponseModel
{
public PolicyResponseModel(Policy policy)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
Id = policy.Id;
Type = policy.Type;
Enabled = policy.Enabled;
if (!string.IsNullOrWhiteSpace(policy.Data))
{
Data = JsonConvert.DeserializeObject<Dictionary<string, object>>(policy.Data);
}
}
/// <summary>
/// String representing the object's type. Objects of the same type share the same properties.
/// </summary>
/// <example>policy</example>
[Required]
public string Object => "policy";
/// <summary>
/// The policy's unique identifier.
/// </summary>
/// <example>539a36c5-e0d2-4cf9-979e-51ecf5cf6593</example>
[Required]
public Guid Id { get; set; }
/// <summary>
/// The type of policy.
/// </summary>
[Required]
public Enums.PolicyType? Type { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class DeleteRecoverRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Models.Api;
namespace Bit.Core.Models.Api
{
public class EmailRequestModel : SecretVerificationRequestModel
{
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string NewEmail { get; set; }
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Token { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Models.Api;
namespace Bit.Core.Models.Api
{
public class EmailTokenRequestModel : SecretVerificationRequestModel
{
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string NewEmail { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
namespace Bit.Core.Models.Api
{
public class ImportCiphersRequestModel
{
public FolderRequestModel[] Folders { get; set; }
public CipherRequestModel[] Ciphers { get; set; }
public KeyValuePair<int, int>[] FolderRelationships { get; set; }
}
}

View File

@ -1,33 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class KdfRequestModel : PasswordRequestModel, IValidatableObject
{
[Required]
public KdfType? Kdf { get; set; }
[Required]
public int? KdfIterations { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Kdf.HasValue && KdfIterations.HasValue)
{
switch (Kdf.Value)
{
case KdfType.PBKDF2_SHA256:
if (KdfIterations.Value < 5000 || KdfIterations.Value > 2_000_000)
{
yield return new ValidationResult("KDF iterations must be between 5000 and 2000000.");
}
break;
default:
break;
}
}
}
}
}

View File

@ -1,27 +0,0 @@
using Bit.Core.Models.Table;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class KeysRequestModel
{
public string PublicKey { get; set; }
[Required]
public string EncryptedPrivateKey { get; set; }
public User ToUser(User existingUser)
{
if (string.IsNullOrWhiteSpace(existingUser.PublicKey) && !string.IsNullOrWhiteSpace(PublicKey))
{
existingUser.PublicKey = PublicKey;
}
if (string.IsNullOrWhiteSpace(existingUser.PrivateKey))
{
existingUser.PrivateKey = EncryptedPrivateKey;
}
return existingUser;
}
}
}

View File

@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class PasswordHintRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class PasswordRequestModel : SecretVerificationRequestModel
{
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class PreloginRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
}
}

View File

@ -1,45 +0,0 @@
using Microsoft.AspNetCore.Http;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using Bit.Core.Enums;
using Bit.Core.Settings;
namespace Bit.Core.Models.Api
{
public class PremiumRequestModel : IValidatableObject
{
[Required]
public PaymentMethodType? PaymentMethodType { get; set; }
public string PaymentToken { get; set; }
[Range(0, 99)]
public short? AdditionalStorageGb { get; set; }
public IFormFile License { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
public bool Validate(GlobalSettings globalSettings)
{
if (!(License == null && !globalSettings.SelfHosted) ||
(License != null && globalSettings.SelfHosted))
{
return false;
}
return globalSettings.SelfHosted || !string.IsNullOrWhiteSpace(Country);
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var creditType = PaymentMethodType.HasValue && PaymentMethodType.Value == Enums.PaymentMethodType.Credit;
if (string.IsNullOrWhiteSpace(PaymentToken) && !creditType && License == null)
{
yield return new ValidationResult("Payment token or license is required.");
}
if (Country == "US" && string.IsNullOrWhiteSpace(PostalCode))
{
yield return new ValidationResult("Zip / postal code is required.",
new string[] { nameof(PostalCode) });
}
}
}
}

View File

@ -1,14 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class RegenerateTwoFactorRequestModel
{
[Required]
public string MasterPasswordHash { get; set; }
[Required]
[StringLength(50)]
public string Token { get; set; }
}
}

View File

@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using Bit.Core.Models.Table;
using Bit.Core.Utilities;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api
{
public class RegisterRequestModel : IValidatableObject, ICaptchaProtectedModel
{
[StringLength(50)]
public string Name { get; set; }
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string Email { get; set; }
[Required]
[StringLength(1000)]
public string MasterPasswordHash { get; set; }
[StringLength(50)]
public string MasterPasswordHint { get; set; }
public string CaptchaResponse { get; set; }
public string Key { get; set; }
public KeysRequestModel Keys { get; set; }
public string Token { get; set; }
public Guid? OrganizationUserId { get; set; }
public KdfType? Kdf { get; set; }
public int? KdfIterations { get; set; }
public Dictionary<string, object> ReferenceData { get; set; }
public User ToUser()
{
var user = new User
{
Name = Name,
Email = Email,
MasterPasswordHint = MasterPasswordHint,
Kdf = Kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256),
KdfIterations = KdfIterations.GetValueOrDefault(5000),
};
if (ReferenceData != null)
{
user.ReferenceData = JsonConvert.SerializeObject(ReferenceData);
}
if (Key != null)
{
user.Key = Key;
}
if (Keys != null)
{
Keys.ToUser(user);
}
return user;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Kdf.HasValue && KdfIterations.HasValue)
{
switch (Kdf.Value)
{
case KdfType.PBKDF2_SHA256:
if (KdfIterations.Value < 5000 || KdfIterations.Value > 1_000_000)
{
yield return new ValidationResult("KDF iterations must be between 5000 and 1000000.");
}
break;
default:
break;
}
}
}
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class SecretVerificationRequestModel : IValidatableObject
{
[StringLength(300)]
public string MasterPasswordHash { get; set; }
public string OTP { get; set; }
public string Secret => !string.IsNullOrEmpty(MasterPasswordHash) ? MasterPasswordHash : OTP;
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(Secret))
{
yield return new ValidationResult("MasterPasswordHash or OTP must be supplied.");
}
}
}
}

View File

@ -1,29 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Request.Accounts
{
public class SetKeyConnectorKeyRequestModel
{
[Required]
public string Key { get; set; }
[Required]
public KeysRequestModel Keys { get; set; }
[Required]
public KdfType Kdf { get; set; }
[Required]
public int KdfIterations { get; set; }
[Required]
public string OrgIdentifier { get; set; }
public User ToUser(User existingUser)
{
existingUser.Kdf = Kdf;
existingUser.KdfIterations = KdfIterations;
existingUser.Key = Key;
Keys.ToUser(existingUser);
return existingUser;
}
}
}

View File

@ -1,34 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Request.Accounts
{
public class SetPasswordRequestModel
{
[Required]
[StringLength(300)]
public string MasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
[StringLength(50)]
public string MasterPasswordHint { get; set; }
[Required]
public KeysRequestModel Keys { get; set; }
[Required]
public KdfType Kdf { get; set; }
[Required]
public int KdfIterations { get; set; }
public string OrgIdentifier { get; set; }
public User ToUser(User existingUser)
{
existingUser.MasterPasswordHint = MasterPasswordHint;
existingUser.Kdf = Kdf;
existingUser.KdfIterations = KdfIterations;
existingUser.Key = Key;
Keys.ToUser(existingUser);
return existingUser;
}
}
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class StorageRequestModel : IValidatableObject
{
[Required]
public short? StorageGbAdjustment { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (StorageGbAdjustment == 0)
{
yield return new ValidationResult("Storage adjustment cannot be 0.",
new string[] { nameof(StorageGbAdjustment) });
}
}
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class TaxInfoUpdateRequestModel : IValidatableObject
{
[Required]
public string Country { get; set; }
public string PostalCode { get; set; }
public virtual IEnumerable<ValidationResult> Validate (ValidationContext validationContext)
{
if (Country == "US" && string.IsNullOrWhiteSpace(PostalCode))
{
yield return new ValidationResult("Zip / postal code is required.",
new string[] { nameof(PostalCode) });
}
}
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class UpdateKeyRequestModel
{
[Required]
[StringLength(300)]
public string MasterPasswordHash { get; set; }
[Required]
public IEnumerable<CipherWithIdRequestModel> Ciphers { get; set; }
[Required]
public IEnumerable<FolderWithIdRequestModel> Folders { get; set; }
public IEnumerable<SendWithIdRequestModel> Sends { get; set; }
[Required]
public string PrivateKey { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api
{
public class UpdateProfileRequestModel
{
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string MasterPasswordHint { get; set; }
public User ToUser(User existingUser)
{
existingUser.Name = Name;
existingUser.MasterPasswordHint = string.IsNullOrWhiteSpace(MasterPasswordHint) ? null : MasterPasswordHint;
return existingUser;
}
}
}

View File

@ -1,10 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api.Request.Accounts
{
public class UpdateTempPasswordRequestModel : OrganizationUserResetPasswordRequestModel
{
[StringLength(50)]
public string MasterPasswordHint { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class VerifyDeleteRecoverRequestModel
{
[Required]
public string UserId { get; set; }
[Required]
public string Token { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class VerifyEmailRequestModel
{
[Required]
public string UserId { get; set; }
[Required]
public string Token { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class VerifyOTPRequestModel
{
[Required]
public string OTP { get; set; }
}
}

View File

@ -1,10 +0,0 @@
namespace Bit.Core.Models.Api
{
public class AttachmentRequestModel
{
public string Key { get; set; }
public string FileName { get; set; }
public long FileSize { get; set; }
public bool AdminRequest { get; set; } = false;
}
}

View File

@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Settings;
namespace Bit.Core.Models.Api
{
public class BitPayInvoiceRequestModel : IValidatableObject
{
public Guid? UserId { get; set; }
public Guid? OrganizationId { get; set; }
public bool Credit { get; set; }
[Required]
public decimal? Amount { get; set; }
public string ReturnUrl { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public BitPayLight.Models.Invoice.Invoice ToBitpayInvoice(GlobalSettings globalSettings)
{
var inv = new BitPayLight.Models.Invoice.Invoice
{
Price = Convert.ToDouble(Amount.Value),
Currency = "USD",
RedirectUrl = ReturnUrl,
Buyer = new BitPayLight.Models.Invoice.Buyer
{
Email = Email,
Name = Name
},
NotificationUrl = globalSettings.BitPay.NotificationUrl,
FullNotifications = true,
ExtendedNotifications = true
};
var posData = string.Empty;
if (UserId.HasValue)
{
posData = "userId:" + UserId.Value;
}
else if (OrganizationId.HasValue)
{
posData = "organizationId:" + OrganizationId.Value;
}
if (Credit)
{
posData += ",accountCredit:1";
inv.ItemDesc = "Bitwarden Account Credit";
}
else
{
inv.ItemDesc = "Bitwarden";
}
inv.PosData = posData;
return inv;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!UserId.HasValue && !OrganizationId.HasValue)
{
yield return new ValidationResult("User or Ooganization is required.");
}
}
}
}

View File

@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class CipherPartialRequestModel
{
[StringLength(36)]
public string FolderId { get; set; }
public bool Favorite { get; set; }
}
}

View File

@ -1,272 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using Core.Models.Data;
using Bit.Core.Models.Data;
using Newtonsoft.Json.Linq;
namespace Bit.Core.Models.Api
{
public class CipherRequestModel
{
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)
{
var hasOrgId = !string.IsNullOrWhiteSpace(OrganizationId);
var cipher = new CipherDetails
{
Type = Type,
UserId = !hasOrgId ? (Guid?)userId : null,
OrganizationId = allowOrgIdSet && hasOrgId ? new Guid(OrganizationId) : (Guid?)null,
Edit = true,
ViewPassword = true,
};
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)
{
switch (existingCipher.Type)
{
case CipherType.Login:
var loginObj = JObject.FromObject(new CipherLoginData(this),
new JsonSerializer { NullValueHandling = NullValueHandling.Ignore });
loginObj[nameof(CipherLoginData.Uri)]?.Parent?.Remove();
existingCipher.Data = loginObj.ToString(Formatting.None);
break;
case CipherType.Card:
existingCipher.Data = JsonConvert.SerializeObject(new CipherCardData(this),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break;
case CipherType.Identity:
existingCipher.Data = JsonConvert.SerializeObject(new CipherIdentityData(this),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break;
case CipherType.SecureNote:
existingCipher.Data = JsonConvert.SerializeObject(new CipherSecureNoteData(this),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break;
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
}
existingCipher.Reprompt = Reprompt;
var hasAttachments2 = (Attachments2?.Count ?? 0) > 0;
var hasAttachments = (Attachments?.Count ?? 0) > 0;
if (!hasAttachments2 && !hasAttachments)
{
return existingCipher;
}
var attachments = existingCipher.GetAttachments();
if ((attachments?.Count ?? 0) == 0)
{
return existingCipher;
}
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;
}
}
else if (hasAttachments)
{
foreach (var attachment in attachments.Where(a => Attachments.ContainsKey(a.Key)))
{
attachment.Value.FileName = Attachments[attachment.Key];
attachment.Value.Key = null;
}
}
existingCipher.SetAttachments(attachments);
return existingCipher;
}
public Cipher ToOrganizationCipher()
{
if (string.IsNullOrWhiteSpace(OrganizationId))
{
throw new ArgumentNullException(nameof(OrganizationId));
}
return ToCipher(new Cipher
{
Type = Type,
OrganizationId = new Guid(OrganizationId)
});
}
public CipherDetails ToOrganizationCipherDetails(Guid orgId)
{
return ToCipherDetails(new CipherDetails
{
Type = Type,
OrganizationId = orgId,
Edit = true
});
}
}
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)
{
if (!string.IsNullOrWhiteSpace(Cipher.OrganizationId) && (!CollectionIds?.Any() ?? true))
{
yield return new ValidationResult("You must select at least one collection.",
new string[] { nameof(CollectionIds) });
}
}
}
public class CipherShareRequestModel : IValidatableObject
{
[Required]
public IEnumerable<string> CollectionIds { get; set; }
[Required]
public CipherRequestModel Cipher { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
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) });
}
}
}
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; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!Ciphers?.Any() ?? true)
{
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)
{
organizationIds.Add(c.OrganizationId);
if (allHaveIds)
{
allHaveIds = !(!c.Id.HasValue || string.IsNullOrWhiteSpace(c.OrganizationId));
}
}
if (!allHaveIds)
{
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.");
}
}
if (!CollectionIds?.Any() ?? true)
{
yield return new ValidationResult("You must select at least one collection.",
new string[] { nameof(CollectionIds) });
}
}
}
}

View File

@ -1,35 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Models.Table;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Bit.Core.Models.Api
{
public class CollectionRequestModel
{
[Required]
[EncryptedString]
[EncryptedStringLength(1000)]
public string Name { get; set; }
[StringLength(300)]
public string ExternalId { get; set; }
public IEnumerable<SelectionReadOnlyRequestModel> Groups { get; set; }
public Collection ToCollection(Guid orgId)
{
return ToCollection(new Collection
{
OrganizationId = orgId
});
}
public Collection ToCollection(Collection existingCollection)
{
existingCollection.Name = Name;
existingCollection.ExternalId = ExternalId;
return existingCollection;
}
}
}

View File

@ -1,52 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api
{
public class DeviceRequestModel
{
[Required]
public DeviceType? Type { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(50)]
public string Identifier { get; set; }
[StringLength(255)]
public string PushToken { get; set; }
public Device ToDevice(Guid? userId = null)
{
return ToDevice(new Device
{
UserId = userId == null ? default(Guid) : userId.Value
});
}
public Device ToDevice(Device existingDevice)
{
existingDevice.Name = Name;
existingDevice.Identifier = Identifier;
existingDevice.PushToken = PushToken;
existingDevice.Type = Type.Value;
return existingDevice;
}
}
public class DeviceTokenRequestModel
{
[StringLength(255)]
public string PushToken { get; set; }
public Device ToDevice(Device existingDevice)
{
existingDevice.PushToken = PushToken;
return existingDevice;
}
}
}

View File

@ -1,48 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api.Request
{
public class EmergencyAccessInviteRequestModel
{
[Required]
[StrictEmailAddress]
[StringLength(256)]
public string Email { get; set; }
[Required]
public Enums.EmergencyAccessType? Type { get; set; }
[Required]
public int WaitTimeDays { get; set; }
}
public class EmergencyAccessUpdateRequestModel
{
[Required]
public Enums.EmergencyAccessType Type { get; set; }
[Required]
public int WaitTimeDays { get; set; }
public string KeyEncrypted { get; set; }
public EmergencyAccess ToEmergencyAccess(EmergencyAccess existingEmergencyAccess)
{
// Ensure we only set keys for a confirmed emergency access.
if (!string.IsNullOrWhiteSpace(existingEmergencyAccess.KeyEncrypted) && !string.IsNullOrWhiteSpace(KeyEncrypted))
{
existingEmergencyAccess.KeyEncrypted = KeyEncrypted;
}
existingEmergencyAccess.Type = Type;
existingEmergencyAccess.WaitTimeDays = WaitTimeDays;
return existingEmergencyAccess;
}
}
public class EmergencyAccessPasswordRequestModel
{
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -1,35 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
using Bit.Core.Models.Table;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api
{
public class FolderRequestModel
{
[Required]
[EncryptedString]
[EncryptedStringLength(1000)]
public string Name { get; set; }
public Folder ToFolder(Guid userId)
{
return ToFolder(new Folder
{
UserId = userId
});
}
public Folder ToFolder(Folder existingFolder)
{
existingFolder.Name = Name;
return existingFolder;
}
}
public class FolderWithIdRequestModel : FolderRequestModel
{
public Guid Id { get; set; }
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Bit.Core.Models.Api
{
public class GroupRequestModel
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
public bool? AccessAll { get; set; }
[StringLength(300)]
public string ExternalId { get; set; }
public IEnumerable<SelectionReadOnlyRequestModel> Collections { get; set; }
public Group ToGroup(Guid orgId)
{
return ToGroup(new Group
{
OrganizationId = orgId
});
}
public Group ToGroup(Group existingGroup)
{
existingGroup.Name = Name;
existingGroup.AccessAll = AccessAll.Value;
existingGroup.ExternalId = ExternalId;
return existingGroup;
}
}
}

View File

@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class IapCheckRequestModel : IValidatableObject
{
[Required]
public PaymentMethodType? PaymentMethodType { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PaymentMethodType != Enums.PaymentMethodType.AppleInApp)
{
yield return new ValidationResult("Not a supported in-app purchase payment method.",
new string[] { nameof(PaymentMethodType) });
}
}
}
}

View File

@ -1,23 +0,0 @@
using Bit.Core.Models.Table;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class InstallationRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
public Installation ToInstallation()
{
return new Installation
{
Key = Utilities.CoreHelpers.SecureRandomString(20),
Email = Email,
Enabled = true
};
}
}
}

View File

@ -1,11 +0,0 @@
using Microsoft.AspNetCore.Http;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class LicenseRequestModel
{
[Required]
public IFormFile License { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using System.Collections.Generic;
namespace Bit.Core.Models.Api
{
public class ImportOrganizationCiphersRequestModel
{
public CollectionRequestModel[] Collections { get; set; }
public CipherRequestModel[] Ciphers { get; set; }
public KeyValuePair<int, int>[] CollectionRelationships { get; set; }
}
}

View File

@ -1,73 +0,0 @@
using Bit.Core.Models.Business;
using Bit.Core.Models.Table;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class ImportOrganizationUsersRequestModel
{
public Group[] Groups { get; set; }
public User[] Users { get; set; }
public bool OverwriteExisting { get; set; }
public bool LargeImport { get; set; }
public class Group
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(300)]
public string ExternalId { get; set; }
public IEnumerable<string> Users { get; set; }
public ImportedGroup ToImportedGroup(Guid organizationId)
{
var importedGroup = new ImportedGroup
{
Group = new Table.Group
{
OrganizationId = organizationId,
Name = Name,
ExternalId = ExternalId
},
ExternalUserIds = new HashSet<string>(Users)
};
return importedGroup;
}
}
public class User : IValidatableObject
{
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
public bool Deleted { get; set; }
[Required]
[StringLength(300)]
public string ExternalId { get; set; }
public ImportedOrganizationUser ToImportedOrganizationUser()
{
var importedUser = new ImportedOrganizationUser
{
Email = Email.ToLowerInvariant(),
ExternalId = ExternalId
};
return importedUser;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Email) && !Deleted)
{
yield return new ValidationResult("Email is required for enabled users.", new string[] { nameof(Email) });
}
}
}
}
}

View File

@ -1,15 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class OrganizationCreateLicenseRequestModel : LicenseRequestModel
{
[Required]
public string Key { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string CollectionName { get; set; }
public OrganizationKeysRequestModel Keys { get; set; }
}
}

View File

@ -1,103 +0,0 @@
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class OrganizationCreateRequestModel : IValidatableObject
{
[Required]
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string BusinessName { get; set; }
[Required]
[StringLength(256)]
[EmailAddress]
public string BillingEmail { get; set; }
public PlanType PlanType { get; set; }
[Required]
public string Key { get; set; }
public OrganizationKeysRequestModel Keys { get; set; }
public PaymentMethodType? PaymentMethodType { get; set; }
public string PaymentToken { get; set; }
[Range(0, int.MaxValue)]
public int AdditionalSeats { get; set; }
[Range(0, 99)]
public short? AdditionalStorageGb { get; set; }
public bool PremiumAccessAddon { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string CollectionName { get; set; }
public string TaxIdNumber { get; set; }
public string BillingAddressLine1 { get; set; }
public string BillingAddressLine2 { get; set; }
public string BillingAddressCity { get; set; }
public string BillingAddressState { get; set; }
public string BillingAddressPostalCode { get; set; }
[StringLength(2)]
public string BillingAddressCountry { get; set; }
public int? MaxAutoscaleSeats { get; set; }
public virtual OrganizationSignup ToOrganizationSignup(User user)
{
var orgSignup = new OrganizationSignup
{
Owner = user,
OwnerKey = Key,
Name = Name,
Plan = PlanType,
PaymentMethodType = PaymentMethodType,
PaymentToken = PaymentToken,
AdditionalSeats = AdditionalSeats,
MaxAutoscaleSeats = MaxAutoscaleSeats,
AdditionalStorageGb = AdditionalStorageGb.GetValueOrDefault(0),
PremiumAccessAddon = PremiumAccessAddon,
BillingEmail = BillingEmail,
BusinessName = BusinessName,
CollectionName = CollectionName,
TaxInfo = new TaxInfo
{
TaxIdNumber = TaxIdNumber,
BillingAddressLine1 = BillingAddressLine1,
BillingAddressLine2 = BillingAddressLine2,
BillingAddressCity = BillingAddressCity,
BillingAddressState = BillingAddressState,
BillingAddressPostalCode = BillingAddressPostalCode,
BillingAddressCountry = BillingAddressCountry,
},
};
Keys?.ToOrganizationSignup(orgSignup);
return orgSignup;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PlanType != PlanType.Free && string.IsNullOrWhiteSpace(PaymentToken))
{
yield return new ValidationResult("Payment required.", new string[] { nameof(PaymentToken) });
}
if (PlanType != PlanType.Free && !PaymentMethodType.HasValue)
{
yield return new ValidationResult("Payment method type required.",
new string[] { nameof(PaymentMethodType) });
}
if (PlanType != PlanType.Free && string.IsNullOrWhiteSpace(BillingAddressCountry))
{
yield return new ValidationResult("Country required.",
new string[] { nameof(BillingAddressCountry) });
}
if (PlanType != PlanType.Free && BillingAddressCountry == "US" &&
string.IsNullOrWhiteSpace(BillingAddressPostalCode))
{
yield return new ValidationResult("Zip / postal code is required.",
new string[] { nameof(BillingAddressPostalCode) });
}
}
}
}

View File

@ -1,59 +0,0 @@
using Bit.Core.Models.Table;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Business;
namespace Bit.Core.Models.Api
{
public class OrganizationKeysRequestModel
{
[Required]
public string PublicKey { get; set; }
[Required]
public string EncryptedPrivateKey { get; set; }
public OrganizationSignup ToOrganizationSignup(OrganizationSignup existingSignup)
{
if (string.IsNullOrWhiteSpace(existingSignup.PublicKey))
{
existingSignup.PublicKey = PublicKey;
}
if (string.IsNullOrWhiteSpace(existingSignup.PrivateKey))
{
existingSignup.PrivateKey = EncryptedPrivateKey;
}
return existingSignup;
}
public OrganizationUpgrade ToOrganizationUpgrade(OrganizationUpgrade existingUpgrade)
{
if (string.IsNullOrWhiteSpace(existingUpgrade.PublicKey))
{
existingUpgrade.PublicKey = PublicKey;
}
if (string.IsNullOrWhiteSpace(existingUpgrade.PrivateKey))
{
existingUpgrade.PrivateKey = EncryptedPrivateKey;
}
return existingUpgrade;
}
public Organization ToOrganization(Organization existingOrg)
{
if (string.IsNullOrWhiteSpace(existingOrg.PublicKey))
{
existingOrg.PublicKey = PublicKey;
}
if (string.IsNullOrWhiteSpace(existingOrg.PrivateKey))
{
existingOrg.PrivateKey = EncryptedPrivateKey;
}
return existingOrg;
}
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationSeatRequestModel : IValidatableObject
{
[Required]
public int? SeatAdjustment { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (SeatAdjustment == 0)
{
yield return new ValidationResult("Seat adjustment cannot be 0.", new string[] { nameof(SeatAdjustment) });
}
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class OrganizationSponsorshipRedeemRequestModel
{
[Required]
public PlanSponsorshipType PlanSponsorshipType { get; set; }
[Required]
public Guid SponsoredOrganizationId { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api.Request
{
public class OrganizationSponsorshipRequestModel
{
[Required]
public PlanSponsorshipType PlanSponsorshipType { get; set; }
[Required]
[StringLength(256)]
[StrictEmailAddress]
public string SponsoredEmail { get; set; }
[StringLength(256)]
public string FriendlyName { get; set; }
}
}

View File

@ -1,239 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using Bit.Core.Services;
using Bit.Core.Models.Data;
using Bit.Core.Enums;
using Bit.Core.Sso;
using U2F.Core.Utils;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using Bit.Core.Models.Table;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
namespace Bit.Core.Models.Api
{
public class OrganizationSsoRequestModel
{
[Required]
public bool Enabled { get; set; }
[Required]
public SsoConfigurationDataRequest Data { get; set; }
public SsoConfig ToSsoConfig(Guid organizationId)
{
return ToSsoConfig(new SsoConfig { OrganizationId = organizationId });
}
public SsoConfig ToSsoConfig(SsoConfig existingConfig)
{
existingConfig.Enabled = Enabled;
var configurationData = Data.ToConfigurationData();
existingConfig.SetData(configurationData);
return existingConfig;
}
}
public class SsoConfigurationDataRequest : IValidatableObject
{
public SsoConfigurationDataRequest() {}
[Required]
public SsoType ConfigType { get; set; }
public bool KeyConnectorEnabled { get; set; }
public string KeyConnectorUrl { get; set; }
// OIDC
public string Authority { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string MetadataAddress { get; set; }
public OpenIdConnectRedirectBehavior RedirectBehavior { get; set; }
public bool? GetClaimsFromUserInfoEndpoint { get; set; }
public string AdditionalScopes { get; set; }
public string AdditionalUserIdClaimTypes { get; set; }
public string AdditionalEmailClaimTypes { get; set; }
public string AdditionalNameClaimTypes { get; set; }
public string AcrValues { get; set; }
public string ExpectedReturnAcrValue { get; set; }
// SAML2 SP
public Saml2NameIdFormat SpNameIdFormat { get; set; }
public string SpOutboundSigningAlgorithm { get; set; }
public Saml2SigningBehavior SpSigningBehavior { get; set; }
public bool? SpWantAssertionsSigned { get; set; }
public bool? SpValidateCertificates { get; set; }
public string SpMinIncomingSigningAlgorithm { get; set; }
// SAML2 IDP
public string IdpEntityId { get; set; }
public Saml2BindingType IdpBindingType { get; set; }
public string IdpSingleSignOnServiceUrl { get; set; }
public string IdpSingleLogoutServiceUrl { get; set; }
public string IdpArtifactResolutionServiceUrl { get; set; }
public string IdpX509PublicCert { get; set; }
public string IdpOutboundSigningAlgorithm { get; set; }
public bool? IdpAllowUnsolicitedAuthnResponse { get; set; }
public bool? IdpDisableOutboundLogoutRequests { get; set; }
public bool? IdpWantAuthnRequestsSigned { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context)
{
var i18nService = context.GetService(typeof(II18nService)) as I18nService;
if (ConfigType == SsoType.OpenIdConnect)
{
if (string.IsNullOrWhiteSpace(Authority))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("AuthorityValidationError"),
new[] { nameof(Authority) });
}
if (string.IsNullOrWhiteSpace(ClientId))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("ClientIdValidationError"),
new[] { nameof(ClientId) });
}
if (string.IsNullOrWhiteSpace(ClientSecret))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("ClientSecretValidationError"),
new[] { nameof(ClientSecret) });
}
}
else if (ConfigType == SsoType.Saml2)
{
if (string.IsNullOrWhiteSpace(IdpEntityId))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpEntityIdValidationError"),
new[] { nameof(IdpEntityId) });
}
if (IdpBindingType == Saml2BindingType.Artifact && string.IsNullOrWhiteSpace(IdpArtifactResolutionServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("Saml2BindingTypeValidationError"),
new[] { nameof(IdpArtifactResolutionServiceUrl) });
}
if (!Uri.IsWellFormedUriString(IdpEntityId, UriKind.Absolute) && string.IsNullOrWhiteSpace(IdpSingleSignOnServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleSignOnServiceUrlValidationError"),
new[] { nameof(IdpSingleSignOnServiceUrl) });
}
if (InvalidServiceUrl(IdpSingleSignOnServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleSignOnServiceUrlInvalid"),
new[] { nameof(IdpSingleSignOnServiceUrl) });
}
if (InvalidServiceUrl(IdpArtifactResolutionServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpArtifactResolutionServiceUrlInvalid"),
new[] { nameof(IdpArtifactResolutionServiceUrl) });
}
if (InvalidServiceUrl(IdpSingleLogoutServiceUrl))
{
yield return new ValidationResult(i18nService.GetLocalizedHtmlString("IdpSingleLogoutServiceUrlInvalid"),
new[] { nameof(IdpSingleLogoutServiceUrl) });
}
if (!string.IsNullOrWhiteSpace(IdpX509PublicCert))
{
// Validate the certificate is in a valid format
ValidationResult failedResult = null;
try
{
var certData = StripPemCertificateElements(IdpX509PublicCert).Base64StringToByteArray();
new X509Certificate2(certData);
}
catch (FormatException)
{
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertInvalidFormatValidationError"),
new[] { nameof(IdpX509PublicCert) });
}
catch (CryptographicException cryptoEx)
{
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertCryptographicExceptionValidationError", cryptoEx.Message),
new[] { nameof(IdpX509PublicCert) });
}
catch (Exception ex)
{
failedResult = new ValidationResult(i18nService.GetLocalizedHtmlString("IdpX509PublicCertValidationError", ex.Message),
new[] { nameof(IdpX509PublicCert) });
}
if (failedResult != null)
{
yield return failedResult;
}
}
}
}
public SsoConfigurationData ToConfigurationData()
{
return new SsoConfigurationData
{
ConfigType = ConfigType,
KeyConnectorEnabled = KeyConnectorEnabled,
KeyConnectorUrl = KeyConnectorUrl,
Authority = Authority,
ClientId = ClientId,
ClientSecret = ClientSecret,
MetadataAddress = MetadataAddress,
GetClaimsFromUserInfoEndpoint = GetClaimsFromUserInfoEndpoint.GetValueOrDefault(),
RedirectBehavior = RedirectBehavior,
IdpEntityId = IdpEntityId,
IdpBindingType = IdpBindingType,
IdpSingleSignOnServiceUrl = IdpSingleSignOnServiceUrl,
IdpSingleLogoutServiceUrl = IdpSingleLogoutServiceUrl,
IdpArtifactResolutionServiceUrl = IdpArtifactResolutionServiceUrl,
IdpX509PublicCert = StripPemCertificateElements(IdpX509PublicCert),
IdpOutboundSigningAlgorithm = IdpOutboundSigningAlgorithm,
IdpAllowUnsolicitedAuthnResponse = IdpAllowUnsolicitedAuthnResponse.GetValueOrDefault(),
IdpDisableOutboundLogoutRequests = IdpDisableOutboundLogoutRequests.GetValueOrDefault(),
IdpWantAuthnRequestsSigned = IdpWantAuthnRequestsSigned.GetValueOrDefault(),
SpNameIdFormat = SpNameIdFormat,
SpOutboundSigningAlgorithm = SpOutboundSigningAlgorithm ?? SamlSigningAlgorithms.Sha256,
SpSigningBehavior = SpSigningBehavior,
SpWantAssertionsSigned = SpWantAssertionsSigned.GetValueOrDefault(),
SpValidateCertificates = SpValidateCertificates.GetValueOrDefault(),
SpMinIncomingSigningAlgorithm = SpMinIncomingSigningAlgorithm,
AdditionalScopes = AdditionalScopes,
AdditionalUserIdClaimTypes = AdditionalUserIdClaimTypes,
AdditionalEmailClaimTypes = AdditionalEmailClaimTypes,
AdditionalNameClaimTypes = AdditionalNameClaimTypes,
AcrValues = AcrValues,
ExpectedReturnAcrValue = ExpectedReturnAcrValue,
};
}
private string StripPemCertificateElements(string certificateText)
{
if (string.IsNullOrWhiteSpace(certificateText))
{
return null;
}
return Regex.Replace(certificateText,
@"(((BEGIN|END) CERTIFICATE)|([\-\n\r\t\s\f]))",
string.Empty,
RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
private bool InvalidServiceUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
{
return false;
}
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
{
return true;
}
return Regex.IsMatch(url, "[<>\"]");
}
}
}

View File

@ -1,11 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationSubscriptionUpdateRequestModel
{
[Required]
public int SeatAdjustment { get; set; }
public int? MaxAutoscaleSeats { get; set; }
}
}

View File

@ -1,11 +0,0 @@
namespace Bit.Core.Models.Api
{
public class OrganizationTaxInfoUpdateRequestModel : TaxInfoUpdateRequestModel
{
public string TaxId { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
}
}

View File

@ -1,38 +0,0 @@
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Settings;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationUpdateRequestModel
{
[Required]
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string BusinessName { get; set; }
[StringLength(50)]
public string Identifier { get; set; }
[EmailAddress]
[Required]
[StringLength(256)]
public string BillingEmail { get; set; }
public Permissions Permissions { get; set; }
public OrganizationKeysRequestModel Keys { get; set; }
public virtual Organization ToOrganization(Organization existingOrganization, GlobalSettings globalSettings)
{
if (!globalSettings.SelfHosted)
{
// These items come from the license file
existingOrganization.Name = Name;
existingOrganization.BusinessName = BusinessName;
existingOrganization.BillingEmail = BillingEmail?.ToLowerInvariant()?.Trim();
}
existingOrganization.Identifier = Identifier;
Keys?.ToOrganization(existingOrganization);
return existingOrganization;
}
}
}

View File

@ -1,42 +0,0 @@
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationUpgradeRequestModel
{
[StringLength(50)]
public string BusinessName { get; set; }
public PlanType PlanType { get; set; }
[Range(0, int.MaxValue)]
public int AdditionalSeats { get; set; }
[Range(0, 99)]
public short? AdditionalStorageGb { get; set; }
public bool PremiumAccessAddon { get; set; }
public string BillingAddressCountry { get; set; }
public string BillingAddressPostalCode { get; set; }
public OrganizationKeysRequestModel Keys { get; set; }
public OrganizationUpgrade ToOrganizationUpgrade()
{
var orgUpgrade = new OrganizationUpgrade
{
AdditionalSeats = AdditionalSeats,
AdditionalStorageGb = AdditionalStorageGb.GetValueOrDefault(),
BusinessName = BusinessName,
Plan = PlanType,
PremiumAccessAddon = PremiumAccessAddon,
TaxInfo = new TaxInfo()
{
BillingAddressCountry = BillingAddressCountry,
BillingAddressPostalCode = BillingAddressPostalCode
}
};
Keys?.ToOrganizationUpgrade(orgUpgrade);
return orgUpgrade;
}
}
}

View File

@ -1,91 +0,0 @@
using System;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text.Json;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class OrganizationUserInviteRequestModel
{
[Required]
[StrictEmailAddressList]
public IEnumerable<string> Emails { get; set; }
[Required]
public Enums.OrganizationUserType? Type { get; set; }
public bool AccessAll { get; set; }
public Permissions Permissions { get; set; }
public IEnumerable<SelectionReadOnlyRequestModel> Collections { get; set; }
}
public class OrganizationUserAcceptRequestModel
{
[Required]
public string Token { get; set; }
}
public class OrganizationUserConfirmRequestModel
{
[Required]
public string Key { get; set; }
}
public class OrganizationUserBulkConfirmRequestModelEntry
{
[Required]
public Guid Id { get; set; }
[Required]
public string Key { get; set; }
}
public class OrganizationUserBulkConfirmRequestModel
{
[Required]
public IEnumerable<OrganizationUserBulkConfirmRequestModelEntry> Keys { get; set; }
public Dictionary<Guid, string> ToDictionary()
{
return Keys.ToDictionary(e => e.Id, e => e.Key);
}
}
public class OrganizationUserUpdateRequestModel
{
[Required]
public Enums.OrganizationUserType? Type { get; set; }
public bool AccessAll { get; set; }
public Permissions Permissions { get; set; }
public IEnumerable<SelectionReadOnlyRequestModel> Collections { get; set; }
public OrganizationUser ToOrganizationUser(OrganizationUser existingUser)
{
existingUser.Type = Type.Value;
existingUser.Permissions = JsonSerializer.Serialize(Permissions, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
existingUser.AccessAll = AccessAll;
return existingUser;
}
}
public class OrganizationUserUpdateGroupsRequestModel
{
[Required]
public IEnumerable<string> GroupIds { get; set; }
}
public class OrganizationUserResetPasswordEnrollmentRequestModel
{
public string ResetPasswordKey { get; set; }
}
public class OrganizationUserBulkRequestModel
{
[Required]
public IEnumerable<Guid> Ids { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationUserResetPasswordRequestModel
{
[Required]
[StringLength(300)]
public string NewMasterPasswordHash { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class OrganizationVerifyBankRequestModel
{
[Required]
[Range(1, 99)]
public int? Amount1 { get; set; }
[Required]
[Range(1, 99)]
public int? Amount2 { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class PaymentRequestModel : OrganizationTaxInfoUpdateRequestModel
{
[Required]
public PaymentMethodType? PaymentMethodType { get; set; }
[Required]
public string PaymentToken { get; set; }
}
}

View File

@ -1,33 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Bit.Core.Models.Api
{
public class PolicyRequestModel
{
[Required]
public Enums.PolicyType? Type { get; set; }
[Required]
public bool? Enabled { get; set; }
public Dictionary<string, object> Data { get; set; }
public Policy ToPolicy(Guid orgId)
{
return ToPolicy(new Policy
{
Type = Type.Value,
OrganizationId = orgId
});
}
public Policy ToPolicy(Policy existingPolicy)
{
existingPolicy.Enabled = Enabled.GetValueOrDefault();
existingPolicy.Data = Data != null ? JsonConvert.SerializeObject(Data) : null;
return existingPolicy;
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class ProviderOrganizationAddRequestModel
{
[Required]
public Guid OrganizationId { get; set; }
[Required]
public string Key { get; set; }
}
}

View File

@ -1,15 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api.Request
{
public class ProviderOrganizationCreateRequestModel
{
[Required]
[StringLength(256)]
[StrictEmailAddress]
public string ClientOwnerEmail { get; set; }
[Required]
public OrganizationCreateRequestModel OrganizationCreateRequest { get; set; }
}
}

View File

@ -1,31 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table.Provider;
namespace Bit.Core.Models.Api
{
public class ProviderSetupRequestModel
{
[Required]
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string BusinessName { get; set; }
[Required]
[StringLength(256)]
[EmailAddress]
public string BillingEmail { get; set; }
[Required]
public string Token { get; set; }
[Required]
public string Key { get; set; }
public virtual Provider ToProvider(Provider provider)
{
provider.Name = Name;
provider.BusinessName = BusinessName;
provider.BillingEmail = BillingEmail;
return provider;
}
}
}

View File

@ -1,31 +0,0 @@
using Bit.Core.Settings;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Models.Table.Provider;
namespace Bit.Core.Models.Api
{
public class ProviderUpdateRequestModel
{
[Required]
[StringLength(50)]
public string Name { get; set; }
[StringLength(50)]
public string BusinessName { get; set; }
[EmailAddress]
[Required]
[StringLength(256)]
public string BillingEmail { get; set; }
public virtual Provider ToProvider(Provider existingProvider, GlobalSettings globalSettings)
{
if (!globalSettings.SelfHosted)
{
// These items come from the license file
existingProvider.Name = Name;
existingProvider.BusinessName = BusinessName;
existingProvider.BillingEmail = BillingEmail?.ToLowerInvariant()?.Trim();
}
return existingProvider;
}
}
}

View File

@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Bit.Core.Enums.Provider;
using Bit.Core.Models.Table.Provider;
using Bit.Core.Utilities;
namespace Bit.Core.Models.Api
{
public class ProviderUserInviteRequestModel
{
[Required]
[StrictEmailAddressList]
public IEnumerable<string> Emails { get; set; }
[Required]
public ProviderUserType? Type { get; set; }
}
public class ProviderUserAcceptRequestModel
{
[Required]
public string Token { get; set; }
}
public class ProviderUserConfirmRequestModel
{
[Required]
public string Key { get; set; }
}
public class ProviderUserBulkConfirmRequestModelEntry
{
[Required]
public Guid Id { get; set; }
[Required]
public string Key { get; set; }
}
public class ProviderUserBulkConfirmRequestModel
{
[Required]
public IEnumerable<ProviderUserBulkConfirmRequestModelEntry> Keys { get; set; }
public Dictionary<Guid, string> ToDictionary()
{
return Keys.ToDictionary(e => e.Id, e => e.Key);
}
}
public class ProviderUserUpdateRequestModel
{
[Required]
public ProviderUserType? Type { get; set; }
public ProviderUser ToProviderUser(ProviderUser existingUser)
{
existingUser.Type = Type.Value;
return existingUser;
}
}
public class ProviderUserBulkRequestModel
{
[Required]
public IEnumerable<Guid> Ids { get; set; }
}
}

View File

@ -1,26 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Bit.Core.Models.Table;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api
{
public class SelectionReadOnlyRequestModel
{
[Required]
public string Id { get; set; }
public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; }
public SelectionReadOnly ToSelectionReadOnly()
{
return new SelectionReadOnly
{
Id = new Guid(Id),
ReadOnly = ReadOnly,
HidePasswords = HidePasswords,
};
}
}
}

View File

@ -1,10 +0,0 @@
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Models.Api
{
public class SendAccessRequestModel
{
[StringLength(300)]
public string Password { get; set; }
}
}

View File

@ -1,139 +0,0 @@
using System;
using Bit.Core.Utilities;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Newtonsoft.Json;
using Bit.Core.Models.Data;
using System.ComponentModel.DataAnnotations;
using Bit.Core.Services;
using Bit.Core.Exceptions;
namespace Bit.Core.Models.Api
{
public class SendRequestModel
{
public SendType Type { get; set; }
public long? FileLength { get; set; } = null;
[EncryptedString]
[EncryptedStringLength(1000)]
public string Name { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string Notes { get; set; }
[Required]
[EncryptedString]
[EncryptedStringLength(1000)]
public string Key { get; set; }
[Range(1, int.MaxValue)]
public int? MaxAccessCount { get; set; }
public DateTime? ExpirationDate { get; set; }
[Required]
public DateTime? DeletionDate { get; set; }
public SendFileModel File { get; set; }
public SendTextModel Text { get; set; }
[StringLength(1000)]
public string Password { get; set; }
[Required]
public bool? Disabled { get; set; }
public bool? HideEmail { get; set; }
public Send ToSend(Guid userId, ISendService sendService)
{
var send = new Send
{
Type = Type,
UserId = (Guid?)userId
};
ToSend(send, sendService);
return send;
}
public (Send, SendFileData) ToSend(Guid userId, string fileName, ISendService sendService)
{
var send = ToSendBase(new Send
{
Type = Type,
UserId = (Guid?)userId
}, sendService);
var data = new SendFileData(this, fileName);
return (send, data);
}
public Send ToSend(Send existingSend, ISendService sendService)
{
existingSend = ToSendBase(existingSend, sendService);
switch (existingSend.Type)
{
case SendType.File:
var fileData = JsonConvert.DeserializeObject<SendFileData>(existingSend.Data);
fileData.Name = Name;
fileData.Notes = Notes;
existingSend.Data = JsonConvert.SerializeObject(fileData,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break;
case SendType.Text:
existingSend.Data = JsonConvert.SerializeObject(new SendTextData(this),
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
break;
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
}
return existingSend;
}
public void ValidateCreation()
{
var now = DateTime.UtcNow;
// Add 1 minute for a sane buffer and client clock float
var nowPlus1Minute = now.AddMinutes(1);
if (ExpirationDate.HasValue && ExpirationDate.Value <= nowPlus1Minute)
{
throw new BadRequestException("You cannot create a Send that is already expired. " +
"Adjust the expiration date and try again.");
}
ValidateEdit();
}
public void ValidateEdit()
{
var now = DateTime.UtcNow;
// Add 1 minute for a sane buffer and client clock float
var nowPlus1Minute = now.AddMinutes(1);
if (DeletionDate.HasValue)
{
if (DeletionDate.Value <= nowPlus1Minute)
{
throw new BadRequestException("You cannot have a Send with a deletion date in the past. " +
"Adjust the deletion date and try again.");
}
if (DeletionDate.Value > now.AddDays(31))
{
throw new BadRequestException("You cannot have a Send with a deletion date that far " +
"into the future. Adjust the Deletion Date to a value less than 31 days from now " +
"and try again.");
}
}
}
private Send ToSendBase(Send existingSend, ISendService sendService)
{
existingSend.Key = Key;
existingSend.ExpirationDate = ExpirationDate;
existingSend.DeletionDate = DeletionDate.Value;
existingSend.MaxAccessCount = MaxAccessCount;
if (!string.IsNullOrWhiteSpace(Password))
{
existingSend.Password = sendService.HashPassword(Password);
}
existingSend.Disabled = Disabled.GetValueOrDefault();
existingSend.HideEmail = HideEmail.GetValueOrDefault();
return existingSend;
}
}
public class SendWithIdRequestModel : SendRequestModel
{
[Required]
public Guid? Id { get; set; }
}
}

View File

@ -1,272 +0,0 @@
using Bit.Core.Enums;
using Bit.Core.Models.Table;
using Fido2NetLib;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Bit.Core.Models.Api
{
public class UpdateTwoFactorAuthenticatorRequestModel : SecretVerificationRequestModel
{
[Required]
[StringLength(50)]
public string Token { get; set; }
[Required]
[StringLength(50)]
public string Key { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.Authenticator))
{
providers.Remove(TwoFactorProviderType.Authenticator);
}
providers.Add(TwoFactorProviderType.Authenticator, new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Key"] = Key },
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
}
public class UpdateTwoFactorDuoRequestModel : SecretVerificationRequestModel, IValidatableObject
{
[Required]
[StringLength(50)]
public string IntegrationKey { get; set; }
[Required]
[StringLength(50)]
public string SecretKey { get; set; }
[Required]
[StringLength(50)]
public string Host { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.Duo))
{
providers.Remove(TwoFactorProviderType.Duo);
}
providers.Add(TwoFactorProviderType.Duo, new TwoFactorProvider
{
MetaData = new Dictionary<string, object>
{
["SKey"] = SecretKey,
["IKey"] = IntegrationKey,
["Host"] = Host
},
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
public Organization ToOrganization(Organization extistingOrg)
{
var providers = extistingOrg.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.OrganizationDuo))
{
providers.Remove(TwoFactorProviderType.OrganizationDuo);
}
providers.Add(TwoFactorProviderType.OrganizationDuo, new TwoFactorProvider
{
MetaData = new Dictionary<string, object>
{
["SKey"] = SecretKey,
["IKey"] = IntegrationKey,
["Host"] = Host
},
Enabled = true
});
extistingOrg.SetTwoFactorProviders(providers);
return extistingOrg;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!Host.StartsWith("api-") || (!Host.EndsWith(".duosecurity.com") && !Host.EndsWith(".duofederal.com")))
{
yield return new ValidationResult("Host is invalid.", new string[] { nameof(Host) });
}
}
}
public class UpdateTwoFactorYubicoOtpRequestModel : SecretVerificationRequestModel, IValidatableObject
{
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Key3 { get; set; }
public string Key4 { get; set; }
public string Key5 { get; set; }
[Required]
public bool? Nfc { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.YubiKey))
{
providers.Remove(TwoFactorProviderType.YubiKey);
}
providers.Add(TwoFactorProviderType.YubiKey, new TwoFactorProvider
{
MetaData = new Dictionary<string, object>
{
["Key1"] = FormatKey(Key1),
["Key2"] = FormatKey(Key2),
["Key3"] = FormatKey(Key3),
["Key4"] = FormatKey(Key4),
["Key5"] = FormatKey(Key5),
["Nfc"] = Nfc.Value
},
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
private string FormatKey(string keyValue)
{
if (string.IsNullOrWhiteSpace(keyValue))
{
return null;
}
return keyValue.Substring(0, 12);
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrWhiteSpace(Key1) && string.IsNullOrWhiteSpace(Key2) && string.IsNullOrWhiteSpace(Key3) &&
string.IsNullOrWhiteSpace(Key4) && string.IsNullOrWhiteSpace(Key5))
{
yield return new ValidationResult("A key is required.", new string[] { nameof(Key1) });
}
if (!string.IsNullOrWhiteSpace(Key1) && Key1.Length < 12)
{
yield return new ValidationResult("Key 1 in invalid.", new string[] { nameof(Key1) });
}
if (!string.IsNullOrWhiteSpace(Key2) && Key2.Length < 12)
{
yield return new ValidationResult("Key 2 in invalid.", new string[] { nameof(Key2) });
}
if (!string.IsNullOrWhiteSpace(Key3) && Key3.Length < 12)
{
yield return new ValidationResult("Key 3 in invalid.", new string[] { nameof(Key3) });
}
if (!string.IsNullOrWhiteSpace(Key4) && Key4.Length < 12)
{
yield return new ValidationResult("Key 4 in invalid.", new string[] { nameof(Key4) });
}
if (!string.IsNullOrWhiteSpace(Key5) && Key5.Length < 12)
{
yield return new ValidationResult("Key 5 in invalid.", new string[] { nameof(Key5) });
}
}
}
public class TwoFactorEmailRequestModel : SecretVerificationRequestModel
{
[Required]
[EmailAddress]
[StringLength(256)]
public string Email { get; set; }
public User ToUser(User extistingUser)
{
var providers = extistingUser.GetTwoFactorProviders();
if (providers == null)
{
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
}
else if (providers.ContainsKey(TwoFactorProviderType.Email))
{
providers.Remove(TwoFactorProviderType.Email);
}
providers.Add(TwoFactorProviderType.Email, new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = Email.ToLowerInvariant() },
Enabled = true
});
extistingUser.SetTwoFactorProviders(providers);
return extistingUser;
}
}
public class TwoFactorWebAuthnRequestModel : TwoFactorWebAuthnDeleteRequestModel
{
[Required]
public AuthenticatorAttestationRawResponse DeviceResponse { get; set; }
public string Name { get; set; }
}
public class TwoFactorWebAuthnDeleteRequestModel : SecretVerificationRequestModel, IValidatableObject
{
[Required]
public int? Id { get; set; }
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach (var validationResult in base.Validate(validationContext))
{
yield return validationResult;
}
if (!Id.HasValue || Id < 0 || Id > 5)
{
yield return new ValidationResult("Invalid Key Id", new string[] { nameof(Id) });
}
}
}
public class UpdateTwoFactorEmailRequestModel : TwoFactorEmailRequestModel
{
[Required]
[StringLength(50)]
public string Token { get; set; }
}
public class TwoFactorProviderRequestModel : SecretVerificationRequestModel
{
[Required]
public TwoFactorProviderType? Type { get; set; }
}
public class TwoFactorRecoveryRequestModel : TwoFactorEmailRequestModel
{
[Required]
[StringLength(32)]
public string RecoveryCode { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using Bit.Core.Models.Table;
using System.Collections.Generic;
using Bit.Core.Enums;
using Newtonsoft.Json;
namespace Bit.Core.Models.Api
{
public class UpdateDomainsRequestModel
{
public IEnumerable<IEnumerable<string>> EquivalentDomains { get; set; }
public IEnumerable<GlobalEquivalentDomainsType> ExcludedGlobalEquivalentDomains { get; set; }
public User ToUser(User existingUser)
{
existingUser.EquivalentDomains = EquivalentDomains != null ? JsonConvert.SerializeObject(EquivalentDomains) : null;
existingUser.ExcludedGlobalEquivalentDomains = ExcludedGlobalEquivalentDomains != null ?
JsonConvert.SerializeObject(ExcludedGlobalEquivalentDomains) : null;
return existingUser;
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Api
{
public class ApiKeyResponseModel : ResponseModel
{
public ApiKeyResponseModel(Organization organization, string obj = "apiKey")
: base(obj)
{
if (organization == null)
{
throw new ArgumentNullException(nameof(organization));
}
ApiKey = organization.ApiKey;
}
public ApiKeyResponseModel(User user, string obj = "apiKey")
: base(obj)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
ApiKey = user.ApiKey;
}
public string ApiKey { get; set; }
}
}

View File

@ -1,41 +0,0 @@
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using System.Collections.Generic;
using System.Linq;
using Bit.Core.Settings;
namespace Bit.Core.Models.Api
{
public class AttachmentResponseModel : ResponseModel
{
public AttachmentResponseModel(string id, CipherAttachment.MetaData data, Cipher cipher,
GlobalSettings globalSettings)
: base("attachment")
{
Id = id;
Url = $"{globalSettings.Attachment.BaseUrl}/{cipher.Id}/{id}";
FileName = data.FileName;
Key = data.Key;
Size = data.SizeString;
SizeName = Utilities.CoreHelpers.ReadableBytesSize(data.Size);
}
public string Id { get; set; }
public string Url { get; set; }
public string FileName { get; set; }
public string Key { get; set; }
public string Size { get; set; }
public string SizeName { get; set; }
public static IEnumerable<AttachmentResponseModel> FromCipher(Cipher cipher, GlobalSettings globalSettings)
{
var attachments = cipher.GetAttachments();
if (attachments == null)
{
return null;
}
return attachments.Select(a => new AttachmentResponseModel(a.Key, a.Value, cipher, globalSettings));
}
}
}

View File

@ -1,15 +0,0 @@
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class AttachmentUploadDataResponseModel : ResponseModel
{
public string AttachmentId { get; set; }
public string Url { get; set; }
public FileUploadType FileUploadType { get; set; }
public CipherResponseModel CipherResponse { get; set; }
public CipherMiniResponseModel CipherMiniResponse { get; set; }
public AttachmentUploadDataResponseModel() : base("attachment-fileUpload") { }
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Bit.Core.Models.Business;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class BillingResponseModel : ResponseModel
{
public BillingResponseModel(BillingInfo billing)
: base("billing")
{
Balance = billing.Balance;
PaymentSource = billing.PaymentSource != null ? new BillingSource(billing.PaymentSource) : null;
Transactions = billing.Transactions?.Select(t => new BillingTransaction(t));
Invoices = billing.Invoices?.Select(i => new BillingInvoice(i));
}
public decimal Balance { get; set; }
public BillingSource PaymentSource { get; set; }
public IEnumerable<BillingInvoice> Invoices { get; set; }
public IEnumerable<BillingTransaction> Transactions { get; set; }
}
public class BillingSource
{
public BillingSource(BillingInfo.BillingSource source)
{
Type = source.Type;
CardBrand = source.CardBrand;
Description = source.Description;
NeedsVerification = source.NeedsVerification;
}
public PaymentMethodType Type { get; set; }
public string CardBrand { get; set; }
public string Description { get; set; }
public bool NeedsVerification { get; set; }
}
public class BillingInvoice
{
public BillingInvoice(BillingInfo.BillingInvoice inv)
{
Amount = inv.Amount;
Date = inv.Date;
Url = inv.Url;
PdfUrl = inv.PdfUrl;
Number = inv.Number;
Paid = inv.Paid;
}
public decimal Amount { get; set; }
public DateTime? Date { get; set; }
public string Url { get; set; }
public string PdfUrl { get; set; }
public string Number { get; set; }
public bool Paid { get; set; }
}
public class BillingTransaction
{
public BillingTransaction(BillingInfo.BillingTransaction transaction)
{
CreatedDate = transaction.CreatedDate;
Amount = transaction.Amount;
Refunded = transaction.Refunded;
RefundedAmount = transaction.RefundedAmount;
PartiallyRefunded = transaction.PartiallyRefunded;
Type = transaction.Type;
PaymentMethodType = transaction.PaymentMethodType;
Details = transaction.Details;
}
public DateTime CreatedDate { get; set; }
public decimal Amount { get; set; }
public bool? Refunded { get; set; }
public bool? PartiallyRefunded { get; set; }
public decimal? RefundedAmount { get; set; }
public TransactionType Type { get; set; }
public PaymentMethodType? PaymentMethodType { get; set; }
public string Details { get; set; }
}
}

View File

@ -1,149 +0,0 @@
using System;
using Core.Models.Data;
using System.Collections.Generic;
using Bit.Core.Models.Table;
using System.Linq;
using Newtonsoft.Json;
using Bit.Core.Models.Data;
using Bit.Core.Settings;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class CipherMiniResponseModel : ResponseModel
{
public CipherMiniResponseModel(Cipher cipher, GlobalSettings globalSettings, bool orgUseTotp, string obj = "cipherMini")
: base(obj)
{
if (cipher == null)
{
throw new ArgumentNullException(nameof(cipher));
}
Id = cipher.Id.ToString();
Type = cipher.Type;
CipherData cipherData;
switch (cipher.Type)
{
case Enums.CipherType.Login:
var loginData = JsonConvert.DeserializeObject<CipherLoginData>(cipher.Data);
cipherData = loginData;
Data = loginData;
Login = new CipherLoginModel(loginData);
break;
case Enums.CipherType.SecureNote:
var secureNoteData = JsonConvert.DeserializeObject<CipherSecureNoteData>(cipher.Data);
Data = secureNoteData;
cipherData = secureNoteData;
SecureNote = new CipherSecureNoteModel(secureNoteData);
break;
case Enums.CipherType.Card:
var cardData = JsonConvert.DeserializeObject<CipherCardData>(cipher.Data);
Data = cardData;
cipherData = cardData;
Card = new CipherCardModel(cardData);
break;
case Enums.CipherType.Identity:
var identityData = JsonConvert.DeserializeObject<CipherIdentityData>(cipher.Data);
Data = identityData;
cipherData = identityData;
Identity = new CipherIdentityModel(identityData);
break;
default:
throw new ArgumentException("Unsupported " + nameof(Type) + ".");
}
Name = cipherData.Name;
Notes = cipherData.Notes;
Fields = cipherData.Fields?.Select(f => new CipherFieldModel(f));
PasswordHistory = cipherData.PasswordHistory?.Select(ph => new CipherPasswordHistoryModel(ph));
RevisionDate = cipher.RevisionDate;
OrganizationId = cipher.OrganizationId?.ToString();
Attachments = AttachmentResponseModel.FromCipher(cipher, globalSettings);
OrganizationUseTotp = orgUseTotp;
DeletedDate = cipher.DeletedDate;
Reprompt = cipher.Reprompt.GetValueOrDefault(CipherRepromptType.None);
}
public string Id { get; set; }
public string OrganizationId { get; set; }
public Enums.CipherType Type { get; set; }
public dynamic Data { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public CipherLoginModel Login { get; set; }
public CipherCardModel Card { get; set; }
public CipherIdentityModel Identity { get; set; }
public CipherSecureNoteModel SecureNote { get; set; }
public IEnumerable<CipherFieldModel> Fields { get; set; }
public IEnumerable<CipherPasswordHistoryModel> PasswordHistory { get; set; }
public IEnumerable<AttachmentResponseModel> Attachments { get; set; }
public bool OrganizationUseTotp { get; set; }
public DateTime RevisionDate { get; set; }
public DateTime? DeletedDate { get; set; }
public CipherRepromptType Reprompt { get; set; }
}
public class CipherResponseModel : CipherMiniResponseModel
{
public CipherResponseModel(CipherDetails cipher, GlobalSettings globalSettings, string obj = "cipher")
: base(cipher, globalSettings, cipher.OrganizationUseTotp, obj)
{
FolderId = cipher.FolderId?.ToString();
Favorite = cipher.Favorite;
Edit = cipher.Edit;
ViewPassword = cipher.ViewPassword;
}
public string FolderId { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool ViewPassword { get; set; }
}
public class CipherDetailsResponseModel : CipherResponseModel
{
public CipherDetailsResponseModel(CipherDetails cipher, GlobalSettings globalSettings,
IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphers, string obj = "cipherDetails")
: base(cipher, globalSettings, obj)
{
if (collectionCiphers?.ContainsKey(cipher.Id) ?? false)
{
CollectionIds = collectionCiphers[cipher.Id].Select(c => c.CollectionId);
}
else
{
CollectionIds = new Guid[] { };
}
}
public CipherDetailsResponseModel(CipherDetails cipher, GlobalSettings globalSettings,
IEnumerable<CollectionCipher> collectionCiphers, string obj = "cipherDetails")
: base(cipher, globalSettings, obj)
{
CollectionIds = collectionCiphers?.Select(c => c.CollectionId) ?? new List<Guid>();
}
public IEnumerable<Guid> CollectionIds { get; set; }
}
public class CipherMiniDetailsResponseModel : CipherMiniResponseModel
{
public CipherMiniDetailsResponseModel(Cipher cipher, GlobalSettings globalSettings,
IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphers, string obj = "cipherMiniDetails")
: base(cipher, globalSettings, false, obj)
{
if (collectionCiphers?.ContainsKey(cipher.Id) ?? false)
{
CollectionIds = collectionCiphers[cipher.Id].Select(c => c.CollectionId);
}
else
{
CollectionIds = new Guid[] { };
}
}
public IEnumerable<Guid> CollectionIds { get; set; }
}
}

View File

@ -1,54 +0,0 @@
using System;
using Bit.Core.Models.Table;
using System.Collections.Generic;
using Bit.Core.Models.Data;
using System.Linq;
namespace Bit.Core.Models.Api
{
public class CollectionResponseModel : ResponseModel
{
public CollectionResponseModel(Collection collection, string obj = "collection")
: base(obj)
{
if (collection == null)
{
throw new ArgumentNullException(nameof(collection));
}
Id = collection.Id.ToString();
OrganizationId = collection.OrganizationId.ToString();
Name = collection.Name;
ExternalId = collection.ExternalId;
}
public string Id { get; set; }
public string OrganizationId { get; set; }
public string Name { get; set; }
public string ExternalId { get; set; }
}
public class CollectionDetailsResponseModel : CollectionResponseModel
{
public CollectionDetailsResponseModel(CollectionDetails collectionDetails)
: base(collectionDetails, "collectionDetails")
{
ReadOnly = collectionDetails.ReadOnly;
HidePasswords = collectionDetails.HidePasswords;
}
public bool ReadOnly { get; set; }
public bool HidePasswords { get; set; }
}
public class CollectionGroupDetailsResponseModel : CollectionResponseModel
{
public CollectionGroupDetailsResponseModel(Collection collection, IEnumerable<SelectionReadOnly> groups)
: base(collection, "collectionGroupDetails")
{
Groups = groups.Select(g => new SelectionReadOnlyResponseModel(g));
}
public IEnumerable<SelectionReadOnlyResponseModel> Groups { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More