From ee9995616e8e8c9e38e929c2f21362e963ed2424 Mon Sep 17 00:00:00 2001
From: John Harrington <84741727+harr1424@users.noreply.github.com>
Date: Sat, 17 Jan 2026 16:48:41 -0700
Subject: [PATCH] models, entity, and stored procs updated to work with
EmailHashes with migrations
---
.../Tools/Models/Request/SendRequestModel.cs | 11 +-
.../Models/Response/SendResponseModel.cs | 7 +
src/Core/Tools/Entities/Send.cs | 9 +
.../Tools/Stored Procedures/Send_Create.sql | 9 +-
.../Tools/Stored Procedures/Send_Update.sql | 6 +-
src/Sql/dbo/Tools/Tables/Send.sql | 22 +-
.../2026-01-17_00_Send_EmailHashes.sql | 148 +
...2026-01-17_00_Send_EmailHashes.Designer.cs | 3506 ++++++++++++++++
...17234040_2026-01-17_00_Send_EmailHashes.cs | 29 +
.../DatabaseContextModelSnapshot.cs | 4 +
...2026-01-17_00_Send_EmailHashes.Designer.cs | 3512 +++++++++++++++++
...17234031_2026-01-17_00_Send_EmailHashes.cs | 28 +
.../DatabaseContextModelSnapshot.cs | 4 +
...2026-01-17_00_Send_EmailHashes.Designer.cs | 3495 ++++++++++++++++
...17234036_2026-01-17_00_Send_EmailHashes.cs | 28 +
.../DatabaseContextModelSnapshot.cs | 4 +
16 files changed, 10806 insertions(+), 16 deletions(-)
create mode 100644 util/Migrator/DbScripts/2026-01-17_00_Send_EmailHashes.sql
create mode 100644 util/MySqlMigrations/Migrations/20260117234040_2026-01-17_00_Send_EmailHashes.Designer.cs
create mode 100644 util/MySqlMigrations/Migrations/20260117234040_2026-01-17_00_Send_EmailHashes.cs
create mode 100644 util/PostgresMigrations/Migrations/20260117234031_2026-01-17_00_Send_EmailHashes.Designer.cs
create mode 100644 util/PostgresMigrations/Migrations/20260117234031_2026-01-17_00_Send_EmailHashes.cs
create mode 100644 util/SqliteMigrations/Migrations/20260117234036_2026-01-17_00_Send_EmailHashes.Designer.cs
create mode 100644 util/SqliteMigrations/Migrations/20260117234036_2026-01-17_00_Send_EmailHashes.cs
diff --git a/src/Api/Tools/Models/Request/SendRequestModel.cs b/src/Api/Tools/Models/Request/SendRequestModel.cs
index f3308dbd5a..4afb9ade68 100644
--- a/src/Api/Tools/Models/Request/SendRequestModel.cs
+++ b/src/Api/Tools/Models/Request/SendRequestModel.cs
@@ -102,9 +102,17 @@ public class SendRequestModel
/// Comma-separated list of emails that may access the send using OTP
/// authentication. Mutually exclusive with .
///
- [StringLength(4000)]
+ [EncryptedString]
+ [EncryptedStringLength(4000)]
public string Emails { get; set; }
+ ///
+ /// Comma-separated list of email **hashes** that may access the send using OTP
+ /// authentication. Mutually exclusive with .
+ ///
+ [StringLength(1000)]
+ public string EmailHashes { get; set; }
+
///
/// When , send access is disabled.
/// Defaults to .
@@ -253,6 +261,7 @@ public class SendRequestModel
// normalize encoding
var emails = Emails.Split(',', RemoveEmptyEntries | TrimEntries);
existingSend.Emails = string.Join(",", emails);
+ existingSend.EmailHashes = EmailHashes;
existingSend.Password = null;
existingSend.AuthType = Core.Tools.Enums.AuthType.Email;
}
diff --git a/src/Api/Tools/Models/Response/SendResponseModel.cs b/src/Api/Tools/Models/Response/SendResponseModel.cs
index f7f6b683d6..295814353c 100644
--- a/src/Api/Tools/Models/Response/SendResponseModel.cs
+++ b/src/Api/Tools/Models/Response/SendResponseModel.cs
@@ -47,6 +47,7 @@ public class SendResponseModel : ResponseModel
DeletionDate = send.DeletionDate;
Password = send.Password;
Emails = send.Emails;
+ EmailHashes = send.EmailHashes;
Disabled = send.Disabled;
HideEmail = send.HideEmail.GetValueOrDefault();
@@ -154,6 +155,12 @@ public class SendResponseModel : ResponseModel
///
public string Emails { get; set; }
+ ///
+ /// Comma-separated list of email **hashes** that may access the send using OTP
+ /// authentication. Mutually exclusive with .
+ ///
+ public string EmailHashes { get; set; }
+
///
/// When , send access is disabled.
///
diff --git a/src/Core/Tools/Entities/Send.cs b/src/Core/Tools/Entities/Send.cs
index 52b439c41e..c4398e212c 100644
--- a/src/Core/Tools/Entities/Send.cs
+++ b/src/Core/Tools/Entities/Send.cs
@@ -81,6 +81,15 @@ public class Send : ITableObject
[MaxLength(4000)]
public string? Emails { get; set; }
+ ///
+ /// Comma-separated list of email **hashes** for OTP authentication.
+ ///
+ ///
+ /// This field is mutually exclusive with
+ ///
+ [MaxLength(4000)]
+ public string? EmailHashes { get; set; }
+
///
/// The send becomes unavailable to API callers when
/// >= .
diff --git a/src/Sql/dbo/Tools/Stored Procedures/Send_Create.sql b/src/Sql/dbo/Tools/Stored Procedures/Send_Create.sql
index 752f8fb496..e277174717 100644
--- a/src/Sql/dbo/Tools/Stored Procedures/Send_Create.sql
+++ b/src/Sql/dbo/Tools/Stored Procedures/Send_Create.sql
@@ -18,7 +18,8 @@
-- FIXME: remove null default value once this argument has been
-- in 2 server releases
@Emails NVARCHAR(4000) = NULL,
- @AuthType TINYINT = NULL
+ @AuthType TINYINT = NULL,
+ @EmailHashes NVARCHAR(4000) = NULL
AS
BEGIN
SET NOCOUNT ON
@@ -42,7 +43,8 @@ BEGIN
[HideEmail],
[CipherId],
[Emails],
- [AuthType]
+ [AuthType],
+ [EmailHashes]
)
VALUES
(
@@ -63,7 +65,8 @@ BEGIN
@HideEmail,
@CipherId,
@Emails,
- @AuthType
+ @AuthType,
+ @EmailHashes
)
IF @UserId IS NOT NULL
diff --git a/src/Sql/dbo/Tools/Stored Procedures/Send_Update.sql b/src/Sql/dbo/Tools/Stored Procedures/Send_Update.sql
index fba842d8d6..a2bcb0a24b 100644
--- a/src/Sql/dbo/Tools/Stored Procedures/Send_Update.sql
+++ b/src/Sql/dbo/Tools/Stored Procedures/Send_Update.sql
@@ -16,7 +16,8 @@
@HideEmail BIT,
@CipherId UNIQUEIDENTIFIER = NULL,
@Emails NVARCHAR(4000) = NULL,
- @AuthType TINYINT = NULL
+ @AuthType TINYINT = NULL,
+ @EmailHashes NVARCHAR(4000) = NULL
AS
BEGIN
SET NOCOUNT ON
@@ -40,7 +41,8 @@ BEGIN
[HideEmail] = @HideEmail,
[CipherId] = @CipherId,
[Emails] = @Emails,
- [AuthType] = @AuthType
+ [AuthType] = @AuthType,
+ [EmailHashes] = @EmailHashes
WHERE
[Id] = @Id
diff --git a/src/Sql/dbo/Tools/Tables/Send.sql b/src/Sql/dbo/Tools/Tables/Send.sql
index 94311d6328..b28be11e03 100644
--- a/src/Sql/dbo/Tools/Tables/Send.sql
+++ b/src/Sql/dbo/Tools/Tables/Send.sql
@@ -1,22 +1,24 @@
-CREATE TABLE [dbo].[Send] (
+CREATE TABLE [dbo].[Send]
+(
[Id] UNIQUEIDENTIFIER NOT NULL,
[UserId] UNIQUEIDENTIFIER NULL,
[OrganizationId] UNIQUEIDENTIFIER NULL,
[Type] TINYINT NOT NULL,
[Data] VARCHAR(MAX) NOT NULL,
- [Key] VARCHAR (MAX) NOT NULL,
- [Password] NVARCHAR (300) NULL,
- [Emails] NVARCHAR (4000) NULL,
+ [Key] VARCHAR(MAX) NOT NULL,
+ [Password] NVARCHAR(300) NULL,
+ [Emails] NVARCHAR(4000) NULL,
[MaxAccessCount] INT NULL,
[AccessCount] INT NOT NULL,
- [CreationDate] DATETIME2 (7) NOT NULL,
- [RevisionDate] DATETIME2 (7) NOT NULL,
- [ExpirationDate] DATETIME2 (7) NULL,
- [DeletionDate] DATETIME2 (7) NOT NULL,
+ [CreationDate] DATETIME2(7) NOT NULL,
+ [RevisionDate] DATETIME2(7) NOT NULL,
+ [ExpirationDate] DATETIME2(7) NULL,
+ [DeletionDate] DATETIME2(7) NOT NULL,
[Disabled] BIT NOT NULL,
[HideEmail] BIT NULL,
[CipherId] UNIQUEIDENTIFIER NULL,
[AuthType] TINYINT NULL,
+ [EmailHashes] NVARCHAR(4000) NULL,
CONSTRAINT [PK_Send] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Send_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]),
CONSTRAINT [FK_Send_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id]),
@@ -26,9 +28,9 @@
GO
CREATE NONCLUSTERED INDEX [IX_Send_UserId_OrganizationId]
- ON [dbo].[Send]([UserId] ASC, [OrganizationId] ASC);
+ ON [dbo].[Send] ([UserId] ASC, [OrganizationId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_Send_DeletionDate]
- ON [dbo].[Send]([DeletionDate] ASC);
+ ON [dbo].[Send] ([DeletionDate] ASC);
diff --git a/util/Migrator/DbScripts/2026-01-17_00_Send_EmailHashes.sql b/util/Migrator/DbScripts/2026-01-17_00_Send_EmailHashes.sql
new file mode 100644
index 0000000000..2b00913661
--- /dev/null
+++ b/util/Migrator/DbScripts/2026-01-17_00_Send_EmailHashes.sql
@@ -0,0 +1,148 @@
+-- Update Send table to add EmailHashes Column
+IF COL_LENGTH('[dbo].[Send]', 'EmailHashes') IS NULL
+BEGIN
+ALTER TABLE [dbo].[Send]
+ ADD [EmailHashes] NVARCHAR(4000) NULL;
+END
+GO
+
+-- Update Send_Create to include EmailHashes column
+CREATE OR ALTER PROCEDURE [dbo].[Send_Create]
+ @Id UNIQUEIDENTIFIER OUTPUT,
+ @UserId UNIQUEIDENTIFIER,
+ @OrganizationId UNIQUEIDENTIFIER,
+ @Type TINYINT,
+ @Data VARCHAR(MAX),
+ @Key VARCHAR(MAX),
+ @Password NVARCHAR(300),
+ @MaxAccessCount INT,
+ @AccessCount INT,
+ @CreationDate DATETIME2(7),
+ @RevisionDate DATETIME2(7),
+ @ExpirationDate DATETIME2(7),
+ @DeletionDate DATETIME2(7),
+ @Disabled BIT,
+ @HideEmail BIT,
+ @CipherId UNIQUEIDENTIFIER = NULL,
+ @Emails NVARCHAR(4000) = NULL,
+ @AuthType TINYINT = NULL,
+ @EmailHashes NVARCHAR(4000) = NULL
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ INSERT INTO [dbo].[Send]
+ (
+ [Id],
+ [UserId],
+ [OrganizationId],
+ [Type],
+ [Data],
+ [Key],
+ [Password],
+ [MaxAccessCount],
+ [AccessCount],
+ [CreationDate],
+ [RevisionDate],
+ [ExpirationDate],
+ [DeletionDate],
+ [Disabled],
+ [HideEmail],
+ [CipherId],
+ [Emails],
+ [AuthType],
+ [EmailHashes]
+ )
+ VALUES
+ (
+ @Id,
+ @UserId,
+ @OrganizationId,
+ @Type,
+ @Data,
+ @Key,
+ @Password,
+ @MaxAccessCount,
+ @AccessCount,
+ @CreationDate,
+ @RevisionDate,
+ @ExpirationDate,
+ @DeletionDate,
+ @Disabled,
+ @HideEmail,
+ @CipherId,
+ @Emails,
+ @AuthType,
+ @EmailHashes
+ )
+
+ IF @UserId IS NOT NULL
+ BEGIN
+ IF @Type = 1 --File
+ BEGIN
+ EXEC [dbo].[User_UpdateStorage] @UserId
+ END
+ EXEC [dbo].[User_BumpAccountRevisionDate] @UserId
+ END
+ -- TODO: OrganizationId bump?
+END
+GO
+
+-- Update Send_Update to include EmailHashes column
+CREATE OR ALTER PROCEDURE [dbo].[Send_Update]
+ @Id UNIQUEIDENTIFIER,
+ @UserId UNIQUEIDENTIFIER,
+ @OrganizationId UNIQUEIDENTIFIER,
+ @Type TINYINT,
+ @Data VARCHAR(MAX),
+ @Key VARCHAR(MAX),
+ @Password NVARCHAR(300),
+ @MaxAccessCount INT,
+ @AccessCount INT,
+ @CreationDate DATETIME2(7),
+ @RevisionDate DATETIME2(7),
+ @ExpirationDate DATETIME2(7),
+ @DeletionDate DATETIME2(7),
+ @Disabled BIT,
+ @HideEmail BIT,
+ @CipherId UNIQUEIDENTIFIER = NULL,
+ @Emails NVARCHAR(4000) = NULL,
+ @AuthType TINYINT = NULL,
+ @EmailHashes NVARCHAR(4000) = NULL
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ UPDATE
+ [dbo].[Send]
+ SET
+ [UserId] = @UserId,
+ [OrganizationId] = @OrganizationId,
+ [Type] = @Type,
+ [Data] = @Data,
+ [Key] = @Key,
+ [Password] = @Password,
+ [MaxAccessCount] = @MaxAccessCount,
+ [AccessCount] = @AccessCount,
+ [CreationDate] = @CreationDate,
+ [RevisionDate] = @RevisionDate,
+ [ExpirationDate] = @ExpirationDate,
+ [DeletionDate] = @DeletionDate,
+ [Disabled] = @Disabled,
+ [HideEmail] = @HideEmail,
+ [CipherId] = @CipherId,
+ [Emails] = @Emails,
+ [AuthType] = @AuthType,
+ [EmailHashes] = @EmailHashes
+ WHERE
+ [Id] = @Id
+
+ IF @UserId IS NOT NULL
+ BEGIN
+ EXEC [dbo].[User_BumpAccountRevisionDate] @UserId
+ END
+ -- TODO: OrganizationId bump?
+END
+GO
+EXECUTE sp_refreshview N'[dbo].[SendView]'
+GO
diff --git a/util/MySqlMigrations/Migrations/20260117234040_2026-01-17_00_Send_EmailHashes.Designer.cs b/util/MySqlMigrations/Migrations/20260117234040_2026-01-17_00_Send_EmailHashes.Designer.cs
new file mode 100644
index 0000000000..3b2aff4547
--- /dev/null
+++ b/util/MySqlMigrations/Migrations/20260117234040_2026-01-17_00_Send_EmailHashes.Designer.cs
@@ -0,0 +1,3506 @@
+//
+using System;
+using Bit.Infrastructure.EntityFramework.Repositories;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Bit.MySqlMigrations.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20260117234040_2026-01-17_00_Send_EmailHashes")]
+ partial class _20260117_00_Send_EmailHashes
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.8")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
+
+ modelBuilder.Entity("Bit.Core.Dirt.Reports.Models.Data.OrganizationMemberBaseDetail", b =>
+ {
+ b.Property("CipherId")
+ .HasColumnType("char(36)");
+
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("CollectionName")
+ .HasColumnType("longtext");
+
+ b.Property("Email")
+ .HasColumnType("longtext");
+
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("GroupName")
+ .HasColumnType("longtext");
+
+ b.Property("HidePasswords")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Manage")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ReadOnly")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ResetPasswordKey")
+ .HasColumnType("longtext");
+
+ b.Property("TwoFactorProviders")
+ .HasColumnType("longtext");
+
+ b.Property("UserGuid")
+ .HasColumnType("char(36)");
+
+ b.Property("UserName")
+ .HasColumnType("longtext");
+
+ b.Property("UsesKeyConnector")
+ .HasColumnType("tinyint(1)");
+
+ b.ToTable("OrganizationMemberBaseDetails");
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AllowAdminAccessToAllCollectionItems")
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(true);
+
+ b.Property("BillingEmail")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("BusinessAddress1")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessAddress2")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessAddress3")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessCountry")
+ .HasMaxLength(2)
+ .HasColumnType("varchar(2)");
+
+ b.Property("BusinessName")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("BusinessTaxNumber")
+ .HasMaxLength(30)
+ .HasColumnType("varchar(30)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Gateway")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("GatewayCustomerId")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("GatewaySubscriptionId")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Identifier")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("LicenseKey")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("LimitCollectionCreation")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LimitCollectionDeletion")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LimitItemDeletion")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("MaxAutoscaleSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxAutoscaleSmSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxAutoscaleSmServiceAccounts")
+ .HasColumnType("int");
+
+ b.Property("MaxCollections")
+ .HasColumnType("smallint");
+
+ b.Property("MaxStorageGb")
+ .HasColumnType("smallint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("OwnersNotifiedOfAutoscaling")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Plan")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PlanType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("PrivateKey")
+ .HasColumnType("longtext");
+
+ b.Property("PublicKey")
+ .HasColumnType("longtext");
+
+ b.Property("ReferenceData")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Seats")
+ .HasColumnType("int");
+
+ b.Property("SelfHost")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("SmSeats")
+ .HasColumnType("int");
+
+ b.Property("SmServiceAccounts")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Storage")
+ .HasColumnType("bigint");
+
+ b.Property("SyncSeats")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("TwoFactorProviders")
+ .HasColumnType("longtext");
+
+ b.Property("Use2fa")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseAdminSponsoredFamilies")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseApi")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseAutomaticUserConfirmation")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseCustomPermissions")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseDirectory")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseDisableSmAdsForUsers")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseGroups")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseKeyConnector")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseOrganizationDomains")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePasswordManager")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePhishingBlocker")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePolicies")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseResetPassword")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseRiskInsights")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseScim")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseSecretsManager")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseSso")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseTotp")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsersGetPremium")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Id", "Enabled")
+ .HasAnnotation("Npgsql:IndexInclude", new[] { "UseTotp", "UsersGetPremium" });
+
+ b.ToTable("Organization", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Policy", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .HasColumnType("longtext");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId", "Type")
+ .IsUnique()
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("Policy", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider.Provider", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("BillingEmail")
+ .HasColumnType("longtext");
+
+ b.Property("BillingPhone")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessAddress1")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessAddress2")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessAddress3")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessCountry")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessName")
+ .HasColumnType("longtext");
+
+ b.Property("BusinessTaxNumber")
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("DiscountId")
+ .HasColumnType("longtext");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Gateway")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("GatewayCustomerId")
+ .HasColumnType("longtext");
+
+ b.Property("GatewaySubscriptionId")
+ .HasColumnType("longtext");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Provider", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider.ProviderOrganization", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Settings")
+ .HasColumnType("longtext");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.HasIndex("ProviderId");
+
+ b.ToTable("ProviderOrganization", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider.ProviderUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Email")
+ .HasColumnType("longtext");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("Permissions")
+ .HasColumnType("longtext");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ProviderUser", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.AuthRequest", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AccessCode")
+ .HasMaxLength(25)
+ .HasColumnType("varchar(25)");
+
+ b.Property("Approved")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AuthenticationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Key")
+ .HasColumnType("longtext");
+
+ b.Property("MasterPasswordHash")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("PublicKey")
+ .HasColumnType("longtext");
+
+ b.Property("RequestCountryName")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("RequestDeviceIdentifier")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("RequestDeviceType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("RequestIpAddress")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("ResponseDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ResponseDeviceId")
+ .HasColumnType("char(36)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.HasIndex("ResponseDeviceId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AuthRequest", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.EmergencyAccess", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("GranteeId")
+ .HasColumnType("char(36)");
+
+ b.Property("GrantorId")
+ .HasColumnType("char(36)");
+
+ b.Property("KeyEncrypted")
+ .HasColumnType("longtext");
+
+ b.Property("LastNotificationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("RecoveryInitiatedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("WaitTimeDays")
+ .HasColumnType("smallint");
+
+ b.HasKey("Id");
+
+ b.HasIndex("GranteeId");
+
+ b.HasIndex("GrantorId");
+
+ b.ToTable("EmergencyAccess", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.Grant", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("ClientId")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ConsumedDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("Description")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("SessionId")
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)");
+
+ b.Property("SubjectId")
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)");
+
+ b.Property("Type")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.HasKey("Id")
+ .HasName("PK_Grant")
+ .HasAnnotation("SqlServer:Clustered", true);
+
+ b.HasIndex("ExpirationDate")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("Key")
+ .IsUnique();
+
+ b.ToTable("Grant", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.SsoConfig", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Data")
+ .HasColumnType("longtext");
+
+ b.Property("Enabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.ToTable("SsoConfig", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.SsoUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExternalId")
+ .HasMaxLength(300)
+ .HasColumnType("varchar(300)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("UserId");
+
+ b.HasIndex("OrganizationId", "ExternalId")
+ .IsUnique()
+ .HasAnnotation("Npgsql:IndexInclude", new[] { "UserId" })
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId", "UserId")
+ .IsUnique()
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("SsoUser", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Auth.Models.WebAuthnCredential", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AaGuid")
+ .HasColumnType("char(36)");
+
+ b.Property("Counter")
+ .HasColumnType("int");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CredentialId")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("EncryptedPrivateKey")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)");
+
+ b.Property("EncryptedPublicKey")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)");
+
+ b.Property("EncryptedUserKey")
+ .HasMaxLength(2000)
+ .HasColumnType("varchar(2000)");
+
+ b.Property("Name")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PublicKey")
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("SupportsPrf")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Type")
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("WebAuthnCredential", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.ClientOrganizationMigrationRecord", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("ExpirationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("GatewayCustomerId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("GatewaySubscriptionId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("MaxAutoscaleSeats")
+ .HasColumnType("int");
+
+ b.Property("MaxStorageGb")
+ .HasColumnType("smallint");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("PlanType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("Seats")
+ .HasColumnType("int");
+
+ b.Property("Status")
+ .HasColumnType("tinyint unsigned");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId", "OrganizationId")
+ .IsUnique();
+
+ b.ToTable("ClientOrganizationMigrationRecord", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.OrganizationInstallation", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("InstallationId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id")
+ .HasAnnotation("SqlServer:Clustered", true);
+
+ b.HasIndex("InstallationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("OrganizationInstallation", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.ProviderInvoiceItem", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AssignedSeats")
+ .HasColumnType("int");
+
+ b.Property("ClientId")
+ .HasColumnType("char(36)");
+
+ b.Property("ClientName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Created")
+ .HasColumnType("datetime(6)");
+
+ b.Property("InvoiceId")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("InvoiceNumber")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PlanName")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("Total")
+ .HasColumnType("decimal(65,30)");
+
+ b.Property("UsedSeats")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId");
+
+ b.ToTable("ProviderInvoiceItem", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Billing.Models.ProviderPlan", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("AllocatedSeats")
+ .HasColumnType("int");
+
+ b.Property("PlanType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("PurchasedSeats")
+ .HasColumnType("int");
+
+ b.Property("SeatMinimum")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ProviderId");
+
+ b.HasIndex("Id", "PlanType")
+ .IsUnique();
+
+ b.ToTable("ProviderPlan", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationApplication", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("Applications")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("ContentEncryptionKey")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Id")
+ .HasAnnotation("SqlServer:Clustered", true);
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("OrganizationApplication", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationIntegration", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("Configuration")
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("OrganizationId", "Type")
+ .IsUnique()
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("OrganizationIntegration", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationIntegrationConfiguration", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("Configuration")
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("EventType")
+ .HasColumnType("int");
+
+ b.Property("Filters")
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationIntegrationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Template")
+ .HasColumnType("longtext");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationIntegrationId");
+
+ b.ToTable("OrganizationIntegrationConfiguration", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Dirt.Models.OrganizationReport", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("ApplicationAtRiskCount")
+ .HasColumnType("int");
+
+ b.Property("ApplicationCount")
+ .HasColumnType("int");
+
+ b.Property("ApplicationData")
+ .HasColumnType("longtext");
+
+ b.Property("ContentEncryptionKey")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("CriticalApplicationAtRiskCount")
+ .HasColumnType("int");
+
+ b.Property("CriticalApplicationCount")
+ .HasColumnType("int");
+
+ b.Property("CriticalMemberAtRiskCount")
+ .HasColumnType("int");
+
+ b.Property("CriticalMemberCount")
+ .HasColumnType("int");
+
+ b.Property("CriticalPasswordAtRiskCount")
+ .HasColumnType("int");
+
+ b.Property