1
0
mirror of https://github.com/bitwarden/server synced 2026-01-04 17:43:53 +00:00

Merge branch 'main' of github.com:bitwarden/server into arch/seeder-api

# Conflicts:
#	util/Seeder/Recipes/OrganizationWithUsersRecipe.cs
This commit is contained in:
Hinton
2025-12-16 16:48:29 +01:00
484 changed files with 43837 additions and 8360 deletions

View File

@@ -34,6 +34,6 @@ public class Program
var db = scopedServices.GetRequiredService<DatabaseContext>();
var recipe = new OrganizationWithUsersRecipe(db);
recipe.Seed(name, users, domain);
recipe.Seed(name: name, domain: domain, users: users);
}
}

View File

@@ -0,0 +1,382 @@
/* Introduce new column 'UsePhishingBlocker' not nullable with default of 0 */
IF COL_LENGTH('[dbo].[Organization]', 'UsePhishingBlocker') is NULL
BEGIN
ALTER TABLE [dbo].[Organization] ADD [UsePhishingBlocker] bit NOT NULL CONSTRAINT [DF_Organization_UsePhishingBlocker] default (0)
END
GO
/* Update existing stored procedures to include the new column - UsePhishingBlocker */
CREATE OR ALTER PROCEDURE [dbo].[Organization_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@Identifier NVARCHAR(50),
@Name NVARCHAR(50),
@BusinessName NVARCHAR(50),
@BusinessAddress1 NVARCHAR(50),
@BusinessAddress2 NVARCHAR(50),
@BusinessAddress3 NVARCHAR(50),
@BusinessCountry VARCHAR(2),
@BusinessTaxNumber NVARCHAR(30),
@BillingEmail NVARCHAR(256),
@Plan NVARCHAR(50),
@PlanType TINYINT,
@Seats INT,
@MaxCollections SMALLINT,
@UsePolicies BIT,
@UseSso BIT,
@UseGroups BIT,
@UseDirectory BIT,
@UseEvents BIT,
@UseTotp BIT,
@Use2fa BIT,
@UseApi BIT,
@UseResetPassword BIT,
@SelfHost BIT,
@UsersGetPremium BIT,
@Storage BIGINT,
@MaxStorageGb SMALLINT,
@Gateway TINYINT,
@GatewayCustomerId VARCHAR(50),
@GatewaySubscriptionId VARCHAR(50),
@ReferenceData VARCHAR(MAX),
@Enabled BIT,
@LicenseKey VARCHAR(100),
@PublicKey VARCHAR(MAX),
@PrivateKey VARCHAR(MAX),
@TwoFactorProviders NVARCHAR(MAX),
@ExpirationDate DATETIME2(7),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@OwnersNotifiedOfAutoscaling DATETIME2(7),
@MaxAutoscaleSeats INT,
@UseKeyConnector BIT = 0,
@UseScim BIT = 0,
@UseCustomPermissions BIT = 0,
@UseSecretsManager BIT = 0,
@Status TINYINT = 0,
@UsePasswordManager BIT = 1,
@SmSeats INT = null,
@SmServiceAccounts INT = null,
@MaxAutoscaleSmSeats INT= null,
@MaxAutoscaleSmServiceAccounts INT = null,
@SecretsManagerBeta BIT = 0,
@LimitCollectionCreation BIT = NULL,
@LimitCollectionDeletion BIT = NULL,
@AllowAdminAccessToAllCollectionItems BIT = 0,
@UseRiskInsights BIT = 0,
@LimitItemDeletion BIT = 0,
@UseOrganizationDomains BIT = 0,
@UseAdminSponsoredFamilies BIT = 0,
@SyncSeats BIT = 0,
@UseAutomaticUserConfirmation BIT = 0,
@UsePhishingBlocker BIT = 0
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Organization]
(
[Id],
[Identifier],
[Name],
[BusinessName],
[BusinessAddress1],
[BusinessAddress2],
[BusinessAddress3],
[BusinessCountry],
[BusinessTaxNumber],
[BillingEmail],
[Plan],
[PlanType],
[Seats],
[MaxCollections],
[UsePolicies],
[UseSso],
[UseGroups],
[UseDirectory],
[UseEvents],
[UseTotp],
[Use2fa],
[UseApi],
[UseResetPassword],
[SelfHost],
[UsersGetPremium],
[Storage],
[MaxStorageGb],
[Gateway],
[GatewayCustomerId],
[GatewaySubscriptionId],
[ReferenceData],
[Enabled],
[LicenseKey],
[PublicKey],
[PrivateKey],
[TwoFactorProviders],
[ExpirationDate],
[CreationDate],
[RevisionDate],
[OwnersNotifiedOfAutoscaling],
[MaxAutoscaleSeats],
[UseKeyConnector],
[UseScim],
[UseCustomPermissions],
[UseSecretsManager],
[Status],
[UsePasswordManager],
[SmSeats],
[SmServiceAccounts],
[MaxAutoscaleSmSeats],
[MaxAutoscaleSmServiceAccounts],
[SecretsManagerBeta],
[LimitCollectionCreation],
[LimitCollectionDeletion],
[AllowAdminAccessToAllCollectionItems],
[UseRiskInsights],
[LimitItemDeletion],
[UseOrganizationDomains],
[UseAdminSponsoredFamilies],
[SyncSeats],
[UseAutomaticUserConfirmation],
[UsePhishingBlocker]
)
VALUES
(
@Id,
@Identifier,
@Name,
@BusinessName,
@BusinessAddress1,
@BusinessAddress2,
@BusinessAddress3,
@BusinessCountry,
@BusinessTaxNumber,
@BillingEmail,
@Plan,
@PlanType,
@Seats,
@MaxCollections,
@UsePolicies,
@UseSso,
@UseGroups,
@UseDirectory,
@UseEvents,
@UseTotp,
@Use2fa,
@UseApi,
@UseResetPassword,
@SelfHost,
@UsersGetPremium,
@Storage,
@MaxStorageGb,
@Gateway,
@GatewayCustomerId,
@GatewaySubscriptionId,
@ReferenceData,
@Enabled,
@LicenseKey,
@PublicKey,
@PrivateKey,
@TwoFactorProviders,
@ExpirationDate,
@CreationDate,
@RevisionDate,
@OwnersNotifiedOfAutoscaling,
@MaxAutoscaleSeats,
@UseKeyConnector,
@UseScim,
@UseCustomPermissions,
@UseSecretsManager,
@Status,
@UsePasswordManager,
@SmSeats,
@SmServiceAccounts,
@MaxAutoscaleSmSeats,
@MaxAutoscaleSmServiceAccounts,
@SecretsManagerBeta,
@LimitCollectionCreation,
@LimitCollectionDeletion,
@AllowAdminAccessToAllCollectionItems,
@UseRiskInsights,
@LimitItemDeletion,
@UseOrganizationDomains,
@UseAdminSponsoredFamilies,
@SyncSeats,
@UseAutomaticUserConfirmation,
@UsePhishingBlocker
);
END
GO
/* Update existing stored procedures to include the new column - UsePhishingBlocker */
CREATE OR ALTER PROCEDURE [dbo].[Organization_ReadAbilities]
AS
BEGIN
SET NOCOUNT ON
SELECT
[Id],
[UseEvents],
[Use2fa],
CASE
WHEN [Use2fa] = 1 AND [TwoFactorProviders] IS NOT NULL AND [TwoFactorProviders] != '{}' THEN
1
ELSE
0
END AS [Using2fa],
[UsersGetPremium],
[UseCustomPermissions],
[UseSso],
[UseKeyConnector],
[UseScim],
[UseResetPassword],
[UsePolicies],
[Enabled],
[LimitCollectionCreation],
[LimitCollectionDeletion],
[AllowAdminAccessToAllCollectionItems],
[UseRiskInsights],
[LimitItemDeletion],
[UseOrganizationDomains],
[UseAdminSponsoredFamilies],
[UseAutomaticUserConfirmation],
[UsePhishingBlocker]
FROM
[dbo].[Organization]
END
GO
/* Update existing stored procedures to include the new column - UsePhishingBlocker */
CREATE OR ALTER PROCEDURE [dbo].[Organization_Update]
@Id UNIQUEIDENTIFIER,
@Identifier NVARCHAR(50),
@Name NVARCHAR(50),
@BusinessName NVARCHAR(50),
@BusinessAddress1 NVARCHAR(50),
@BusinessAddress2 NVARCHAR(50),
@BusinessAddress3 NVARCHAR(50),
@BusinessCountry VARCHAR(2),
@BusinessTaxNumber NVARCHAR(30),
@BillingEmail NVARCHAR(256),
@Plan NVARCHAR(50),
@PlanType TINYINT,
@Seats INT,
@MaxCollections SMALLINT,
@UsePolicies BIT,
@UseSso BIT,
@UseGroups BIT,
@UseDirectory BIT,
@UseEvents BIT,
@UseTotp BIT,
@Use2fa BIT,
@UseApi BIT,
@UseResetPassword BIT,
@SelfHost BIT,
@UsersGetPremium BIT,
@Storage BIGINT,
@MaxStorageGb SMALLINT,
@Gateway TINYINT,
@GatewayCustomerId VARCHAR(50),
@GatewaySubscriptionId VARCHAR(50),
@ReferenceData VARCHAR(MAX),
@Enabled BIT,
@LicenseKey VARCHAR(100),
@PublicKey VARCHAR(MAX),
@PrivateKey VARCHAR(MAX),
@TwoFactorProviders NVARCHAR(MAX),
@ExpirationDate DATETIME2(7),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@OwnersNotifiedOfAutoscaling DATETIME2(7),
@MaxAutoscaleSeats INT,
@UseKeyConnector BIT = 0,
@UseScim BIT = 0,
@UseCustomPermissions BIT = 0,
@UseSecretsManager BIT = 0,
@Status TINYINT = 0,
@UsePasswordManager BIT = 1,
@SmSeats INT = null,
@SmServiceAccounts INT = null,
@MaxAutoscaleSmSeats INT = null,
@MaxAutoscaleSmServiceAccounts INT = null,
@SecretsManagerBeta BIT = 0,
@LimitCollectionCreation BIT = null,
@LimitCollectionDeletion BIT = null,
@AllowAdminAccessToAllCollectionItems BIT = 0,
@UseRiskInsights BIT = 0,
@LimitItemDeletion BIT = 0,
@UseOrganizationDomains BIT = 0,
@UseAdminSponsoredFamilies BIT = 0,
@SyncSeats BIT = 0,
@UseAutomaticUserConfirmation BIT = 0,
@UsePhishingBlocker BIT = 0
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[Organization]
SET
[Identifier] = @Identifier,
[Name] = @Name,
[BusinessName] = @BusinessName,
[BusinessAddress1] = @BusinessAddress1,
[BusinessAddress2] = @BusinessAddress2,
[BusinessAddress3] = @BusinessAddress3,
[BusinessCountry] = @BusinessCountry,
[BusinessTaxNumber] = @BusinessTaxNumber,
[BillingEmail] = @BillingEmail,
[Plan] = @Plan,
[PlanType] = @PlanType,
[Seats] = @Seats,
[MaxCollections] = @MaxCollections,
[UsePolicies] = @UsePolicies,
[UseSso] = @UseSso,
[UseGroups] = @UseGroups,
[UseDirectory] = @UseDirectory,
[UseEvents] = @UseEvents,
[UseTotp] = @UseTotp,
[Use2fa] = @Use2fa,
[UseApi] = @UseApi,
[UseResetPassword] = @UseResetPassword,
[SelfHost] = @SelfHost,
[UsersGetPremium] = @UsersGetPremium,
[Storage] = @Storage,
[MaxStorageGb] = @MaxStorageGb,
[Gateway] = @Gateway,
[GatewayCustomerId] = @GatewayCustomerId,
[GatewaySubscriptionId] = @GatewaySubscriptionId,
[ReferenceData] = @ReferenceData,
[Enabled] = @Enabled,
[LicenseKey] = @LicenseKey,
[PublicKey] = @PublicKey,
[PrivateKey] = @PrivateKey,
[TwoFactorProviders] = @TwoFactorProviders,
[ExpirationDate] = @ExpirationDate,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate,
[OwnersNotifiedOfAutoscaling] = @OwnersNotifiedOfAutoscaling,
[MaxAutoscaleSeats] = @MaxAutoscaleSeats,
[UseKeyConnector] = @UseKeyConnector,
[UseScim] = @UseScim,
[UseCustomPermissions] = @UseCustomPermissions,
[UseSecretsManager] = @UseSecretsManager,
[Status] = @Status,
[UsePasswordManager] = @UsePasswordManager,
[SmSeats] = @SmSeats,
[SmServiceAccounts] = @SmServiceAccounts,
[MaxAutoscaleSmSeats] = @MaxAutoscaleSmSeats,
[MaxAutoscaleSmServiceAccounts] = @MaxAutoscaleSmServiceAccounts,
[SecretsManagerBeta] = @SecretsManagerBeta,
[LimitCollectionCreation] = @LimitCollectionCreation,
[LimitCollectionDeletion] = @LimitCollectionDeletion,
[AllowAdminAccessToAllCollectionItems] = @AllowAdminAccessToAllCollectionItems,
[UseRiskInsights] = @UseRiskInsights,
[LimitItemDeletion] = @LimitItemDeletion,
[UseOrganizationDomains] = @UseOrganizationDomains,
[UseAdminSponsoredFamilies] = @UseAdminSponsoredFamilies,
[SyncSeats] = @SyncSeats,
[UseAutomaticUserConfirmation] = @UseAutomaticUserConfirmation,
[UsePhishingBlocker] = @UsePhishingBlocker
WHERE
[Id] = @Id;
END

