From 2893ca729fc92bf92370a42c715eb94dccec08af Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 31 Oct 2024 11:02:23 +0100
Subject: [PATCH 01/24] [deps] Billing: Update swashbuckle-aspnetcore monorepo
to 6.9.0 (#4948)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
.config/dotnet-tools.json | 2 +-
src/Api/Api.csproj | 2 +-
src/SharedWeb/SharedWeb.csproj | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index ada906329..d56bb2796 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"swashbuckle.aspnetcore.cli": {
- "version": "6.8.1",
+ "version": "6.9.0",
"commands": ["swagger"]
},
"dotnet-ef": {
diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj
index 13066ed01..d6d055e90 100644
--- a/src/Api/Api.csproj
+++ b/src/Api/Api.csproj
@@ -35,7 +35,7 @@
-
+
diff --git a/src/SharedWeb/SharedWeb.csproj b/src/SharedWeb/SharedWeb.csproj
index 40915cb7e..8d1097eee 100644
--- a/src/SharedWeb/SharedWeb.csproj
+++ b/src/SharedWeb/SharedWeb.csproj
@@ -7,7 +7,7 @@
-
+
From 249c39e71efd89bc2dd5bea4f49da79804ad223e Mon Sep 17 00:00:00 2001
From: Alex Morask <144709477+amorask-bitwarden@users.noreply.github.com>
Date: Thu, 31 Oct 2024 11:01:37 -0400
Subject: [PATCH 02/24] [PM-14275] Add IsManaged to OrganizationMetadata
(#4957)
* Add IsManaged to OrganizationMetadata
* Remove subscription requirement from self-host eligibility check
* Remove unused service
* Run dotnet format
---
.../Responses/OrganizationMetadataResponse.cs | 2 ++
.../Billing/Models/OrganizationMetadata.cs | 8 ++---
.../OrganizationBillingService.cs | 30 +++++--------------
.../OrganizationBillingControllerTests.cs | 9 +++---
4 files changed, 16 insertions(+), 33 deletions(-)
diff --git a/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs b/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs
index b5f9ab2f5..ebaf7b548 100644
--- a/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs
+++ b/src/Api/Billing/Models/Responses/OrganizationMetadataResponse.cs
@@ -4,10 +4,12 @@ namespace Bit.Api.Billing.Models.Responses;
public record OrganizationMetadataResponse(
bool IsEligibleForSelfHost,
+ bool IsManaged,
bool IsOnSecretsManagerStandalone)
{
public static OrganizationMetadataResponse From(OrganizationMetadata metadata)
=> new(
metadata.IsEligibleForSelfHost,
+ metadata.IsManaged,
metadata.IsOnSecretsManagerStandalone);
}
diff --git a/src/Core/Billing/Models/OrganizationMetadata.cs b/src/Core/Billing/Models/OrganizationMetadata.cs
index 136964d7c..6b31b51d0 100644
--- a/src/Core/Billing/Models/OrganizationMetadata.cs
+++ b/src/Core/Billing/Models/OrganizationMetadata.cs
@@ -2,9 +2,5 @@
public record OrganizationMetadata(
bool IsEligibleForSelfHost,
- bool IsOnSecretsManagerStandalone)
-{
- public static OrganizationMetadata Default() => new(
- IsEligibleForSelfHost: false,
- IsOnSecretsManagerStandalone: false);
-}
+ bool IsManaged,
+ bool IsOnSecretsManagerStandalone);
diff --git a/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs b/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs
index 7db886203..5956e3d85 100644
--- a/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs
+++ b/src/Core/Billing/Services/Implementations/OrganizationBillingService.cs
@@ -1,5 +1,4 @@
using Bit.Core.AdminConsole.Entities;
-using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Caches;
using Bit.Core.Billing.Constants;
using Bit.Core.Billing.Models;
@@ -27,7 +26,6 @@ public class OrganizationBillingService(
IGlobalSettings globalSettings,
ILogger logger,
IOrganizationRepository organizationRepository,
- IProviderRepository providerRepository,
ISetupIntentCache setupIntentCache,
IStripeAdapter stripeAdapter,
ISubscriberService subscriberService) : IOrganizationBillingService
@@ -71,11 +69,11 @@ public class OrganizationBillingService(
var subscription = await subscriberService.GetSubscription(organization);
- var isEligibleForSelfHost = await IsEligibleForSelfHost(organization, subscription);
-
+ var isEligibleForSelfHost = IsEligibleForSelfHost(organization);
+ var isManaged = organization.Status == OrganizationStatusType.Managed;
var isOnSecretsManagerStandalone = IsOnSecretsManagerStandalone(organization, customer, subscription);
- return new OrganizationMetadata(isEligibleForSelfHost, isOnSecretsManagerStandalone);
+ return new OrganizationMetadata(isEligibleForSelfHost, isManaged, isOnSecretsManagerStandalone);
}
public async Task UpdatePaymentMethod(
@@ -339,26 +337,12 @@ public class OrganizationBillingService(
return await stripeAdapter.SubscriptionCreateAsync(subscriptionCreateOptions);
}
- private async Task IsEligibleForSelfHost(
- Organization organization,
- Subscription? organizationSubscription)
+ private static bool IsEligibleForSelfHost(
+ Organization organization)
{
- if (organization.Status != OrganizationStatusType.Managed)
- {
- return organization.Plan.Contains("Families") ||
- organization.Plan.Contains("Enterprise") && IsActive(organizationSubscription);
- }
+ var eligibleSelfHostPlans = StaticStore.Plans.Where(plan => plan.HasSelfHost).Select(plan => plan.Type);
- var provider = await providerRepository.GetByOrganizationIdAsync(organization.Id);
-
- var providerSubscription = await subscriberService.GetSubscriptionOrThrow(provider);
-
- return organization.Plan.Contains("Enterprise") && IsActive(providerSubscription);
-
- bool IsActive(Subscription? subscription) => subscription?.Status is
- StripeConstants.SubscriptionStatus.Active or
- StripeConstants.SubscriptionStatus.Trialing or
- StripeConstants.SubscriptionStatus.PastDue;
+ return eligibleSelfHostPlans.Contains(organization.PlanType);
}
private static bool IsOnSecretsManagerStandalone(
diff --git a/test/Api.Test/Billing/Controllers/OrganizationBillingControllerTests.cs b/test/Api.Test/Billing/Controllers/OrganizationBillingControllerTests.cs
index b46fd307e..eadf7e97b 100644
--- a/test/Api.Test/Billing/Controllers/OrganizationBillingControllerTests.cs
+++ b/test/Api.Test/Billing/Controllers/OrganizationBillingControllerTests.cs
@@ -52,16 +52,17 @@ public class OrganizationBillingControllerTests
{
sutProvider.GetDependency().AccessMembersTab(organizationId).Returns(true);
sutProvider.GetDependency().GetMetadata(organizationId)
- .Returns(new OrganizationMetadata(true, true));
+ .Returns(new OrganizationMetadata(true, true, true));
var result = await sutProvider.Sut.GetMetadataAsync(organizationId);
Assert.IsType>(result);
- var organizationMetadataResponse = ((Ok)result).Value;
+ var response = ((Ok)result).Value;
- Assert.True(organizationMetadataResponse.IsEligibleForSelfHost);
- Assert.True(organizationMetadataResponse.IsOnSecretsManagerStandalone);
+ Assert.True(response.IsEligibleForSelfHost);
+ Assert.True(response.IsManaged);
+ Assert.True(response.IsOnSecretsManagerStandalone);
}
[Theory, BitAutoData]
From 997bf03d97f5641a70e032b8186c2e186b1ed98d Mon Sep 17 00:00:00 2001
From: Vince Grassia <593223+vgrassia@users.noreply.github.com>
Date: Thu, 31 Oct 2024 11:40:54 -0400
Subject: [PATCH 03/24] Update version to 2024.10.2 (#4962)
---
Directory.Build.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Directory.Build.props b/Directory.Build.props
index 5cd12bfb7..1883c756d 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -3,7 +3,7 @@
net8.0
- 2024.10.1
+ 2024.10.2
Bit.$(MSBuildProjectName)
enable
From 751fd33aef8673a7ce566195e1f749f3fbf2ee8d Mon Sep 17 00:00:00 2001
From: tangowithfoxtrot <5676771+tangowithfoxtrot@users.noreply.github.com>
Date: Thu, 31 Oct 2024 09:13:57 -0700
Subject: [PATCH 04/24] fix: ensure vault URI is propagated from `config.yml`
(#4925)
* fix: ensure vault URI matches Url from config.yml
* fmt: use camelCase for vaultUri
Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>
---------
Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>
---
util/Setup/EnvironmentFileBuilder.cs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/util/Setup/EnvironmentFileBuilder.cs b/util/Setup/EnvironmentFileBuilder.cs
index a57013a6d..9c6471cb3 100644
--- a/util/Setup/EnvironmentFileBuilder.cs
+++ b/util/Setup/EnvironmentFileBuilder.cs
@@ -51,6 +51,12 @@ public class EnvironmentFileBuilder
_globalOverrideValues.Remove("globalSettings__pushRelayBaseUri");
}
+ if (_globalOverrideValues.TryGetValue("globalSettings__baseServiceUri__vault", out var vaultUri) && vaultUri != _context.Config.Url)
+ {
+ _globalOverrideValues["globalSettings__baseServiceUri__vault"] = _context.Config.Url;
+ Helpers.WriteLine(_context, "Updated globalSettings__baseServiceUri__vault to match value in config.yml");
+ }
+
Build();
}
From a04df4bebab8b7599d7a5de19535e18487e7f678 Mon Sep 17 00:00:00 2001
From: Matt Bishop
Date: Thu, 31 Oct 2024 17:05:13 -0400
Subject: [PATCH 05/24] Device deactivation (#4963)
* Device deactivation
* Check active status in service
* Format and work around potential deadlocks
---
src/Api/Controllers/DevicesController.cs | 6 +-
src/Core/Entities/Device.cs | 4 +
src/Core/Services/IDeviceService.cs | 2 +-
.../Services/Implementations/DeviceService.cs | 13 +-
.../DeviceEntityTypeConfiguration.cs | 4 +
.../dbo/Stored Procedures/Device_Create.sql | 9 +-
.../Stored Procedures/Device_DeleteById.sql | 12 -
.../dbo/Stored Procedures/Device_Update.sql | 6 +-
src/Sql/dbo/Tables/Device.sql | 25 +-
.../2024-10-31-00_DeviceActivation.sql | 118 +
...0241031170511_DeviceActivation.Designer.cs | 2849 ++++++++++++++++
.../20241031170511_DeviceActivation.cs | 28 +
.../DatabaseContextModelSnapshot.cs | 4 +
...0241031170505_DeviceActivation.Designer.cs | 2855 +++++++++++++++++
.../20241031170505_DeviceActivation.cs | 28 +
.../DatabaseContextModelSnapshot.cs | 4 +
...0241031170500_DeviceActivation.Designer.cs | 2838 ++++++++++++++++
.../20241031170500_DeviceActivation.cs | 28 +
.../DatabaseContextModelSnapshot.cs | 4 +
19 files changed, 8801 insertions(+), 36 deletions(-)
delete mode 100644 src/Sql/dbo/Stored Procedures/Device_DeleteById.sql
create mode 100644 util/Migrator/DbScripts/2024-10-31-00_DeviceActivation.sql
create mode 100644 util/MySqlMigrations/Migrations/20241031170511_DeviceActivation.Designer.cs
create mode 100644 util/MySqlMigrations/Migrations/20241031170511_DeviceActivation.cs
create mode 100644 util/PostgresMigrations/Migrations/20241031170505_DeviceActivation.Designer.cs
create mode 100644 util/PostgresMigrations/Migrations/20241031170505_DeviceActivation.cs
create mode 100644 util/SqliteMigrations/Migrations/20241031170500_DeviceActivation.Designer.cs
create mode 100644 util/SqliteMigrations/Migrations/20241031170500_DeviceActivation.cs
diff --git a/src/Api/Controllers/DevicesController.cs b/src/Api/Controllers/DevicesController.cs
index bbb2b7005..f55b30eb2 100644
--- a/src/Api/Controllers/DevicesController.cs
+++ b/src/Api/Controllers/DevicesController.cs
@@ -196,8 +196,8 @@ public class DevicesController : Controller
}
[HttpDelete("{id}")]
- [HttpPost("{id}/delete")]
- public async Task Delete(string id)
+ [HttpPost("{id}/deactivate")]
+ public async Task Deactivate(string id)
{
var device = await _deviceRepository.GetByIdAsync(new Guid(id), _userService.GetProperUserId(User).Value);
if (device == null)
@@ -205,7 +205,7 @@ public class DevicesController : Controller
throw new NotFoundException();
}
- await _deviceService.DeleteAsync(device);
+ await _deviceService.DeactivateAsync(device);
}
[AllowAnonymous]
diff --git a/src/Core/Entities/Device.cs b/src/Core/Entities/Device.cs
index 44929fa2d..efb011861 100644
--- a/src/Core/Entities/Device.cs
+++ b/src/Core/Entities/Device.cs
@@ -38,6 +38,10 @@ public class Device : ITableObject
///
public string? EncryptedPrivateKey { get; set; }
+ ///
+ /// Whether the device is active for the user.
+ ///
+ public bool Active { get; set; } = true;
public void SetNewId()
{
diff --git a/src/Core/Services/IDeviceService.cs b/src/Core/Services/IDeviceService.cs
index cadc3e4be..b5f3a0b8f 100644
--- a/src/Core/Services/IDeviceService.cs
+++ b/src/Core/Services/IDeviceService.cs
@@ -7,7 +7,7 @@ public interface IDeviceService
{
Task SaveAsync(Device device);
Task ClearTokenAsync(Device device);
- Task DeleteAsync(Device device);
+ Task DeactivateAsync(Device device);
Task UpdateDevicesTrustAsync(string currentDeviceIdentifier,
Guid currentUserId,
DeviceKeysUpdateRequestModel currentDeviceUpdate,
diff --git a/src/Core/Services/Implementations/DeviceService.cs b/src/Core/Services/Implementations/DeviceService.cs
index 5b1e4b0f0..638e4c5e0 100644
--- a/src/Core/Services/Implementations/DeviceService.cs
+++ b/src/Core/Services/Implementations/DeviceService.cs
@@ -41,9 +41,18 @@ public class DeviceService : IDeviceService
await _pushRegistrationService.DeleteRegistrationAsync(device.Id.ToString());
}
- public async Task DeleteAsync(Device device)
+ public async Task DeactivateAsync(Device device)
{
- await _deviceRepository.DeleteAsync(device);
+ // already deactivated
+ if (!device.Active)
+ {
+ return;
+ }
+
+ device.Active = false;
+ device.RevisionDate = DateTime.UtcNow;
+ await _deviceRepository.UpsertAsync(device);
+
await _pushRegistrationService.DeleteRegistrationAsync(device.Id.ToString());
}
diff --git a/src/Infrastructure.EntityFramework/Configurations/DeviceEntityTypeConfiguration.cs b/src/Infrastructure.EntityFramework/Configurations/DeviceEntityTypeConfiguration.cs
index 53cf98bd9..cf6afce7c 100644
--- a/src/Infrastructure.EntityFramework/Configurations/DeviceEntityTypeConfiguration.cs
+++ b/src/Infrastructure.EntityFramework/Configurations/DeviceEntityTypeConfiguration.cs
@@ -21,6 +21,10 @@ public class DeviceEntityTypeConfiguration : IEntityTypeConfiguration
.HasIndex(d => d.Identifier)
.IsClustered(false);
+ builder.Property(c => c.Active)
+ .ValueGeneratedNever()
+ .HasDefaultValue(true);
+
builder.ToTable(nameof(Device));
}
}
diff --git a/src/Sql/dbo/Stored Procedures/Device_Create.sql b/src/Sql/dbo/Stored Procedures/Device_Create.sql
index 6e9159c52..11df68060 100644
--- a/src/Sql/dbo/Stored Procedures/Device_Create.sql
+++ b/src/Sql/dbo/Stored Procedures/Device_Create.sql
@@ -9,7 +9,8 @@
@RevisionDate DATETIME2(7),
@EncryptedUserKey VARCHAR(MAX) = NULL,
@EncryptedPublicKey VARCHAR(MAX) = NULL,
- @EncryptedPrivateKey VARCHAR(MAX) = NULL
+ @EncryptedPrivateKey VARCHAR(MAX) = NULL,
+ @Active BIT = 1
AS
BEGIN
SET NOCOUNT ON
@@ -26,7 +27,8 @@ BEGIN
[RevisionDate],
[EncryptedUserKey],
[EncryptedPublicKey],
- [EncryptedPrivateKey]
+ [EncryptedPrivateKey],
+ [Active]
)
VALUES
(
@@ -40,6 +42,7 @@ BEGIN
@RevisionDate,
@EncryptedUserKey,
@EncryptedPublicKey,
- @EncryptedPrivateKey
+ @EncryptedPrivateKey,
+ @Active
)
END
diff --git a/src/Sql/dbo/Stored Procedures/Device_DeleteById.sql b/src/Sql/dbo/Stored Procedures/Device_DeleteById.sql
deleted file mode 100644
index ab1996ceb..000000000
--- a/src/Sql/dbo/Stored Procedures/Device_DeleteById.sql
+++ /dev/null
@@ -1,12 +0,0 @@
-CREATE PROCEDURE [dbo].[Device_DeleteById]
- @Id UNIQUEIDENTIFIER
-AS
-BEGIN
- SET NOCOUNT ON
-
- DELETE
- FROM
- [dbo].[Device]
- WHERE
- [Id] = @Id
-END
\ No newline at end of file
diff --git a/src/Sql/dbo/Stored Procedures/Device_Update.sql b/src/Sql/dbo/Stored Procedures/Device_Update.sql
index dd3bf4ba2..297523159 100644
--- a/src/Sql/dbo/Stored Procedures/Device_Update.sql
+++ b/src/Sql/dbo/Stored Procedures/Device_Update.sql
@@ -9,7 +9,8 @@
@RevisionDate DATETIME2(7),
@EncryptedUserKey VARCHAR(MAX) = NULL,
@EncryptedPublicKey VARCHAR(MAX) = NULL,
- @EncryptedPrivateKey VARCHAR(MAX) = NULL
+ @EncryptedPrivateKey VARCHAR(MAX) = NULL,
+ @Active BIT = 1
AS
BEGIN
SET NOCOUNT ON
@@ -26,7 +27,8 @@ BEGIN
[RevisionDate] = @RevisionDate,
[EncryptedUserKey] = @EncryptedUserKey,
[EncryptedPublicKey] = @EncryptedPublicKey,
- [EncryptedPrivateKey] = @EncryptedPrivateKey
+ [EncryptedPrivateKey] = @EncryptedPrivateKey,
+ [Active] = @Active
WHERE
[Id] = @Id
END
diff --git a/src/Sql/dbo/Tables/Device.sql b/src/Sql/dbo/Tables/Device.sql
index 75ba218ff..66328afe5 100644
--- a/src/Sql/dbo/Tables/Device.sql
+++ b/src/Sql/dbo/Tables/Device.sql
@@ -1,25 +1,24 @@
CREATE TABLE [dbo].[Device] (
- [Id] UNIQUEIDENTIFIER NOT NULL,
- [UserId] UNIQUEIDENTIFIER NOT NULL,
- [Name] NVARCHAR (50) NOT NULL,
- [Type] SMALLINT NOT NULL,
- [Identifier] NVARCHAR (50) NOT NULL,
- [PushToken] NVARCHAR (255) NULL,
- [CreationDate] DATETIME2 (7) NOT NULL,
- [RevisionDate] DATETIME2 (7) NOT NULL,
- [EncryptedUserKey] VARCHAR (MAX) NULL,
- [EncryptedPublicKey] VARCHAR (MAX) NULL,
- [EncryptedPrivateKey] VARCHAR (MAX) NULL,
+ [Id] UNIQUEIDENTIFIER NOT NULL,
+ [UserId] UNIQUEIDENTIFIER NOT NULL,
+ [Name] NVARCHAR (50) NOT NULL,
+ [Type] SMALLINT NOT NULL,
+ [Identifier] NVARCHAR (50) NOT NULL,
+ [PushToken] NVARCHAR (255) NULL,
+ [CreationDate] DATETIME2 (7) NOT NULL,
+ [RevisionDate] DATETIME2 (7) NOT NULL,
+ [EncryptedUserKey] VARCHAR (MAX) NULL,
+ [EncryptedPublicKey] VARCHAR (MAX) NULL,
+ [EncryptedPrivateKey] VARCHAR (MAX) NULL,
+ [Active] BIT NOT NULL CONSTRAINT [DF_Device_Active] DEFAULT (1),
CONSTRAINT [PK_Device] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Device_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
);
-
GO
CREATE UNIQUE NONCLUSTERED INDEX [UX_Device_UserId_Identifier]
ON [dbo].[Device]([UserId] ASC, [Identifier] ASC);
-
GO
CREATE NONCLUSTERED INDEX [IX_Device_Identifier]
ON [dbo].[Device]([Identifier] ASC);
diff --git a/util/Migrator/DbScripts/2024-10-31-00_DeviceActivation.sql b/util/Migrator/DbScripts/2024-10-31-00_DeviceActivation.sql
new file mode 100644
index 000000000..cf29f2823
--- /dev/null
+++ b/util/Migrator/DbScripts/2024-10-31-00_DeviceActivation.sql
@@ -0,0 +1,118 @@
+SET DEADLOCK_PRIORITY HIGH
+GO
+
+-- add column
+IF COL_LENGTH('[dbo].[Device]', 'Active') IS NULL
+ BEGIN
+ ALTER TABLE
+ [dbo].[Device]
+ ADD
+ [Active] BIT NOT NULL CONSTRAINT [DF_Device_Active] DEFAULT (1)
+END
+GO
+
+-- refresh view
+CREATE OR ALTER VIEW [dbo].[DeviceView]
+AS
+ SELECT
+ *
+ FROM
+ [dbo].[Device]
+GO
+
+-- drop now-unused proc for deletion
+IF OBJECT_ID('[dbo].[Device_DeleteById]') IS NOT NULL
+ BEGIN
+ DROP PROCEDURE [dbo].[Device_DeleteById]
+END
+GO
+
+-- refresh procs
+CREATE OR ALTER PROCEDURE [dbo].[Device_Create]
+ @Id UNIQUEIDENTIFIER OUTPUT,
+ @UserId UNIQUEIDENTIFIER,
+ @Name NVARCHAR(50),
+ @Type TINYINT,
+ @Identifier NVARCHAR(50),
+ @PushToken NVARCHAR(255),
+ @CreationDate DATETIME2(7),
+ @RevisionDate DATETIME2(7),
+ @EncryptedUserKey VARCHAR(MAX) = NULL,
+ @EncryptedPublicKey VARCHAR(MAX) = NULL,
+ @EncryptedPrivateKey VARCHAR(MAX) = NULL,
+ @Active BIT = 1
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ INSERT INTO [dbo].[Device]
+ (
+ [Id],
+ [UserId],
+ [Name],
+ [Type],
+ [Identifier],
+ [PushToken],
+ [CreationDate],
+ [RevisionDate],
+ [EncryptedUserKey],
+ [EncryptedPublicKey],
+ [EncryptedPrivateKey],
+ [Active]
+ )
+ VALUES
+ (
+ @Id,
+ @UserId,
+ @Name,
+ @Type,
+ @Identifier,
+ @PushToken,
+ @CreationDate,
+ @RevisionDate,
+ @EncryptedUserKey,
+ @EncryptedPublicKey,
+ @EncryptedPrivateKey,
+ @Active
+ )
+END
+GO
+
+CREATE OR ALTER PROCEDURE [dbo].[Device_Update]
+ @Id UNIQUEIDENTIFIER,
+ @UserId UNIQUEIDENTIFIER,
+ @Name NVARCHAR(50),
+ @Type TINYINT,
+ @Identifier NVARCHAR(50),
+ @PushToken NVARCHAR(255),
+ @CreationDate DATETIME2(7),
+ @RevisionDate DATETIME2(7),
+ @EncryptedUserKey VARCHAR(MAX) = NULL,
+ @EncryptedPublicKey VARCHAR(MAX) = NULL,
+ @EncryptedPrivateKey VARCHAR(MAX) = NULL,
+ @Active BIT = 1
+AS
+BEGIN
+ SET NOCOUNT ON
+
+ UPDATE
+ [dbo].[Device]
+ SET
+ [UserId] = @UserId,
+ [Name] = @Name,
+ [Type] = @Type,
+ [Identifier] = @Identifier,
+ [PushToken] = @PushToken,
+ [CreationDate] = @CreationDate,
+ [RevisionDate] = @RevisionDate,
+ [EncryptedUserKey] = @EncryptedUserKey,
+ [EncryptedPublicKey] = @EncryptedPublicKey,
+ [EncryptedPrivateKey] = @EncryptedPrivateKey,
+ [Active] = @Active
+ WHERE
+ [Id] = @Id
+END
+GO
+
+SET DEADLOCK_PRIORITY NORMAL
+GO
diff --git a/util/MySqlMigrations/Migrations/20241031170511_DeviceActivation.Designer.cs b/util/MySqlMigrations/Migrations/20241031170511_DeviceActivation.Designer.cs
new file mode 100644
index 000000000..b96f61b47
--- /dev/null
+++ b/util/MySqlMigrations/Migrations/20241031170511_DeviceActivation.Designer.cs
@@ -0,0 +1,2849 @@
+//
+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("20241031170511_DeviceActivation")]
+ partial class DeviceActivation
+ {
+ ///
+ 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.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("LimitCollectionCreationDeletion")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LimitCollectionDeletion")
+ .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("TwoFactorProviders")
+ .HasColumnType("longtext");
+
+ b.Property("Use2fa")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseApi")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseCustomPermissions")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseDirectory")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseEvents")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseGroups")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseKeyConnector")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePasswordManager")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UsePolicies")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("UseResetPassword")
+ .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" });
+
+ 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("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("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("int");
+
+ 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(50)
+ .HasColumnType("varchar(50)");
+
+ 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.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.Models.Cache", b =>
+ {
+ b.Property("Id")
+ .HasMaxLength(449)
+ .HasColumnType("varchar(449)");
+
+ b.Property("AbsoluteExpiration")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExpiresAtTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("SlidingExpirationInSeconds")
+ .HasColumnType("bigint");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasColumnType("longblob");
+
+ b.HasKey("Id")
+ .HasAnnotation("SqlServer:Clustered", true);
+
+ b.HasIndex("ExpiresAtTime")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("Cache", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ExternalId")
+ .HasMaxLength(300)
+ .HasColumnType("varchar(300)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OrganizationId");
+
+ b.ToTable("Collection", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b =>
+ {
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("CipherId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("CollectionId", "CipherId");
+
+ b.HasIndex("CipherId");
+
+ b.ToTable("CollectionCipher", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b =>
+ {
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("HidePasswords")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Manage")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ReadOnly")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("CollectionId", "GroupId");
+
+ b.HasIndex("GroupId");
+
+ b.ToTable("CollectionGroups");
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b =>
+ {
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("HidePasswords")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Manage")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ReadOnly")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("CollectionId", "OrganizationUserId");
+
+ b.HasIndex("OrganizationUserId");
+
+ b.ToTable("CollectionUsers");
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(true);
+
+ b.Property("CreationDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("EncryptedPrivateKey")
+ .HasColumnType("longtext");
+
+ b.Property("EncryptedPublicKey")
+ .HasColumnType("longtext");
+
+ b.Property("EncryptedUserKey")
+ .HasColumnType("longtext");
+
+ b.Property("Identifier")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("PushToken")
+ .HasMaxLength(255)
+ .HasColumnType("varchar(255)");
+
+ b.Property("RevisionDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Identifier")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("UserId")
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.HasIndex("UserId", "Identifier")
+ .IsUnique()
+ .HasAnnotation("SqlServer:Clustered", false);
+
+ b.ToTable("Device", (string)null);
+ });
+
+ modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("char(36)");
+
+ b.Property("ActingUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("CipherId")
+ .HasColumnType("char(36)");
+
+ b.Property("CollectionId")
+ .HasColumnType("char(36)");
+
+ b.Property("Date")
+ .HasColumnType("datetime(6)");
+
+ b.Property("DeviceType")
+ .HasColumnType("tinyint unsigned");
+
+ b.Property("DomainName")
+ .HasColumnType("longtext");
+
+ b.Property("GroupId")
+ .HasColumnType("char(36)");
+
+ b.Property("InstallationId")
+ .HasColumnType("char(36)");
+
+ b.Property("IpAddress")
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)");
+
+ b.Property("OrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property("OrganizationUserId")
+ .HasColumnType("char(36)");
+
+ b.Property("PolicyId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderId")
+ .HasColumnType("char(36)");
+
+ b.Property("ProviderOrganizationId")
+ .HasColumnType("char(36)");
+
+ b.Property