View File

@@ -0,0 +1,241 @@
/* Adds the UsePhishingBlocker column to the OrganizationUserOrganizationDetailsView view. */
CREATE OR ALTER VIEW [dbo].[OrganizationUserOrganizationDetailsView]
AS
SELECT
OU.[UserId],
OU.[OrganizationId],
OU.[Id] OrganizationUserId,
O.[Name],
O.[Enabled],
O.[PlanType],
O.[UsePolicies],
O.[UseSso],
O.[UseKeyConnector],
O.[UseScim],
O.[UseGroups],
O.[UseDirectory],
O.[UseEvents],
O.[UseTotp],
O.[Use2fa],
O.[UseApi],
O.[UseResetPassword],
O.[SelfHost],
O.[UsersGetPremium],
O.[UseCustomPermissions],
O.[UseSecretsManager],
O.[Seats],
O.[MaxCollections],
COALESCE(O.[MaxStorageGbIncreased], O.[MaxStorageGb]) AS [MaxStorageGb],
O.[Identifier],
OU.[Key],
OU.[ResetPasswordKey],
O.[PublicKey],
O.[PrivateKey],
OU.[Status],
OU.[Type],
SU.[ExternalId] SsoExternalId,
OU.[Permissions],
PO.[ProviderId],
P.[Name] ProviderName,
P.[Type] ProviderType,
SS.[Enabled] SsoEnabled,
SS.[Data] SsoConfig,
OS.[FriendlyName] FamilySponsorshipFriendlyName,
OS.[LastSyncDate] FamilySponsorshipLastSyncDate,
OS.[ToDelete] FamilySponsorshipToDelete,
OS.[ValidUntil] FamilySponsorshipValidUntil,
OU.[AccessSecretsManager],
O.[UsePasswordManager],
O.[SmSeats],
O.[SmServiceAccounts],
O.[LimitCollectionCreation],
O.[LimitCollectionDeletion],
O.[AllowAdminAccessToAllCollectionItems],
O.[UseRiskInsights],
O.[LimitItemDeletion],
O.[UseAdminSponsoredFamilies],
O.[UseOrganizationDomains],
OS.[IsAdminInitiated],
O.[UseAutomaticUserConfirmation],
O.[UsePhishingBlocker]
FROM
[dbo].[OrganizationUser] OU
LEFT JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
LEFT JOIN
[dbo].[SsoUser] SU ON SU.[UserId] = OU.[UserId] AND SU.[OrganizationId] = OU.[OrganizationId]
LEFT JOIN
[dbo].[ProviderOrganization] PO ON PO.[OrganizationId] = O.[Id]
LEFT JOIN
[dbo].[Provider] P ON P.[Id] = PO.[ProviderId]
LEFT JOIN
[dbo].[SsoConfig] SS ON SS.[OrganizationId] = OU.[OrganizationId]
LEFT JOIN
[dbo].[OrganizationSponsorship] OS ON OS.[SponsoringOrganizationUserID] = OU.[Id]
GO
/* Updates the ProviderUserProviderOrganizationDetailsView view to include the UsePhishingBlocker column. */
CREATE OR ALTER VIEW [dbo].[ProviderUserProviderOrganizationDetailsView]
AS
SELECT
PU.[UserId],
PO.[OrganizationId],
O.[Name],
O.[Enabled],
O.[UsePolicies],
O.[UseSso],
O.[UseKeyConnector],
O.[UseScim],
O.[UseGroups],
O.[UseDirectory],
O.[UseEvents],
O.[UseTotp],
O.[Use2fa],
O.[UseApi],
O.[UseResetPassword],
O.[UseSecretsManager],
O.[UsePasswordManager],
O.[SelfHost],
O.[UsersGetPremium],
O.[UseCustomPermissions],
O.[Seats],
O.[MaxCollections],
COALESCE(O.[MaxStorageGbIncreased], O.[MaxStorageGb]) AS [MaxStorageGb],
O.[Identifier],
PO.[Key],
O.[PublicKey],
O.[PrivateKey],
PU.[Status],
PU.[Type],
PO.[ProviderId],
PU.[Id] ProviderUserId,
P.[Name] ProviderName,
O.[PlanType],
O.[LimitCollectionCreation],
O.[LimitCollectionDeletion],
O.[AllowAdminAccessToAllCollectionItems],
O.[UseRiskInsights],
O.[UseAdminSponsoredFamilies],
P.[Type] ProviderType,
O.[LimitItemDeletion],
O.[UseOrganizationDomains],
O.[UseAutomaticUserConfirmation],
SS.[Enabled] SsoEnabled,
SS.[Data] SsoConfig,
O.[UsePhishingBlocker]
FROM
[dbo].[ProviderUser] PU
INNER JOIN
[dbo].[ProviderOrganization] PO ON PO.[ProviderId] = PU.[ProviderId]
INNER JOIN
[dbo].[Organization] O ON O.[Id] = PO.[OrganizationId]
INNER JOIN
[dbo].[Provider] P ON P.[Id] = PU.[ProviderId]
LEFT JOIN
[dbo].[SsoConfig] SS ON SS.[OrganizationId] = O.[Id]
GO
/* Updates the OrganizationView view to include the UsePhishingBlocker column. */
CREATE OR ALTER VIEW [dbo].[OrganizationView]
AS
SELECT
[Id],
[Identifier],
[Name],
[BusinessName],
[BusinessAddress1],
[BusinessAddress2],
[BusinessAddress3],
[BusinessCountry],
[BusinessTaxNumber],
[BillingEmail],
[Plan],
[PlanType],
[Seats],
[MaxCollections],
[UsePolicies],
[UseSso],
[UseGroups],
[UseDirectory],
[UseEvents],
[UseTotp],
[Use2fa],
[UseApi],
[UseResetPassword],
[SelfHost],
[UsersGetPremium],
[Storage],
COALESCE([MaxStorageGbIncreased], [MaxStorageGb]) AS [MaxStorageGb],
[Gateway],
[GatewayCustomerId],
[GatewaySubscriptionId],
[ReferenceData],
[Enabled],
[LicenseKey],
[PublicKey],
[PrivateKey],
[TwoFactorProviders],
[ExpirationDate],
[CreationDate],
[RevisionDate],
[OwnersNotifiedOfAutoscaling],
[MaxAutoscaleSeats],
[UseKeyConnector],
[UseScim],
[UseCustomPermissions],
[UseSecretsManager],
[Status],
[UsePasswordManager],
[SmSeats],
[SmServiceAccounts],
[MaxAutoscaleSmSeats],
[MaxAutoscaleSmServiceAccounts],
[SecretsManagerBeta],
[LimitCollectionCreation],
[LimitCollectionDeletion],
[LimitItemDeletion],
[AllowAdminAccessToAllCollectionItems],
[UseRiskInsights],
[UseOrganizationDomains],
[UseAdminSponsoredFamilies],
[SyncSeats],
[UseAutomaticUserConfirmation],
[UsePhishingBlocker]
FROM
[dbo].[Organization]
GO
--Manually refresh [dbo].[OrganizationUserOrganizationDetailsView]
IF OBJECT_ID('[dbo].[OrganizationUserOrganizationDetailsView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[OrganizationUserOrganizationDetailsView]';
END
GO
--Manually refresh [dbo].[ProviderUserProviderOrganizationDetailsView]
IF OBJECT_ID('[dbo].[ProviderUserProviderOrganizationDetailsView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[ProviderUserProviderOrganizationDetailsView]';
END
GO
--Manually refresh [dbo].[OrganizationView]
IF OBJECT_ID('[dbo].[OrganizationView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[OrganizationView]';
END
GO
--Manually refresh [dbo].[OrganizationCipherDetailsCollectionsView]
IF OBJECT_ID('[dbo].[OrganizationCipherDetailsCollectionsView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[OrganizationCipherDetailsCollectionsView]';
END
GO
--Manually refresh [dbo].[ProviderOrganizationOrganizationDetailsView]
IF OBJECT_ID('[dbo].[ProviderOrganizationOrganizationDetailsView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[ProviderOrganizationOrganizationDetailsView]';
END
GO

View File

@@ -0,0 +1,13 @@
CREATE OR ALTER PROCEDURE [dbo].[ProviderUser_ReadManyByManyUserIds]
@UserIds AS [dbo].[GuidIdArray] READONLY
AS
BEGIN
SET NOCOUNT ON
SELECT
[pu].*
FROM
[dbo].[ProviderUserView] AS [pu]
INNER JOIN
@UserIds [u] ON [u].[Id] = [pu].[UserId]
END

View File

@@ -0,0 +1,20 @@
CREATE OR ALTER PROCEDURE [dbo].[OrganizationIntegrationConfigurationDetails_ReadManyByEventTypeOrganizationIdIntegrationType]
@EventType SMALLINT,
@OrganizationId UNIQUEIDENTIFIER,
@IntegrationType SMALLINT
AS
BEGIN
SET NOCOUNT ON
SELECT
oic.*
FROM
[dbo].[OrganizationIntegrationConfigurationDetailsView] oic
WHERE
(oic.[EventType] = @EventType OR oic.[EventType] IS NULL)
AND
oic.[OrganizationId] = @OrganizationId
AND
oic.[IntegrationType] = @IntegrationType
END
GO

View File

@@ -0,0 +1,72 @@
IF OBJECT_ID('[dbo].[User_UpdateAccountCryptographicState]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[User_UpdateAccountCryptographicState]
END
GO
CREATE PROCEDURE [dbo].[User_UpdateAccountCryptographicState]
@Id UNIQUEIDENTIFIER,
@PublicKey NVARCHAR(MAX),
@PrivateKey NVARCHAR(MAX),
@SignedPublicKey NVARCHAR(MAX) = NULL,
@SecurityState NVARCHAR(MAX) = NULL,
@SecurityVersion INT = NULL,
@SignatureKeyPairId UNIQUEIDENTIFIER = NULL,
@SignatureAlgorithm TINYINT = NULL,
@SigningKey VARCHAR(MAX) = NULL,
@VerifyingKey VARCHAR(MAX) = NULL,
@RevisionDate DATETIME2(7),
@AccountRevisionDate DATETIME2(7)
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[User]
SET
[PublicKey] = @PublicKey,
[PrivateKey] = @PrivateKey,
[SignedPublicKey] = @SignedPublicKey,
[SecurityState] = @SecurityState,
[SecurityVersion] = @SecurityVersion,
[RevisionDate] = @RevisionDate,
[AccountRevisionDate] = @AccountRevisionDate
WHERE
[Id] = @Id
IF EXISTS (SELECT 1 FROM [dbo].[UserSignatureKeyPair] WHERE [UserId] = @Id)
BEGIN
UPDATE [dbo].[UserSignatureKeyPair]
SET
[SignatureAlgorithm] = @SignatureAlgorithm,
[SigningKey] = @SigningKey,
[VerifyingKey] = @VerifyingKey,
[RevisionDate] = @RevisionDate
WHERE
[UserId] = @Id
END
ELSE
BEGIN
INSERT INTO [dbo].[UserSignatureKeyPair]
(
[Id],
[UserId],
[SignatureAlgorithm],
[SigningKey],
[VerifyingKey],
[CreationDate],
[RevisionDate]
)
VALUES
(
@SignatureKeyPairId,
@Id,
@SignatureAlgorithm,
@SigningKey,
@VerifyingKey,
@RevisionDate,
@RevisionDate
)
END
END
GO

View File

@@ -0,0 +1,62 @@
CREATE OR ALTER PROCEDURE [dbo].[Cipher_UpdateWithCollections]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER,
@Type TINYINT,
@Data NVARCHAR(MAX),
@Favorites NVARCHAR(MAX),
@Folders NVARCHAR(MAX),
@Attachments NVARCHAR(MAX),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@DeletedDate DATETIME2(7),
@Reprompt TINYINT,
@Key VARCHAR(MAX) = NULL,
@CollectionIds AS [dbo].[GuidIdArray] READONLY,
@ArchivedDate DATETIME2(7) = NULL
AS
BEGIN
SET NOCOUNT ON
BEGIN TRANSACTION Cipher_UpdateWithCollections
DECLARE @UpdateCollectionsSuccess INT
EXEC @UpdateCollectionsSuccess = [dbo].[Cipher_UpdateCollections] @Id, @UserId, @OrganizationId, @CollectionIds
IF @UpdateCollectionsSuccess < 0
BEGIN
COMMIT TRANSACTION Cipher_UpdateWithCollections
SELECT -1 -- -1 = Failure
RETURN
END
UPDATE
[dbo].[Cipher]
SET
[UserId] = NULL,
[OrganizationId] = @OrganizationId,
[Data] = @Data,
[Attachments] = @Attachments,
[RevisionDate] = @RevisionDate,
[DeletedDate] = @DeletedDate,
[Key] = @Key,
[ArchivedDate] = @ArchivedDate,
[Folders] = @Folders,
[Favorites] = @Favorites,
[Reprompt] = @Reprompt
-- No need to update CreationDate or Type since that data will not change
WHERE
[Id] = @Id
COMMIT TRANSACTION Cipher_UpdateWithCollections
IF @Attachments IS NOT NULL
BEGIN
EXEC [dbo].[Organization_UpdateStorage] @OrganizationId
EXEC [dbo].[User_UpdateStorage] @UserId
END
EXEC [dbo].[User_BumpAccountRevisionDateByCipherId] @Id, @OrganizationId
SELECT 0 -- 0 = Success
END

View File

@@ -0,0 +1,60 @@
-- Add UsersGetPremium to IX_Organization_Enabled index to support premium access queries
IF EXISTS (
SELECT * FROM sys.indexes
WHERE name = 'IX_Organization_Enabled'
AND object_id = OBJECT_ID('[dbo].[Organization]')
)
BEGIN
CREATE NONCLUSTERED INDEX [IX_Organization_Enabled]
ON [dbo].[Organization]([Id] ASC, [Enabled] ASC)
INCLUDE ([UseTotp], [UsersGetPremium])
WITH (DROP_EXISTING = ON);
END
ELSE
BEGIN
CREATE NONCLUSTERED INDEX [IX_Organization_Enabled]
ON [dbo].[Organization]([Id] ASC, [Enabled] ASC)
INCLUDE ([UseTotp], [UsersGetPremium]);
END
GO
CREATE OR ALTER VIEW [dbo].[UserPremiumAccessView]
AS
SELECT
U.[Id],
U.[Premium] AS [PersonalPremium],
CAST(
MAX(CASE
WHEN O.[Id] IS NOT NULL THEN 1
ELSE 0
END) AS BIT
) AS [OrganizationPremium]
FROM
[dbo].[User] U
LEFT JOIN
[dbo].[OrganizationUser] OU ON OU.[UserId] = U.[Id]
LEFT JOIN
[dbo].[Organization] O ON O.[Id] = OU.[OrganizationId]
AND O.[UsersGetPremium] = 1
AND O.[Enabled] = 1
GROUP BY
U.[Id], U.[Premium];
GO
CREATE OR ALTER PROCEDURE [dbo].[User_ReadPremiumAccessByIds]
@Ids [dbo].[GuidIdArray] READONLY
AS
BEGIN
SET NOCOUNT ON
SELECT
UPA.[Id],
UPA.[PersonalPremium],
UPA.[OrganizationPremium]
FROM
[dbo].[UserPremiumAccessView] UPA
WHERE
UPA.[Id] IN (SELECT [Id] FROM @Ids)
END
GO

View File

@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class _20251121_00_AddUsePhishingBlockerToOrganization : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsePhishingBlocker",
table: "Organization",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsePhishingBlocker",
table: "Organization");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
/// <inheritdoc />
public partial class OrganizationUsersGetPremiumIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}

View File

@@ -244,6 +244,9 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<bool>("UsePasswordManager")
.HasColumnType("tinyint(1)");
b.Property<bool>("UsePhishingBlocker")
.HasColumnType("tinyint(1)");
b.Property<bool>("UsePolicies")
.HasColumnType("tinyint(1)");
@@ -271,7 +274,7 @@ namespace Bit.MySqlMigrations.Migrations
b.HasKey("Id");
b.HasIndex("Id", "Enabled")
.HasAnnotation("Npgsql:IndexInclude", new[] { "UseTotp" });
.HasAnnotation("Npgsql:IndexInclude", new[] { "UseTotp", "UsersGetPremium" });
b.ToTable("Organization", (string)null);
});

View File

@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class _20251121_00_AddUsePhishingBlockerToOrganization : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsePhishingBlocker",
table: "Organization",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsePhishingBlocker",
table: "Organization");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
/// <inheritdoc />
public partial class OrganizationUsersGetPremiumIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Organization_Id_Enabled",
table: "Organization");
migrationBuilder.CreateIndex(
name: "IX_Organization_Id_Enabled",
table: "Organization",
columns: new[] { "Id", "Enabled" })
.Annotation("Npgsql:IndexInclude", new[] { "UseTotp", "UsersGetPremium" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Organization_Id_Enabled",
table: "Organization");
migrationBuilder.CreateIndex(
name: "IX_Organization_Id_Enabled",
table: "Organization",
columns: new[] { "Id", "Enabled" })
.Annotation("Npgsql:IndexInclude", new[] { "UseTotp" });
}
}

View File

@@ -246,6 +246,9 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<bool>("UsePasswordManager")
.HasColumnType("boolean");
b.Property<bool>("UsePhishingBlocker")
.HasColumnType("boolean");
b.Property<bool>("UsePolicies")
.HasColumnType("boolean");
@@ -274,7 +277,7 @@ namespace Bit.PostgresMigrations.Migrations
b.HasIndex("Id", "Enabled");
NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("Id", "Enabled"), new[] { "UseTotp" });
NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("Id", "Enabled"), new[] { "UseTotp", "UsersGetPremium" });
b.ToTable("Organization", (string)null);
});

View File

@@ -17,7 +17,31 @@ public class OrganizationSeeder
Plan = "Enterprise (Annually)",
PlanType = PlanType.EnterpriseAnnually,
Seats = seats,
UseCustomPermissions = true,
UseOrganizationDomains = true,
UseSecretsManager = true,
UseGroups = true,
UseDirectory = true,
UseEvents = true,
UseTotp = true,
Use2fa = true,
UseApi = true,
UseResetPassword = true,
UsePasswordManager = true,
UseAutomaticUserConfirmation = true,
SelfHost = true,
UsersGetPremium = true,
LimitCollectionCreation = true,
LimitCollectionDeletion = true,
LimitItemDeletion = true,
AllowAdminAccessToAllCollectionItems = true,
UseRiskInsights = true,
UseAdminSponsoredFamilies = true,
SyncSeats = true,
Status = OrganizationStatusType.Created,
//GatewayCustomerId = "example-customer-id",
//GatewaySubscriptionId = "example-subscription-id",
MaxStorageGb = 10,
// Currently hardcoded to the values from https://github.com/bitwarden/sdk-internal/blob/main/crates/bitwarden-core/src/client/test_accounts.rs.
// TODO: These should be dynamically generated by the SDK.
PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmIJbGMk6eZqVE7UxhZ46Weu2jKciqOiOkSVYtGvs61rfe9AXxtLaaZEKN4d4DmkZcF6dna2eXNxZmb7U4pwlttye8ksqISe6IUAZQox7auBpjopdCEPhKRg3BD/u8ks9UxSxgWe+fpebjt6gd5hsl1/5HOObn7SeU6EEU04cp3/eH7a4OTdXxB8oN62HGV9kM/ubM1goILgjoSJDbihMK0eb7b8hPHwcA/YOgKKiu/N3FighccdSMD5Pk+HfjacsFNZQa2EsqW09IvvSZ+iL6HQeZ1vwc/6TO1J7EOfJZFQcjoEL9LVI693efYoMZSmrPEWziZ4PvwpOOGo6OObyMQIDAQAB",
@@ -28,17 +52,25 @@ public class OrganizationSeeder
public static class OrgnaizationExtensions
{
public static OrganizationUser CreateOrganizationUser(this Organization organization, User user)
/// <summary>
/// Creates an OrganizationUser with fields populated based on status.
/// For Invited status, only user.Email is used. For other statuses, user.Id is used.
/// </summary>
public static OrganizationUser CreateOrganizationUser(
this Organization organization, User user, OrganizationUserType type, OrganizationUserStatusType status)
{
var isInvited = status == OrganizationUserStatusType.Invited;
var isConfirmed = status == OrganizationUserStatusType.Confirmed || status == OrganizationUserStatusType.Revoked;
return new OrganizationUser
{
Id = Guid.NewGuid(),
OrganizationId = organization.Id,
UserId = user.Id,
Key = "4.rY01mZFXHOsBAg5Fq4gyXuklWfm6mQASm42DJpx05a+e2mmp+P5W6r54WU2hlREX0uoTxyP91bKKwickSPdCQQ58J45LXHdr9t2uzOYyjVzpzebFcdMw1eElR9W2DW8wEk9+mvtWvKwu7yTebzND+46y1nRMoFydi5zPVLSlJEf81qZZ4Uh1UUMLwXz+NRWfixnGXgq2wRq1bH0n3mqDhayiG4LJKgGdDjWXC8W8MMXDYx24SIJrJu9KiNEMprJE+XVF9nQVNijNAjlWBqkDpsfaWTUfeVLRLctfAqW1blsmIv4RQ91PupYJZDNc8nO9ZTF3TEVM+2KHoxzDJrLs2Q==",
Type = OrganizationUserType.Admin,
Status = OrganizationUserStatusType.Confirmed
UserId = isInvited ? null : user.Id,
Email = isInvited ? user.Email : null,
Key = isConfirmed ? "4.rY01mZFXHOsBAg5Fq4gyXuklWfm6mQASm42DJpx05a+e2mmp+P5W6r54WU2hlREX0uoTxyP91bKKwickSPdCQQ58J45LXHdr9t2uzOYyjVzpzebFcdMw1eElR9W2DW8wEk9+mvtWvKwu7yTebzND+46y1nRMoFydi5zPVLSlJEf81qZZ4Uh1UUMLwXz+NRWfixnGXgq2wRq1bH0n3mqDhayiG4LJKgGdDjWXC8W8MMXDYx24SIJrJu9KiNEMprJE+XVF9nQVNijNAjlWBqkDpsfaWTUfeVLRLctfAqW1blsmIv4RQ91PupYJZDNc8nO9ZTF3TEVM+2KHoxzDJrLs2Q==" : null,
Type = type,
Status = status
};
}

View File

@@ -0,0 +1,122 @@
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Bit.Infrastructure.EntityFramework.Repositories;
using LinqToDB.EntityFrameworkCore;
namespace Bit.Seeder.Recipes;
public class CollectionsRecipe(DatabaseContext db)
{
/// <summary>
/// Adds collections to an organization and creates relationships between users and collections.
/// </summary>
/// <param name="organizationId">The ID of the organization to add collections to.</param>
/// <param name="collections">The number of collections to add.</param>
/// <param name="organizationUserIds">The IDs of the users to create relationships with.</param>
/// <param name="maxUsersWithRelationships">The maximum number of users to create relationships with.</param>
public List<Guid> AddToOrganization(Guid organizationId, int collections, List<Guid> organizationUserIds, int maxUsersWithRelationships = 1000)
{
var collectionList = CreateAndSaveCollections(organizationId, collections);
if (collectionList.Any())
{
CreateAndSaveCollectionUserRelationships(collectionList, organizationUserIds, maxUsersWithRelationships);
}
return collectionList.Select(c => c.Id).ToList();
}
private List<Core.Entities.Collection> CreateAndSaveCollections(Guid organizationId, int count)
{
var collectionList = new List<Core.Entities.Collection>();
for (var i = 0; i < count; i++)
{
collectionList.Add(new Core.Entities.Collection
{
Id = CoreHelpers.GenerateComb(),
OrganizationId = organizationId,
Name = $"Collection {i + 1}",
Type = CollectionType.SharedCollection,
CreationDate = DateTime.UtcNow,
RevisionDate = DateTime.UtcNow
});
}
if (collectionList.Any())
{
db.BulkCopy(collectionList);
}
return collectionList;
}
private void CreateAndSaveCollectionUserRelationships(
List<Core.Entities.Collection> collections,
List<Guid> organizationUserIds,
int maxUsersWithRelationships)
{
if (!organizationUserIds.Any() || maxUsersWithRelationships <= 0)
{
return;
}
var collectionUsers = BuildCollectionUserRelationships(collections, organizationUserIds, maxUsersWithRelationships);
if (collectionUsers.Any())
{
db.BulkCopy(collectionUsers);
}
}
/// <summary>
/// Creates user-to-collection relationships with varied assignment patterns for realistic test data.
/// Each user gets 1-3 collections based on a rotating pattern.
/// </summary>
private List<Core.Entities.CollectionUser> BuildCollectionUserRelationships(
List<Core.Entities.Collection> collections,
List<Guid> organizationUserIds,
int maxUsersWithRelationships)
{
var maxRelationships = Math.Min(organizationUserIds.Count, maxUsersWithRelationships);
var collectionUsers = new List<Core.Entities.CollectionUser>();
for (var i = 0; i < maxRelationships; i++)
{
var orgUserId = organizationUserIds[i];
var userCollectionAssignments = CreateCollectionAssignmentsForUser(collections, orgUserId, i);
collectionUsers.AddRange(userCollectionAssignments);
}
return collectionUsers;
}
/// <summary>
/// Assigns collections to a user with varying permissions.
/// Pattern: 1-3 collections per user (cycles: 1, 2, 3, 1, 2, 3...).
/// First collection has Manage rights, subsequent ones are ReadOnly.
/// </summary>
private List<Core.Entities.CollectionUser> CreateCollectionAssignmentsForUser(
List<Core.Entities.Collection> collections,
Guid organizationUserId,
int userIndex)
{
var assignments = new List<Core.Entities.CollectionUser>();
var userCollectionCount = (userIndex % 3) + 1; // Cycles through 1, 2, or 3 collections
for (var j = 0; j < userCollectionCount; j++)
{
var collectionIndex = (userIndex + j) % collections.Count; // Distribute across available collections
assignments.Add(new Core.Entities.CollectionUser
{
CollectionId = collections[collectionIndex].Id,
OrganizationUserId = organizationUserId,
ReadOnly = j > 0, // First assignment gets write access
HidePasswords = false,
Manage = j == 0 // First assignment gets manage permissions
});
}
return assignments;
}
}

View File

@@ -0,0 +1,94 @@
using Bit.Core.Utilities;
using Bit.Infrastructure.EntityFramework.Repositories;
using LinqToDB.EntityFrameworkCore;
namespace Bit.Seeder.Recipes;
public class GroupsRecipe(DatabaseContext db)
{
/// <summary>
/// Adds groups to an organization and creates relationships between users and groups.
/// </summary>
/// <param name="organizationId">The ID of the organization to add groups to.</param>
/// <param name="groups">The number of groups to add.</param>
/// <param name="organizationUserIds">The IDs of the users to create relationships with.</param>
/// <param name="maxUsersWithRelationships">The maximum number of users to create relationships with.</param>
public List<Guid> AddToOrganization(Guid organizationId, int groups, List<Guid> organizationUserIds, int maxUsersWithRelationships = 1000)
{
var groupList = CreateAndSaveGroups(organizationId, groups);
if (groupList.Any())
{
CreateAndSaveGroupUserRelationships(groupList, organizationUserIds, maxUsersWithRelationships);
}
return groupList.Select(g => g.Id).ToList();
}
private List<Core.AdminConsole.Entities.Group> CreateAndSaveGroups(Guid organizationId, int count)
{
var groupList = new List<Core.AdminConsole.Entities.Group>();
for (var i = 0; i < count; i++)
{
groupList.Add(new Core.AdminConsole.Entities.Group
{
Id = CoreHelpers.GenerateComb(),
OrganizationId = organizationId,
Name = $"Group {i + 1}"
});
}
if (groupList.Any())
{
db.BulkCopy(groupList);
}
return groupList;
}
private void CreateAndSaveGroupUserRelationships(
List<Core.AdminConsole.Entities.Group> groups,
List<Guid> organizationUserIds,
int maxUsersWithRelationships)
{
if (!organizationUserIds.Any() || maxUsersWithRelationships <= 0)
{
return;
}
var groupUsers = BuildGroupUserRelationships(groups, organizationUserIds, maxUsersWithRelationships);
if (groupUsers.Any())
{
db.BulkCopy(groupUsers);
}
}
/// <summary>
/// Creates user-to-group relationships with distributed assignment patterns for realistic test data.
/// Each user is assigned to one group, distributed evenly across available groups.
/// </summary>
private List<Core.AdminConsole.Entities.GroupUser> BuildGroupUserRelationships(
List<Core.AdminConsole.Entities.Group> groups,
List<Guid> organizationUserIds,
int maxUsersWithRelationships)
{
var maxRelationships = Math.Min(organizationUserIds.Count, maxUsersWithRelationships);
var groupUsers = new List<Core.AdminConsole.Entities.GroupUser>();
for (var i = 0; i < maxRelationships; i++)
{
var orgUserId = organizationUserIds[i];
var groupIndex = i % groups.Count; // Round-robin distribution across groups
groupUsers.Add(new Core.AdminConsole.Entities.GroupUser
{
GroupId = groups[groupIndex].Id,
OrganizationUserId = orgUserId
});
}
return groupUsers;
}
}

View File

@@ -0,0 +1,25 @@
using Bit.Infrastructure.EntityFramework.Models;
using Bit.Infrastructure.EntityFramework.Repositories;
namespace Bit.Seeder.Recipes;
public class OrganizationDomainRecipe(DatabaseContext db)
{
public void AddVerifiedDomainToOrganization(Guid organizationId, string domainName)
{
var domain = new OrganizationDomain
{
Id = Guid.NewGuid(),
OrganizationId = organizationId,
DomainName = domainName,
Txt = Guid.NewGuid().ToString("N"),
CreationDate = DateTime.UtcNow,
};
domain.SetVerifiedDate();
domain.SetLastCheckedDate();
db.Add(domain);
db.SaveChanges();
}
}

View File

@@ -1,4 +1,5 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Seeder.Factories;
using LinqToDB.EntityFrameworkCore;
@@ -7,11 +8,12 @@ namespace Bit.Seeder.Recipes;
public class OrganizationWithUsersRecipe(DatabaseContext db)
{
public Guid Seed(string name, int users, string domain)
public Guid Seed(string name, string domain, int users, OrganizationUserStatusType usersStatus = OrganizationUserStatusType.Confirmed)
{
var organization = OrganizationSeeder.CreateEnterprise(name, domain, users);
var user = UserSeeder.CreateUserNoMangle($"admin@{domain}");
var orgUser = organization.CreateOrganizationUser(user);
var seats = Math.Max(users + 1, 1000);
var organization = OrganizationSeeder.CreateEnterprise(name, domain, seats);
var ownerUser = UserSeeder.CreateUserNoMangle($"owner@{domain}");
var ownerOrgUser = organization.CreateOrganizationUser(ownerUser, OrganizationUserType.Owner, OrganizationUserStatusType.Confirmed);
var additionalUsers = new List<User>();
var additionalOrgUsers = new List<OrganizationUser>();
@@ -19,12 +21,12 @@ public class OrganizationWithUsersRecipe(DatabaseContext db)
{
var additionalUser = UserSeeder.CreateUserNoMangle($"user{i}@{domain}");
additionalUsers.Add(additionalUser);
additionalOrgUsers.Add(organization.CreateOrganizationUser(additionalUser));
additionalOrgUsers.Add(organization.CreateOrganizationUser(additionalUser, OrganizationUserType.User, usersStatus));
}
db.Add(organization);
db.Add(user);
db.Add(orgUser);
db.Add(ownerUser);
db.Add(ownerOrgUser);
db.SaveChanges();

View File

@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class _20251121_00_AddUsePhishingBlockerToOrganization : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsePhishingBlocker",
table: "Organization",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsePhishingBlocker",
table: "Organization");
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
/// <inheritdoc />
public partial class OrganizationUsersGetPremiumIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}

View File

@@ -239,6 +239,9 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<bool>("UsePasswordManager")
.HasColumnType("INTEGER");
b.Property<bool>("UsePhishingBlocker")
.HasColumnType("INTEGER");
b.Property<bool>("UsePolicies")
.HasColumnType("INTEGER");
@@ -266,7 +269,7 @@ namespace Bit.SqliteMigrations.Migrations
b.HasKey("Id");
b.HasIndex("Id", "Enabled")
.HasAnnotation("Npgsql:IndexInclude", new[] { "UseTotp" });
.HasAnnotation("Npgsql:IndexInclude", new[] { "UseTotp", "UsersGetPremium" });
b.ToTable("Organization", (string)null);
});